public override object Load([NotNull] IProgressIndicator progress, bool enablePersistence) { base.Load(progress, enablePersistence); // Map is loaded on class instantiation progress.CurrentItemText = "Loading T4 file include caches"; var result = new Dictionary <IPsiSourceFile, T4ReversedFileDependencyData>(); var stopWatch = new Stopwatch(); stopWatch.Start(); foreach (var(sourceFile, data) in Map) { // This lock is intentionally taken per-file to avoid too long blocking. Just in case. using (ReadLockCookie.Create()) { var includes = new JetHashSet <IPsiSourceFile>( data.Includes.Select(include => PsiFileSelector.FindMostSuitableFile(include, sourceFile)) ); UpdateIncluders(result, sourceFile, includes, JetHashSet <IPsiSourceFile> .Empty); } } stopWatch.Stop(); Logger.Verbose("Loading T4 cache took {0} ms", stopWatch.ElapsedMilliseconds); return(result); }
public override void Drop(IPsiSourceFile sourceFile) { // Calculate them here, because following actions // will disturb the graph and change the dependencies var includePaths = Map.TryGetValue(sourceFile); var indirectDependencies = FindIndirectIncludesTransitiveClosure(sourceFile); // First of all, this file itself should be removed from Map and ReversedMap base.Drop(sourceFile); ReversedMap.Remove(sourceFile); // Then, all its includes should no longer view this file as an includer. // This deletion might be a genuine deletion of the file from the file system, // and nonexistent files obviously don't include anything. // If this drop was caused by moving the file between PSI modules, // it will be re-added into lists of includers by the Merge method. var location = sourceFile.GetLocation(); var includes = includePaths?.Includes .Select(includePath => PsiFileSelector.FindMostSuitableFile(includePath, sourceFile)) .WhereNotNull() ?? EmptyList <IPsiSourceFile> .InstanceList; foreach (var include in includes) { ReversedMap.TryGetValue(include)?.Includers.Remove(location); } // Finally, we trigger indirect include invalidation. // Deletion can happen either when the file is genuinely deleted, // or when it is transferred between PSI modules // (e.g. a file that used to be preprocessed becomes executable). // In either case, we need to update its indirect dependencies. // However, that cannot be done in Merge, // because Merge happens on the new PSI file. // That's why we update dependencies here. var data = new T4FileInvalidationData(indirectDependencies.Except(sourceFile), sourceFile); OnFilesIndirectlyAffected.Fire(data); }
private IEnumerable <IPsiSourceFile> GetIncludes([NotNull] IPsiSourceFile sourceFile) => Map .TryGetValue(sourceFile) ?.Includes .Select(path => PsiFileSelector.FindMostSuitableFile(path, sourceFile));