public async Task Generate() { if (Configuration.CalculateRoslynSemantics) { this.Text = await Document.GetTextAsync(); this.Root = await Document.GetSyntaxRootAsync(); this.SemanticModel = await Document.GetSemanticModelAsync(); this.SemanticFactsService = WorkspaceHacks.GetSemanticFactsService(this.Document); this.SyntaxFactsService = WorkspaceHacks.GetSyntaxFactsService(this.Document); var semanticFactsServiceType = SemanticFactsService.GetType(); var isWrittenTo = semanticFactsServiceType.GetMethod("IsWrittenTo"); this.isWrittenToDelegate = (Func <SemanticModel, SyntaxNode, CancellationToken, bool>) Delegate.CreateDelegate(typeof(Func <SemanticModel, SyntaxNode, CancellationToken, bool>), SemanticFactsService, isWrittenTo); var syntaxFactsServiceType = SyntaxFactsService.GetType(); var getBindableParent = syntaxFactsServiceType.GetMethod("GetBindableParent"); this.getBindableParentDelegate = (Func <SyntaxToken, SyntaxNode>) Delegate.CreateDelegate(typeof(Func <SyntaxToken, SyntaxNode>), SyntaxFactsService, getBindableParent); this.DeclaredSymbols = new HashSet <ISymbol>(); Interlocked.Increment(ref projectGenerator.DocumentCount); Interlocked.Add(ref projectGenerator.LinesOfCode, Text.Lines.Count); Interlocked.Add(ref projectGenerator.BytesOfCode, Text.Length); } CalculateDocumentDestinationPath(); CalculateRelativePathToRoot(); // add the file itself as a "declared symbol", so that clicking on document in search // results redirects to the document ProjectGenerator.AddDeclaredSymbolToRedirectMap( this.projectGenerator.SymbolIDToListOfLocationsMap, SymbolIdService.GetId(this.Document), documentRelativeFilePathWithoutHtmlExtension, 0); if (File.Exists(documentDestinationFilePath)) { // someone already generated this file, likely a shared linked file from elsewhere return; } this.classifier = new Classification(); Log.Write(documentDestinationFilePath); try { var directoryName = Path.GetDirectoryName(documentDestinationFilePath); var sanitized = Paths.SanitizeFolder(directoryName); if (directoryName != sanitized) { Log.Exception("Illegal characters in path: " + directoryName + " Project: " + this.projectGenerator.AssemblyName); } if (Configuration.CreateFoldersOnDisk) { Directory.CreateDirectory(directoryName); } } catch (PathTooLongException) { // there's one case where a path is too long - we don't care enough about it return; } if (Configuration.WriteDocumentsToDisk) { using (var streamWriter = new StreamWriter( documentDestinationFilePath, append: false, encoding: Encoding.UTF8)) { await GenerateHtml(streamWriter); } } else { using (var memoryStream = new MemoryStream()) using (var streamWriter = new StreamWriter(memoryStream)) { await GeneratePre(streamWriter); } } }
public static Solution LoadMetadataAsSourceSolution(string assemblyFilePath) { try { using (Disposable.Timing("Metadata as source: " + assemblyFilePath)) { var assemblyName = Path.GetFileNameWithoutExtension(assemblyFilePath); var solution = new AdhocWorkspace(WorkspaceHacks.Pack).CurrentSolution; var workspace = solution.Workspace; var project = solution.AddProject(assemblyName, assemblyName, LanguageNames.CSharp); var metadataReference = CreateReferenceFromFilePath(assemblyFilePath); var referencePaths = MetadataReading.GetReferencePaths(metadataReference); foreach (var referencePath in referencePaths) { project = project.AddMetadataReference(CreateReferenceFromFilePath(referencePath)); } var projectWithReference = project.AddMetadataReference(metadataReference); var compilation = projectWithReference.GetCompilationAsync().ConfigureAwait(false).GetAwaiter().GetResult(); var assemblyOrModuleSymbol = compilation.GetAssemblyOrModuleSymbol(metadataReference); IAssemblySymbol assemblySymbol = assemblyOrModuleSymbol as IAssemblySymbol; IModuleSymbol moduleSymbol = assemblyOrModuleSymbol as IModuleSymbol; if (moduleSymbol != null && assemblySymbol == null) { assemblySymbol = moduleSymbol.ContainingAssembly; } var assemblyAttributes = MetadataReading.GetAssemblyAttributes(assemblySymbol); var assemblyAttributesFileText = MetadataReading.GetAssemblyAttributesFileText( LanguageNames.CSharp, assemblyFilePath.Substring(0, 3), assemblyAttributes); INamespaceSymbol namespaceSymbol = null; if (assemblySymbol != null) { namespaceSymbol = assemblySymbol.GlobalNamespace; } else if (moduleSymbol != null) { namespaceSymbol = moduleSymbol.GlobalNamespace; } var types = GetTypes(namespaceSymbol) .OfType <INamedTypeSymbol>() .Where(t => t.CanBeReferencedByName); var tempDocument = projectWithReference.AddDocument("temp", SourceText.From(""), null); var metadataAsSourceService = WorkspaceHacks.GetMetadataAsSourceService(tempDocument); if (addSourceToAsync == null) { addSourceToAsync = ReflectAddSourceToAsync(metadataAsSourceService); } var texts = new Dictionary <INamedTypeSymbol, string>(); Parallel.ForEach( types, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, type => { try { string text = ""; if (Configuration.GenerateMetadataAsSourceBodies) { var document = addSourceToAsync( tempDocument, type, CancellationToken.None).Result; text = document.GetTextAsync().Result.ToString(); } lock (texts) { texts.Add(type, text); } } catch (Exception ex) { Log.Exception(ex, "Error when adding a MAS document to texts: " + assemblyFilePath); } }); HashSet <string> existingFileNames = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var kvp in texts) { var tempProject = AddDocument(project, kvp, existingFileNames); // tempProject can be null if the document was in an unutterable namespace // we want to skip such documents if (tempProject != null) { project = tempProject; } } project = project.AddDocument( "AssemblyAttributes.cs", assemblyAttributesFileText).Project; solution = project.Solution; return(solution); } } catch (Exception ex) { Log.Exception(ex, "Failed to run metadata as source for: " + assemblyFilePath); return(null); } }