Пример #1
0
        /// <summary>
        ///     Extract an assembly to a new trap file.
        ///     If the trap file exists, skip extraction to avoid duplicating
        ///     extraction within the snapshot.
        /// </summary>
        /// <param name="r">The assembly to extract.</param>
        void DoAnalyseAssembly(PortableExecutableReference r)
        {
            try
            {
                var stopwatch = new Stopwatch();
                stopwatch.Start();

                var assemblyPath  = r.FilePath;
                var projectLayout = layout.LookupProjectOrDefault(assemblyPath);
                using (var trapWriter = projectLayout.CreateTrapWriter(Logger, assemblyPath, true))
                {
                    var skipExtraction = FileIsCached(assemblyPath, trapWriter.TrapFile);

                    if (!skipExtraction)
                    {
                        /* Note on parallel builds:
                         *
                         * The trap writer and source archiver both perform atomic moves
                         * of the file to the final destination.
                         *
                         * If the same source file or trap file are generated concurrently
                         * (by different parallel invocations of the extractor), then
                         * last one wins.
                         *
                         * Specifically, if two assemblies are analysed concurrently in a build,
                         * then there is a small amount of duplicated work but the output should
                         * still be correct.
                         */

                        // compilation.Clone() reduces memory footprint by allowing the symbols
                        // in c to be garbage collected.
                        Compilation c = compilation.Clone();

                        var assembly = c.GetAssemblyOrModuleSymbol(r) as IAssemblySymbol;

                        if (assembly != null)
                        {
                            var cx = new Context(extractor, c, trapWriter, new AssemblyScope(assembly, assemblyPath));

                            foreach (var module in assembly.Modules)
                            {
                                AnalyseNamespace(cx, module.GlobalNamespace);
                            }

                            cx.PopulateAll();
                        }
                    }

                    ReportProgress(assemblyPath, trapWriter.TrapFile, stopwatch.Elapsed, skipExtraction ? AnalysisAction.UpToDate : AnalysisAction.Extracted);
                }
            }
            catch (Exception ex)
            {
                Logger.Log(Severity.Error, "  Unhandled exception analyzing {0}: {1}", r.FilePath, ex);
            }
        }
Пример #2
0
        void DoAnalyseCompilation(string cwd, string[] args)
        {
            try
            {
                var assemblyPath  = extractor.OutputPath;
                var assembly      = compilation.Assembly;
                var projectLayout = layout.LookupProjectOrDefault(assemblyPath);
                var trapWriter    = projectLayout.CreateTrapWriter(Logger, assemblyPath, true, options.TrapCompression);
                compilationTrapFile = trapWriter;  // Dispose later
                var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath, true));

                compilationEntity = new Entities.Compilation(cx, cwd, args);
            }
            catch (Exception ex)  // lgtm[cs/catch-of-all-exceptions]
            {
                Logger.Log(Severity.Error, "  Unhandled exception analyzing {0}: {1}", "compilation", ex);
            }
        }
Пример #3
0
        private void DoAnalyseCompilation()
        {
            try
            {
                var assemblyPath            = extractor.OutputPath;
                var transformedAssemblyPath = PathTransformer.Transform(assemblyPath);
                var assembly      = compilation.Assembly;
                var projectLayout = layout.LookupProjectOrDefault(transformedAssemblyPath);
                var trapWriter    = projectLayout.CreateTrapWriter(Logger, transformedAssemblyPath, options.TrapCompression, discardDuplicates: false);
                compilationTrapFile = trapWriter;  // Dispose later
                var cx = new Context(extractor, compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix);

                compilationEntity = Entities.Compilation.Create(cx);
            }
            catch (Exception ex)  // lgtm[cs/catch-of-all-exceptions]
            {
                Logger.Log(Severity.Error, "  Unhandled exception analyzing {0}: {1}", "compilation", ex);
            }
        }
Пример #4
0
        /// <summary>
        ///   Injects the custom <see cref="CSharpCompilation"/> to the emitting process,
        ///   and resumes it.
        /// </summary>
        /// <seealso href="http://source.roslyn.io/#Microsoft.CodeAnalysis/Compilation/Compilation.cs,42341c66e909e676"/>
        private static void CheckOptionsAndCreateModuleBuilder(RedirectionContext context)
        {
            // Sender is a CSharpCompilation
            CSharpCompilation compilation = (CSharpCompilation)context.Sender;
            CSharpCompilation clone       = compilation.Clone();

            // First argument is a DiagnosticBag
            object diagnosticBag = context.Arguments[0];

            Action <Diagnostic> addDiagnostic = Helpers.MakeAddDiagnostic(diagnosticBag);
            Func <IEnumerable <Diagnostic> > getDiagnostics = Helpers.MakeGetDiagnostics(diagnosticBag);

            object GetOriginal(CSharpCompilation newCompilation)
            {
                object[] args = new object[context.Arguments.Count];
                context.Arguments.CopyTo(args, 0);

                newCompilation.CopyTo(compilation);

                return(context.Invoke(args));
            }

            // CancellationToken should be last argument, but whatever.
            CancellationToken cancellationToken = context.Arguments.OfType <CancellationToken>().FirstOrDefault();

            // Edit the compilation (if a matching CometaryManager is found)
            CompilationRedirection.Stop();

            using (CompilationProcessor manager = CompilationProcessor.Create(GetOriginal, addDiagnostic, getDiagnostics))
            {
                manager.RegisterAttributes(compilation.Assembly);

                // Edit the compilation, and emit it.
                if (manager.TryEditCompilation(compilation, cancellationToken, out CSharpCompilation _, out object moduleBuilder))
                {
                    // No error, we can keep going
                    context.ReturnValue = moduleBuilder;

                    addDiagnostic(Diagnostic.Create(
                                      id: "ProcessSuccess",
                                      category: Common.DiagnosticsCategory,
                                      message: "Successfully edited the emitted compilation.",
                                      severity: DiagnosticSeverity.Info,
                                      defaultSeverity: DiagnosticSeverity.Info,
                                      isEnabledByDefault: true,
                                      warningLevel: -1,
                                      isSuppressed: false));
                }
Пример #5
0
        private static CSharpCompilation GetCompilationWithExternAliases(CSharpCompilation compilation, ImmutableArray<ExternAliasRecord> externAliasRecords)
        {
            if (externAliasRecords.IsDefaultOrEmpty)
            {
                return compilation.Clone();
            }

            var updatedReferences = ArrayBuilder<MetadataReference>.GetInstance();
            var assembliesAndModulesBuilder = ArrayBuilder<Symbol>.GetInstance();
            foreach (var reference in compilation.References)
            {
                updatedReferences.Add(reference);
                assembliesAndModulesBuilder.Add(compilation.GetAssemblyOrModuleSymbol(reference));
            }
            Debug.Assert(assembliesAndModulesBuilder.Count == updatedReferences.Count);

            var assembliesAndModules = assembliesAndModulesBuilder.ToImmutableAndFree();

            foreach (var externAliasRecord in externAliasRecords)
            {
                var targetAssembly = externAliasRecord.TargetAssembly as AssemblySymbol;
                int index;
                if (targetAssembly != null)
                {
                    index = assembliesAndModules.IndexOf(targetAssembly);
                }
                else
                {
                    index = IndexOfMatchingAssembly((AssemblyIdentity)externAliasRecord.TargetAssembly, assembliesAndModules, compilation.Options.AssemblyIdentityComparer);
                }

                if (index < 0)
                {
                    Debug.WriteLine($"Unable to find corresponding assembly reference for extern alias '{externAliasRecord}'");
                    continue;
                }

                var externAlias = externAliasRecord.Alias;

                var assemblyReference = updatedReferences[index];
                var oldAliases = assemblyReference.Properties.Aliases;
                var newAliases = oldAliases.IsEmpty
                    ? ImmutableArray.Create(MetadataReferenceProperties.GlobalAlias, externAlias)
                    : oldAliases.Concat(ImmutableArray.Create(externAlias));

                // NOTE: Dev12 didn't emit custom debug info about "global", so we don't have
                // a good way to distinguish between a module aliased with both (e.g.) "X" and 
                // "global" and a module aliased with only "X".  As in Dev12, we assume that 
                // "global" is a valid alias to remain at least as permissive as source.
                // NOTE: In the event that this introduces ambiguities between two assemblies
                // (e.g. because one was "global" in source and the other was "X"), it should be
                // possible to disambiguate as long as each assembly has a distinct extern alias,
                // not necessarily used in source.
                Debug.Assert(newAliases.Contains(MetadataReferenceProperties.GlobalAlias));

                // Replace the value in the map with the updated reference.
                updatedReferences[index] = assemblyReference.WithAliases(newAliases);
            }

            compilation = compilation.WithReferences(updatedReferences);

            updatedReferences.Free();

            return compilation;
        }
Пример #6
0
        private static CSharpCompilation GetCompilationWithExternAliases(CSharpCompilation compilation, ImmutableArray<string> externAliasStrings)
        {
            if (externAliasStrings.IsDefaultOrEmpty)
            {
                return compilation.Clone();
            }

            var updatedReferences = ArrayBuilder<MetadataReference>.GetInstance();
            var assemblyIdentities = ArrayBuilder<AssemblyIdentity>.GetInstance();
            foreach (var reference in compilation.References)
            {
                var identity = reference.Properties.Kind == MetadataImageKind.Assembly
                    ? ((AssemblySymbol)compilation.GetAssemblyOrModuleSymbol(reference)).Identity
                    : null;
                assemblyIdentities.Add(identity);
                updatedReferences.Add(reference);
            }
            Debug.Assert(assemblyIdentities.Count == updatedReferences.Count);

            var comparer = compilation.Options.AssemblyIdentityComparer;
            var numAssemblies = assemblyIdentities.Count;

            foreach (var externAliasString in externAliasStrings)
            {
                string alias;
                string externAlias;
                string target;
                ImportTargetKind kind;
                if (!CustomDebugInfoReader.TryParseCSharpImportString(externAliasString, out alias, out externAlias, out target, out kind))
                {
                    Debug.WriteLine("Unable to parse extern alias '{0}'", (object)externAliasString);
                    continue;
                }

                Debug.Assert(kind == ImportTargetKind.Assembly, "Programmer error: How did a non-assembly get in the extern alias list?");
                Debug.Assert(alias == null); // Not used.
                Debug.Assert(externAlias != null); // Name of the extern alias.
                Debug.Assert(target != null); // Name of the target assembly.

                AssemblyIdentity targetIdentity;
                if (!AssemblyIdentity.TryParseDisplayName(target, out targetIdentity))
                {
                    Debug.WriteLine("Unable to parse target of extern alias '{0}'", (object)externAliasString);
                    continue;
                }

                int index = -1;
                for (int i = 0; i < numAssemblies; i++)
                {
                    var candidateIdentity = assemblyIdentities[i];
                    if (candidateIdentity != null && comparer.ReferenceMatchesDefinition(targetIdentity, candidateIdentity))
                    {
                        index = i;
                        break;
                    }
                }

                if (index < 0)
                {
                    Debug.WriteLine("Unable to find corresponding assembly reference for extern alias '{0}'", (object)externAliasString);
                    continue;
                }

                var assemblyReference = updatedReferences[index];
                var oldAliases = assemblyReference.Properties.Aliases;
                var newAliases = oldAliases.IsEmpty
                    ? ImmutableArray.Create(MetadataReferenceProperties.GlobalAlias, externAlias)
                    : oldAliases.Concat(ImmutableArray.Create(externAlias));

                // NOTE: Dev12 didn't emit custom debug info about "global", so we don't have
                // a good way to distinguish between a module aliased with both (e.g.) "X" and 
                // "global" and a module aliased with only "X".  As in Dev12, we assume that 
                // "global" is a valid alias to remain at least as permissive as source.
                // NOTE: In the event that this introduces ambiguities between two assemblies
                // (e.g. because one was "global" in source and the other was "X"), it should be
                // possible to disambiguate as long as each assembly has a distinct extern alias,
                // not necessarily used in source.
                Debug.Assert(newAliases.Contains(MetadataReferenceProperties.GlobalAlias));

                // Replace the value in the map with the updated reference.
                updatedReferences[index] = assemblyReference.WithAliases(newAliases);
            }

            compilation = compilation.WithReferences(updatedReferences);

            assemblyIdentities.Free();
            updatedReferences.Free();

            return compilation;
        }