Ejemplo n.º 1
0
        /// <summary>
        /// Loads and returns the topological sorted list of unique assemblies to rewrite.
        /// </summary>
        internal static IEnumerable <AssemblyInfo> LoadAssembliesToRewrite(RewritingOptions options,
                                                                           AssemblyResolveEventHandler handler)
        {
            // Add all explicitly requested assemblies.
            var assemblies = new HashSet <AssemblyInfo>();

            foreach (string path in options.AssemblyPaths)
            {
                if (!assemblies.Any(assembly => assembly.FilePath == path))
                {
                    var name = Path.GetFileName(path);
                    if (options.IsAssemblyIgnored(name))
                    {
                        throw new InvalidOperationException($"Rewriting assembly '{name}' ({path}) that is in the ignore list.");
                    }

                    assemblies.Add(new AssemblyInfo(name, path, options, handler));
                }
            }

            // Find direct dependencies to each assembly and load them, if the corresponding option is enabled.
            foreach (var assembly in assemblies)
            {
                assembly.LoadDependencies(assemblies, handler);
            }

            // Validate that all assemblies are eligible for rewriting.
            foreach (var assembly in assemblies)
            {
                assembly.ValidateAssembly();
            }

            return(SortAssemblies(assemblies));
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="RewritingEngine"/> class.
 /// </summary>
 private RewritingEngine(RewritingOptions options, Configuration configuration, ILogger logger, Profiler profiler)
 {
     this.Options         = options.Sanitize();
     this.Configuration   = configuration;
     this.Passes          = new LinkedList <Pass>();
     this.ResolveWarnings = new HashSet <string>();
     this.Logger          = logger;
     this.Profiler        = profiler;
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Runs the engine using the specified rewriting options.
        /// </summary>
        internal static void Run(RewritingOptions options, Configuration configuration, Profiler profiler)
        {
            var logger = new ConsoleLogger()
            {
                LogLevel = configuration.LogLevel
            };
            var engine = new RewritingEngine(options, configuration, logger, profiler);

            engine.Run();
        }
Ejemplo n.º 4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="AssemblySignature"/> class.
 /// </summary>
 internal AssemblySignature(AssemblyInfo assembly, HashSet <AssemblyInfo> dependencies,
                            Version rewriterVersion, RewritingOptions options)
 {
     this.FullName     = assembly.FullName;
     this.Version      = rewriterVersion.ToString();
     this.Dependencies = new List <string>(dependencies.Select(dependency => dependency.FullName));
     this.IsRewritingConcurrentCollections = options.IsRewritingConcurrentCollections;
     this.IsDataRaceCheckingEnabled        = options.IsDataRaceCheckingEnabled;
     this.IsRewritingDependencies          = options.IsRewritingDependencies;
     this.IsRewritingUnitTests             = options.IsRewritingUnitTests;
     this.IsRewritingThreads = options.IsRewritingThreads;
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TypeRewritingPass"/> class.
        /// </summary>
        internal TypeRewritingPass(RewritingOptions options, IEnumerable <AssemblyInfo> visitedAssemblies, ILogger logger)
            : base(visitedAssemblies, logger)
        {
            this.KnownTypes = new Dictionary <string, Type>();

            // Populate the map with the known compiler types.
            this.KnownTypes[NameCache.AsyncTaskMethodBuilder] =
                typeof(Runtime.CompilerServices.AsyncTaskMethodBuilder);
            this.KnownTypes[NameCache.GenericAsyncTaskMethodBuilder] =
                typeof(Runtime.CompilerServices.AsyncTaskMethodBuilder <>);
            this.KnownTypes[NameCache.TaskAwaiter]             = typeof(Runtime.CompilerServices.TaskAwaiter);
            this.KnownTypes[NameCache.GenericTaskAwaiter]      = typeof(Runtime.CompilerServices.TaskAwaiter <>);
            this.KnownTypes[NameCache.ConfiguredTaskAwaitable] =
                typeof(Runtime.CompilerServices.ConfiguredTaskAwaitable);
            this.KnownTypes[NameCache.GenericConfiguredTaskAwaitable] =
                typeof(Runtime.CompilerServices.ConfiguredTaskAwaitable <>);
            this.KnownTypes[NameCache.ConfiguredTaskAwaiter] =
                typeof(Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter);
            this.KnownTypes[NameCache.GenericConfiguredTaskAwaiter] =
                typeof(Runtime.CompilerServices.ConfiguredTaskAwaitable <> .ConfiguredTaskAwaiter);

            // Populate the map with the default task-based types.
            this.KnownTypes[NameCache.Task]        = typeof(Types.Threading.Tasks.Task);
            this.KnownTypes[NameCache.GenericTask] = typeof(Types.Threading.Tasks.Task <>);
            this.KnownTypes[NameCache.GenericTaskCompletionSource] =
                typeof(Types.Threading.Tasks.TaskCompletionSource <>);
            this.KnownTypes[NameCache.TaskExtensions]     = typeof(Types.TaskExtensions);
            this.KnownTypes[NameCache.TaskFactory]        = typeof(Types.Threading.Tasks.TaskFactory);
            this.KnownTypes[NameCache.GenericTaskFactory] = typeof(Types.Threading.Tasks.TaskFactory <>);
            this.KnownTypes[NameCache.TaskParallel]       = typeof(Types.Threading.Tasks.Parallel);

            // Populate the map with the known synchronization types.
            this.KnownTypes[NameCache.Monitor] = typeof(Types.Threading.Monitor);

            if (options.IsRewritingConcurrentCollections)
            {
                this.KnownTypes[NameCache.ConcurrentBag]        = typeof(Types.Collections.Concurrent.ConcurrentBag <>);
                this.KnownTypes[NameCache.ConcurrentDictionary] = typeof(Types.Collections.Concurrent.ConcurrentDictionary <,>);
                this.KnownTypes[NameCache.ConcurrentQueue]      = typeof(Types.Collections.Concurrent.ConcurrentQueue <>);
                this.KnownTypes[NameCache.ConcurrentStack]      = typeof(Types.Collections.Concurrent.ConcurrentStack <>);
            }

            if (options.IsDataRaceCheckingEnabled)
            {
                this.KnownTypes[NameCache.GenericList]       = typeof(Types.Collections.Generic.List <>);
                this.KnownTypes[NameCache.GenericDictionary] = typeof(Types.Collections.Generic.Dictionary <,>);
                this.KnownTypes[NameCache.GenericHashSet]    = typeof(Types.Collections.Generic.HashSet <>);
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Parses the JSON configuration file and merges the options into the specified
        /// <see cref="RewritingOptions"/> object.
        /// </summary>
        internal static RewritingOptions ParseFromJSON(RewritingOptions options, string configurationPath)
        {
            try
            {
                // TODO: replace with the new 'System.Text.Json'.
                using FileStream fs = new FileStream(configurationPath, FileMode.Open, FileAccess.Read);
                var serializer = new DataContractJsonSerializer(typeof(JsonConfiguration));
                JsonConfiguration configuration = (JsonConfiguration)serializer.ReadObject(fs);

                Uri baseUri     = new Uri(Path.GetDirectoryName(Path.GetFullPath(configurationPath)) + Path.DirectorySeparatorChar);
                Uri resolvedUri = new Uri(baseUri, configuration.AssembliesPath);
                options.AssembliesDirectory = resolvedUri.LocalPath;
                if (string.IsNullOrEmpty(configuration.OutputPath))
                {
                    options.OutputDirectory = options.AssembliesDirectory;
                }
                else
                {
                    resolvedUri             = new Uri(baseUri, configuration.OutputPath);
                    options.OutputDirectory = resolvedUri.LocalPath;
                }

                options.AssemblyPaths = new HashSet <string>();
                if (configuration.Assemblies != null)
                {
                    foreach (string assembly in configuration.Assemblies)
                    {
                        resolvedUri = new Uri(Path.Combine(options.AssembliesDirectory, assembly));
                        options.AssemblyPaths.Add(resolvedUri.LocalPath);
                    }
                }

                options.DependencySearchPaths    = configuration.DependencySearchPaths;
                options.IgnoredAssembliesPattern = GetDisallowedAssembliesRegex(
                    configuration.IgnoredAssemblies ?? Array.Empty <string>());
                options.IsRewritingConcurrentCollections = configuration.IsRewritingConcurrentCollections;
                options.IsDataRaceCheckingEnabled        = configuration.IsDataRaceCheckingEnabled;
                options.IsRewritingDependencies          = configuration.IsRewritingDependencies;
                options.IsRewritingUnitTests             = configuration.IsRewritingUnitTests;
                options.IsRewritingThreads = configuration.IsRewritingThreads;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException(
                          $"Unexpected JSON format in the '{configurationPath}' configuration file.\n{ex.Message}");
            }

            return(options);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Runs the engine using the specified rewriting options.
        /// </summary>
        public static void Run(Configuration configuration, RewritingOptions options)
        {
            if (string.IsNullOrEmpty(options.AssembliesDirectory))
            {
                throw new Exception("Please provide RewritingOptions.AssembliesDirectory");
            }

            if (string.IsNullOrEmpty(options.OutputDirectory))
            {
                throw new Exception("Please provide RewritingOptions.OutputDirectory");
            }

            if (options.AssemblyPaths is null || options.AssemblyPaths.Count is 0)
            {
                throw new Exception("Please provide RewritingOptions.AssemblyPaths");
            }

            var engine = new RewritingEngine(configuration, options);

            engine.Run();
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AssemblyInfo"/> class.
        /// </summary>
        private AssemblyInfo(string name, string path, RewritingOptions options, AssemblyResolveEventHandler handler)
        {
            this.Name         = name;
            this.FilePath     = path;
            this.Dependencies = new HashSet <AssemblyInfo>();
            this.Options      = options;
            this.IsRewritten  = false;
            this.IsDisposed   = false;

            // TODO: can we reuse it, or do we need a new one for each assembly?
            var assemblyResolver = new DefaultAssemblyResolver();

            // Add known search directories for resolving assemblies.
            assemblyResolver.AddSearchDirectory(
                Path.GetDirectoryName(typeof(Types.Threading.Tasks.Task).Assembly.Location));
            assemblyResolver.AddSearchDirectory(this.Options.AssembliesDirectory);
            if (this.Options.DependencySearchPaths != null)
            {
                foreach (var dependencySearchPath in this.Options.DependencySearchPaths)
                {
                    assemblyResolver.AddSearchDirectory(dependencySearchPath);
                }
            }

            // Add the assembly resolution error handler.
            assemblyResolver.ResolveFailure += handler;

            this.Resolver = assemblyResolver;
            var readerParameters = new ReaderParameters()
            {
                AssemblyResolver = assemblyResolver,
                ReadSymbols      = this.IsSymbolFileAvailable()
            };

            this.Definition = AssemblyDefinition.ReadAssembly(this.FilePath, readerParameters);
            this.FullName   = this.Definition.FullName;
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="MethodBodyTypeRewritingPass"/> class.
 /// </summary>
 internal MethodBodyTypeRewritingPass(RewritingOptions options, IEnumerable <AssemblyInfo> visitedAssemblies,
                                      ILogger logger)
     : base(options, visitedAssemblies, logger)
 {
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RewritingEngine"/> class.
        /// </summary>
        /// <param name="configuration">The test configuration to use when rewriting unit tests.</param>
        /// <param name="options">The <see cref="RewritingOptions"/> for this rewriter.</param>
        private RewritingEngine(Configuration configuration, RewritingOptions options)
        {
            this.Configuration = configuration;
            this.Options       = options;
            this.Logger        = options.Logger ?? new ConsoleLogger()
            {
                LogLevel = options.LogLevel
            };
            this.Profiler = new Profiler();

            this.RewrittenAssemblies = new Dictionary <string, AssemblyNameDefinition>();
            var           ignoredAssemblies = options.IgnoredAssemblies ?? Array.Empty <string>();
            StringBuilder combined          = new StringBuilder();

            foreach (var e in this.DefaultDisallowedList.Concat(ignoredAssemblies))
            {
                combined.Append(combined.Length is 0 ? "(" : "|");
                combined.Append(e);
            }

            combined.Append(')');
            try
            {
                this.DisallowedAssemblies = new Regex(combined.ToString());
            }
            catch (Exception ex)
            {
                throw new Exception("DisallowedAssemblies not a valid regular expression\n" + ex.Message);
            }

            this.RewritingPasses = new List <AssemblyRewriter>()
            {
                new TaskRewriter(this.Logger),
                new MonitorRewriter(this.Logger),
                new ExceptionFilterRewriter(this.Logger)
            };

            if (this.Options.IsRewritingThreads)
            {
                this.RewritingPasses.Add(new ThreadingRewriter(this.Logger));
            }

            if (this.Options.IsDataRaceCheckingEnabled)
            {
                this.RewritingPasses.Add(new DataRaceCheckingRewriter(this.Logger));
            }

            if (this.Options.IsRewritingUnitTests)
            {
                // We are running this pass last, as we are rewriting the original method, and
                // we need the other rewriting passes to happen before this pass.
                this.RewritingPasses.Add(new MSTestRewriter(this.Configuration, this.Logger));
            }

            this.RewritingPasses.Add(new AssertionInjectionRewriter(this.Logger));
            this.RewritingPasses.Add(new NotSupportedInvocationRewriter(this.Logger));

            // expand folder
            if (this.Options.AssemblyPaths is null || this.Options.AssemblyPaths.Count is 0)
            {
                // Expand to include all .dll files in AssemblyPaths.
                foreach (var file in Directory.GetFiles(this.Options.AssembliesDirectory, "*.dll"))
                {
                    if (this.IsDisallowed(Path.GetFileName(file)))
                    {
                        this.Options.AssemblyPaths.Add(file);
                    }
                    else
                    {
                        Debug.WriteLine("Skipping " + file);
                    }
                }
            }
        }