/// <see cref="AddIncludesRecursively_ManualParsing(IncludeGraph, string, string, IEnumerable{string})"/>
        public static void AddIncludesRecursively_ManualParsing(this IncludeGraph graph, string filename, IEnumerable <string> includeDirectories, IEnumerable <string> nonParseDirectories)
        {
            var graphItem = graph.CreateOrGetItem(filename, out bool isNewGraphItem);

            if (!isNewGraphItem)
            {
                return;
            }

            ParseIncludesRecursively(graph, graphItem, File.ReadAllText(filename), includeDirectories, nonParseDirectories);
        }
        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;
        }
Beispiel #3
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;
        }
        static public DGMLGraph ToDGMLGraph(this IncludeGraph graph, bool folderGrouping, bool expandGroups)
        {
            var uniqueTransitiveChildrenMap = FindUniqueChildren(graph.GraphItems);

            DGMLGraph dgmlGraph = new DGMLGraph();

            foreach (GraphItem node in graph.GraphItems)
            {
                dgmlGraph.Nodes.Add(new DGMLGraph.Node
                {
                    Id          = node.AbsoluteFilename,
                    Label       = node.FormattedName,
                    Background  = null,
                    NumIncludes = node.Includes.Count,
                    NumUniqueTransitiveChildren = uniqueTransitiveChildrenMap[node].Count,
                });
                foreach (Include include in node.Includes)
                {
                    dgmlGraph.Links.Add(new DGMLGraph.Link {
                        Source = node.AbsoluteFilename, Target = include.IncludedFile?.AbsoluteFilename ?? null
                    });
                }
            }

            if (folderGrouping)
            {
                // Reusing a ViewModel datastructure is arguably a bit ugly, but it matches exactly what we want.
                // TODO: Consider splitting functionallity out.
                var folderGroupingRoot = new FolderIncludeTreeViewItem_Root(graph.GraphItems, null);
                foreach (var child in folderGroupingRoot.Children)
                {
                    AddFolderGroupingRecursive(dgmlGraph, child, null, expandGroups);
                }
            }


            return(dgmlGraph);
        }
        private static void ParseIncludesRecursively(IncludeGraph graph, IncludeGraph.GraphItem parentItem, string fileContent, IEnumerable <string> includeDirectories, IEnumerable <string> nonParseDirectories)
        {
            string currentDirectory            = Path.GetDirectoryName(parentItem.AbsoluteFilename);
            var    includeDirectoriesPlusLocal = includeDirectories.Prepend(currentDirectory);

            var includes = Formatter.IncludeLineInfo.ParseIncludes(fileContent, Formatter.ParseOptions.KeepOnlyValidIncludes);

            foreach (var includeLine in includes)
            {
                // Try to resolve the include (may fail)
                string resolvedInclude = includeLine.TryResolveInclude(includeDirectoriesPlusLocal, out bool successfullyResolved);
                // Create a link to the file in any case now even if resolving was unsuccessful.
                var includedFile = graph.CreateOrGetItem_AbsoluteNormalizedPath(resolvedInclude, out bool isNewGraphItem);

                if (successfullyResolved && isNewGraphItem && !nonParseDirectories.Any(x => resolvedInclude.StartsWith(x)))
                {
                    bool successReadingFile = true;
                    try
                    {
                        fileContent = File.ReadAllText(resolvedInclude);
                    }
                    catch
                    {
                        successReadingFile = false;
                        Output.Instance.WriteLine("Unable to read included file: '{0}'", resolvedInclude);
                    }
                    if (successReadingFile)
                    {
                        ParseIncludesRecursively(graph, includedFile, fileContent, includeDirectories, nonParseDirectories);
                    }
                }

                parentItem.Includes.Add(new IncludeGraph.Include {
                    IncludeLine = includeLine, IncludedFile = includedFile
                });
            }
        }
Beispiel #6
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);
        }
        /// <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);
        }