using System.IO; using System.Linq; using System.Collections.Generic; using IntelligentProjectAnalyzer.Analyzer; // All using statements now refer to the new data-only class using static IntelligentProjectAnalyzer.Editor.DependencyBuilderData; namespace IntelligentProjectAnalyzer.Editor { /// /// Executes the CPU-intensive analysis on a background thread to avoid freezing the editor. /// public static class BackgroundAnalyzer { /// /// Runs the full dependency analysis on a collection of assets. /// /// A list containing metadata for all assets to be analyzed. /// The setup data required for Roslyn analysis. /// A list of analysis results, one for each processed asset. public static List RunAnalysis(List allMetadata, RoslynSetupData roslynSetupData) { // Initialize the Roslyn analyzer with all the necessary data. var roslynAnalyzer = new RoslynTypeDependencyAnalyzer(roslynSetupData.SourceFiles, roslynSetupData.References, roslynSetupData.PreprocessorSymbols, roslynSetupData.SystemTypePrefixes); // --- IMPORTANT --- // First, run analysis on ALL script types to build the complete, internal dependency tree in the analyzer. var allScriptTypes = roslynAnalyzer.TypeToPathMap.Keys; roslynAnalyzer.AnalyzeTypeDependenciesForFile(allScriptTypes); // Now, iterate through our assets and populate the script dependencies. foreach (var metadata in allMetadata) { // We only need to run Roslyn analysis for scripts. // Prefabs and SOs have their direct dependencies already. if (metadata is ScriptMetadata scriptMetadata) { ProcessScript(scriptMetadata, roslynAnalyzer, roslynSetupData.TypeToGuidMap); } } return allMetadata; } /// /// Processes a single script to find all its recursive dependencies. /// private static void ProcessScript(ScriptMetadata metadata, RoslynTypeDependencyAnalyzer analyzer, IReadOnlyDictionary typeToGuidMap) { // Get all types defined within this specific script file. var typesInFile = analyzer.TypeToPathMap .Where(pair => Path.GetFullPath(pair.Value).Replace('\\', '/') == metadata.FullPath) .Select(pair => pair.Key); var allDependenciesInFile = new HashSet(); foreach (var typeName in typesInFile) { // For each type, get its complete, recursive list of dependencies from the analyzer's pre-built tree. var dependenciesForType = analyzer.GetRecursiveDependencies(typeName); foreach (var dep in dependenciesForType) { allDependenciesInFile.Add(dep); } } // Now, convert the dependency type names back to GUIDs and add them to the metadata object. foreach (var depName in allDependenciesInFile) { if (typeToGuidMap.TryGetValue(depName, out var depGuid) && !string.IsNullOrEmpty(depGuid) && !metadata.DependencyGuids.Contains(depGuid)) { metadata.DependencyGuids.Add(depGuid); } } } } }