Esempio n. 1
0
        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);
                }
            }
        }
Esempio n. 2
0
        /// <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)));
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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);
        }