Beispiel #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();
            }
        }
Beispiel #2
0
        public override async Task NavigateToInclude()
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            // Want to navigate to origin of this include, not target if possible
            if (includingFileAbsoluteFilename != null && Path.IsPathRooted(includingFileAbsoluteFilename))
            {
                var fileWindow = VSUtils.OpenFileAndShowDocument(includingFileAbsoluteFilename);

                // Try to move to carret if possible.
                if (include.IncludeLine != null)
                {
                    var textDocument = fileWindow.Document.Object() as EnvDTE.TextDocument;

                    if (textDocument != null)
                    {
                        var includeLinePoint = textDocument.StartPoint.CreateEditPoint();
                        includeLinePoint.MoveToLineAndOffset(include.IncludeLine.LineNumber + 1, 1);
                        includeLinePoint.TryToShow();

                        textDocument.Selection.MoveToPoint(includeLinePoint);
                    }
                }
            }
        }
Beispiel #3
0
 public override void NavigateToInclude()
 {
     if (AbsoluteFilename != null && Path.IsPathRooted(AbsoluteFilename))
     {
         var fileWindow = VSUtils.OpenFileAndShowDocument(AbsoluteFilename);
     }
 }
        static Project GetSelectedCppProject(out string reasonForFailure)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            reasonForFailure = "";

            var selectedItems = VSUtils.GetDTE().SelectedItems;

            if (selectedItems.Count < 1)
            {
                reasonForFailure = "Selection is empty!";
                return(null);
            }

            // Reading .Item(object) behaves weird, but iterating works.
            foreach (SelectedItem item in selectedItems)
            {
                Project vcProject = item?.Project;
                if (VSUtils.VCUtils.IsVCProject(vcProject))
                {
                    return(vcProject);
                }
            }

            reasonForFailure = "Selection does not contain a C++ project!";
            return(null);
        }
Beispiel #5
0
        private async Task PerformanceTrialAndErrorRemovel()
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            List <string> proNames = new List <string>();

            vcProjects.Clear();
            Projects allProjs = VSUtils.GetDTE().Solution.Projects;

            foreach (Project proj in allProjs)
            {
                if (VSUtils.VCUtils.IsVCProject(proj))
                {
                    proNames.Add(proj.Name);
                    vcProjects.Enqueue(proj);
                }
            }
            {// to delete
                Utils.SaveProjectsConfig(proNames);
            }

            if (await Output.Instance.YesNoMsg("Attention! Trial and error include removal on large solution make take up to several hours! In this time you will not be able to use Visual Studio. Are you sure you want to continue?")
                != Output.MessageResult.Yes)
            {
                return;
            }

            numTotoalProcessedFiles = 0;
            numTotalRemovedIncludes = 0;

            await ProcessNextProject();
        }
        private void UpdateVisibility(object sender, EventArgs e)
        {
            // Needs to be part of a VCProject to be applicable.
            var document = VSUtils.GetDTE()?.ActiveDocument;

            menuCommand.Visible = VSUtils.VCUtils.IsVCProject(document?.ProjectItem?.ContainingProject);
        }
Beispiel #7
0
        public static async Task <BoolWithReason> CanPerformShowIncludeCompilation(Document document)
        {
            if (CompilationOngoing)
            {
                return(new BoolWithReason
                {
                    Result = false,
                    Reason = "Can't compile while another file is being compiled.",
                });
            }

            var dte = VSUtils.GetDTE();

            if (dte == null)
            {
                return(new BoolWithReason
                {
                    Result = false,
                    Reason = "Failed to acquire dte object.",
                });
            }

            var result = await VSUtils.VCUtils.IsCompilableFile(document);

            if (result.Result == false)
            {
                result.Reason = $"Can't extract include graph since current file '{document?.FullName ?? "<no file>"}' can't be compiled: {result.Reason}.";
                return(result);
            }

            return(new BoolWithReason {
                Result = true, Reason = ""
            });
        }
        private void UpdateVisibility(object sender, EventArgs e)
        {
            string reason;
            bool   isHeader;
            var    config = CompileUnityFile.GetFileConfig(VSUtils.GetDTE().ActiveDocument, out reason, out isHeader);

            menuCommand.Visible = (config != null) && !isHeader;
        }
Beispiel #9
0
        private void UpdateVisibility(object sender, EventArgs e)
        {
            // Check whether any includes are selected.
            var viewHost      = VSUtils.GetCurrentTextViewHost();
            var selectionSpan = GetSelectionSpan(viewHost);
            var lines         = Formatter.IncludeLineInfo.ParseIncludes(selectionSpan.GetText(), Formatter.ParseOptions.RemoveEmptyLines);

            menuCommand.Visible = lines.Any(x => x.ContainsActiveInclude);
        }
Beispiel #10
0
        public override async Task NavigateToInclude()
        {
            if (AbsoluteFilename != null && Path.IsPathRooted(AbsoluteFilename))
            {
                await Microsoft.VisualStudio.Shell.ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                var fileWindow = VSUtils.OpenFileAndShowDocument(AbsoluteFilename);
            }
        }
Beispiel #11
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 async Task MenuItemCallback(object sender, EventArgs e)
        {
            var document = VSUtils.GetDTE().ActiveDocument;

            if (document != null)
            {
                await impl.PerformTrialAndErrorIncludeRemoval(document, (TrialAndErrorRemovalOptionsPage)Package.GetDialogPage(typeof(TrialAndErrorRemovalOptionsPage)));
            }
        }
Beispiel #12
0
        protected override void MenuItemCallback(object sender, EventArgs e)
        {
            if (viewModel == null)
            {
                return;
            }

            if (viewModel.NumIncludes <= 0)
            {
                Output.Instance.ErrorMsg("There is no include tree to save!");
                return;
            }

            // Show save dialog.
            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
            dlg.FileName   = ".dgml";
            dlg.DefaultExt = ".dgml";
            dlg.Filter     = "Text documents (.dgml)|*.dgml";
            bool?result = dlg.ShowDialog();

            // Process save file dialog box results
            if (result ?? false)
            {
                var       settings = (ViewerOptionsPage)IncludeToolboxPackage.Instance.GetDialogPage(typeof(ViewerOptionsPage));
                DGMLGraph dgmlGraph;

                try
                {
                    dgmlGraph = viewModel.Graph.ToDGMLGraph(settings.CreateGroupNodesForFolders, settings.ExpandFolderGroupNodes);
                    if (settings.ColorCodeNumTransitiveIncludes)
                    {
                        dgmlGraph.ColorizeByTransitiveChildCount(settings.NoChildrenColor, settings.MaxChildrenColor);
                    }
                }
                catch
                {
                    Output.Instance.ErrorMsg($"Failed to create dgml graph.");
                    return;
                }

                try
                {
                    dgmlGraph.Serialize(dlg.FileName);
                }
                catch
                {
                    Output.Instance.ErrorMsg($"Failed to safe dgml to {dlg.FileName}.");
                    return;
                }

                if (Output.Instance.YesNoMsg("Saved dgml successfully. Do you want to open it in Visual Studio?") == Output.MessageResult.Yes)
                {
                    VSUtils.OpenFileAndShowDocument(dlg.FileName);
                }
            }
        }
        private static void ResetPendingCompilationInfo()
        {
            string reasonForFailure;

            VSUtils.VCUtils.SetCompilerSetting_ShowIncludes(documentBeingCompiled.ProjectItem?.ContainingProject, showIncludeSettingBefore, out reasonForFailure);

            onCompleted           = null;
            documentBeingCompiled = null;
            graphBeingExtended    = null;

            VSUtils.GetDTE().Events.BuildEvents.OnBuildDone -= OnBuildConfigFinished;
        }
        /// <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 document = VSUtils.GetDTE().ActiveDocument;

            if (document != null)
            {
                try
                {
                    impl.PerformCompileUnityFile(document);
                }
                catch (Exception ex)
                {
                    Output.Instance.WriteLine("Unexpected error: {0}", ex);
                }
            }
        }
        public static void AddCommandFilter(IVsTextView viewAdapter, VSUtils.IMenuCommand commandFilter)
        {
            if (!commandFilter.IsAdded)
            {
                // Get the view adapter from the editor factory
                IOleCommandTarget next;
                int hr = viewAdapter.AddCommandFilter(commandFilter, out next);

                if (hr == VSConstants.S_OK)
                {
                    commandFilter.IsAdded = true;
                    // You'll need the next target for Exec and QueryStatus
                    if (next != null) commandFilter.NextTarget = next;
                }
            }
        }
Beispiel #16
0
        private static async Task ResetPendingCompilationInfo()
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            try
            {
                VSUtils.VCUtils.SetCompilerSetting_ShowIncludes(documentBeingCompiled.ProjectItem?.ContainingProject, showIncludeSettingBefore);
            }
            catch (VCQueryFailure) { }

            onCompleted           = null;
            documentBeingCompiled = null;
            graphBeingExtended    = null;

            VSUtils.GetDTE().Events.BuildEvents.OnBuildDone -= OnBuildConfigFinished;
        }
Beispiel #17
0
        private void NavigateProjectFolder(ProjectItems itemCollection)
        {
            if (itemCollection == null)
            {
                return;
            }

            // ================================================================================
            // Navigate through the solution structure and determine whether
            // valid projects exist that we can add.
            // ================================================================================
            foreach (ProjectItem item in itemCollection)
            {
                if (item.SubProject != null)
                {
                    if (VSUtils.IsValidSolutionProject(item.SubProject.Kind))
                    {
                        if (item.SubProject == null)
                        {
                            continue;
                        }
                        else if (item.SubProject is Project)
                        {
                            ISolutionProject subProject = new VSSolutionProject(this._solution, item.SubProject);
                            this._solution.AddProject(subProject);
                        }
                    }
                    else
                    {
                        NavigateProjectFolder(item.SubProject.ProjectItems);
                    }
                }
                else
                {
                    if (item.Object == null)
                    {
                        continue;
                    }
                    else if (item.Object is Project)
                    {
                        ISolutionProject solutionProject = new VSSolutionProject(this._solution, item.Object as Project);
                        this._solution.AddProject(solutionProject);
                    }
                }
            }
        }
        public static bool CanPerformShowIncludeCompilation(Document document, out string reasonForFailure)
        {
            if (CompilationOngoing)
            {
                reasonForFailure = "Can't compile while another file is being compiled.";
                return(false);
            }

            var dte = VSUtils.GetDTE();

            if (dte == null)
            {
                reasonForFailure = "Failed to acquire dte object.";
                return(false);
            }

            if (VSUtils.VCUtils.IsCompilableFile(document, out reasonForFailure) == false)
            {
                reasonForFailure = string.Format("Can't extract BuildTime graph since current file '{0}' can't be compiled: {1}.", document?.FullName ?? "<no file>", reasonForFailure);
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Parses a given source file using cl.exe with the /showIncludes option and adds the output to the original graph.
        /// </summary>
        /// <remarks>
        /// If this is the first file, the graph is necessarily a tree after this operation.
        /// </remarks>
        /// <returns>true if successful, false otherwise.</returns>
        public static bool AddIncludesRecursively_ShowIncludesCompilation(this IncludeGraph graph, Document document, OnCompleteCallback onCompleted)
        {
            if (!CanPerformShowIncludeCompilation(document, out string reasonForFailure))
            {
                Output.Instance.ErrorMsg(reasonForFailure);
                return(false);
            }

            try
            {
                var dte = VSUtils.GetDTE();
                if (dte == null)
                {
                    Output.Instance.ErrorMsg("Failed to acquire dte object.");
                    return(false);
                }

                {
                    bool?setting = VSUtils.VCUtils.GetCompilerSetting_ShowIncludes(document.ProjectItem?.ContainingProject, out reasonForFailure);
                    if (!setting.HasValue)
                    {
                        Output.Instance.ErrorMsg("Can't compile with show includes: {0}.", reasonForFailure);
                        return(false);
                    }
                    else
                    {
                        showIncludeSettingBefore = setting.Value;
                    }

                    VSUtils.VCUtils.SetCompilerSetting_ShowIncludes(document.ProjectItem?.ContainingProject, true, out reasonForFailure);
                    if (!string.IsNullOrEmpty(reasonForFailure))
                    {
                        Output.Instance.ErrorMsg("Can't compile with show includes: {0}.", reasonForFailure);
                        return(false);
                    }
                }

                // Only after we're through all early out error cases, set static compilation infos.
                dte.Events.BuildEvents.OnBuildDone               += OnBuildConfigFinished;
                CompilationBasedGraphParser.onCompleted           = onCompleted;
                CompilationBasedGraphParser.documentBeingCompiled = document;
                CompilationBasedGraphParser.graphBeingExtended    = graph;

                // Even with having the config changed and having compile force==true, we still need to make a dummy change in order to enforce recompilation of this file.
                {
                    document.Activate();
                    var documentTextView = VSUtils.GetCurrentTextViewHost();
                    var textBuffer       = documentTextView.TextView.TextBuffer;
                    using (var edit = textBuffer.CreateEdit())
                    {
                        edit.Insert(0, " ");
                        edit.Apply();
                    }
                    using (var edit = textBuffer.CreateEdit())
                    {
                        edit.Replace(new Microsoft.VisualStudio.Text.Span(0, 1), "");
                        edit.Apply();
                    }
                }

                VSUtils.VCUtils.CompileSingleFile(document);
            }
            catch (Exception e)
            {
                ResetPendingCompilationInfo();
                Output.Instance.ErrorMsg("Compilation of file '{0}' with /showIncludes failed: {1}.", document.FullName, e);
                return(false);
            }

            return(true);
        }
        private void UpdateVisibility(object sender, EventArgs e)
        {
            string reason;

            menuCommand.Visible = VSUtils.VCUtils.IsCompilableFile(VSUtils.GetDTE().ActiveDocument, out reason);
        }
        /// <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 async Task MenuItemCallback(object sender, EventArgs e)
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            var settingsIwyu = (IncludeWhatYouUseOptionsPage)Package.GetDialogPage(typeof(IncludeWhatYouUseOptionsPage));

            Output.Instance.Clear();

            var document = VSUtils.GetDTE().ActiveDocument;

            if (document == null)
            {
                Output.Instance.WriteLine("No active document!");
                return;
            }
            var project = document.ProjectItem?.ContainingProject;

            if (project == null)
            {
                Output.Instance.WriteLine("The document {0} is not part of a project.", document.Name);
                return;
            }

            var dialogFactory = ServiceProvider.GetService(typeof(SVsThreadedWaitDialogFactory)) as IVsThreadedWaitDialogFactory;

            if (dialogFactory == null)
            {
                Output.Instance.WriteLine("Failed to get IVsThreadedWaitDialogFactory service.");
                return;
            }

            await OptionalDownloadOrUpdate(settingsIwyu, dialogFactory);

            // We should really have it now, but just in case our update or download method screwed up.
            if (!File.Exists(settingsIwyu.ExecutablePath))
            {
                await Output.Instance.ErrorMsg("Unexpected error: Can't find include-what-you-use.exe after download/update.");

                return;
            }
            checkedForUpdatesThisSession = true;

            // Save all documents.
            try
            {
                document.DTE.Documents.SaveAll();
            }
            catch (Exception saveException)
            {
                Output.Instance.WriteLine("Failed to get save all documents: {0}", saveException);
            }

            // Start wait dialog.
            {
                IVsThreadedWaitDialog2 dialog = null;
                dialogFactory.CreateInstance(out dialog);
                dialog?.StartWaitDialog("Include Toolbox", "Running include-what-you-use", null, null, "Running include-what-you-use", 0, false, true);

                string output = await IWYU.RunIncludeWhatYouUse(document.FullName, project, settingsIwyu);

                if (settingsIwyu.ApplyProposal && output != null)
                {
                    var settingsFormatting = (FormatterOptionsPage)Package.GetDialogPage(typeof(FormatterOptionsPage));
                    await IWYU.Apply(output, settingsIwyu.RunIncludeFormatter, settingsFormatting);
                }

                dialog?.EndWaitDialog();
            }
        }
Beispiel #22
0
 private async void UpdateVisibility(object sender, EventArgs e)
 {
     menuCommand.Visible = (await VSUtils.VCUtils.IsCompilableFile(VSUtils.GetDTE().ActiveDocument)).Result;
 }
Beispiel #23
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);
        }
Beispiel #24
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);
        }
        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();
                }
            }
        }
Beispiel #26
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();
            }
        }
Beispiel #27
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());
            }
        }
Beispiel #28
0
        /// <summary>
        /// Parses a given source file using cl.exe with the /showIncludes option and adds the output to the original graph.
        /// </summary>
        /// <remarks>
        /// If this is the first file, the graph is necessarily a tree after this operation.
        /// </remarks>
        /// <returns>true if successful, false otherwise.</returns>
        public static async Task <bool> AddIncludesRecursively_ShowIncludesCompilation(this IncludeGraph graph, Document document, OnCompleteCallback onCompleted)
        {
            var canPerformShowIncludeCompilation = await CanPerformShowIncludeCompilation(document);

            if (!canPerformShowIncludeCompilation.Result)
            {
                await Output.Instance.ErrorMsg(canPerformShowIncludeCompilation.Reason);

                return(false);
            }

            try
            {
                var dte = VSUtils.GetDTE();
                if (dte == null)
                {
                    await Output.Instance.ErrorMsg("Failed to acquire dte object.");

                    return(false);
                }

                try
                {
                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                    showIncludeSettingBefore = VSUtils.VCUtils.GetCompilerSetting_ShowIncludes(document.ProjectItem?.ContainingProject);
                    VSUtils.VCUtils.SetCompilerSetting_ShowIncludes(document.ProjectItem?.ContainingProject, true);
                }
                catch (VCQueryFailure queryFailure)
                {
                    await Output.Instance.ErrorMsg("Can't compile with show includes: {0}.", queryFailure.Message);

                    return(false);
                }

                // Only after we're through all early out error cases, set static compilation infos.
                dte.Events.BuildEvents.OnBuildDone               += OnBuildConfigFinished;
                CompilationBasedGraphParser.onCompleted           = onCompleted;
                CompilationBasedGraphParser.documentBeingCompiled = document;
                CompilationBasedGraphParser.graphBeingExtended    = graph;

                // Even with having the config changed and having compile force==true, we still need to make a dummy change in order to enforce recompilation of this file.
                {
                    document.Activate();
                    var documentTextView = VSUtils.GetCurrentTextViewHost();
                    var textBuffer       = documentTextView.TextView.TextBuffer;
                    using (var edit = textBuffer.CreateEdit())
                    {
                        edit.Insert(0, " ");
                        edit.Apply();
                    }
                    using (var edit = textBuffer.CreateEdit())
                    {
                        edit.Replace(new Microsoft.VisualStudio.Text.Span(0, 1), "");
                        edit.Apply();
                    }
                }

                await VSUtils.VCUtils.CompileSingleFile(document);
            }
            catch (Exception e)
            {
                await ResetPendingCompilationInfo();

                await Output.Instance.ErrorMsg("Compilation of file '{0}' with /showIncludes failed: {1}.", document.FullName, e);

                return(false);
            }

            return(true);
        }
Beispiel #29
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);
        }