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 #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();
            }
        }
        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();
                }
            }
        }