示例#1
0
        /// <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();
            }
        }
示例#2
0
        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();
            }
        }
示例#3
0
        /// <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);
        }
示例#4
0
        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());
            }
        }
示例#5
0
        /// <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);
        }
示例#6
0
        /// <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();
                }
            }
        }