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