Ejemplo n.º 1
0
        public static void SynthesizeBody(IMethodDeclaration methodDecl, MethodDeclarationSyntax methodSyntax, SemanticModel model, Dictionary <string, ITypeDeclaration> typeDecls)
        {
            var synthesizer = new MethodBodySynthesizer(model, methodDecl.DeclaringType, typeDecls);

            synthesizer.SynthesizeBody(methodDecl, methodSyntax);
        }
        /// <summary>
        /// Returns TypeDeclaration for a given type. Some methods in the returned declaration may miss their bodies, because they contain unsupported constructions.
        /// </summary>
        public ITypeDeclaration GetTypeDeclaration(Type t, bool translate)
        {
            // false by default since, for some reason, excessive tracing seems to cause failure of CompilerOptions test
            bool traceFailures = false;
            // This used to be a cache peersistent between GetTypeDeclaration calls, but
            // it didn't work, because of GetTypeDeclaration's mutability
            Dictionary <string, ITypeDeclaration> declarations = new Dictionary <string, ITypeDeclaration>();
            // To be uncommented when/if ITypeDeclaration will become immutable
            //if (declarations.ContainsKey(t.FullName))
            //{
            //    return declarations[t.FullName];
            //}

            // Collecting all the assemblies, t can possibly need to compile
            var referencedAssemblies       = new HashSet <Assembly>(t.Assembly.GetReferencedAssemblies().Select(Assembly.Load));
            Stack <Assembly> assemblyStack = new Stack <Assembly>();

            foreach (Assembly assembly in referencedAssemblies)
            {
                assemblyStack.Push(assembly);
            }
            while (assemblyStack.Count != 0)
            {
                Assembly assembly = assemblyStack.Pop();
                foreach (AssemblyName name in assembly.GetReferencedAssemblies())
                {
                    try
                    {
                        Assembly referenced = Assembly.Load(name);
                        if (!referencedAssemblies.Contains(referenced))
                        {
                            referencedAssemblies.Add(referenced);
                            assemblyStack.Push(referenced);
                        }
                    }
                    catch (FileNotFoundException) { } // Assembly was referenced but is not present => hopefully, not really needed
                    // Often happens when running code compiled on Windows machine on Linux with Mono
                }
            }
            var references = referencedAssemblies.Select(ra => MetadataReference.CreateFromFile(ra.Location));
            var source     = SourceProvider.TryGetSource(t);

            if (source == null)
            {
                throw new InvalidOperationException($"Cannot find source code for the type {t.Name}");
            }
            var tree = CSharpSyntaxTree.ParseText(source.SourceText, null, source.FilePath, Encoding.UTF8);

            var options            = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
            var targetAssemblyName = Path.GetFileNameWithoutExtension(tree.FilePath);
            var asmName            = t.Assembly.GetName();
            var pk = asmName.GetPublicKey();

            if (pk != null && pk.Length > 0)
            {
                // assembly containing target type is signed
                // spoofing name and signature (via public sign) in order to keep 'make internals visible' working
                targetAssemblyName = asmName.Name;
                options            = options
                                     .WithPublicSign(true)
                                     .WithCryptoPublicKey(System.Collections.Immutable.ImmutableArray.Create(pk));
            }
            var compilation = CSharpCompilation.Create(targetAssemblyName, new[] { tree }, references, options);
            var model       = compilation.GetSemanticModel(tree);

            var errors = compilation.GetDiagnostics().ToList();

            // First pass that just converts structure
            var methodBodies = new DeclarationTreeBuilder(model, t.Assembly, declarations).Build();

            // Convert bodies as declarations are all now in place
            foreach (var kvp in methodBodies)
            {
                var methodDecl   = kvp.Key;
                var methodSyntax = kvp.Value;
                try
                {
                    MethodBodySynthesizer.SynthesizeBody(methodDecl, methodSyntax, model, declarations);
                }
                catch (Exception e)
                {
                    if (traceFailures)
                    {
                        var methodName = methodSyntax.Identifier.ToString();
                        Trace.TraceWarning($"Failed to synthesize the body for method {methodName}: {e}");
                    }

                    // All kinds of compilation issues can arise because we're compiling a single file rather than the project -
                    //   Referencing other classes in the same project
                    //   Non-model methods may have all kinds of syntax that we don't need to or can't support
                }
            }

            // TODO replace this hack
            declarations.Values.Where(td => td.Owner == null).ToList().ForEach(td => td.Owner = t.Assembly);

            var decl = declarations[t.FullName];

            return(decl);
        }