Backend/RiderPlugin/ForTea.RiderPlugin/TemplateProcessing/CodeGeneration/Reference/Impl/T4ReferenceExtractionManager.cs (114 lines of code) (raw):

using System.Collections.Generic; using System.Linq; using GammaJul.ForTea.Core; using GammaJul.ForTea.Core.Psi.Directives; using GammaJul.ForTea.Core.Psi.Modules; using GammaJul.ForTea.Core.Psi.Resolve.Assemblies; using GammaJul.ForTea.Core.TemplateProcessing.CodeCollecting.Interrupt; using GammaJul.ForTea.Core.TemplateProcessing.CodeGeneration.Reference; using GammaJul.ForTea.Core.Tree; using JetBrains.Annotations; using JetBrains.Application.Parts; using JetBrains.Diagnostics; using JetBrains.Lifetimes; using JetBrains.ProjectModel; using JetBrains.ReSharper.Psi; using JetBrains.ReSharper.Psi.Tree; using JetBrains.Util; using JetBrains.Util.dataStructures; using Microsoft.CodeAnalysis; namespace JetBrains.ForTea.RiderPlugin.TemplateProcessing.CodeGeneration.Reference.Impl { [SolutionComponent(Instantiation.DemandAnyThreadSafe)] public sealed class T4ReferenceExtractionManager : IT4ReferenceExtractionManager { [NotNull] private IT4AssemblyReferenceResolver AssemblyReferenceResolver { get; } [NotNull] private IT4LowLevelReferenceExtractionManager LowLevelReferenceExtractionManager { get; } [NotNull] private IT4Environment Environment { get; } public T4ReferenceExtractionManager( [NotNull] IT4AssemblyReferenceResolver assemblyReferenceResolver, [NotNull] IT4LowLevelReferenceExtractionManager lowLevelReferenceExtractionManager, [NotNull] IT4Environment environment ) { AssemblyReferenceResolver = assemblyReferenceResolver; LowLevelReferenceExtractionManager = lowLevelReferenceExtractionManager; Environment = environment; } public IEnumerable<MetadataReference> ExtractPortableReferencesForResolve(Lifetime lifetime, IT4File file) => ExtractReferenceLocations(file) .Select(location => LowLevelReferenceExtractionManager.ResolveMetadata(lifetime, location)) .AsList(); public IEnumerable<MetadataReference> ExtractPortableReferencesForCompilation( Lifetime lifetime, IT4File file ) => ExtractPortableReferencesForResolve(lifetime, file) .Concat(Environment .AdditionalCompilationAssemblyLocations .Select(location => LowLevelReferenceExtractionManager.ResolveMetadata(lifetime, location) ) ); public IEnumerable<T4AssemblyReferenceInfo> ExtractReferenceLocationsTransitive(IT4File file) { var directDependencies = ExtractReferenceLocations(file); var sourceFile = file.PhysicalPsiSourceFile.NotNull(); var projectFile = sourceFile.ToProjectFile().NotNull(); return LowLevelReferenceExtractionManager.ResolveTransitiveDependencies( directDependencies, projectFile.SelectResolveContext() ); } [NotNull] private List<VirtualFileSystemPath> ExtractReferenceLocations([NotNull] IT4File file) { file.AssertContainsNoIncludeContext(); var directives = file.GetThisAndIncludedFilesRecursive() .SelectMany(it => it.Blocks) .OfType<IT4AssemblyDirective>(); var errors = new FrugalLocalList<T4FailureRawData>(); var directDependencies = directives.SelectNotNull( directive => { var resolved = AssemblyReferenceResolver.Resolve(directive); if (resolved == null) errors.Add(CreateError(directive)); return resolved; } ).AsList(); if (!errors.IsEmpty) throw new T4OutputGenerationException(errors); AddBaseReferences(directDependencies, file); return directDependencies; } private static T4FailureRawData CreateError([NotNull] IT4AssemblyDirective directive) { var attribute = directive.GetFirstAttribute(T4DirectiveInfoManager.Assembly.NameAttribute); if (attribute == null) return T4FailureRawData.FromElement(directive, "Missing assembly name"); string message = $"Unresolved assembly reference: {attribute.Value.GetText()}"; return T4FailureRawData.FromElement(directive, message); } private void AddBaseReferences( [NotNull, ItemNotNull] List<VirtualFileSystemPath> directDependencies, [NotNull] IT4File file ) => directDependencies.AddRange( Environment.DefaultAssemblyNames.Select(assemblyName => ResolveBaseReference(file, assemblyName)) ); [NotNull] private VirtualFileSystemPath ResolveBaseReference( [NotNull] IT4File file, [NotNull] string assemblyName ) { var resolved = AssemblyReferenceResolver.Resolve(assemblyName, file.LogicalPsiSourceFile); if (resolved != null) return resolved; var node = FindSuitableNodeForErrorReporting(file); string message = $"Could not find standard assembly: {assemblyName}"; throw new T4OutputGenerationException(T4FailureRawData.FromElement(node, message)); } [NotNull] private ITreeNode FindSuitableNodeForErrorReporting([NotNull] IT4File file) { ITreeNode templateDirective = file.BlocksEnumerable.OfType<IT4TemplateDirective>().FirstOrDefault(); return templateDirective ?? file; } } }