diff --git a/BeefLibs/Beefy2D/src/theme/dark/DarkTheme.bf b/BeefLibs/Beefy2D/src/theme/dark/DarkTheme.bf index 72e9e6bc..20a20471 100644 --- a/BeefLibs/Beefy2D/src/theme/dark/DarkTheme.bf +++ b/BeefLibs/Beefy2D/src/theme/dark/DarkTheme.bf @@ -179,6 +179,8 @@ namespace Beefy.theme.dark ThreadBreakpointUnbound, Search, CheckIndeterminate, + CodeError, + CodeWarning, COUNT }; diff --git a/BeefLibs/Beefy2D/src/widgets/ListView.bf b/BeefLibs/Beefy2D/src/widgets/ListView.bf index 0728eefe..17f42b90 100644 --- a/BeefLibs/Beefy2D/src/widgets/ListView.bf +++ b/BeefLibs/Beefy2D/src/widgets/ListView.bf @@ -78,7 +78,7 @@ namespace Beefy.widgets { if (mIsFocused != value) { - Selected = true; + Selected = value; mIsFocused = value; if (mListView.mOnFocusChanged.HasListeners) mListView.mOnFocusChanged(this); diff --git a/IDE/BeefProj.toml b/IDE/BeefProj.toml index 3bb0bd29..e0746b6f 100644 --- a/IDE/BeefProj.toml +++ b/IDE/BeefProj.toml @@ -25,7 +25,7 @@ OtherLinkFlags = "" TargetDirectory = "$(WorkspaceDir)/dist" TargetName = "BeefIDE_d" OtherLinkFlags = "$(LinkFlags) Comdlg32.lib kernel32.lib user32.lib advapi32.lib shell32.lib IDEHelper64_d.lib" -DebugCommandArguments = "-proddir=C:\\proj\\CycloBuddy" +DebugCommandArguments = "-proddir=c:\\beef\\idehelper\\tests" DebugWorkingDirectory = "c:\\Beef\\IDE\\Tests\\EmptyTest" EnvironmentVars = ["_NO_DEBUG_HEAP=1"] diff --git a/IDE/dist/images/DarkUI.png b/IDE/dist/images/DarkUI.png index 50820446..2ea78676 100644 Binary files a/IDE/dist/images/DarkUI.png and b/IDE/dist/images/DarkUI.png differ diff --git a/IDE/dist/images/DarkUI.psd b/IDE/dist/images/DarkUI.psd index 9b0d2722..47e2720f 100644 Binary files a/IDE/dist/images/DarkUI.psd and b/IDE/dist/images/DarkUI.psd differ diff --git a/IDE/dist/images/DarkUI_2.png b/IDE/dist/images/DarkUI_2.png index dcfece26..66a37c0c 100644 Binary files a/IDE/dist/images/DarkUI_2.png and b/IDE/dist/images/DarkUI_2.png differ diff --git a/IDE/dist/images/DarkUI_4.png b/IDE/dist/images/DarkUI_4.png index b7d44fc7..504b41e2 100644 Binary files a/IDE/dist/images/DarkUI_4.png and b/IDE/dist/images/DarkUI_4.png differ diff --git a/IDE/dist/images/DarkUI_4.psd b/IDE/dist/images/DarkUI_4.psd index 333d6e5b..26298d1b 100644 Binary files a/IDE/dist/images/DarkUI_4.psd and b/IDE/dist/images/DarkUI_4.psd differ diff --git a/IDE/mintest/BeefProj.toml b/IDE/mintest/BeefProj.toml index 840a63e9..18efa131 100644 --- a/IDE/mintest/BeefProj.toml +++ b/IDE/mintest/BeefProj.toml @@ -73,7 +73,7 @@ BeefLibType = "Static" [Configs.Test.Win64] CLibType = "Static" -BeefLibType = "Static" +BeefLibType = "DynamicDebug" [Configs.Test.WinFart] BuildKind = "Normal" @@ -88,8 +88,6 @@ BuildKind = "StaticLib" BuildKind = "StaticLib" RelocType = "PIC" -[ProjectFolder] - [[ProjectFolder.Items]] Type = "Source" Path = "../../../temp/test.txt" @@ -98,3 +96,7 @@ Path = "../../../temp/test.txt" Type = "Folder" Path = "../../../temp/borf" AutoInclude = true + +[[ProjectFolder.Items]] +Type = "Source" +Path = "../../../temp/test.bf" diff --git a/IDE/mintest/src/main3.bf b/IDE/mintest/src/main3.bf index f0585e42..88fd7a55 100644 --- a/IDE/mintest/src/main3.bf +++ b/IDE/mintest/src/main3.bf @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading; +#region EnumA Crapsos [AllowDuplicates] enum EnumA { @@ -18,12 +19,35 @@ enum EnumA Zoop = 1 } +struct StructA +{ + public int mA; + public int mB; +} + +#region Blurg struct Blurg { + static mixin MixA(var sa2) + { + sa2.mA++; + } + + static mixin MixB(mut StructA sa2) + { + sa2.mA++; + } + + static void MethodA(mut StructA sa) + { + MixA!(sa); + //MixB!(mut sa); + } + public static int32 Hey() { - int a = 123; - int* aPtr = &a; + StructA sa = .(); + sa.mA = 123 return (int32)123; } diff --git a/IDE/src/BuildContext.bf b/IDE/src/BuildContext.bf index d8f103e2..0e7d29a6 100644 --- a/IDE/src/BuildContext.bf +++ b/IDE/src/BuildContext.bf @@ -135,7 +135,7 @@ namespace IDE { mScriptManager = new .(); mScriptManager.mProjectName = new String(project.mProjectName); - mScriptManager.mAllowCompiling = true; + mScriptManager.mIsBuildScript = true; mScriptManager.mSoftFail = true; mScriptManager.mVerbosity = gApp.mVerbosity; didCommands = true; diff --git a/IDE/src/Commands.bf b/IDE/src/Commands.bf index 9fbf0bc1..55dc7c77 100644 --- a/IDE/src/Commands.bf +++ b/IDE/src/Commands.bf @@ -250,6 +250,8 @@ namespace IDE Add("Show Class View", new => gApp.ShowClassViewPanel); Add("Show Current", new => gApp.Cmd_ShowCurrent); Add("Show Disassembly", new => gApp.[Friend]ShowDisassemblyAtStack); + Add("Show Errors", new => gApp.[Friend]ShowErrors); + Add("Show Error Next", new => gApp.ShowErrorNext); Add("Show File Externally", new => gApp.Cmd_ShowFileExternally); Add("Show Find Results", new => gApp.ShowFindResults); Add("Show Fixit", new => gApp.Cmd_ShowFixit); diff --git a/IDE/src/Compiler/BfCompiler.bf b/IDE/src/Compiler/BfCompiler.bf index 5cd0b7ff..9045d191 100644 --- a/IDE/src/Compiler/BfCompiler.bf +++ b/IDE/src/Compiler/BfCompiler.bf @@ -8,6 +8,7 @@ using Beefy.widgets; using Beefy; using Beefy.utils; using IDE.Util; +using IDE.ui; namespace IDE.Compiler { @@ -295,6 +296,8 @@ namespace IDE.Compiler protected override void DoProcessQueue() { + BfPassInstance.PassKind passKind = .None; + BfPassInstance passInstance = null; bool didPassInstanceAlloc = false; @@ -312,6 +315,23 @@ namespace IDE.Compiler command = mCommandQueue[0]; } + bool commandProcessed = true; + defer + { + if (commandProcessed) + { + using (mMonitor.Enter()) + { + delete command; + if (!mShuttingDown) + { + var poppedCmd = mCommandQueue.PopFront(); + Debug.Assert(poppedCmd == command); + } + } + } + } + if (command is SetPassInstanceCommand) { var setPassInstanceCommand = (SetPassInstanceCommand)command; @@ -345,9 +365,12 @@ namespace IDE.Compiler var projectSource = projectSourceCommand.mProjectSource; if (projectSource.mIncludeKind != .Ignore) { + BfProject bfProject = null; + using (projectSource.mProject.mMonitor.Enter()) { projectSourceCommand.mProjectSource.GetFullImportPath(sourceFilePath); + bfProject = mBfSystem.GetBfProject(projectSource.mProject); } bool canMoveSourceString = true; @@ -389,10 +412,15 @@ namespace IDE.Compiler else bfParser.SetSource("", sourceFilePath); bfParser.SetCharIdData(ref char8IdData); + + //passInstance.SetProject(bfProject); worked &= bfParser.Parse(passInstance, false); worked &= bfParser.Reduce(passInstance); + //passInstance.SetProject(bfProject); worked &= bfParser.BuildDefs(passInstance, null, false); + passKind = .Parse; + // Do this to make sure we re-trigger errors in parse/reduce/builddefs if (!worked) projectSource.HasChangedSinceLastCompile = true; @@ -402,6 +430,15 @@ namespace IDE.Compiler if (command is ProjectSourceRemovedCommand) { var fileRemovedCommand = (ProjectSourceRemovedCommand)command; + let projectSource = fileRemovedCommand.mProjectSource; + + using (projectSource.mProject.mMonitor.Enter()) + { + String sourceFilePath = scope String(); + projectSource.GetFullImportPath(sourceFilePath); + gApp.mErrorsPanel.ClearParserErrors(sourceFilePath); + } + var bfParser = mBfSystem.FileRemoved(fileRemovedCommand.mProjectSource); if (bfParser != null) { @@ -421,13 +458,24 @@ namespace IDE.Compiler if (command is ResolveAllCommand) { + if (passKind != .None) + { + commandProcessed = false; + break; + } + var resolvePassData = BfResolvePassData.Create(ResolveType.Classify); // If we get canceled then try again after waiting a couple updates if (!ClassifySource(passInstance, null, resolvePassData, null)) QueueDeferredResolveAll(); + delete resolvePassData; mBfSystem.RemoveOldParsers(); mBfSystem.RemoveOldData(); + passKind = .Classify; + + // End after resolveAll + break; } if (command is SetWorkspaceOptionsCommand) @@ -444,22 +492,16 @@ namespace IDE.Compiler { mWantsActiveViewRefresh = true; } - - using (mMonitor.Enter()) - { - delete command; - if (!mShuttingDown) - { - var poppedCmd = mCommandQueue.PopFront(); - Debug.Assert(poppedCmd == command); - } - } } mBfSystem.Unlock(); if (didPassInstanceAlloc) - delete passInstance; + { + if ((passKind != .None) && (mIsResolveOnly)) + gApp.mErrorsPanel.ProcessPassInstance(passInstance, passKind); + delete passInstance; + } } void HandleOptions(BfProject hotBfProject, int32 hotIdx) diff --git a/IDE/src/Compiler/BfPassInstance.bf b/IDE/src/Compiler/BfPassInstance.bf index 5808db88..52e87734 100644 --- a/IDE/src/Compiler/BfPassInstance.bf +++ b/IDE/src/Compiler/BfPassInstance.bf @@ -10,6 +10,13 @@ namespace IDE.Compiler { public class BfPassInstance { + public enum PassKind + { + None, + Parse, + Classify + } + [StdCall, CLink] static extern void BfPassInstance_Delete(void* bfSystem); @@ -23,12 +30,12 @@ namespace IDE.Compiler static extern int32 BfPassInstance_GetErrorCount(void* mNativeResolvePassData); [StdCall, CLink] - static extern char8* BfPassInstance_GetErrorData(void* mNativeResolvePassData, int32 errorIdx, out bool isWarning, - out bool isAfter, out bool isDeferred, out bool isWhileSpecializing, - out bool isPersistent, out int32 srcStart, out int32 srcEnd, out int32 moreInfoCount); + static extern char8* BfPassInstance_GetErrorData(void* mNativeResolvePassData, int32 errorIdx, out int32 code, out bool isWarning, + out bool isAfter, out bool isDeferred, out bool isWhileSpecializing, out bool isPersistent, out char8* projectName, + out char8* fileName, out int32 srcStart, out int32 srcEnd, int32* srcLine, int32* srcColumn, out int32 moreInfoCount); [StdCall, CLink] - static extern char8* BfPassInstance_Error_GetMoreInfoData(void* mNativeResolvePassData, int32 errorIdx, int32 moreInfoIdx, out char8* fileName, out int32 srcStart, out int32 srcEnd); + static extern char8* BfPassInstance_Error_GetMoreInfoData(void* mNativeResolvePassData, int32 errorIdx, int32 moreInfoIdx, out char8* fileName, out int32 srcStart, out int32 srcEnd, int32* srcLine, int32* srcColumn); [StdCall, CLink] static extern bool BfPassInstance_HadSignatureChanges(void* mNativeResolvePassData); @@ -36,18 +43,22 @@ namespace IDE.Compiler public class BfError { public bool mIsWarning; + public int32 mCode; public bool mIsAfter; public bool mIsDeferred; public bool mIsWhileSpecializing; public bool mIsPersistent; + public String mProject ~ delete _; public String mError ~ delete _; public int32 mSrcStart; public int32 mSrcEnd; + public int32 mLine = -1; + public int32 mColumn = -1; public int32 mMoreInfoCount; public bool mOwnsSpan; public IdSpan mIdSpan ~ { if (mOwnsSpan) _.Dispose(); }; public int32 mErrorIdx = -1; - public String mFileName ~ delete _; + public String mFilePath ~ delete _; public List mMoreInfo ~ DeleteContainerAndItems!(_); } @@ -110,21 +121,30 @@ namespace IDE.Compiler return BfPassInstance_GetErrorCount(mNativeBfPassInstance); } - public void GetErrorData(int32 errorIdx, BfError bfError) + public void GetErrorData(int32 errorIdx, BfError bfError, bool getLine = false) { Debug.Assert(bfError.mError == null); bfError.mErrorIdx = errorIdx; - bfError.mError = new String(BfPassInstance_GetErrorData(mNativeBfPassInstance, errorIdx, out bfError.mIsWarning, out bfError.mIsAfter, out bfError.mIsDeferred, - out bfError.mIsWhileSpecializing, out bfError.mIsPersistent, out bfError.mSrcStart, out bfError.mSrcEnd, out bfError.mMoreInfoCount)); + char8* projectName = null; + char8* fileName = null; + bfError.mError = new String(BfPassInstance_GetErrorData(mNativeBfPassInstance, errorIdx, out bfError.mCode, out bfError.mIsWarning, out bfError.mIsAfter, out bfError.mIsDeferred, + out bfError.mIsWhileSpecializing, out bfError.mIsPersistent, out projectName, out fileName, out bfError.mSrcStart, out bfError.mSrcEnd, + getLine ? &bfError.mLine : null, getLine ? &bfError.mColumn : null, + out bfError.mMoreInfoCount)); + if (projectName != null) + bfError.mProject = new String(projectName); + if (fileName != null) + bfError.mFilePath = new String(fileName); } - public void GetMoreInfoErrorData(int32 errorIdx, int32 moreInfoIdx, BfError bfError) + public void GetMoreInfoErrorData(int32 errorIdx, int32 moreInfoIdx, BfError bfError, bool getLine = false) { char8* fileName = null; - char8* errorStr = BfPassInstance_Error_GetMoreInfoData(mNativeBfPassInstance, errorIdx, moreInfoIdx, out fileName, out bfError.mSrcStart, out bfError.mSrcEnd); - Debug.Assert(bfError.mFileName == null); + char8* errorStr = BfPassInstance_Error_GetMoreInfoData(mNativeBfPassInstance, errorIdx, moreInfoIdx, out fileName, out bfError.mSrcStart, out bfError.mSrcEnd, + getLine ? &bfError.mLine : null, getLine ? &bfError.mColumn : null); + Debug.Assert(bfError.mFilePath == null); if (fileName != null) - bfError.mFileName = new String(fileName); + bfError.mFilePath = new String(fileName); if (bfError.mError == null) bfError.mError = new String(errorStr); else diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index d7622a1d..30492446 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -176,6 +176,7 @@ namespace IDE public WatchPanel mWatchPanel; public MemoryPanel mMemoryPanel; public CallStackPanel mCallStackPanel; + public ErrorsPanel mErrorsPanel; public BreakpointPanel mBreakpointPanel; public ModulePanel mModulePanel; public ThreadPanel mThreadPanel; @@ -625,6 +626,7 @@ namespace IDE RemoveAndDelete!(mProjectPanel); RemoveAndDelete!(mClassViewPanel); + RemoveAndDelete!(mErrorsPanel); RemoveAndDelete!(mOutputPanel); RemoveAndDelete!(mImmediatePanel); RemoveAndDelete!(mFindResultsPanel); @@ -4327,6 +4329,18 @@ namespace IDE ShowPanel(mCallStackPanel, "Call Stack"); } + [IDECommand] + public void ShowErrors() + { + ShowPanel(mErrorsPanel, "Errors"); + } + + [IDECommand] + public void ShowErrorNext() + { + mErrorsPanel.ShowErrorNext(); + } + [IDECommand] public void ShowWatches() { @@ -4868,20 +4882,21 @@ namespace IDE ////////// subMenu = root.AddMenuItem("&View"); - AddMenuItem(subMenu, "Work&space Explorer", "Show Workspace Explorer"); - AddMenuItem(subMenu, "C&lass View", "Show Class View"); - AddMenuItem(subMenu, "&Immediate Window", "Show Immediate"); - AddMenuItem(subMenu, "&Threads", "Show Threads"); + AddMenuItem(subMenu, "A&utoComplete", "Show Autocomplete Panel"); + AddMenuItem(subMenu, "&Auto Watches", "Show Auto Watches"); + AddMenuItem(subMenu, "&Breakpoints", "Show Breakpoints"); AddMenuItem(subMenu, "&Call Stack", "Show Call Stack"); - AddMenuItem(subMenu, "&Watches", "Show Watches"); - AddMenuItem(subMenu, "&Auto Watches", "Show Auto Watches"); - AddMenuItem(subMenu, "&Breakpoints", "Show Breakpoints"); + AddMenuItem(subMenu, "C&lass View", "Show Class View"); + AddMenuItem(subMenu, "E&rrors", "Show Errors"); + AddMenuItem(subMenu, "&Find Results", "Show Find Results"); + AddMenuItem(subMenu, "&Immediate Window", "Show Immediate"); AddMenuItem(subMenu, "&Memory", "Show Memory"); AddMenuItem(subMenu, "Mo&dules", "Show Modules"); AddMenuItem(subMenu, "&Output", "Show Output"); - AddMenuItem(subMenu, "&Find Results", "Show Find Results"); AddMenuItem(subMenu, "&Profiler", "Show Profiler"); - AddMenuItem(subMenu, "A&utoComplete", "Show Autocomplete Panel"); + AddMenuItem(subMenu, "&Threads", "Show Threads"); + AddMenuItem(subMenu, "&Watches", "Show Watches"); + AddMenuItem(subMenu, "Work&space Explorer", "Show Workspace Explorer"); subMenu.AddMenuItem(null); AddMenuItem(subMenu, "Next Document Panel", "Next Document Panel"); AddMenuItem(subMenu, "Navigate Backwards", "Navigate Backwards"); @@ -8904,7 +8919,7 @@ namespace IDE bool bfHadOutputChanges; List bfFileNames = scope List(); bfCompiler.GetOutputFileNames(bfProject, false, out bfHadOutputChanges, bfFileNames); - defer(scope) ClearAndDeleteItems(bfFileNames); + defer ClearAndDeleteItems(bfFileNames); if (bfHadOutputChanges) project.mNeedsTargetRebuild = true; } @@ -10227,6 +10242,8 @@ namespace IDE mCallStackPanel.mAutoDelete = false; mBreakpointPanel = new BreakpointPanel(); mBreakpointPanel.mAutoDelete = false; + mErrorsPanel = new ErrorsPanel(); + mErrorsPanel.mAutoDelete = false; mModulePanel = new ModulePanel(); mModulePanel.mAutoDelete = false; mThreadPanel = new ThreadPanel(); @@ -10857,6 +10874,9 @@ namespace IDE didClean = true; OutputLine("Cleaned Beef."); + if (mErrorsPanel != null) + mErrorsPanel.ClearParserErrors(null); + delete mBfResolveCompiler; delete mBfResolveSystem; delete mBfResolveHelper; @@ -10932,6 +10952,9 @@ namespace IDE { OutputLine("Cleaned."); + if (mErrorsPanel != null) + mErrorsPanel.ClearParserErrors(null); + let workspaceOptions = GetCurWorkspaceOptions(); delete mBfResolveHelper; @@ -11038,17 +11061,17 @@ namespace IDE } } + CurrentWorkspaceConfigChanged(); + if (mBfResolveSystem != null) { - for (var project in mWorkspace.mProjects) + /*for (var project in mWorkspace.mProjects) { if (IsProjectEnabled(project)) QueueProjectItems(project); - } + }*/ mBfResolveCompiler.QueueDeferredResolveAll(); } - - CurrentWorkspaceConfigChanged(); } mBfBuildSystem.Update(); @@ -11519,6 +11542,8 @@ namespace IDE if ((mBuildContext == null) && (!IsCompiling)) DeleteAndNullify!(mLaunchData); + + mErrorsPanel?.CheckResolveAll(); } public void ShowPassOutput(BfPassInstance bfPassInstance) diff --git a/IDE/src/ScriptManager.bf b/IDE/src/ScriptManager.bf index fec32ae5..3f93cf18 100644 --- a/IDE/src/ScriptManager.bf +++ b/IDE/src/ScriptManager.bf @@ -72,7 +72,7 @@ namespace IDE public String mExpectingError ~ delete _; public bool mHadExpectingError; public int mDoneTicks; - public bool mAllowCompiling; + public bool mIsBuildScript; public bool mSoftFail; public Verbosity mVerbosity = .Quiet; public String mProjectName ~ delete _; @@ -950,7 +950,7 @@ namespace IDE if (gApp.IsCompiling) { - if (!ScriptManager.sActiveManager.mAllowCompiling) + if (!ScriptManager.sActiveManager.mIsBuildScript) return false; } @@ -960,8 +960,16 @@ namespace IDE if (gApp.mDebugger == null) return true; - if ((!gApp.AreTestsRunning()) && (!gApp.mDebugger.HasPendingDebugLoads()) && - ((gApp.mExecutionPaused) || (!gApp.mDebugger.mIsRunning))) + bool checkRunState = (!gApp.mDebugger.HasPendingDebugLoads()) && + ((gApp.mExecutionPaused) || (!gApp.mDebugger.mIsRunning)); + + if ((!ScriptManager.sActiveManager.mIsBuildScript) && (gApp.AreTestsRunning())) + checkRunState = false; + + /*if (gApp.AreTestsRunning()) + checkRunState = false;*/ + + if (checkRunState) { var runState = gApp.mDebugger.GetRunState(); if (runState == .Terminating) diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index bd66992c..499f306c 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -451,12 +451,14 @@ namespace IDE Add("Save All", "Ctrl+Shift+S"); Add("Save File", "Ctrl+S"); Add("Set Next Statement", "Ctrl+Shift+F10"); - Add("Show Current", "Alt+C"); Add("Show Auto Watches", "Ctrl+Alt+A"); Add("Show Autocomplete Panel", "Ctrl+Alt+U"); Add("Show Breakpoints", "Ctrl+Alt+B"); Add("Show Call Stack", "Ctrl+Alt+C"); Add("Show Class View", "Ctrl+Alt+L"); + Add("Show Current", "Alt+C"); + Add("Show Errors", "Ctrl+Alt+E"); + Add("Show Error Next", "Ctrl+Shift+F12"); Add("Show File Externally", "Ctrl+Tilde"); Add("Show Find Results", "Ctrl+Alt+F"); Add("Show Fixit", "Ctrl+Period"); diff --git a/IDE/src/TestManager.bf b/IDE/src/TestManager.bf index a1a8eb52..52d07f64 100644 --- a/IDE/src/TestManager.bf +++ b/IDE/src/TestManager.bf @@ -183,6 +183,9 @@ namespace IDE cmd.Append(clientStr, 0, crPos); clientStr.Remove(0, crPos + 1); + if (cmd.IsWhiteSpace) + continue; + /*String outStr = scope String(); outStr.AppendF("CMD: {0}", cmd); QueueOutput(outStr);*/ @@ -254,6 +257,13 @@ namespace IDE case ":TestFinish": testsFinished = true; default: + if ((cmdParts.Count < 5) || (cmdParts[0].StartsWith(":"))) + { + QueueOutputLine("ERROR: Failed communicate with test target '{0}'", curProjectInfo.mTestExePath); + TestFailed(); + return; + } + Debug.Assert(cmdParts[0][0] != ':'); let attribs = cmdParts[1]; @@ -347,11 +357,12 @@ namespace IDE } else if (exitCode != 0) { - if (exitCode != 0) - { - QueueOutputLine("ERROR: Test process exited with error code: {0}", exitCode); - TestFailed(); - } + QueueOutputLine("ERROR: Test process exited with error code: {0}", exitCode); + TestFailed(); + } + else if (testInstance.mTestEntries.IsEmpty) + { + QueueOutputLine("WARNING: No test methods defined. Consider adding a [Test] attribute to a static method in a project whose build type is set to 'Test'."); } } diff --git a/IDE/src/ui/ErrorsPanel.bf b/IDE/src/ui/ErrorsPanel.bf index eaf81793..3d20b149 100644 --- a/IDE/src/ui/ErrorsPanel.bf +++ b/IDE/src/ui/ErrorsPanel.bf @@ -51,7 +51,8 @@ namespace IDE.ui public bool mNeedsResolveAll; public bool mErrorsDirty; public Monitor mMonitor = new .() ~ delete _; - public List mErrorList = new .() ~ DeleteContainerAndItems!(_); + public Dictionary> mParseErrors = new .() ~ delete _; + public List mResolveErrors = new .() ~ DeleteContainerAndItems!(_); public int mDirtyTicks; public int mErrorCount; @@ -98,6 +99,11 @@ namespace IDE.ui AddWidget(mDockingFrame); } + public ~this() + { + ClearParserErrors(null); + } + public override void Serialize(StructuredData data) { base.Serialize(data); @@ -122,12 +128,23 @@ namespace IDE.ui { using (mMonitor.Enter()) { - mErrorCount = 0; - mWarningCount = 0; - int32 errorCount = passInstance.GetErrorCount(); - ClearAndDeleteItems(mErrorList); - mErrorList.Capacity = mErrorList.Count; + if (passKind != .Parse) + { + if (!mResolveErrors.IsEmpty) + mErrorsDirty = true; + + for (let error in mResolveErrors) + { + if (error.mIsWarning) + mWarningCount--; + else + mErrorCount--; + } + + ClearAndDeleteItems(mResolveErrors); + mResolveErrors.Capacity = mResolveErrors.Count; + } for (int32 errorIdx = 0; errorIdx < errorCount; errorIdx++) { @@ -148,16 +165,61 @@ namespace IDE.ui bfError.mMoreInfo.Add(moreInfo); } - mErrorList.Add(bfError); - } + if (passKind == .Parse) + { + bool added = mParseErrors.TryAdd(bfError.mFilePath, var keyPtr, var valuePtr); + if (added) + { + *keyPtr = new .(bfError.mFilePath); + *valuePtr = new .(); + } + (*valuePtr).Add(bfError); + } + else + mResolveErrors.Add(bfError); - mErrorsDirty = true; + mErrorsDirty = true; + } } } - public void ClearParserErrors(StringView filePath) + public void ClearParserErrors(String filePath) { + using (mMonitor.Enter()) + { + void DeleteErrorList(List list) + { + for (let error in list) + { + if (error.mIsWarning) + mWarningCount--; + else + mErrorCount--; + delete error; + } + delete list; + } + if (filePath == null) + { + for (var kv in mParseErrors) + { + delete kv.key; + DeleteErrorList(kv.value); + mErrorsDirty = true; + } + mParseErrors.Clear(); + } + else + { + if (mParseErrors.GetAndRemove(filePath) case .Ok((let key, let list))) + { + delete key; + DeleteErrorList(list); + mErrorsDirty = true; + } + } + } } void ProcessErrors() @@ -168,7 +230,8 @@ namespace IDE.ui { let root = mErrorLV.GetRoot(); - for (let error in mErrorList) + int idx = 0; + void HandleError(BfPassInstance.BfError error) { ErrorsListViewItem item; @@ -181,7 +244,6 @@ namespace IDE.ui item.Label = str; } - int idx = @error.Index; if (idx >= root.GetChildCount()) { item = (.)root.CreateChildItem(); @@ -225,9 +287,28 @@ namespace IDE.ui if (changed) item.Focused = false; + + idx++; } - while (root.GetChildCount() > mErrorList.Count) + if (!mParseErrors.IsEmpty) + { + List paths = scope .(); + for (var path in mParseErrors.Keys) + paths.Add(path); + paths.Sort(); + + for (var path in paths) + { + for (var error in mParseErrors[path]) + HandleError(error); + } + } + + for (let error in mResolveErrors) + HandleError(error); + + while (root.GetChildCount() > idx) root.RemoveChildItemAt(root.GetChildCount() - 1); mErrorsDirty = false; @@ -277,7 +358,7 @@ namespace IDE.ui bool foundFocused = false; let root = mErrorLV.GetRoot(); - if (root.mChildItems == null) + if (root.GetChildCount() == 0) return; for (let lvItem in root.mChildItems) { diff --git a/IDE/src/ui/NavigationBar.bf b/IDE/src/ui/NavigationBar.bf index 72361375..b0a39660 100644 --- a/IDE/src/ui/NavigationBar.bf +++ b/IDE/src/ui/NavigationBar.bf @@ -195,7 +195,7 @@ namespace IDE.ui if (mShowingDropdown) return null; mShowingDropdown = true; - defer(scope) { mShowingDropdown = false; } + defer { mShowingDropdown = false; } /*var stopWatch = scope Stopwatch(); stopWatch.Start();*/ diff --git a/IDE/src/ui/Panel.bf b/IDE/src/ui/Panel.bf index a3009610..cd5d2016 100644 --- a/IDE/src/ui/Panel.bf +++ b/IDE/src/ui/Panel.bf @@ -97,6 +97,10 @@ namespace IDE.ui { panel = gApp.mImmediatePanel; } + else if (type == "ErrorsPanel") + { + panel = gApp.mErrorsPanel; + } else if (type == "FindResultsPanel") { panel = gApp.mFindResultsPanel; diff --git a/IDE/src/ui/ProjectPanel.bf b/IDE/src/ui/ProjectPanel.bf index 52cf713d..8fe44bc7 100644 --- a/IDE/src/ui/ProjectPanel.bf +++ b/IDE/src/ui/ProjectPanel.bf @@ -868,7 +868,7 @@ namespace IDE.ui String dir = scope String(fileDialog.InitialDirectory); List alreadyHadFileList = scope List(); - defer(scope) ClearAndDeleteItems(alreadyHadFileList); + defer ClearAndDeleteItems(alreadyHadFileList); for (String fileNameIn in fileDialog.FileNames) { diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index 41098d98..dbe1fec0 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -1653,6 +1653,9 @@ namespace IDE.ui if (gApp.mDbgDelayedAutocomplete) Thread.Sleep(250); + if ((resolveType == .Classify) || (resolveType == .ClassifyFullRefresh)) + gApp.mErrorsPanel.SetNeedsResolveAll(); + /*if (resolveType == .Autocomplete) { Thread.Sleep(250); @@ -1818,6 +1821,13 @@ namespace IDE.ui resolvePassData.SetDocumentationRequest(resolveParams.mDocumentationName); parser.Parse(passInstance, !mIsBeefSource); parser.Reduce(passInstance); + + if ((mIsBeefSource) && + ((resolveType == .Classify) || (resolveType == .ClassifyFullRefresh))) + { + gApp.mErrorsPanel.ClearParserErrors(mFilePath); + gApp.mErrorsPanel.ProcessPassInstance(passInstance, .Parse); + } if (isInterrupt) { @@ -2511,13 +2521,16 @@ namespace IDE.ui if (trackedElement.mSnapToLineStart) { int32 lineLeft = trackedElementView.mTextPosition.mIndex; - repeat - { - if (!((char8)editContent.mData.mText[lineLeft].mChar).IsWhiteSpace) - startContentIdx = lineLeft; - lineLeft--; - } - while ((lineLeft > 0) && (editContent.mData.mText[lineLeft].mChar != '\n')); + if (lineLeft < editContent.mData.mTextLength) + { + repeat + { + if (!((char8)editContent.mData.mText[lineLeft].mChar).IsWhiteSpace) + startContentIdx = lineLeft; + lineLeft--; + } + while ((lineLeft > 0) && (editContent.mData.mText[lineLeft].mChar != '\n')); + } if (startContentIdx == -1) { @@ -4926,7 +4939,7 @@ namespace IDE.ui { for (var moreInfo in bestError.mMoreInfo) { - showMouseoverString.AppendF("\n@{0}\t{1}\t{2}", moreInfo.mFileName, moreInfo.mSrcStart, moreInfo.mError); + showMouseoverString.AppendF("\n@{0}\t{1}\t{2}", moreInfo.mFilePath, moreInfo.mSrcStart, moreInfo.mError); } } } diff --git a/IDE/src/ui/StatusBar.bf b/IDE/src/ui/StatusBar.bf index 7494bc78..120f40b0 100644 --- a/IDE/src/ui/StatusBar.bf +++ b/IDE/src/ui/StatusBar.bf @@ -365,9 +365,21 @@ namespace IDE.ui else mStatusBoxUpdateCnt = -1; + /// + { + if (gApp.mErrorsPanel.mErrorCount > 0) + { + g.Draw(DarkTheme.sDarkTheme.GetImage(.CodeError), GS!(6), 0); + } + else if (gApp.mErrorsPanel.mWarningCount > 0) + { + g.Draw(DarkTheme.sDarkTheme.GetImage(.CodeWarning), GS!(6), 0); + } + } + if (gApp.mSettings.mEnableDevMode) { - g.DrawString(StackStringFormat!("FPS: {0}", gApp.mLastFPS), GS!(4), 0); + g.DrawString(StackStringFormat!("FPS: {0}", gApp.mLastFPS), GS!(32), 0); String resolveStr = scope String(); let bfResolveCompiler = gApp.mBfResolveCompiler; @@ -418,5 +430,16 @@ namespace IDE.ui g.DrawString(resolveStr, GS!(100), 0); } } + + public override void MouseDown(float x, float y, int32 btn, int32 btnCount) + { + base.MouseDown(x, y, btn, btnCount); + + if (Rect(GS!(6), 0, GS!(20), mHeight).Contains(x, y)) + { + gApp.mErrorsPanel.ShowErrorNext(); + return; + } + } } } diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 41706047..450aa122 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -3482,6 +3482,22 @@ void BfCompiler::ProcessAutocompleteTempType() BF_ASSERT(mResolvePassData->mAutoComplete->mDefMethod == NULL); if (autoComplete->mResolveType == BfResolveType_GetNavigationData) { + for (auto node : mResolvePassData->mParser->mSidechannelRootNode->mChildArr) + { + if (auto preprocNode = BfNodeDynCast(node)) + { + if (preprocNode->mCommand->Equals("region")) + { + if (!autoCompleteResultString.empty()) + autoCompleteResultString += "\n"; + autoCompleteResultString += "#"; + preprocNode->mArgument->ToString(autoCompleteResultString); + mContext->mScratchModule->UpdateSrcPos(preprocNode, (BfSrcPosFlags)(BfSrcPosFlag_NoSetDebugLoc | BfSrcPosFlag_Force)); + autoCompleteResultString += StrFormat("\tregion\t%d\t%d", module->mCurFilePosition.mCurLine, module->mCurFilePosition.mCurColumn); + } + } + } + for (auto tempTypeDef : mResolvePassData->mAutoCompleteTempTypes) { String typeName = tempTypeDef->ToString(); diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index b10c26ad..67c26803 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -195,7 +195,7 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD { if (genericParams[checkParamsIdx]->mName == name) { - mPassInstance->Fail("Duplicate generic param name", genericParamNode); + Fail("Duplicate generic param name", genericParamNode); } } @@ -256,7 +256,7 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD { if (externConstraintDefs == NULL) { - mPassInstance->Fail("Cannot find generic parameter in constraint", genericConstraint->mTypeRef); + Fail("Cannot find generic parameter in constraint", genericConstraint->mTypeRef); if (genericParams.IsEmpty()) continue; @@ -307,9 +307,9 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD prevFlagName = "struct*"; if (prevFlagName == name) - mPassInstance->Fail(StrFormat("Cannot specify '%s' twice", prevFlagName.c_str()), constraintNode); + Fail(StrFormat("Cannot specify '%s' twice", prevFlagName.c_str()), constraintNode); else - mPassInstance->Fail(StrFormat("Cannot specify both '%s' and '%s'", prevFlagName.c_str(), name.c_str()), constraintNode); + Fail(StrFormat("Cannot specify both '%s' and '%s'", prevFlagName.c_str(), name.c_str()), constraintNode); return; } @@ -347,7 +347,7 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD auto constraintType = BfNodeDynCast(constraintNode); if (constraintType == NULL) { - mPassInstance->Fail("Invalid constraint", constraintNode); + Fail("Invalid constraint", constraintNode); return; } } @@ -360,7 +360,7 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD } else { - mPassInstance->Fail("Type assignment must be the first constraint", genericConstraint->mColonToken); + Fail("Type assignment must be the first constraint", genericConstraint->mColonToken); } } @@ -453,22 +453,22 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio if (mCurTypeDef->mTypeCode == BfTypeCode_Interface) { if ((methodDef->mIsConcrete) && (!mCurTypeDef->mIsConcrete)) - mPassInstance->Fail("Only interfaces declared as 'concrete' can be declare methods as 'concrete'. Consider adding 'concrete' to the interface declaration.", methodDeclaration->mVirtualSpecifier); + Fail("Only interfaces declared as 'concrete' can be declare methods as 'concrete'. Consider adding 'concrete' to the interface declaration.", methodDeclaration->mVirtualSpecifier); //if (!methodDef->mIsConcrete) - //mPassInstance->Fail(StrFormat("Interfaces methods cannot be declared as '%s'", methodDeclaration->mVirtualSpecifier->ToString().c_str()), methodDeclaration->mVirtualSpecifier); + //Fail(StrFormat("Interfaces methods cannot be declared as '%s'", methodDeclaration->mVirtualSpecifier->ToString().c_str()), methodDeclaration->mVirtualSpecifier); } else { if (methodDef->mIsConcrete) - mPassInstance->Fail("Only interfaces methods can be declared as 'concrete'", methodDeclaration->mVirtualSpecifier); + Fail("Only interfaces methods can be declared as 'concrete'", methodDeclaration->mVirtualSpecifier); } if (methodDef->mIsAbstract) { if ((!mCurTypeDef->mIsAbstract) && (mCurTypeDef->mTypeCode != BfTypeCode_Interface)) - mPassInstance->Fail("Method is abstract but it is contained in non-abstract class", methodDeclaration); + Fail("Method is abstract but it is contained in non-abstract class", methodDeclaration); if (methodDeclaration->mBody != NULL) - mPassInstance->Fail("Abstract method cannot declare a body", methodDeclaration); + Fail("Abstract method cannot declare a body", methodDeclaration); } } else @@ -513,7 +513,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio methodDef->mMethodType = BfMethodType_Operator; /*if (propertyDecl->mStaticSpecifier == NULL) { - mPassInstance->Fail("Operators must be declared as static", methodDeclaration); + Fail("Operators must be declared as static", methodDeclaration); }*/ String declError; @@ -531,7 +531,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio } if (!declError.empty()) { - mPassInstance->Fail(StrFormat("Operator must be declared %s", declError.c_str()), operatorDecl->mOperatorToken); + Fail(StrFormat("Operator must be declared %s", declError.c_str()), operatorDecl->mOperatorToken); } } else if ((mCurTypeDef->mIsDelegate) || (mCurTypeDef->mIsFunction)) @@ -560,7 +560,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio methodDef->mName = methodDeclaration->mNameNode->ToString(); methodDef->mMethodType = BfMethodType_Mixin; /*if (!methodDef->mIsStatic) - mPassInstance->Fail("Mixin must be declared static", methodDeclaration->mMixinSpecifier);*/ + Fail("Mixin must be declared static", methodDeclaration->mMixinSpecifier);*/ } else { @@ -612,7 +612,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio { methodDef->mParams[paramIdx - 1]->mParamKind = BfParamKind_Normal; hadParams = false; - mPassInstance->Fail("Params parameter must be the last parameter", methodDef->mParams[paramIdx - 1]->mParamDeclaration); + Fail("Params parameter must be the last parameter", methodDef->mParams[paramIdx - 1]->mParamDeclaration); } if (paramDef->mParamDeclaration->mInitializer != NULL) @@ -620,7 +620,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio else if (hasDefault) { if (!didDefaultsError) - mPassInstance->Fail("Optional parameters must appear after all required parameters", methodDef->mParams[paramIdx - 1]->mParamDeclaration); + Fail("Optional parameters must appear after all required parameters", methodDef->mParams[paramIdx - 1]->mParamDeclaration); didDefaultsError = true; } } @@ -632,6 +632,14 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio return methodDef; } +BfError* BfDefBuilder::Fail(const StringImpl& errorStr, BfAstNode* refNode) +{ + auto error = mPassInstance->Fail(errorStr, refNode); + if (error != NULL) + error->mProject = mCurSource->mProject; + return error; +} + void BfDefBuilder::Visit(BfMethodDeclaration* methodDeclaration) { if (mCurTypeDef == NULL) @@ -742,7 +750,7 @@ void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef { if (methodDef->mParams.size() != 2) { - mPassInstance->Fail("Commutable attributes can only be applied to methods with two arguments", attributes->mAttributeTypeRef); + Fail("Commutable attributes can only be applied to methods with two arguments", attributes->mAttributeTypeRef); } else { @@ -790,7 +798,7 @@ void BfDefBuilder::Visit(BfPropertyDeclaration* propertyDeclaration) if (propertyDeclaration->mConstSpecifier != NULL) { - mPassInstance->Fail("Const properties are not allowed", propertyDeclaration->mConstSpecifier); + Fail("Const properties are not allowed", propertyDeclaration->mConstSpecifier); } HashNode(*mSignatureHashCtx, propertyDeclaration, propertyDeclaration->mDefinitionBlock); @@ -871,7 +879,7 @@ void BfDefBuilder::Visit(BfPropertyDeclaration* propertyDeclaration) { BfProtection newProtection = GetProtection(methodDeclaration->mProtectionSpecifier); if (newProtection > methodDef->mProtection) - mPassInstance->Fail(StrFormat("the accessibility modifier of the 'get' accessor must be more restrictive than the property or indexer '%s'", propertyDef->mName.c_str()), + Fail(StrFormat("the accessibility modifier of the 'get' accessor must be more restrictive than the property or indexer '%s'", propertyDef->mName.c_str()), methodDeclaration->mProtectionSpecifier); methodDef->mProtection = newProtection; } @@ -997,7 +1005,7 @@ void BfDefBuilder::Visit(BfFieldDeclaration* fieldDeclaration) // This check is a bit of a hack to determine the difference between a "MemberType mMember" and a proper case entry of "mMember(TupleType)" if (!isEnumEntryDecl) { - mPassInstance->Fail("Non-static field declarations are not allowed in enums", fieldDeclaration); + Fail("Non-static field declarations are not allowed in enums", fieldDeclaration); } } @@ -1231,7 +1239,7 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) mCurTypeDef->mName = mSystem->GetAtom(typeDeclaration->mNameNode->ToString()); if (mCurTypeDef->mName->mIsSystemType) { - mPassInstance->Fail(StrFormat("Type name '%s' is reserved", typeDeclaration->mNameNode->ToString().c_str()), typeDeclaration->mNameNode); + Fail(StrFormat("Type name '%s' is reserved", typeDeclaration->mNameNode->ToString().c_str()), typeDeclaration->mNameNode); } } @@ -1245,7 +1253,7 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) if ((outerTypeDef == NULL) && (typeDeclaration->mProtectionSpecifier->GetToken() != BfToken_Public)) { //CS1527 - mPassInstance->Fail("Elements defined in a namespace cannot be explicitly declared as private, protected, or protected internal", typeDeclaration->mProtectionSpecifier); + Fail("Elements defined in a namespace cannot be explicitly declared as private, protected, or protected internal", typeDeclaration->mProtectionSpecifier); } else { @@ -1677,13 +1685,13 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) { if (hasStaticCtor) { - mPassInstance->Fail("Only one static constructor is allowed", method->mMethodDeclaration); + Fail("Only one static constructor is allowed", method->mMethodDeclaration); method->mIsStatic = false; } if (method->mParams.size() != 0) { - mPassInstance->Fail("Static constructor cannot declare parameters", method->mMethodDeclaration); + Fail("Static constructor cannot declare parameters", method->mMethodDeclaration); method->mIsStatic = false; } @@ -1740,7 +1748,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) { if (hasStaticDtor) { - mPassInstance->Fail("Only one static constructor is allowed", method->mMethodDeclaration); + Fail("Only one static constructor is allowed", method->mMethodDeclaration); method->mIsStatic = false; } @@ -1750,14 +1758,14 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) { if (hasDtor) { - mPassInstance->Fail("Only one destructor is allowed", method->mMethodDeclaration); + Fail("Only one destructor is allowed", method->mMethodDeclaration); method->mIsStatic = false; } hasDtor = true; } if (method->mParams.size() != 0) - mPassInstance->Fail("Destructors cannot declare parameters", method->GetMethodDeclaration()->mParams[0]); + Fail("Destructors cannot declare parameters", method->GetMethodDeclaration()->mParams[0]); } else if (method->mMethodType == BfMethodType_Normal) { diff --git a/IDEHelper/Compiler/BfDefBuilder.h b/IDEHelper/Compiler/BfDefBuilder.h index f9756c89..acd6c8f0 100644 --- a/IDEHelper/Compiler/BfDefBuilder.h +++ b/IDEHelper/Compiler/BfDefBuilder.h @@ -41,6 +41,7 @@ public: void ParseAttributes(BfAttributeDirective* attributes, BfMethodDef* methodDef); void ParseAttributes(BfAttributeDirective* attributes, BfTypeDef* typeDef); BfMethodDef* CreateMethodDef(BfMethodDeclaration* methodDecl, BfMethodDef* outerMethodDef = NULL); + BfError* Fail(const StringImpl& errorStr, BfAstNode* refNode); public: BfDefBuilder(BfSystem* bfSystem); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 62b5112b..60b2619c 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -2839,7 +2839,7 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI varSkipCount--; } - if (varDecl->mNotCaptured) + if ((varDecl != NULL) && (varDecl->mNotCaptured)) { mModule->Fail("Local variable is not captured", refNode); } diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 8941211b..c4b90b81 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2610,6 +2610,7 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers } if (bfError != NULL) { + bfError->mProject = mProject; bfError->mIsPersistent = isPersistent; bfError->mIsWhileSpecializing = isWhileSpecializing; @@ -2629,7 +2630,10 @@ BfError* BfModule::FailAfter(const StringImpl& error, BfAstNode* refNode) refNode = BfNodeToNonTemporary(refNode); mHadBuildError = true; - return mCompiler->mPassInstance->FailAfter(error, refNode); + BfError* bfError = mCompiler->mPassInstance->FailAfter(error, refNode); + if (bfError != NULL) + bfError->mProject = mProject; + return bfError; } BfError* BfModule::Warn(int warningNum, const StringImpl& warning, BfAstNode* refNode, bool isPersistent) @@ -2692,6 +2696,7 @@ BfError* BfModule::Warn(int warningNum, const StringImpl& warning, BfAstNode* re BfError* bfError = mCompiler->mPassInstance->WarnAt(warningNum, warning, refNode->GetSourceData(), refNode->GetSrcStart(), refNode->GetSrcLength()); if (bfError != NULL) { + bfError->mProject = mProject; AddFailType(mCurTypeInstance); mHadBuildWarning = true; diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index a7bb710f..c839e36f 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -197,15 +197,18 @@ BfAstNode* BfReducer::Fail(const StringImpl& errorMsg, BfAstNode* refNode) mStmtHasError = true; if (mPassInstance->HasLastFailedAt(refNode)) // No duplicate failures return NULL; - mPassInstance->Fail(errorMsg, refNode); + auto error = mPassInstance->Fail(errorMsg, refNode); + if (error != NULL) + error->mProject = mSource->mProject; return NULL; } BfAstNode* BfReducer::FailAfter(const StringImpl& errorMsg, BfAstNode* prevNode) { mStmtHasError = true; - mPassInstance->FailAfter(errorMsg, prevNode); - + auto error = mPassInstance->FailAfter(errorMsg, prevNode); + if (error != NULL) + error->mProject = mSource->mProject; return NULL; } @@ -4053,11 +4056,11 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS if ((unaryOperatorExpr->mOp == BfUnaryOp_Ref) || (unaryOperatorExpr->mOp == BfUnaryOp_Mut) || (unaryOperatorExpr->mOp == BfUnaryOp_Out)) { if (unaryOperatorExpr->mOp == BfUnaryOp_Ref) - mPassInstance->Fail("Cannot use 'ref' in this context", unaryOperatorExpr); + Fail("Cannot use 'ref' in this context", unaryOperatorExpr); else if (unaryOperatorExpr->mOp == BfUnaryOp_Mut) - mPassInstance->Fail("Cannot use 'mut' in this context", unaryOperatorExpr); + Fail("Cannot use 'mut' in this context", unaryOperatorExpr); else - mPassInstance->Fail("Cannot use 'out' in this context", unaryOperatorExpr); + Fail("Cannot use 'out' in this context", unaryOperatorExpr); return NULL; } } @@ -4246,7 +4249,7 @@ BfAstNode* BfReducer::CreateStatement(BfAstNode* node, CreateStmtFlags createStm auto nextNode = mVisitorPos.GetNext(); if (nextNode != NULL) { - mPassInstance->FailAfter("Semicolon expected", expr); + FailAfter("Semicolon expected", expr); } return expr; @@ -4295,7 +4298,9 @@ BfAstNode* BfReducer::CreateStatement(BfAstNode* node, CreateStmtFlags createStm if (((createStmtFlags & CreateStmtFlags_AllowUnterminatedExpression) != 0) && (origStmtNode->IsA()) && (nextNode == NULL)) return stmt; - mPassInstance->FailAfterAt("Semicolon expected", node->GetSourceData(), stmt->GetSrcEnd() - 1); + auto error = mPassInstance->FailAfterAt("Semicolon expected", node->GetSourceData(), stmt->GetSrcEnd() - 1); + if (error != NULL) + error->mProject = mSource->mProject; mPrevStmtHadError = true; return stmt; } @@ -4881,7 +4886,7 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF if ((!doAddType) && (isBoundName)) { - mPassInstance->FailAfter("Expected type", genericInstance); + FailAfter("Expected type", genericInstance); } if ((doAddType) && (!isUnboundName)) { @@ -5539,7 +5544,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, int depth) innerType->mAttributes = attributes; return innerType; } - mPassInstance->Fail("Invalid target for attributes", memberNode); + Fail("Invalid target for attributes", memberNode); return memberNode; } @@ -8595,9 +8600,9 @@ BfTokenNode* BfReducer::ParseMethodParams(BfAstNode* node, SizedArrayImpl(node)) - mPassInstance->Fail("Unexpected token", node); + Fail("Unexpected token", node); else - mPassInstance->Fail("Unexpected identifier", node); + Fail("Unexpected identifier", node); AddErrorNode(node); } diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index 9516abd7..f8687a55 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -5568,7 +5568,7 @@ void BfModule::Visit(BfForEachStatement* forEachStmt) autoComplete->CheckTypeRef(forEachStmt->mVariableTypeRef, false); varType = ResolveTypeRef(forEachStmt->mVariableTypeRef, BfPopulateType_Data, BfResolveTypeRefFlag_AllowRef); } - + if (varType == NULL) varType = mContext->mBfObjectType; bool isArray = target.mType->IsArray(); @@ -5979,6 +5979,9 @@ void BfModule::Visit(BfForEachStatement* forEachStmt) scopeData.mIsLoop = true; + if ((autoComplete != NULL) && (forEachStmt->mVariableTypeRef != NULL)) + autoComplete->CheckVarResolution(forEachStmt->mVariableTypeRef, varType); + if (isArray || isSizedArray) mBfIRBuilder->CreateStore(GetConstValue(0), itr.mValue); diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 02fb9188..8a26c602 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -1391,17 +1391,21 @@ BfError* BfPassInstance::Fail(const StringImpl& error) return mErrors.back(); } -BfError* BfPassInstance::Fail(const StringImpl& error, BfAstNode* refNode) +BfError* BfPassInstance::Fail(const StringImpl& errorStr, BfAstNode* refNode) { BP_ZONE("BfPassInstance::Fail"); + BfError* error = NULL; + mFailedIdx++; if ((refNode == NULL) || (refNode->IsTemporary())) - return Fail(error); + error = Fail(errorStr); else if (refNode->IsA()) - return FailAt(error, refNode->GetSourceData(), refNode->GetSrcStart(), 1); + error = FailAt(errorStr, refNode->GetSourceData(), refNode->GetSrcStart(), 1); else - return FailAt(error, refNode->GetSourceData(), refNode->GetSrcStart(), refNode->GetSrcLength()); + error = FailAt(errorStr, refNode->GetSourceData(), refNode->GetSrcStart(), refNode->GetSrcLength()); + + return error; } BfError* BfPassInstance::FailAfter(const StringImpl& error, BfAstNode* refNode) @@ -1504,7 +1508,7 @@ BfError* BfPassInstance::WarnAt(int warningNumber, const StringImpl& warning, Bf if ((int)mErrors.size() > 1) errorStart += StrFormat("(%d)", mErrors.size()); if (warningNumber > 0) - errorStart += StrFormat(": CS%04d", warningNumber); + errorStart += StrFormat(": BF%04d", warningNumber); MessageAt(":warn", errorStart + ": " + warning, bfParser, srcIdx); } return errorVal; @@ -3334,7 +3338,8 @@ BF_EXPORT int BF_CALLTYPE BfPassInstance_GetErrorCount(BfPassInstance* bfPassIns return (int)bfPassInstance->mErrors.size(); } -BF_EXPORT const char* BF_CALLTYPE BfPassInstance_GetErrorData(BfPassInstance* bfPassInstance, int errorIdx, bool& outIsWarning, bool& outIsAfter, bool& outIsDeferred, bool& outIsWhileSpecializing, bool& outIsPersistent, int& outSrcStart, int& outSrcEnd, int& outMoreInfoCount) +BF_EXPORT const char* BF_CALLTYPE BfPassInstance_GetErrorData(BfPassInstance* bfPassInstance, int errorIdx, int& outCode, bool& outIsWarning, bool& outIsAfter, bool& outIsDeferred, bool& outIsWhileSpecializing, bool& outIsPersistent, + char*& projectName, char*& fileName, int& outSrcStart, int& outSrcEnd, int* outLine, int* outColumn, int& outMoreInfoCount) { BfError* bfError = bfPassInstance->mErrors[errorIdx]; outIsWarning = bfError->mIsWarning; @@ -3342,13 +3347,33 @@ BF_EXPORT const char* BF_CALLTYPE BfPassInstance_GetErrorData(BfPassInstance* bf outIsDeferred = bfError->mIsDeferred; outIsWhileSpecializing = bfError->mIsWhileSpecializing; outIsPersistent = bfError->mIsPersistent; + outCode = bfError->mWarningNumber; + if (bfError->mProject != NULL) + projectName = (char*)bfError->mProject->mName.c_str(); + if (bfError->mSource != NULL) + { + String* srcFileName; + if (bfPassInstance->mSourceFileNameMap.TryGetValue(bfError->mSource, &srcFileName)) + { + fileName = (char*)srcFileName->c_str(); + } + + if (outLine != NULL) + { + auto parserData = bfError->mSource->ToParserData(); + if (parserData != NULL) + { + parserData->GetLineCharAtIdx(bfError->mSrcStart, *outLine, *outColumn); + } + } + } outSrcStart = bfError->mSrcStart; outSrcEnd = bfError->mSrcEnd; outMoreInfoCount = (int)bfError->mMoreInfo.size(); return bfError->mError.c_str(); } -BF_EXPORT const char* BfPassInstance_Error_GetMoreInfoData(BfPassInstance* bfPassInstance, int errorIdx, int moreInfoIdx, char*& fileName, int& srcStart, int& srcEnd) +BF_EXPORT const char* BfPassInstance_Error_GetMoreInfoData(BfPassInstance* bfPassInstance, int errorIdx, int moreInfoIdx, char*& fileName, int& srcStart, int& srcEnd, int* outLine, int* outColumn) { BfError* rootError = bfPassInstance->mErrors[errorIdx]; BfMoreInfo* moreInfo = rootError->mMoreInfo[moreInfoIdx]; diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 253bf114..c0aea511 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -1114,17 +1114,19 @@ public: bool mIsPersistent; bool mIsWhileSpecializing; bool mIgnore; + BfProject* mProject; String mError; int mWarningNumber; Array mMoreInfo; public: BfError() - { + { mIsAfter = false; mIsPersistent = false; mIsWhileSpecializing = false; mIgnore = false; + mProject = NULL; mWarningNumber = 0; }