/// <summary> /// Recurses through the given file and all of its includes, attempting to identify cycles. /// </summary> /// <param name="File">The file to search through</param> /// <param name="Includes">Current include stack of the preprocessor</param> /// <param name="VisitedFiles">Set of files that have already been checked for cycles</param> /// <param name="Cycles">List which receives any cycles that are found</param> static void FindCyclesRecursive(SourceFile File, List <SourceFile> Includes, HashSet <SourceFile> VisitedFiles, List <IncludeCycle> Cycles) { // Check if this include forms a cycle int IncludeIdx = Includes.IndexOf(File); if (IncludeIdx != -1) { IncludeCycle NewCycle = new IncludeCycle(Includes.Skip(IncludeIdx)); for (int Idx = 0;; Idx++) { if (Idx == Cycles.Count) { Cycles.Add(NewCycle); break; } else if (Cycles[Idx].Matches(NewCycle)) { Cycles[Idx].AddStartingPoint(NewCycle.Files[0]); break; } } } // If we haven't already looked from cycles from this include, search now if (!VisitedFiles.Contains(File)) { VisitedFiles.Add(File); Includes.Add(File); foreach (PreprocessorMarkup Markup in File.Markup) { if (Markup.Type == PreprocessorMarkupType.Include && Markup.IncludedFile != null) { SourceFile IncludedFile = Markup.IncludedFile; if (!IncludedFile.Flags.HasFlag(SourceFileFlags.External)) { FindCyclesRecursive(Markup.IncludedFile, Includes, VisitedFiles, Cycles); } } } Includes.RemoveAt(Includes.Count - 1); } }
/// <summary> /// Checks whether an include cycle matches another include cycle, ignoring the start location. /// </summary> /// <param name="Other">The cycle to compare against</param> /// <returns>True if the cycles are identical, false otherwise</returns> public bool Matches(IncludeCycle Other) { if (Other.Files.Length != Files.Length) { return(false); } int Offset = Array.IndexOf(Other.Files, Files[0]); if (Offset == -1) { return(false); } for (int Idx = 0; Idx < Files.Length; Idx++) { if (Files[Idx] != Other.Files[(Offset + Idx) % Files.Length]) { return(false); } } return(true); }