private void AddAsseblyReference(List <MetadataImageReference> assemblies, HashSet <AssemblyIdentity> added, AssemblyIdentity assemblyIdentity) { if (added.Contains(assemblyIdentity)) { return; } var resolvedFilePath = this.ResolveReferencePath(assemblyIdentity); if (resolvedFilePath == null) { return; } var metadata = AssemblyMetadata.CreateFromImageStream(new FileStream(resolvedFilePath, FileMode.Open, FileAccess.Read)); if (added.Add(metadata.Assembly.Identity)) { var metadataImageReference = new MetadataImageReference(new FileStream(resolvedFilePath, FileMode.Open, FileAccess.Read)); assemblies.Add(metadataImageReference); this.LoadAssemblySymbol(metadata, true); // process nested foreach (var refAssemblyIdentity in metadata.Assembly.AssemblyReferences) { this.AddAsseblyReference(assemblies, added, refAssemblyIdentity); } } }
/// <summary> /// </summary> /// <param name="assemblyIdentity"> /// </param> /// <returns> /// </returns> private AssemblyMetadata GetAssemblyMetadata(AssemblyIdentity assemblyIdentity) { var resolveReferencePath = this.ResolveReferencePath(assemblyIdentity); if (string.IsNullOrWhiteSpace(resolveReferencePath)) { return(null); } return(AssemblyMetadata.CreateFromImageStream(new FileStream(resolveReferencePath, FileMode.Open, FileAccess.Read))); }
public override bool Execute() { var files = InputFiles.Select(f => new SourceFile { Name = f.ItemSpec, SyntaxTree = SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f.ItemSpec)) }).ToList(); // Creation of the assembly reference should be done this way: // var mscorlib = new MetadataFileReference(typeof(object).Assembly.Location); // But this creates a "path not absolute" exception on mono in GetAssemblyOrModuleSymbol() below. // See http://stackoverflow.com/questions/26355922/creating-roslyn-metadatafilereference-bombs-on-mono-linux var mscorlibMetadata = AssemblyMetadata.CreateFromImageStream(new FileStream(typeof(object).Assembly.Location, FileMode.Open, FileAccess.Read)); var mscorlib = new MetadataImageReference(mscorlibMetadata); var datalibMetadata = AssemblyMetadata.CreateFromImageStream(new FileStream(typeof(CommandBehavior).Assembly.Location, FileMode.Open, FileAccess.Read)); var datalib = new MetadataImageReference(datalibMetadata); var compilation = CSharpCompilation.Create( "Temp", files.Select(f => f.SyntaxTree), new[] { mscorlib, datalib } ); foreach (var file in files) { file.SemanticModel = compilation.GetSemanticModel(file.SyntaxTree); } var corlibSymbol = (IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol(mscorlib); _excludedTypes = new HashSet <ITypeSymbol> { corlibSymbol.GetTypeByMetadataName("System.IO.TextWriter"), corlibSymbol.GetTypeByMetadataName("System.IO.MemoryStream") }; // First pass: find methods with the [GenerateAsync] attribute foreach (var file in files) { foreach (var m in file.SyntaxTree.GetRoot() .DescendantNodes() .OfType <MethodDeclarationSyntax>() ) { // Syntactically filter out any method without [GenerateAsync] (for performance) if (m.AttributeLists.SelectMany(al => al.Attributes).All(a => a.Name.ToString() != "GenerateAsync")) { continue; } var methodSymbol = file.SemanticModel.GetDeclaredSymbol(m); var cls = m.FirstAncestorOrSelf <ClassDeclarationSyntax>(); var ns = cls.FirstAncestorOrSelf <NamespaceDeclarationSyntax>(); Dictionary <ClassDeclarationSyntax, HashSet <MethodInfo> > classes; if (!file.NamespaceToClasses.TryGetValue(ns, out classes)) { classes = file.NamespaceToClasses[ns] = new Dictionary <ClassDeclarationSyntax, HashSet <MethodInfo> >(); } HashSet <MethodInfo> methods; if (!classes.TryGetValue(cls, out methods)) { methods = classes[cls] = new HashSet <MethodInfo>(); } var methodInfo = new MethodInfo { DeclarationSyntax = m, Symbol = methodSymbol, Transformed = m.Identifier.Text + "Async", WithOverride = false }; var attr = methodSymbol.GetAttributes().Single(a => a.AttributeClass.Name == "GenerateAsync"); if (attr.ConstructorArguments.Length > 0 && attr.ConstructorArguments[0].Value != null) { methodInfo.Transformed = (string)attr.ConstructorArguments[0].Value; } if (attr.ConstructorArguments.Length > 1 && ((bool)attr.ConstructorArguments[1].Value)) { methodInfo.WithOverride = true; } methods.Add(methodInfo); } } Log.LogMessage("Found {0} methods marked for async rewriting", files.SelectMany(f => f.NamespaceToClasses.Values).SelectMany(ctm => ctm.Values).SelectMany(m => m).Count()); // Second pass: transform foreach (var f in files) { Log.LogMessage("Writing out {0}", f.TransformedName); File.WriteAllText(f.TransformedName, RewriteFile(f).ToString()); } OutputFiles = files.Select(f => new TaskItem(f.TransformedName)).ToArray(); return(true); }
private AssemblyMetadata CompileWithRoslynInMemory(string[] source) { Console.WriteLine($"RoslynCompile> Compiling sources with Roslyn: {string.Join(" ", source)}\n"); var srcFileName = Path.GetFileNameWithoutExtension(this.FirstSource); var assemblyName = srcFileName; var defineSeparators = new[] { ';', ' ' }; var syntaxTrees = source.Select( s => CSharpSyntaxTree.ParseText( SourceText.From(new FileStream(s, FileMode.Open, FileAccess.Read), Encoding.UTF8), new CSharpParseOptions( LanguageVersion.Experimental, preprocessorSymbols: this.Options["DefineConstants"].Split(defineSeparators, StringSplitOptions.RemoveEmptyEntries)), s)); var assemblies = new List <MetadataImageReference>(); this.Assemblies = this.LoadReferencesForCompiling(assemblies); Console.WriteLine($" > References: {string.Join(" ", assemblies.Select(asm => asm.Display))}"); var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithAllowUnsafe(true) .WithOptimizations(!DebugOutput) .WithRuntimeMetadataVersion("4.5"); var compilation = CSharpCompilation.Create(assemblyName, syntaxTrees, assemblies.ToArray(), options); var dllStream = new MemoryStream(); var pdbStream = new MemoryStream(); PEModuleBuilder.OnMethodBoundBodySynthesizedDelegate peModuleBuilderOnOnMethodBoundBodySynthesized = (symbol, body) => { var key = symbol.ToKeyString(); Debug.Assert(!this.boundBodyByMethodSymbol.ContainsKey(key), "Check if method is partial"); this.boundBodyByMethodSymbol[key] = body; }; PEModuleBuilder.OnSourceMethodDelegate peModuleBuilderOnSourceMethod = (symbol, sourceMethod) => { var key = symbol.ToKeyString(); Debug.Assert(!this.sourceMethodByMethodSymbol.ContainsKey(key), "Check if method is partial"); this.sourceMethodByMethodSymbol[key] = sourceMethod; }; PEModuleBuilder.OnMethodBoundBodySynthesized += peModuleBuilderOnOnMethodBoundBodySynthesized; PEModuleBuilder.OnSourceMethod += peModuleBuilderOnSourceMethod; var result = compilation.Emit(peStream: dllStream, pdbStream: pdbStream); PEModuleBuilder.OnMethodBoundBodySynthesized -= peModuleBuilderOnOnMethodBoundBodySynthesized; PEModuleBuilder.OnSourceMethod -= peModuleBuilderOnSourceMethod; if (result.Diagnostics.Length > 0) { var errors = result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToList(); Console.WriteLine(@"Errors: {0}", errors.Count); foreach (var diagnostic in errors) { Console.WriteLine(diagnostic); } var diagnostics = result.Diagnostics.Where(d => d.Severity != DiagnosticSeverity.Error); Console.WriteLine(@"Warnings/Info: {0}", diagnostics.Count()); foreach (var diagnostic in diagnostics) { Console.WriteLine(diagnostic); } } dllStream.Flush(); dllStream.Position = 0; pdbStream.Flush(); pdbStream.Position = 0; // Successful Compile return(AssemblyMetadata.CreateFromImageStream(dllStream)); }
public void CompilationReferences_More() { string src1 = @" using System; class C { public static int F(object a) { return 1; } public static void Main() { Console.WriteLine(F(null)); } } "; string src2 = @" using System; class C { public static int F(object a) { return 1; } public static void Main() { Console.WriteLine(F(null)); } } "; // Let's say an IL rewriter inserts a new overload of F that references // a type in a new AssemblyRef. string srcPE = @" using System; class C { public static int F(System.Diagnostics.Process a) { return 2; } public static int F(object a) { return 1; } public static void Main() { Console.WriteLine(F(null)); } } "; var md1 = AssemblyMetadata.CreateFromImageStream(CreateCompilation(srcPE, new[] { MscorlibRef, SystemRef }).EmitToStream()); var c1 = CreateCompilation(src1, new[] { MscorlibRef }); var c2 = CreateCompilation(src2, new[] { MscorlibRef }); var baseline = EmitBaseline.CreateInitialBaseline(md1.ManifestModule, (uint i) => ImmutableArray.Create <string>()); var mdStream = new MemoryStream(); var ilStream = new MemoryStream(); var pdbStream = new MemoryStream(); var updatedMethodTokens = new List <uint>(); c2.EmitDifference(baseline, new[] { new SemanticEdit( SemanticEditKind.Update, c1.GlobalNamespace.GetMember <NamedTypeSymbol>("C").GetMember("Main"), c2.GlobalNamespace.GetMember <NamedTypeSymbol>("C").GetMember("Main")) }, mdStream, ilStream, pdbStream, updatedMethodTokens); var actualIL = ilStream.ToArray().GetMethodIL(); // Symbol matcher should ignore overloads with missing type symbols and match // F(object). var expectedIL = @" { // Code size 12 (0xc) .maxstack 8 IL_0000: ldnull IL_0001: call 0x06000002 IL_0006: call 0x0A000005 IL_000b: ret }"; AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL); }
public void CompilationReferences_Less() { // Add some references that are actually not used in the source. // The only actual reference stored in the metadata image would be: mscorlib (rowid 1). // If we incorrectly assume the references are the same we will map TypeRefs of // Mscorlib to System.Windows.Forms. var references = new[] { SystemWindowsFormsRef, MscorlibRef, SystemCoreRef }; string src1 = @" using System; using System.Threading.Tasks; class C { public Task<int> F() { Console.WriteLine(123); return null; } public static void Main() { Console.WriteLine(1); } } "; string src2 = @" using System; using System.Threading.Tasks; class C { public Task<int> F() { Console.WriteLine(123); return null; } public static void Main() { Console.WriteLine(2); } } "; var c1 = CreateCompilation(src1, references); var c2 = CreateCompilation(src2, references); var md1 = AssemblyMetadata.CreateFromImageStream(c1.EmitToStream()); var baseline = EmitBaseline.CreateInitialBaseline(md1.ManifestModule, (uint i) => ImmutableArray.Create <string>()); var mdStream = new MemoryStream(); var ilStream = new MemoryStream(); var pdbStream = new MemoryStream(); var updatedMethodTokens = new List <uint>(); c2.EmitDifference(baseline, new[] { new SemanticEdit( SemanticEditKind.Update, c1.GlobalNamespace.GetMember <NamedTypeSymbol>("C").GetMember("Main"), c2.GlobalNamespace.GetMember <NamedTypeSymbol>("C").GetMember("Main")) }, mdStream, ilStream, pdbStream, updatedMethodTokens); var actualIL = ilStream.ToArray().GetMethodIL(); var expectedIL = @" { // Code size 7 (0x7) .maxstack 8 IL_0000: ldc.i4.2 IL_0001: call 0x0A000005 IL_0006: ret }"; // If the references are mismatched then the symbol matcher won't be able to find Task<T> // and will recompile the method body of F (even though the method hasn't changed). AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedIL, actualIL); }