/// <summary> /// Produces a <see cref="SymbolTreeInfo"/> for a given <see cref="PortableExecutableReference"/>. /// Note: can return <code>null</code> if we weren't able to actually load the metadata for some /// reason. /// </summary> public static Task<SymbolTreeInfo> TryGetInfoForMetadataReferenceAsync( Solution solution, PortableExecutableReference reference, bool loadOnly, CancellationToken cancellationToken) { var metadataId = GetMetadataIdNoThrow(reference); if (metadataId == null) { return SpecializedTasks.Default<SymbolTreeInfo>(); } // Try to acquire the data outside the lock. That way we can avoid any sort of // allocations around acquiring the task for it. Note: once ValueTask is available // (and enabled in the language), we'd likely want to use it here. (Presuming // the lock is not being held most of the time). if (s_metadataIdToInfo.TryGetValue(metadataId, out var infoTask)) { return infoTask; } var metadata = GetMetadataNoThrow(reference); if (metadata == null) { return SpecializedTasks.Default<SymbolTreeInfo>(); } return TryGetInfoForMetadataReferenceSlowAsync( solution, reference, loadOnly, metadata, cancellationToken); }
/// <summary> /// this gives you SymbolTreeInfo for a metadata /// </summary> public static async Task<SymbolTreeInfo> GetInfoForMetadataReferenceAsync( Solution solution, PortableExecutableReference reference, bool loadOnly, CancellationToken cancellationToken) { var metadata = reference.GetMetadata(); if (metadata == null) { return null; } // Find the lock associated with this piece of metadata. This way only one thread is // computing a symbol tree info for a particular piece of metadata at a time. var gate = s_metadataIdToGate.GetValue(metadata.Id, s_metadataIdToGateCallback); using (await gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); SymbolTreeInfo info; if (s_metadataIdToInfo.TryGetValue(metadata.Id, out info)) { return info; } info = await LoadOrCreateMetadataSymbolTreeInfoAsync( solution, reference, loadOnly, cancellationToken: cancellationToken).ConfigureAwait(false); if (info == null && loadOnly) { return null; } return s_metadataIdToInfo.GetValue(metadata.Id, _ => info); } }
private static Metadata GetMetadataNoThrow(PortableExecutableReference reference) { try { return reference.GetMetadata(); } catch (Exception e) when (e is BadImageFormatException || e is IOException) { return null; } }
public MetadataSearchScope( Solution solution, IAssemblySymbol assembly, PortableExecutableReference metadataReference, bool ignoreCase, CancellationToken cancellationToken) : base(ignoreCase, cancellationToken) { _solution = solution; _assembly = assembly; _metadataReference = metadataReference; }
private static Task<SymbolTreeInfo> LoadOrCreateMetadataSymbolTreeInfoAsync( Solution solution, PortableExecutableReference reference, bool loadOnly, CancellationToken cancellationToken) { var filePath = reference.FilePath; return LoadOrCreateAsync( solution, filePath, loadOnly, create: version => CreateMetadataSymbolTreeInfo(solution, version, reference, cancellationToken), keySuffix: "", getVersion: info => info._version, readObject: reader => ReadSymbolTreeInfo(reader, (version, nodes) => GetSpellCheckerTask(solution, version, filePath, nodes)), writeObject: (w, i) => i.WriteTo(w), cancellationToken: cancellationToken); }
private static SymbolTreeInfo CreateMetadataSymbolTreeInfo( Solution solution, VersionStamp version, PortableExecutableReference reference, CancellationToken cancellationToken) { var unsortedNodes = new List<Node> { new Node("", Node.RootNodeParentIndex) }; foreach (var moduleMetadata in GetModuleMetadata(reference.GetMetadata())) { MetadataReader reader; try { reader = moduleMetadata.GetMetadataReader(); } catch (BadImageFormatException) { continue; } GenerateMetadataNodes(reader, unsortedNodes); } return CreateSymbolTreeInfo(solution, version, reference.FilePath, unsortedNodes); }
private static async Task FindImmediateMatchingMetadataTypesInMetadataReferenceAsync( HashSet <INamedTypeSymbol> metadataTypes, Project project, Func <HashSet <INamedTypeSymbol>, INamedTypeSymbol, bool> metadataTypeMatches, Compilation compilation, PortableExecutableReference reference, HashSet <INamedTypeSymbol> result, CancellationToken cancellationToken) { // We store an index in SymbolTreeInfo of the *simple* metadata type name // to the names of the all the types that either immediately derive or // implement that type. Because the mapping is from the simple name // we might get false positives. But that's fine as we still use // 'metadataTypeMatches' to make sure the match is correct. var symbolTreeInfo = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( project.Solution, reference, loadOnly : false, cancellationToken : cancellationToken).ConfigureAwait(false); // For each type we care about, see if we can find any derived types // in this index. foreach (var metadataType in metadataTypes) { var baseTypeName = metadataType.Name; // For each derived type we find, see if we can map that back // to an actual symbol. Then check if that symbol actually fits // our criteria. foreach (var derivedType in symbolTreeInfo.GetDerivedMetadataTypes(baseTypeName, compilation, cancellationToken)) { if (derivedType != null && derivedType.Locations.Any(s_isInMetadata)) { if (metadataTypeMatches(metadataTypes, derivedType)) { result.Add(derivedType); } } } } }
private static async Task <SymbolTreeInfo> GetInfoForMetadataReferenceSlowAsync( Solution solution, PortableExecutableReference reference, Checksum checksum, bool loadOnly, Metadata metadata, CancellationToken cancellationToken) { // Find the lock associated with this piece of metadata. This way only one thread is // computing a symbol tree info for a particular piece of metadata at a time. var gate = s_metadataIdToGate.GetValue(metadata.Id, s_metadataIdToGateCallback); using (await gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); if (s_metadataIdToInfo.TryGetValue(metadata.Id, out var infoTask)) { var oldInfo = await infoTask.ConfigureAwait(false); if (oldInfo.Checksum == checksum) { return(oldInfo); } } var info = await TryLoadOrCreateMetadataSymbolTreeInfoAsync( solution, reference, checksum, loadOnly, cancellationToken).ConfigureAwait(false); if (info == null && loadOnly) { return(CreateEmpty(checksum)); } // Cache the result in our dictionary. Store it as a completed task so that // future callers don't need to allocate to get the result back. infoTask = Task.FromResult(info); s_metadataIdToInfo.Remove(metadata.Id); s_metadataIdToInfo.Add(metadata.Id, infoTask); return(info); } }
/// <summary> /// Produces a <see cref="SymbolTreeInfo"/> for a given <see cref="PortableExecutableReference"/>. /// Note: will never return null; /// </summary> public static async Task <SymbolTreeInfo> GetInfoForMetadataReferenceAsync( Solution solution, PortableExecutableReference reference, Checksum checksum, bool loadOnly, CancellationToken cancellationToken) { var metadataId = GetMetadataIdNoThrow(reference); if (metadataId == null) { return(CreateEmpty(checksum)); } // Try to acquire the data outside the lock. That way we can avoid any sort of // allocations around acquiring the task for it. Note: once ValueTask is available // (and enabled in the language), we'd likely want to use it here. (Presuming // the lock is not being held most of the time). if (s_metadataIdToInfo.TryGetValue(metadataId, out var infoTask)) { var info = await infoTask.ConfigureAwait(false); if (info.Checksum == checksum) { return(info); } } var metadata = GetMetadataNoThrow(reference); if (metadata == null) { return(CreateEmpty(checksum)); } return(await GetInfoForMetadataReferenceSlowAsync( solution, reference, checksum, loadOnly, metadata, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// this gives you SymbolTreeInfo for a metadata /// </summary> public static async Task <SymbolTreeInfo> GetInfoForMetadataReferenceAsync( Solution solution, PortableExecutableReference reference, bool loadOnly, CancellationToken cancellationToken) { var metadata = GetMetadataNoThrow(reference); if (metadata == null) { return(null); } // Find the lock associated with this piece of metadata. This way only one thread is // computing a symbol tree info for a particular piece of metadata at a time. var gate = s_metadataIdToGate.GetValue(metadata.Id, s_metadataIdToGateCallback); using (await gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); SymbolTreeInfo info; if (s_metadataIdToInfo.TryGetValue(metadata.Id, out info)) { return(info); } info = await LoadOrCreateMetadataSymbolTreeInfoAsync( solution, reference, loadOnly, cancellationToken : cancellationToken).ConfigureAwait(false); if (info == null && loadOnly) { return(null); } return(s_metadataIdToInfo.GetValue(metadata.Id, _ => info)); } }
/// <summary> /// If the extended <paramref name="reference"/> is a .Net Assembly return a <see cref="MetadataReader"/> /// instance that can be used to read the assembly's embedded metadata, otherwise return null. /// </summary> /// <param name="reference"> The extended <see cref="PortableExecutableReference"/>. </param> /// <returns> A <see cref="MetadataReader"/> if the reference is a .Net assembly or null otherwise. </returns> public static MetadataReader?GetMetadataReader(this PortableExecutableReference reference) { try { if (reference.GetMetadata() is AssemblyMetadata assembly) { foreach (var module in assembly.GetModules()) { return(module.GetMetadataReader()); } } else if (reference.GetMetadata() is ModuleMetadata module) { return(module.GetMetadataReader()); } return(null); } catch (BadImageFormatException) { return(null); } }
private static Checksum GetMetadataChecksumSlow( Solution solution, PortableExecutableReference reference, CancellationToken cancellationToken ) { return(ChecksumCache.GetOrCreate( reference, _ => { var serializer = solution.Workspace.Services.GetService <ISerializerService>(); var checksum = serializer.CreateChecksum(reference, cancellationToken); // Include serialization format version in our checksum. That way if the // version ever changes, all persisted data won't match the current checksum // we expect, and we'll recompute things. return Checksum.Create( WellKnownSynchronizationKind.SymbolTreeInfo, new[] { checksum, SerializationFormatChecksum } ); } )); }
private static async Task AddMetadataDeclarationsWithNormalQueryAsync( Project project, IAssemblySymbol assembly, PortableExecutableReference referenceOpt, SearchQuery query, SymbolFilter filter, ArrayBuilder <SymbolAndProjectId> list, CancellationToken cancellationToken) { // All entrypoints to this function are Find functions that are only searching // for specific strings (i.e. they never do a custom search). Contract.ThrowIfTrue(query.Kind == SearchKind.Custom, "Custom queries are not supported in this API"); using (Logger.LogBlock(FunctionId.SymbolFinder_Assembly_AddDeclarationsAsync, cancellationToken)) { if (referenceOpt != null) { var info = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( project.Solution, referenceOpt, loadOnly : false, cancellationToken : cancellationToken).ConfigureAwait(false); var symbols = await info.FindAsync( query, assembly, project.Id, filter, cancellationToken).ConfigureAwait(false); list.AddRange(symbols); } } }
private void WriteMvidsTo(PortableExecutableReference reference, ObjectWriter writer, CancellationToken cancellationToken) { var metadata = GetMetadata(reference); var assemblyMetadata = metadata as AssemblyMetadata; if (assemblyMetadata != null) { writer.WriteInt32((int)assemblyMetadata.Kind); var modules = assemblyMetadata.GetModules(); writer.WriteInt32(modules.Length); foreach (var module in modules) { WriteMvidTo(module, writer, cancellationToken); } return; } WriteMvidTo((ModuleMetadata)metadata, writer, cancellationToken); }
public async Task CheckPEReferencesNotSameAfterReferenceChangedTest() { using var ws = new AdhocWorkspace(); var projectInfo = ProjectInfo.Create( ProjectId.CreateNewId(), VersionStamp.Create(), "TestProject", "TestProject", LanguageNames.CSharp, metadataReferences: ImmutableArray.Create <MetadataReference>( PortableExecutableReference.CreateFromFile(typeof(object).Assembly.Location) ) ); var project = ws.AddProject(projectInfo); // get original references var compilation1 = await project.GetCompilationAsync(); var references1 = compilation1.ExternalReferences; // explicitly change references var forkedProject = project.WithMetadataReferences( ImmutableArray.Create <MetadataReference>( PortableExecutableReference.CreateFromFile(typeof(object).Assembly.Location), PortableExecutableReference.CreateFromFile(typeof(Workspace).Assembly.Location) ) ); // get new compilation var compilation2 = await forkedProject.GetCompilationAsync(); var references2 = compilation2.ExternalReferences; Assert.NotEqual(references1, references2); }
public void GetTopLevelTypesFromPEReference( Solution solution, Compilation compilation, PortableExecutableReference peReference, SyntaxContext syntaxContext, Action <CompletionItem, bool> handleItem, CancellationToken cancellationToken) { var key = GetReferenceKey(peReference); if (key == null) { // Can't cache items for reference with null key. We don't want risk potential perf regression by // making those items repeatedly, so simply not returning anything from this assembly, until // we have a better understanding on this sceanrio. // TODO: Add telemetry return; } if (!(compilation.GetAssemblyOrModuleSymbol(peReference) is IAssemblySymbol assemblySymbol)) { return; } var checksum = SymbolTreeInfo.GetMetadataChecksum(solution, peReference, cancellationToken); GetAccessibleTopLevelTypesWorker( key, assemblySymbol, checksum, syntaxContext, handleItem, CacheService.PEItemsCache, cancellationToken); return;
/// <summary> /// sample use of the CompileSource method. /// </summary> /// <param name="source1"></param> /// <param name="source2"></param> /// <returns></returns> public static Tuple <Assembly, IEnumerable <string> > CompileSourceDemo( string source1, string source2, PortableExecutableReference anotherReference) { IEnumerable <string> errmsgs = null; Assembly assem = null; { string[] sourceInput = new string[] { source1, source2 }; var rv = CSharpCompilationExt.CompileSource(sourceInput, anotherReference); assem = rv.Item1; errmsgs = rv.Item2; } if (errmsgs != null) { foreach (var errmsg in errmsgs) { Debug.WriteLine(errmsg); } } return(new Tuple <Assembly, IEnumerable <string> >(assem, errmsgs)); }
public void ConfigureServices(IServiceCollection services) { PortableExecutableReference reference = MetadataReference.CreateFromFile(@"C:\{PathToTheProject}\AspNetCoreApplicationParts\src\AspNetCoreApplicationParts.ModuleA\bin\Debug\netstandard1.5\AspNetCoreApplicationParts.ModuleA.dll"); Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(@"C:\{PathToTheProject}\AspNetCoreApplicationParts\src\AspNetCoreApplicationParts.ModuleA\bin\Debug\netstandard1.5\AspNetCoreApplicationParts.ModuleA.dll"); services.AddMvc().AddApplicationPart(assembly).AddRazorOptions( o => { o.FileProviders.Add(new EmbeddedFileProvider(assembly, assembly.GetName().Name)); Action <RoslynCompilationContext> previous = o.CompilationCallback; o.CompilationCallback = c => { if (previous != null) { previous(c); } c.Compilation = c.Compilation.AddReferences(reference); }; } ); }
private static SymbolTreeInfo CreateMetadataSymbolTreeInfo( Solution solution, VersionStamp version, PortableExecutableReference reference, CancellationToken cancellationToken) { var unsortedNodes = new List <Node> { new Node("", Node.RootNodeParentIndex) }; foreach (var moduleMetadata in GetModuleMetadata(GetMetadataNoThrow(reference))) { MetadataReader reader; try { reader = moduleMetadata.GetMetadataReader(); } catch (BadImageFormatException) { continue; } GenerateMetadataNodes(reader, unsortedNodes); } return(CreateSymbolTreeInfo(solution, version, reference.FilePath, unsortedNodes)); }
public void Analyze( string targetPath, Action <Diagnostic> reportDiagnostic, CancellationToken cancellationToken = default(CancellationToken)) { // Create a Roslyn representation of the IL by constructing a MetadataReference against // the target path (as if we intended to reference this binary during compilation, instead // of analyzing it). Using this mechanism, we can scan types/members contained in the // binary. We cannot currently retrieve IL from method bodies. PortableExecutableReference reference = MetadataReference.CreateFromFile(targetPath); var compilation = CSharpCompilation.Create("_", references: new[] { reference }); ISymbol target = compilation.GetAssemblyOrModuleSymbol(reference); // For each analysis target, we create a compilation start context, which may result // in symbol action registration. We need to capture and throw these registrations // away for each binary we inspect. var compilationStartAnalysisContext = new RoslynCompilationStartAnalysisContext(compilation, _options, cancellationToken); this.GlobalRoslynAnalysisContext.CompilationStartActions?.Invoke(compilationStartAnalysisContext); var visitor = new RoslynSymbolVisitor(symbol => this.Analyze( symbol, compilation, compilationStartAnalysisContext.SymbolActions, reportDiagnostic, cancellationToken)); visitor.Visit(target); // Having finished analysis, we'll invoke any compilation end actions registered previously. // We also discard the per-compilation symbol actions we collected. var compilationAnalysisContext = new CompilationAnalysisContext(compilation, _options, reportDiagnostic, _isSupportedDiagnostic, cancellationToken); this.GlobalRoslynAnalysisContext.CompilationActions?.Invoke(compilationAnalysisContext); compilationStartAnalysisContext.CompilationEndActions?.Invoke(compilationAnalysisContext); }
private static async Task AddDeclarationsAsync( Solution solution, IAssemblySymbol assembly, PortableExecutableReference referenceOpt, SearchQuery query, SymbolFilter filter, ArrayBuilder <ISymbol> list, CancellationToken cancellationToken) { // All entrypoints to this function are Find functions that are only searching // for specific strings (i.e. they never do a custom search). Debug.Assert(query.Kind != SearchKind.Custom); using (Logger.LogBlock(FunctionId.SymbolFinder_Assembly_AddDeclarationsAsync, cancellationToken)) { if (referenceOpt != null) { var info = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( solution, referenceOpt, loadOnly : false, cancellationToken : cancellationToken).ConfigureAwait(false); if (info != null) { var symbols = await info.FindAsync(query, assembly, filter, cancellationToken).ConfigureAwait(false); list.AddRange(symbols); } } } }
private static Task <SymbolTreeInfo> TryCreateMetadataSymbolTreeInfoAsync( HostWorkspaceServices services, SolutionKey solutionKey, PortableExecutableReference reference, Checksum checksum, StorageDatabase database, CancellationToken cancellationToken) { var filePath = reference.FilePath; var result = TryLoadOrCreateAsync( services, solutionKey, checksum, database, loadOnly: false, createAsync: () => CreateMetadataSymbolTreeInfoAsync(services, solutionKey, checksum, database, reference), keySuffix: "_Metadata_" + filePath, tryReadObject: reader => TryReadSymbolTreeInfo(reader, checksum, nodes => GetSpellCheckerAsync(services, solutionKey, checksum, database, filePath, nodes)), cancellationToken: cancellationToken); Contract.ThrowIfNull(result != null); return(result); }
static bool ContainsPathComponent(PortableExecutableReference reference, string pathComponent) => PathUtilities.ContainsPathComponent(reference.FilePath, pathComponent, ignoreCase: true);
private Metadata GetMetadata(PortableExecutableReference reference) { // TODO: right now, use reflection, but this API will be added as public API soon. when that happen, remove reflection var methodInfo = reference.GetType().GetTypeInfo().GetDeclaredMethod("GetMetadataImpl"); return (Metadata)methodInfo.Invoke(reference, null); }
private void WriteMvidsTo(PortableExecutableReference reference, ObjectWriter writer, CancellationToken cancellationToken) { var metadata = reference.GetMetadata(); var assemblyMetadata = metadata as AssemblyMetadata; if (assemblyMetadata != null) { writer.WriteInt32((int)assemblyMetadata.Kind); var modules = assemblyMetadata.GetModules(); writer.WriteInt32(modules.Length); foreach (var module in modules) { WriteMvidTo(module, writer, cancellationToken); } return; } WriteMvidTo((ModuleMetadata)metadata, writer, cancellationToken); }
protected void WritePortableExecutableReferenceHeaderTo( PortableExecutableReference reference, SerializationKinds kind, ObjectWriter writer, CancellationToken cancellationToken) { writer.WriteString(nameof(PortableExecutableReference)); writer.WriteInt32((int)kind); WriteTo(reference.Properties, writer, cancellationToken); writer.WriteString(reference.FilePath); }
void IVisualStudioWorkspaceHost.OnMetadataReferenceRemoved(ProjectId projectId, PortableExecutableReference metadataReference) { _workspace.OnMetadataReferenceRemoved(projectId, metadataReference); }
private static async Task FindImmediateMatchingMetadataTypesInMetadataReferenceAsync( HashSet<INamedTypeSymbol> metadataTypes, Project project, Func<HashSet<INamedTypeSymbol>, INamedTypeSymbol, bool> metadataTypeMatches, Compilation compilation, PortableExecutableReference reference, HashSet<INamedTypeSymbol> result, CancellationToken cancellationToken) { // We store an index in SymbolTreeInfo of the *simple* metadata type name // to the names of the all the types that either immediately derive or // implement that type. Because the mapping is from the simple name // we might get false positives. But that's fine as we still use // 'metadataTypeMatches' to make sure the match is correct. var symbolTreeInfo = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( project.Solution, reference, loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false); // For each type we care about, see if we can find any derived types // in this index. foreach (var metadataType in metadataTypes) { var baseTypeName = metadataType.Name; // For each derived type we find, see if we can map that back // to an actual symbol. Then check if that symbol actually fits // our criteria. foreach (var derivedType in symbolTreeInfo.GetDerivedMetadataTypes(baseTypeName, compilation, cancellationToken)) { if (derivedType != null && derivedType.Locations.Any(s_isInMetadata)) { if (metadataTypeMatches(metadataTypes, derivedType)) { result.Add(derivedType); } } } } }
internal static async Task<IEnumerable<ISymbol>> FindDeclarationsAsync( Solution solution, IAssemblySymbol assembly, PortableExecutableReference reference, SearchQuery query, SymbolFilter filter, CancellationToken cancellationToken) { if (query.Name != null && string.IsNullOrWhiteSpace(query.Name)) { return SpecializedCollections.EmptyEnumerable<ISymbol>(); } var result = new List<ISymbol>(); await AddDeclarationsAsync(solution, assembly, reference, query, filter, result, cancellationToken).ConfigureAwait(false); return result; }
private static Metadata TryGetMetadata(PortableExecutableReference reference) { try { return reference.GetMetadata(); } catch { // we have a reference but the file the reference is pointing to // might not actually exist on disk. // in that case, rather than crashing, we will handle it gracefully. return null; } }
private void WritePortableExecutableReferencePropertiesTo(PortableExecutableReference reference, ObjectWriter writer, CancellationToken cancellationToken) { WriteTo(reference.Properties, writer, cancellationToken); writer.WriteString(reference.FilePath); }
private static async Task AddDeclarationsAsync( Solution solution, IAssemblySymbol assembly, PortableExecutableReference referenceOpt, SearchQuery query, SymbolFilter filter, List<ISymbol> list, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.SymbolFinder_Assembly_AddDeclarationsAsync, cancellationToken)) { if (referenceOpt != null) { var info = await SymbolTreeInfo.TryGetInfoForAssemblyAsync(solution, assembly, referenceOpt, cancellationToken).ConfigureAwait(false); if (info != null) { list.AddRange(FilterByCriteria(Find(query, info, assembly, cancellationToken), filter)); } } } }
private static async Task AddDeclarationsAsync( Solution solution, IAssemblySymbol assembly, PortableExecutableReference referenceOpt, SearchQuery query, SymbolFilter filter, ArrayBuilder<ISymbol> list, CancellationToken cancellationToken) { // All entrypoints to this function are Find functions that are only searching // for specific strings (i.e. they never do a custom search). Debug.Assert(query.Kind != SearchKind.Custom); using (Logger.LogBlock(FunctionId.SymbolFinder_Assembly_AddDeclarationsAsync, cancellationToken)) { if (referenceOpt != null) { var info = await SymbolTreeInfo.TryGetInfoForMetadataReferenceAsync( solution, referenceOpt, loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false); if (info != null) { var symbols = await info.FindAsync(query, assembly, filter, cancellationToken).ConfigureAwait(false); list.AddRange(symbols); } } } }
private static SymbolTreeInfo CreateMetadataSymbolTreeInfo( Solution solution, VersionStamp version, PortableExecutableReference reference, CancellationToken cancellationToken) { var creator = new MetadataInfoCreator(solution, version, reference, cancellationToken); return creator.Create(); }
private static string GetReferenceKey(PortableExecutableReference reference) { return reference.FilePath ?? reference.Display; }
public unsafe static ModuleInstance Create(PortableExecutableReference reference) { // make a copy of the metadata, so that we don't dispose the metadata of a reference that are shared accross tests: return Create(reference.GetMetadata(), symReader: null, includeLocalSignatures: false); }
int IEqualityComparer <PortableExecutableReference> .GetHashCode(PortableExecutableReference obj) { return(StringComparer.OrdinalIgnoreCase.GetHashCode(obj.FilePath ?? obj.Display)); }
private async Task UpdateReferenceAsync( Project project, Compilation compilation, PortableExecutableReference reference, CancellationToken cancellationToken) { var key = GetReferenceKey(reference); if (key == null) { return; } DateTime lastWriteTime; if (!TryGetLastWriteTime(key, out lastWriteTime)) { // Couldn't get the write time. Just ignore this reference. return; } MetadataInfo metadataInfo; if (!_metadataPathToInfo.TryGetValue(key, out metadataInfo) || metadataInfo.TimeStamp == lastWriteTime) { var info = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( project.Solution, reference, loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false); metadataInfo = new MetadataInfo(lastWriteTime, info, metadataInfo.ReferencingProjects ?? new HashSet<ProjectId>()); _metadataPathToInfo.AddOrUpdate(key, metadataInfo, (_1, _2) => metadataInfo); } // Keep track that this dll is referenced by this project. metadataInfo.ReferencingProjects.Add(project.Id); }
// 根据生成的类,动态编译把json转成protobuf private static void ExportExcelProtobuf(ConfigType configType) { string classPath = GetClassDir(configType); List <SyntaxTree> syntaxTrees = new List <SyntaxTree>(); List <string> protoNames = new List <string>(); foreach (string classFile in Directory.GetFiles(classPath, "*.cs")) { protoNames.Add(Path.GetFileNameWithoutExtension(classFile)); syntaxTrees.Add(CSharpSyntaxTree.ParseText(File.ReadAllText(classFile))); } List <PortableExecutableReference> references = new List <PortableExecutableReference>(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { if (assembly.IsDynamic) { continue; } if (assembly.Location == "") { continue; } } catch (Exception e) { Console.WriteLine(e); throw; } PortableExecutableReference reference = MetadataReference.CreateFromFile(assembly.Location); references.Add(reference); } CSharpCompilation compilation = CSharpCompilation.Create( null, syntaxTrees.ToArray(), references.ToArray(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); using MemoryStream memSteam = new MemoryStream(); EmitResult emitResult = compilation.Emit(memSteam); if (!emitResult.Success) { StringBuilder stringBuilder = new StringBuilder(); foreach (Diagnostic t in emitResult.Diagnostics) { stringBuilder.AppendLine(t.GetMessage()); } throw new Exception($"动态编译失败:\n{stringBuilder}"); } memSteam.Seek(0, SeekOrigin.Begin); Assembly ass = Assembly.Load(memSteam.ToArray()); string dir = GetProtoDir(configType); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } foreach (string protoName in protoNames) { Type type = ass.GetType($"ET.{protoName}Category"); Type subType = ass.GetType($"ET.{protoName}"); Serializer.NonGeneric.PrepareSerializer(type); Serializer.NonGeneric.PrepareSerializer(subType); string json = File.ReadAllText(Path.Combine(string.Format(jsonDir, configType), $"{protoName}.txt")); object deserialize = BsonSerializer.Deserialize(json, type); string path = Path.Combine(dir, $"{protoName}Category.bytes"); using FileStream file = File.Create(path); Serializer.Serialize(file, deserialize); } }
private static async Task AddDeclarationsAsync( Solution solution, IAssemblySymbol assembly, PortableExecutableReference referenceOpt, SearchQuery query, SymbolFilter filter, List<ISymbol> list, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.SymbolFinder_Assembly_AddDeclarationsAsync, cancellationToken)) { if (referenceOpt != null) { var info = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( solution, referenceOpt, loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false); if (info != null) { var symbols = await info.FindAsync(query, assembly, filter, cancellationToken).ConfigureAwait(false); list.AddRange(symbols); } } } }
private Checksum CreatePortableExecutableReferenceChecksum(PortableExecutableReference reference, CancellationToken cancellationToken) { using (var stream = SerializableBytes.CreateWritableStream()) using (var writer = new ObjectWriter(stream, cancellationToken: cancellationToken)) { WriteMvidsTo(reference, writer, cancellationToken); stream.Position = 0; return Checksum.Create(stream); } }
private static Task <SymbolTreeInfo> CreateMetadataSymbolTreeInfoAsync( HostWorkspaceServices services, SolutionKey solutionKey, Checksum checksum, StorageDatabase database, PortableExecutableReference reference) { var creator = new MetadataInfoCreator(services, solutionKey, checksum, database, reference); return(Task.FromResult(creator.Create())); }
private void WritePortableExecutableReferenceTo( PortableExecutableReference reference, ObjectWriter writer, CancellationToken cancellationToken) { WritePortableExecutableReferenceHeaderTo(reference, SerializationKinds.Bits, writer, cancellationToken); WriteTo(reference.GetMetadata(), writer, cancellationToken); // TODO: what I should do with documentation provider? it is not exposed outside }
public MetadataInfoCreator( HostWorkspaceServices services, SolutionKey solutionKey, Checksum checksum, StorageDatabase database, PortableExecutableReference reference) { _services = services; _solutionKey = solutionKey; _checksum = checksum; _database = database; _reference = reference; _metadataReader = null; _allTypeDefinitions = new List <MetadataDefinition>(); _containsExtensionsMethod = false; _inheritanceMap = OrderPreservingMultiDictionary <string, string> .GetInstance(); _parentToChildren = OrderPreservingMultiDictionary <MetadataNode, MetadataNode> .GetInstance(); _extensionMethodToParameterTypeInfo = new MultiDictionary <MetadataNode, ParameterTypeInfo>(); _rootNode = MetadataNode.Allocate(name: ""); }
/// <summary> /// We ignore references that are in a directory that contains the names /// "Packages", "packs", "NuGetFallbackFolder", or "NuGetPackages" /// These directories are most likely the ones produced by NuGet, and we don't want /// to offer to add .dll reference manually for dlls that are part of NuGet packages. /// /// Note that this is only a heuristic (though a good one), and we should remove this /// when we can get an API from NuGet that tells us if a reference is actually provided /// by a nuget packages. /// Tracking issue: https://github.com/dotnet/project-system/issues/5275 /// /// This heuristic will do the right thing in practically all cases for all. It /// prevents the very unpleasant experience of us offering to add a direct metadata /// reference to something that should only be referenced as a nuget package. /// /// It does mean that if the following is true: /// You have a project that has a non-nuget metadata reference to something in a "packages" /// directory, and you are in another project that uses a type name that would have matched /// an accessible type from that dll. then we will not offer to add that .dll reference to /// that other project. /// /// However, that would be an exceedingly uncommon case that is degraded. Whereas we're /// vastly improved in the common case. This is a totally acceptable and desirable outcome /// for such a heuristic. /// </summary> private bool IsInPackagesDirectory(PortableExecutableReference reference) { return(ContainsPathComponent(reference, "packages") || ContainsPathComponent(reference, "packs") || ContainsPathComponent(reference, "NuGetFallbackFolder") || ContainsPathComponent(reference, "NuGetPackages"));
private static void WritePortableExecutableReferencePropertiesTo(PortableExecutableReference reference, ObjectWriter writer, CancellationToken cancellationToken) { WriteTo(reference.Properties, writer, cancellationToken); writer.WriteString(reference.FilePath); }
private void LoadReference(PortableExecutableReference resolvedReference, bool suppressWarnings) { AssemblyLoadResult result; try { result = _assemblyLoader.LoadFromPath(resolvedReference.FilePath); } catch (FileNotFoundException e) { Console.Error.WriteLine(e.Message); return; } catch (ArgumentException e) { Console.Error.WriteLine((e.InnerException ?? e).Message); return; } catch (TargetInvocationException e) { // The user might have hooked AssemblyResolve event, which might have thrown an exception. // Display stack trace in this case. Console.Error.WriteLine(e.InnerException.ToString()); return; } if (!result.IsSuccessful && !suppressWarnings) { Console.Out.WriteLine(string.Format(CultureInfo.CurrentCulture, FeaturesResources.RequestedAssemblyAlreadyLoaded, result.OriginalPath)); } }
private static string GetReferenceKey(PortableExecutableReference reference) => reference.FilePath ?? reference.Display;
public NamedMetadataReference(PortableExecutableReference reference, AssemblyNameReference name) => (Reference, Name) = (reference, name);
public MetadataInfoCreator( Solution solution, VersionStamp version, PortableExecutableReference reference, CancellationToken cancellationToken) { _solution = solution; _version = version; _reference = reference; _cancellationToken = cancellationToken; _metadataReader = null; _allTypeDefinitions = new List<MetadataDefinition>(); _inheritanceMap = OrderPreservingMultiDictionary<string, string>.GetInstance(); _parentToChildren = OrderPreservingMultiDictionary<MetadataNode, MetadataNode>.GetInstance(); _rootNode = MetadataNode.Allocate(name: ""); }
private async Task UpdateReferenceAsync( Project project, Compilation compilation, PortableExecutableReference reference, CancellationToken cancellationToken) { var key = GetReferenceKey(reference); if (key == null) { return; } if (!TryGetLastWriteTime(key, out var lastWriteTime)) { // Couldn't get the write time. Just ignore this reference. return; } if (!_metadataPathToInfo.TryGetValue(key, out var metadataInfo) || metadataInfo.TimeStamp == lastWriteTime) { var info = await SymbolTreeInfo.TryGetInfoForMetadataReferenceAsync( project.Solution, reference, loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false); // Note, getting the info may fail (for example, bogus metadata). That's ok. // We still want to cache that result so that don't try to continuously produce // this info over and over again. metadataInfo = new MetadataInfo(lastWriteTime, info, metadataInfo.ReferencingProjects ?? new HashSet<ProjectId>()); _metadataPathToInfo.AddOrUpdate(key, metadataInfo, (_1, _2) => metadataInfo); } // Keep track that this dll is referenced by this project. metadataInfo.ReferencingProjects.Add(project.Id); }
/// <summary> /// We ignore references that are in a directory that contains the names "Packages". /// These directories are most likely the ones produced by NuGet, and we don't want /// to offer to add .dll reference manually for dlls that are part of NuGet packages. /// /// Note that this is only a heuristic (though a good one), and we should remove this /// when we can get an API from NuGet that tells us if a reference is actually provided /// by a nuget packages. /// /// This heuristic will do the right thing in practically all cases for all. It /// prevents the very unpleasant experience of us offering to add a direct metadata /// reference to something that should only be referenced as a nuget package. /// /// It does mean that if the following is true: /// You have a project that has a non-nuget metadata reference to something in a "packages" /// directory, and you are in another project that uses a type name that would have matched /// an accessible type from that dll. then we will not offer to add that .dll reference to /// that other project. /// /// However, that would be an exceedingly uncommon case that is degraded. Whereas we're /// vastly improved in the common case. This is a totally acceptable and desirable outcome /// for such a heuristic. /// </summary> private bool IsInPackagesDirectory(PortableExecutableReference reference) { return(PathUtilities.ContainsPathComponent(reference.FilePath, "packages", ignoreCase: true)); }
private void WritePortableExecutableReferenceMetadataTo( PortableExecutableReference reference, ObjectWriter writer, CancellationToken cancellationToken) { var metadata = GetMetadata(reference); WriteTo(metadata, writer, cancellationToken); }
bool IEqualityComparer <PortableExecutableReference> .Equals(PortableExecutableReference x, PortableExecutableReference y) { return(StringComparer.OrdinalIgnoreCase.Equals( x.FilePath ?? x.Display, y.FilePath ?? y.Display)); }
public async Task<SymbolTreeInfo> TryGetMetadataSymbolTreeInfoAsync( Solution solution, PortableExecutableReference reference, CancellationToken cancellationToken) { var key = GetReferenceKey(reference); if (key != null) { MetadataInfo metadataInfo; if (_metadataPathToInfo.TryGetValue(key, out metadataInfo)) { DateTime writeTime; if (TryGetLastWriteTime(key, out writeTime) && writeTime == metadataInfo.TimeStamp) { return metadataInfo.SymbolTreeInfo; } } } // If we didn't have it in our cache, see if we can load it from disk. // Note: pass 'loadOnly' so we only attempt to load from disk, not to actually // try to create the metadata. var info = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( solution, reference, loadOnly: true, cancellationToken: cancellationToken).ConfigureAwait(false); return info; }
private static async Task<SymbolTreeInfo> TryGetInfoForMetadataReferenceSlowAsync( Solution solution, PortableExecutableReference reference, bool loadOnly, Metadata metadata, CancellationToken cancellationToken) { // Find the lock associated with this piece of metadata. This way only one thread is // computing a symbol tree info for a particular piece of metadata at a time. var gate = s_metadataIdToGate.GetValue(metadata.Id, s_metadataIdToGateCallback); using (await gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); if (s_metadataIdToInfo.TryGetValue(metadata.Id, out var infoTask)) { return await infoTask.ConfigureAwait(false); } var info = await LoadOrCreateMetadataSymbolTreeInfoAsync( solution, reference, loadOnly, cancellationToken: cancellationToken).ConfigureAwait(false); if (info == null && loadOnly) { return null; } // Cache the result in our dictionary. Store it as a completed task so that // future callers don't need to allocate to get the result back. infoTask = Task.FromResult(info); s_metadataIdToInfo.Add(metadata.Id, infoTask); return info; } }
public static ModuleInstance Create(PortableExecutableReference reference) { // make a copy of the metadata, so that we don't dispose the metadata of a reference that are shared accross tests: return(Create(reference.GetMetadata(), symReader: null, includeLocalSignatures: false)); }
static Task GetNewTask(IncrementalAnalyzer self, Func <IncrementalAnalyzer, Project, PortableExecutableReference, CancellationToken, Task> func, Project project, PortableExecutableReference reference, CancellationToken cancellationToken) { return(Task.Run(() => func(self, project, reference, cancellationToken), cancellationToken)); }