public static MetadataOnlyImage Create(ITemporaryStorageService service, Compilation compilation, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); using (Logger.LogBlock(FunctionId.Workspace_SkeletonAssembly_EmitMetadataOnlyImage, cancellationToken)) { // TODO: make it to use SerializableBytes.WritableStream rather than MemoryStream so that // we don't allocate anything for skeleton assembly. using (var stream = SerializableBytes.CreateWritableStream()) { // note: cloning compilation so we don't retain all the generated symbols after its emitted. // * REVIEW * is cloning clone p2p reference compilation as well? var emitResult = compilation.Clone().Emit(stream, options: s_emitOptions, cancellationToken: cancellationToken); if (emitResult.Success) { var storage = service.CreateTemporaryStreamStorage(cancellationToken); stream.Position = 0; storage.WriteStream(stream, cancellationToken); return new MetadataOnlyImage(storage, compilation.AssemblyName); } } } return Empty; }
/// <summary> /// Performs fixup steps on the specified compilation. /// </summary> private static Compilation PerformSyntaxTreeFixup(Compilation compilation, IEnumerable <DataSourceWrapperInfo> infos) { var syncObject = new Object(); var trees = compilation.SyntaxTrees.ToList(); var result = compilation.Clone(); Parallel.ForEach(trees, tree => { var changed = false; var semanticModel = default(SemanticModel); var oldTree = (CSharpSyntaxTree)tree; var newTree = (CSharpSyntaxTree)tree; var info = infos.Where(x => String.Equals(x.UniqueID.ToString(), Path.GetFileNameWithoutExtension(oldTree.FilePath), StringComparison.OrdinalIgnoreCase)).SingleOrDefault(); if (info == null) { return; } lock (syncObject) semanticModel = result.GetSemanticModel(oldTree, true); newTree = RewriteSyntaxTree(oldTree, semanticModel, sm => new FixupExpressionPropertiesRewriter(sm)); if (newTree != oldTree) { lock (syncObject) result = result.ReplaceSyntaxTree(oldTree, newTree); oldTree = newTree; changed = true; } lock (syncObject) semanticModel = result.GetSemanticModel(oldTree, true); newTree = RewriteSyntaxTree(oldTree, semanticModel, sm => new RemoveUnnecessaryDataBindingSetterFieldsRewriter(sm)); if (newTree != oldTree) { lock (syncObject) result = result.ReplaceSyntaxTree(oldTree, newTree); oldTree = newTree; changed = true; } if (changed) { lock (syncObject) info.DataSourceWrapperSourceCode = newTree.ToString(); } }); return(result); }
// Hand out the same compilation reference for everyone who asks. Use // WeakReference<Compilation> so that if no one is using the MetadataReference, // it can be collected. internal static Compilation GetCompilationForMetadataReference(ProjectState projectState, Compilation compilation) { var weakReference = s_compilationReferenceMap.GetValue(projectState, s_createValue); Compilation reference; lock (s_guard) { if (!weakReference.TryGetTarget(out reference)) { reference = compilation.Clone(); // drop all existing symbols weakReference.SetTarget(reference); } } return reference; }
public static MetadataOnlyImage Create(Workspace workspace, ITemporaryStorageService service, Compilation compilation, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); try { workspace.LogTestMessage($"Beginning to create a skeleton assembly for {compilation.AssemblyName}..."); using (Logger.LogBlock(FunctionId.Workspace_SkeletonAssembly_EmitMetadataOnlyImage, cancellationToken)) { // TODO: make it to use SerializableBytes.WritableStream rather than MemoryStream so that // we don't allocate anything for skeleton assembly. using (var stream = SerializableBytes.CreateWritableStream()) { // note: cloning compilation so we don't retain all the generated symbols after its emitted. // * REVIEW * is cloning clone p2p reference compilation as well? var emitResult = compilation.Clone().Emit(stream, options: s_emitOptions, cancellationToken: cancellationToken); if (emitResult.Success) { workspace.LogTestMessage($"Successfully emitted a skeleton assembly for {compilation.AssemblyName}"); var storage = service.CreateTemporaryStreamStorage(cancellationToken); stream.Position = 0; storage.WriteStream(stream, cancellationToken); return new MetadataOnlyImage(storage, compilation.AssemblyName); } else { workspace.LogTestMessage($"Failed to create a skeleton assembly for {compilation.AssemblyName}:"); foreach (var diagnostic in emitResult.Diagnostics) { workspace.LogTestMessage(" " + diagnostic.GetMessage()); } } } } } finally { workspace.LogTestMessage($"Done trying to create a skeleton assembly for {compilation.AssemblyName}"); } return Empty; }
public Compilation CreateNewCompilation() { var partialTypesA = scanner.typeDeclarationsBySymbol.Where(x => x.Value.Count > 1).SelectMany(x => x.Value).ToArray(); var partialTypes = scanner.typeDeclarationsBySymbol.Where(x => x.Value.Count > 1).ToDictionary(x => x.Key, x => x.Value); if (partialTypes.Any()) { foreach (var item in partialTypes) { var type = item.Key; var declarations = item.Value; var newDeclaration = UnifyDeclarations(type, declarations); // Register the first implementation to be replaced by the fully unified type declaration typeDeclarationReplacements[declarations.First()] = newDeclaration; // Register the remaining types for removal foreach (var removedTypeDeclaration in declarations.Skip(1)) { removedTypeDeclarations.Add(removedTypeDeclaration); } } var rewriter = new PartialClassRewriter(this); var newCompilationUnits = new List <Tuple <SyntaxTree, CompilationUnitSyntax> >(); foreach (var syntaxTree in compilation.SyntaxTrees) { var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot(); compilationUnit = (CompilationUnitSyntax)compilationUnit.Accept(rewriter); newCompilationUnits.Add(Tuple.Create(syntaxTree, compilationUnit)); } foreach (var item in newCompilationUnits) { compilation = compilation.ReplaceSyntaxTree(item.Item1, SyntaxFactory.SyntaxTree(item.Item2, item.Item1.FilePath)); } Context.Update(project.Solution, project, compilation, new ReflectionCache(project, compilation)); compilation = compilation.Clone(); } return(compilation); }
public static Compilation RewriteCompilation(Compilation original, ReplacementDictionary dict_old_to_new) { Contract.Requires(dict_old_to_new != null); Contract.Ensures(Contract.Result <Compilation>() != null); Output.WriteLine("Rewriting the compilation"); var curr = original.Clone(); Contract.Assume(curr != null); foreach (var st in original.SyntaxTrees) { Dictionary <SyntaxNode, SyntaxNode> subdict; if (dict_old_to_new.TryGetValue(st.FilePath, out subdict)) { var r = new ReplacerInternal(subdict, original); var newtree = r.Replace(st); if (newtree != st) // did something change? { newtree = AddUsingsContracts(newtree); curr = curr.ReplaceSyntaxTree(st, SyntaxFactory.SyntaxTree(newtree.GetRoot(), null, st.FilePath)); Contract.Assume(curr != null); } } } return(curr); //var r = new Replacer(dict_old_to_new, original); //foreach (var st in original.SyntaxTrees) //{ // //var newnode = SyntaxNodeExtensions.ReplaceNodes(st.GetRoot(), dict_old_to_new.Keys, ComputeReplacement); // var newtree = r.Replace(st); // if (newtree != st) // did something change? // { // newtree = AddUsingsContracts(newtree); // curr = curr.ReplaceSyntaxTree(st, newtree); // } //} }
public virtual Differences VisitCompilation(Compilation compilation1, Compilation compilation2){ Differences differences = new Differences(compilation1, compilation2); if (compilation1 == null || compilation2 == null){ if (compilation1 != compilation2) differences.NumberOfDifferences++; else differences.NumberOfSimilarities++; return differences; } Compilation changes = (Compilation)compilation2.Clone(); Compilation deletions = (Compilation)compilation2.Clone(); Compilation insertions = (Compilation)compilation2.Clone(); this.OriginalModule = compilation1.TargetModule; this.NewModule = compilation2.TargetModule; CompilationUnitList cuChanges, cuDeletions, cuInsertions; Differences diff = this.VisitCompilationUnitList(compilation1.CompilationUnits, compilation2.CompilationUnits, out cuChanges, out cuDeletions, out cuInsertions); if (diff == null){Debug.Assert(false); return differences;} changes.CompilationUnits = cuChanges; deletions.CompilationUnits = cuDeletions; insertions.CompilationUnits = cuInsertions; differences.NumberOfDifferences += diff.NumberOfDifferences; differences.NumberOfSimilarities += diff.NumberOfSimilarities; if (differences.NumberOfDifferences == 0){ differences.Changes = null; differences.Deletions = null; differences.Insertions = null; }else{ differences.Changes = changes; differences.Deletions = deletions; differences.Insertions = insertions; } return differences; }
public FullDeclarationState(Compilation declarationCompilation) : base(new WeakConstantValueSource<Compilation>(declarationCompilation), declarationCompilation.Clone().RemoveAllReferences()) { }
public override Compilation VisitCompilation(Compilation compilation) { if (compilation == null || compilation.TargetModule == null) return null; this.FindTypesToBeDuplicated(compilation.TargetModule.Types); return base.VisitCompilation((Compilation)compilation.Clone()); }
public async Task <Tuple <string, Project> > Compile(string projectFile) { var projectFileInfo = new FileInfo(projectFile); var projectFolder = projectFileInfo.Directory.FullName; // These two lines are just a weird hack because you get no files back from compilation.SyntaxTrees // if the user file isn't modified. Not sure why that's happening. var projectUserFile = projectFolder + "\\" + projectFileInfo.Name + ".user"; if (File.Exists(projectUserFile)) { File.SetLastWriteTime(projectUserFile, DateTime.Now); } var project = await MSBuildWorkspace.Create().OpenProjectAsync(projectFile); var projectName = project.AssemblyName; Compilation compilation = await project.GetCompilationAsync(); Context.Update(project.Solution, project, compilation); // Check for yield foreach (var syntaxTree in compilation.SyntaxTrees) { var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot(); var semanticModel = compilation.GetSemanticModel(syntaxTree); var yieldGenerator = new YieldGenerator(compilation, syntaxTree, semanticModel); compilationUnit = (CompilationUnitSyntax)compilationUnit.Accept(yieldGenerator); compilation = compilation.ReplaceSyntaxTree(syntaxTree, SyntaxFactory.SyntaxTree(compilationUnit, syntaxTree.FilePath)); } compilation = compilation.Clone(); Context.Update(project.Solution, project, compilation); // After the basic transformation happens, we need to fix up some references afterward foreach (var syntaxTree in compilation.SyntaxTrees) { var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot(); var semanticModel = compilation.GetSemanticModel(syntaxTree); var yieldFixer = new YieldGeneratorFixer(compilation, syntaxTree, semanticModel); compilationUnit = (CompilationUnitSyntax)compilationUnit.Accept(yieldFixer); compilation = compilation.ReplaceSyntaxTree(syntaxTree, SyntaxFactory.SyntaxTree(compilationUnit, syntaxTree.FilePath)); } Context.Update(project.Solution, project, compilation); // Check for async foreach (var syntaxTree in compilation.SyntaxTrees) { var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot(); var semanticModel = compilation.GetSemanticModel(syntaxTree); var asyncGenerator = new AsyncGenerator(compilation, syntaxTree, semanticModel); compilationUnit = (CompilationUnitSyntax)compilationUnit.Accept(asyncGenerator); compilation = compilation.ReplaceSyntaxTree(syntaxTree, SyntaxFactory.SyntaxTree(compilationUnit, syntaxTree.FilePath)); } Context.Update(project.Solution, project, compilation); var jsCompilationUnit = new JsCompilationUnit { UseStrict = true }; // If this is the runtime prjoect, declare the array to hold all the GetAssembly functions (this .js file // will be loaded first, and we only want to bother creating the array once. if (projectName == "mscorlib") { var assemblies = Js.Variable(SpecialNames.Assemblies, Js.Array()); jsCompilationUnit.Body.Local(assemblies); // This ensures that Function.$typeName returns `Function` -- this is important when using // a type function as a generic argument, since otherwise when we try to assembly a // unique key for the permuatation of type args including a type function, we would get // an empty string for that arg, which would break the cache. jsCompilationUnit.Body.Assign(Js.Reference("Function").Member(SpecialNames.TypeName), Js.Primitive("Function")); } // Declare assembly variable var assemblyVariable = Js.Variable("$" + projectName.MaskSpecialCharacters() + "$Assembly", Js.Null()); jsCompilationUnit.Body.Local(assemblyVariable); // Declare array to store all anonymous types var anonymousTypes = Js.Variable(compilation.Assembly.GetAssemblyAnonymousTypesArray(), Js.Array()); jsCompilationUnit.Body.Local(anonymousTypes); // Declare array to store all the type functions in the assembly var assemblyTypes = Js.Variable(compilation.Assembly.GetAssemblyTypesArray(), Js.Array()); jsCompilationUnit.Body.Local(assemblyTypes); // Build $GetAssemblyMethod, which lazily creates a new Assembly instance var globalIdioms = new Idioms(null); var getAssembly = Js.Function(); getAssembly.Body.If( assemblyVariable.GetReference().EqualTo(Js.Null()), assemblyVariable.GetReference().Assign(globalIdioms.CreateAssembly(compilation.Assembly, assemblyTypes.GetReference())) ); getAssembly.Body.Return(assemblyVariable.GetReference()); jsCompilationUnit.Body.Assign( Js.Reference(compilation.Assembly.GetAssemblyMethodName()), getAssembly); // Add $GetAssemblyMethod to global assemblies array jsCompilationUnit.Body.Express(Js.Reference("$assemblies").Member("push").Invoke(Js.Reference(compilation.Assembly.GetAssemblyMethodName()))); // Builds out all the namespace objects. Types live inside namepsaces, which are represented as // nested Javascript objects. For example, System.Text.StringBuilder is represented (in part) as: // // System = {}; // System.Text = {}; // System.Text.StringBuilder = function() { ... } // // This allows access to classes using dot notation in the expected way. var namespaceTransformer = new NamespaceTransformer(jsCompilationUnit.Body); foreach (var syntaxTree in compilation.SyntaxTrees) { var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot(); compilationUnit.Accept(namespaceTransformer); } var actions = new List <Tuple <INamedTypeSymbol, Action> >(); // Scan all syntax trees for anonymous type creation expressions. We transform them into class // declarations with a series of auto implemented properties. var anonymousTypeTransformer = new AnonymousTypeTransformer(jsCompilationUnit.Body, actions); foreach (var syntaxTree in compilation.SyntaxTrees) { var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot(); compilationUnit.Accept(anonymousTypeTransformer); } var diagnostics = compilation.GetDiagnostics(); foreach (var diagnostic in diagnostics) { Console.WriteLine("// " + diagnostic); } // Iterate through all the syntax trees and add entries into `actions` that correspond to type // declarations. foreach (var syntaxTree in compilation.SyntaxTrees) { var semanticModel = compilation.GetSemanticModel(syntaxTree); var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot(); var transformer = new JsTransformer(syntaxTree, semanticModel); var typeDeclarations = GetTypeDeclarations(compilationUnit); foreach (var type in typeDeclarations) { Action action = () => { var statements = (JsBlockStatement)type.Accept(transformer); jsCompilationUnit.Body.Aggregate(statements); }; actions.Add(Tuple.Create((INamedTypeSymbol)ModelExtensions.GetDeclaredSymbol(semanticModel, type), action)); } var delegateDeclarations = GetDelegates(compilationUnit); foreach (var type in delegateDeclarations) { Action action = () => { var statements = (JsBlockStatement)type.Accept(transformer); jsCompilationUnit.Body.Aggregate(statements); }; actions.Add(Tuple.Create((INamedTypeSymbol)ModelExtensions.GetDeclaredSymbol(semanticModel, type), action)); } } // Sort all the type declarations such that base types always come before subtypes. SweepSort(actions); foreach (var item in actions) { item.Item2(); } // If the project type is a console application, then invoke the Main method at the very // end of the file. var entryPoint = compilation.GetEntryPoint(CancellationToken.None); if (entryPoint != null) { jsCompilationUnit.Body.Express(globalIdioms.InvokeStatic(entryPoint)); } // Test minification // var minifier = new JsMinifier(); // jsCompilationUnit.Accept(minifier); // Write out the compiled Javascript file to the target location. var renderer = new JsRenderer(); jsCompilationUnit.Accept(renderer); return(Tuple.Create(renderer.Output, project)); }