/// <summary> /// This function is the callback used to execute the command when the menu item is clicked. /// See the constructor to see how the menu item is associated with this function using /// OleMenuCommandService service and MenuCommand class. /// </summary> /// <param name="sender">Event sender.</param> /// <param name="e">Event args.</param> protected override void MenuItemCallback(object sender, EventArgs e) { var settings = (FormatterOptionsPage)Package.GetDialogPage(typeof(FormatterOptionsPage)); // Try to find absolute paths var document = VSUtils.GetDTE().ActiveDocument; var project = document.ProjectItem?.ContainingProject; if (project == null) { Output.Instance.WriteLine("The document '{0}' is not part of a project.", document.Name); } var includeDirectories = VSUtils.GetProjectIncludeDirectories(project); // Read. var viewHost = VSUtils.GetCurrentTextViewHost(); var selectionSpan = GetSelectionSpan(viewHost); // Format string formatedText = Formatter.IncludeFormatter.FormatIncludes(selectionSpan.GetText(), document.FullName, includeDirectories, settings); // Overwrite. using (var edit = viewHost.TextView.TextBuffer.CreateEdit()) { edit.Replace(selectionSpan, formatedText); edit.Apply(); } }
private static void OnBuildConfigFinished(vsBuildScope Scope, vsBuildAction Action) { ThreadHelper.ThrowIfNotOnUIThread(); // Sometimes we get this message several times. if (!CompilationOngoing) { return; } // Parsing maybe successful for an unsuccessful build! bool successfulParsing = true; try { string outputText = VSUtils.GetOutputText(); if (string.IsNullOrEmpty(outputText)) { successfulParsing = false; return; } // What we're building right now is a tree. // However, combined with the existing data it might be a wide graph. var includeTreeItemStack = new Stack <IncludeGraph.GraphItem>(); includeTreeItemStack.Push(graphBeingExtended.CreateOrGetItem(documentBeingCompiled.FullName, out _)); var includeDirectories = VSUtils.GetProjectIncludeDirectories(documentBeingCompiled.ProjectItem.ContainingProject); includeDirectories.Insert(0, PathUtil.Normalize(documentBeingCompiled.Path) + Path.DirectorySeparatorChar); const string includeNoteString = "Note: including file: "; string[] outputLines = System.Text.RegularExpressions.Regex.Split(outputText, "\r\n|\r|\n"); // yes there are actually \r\n in there in some VS versions. foreach (string line in outputLines) { int startIndex = line.IndexOf(includeNoteString); if (startIndex < 0) { continue; } startIndex += includeNoteString.Length; int includeStartIndex = startIndex; while (includeStartIndex < line.Length && line[includeStartIndex] == ' ') { ++includeStartIndex; } int depth = includeStartIndex - startIndex; if (depth >= includeTreeItemStack.Count) { includeTreeItemStack.Push(includeTreeItemStack.Peek().Includes.Last().IncludedFile); } while (depth < includeTreeItemStack.Count - 1) { includeTreeItemStack.Pop(); } string fullIncludePath = line.Substring(includeStartIndex); IncludeGraph.GraphItem includedItem = graphBeingExtended.CreateOrGetItem(fullIncludePath, out _); includeTreeItemStack.Peek().Includes.Add(new IncludeGraph.Include() { IncludedFile = includedItem }); } } catch (Exception e) { _ = Output.Instance.ErrorMsg("Failed to parse output from /showInclude compilation of file '{0}': {1}", documentBeingCompiled.FullName, e); successfulParsing = false; return; } finally { _ = onCompleted(graphBeingExtended, documentBeingCompiled, successfulParsing); _ = ResetPendingCompilationInfo(); } }
/// <summary> /// Runs iwyu. Blocks until finished. /// </summary> static public string RunIncludeWhatYouUse(string fullFileName, EnvDTE.Project project, IncludeWhatYouUseOptionsPage settings) { string reasonForFailure; string preprocessorDefintions = VSUtils.VCUtils.GetCompilerSetting_PreprocessorDefinitions(project, out reasonForFailure); if (preprocessorDefintions == null) { Output.Instance.ErrorMsg("Can't run IWYU: {0}", reasonForFailure); return(null); } string output = ""; using (var process = new System.Diagnostics.Process()) { process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.FileName = settings.ExecutablePath; // Clang options // Disable all diagnostics var iwyuOptions = "-w "; // ... despite of that "invalid token paste" comes through a lot. Disable it. iwyuOptions += "-Wno-invalid-token-paste "; // Assume C++14 // arguments += "-std=c++14 "; // MSVC specific. See https://clang.llvm.org/docs/UsersManual.html#microsoft-extensions iwyuOptions += "-fms-extensions -fms-compatibility -fdelayed-template-parsing "; iwyuOptions += $"-fmsc-version={VSUtils.GetMSCVerString()} "; // Architecture var targetMachine = VSUtils.VCUtils.GetLinkerSetting_TargetMachine(project, out reasonForFailure); if (!targetMachine.HasValue) { Output.Instance.ErrorMsg("Failed to query for target machine: {0}", reasonForFailure); } else { switch (targetMachine.Value) { // Most targets give an error of this form: // "error: unknown target CPU 'x86'" // It seems iwyu is only really fine with x86-64 /*case VCProjectUtils.Base.TargetMachineType.X86: * clangOptions += "-march=x86 "; * break;*/ case VCProjectUtils.Base.TargetMachineType.AMD64: iwyuOptions += "-march=x86-64 "; break; /*case VCProjectUtils.Base.TargetMachineType.ARM: * clangOptions += "-march=arm "; * break; * case VCProjectUtils.Base.TargetMachineType.MIPS: * clangOptions += "-march=mips "; * break; * case VCProjectUtils.Base.TargetMachineType.THUMB: * clangOptions += "-march=thumb "; * break;*/ } } iwyuOptions += "-Xiwyu --verbose=" + settings.LogVerbosity + " "; if (settings.MappingFiles.Length == 0) { settings.MappingFiles = new string[] { "stl.c.headers.imp", "msvc.imp", "boost-all.imp", "boost-all-private.imp" }; } for (int i = 0; i < settings.MappingFiles.Length; ++i) { iwyuOptions += "-Xiwyu --mapping_file=\"" + settings.MappingFiles[i] + "\" "; } if (settings.NoDefaultMappings) { iwyuOptions += "-Xiwyu --no_default_mappings "; } if (settings.PCHInCode) { iwyuOptions += "-Xiwyu --pch_in_code "; } switch (settings.PrefixHeaderIncludes) { case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Add: iwyuOptions += "-Xiwyu --prefix_header_includes=add "; break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Remove: iwyuOptions += "-Xiwyu --prefix_header_includes=remove "; break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Keep: iwyuOptions += "-Xiwyu --prefix_header_includes=keep "; break; } if (settings.TransitiveIncludesOnly) { iwyuOptions += "-Xiwyu --transitive_includes_only "; } // Set max line length so something large so we don't loose comment information. // Documentation: // --max_line_length: maximum line length for includes. Note that this only affects comments and alignment thereof, // the maximum line length can still be exceeded with long file names(default: 80). iwyuOptions += "-Xiwyu --max_line_length=1024 "; // Include-paths and Preprocessor. var includeEntries = VSUtils.GetProjectIncludeDirectories(project, false); var includes = includeEntries.Aggregate("", (current, inc) => current + ("-I \"" + Regex.Escape(inc) + "\" ")); var defines = " -D " + string.Join(" -D", preprocessorDefintions.Split(';')); // write support file. Long argument lists lead to an error. Support files are the solution here. // https://github.com/Wumpf/IncludeToolbox/issues/36 var supportFile = Path.GetTempFileName(); var supportContent = includes + " " + defines + " " + Regex.Escape(fullFileName); File.WriteAllText(supportFile, supportContent); process.StartInfo.Arguments = $"{iwyuOptions} {settings.AdditionalParameters} @{supportFile}"; Output.Instance.Write("Running command '{0}' with following arguments:\n{1}\n\n", process.StartInfo.FileName, process.StartInfo.Arguments); // Start the child process. process.EnableRaisingEvents = true; process.OutputDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.ErrorDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); process.CancelOutputRead(); process.CancelErrorRead(); } output = Regex.Replace(output, @"#include <moduleworks_dummy.*?>.*?\n", ""); return(output); }
static private void ApplyTasks(Dictionary <string, FormatTask> tasks, bool applyFormatting, FormatterOptionsPage formatSettings) { var dte = VSUtils.GetDTE(); foreach (KeyValuePair <string, FormatTask> entry in tasks) { string filename = entry.Key.Replace('/', '\\'); // Classy. But Necessary. EnvDTE.Window fileWindow = dte.ItemOperations.OpenFile(filename); if (fileWindow == null) { Output.Instance.ErrorMsg("Failed to open File {0}", filename); continue; } fileWindow.Activate(); var viewHost = VSUtils.GetCurrentTextViewHost(); using (var edit = viewHost.TextView.TextBuffer.CreateEdit()) { var originalLines = edit.Snapshot.Lines.ToArray(); // Determine which line ending to use by majority. string lineEndingToBeUsed = Utils.GetDominantNewLineSeparator(edit.Snapshot.GetText()); // Add lines. { // Find last include. // Will find even if commented out, but we don't care. int lastIncludeLine = -1; for (int line = originalLines.Length - 1; line >= 0; --line) { if (originalLines[line].GetText().Contains("#include")) { lastIncludeLine = line; break; } } // Build replacement string StringBuilder stringToInsertBuilder = new StringBuilder(); foreach (string lineToAdd in entry.Value.linesToAdd) { stringToInsertBuilder.Append(lineToAdd); stringToInsertBuilder.Append(lineEndingToBeUsed); } string stringToInsert = stringToInsertBuilder.ToString(); // optional, format before adding. if (applyFormatting) { var includeDirectories = VSUtils.GetProjectIncludeDirectories(fileWindow.Document.ProjectItem?.ContainingProject); stringToInsert = Formatter.IncludeFormatter.FormatIncludes(stringToInsert, fileWindow.Document.FullName, includeDirectories, formatSettings); // Add a newline if we removed it. if (formatSettings.RemoveEmptyLines) { stringToInsert += lineEndingToBeUsed; } } // Insert. int insertPosition = 0; if (lastIncludeLine >= 0 && lastIncludeLine < originalLines.Length) { insertPosition = originalLines[lastIncludeLine].EndIncludingLineBreak; } edit.Insert(insertPosition, stringToInsert.ToString()); } // Remove lines. // It should safe to do that last since we added includes at the bottom, this way there is no confusion with the text snapshot. { foreach (int lineToRemove in entry.Value.linesToRemove.Reverse()) { if (!Formatter.IncludeLineInfo.ContainsPreserveFlag(originalLines[lineToRemove].GetText())) { edit.Delete(originalLines[lineToRemove].ExtentIncludingLineBreak); } } } edit.Apply(); } // For Debugging: //Output.Instance.WriteLine(""); //Output.Instance.WriteLine(entry.Key); //Output.Instance.WriteLine(entry.Value.ToString()); } }
/// <summary> /// Runs iwyu. Blocks until finished. /// </summary> static public string RunIncludeWhatYouUse(string fullFileName, EnvDTE.Project project, IncludeWhatYouUseOptionsPage settings) { string reasonForFailure; string preprocessorDefintions = VSUtils.VCUtils.GetCompilerSetting_PreprocessorDefinitions(project, out reasonForFailure); if (preprocessorDefintions == null) { Output.Instance.ErrorMsg("Can't run IWYU: {0}", reasonForFailure); return(null); } string output = ""; using (var process = new System.Diagnostics.Process()) { process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.FileName = settings.ExecutablePath; process.StartInfo.Arguments = ""; // Include-paths and Preprocessor. var includeEntries = VSUtils.GetProjectIncludeDirectories(project, false); process.StartInfo.Arguments = includeEntries.Aggregate("", (current, inc) => current + ("-I \"" + inc + "\" ")); process.StartInfo.Arguments = preprocessorDefintions. Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries). Aggregate(process.StartInfo.Arguments, (current, def) => current + ("-D" + def + " ")); // Clang options // Disable all diagnostics process.StartInfo.Arguments += "-w "; // ... despite of that "invalid token paste" comes through a lot. Disable it. process.StartInfo.Arguments += "-Wno-invalid-token-paste "; // Assume C++14 process.StartInfo.Arguments += "-std=c++14 "; // MSVC specific. See https://clang.llvm.org/docs/UsersManual.html#microsoft-extensions process.StartInfo.Arguments += "-fms-compatibility -fms-extensions -fdelayed-template-parsing "; process.StartInfo.Arguments += $"-fmsc-version={VSUtils.GetMSCVerString()} "; // Architecture var targetMachine = VSUtils.VCUtils.GetLinkerSetting_TargetMachine(project, out reasonForFailure); if (!targetMachine.HasValue) { Output.Instance.ErrorMsg("Failed to query for target machine: {0}", reasonForFailure); } else { switch (targetMachine.Value) { // Most targets give an error of this form: // "error: unknown target CPU 'x86'" // It seems iwyu is only really fine with x86-64 /*case VCProjectUtils.Base.TargetMachineType.X86: * process.StartInfo.Arguments += "-march=x86 "; * break;*/ case VCProjectUtils.Base.TargetMachineType.AMD64: process.StartInfo.Arguments += "-march=x86-64 "; break; /*case VCProjectUtils.Base.TargetMachineType.ARM: * process.StartInfo.Arguments += "-march=arm "; * break; * case VCProjectUtils.Base.TargetMachineType.MIPS: * process.StartInfo.Arguments += "-march=mips "; * break; * case VCProjectUtils.Base.TargetMachineType.THUMB: * process.StartInfo.Arguments += "-march=thumb "; * break;*/ } } // icwyu options { process.StartInfo.Arguments += "-Xiwyu --verbose=" + settings.LogVerbosity + " "; for (int i = 0; i < settings.MappingFiles.Length; ++i) { process.StartInfo.Arguments += "-Xiwyu --mapping_file=\"" + settings.MappingFiles[i] + "\" "; } if (settings.NoDefaultMappings) { process.StartInfo.Arguments += "-Xiwyu --no_default_mappings "; } if (settings.PCHInCode) { process.StartInfo.Arguments += "-Xiwyu --pch_in_code "; } switch (settings.PrefixHeaderIncludes) { case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Add: process.StartInfo.Arguments += "-Xiwyu --prefix_header_includes=add "; break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Remove: process.StartInfo.Arguments += "-Xiwyu --prefix_header_includes=remove "; break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Keep: process.StartInfo.Arguments += "-Xiwyu --prefix_header_includes=keep "; break; } if (settings.TransitiveIncludesOnly) { process.StartInfo.Arguments += "-Xiwyu --transitive_includes_only "; } // Set max line length so something large so we don't loose comment information. // Documentation: // --max_line_length: maximum line length for includes. Note that this only affects comments and alignment thereof, // the maximum line length can still be exceeded with long file names(default: 80). process.StartInfo.Arguments += "-Xiwyu --max_line_length=1024 "; // Custom stuff. process.StartInfo.Arguments += settings.AdditionalParameters; process.StartInfo.Arguments += " "; } // Finally, the file itself. process.StartInfo.Arguments += "\""; process.StartInfo.Arguments += fullFileName; process.StartInfo.Arguments += "\""; Output.Instance.Write("Running command '{0}' with following arguments:\n{1}\n\n", process.StartInfo.FileName, process.StartInfo.Arguments); // Start the child process. process.EnableRaisingEvents = true; process.OutputDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.ErrorDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); process.CancelOutputRead(); process.CancelErrorRead(); } return(output); }
/// <summary> /// Runs iwyu. Blocks until finished. /// </summary> static public async Task <string> RunIncludeWhatYouUse(string fullFileName, EnvDTE.Project project, IncludeWhatYouUseOptionsPage settings) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); string preprocessorDefintions; try { preprocessorDefintions = VSUtils.VCUtils.GetCompilerSetting_PreprocessorDefinitions(project); } catch (VCQueryFailure e) { await Output.Instance.ErrorMsg("Can't run IWYU: {0}", e.Message); return(null); } string output = ""; using (var process = new System.Diagnostics.Process()) { process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.FileName = settings.ExecutablePath; // Clang options var clangOptionList = new List <string>(); // Disable all diagnostics clangOptionList.Add("-w"); // ... despite of that "invalid token paste" comes through a lot. Disable it. clangOptionList.Add("-Wno-invalid-token-paste"); // Assume C++14 clangOptionList.Add("-std=c++14"); // MSVC specific. See https://clang.llvm.org/docs/UsersManual.html#microsoft-extensions clangOptionList.Add("-fms-compatibility -fms-extensions -fdelayed-template-parsing"); clangOptionList.Add($"-fmsc-version={VSUtils.GetMSCVerString()}"); // Architecture try { switch (VSUtils.VCUtils.GetLinkerSetting_TargetMachine(project)) { // Most targets give an error of this form: // "error: unknown target CPU 'x86'" // It seems iwyu is only really fine with x86-64 /*case VCProjectUtils.Base.TargetMachineType.X86: * clangOptions.Add("-march=x86"); * break;*/ case VCHelper.TargetMachineType.AMD64: clangOptionList.Add("-march=x86-64"); break; /*case VCProjectUtils.Base.TargetMachineType.ARM: * clangOptions.Add("-march=arm"); * break; * case VCProjectUtils.Base.TargetMachineType.MIPS: * clangOptions.Add(""-march=mips"); * break; * case VCProjectUtils.Base.TargetMachineType.THUMB: * clangOptions.Add(""-march=thumb"); * break;*/ } } catch (VCQueryFailure e) { await Output.Instance.ErrorMsg($"Failed to query for target machine: {e.Message}"); } // icwyu options var iwyuOptionList = new List <string>(); iwyuOptionList.Add("--verbose=" + settings.LogVerbosity); for (int i = 0; i < settings.MappingFiles.Length; ++i) { iwyuOptionList.Add("--mapping_file=\"" + settings.MappingFiles[i] + "\""); } if (settings.NoDefaultMappings) { iwyuOptionList.Add("--no_default_mappings"); } if (settings.PCHInCode) { iwyuOptionList.Add("--pch_in_code"); } switch (settings.PrefixHeaderIncludes) { case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Add: iwyuOptionList.Add("--prefix_header_includes=add"); break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Remove: iwyuOptionList.Add("--prefix_header_includes=remove"); break; case IncludeWhatYouUseOptionsPage.PrefixHeaderMode.Keep: iwyuOptionList.Add("--prefix_header_includes=keep"); break; } if (settings.TransitiveIncludesOnly) { iwyuOptionList.Add("--transitive_includes_only"); } // Set max line length so something large so we don't loose comment information. // Documentation: // --max_line_length: maximum line length for includes. Note that this only affects comments and alignment thereof, // the maximum line length can still be exceeded with long file names(default: 80). iwyuOptionList.Add("--max_line_length=1024"); /// write support file with includes, defines and the targetgile. Long argument lists lead to an error. Support files are the solution here. /// https://github.com/Wumpf/IncludeToolbox/issues/36 // Include-paths and Preprocessor. var includes = string.Join(" ", VSUtils.GetProjectIncludeDirectories(project, false).Select(x => "-I \"" + x.Replace("\\", "\\\\") + "\"")); var defines = string.Join(" ", preprocessorDefintions.Split(';').Select(x => "-D" + x)); var filename = "\"" + fullFileName.Replace("\\", "\\\\") + "\""; var supportFilePath = Path.GetTempFileName(); File.WriteAllText(supportFilePath, includes + " " + defines + " " + filename); var clangOptions = string.Join(" ", clangOptionList); // each include-what-you-use parameter has an -Xiwyu prefix var iwyuOptions = string.Join(" ", iwyuOptionList.Select(x => " -Xiwyu " + x)); process.StartInfo.Arguments = $"{clangOptions} {iwyuOptions} {settings.AdditionalParameters} \"@{supportFilePath}\""; Output.Instance.Write("Running command '{0}' with following arguments:\n{1}\n\n", process.StartInfo.FileName, process.StartInfo.Arguments); // Start the child process. process.EnableRaisingEvents = true; process.OutputDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.ErrorDataReceived += (s, args) => { Output.Instance.WriteLine(args.Data); output += args.Data + "\n"; }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); process.CancelOutputRead(); process.CancelErrorRead(); } return(output); }
private static void OnBuildConfigFinished(vsBuildScope Scope, vsBuildAction Action) { // Sometimes we get this message several times. if (!CompilationOngoing) { return; } // Parsing maybe successful for an unsuccessful build! bool successfulParsing = true; try { string outputText = VSUtils.GetOutputText(); if (string.IsNullOrEmpty(outputText)) { successfulParsing = false; return; } // What we're building right now is a tree. // However, combined with the existing data it might be a wide graph. var includeTreeItemStack = new Stack <IncludeGraph.GraphItem>(); includeTreeItemStack.Push(graphBeingExtended.CreateOrGetItem(documentBeingCompiled.FullName, 0.0, out _)); var includeDirectories = VSUtils.GetProjectIncludeDirectories(documentBeingCompiled.ProjectItem.ContainingProject); includeDirectories.Insert(0, PathUtil.Normalize(documentBeingCompiled.Path) + Path.DirectorySeparatorChar); const string includeHeadersString = "Include Headers:"; string[] outputLines = System.Text.RegularExpressions.Regex.Split(outputText, "\r\n|\r|\n"); // yes there are actually \r\n in there in some VS versions. /* * mode: * - 0 means not in a parsing mode * - 1 means parsing 'Include Headers:' section */ int mode = 0; for (int line_index = 0; line_index < outputLines.Count(); line_index++) { string line = outputLines[line_index]; // keeping track parsing state if (mode == 0) { if (line.IndexOf(includeHeadersString) >= 0) { mode = 1; continue; } // hack we do not support other states yet continue; } line = CleanString(line); int count = ParseInt(line, "Count:"); for (int include_line_index = 0; include_line_index < count; include_line_index++) { line_index++; string include_line = outputLines[line_index]; include_line = CleanString(include_line); int depth = include_line.Count(f => f == '\t') - 1; if (depth >= includeTreeItemStack.Count) { includeTreeItemStack.Push(includeTreeItemStack.Peek().Includes.Last().IncludedFile); } while (depth < includeTreeItemStack.Count - 1) { includeTreeItemStack.Pop(); } var filename_and_time = GetFilenameAndTime(include_line); IncludeGraph.GraphItem includedItem = graphBeingExtended.CreateOrGetItem(filename_and_time.filename, filename_and_time.time, out _); includeTreeItemStack.Peek().Includes.Add(new IncludeGraph.Include() { IncludedFile = includedItem }); } mode = 0; } } catch (Exception e) { Output.Instance.ErrorMsg("Failed to parse output from -d1reportTime compilation of file '{0}': {1}", documentBeingCompiled.FullName, e); successfulParsing = false; return; } finally { try { onCompleted(graphBeingExtended, successfulParsing); } finally { ResetPendingCompilationInfo(); } } }