// Requires:
 //  replacementMethod.Keys == replacementExceptions.Keys
 //
 public RewriteInvariant(RuntimeContractMethods rcm)
 {
     this.rcm = rcm;
 }
Example #2
0
        private static void MikesArchitecture(AssemblyResolver resolver, AssemblyNode assemblyNode,
            ContractNodes contractNodes, ContractNodes backupContracts)
        {
#if false
      var originalsourceDir = Path.GetDirectoryName(assemblyNode.Location);
      int oldPeVerifyCode = options.verify ? PEVerify(assemblyNode.Location, originalsourceDir) : -1;
#endif

            // Check to see if the assembly has already been rewritten

            if (!options.passthrough)
            {
                if (ContractNodes.IsAlreadyRewritten(assemblyNode))
                {
                    if (!options.allowRewritten)
                    {
                        Console.WriteLine("Assembly '" + assemblyNode.Name +
                                          "' has already been rewritten. I, your poor humble servant, cannot rewrite it. Instead I must give up without rewriting it. Help!");
                    }

                    return;
                }
            }

            // Extract the contracts from the code (includes checking the contracts)
            
            string contractFileName = Path.GetFileNameWithoutExtension(assemblyNode.Location) + ".Contracts";

            if (options.contracts == null || options.contracts.Count <= 0) contractFileName = null;

            if (options.contracts != null &&
                !options.contracts.Exists(name => name.Equals(assemblyNode.Name + ".Contracts.dll", StringComparison.OrdinalIgnoreCase)))
            {
                contractFileName = null;
            }

            AssemblyNode contractAssembly = null;
            if (contractFileName != null)
            {
                contractAssembly = resolver.ProbeForAssembly(contractFileName, assemblyNode.Directory,
                    resolver.DllExt);
            }

            if (!options.passthrough)
            {
                ContractNodes usedContractNodes;

                Extractor.ExtractContracts(assemblyNode, contractAssembly, contractNodes, backupContracts, contractNodes,
                    out usedContractNodes, options.EmitError, false);

                // important to extract source before we perform any more traversals due to contract instantiation. Otherwise,
                // we might get copies of contracts due to instantiation that have no source text yet.

                // Extract the text from the sources (optional)

                if (usedContractNodes != null && options.extractSourceText)
                {
                    GenerateDocumentationFromPDB gd = new GenerateDocumentationFromPDB(contractNodes);
                    gd.VisitForDoc(assemblyNode);
                }

                // After all contracts have been extracted in assembly, do some post-extractor checks

                // we run these even if no contracts were extracted due to checks having to do with overrides
                var contractNodesForChecks = usedContractNodes != null ? usedContractNodes : contractNodes;
                if (contractNodesForChecks != null)
                {
                    PostExtractorChecker pec = new PostExtractorChecker(contractNodesForChecks, options.EmitError, false,
                        options.fSharp, options.IsLegacyModeAssembly, options.addInterfaceWrappersWhenNeeded,
                        options.level);

                    if (contractAssembly != null)
                    {
                        pec.VisitForPostCheck(contractAssembly);
                    }
                    else
                    {
                        pec.VisitForPostCheck(assemblyNode);
                    }
                }

                // don't really need to test, since if they are the same, the assignment doesn't change that
                // but this is to emphasize that the nodes used in the AST by the extractor are different
                // than what we thought we were using.

                if (options.GetErrorCount() > 0)
                {
                    // we are done.
                    // But first, report any metadata errors so they are not masked by the errors
                    CheckForMetaDataErrors(assemblyNode);
                    return;
                }
            }

            // If we have metadata errors, cop out

            {
#if false
          for (int i = 0; i < assemblyNode.ModuleReferences.Count; i++)
          {
            Module m = assemblyNode.ModuleReferences[i].Module;
            Console.WriteLine("Location for referenced module '{0}' is '{1}'", m.Name, m.Location);
          }
#endif
                if (CheckForMetaDataErrors(assemblyNode))
                {
                    throw new Exception("Rewrite aborted due to metadata errors. Check output window");
                }
                for (int i = 0; i < assemblyNode.AssemblyReferences.Count; i++)
                {
                    AssemblyNode aref = assemblyNode.AssemblyReferences[i].Assembly;
                    if (CheckForMetaDataErrors(aref))
                    {
                        throw new Exception("Rewrite aborted due to metadata errors. Check output window");
                    }
                }
            }

            // Inject the contracts into the code (optional)

            if (options.rewrite && !options.passthrough)
            {
                // Rewrite the assembly in memory.
                ContractNodes cnForRuntime = null;

                // make sure to use the correct contract nodes for runtime code generation. We may have Contractnodes pointing to microsoft.Contracts even though
                // the code relies on mscorlib to provide the contracts. So make sure the code references the contract nodes first.
                if (contractNodes != null && contractNodes.ContractClass != null &&
                    contractNodes.ContractClass.DeclaringModule != SystemTypes.SystemAssembly)
                {
                    string assemblyNameContainingContracts = contractNodes.ContractClass.DeclaringModule.Name;
                    for (int i = 0; i < assemblyNode.AssemblyReferences.Count; i++)
                    {
                        if (assemblyNode.AssemblyReferences[i].Name == assemblyNameContainingContracts)
                        {
                            cnForRuntime = contractNodes;
                            break; // runtime actually references the contract library
                        }
                    }
                }

                if (cnForRuntime == null)
                {
                    // try to grab the system assembly contracts
                    cnForRuntime = ContractNodes.GetContractNodes(SystemTypes.SystemAssembly, null);
                }

                if (cnForRuntime == null)
                {
                    // Can happen if the assembly does not use contracts directly, but inherits them from some other place
                    // Use the normal contractNodes in this case (actually we should generate whatever we grab from ContractNodes)
                    cnForRuntime = contractNodes;
                }

                RuntimeContractMethods runtimeContracts =
                    new RuntimeContractMethods(userSpecifiedContractType,
                        cnForRuntime, assemblyNode, options.throwOnFailure, options.level, options.publicSurfaceOnly,
                        options.callSiteRequires,
                        options.recursionGuard, options.hideFromDebugger, options.IsLegacyModeAssembly);

                Rewriter rewriter = new Rewriter(assemblyNode, runtimeContracts, options.EmitError,
                    options.inheritInvariants, options.skipQuantifiers);

                rewriter.Verbose = 0 < options.verbose;
                rewriter.Visit(assemblyNode);

                // Perform this check only when there are no out-of-band contracts in use due to rewriter bug #336
                if (contractAssembly == null)
                {
                    PostRewriteChecker checker = new PostRewriteChecker(options.EmitError);
                    checker.Visit(assemblyNode);
                }
            }

            //Console.WriteLine(">>>Finished Rewriting<<<");

            // Set metadata version for target the same as for the source

            TargetPlatform.TargetRuntimeVersion = assemblyNode.TargetRuntimeVersion;

            // Write out the assembly (optional)

            if (options.rewrite || options.passthrough)
            {
                bool updateInPlace = options.output == "same";

                string pdbFile = Path.ChangeExtension(options.assembly, ".pdb");
                bool pdbExists = File.Exists(pdbFile);

                string backupAssembly = options.assembly + ".original";
                string backupPDB = pdbFile + ".original";


                if (updateInPlace)
                {
                    // Write the rewritten assembly in a temporary location.
                    options.output = options.assembly;

                    MoveAssemblyFileAndPDB(options.output, pdbFile, pdbExists, backupAssembly, backupPDB);
                }

                // Write the assembly.
                // Don't pass the debugInfo flag to WriteModule unless the PDB file exists.
                assemblyNode.WriteModule(options.output, options.debug && pdbExists && options.writePDBFile);

                string outputDir = updateInPlace
                    ? Path.GetDirectoryName(options.assembly)
                    : Path.GetDirectoryName(options.output);

                // Re-attach external file resources to the new output assembly.
                MoveModuleResources(assemblyNode, outputDir);

#if false
        if (oldPeVerifyCode == 0)
        {
          var newPeVerifyCode = PEVerify(assemblyNode.Location, originalsourceDir);
          if (newPeVerifyCode > 0)
          {
            if (updateInPlace)
            {
              // move original back in place
              MoveAssemblyFileAndPDB(backupAssembly, backupPDB, pdbExists, options.output, pdbFile);
            }
            throw new Exception("Rewrite failed to produce verifiable assembly");
          }
          else if (newPeVerifyCode == 0)
          {
            Console.WriteLine("rewriter output verified");
          }
        }
#endif
                if (updateInPlace)
                {
                    if (!options.keepOriginalFiles)
                    {
                        try
                        {
                            File.Delete(backupAssembly);
                        }
                        catch
                        {
                            // there are situations where the exe is still in use
                        }
                        if (options.debug && pdbExists && options.writePDBFile)
                        {
                            try
                            {
                                File.Delete(backupPDB);
                            }
                            catch
                            {
                                // I know this is stupid, but somehow on some machines we get an AccessError trying to delete the pdb.
                                // so we leave it in place.
                            }
                        }
                    }
                }
            }
        }