Initial commit of AsmMeta to GitHub master
This commit is contained in:
Родитель
c2882898d2
Коммит
560bff217b
|
@ -67,6 +67,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Merged DLL Subset (.NET Nat
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Cci", "Microsoft.Cci.csproj", "{319E151C-8F33-49E7-81C9-30F02F9BA8BB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{AFDC146D-558D-415C-9E30-41E42EC221DF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsmMeta", "Samples\AsmMeta\AsmMeta.csproj", "{469FD908-B6E8-4BF7-8A47-AF541FA8927E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -169,6 +173,10 @@ Global
|
|||
{319E151C-8F33-49E7-81C9-30F02F9BA8BB}.Debug|Any CPU.Build.0 = Debug_GitHub|Any CPU
|
||||
{319E151C-8F33-49E7-81C9-30F02F9BA8BB}.Release|Any CPU.ActiveCfg = Release_GitHub|Any CPU
|
||||
{319E151C-8F33-49E7-81C9-30F02F9BA8BB}.Release|Any CPU.Build.0 = Release_GitHub|Any CPU
|
||||
{469FD908-B6E8-4BF7-8A47-AF541FA8927E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{469FD908-B6E8-4BF7-8A47-AF541FA8927E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{469FD908-B6E8-4BF7-8A47-AF541FA8927E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{469FD908-B6E8-4BF7-8A47-AF541FA8927E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -199,5 +207,6 @@ Global
|
|||
{FC046A88-7F85-4028-A3D2-4986F4C3B73D} = {F36B4F2A-52F8-406D-995C-190FF83EAFFB}
|
||||
{584898C1-C197-4D9A-8231-90B41C2793C9} = {7A77E712-F745-4E50-BAB8-0157F42F7057}
|
||||
{319E151C-8F33-49E7-81C9-30F02F9BA8BB} = {38133ADD-B1A7-4940-A5BC-477738DF1D96}
|
||||
{469FD908-B6E8-4BF7-8A47-AF541FA8927E} = {AFDC146D-558D-415C-9E30-41E42EC221DF}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -0,0 +1,393 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (C) Microsoft Corporation. All Rights Reserved.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Cci;
|
||||
using Microsoft.Cci.MutableCodeModel;
|
||||
using Microsoft.Cci.MutableContracts;
|
||||
|
||||
namespace AsmMeta {
|
||||
delegate void ErrorLogger(string format, params string[] args);
|
||||
|
||||
class AsmMetaOptions : OptionParsing {
|
||||
|
||||
[OptionDescription("Attribute to exempt from whatever polarity keepAttributes is", ShortForm = "a")]
|
||||
public List<string> attrs = new List<string>();
|
||||
|
||||
[OptionDescription("Behave as the original AsmMeta", ShortForm = "b")]
|
||||
public bool backwardCompatibility = false;
|
||||
|
||||
[OptionDescription("Emit contracts", ShortForm = "c")]
|
||||
public bool contracts = true;
|
||||
|
||||
[OptionDescription("Specify what elements to keep", ShortForm = "k")]
|
||||
public KeepOptions whatToEmit = KeepOptions.All;
|
||||
|
||||
[OptionDescription("Only emit security transparent & safe API's", ShortForm = "ot")]
|
||||
public bool onlySecurityTransparent = false;
|
||||
|
||||
[OptionDescription("Emit attributes", ShortForm = "ka")]
|
||||
public bool emitAttributes = true;
|
||||
|
||||
[OptionDescription("Output (full) path for the reference assembly.", ShortForm = "out")]
|
||||
public string output = null;
|
||||
|
||||
[OptionDescription("Rename the assembly itself.", ShortForm = "r")]
|
||||
public bool rename = true;
|
||||
|
||||
[OptionDescription("Just rename the assembly, don't modify it in any other way.", ShortForm = "ro")]
|
||||
public bool renameOnly = false;
|
||||
|
||||
[OptionDescription("When emitting contracts, include the source text of the condition. (Ignored if /contracts is not specified.)", ShortForm = "st")]
|
||||
public bool includeSourceTextInContract = true;
|
||||
|
||||
[OptionDescription("Produce a PDB for output", ShortForm = "pdb")]
|
||||
public bool writePDB = false;
|
||||
|
||||
[OptionDescription("Break into debugger", ShortForm = "break")]
|
||||
public bool doBreak = false;
|
||||
|
||||
[OptionDescription("Search path for referenced assemblies")]
|
||||
public List<string> libPaths = new List<string>();
|
||||
|
||||
[OptionDescription("Full paths to candidate dlls to load for resolution.")]
|
||||
public List<string> resolvedPaths = new List<string>();
|
||||
|
||||
[OptionDescription("Search the GAC for assemblies", ShortForm = "gac")]
|
||||
public bool searchGAC = false;
|
||||
}
|
||||
|
||||
class AsmMeta {
|
||||
|
||||
internal ITypeReference/*?*/ compilerGeneratedAttributeType = null;
|
||||
internal ITypeReference/*?*/ contractClassType = null;
|
||||
internal ITypeReference/*?*/ systemAttributeType = null;
|
||||
internal ITypeReference/*?*/ systemBooleanType = null;
|
||||
internal ITypeReference/*?*/ systemStringType = null;
|
||||
internal ITypeReference/*?*/ systemObjectType = null;
|
||||
internal ITypeReference/*?*/ systemVoidType = null;
|
||||
public readonly AsmMetaOptions options;
|
||||
|
||||
private ErrorLogger errorLogger;
|
||||
|
||||
public AsmMeta(ErrorLogger errorLogger) {
|
||||
this.errorLogger = errorLogger;
|
||||
this.options = new AsmMetaOptions();
|
||||
}
|
||||
|
||||
static int Main(string[] args) {
|
||||
// Make this thing as robust as possible even against JIT failures: put all processing in a sub-method
|
||||
// and call it from here. This method should have as few dependencies as possible.
|
||||
int result = 0;
|
||||
var startTime = DateTime.Now;
|
||||
try {
|
||||
#region Turn off all Debug.Assert calls in the infrastructure so this try-catch will report any errors
|
||||
System.Diagnostics.Debug.Listeners.Clear();
|
||||
System.Diagnostics.Trace.Listeners.Clear();
|
||||
#endregion Turn off all Debug.Assert calls in the infrastructure so this try-catch will report any errors
|
||||
result = RealMain(args);
|
||||
} catch (Exception e) { // swallow everything and just return an error code
|
||||
Console.WriteLine("AsmMeta failed with uncaught exception: {0}", e.Message);
|
||||
Console.WriteLine("Stack trace: {0}", e.StackTrace);
|
||||
return 1;
|
||||
} finally {
|
||||
var delta = DateTime.Now - startTime;
|
||||
Console.WriteLine("elapsed time: {0}ms", delta.TotalMilliseconds);
|
||||
}
|
||||
return result; // success
|
||||
}
|
||||
|
||||
static int RealMain(string[] args) {
|
||||
int errorReturnValue = -1;
|
||||
|
||||
#region Parse the command-line arguments.
|
||||
AsmMeta asmmeta = new AsmMeta(ConsoleErrorLogger);
|
||||
asmmeta.options.Parse(args);
|
||||
if (asmmeta.options.HelpRequested) {
|
||||
asmmeta.options.PrintOptions("");
|
||||
return errorReturnValue;
|
||||
}
|
||||
if (asmmeta.options.HasErrors) {
|
||||
asmmeta.options.PrintErrorsAndExit(Console.Out);
|
||||
}
|
||||
#endregion
|
||||
|
||||
return asmmeta.Run();
|
||||
}
|
||||
|
||||
static void ConsoleErrorLogger(string format, params string[] args) {
|
||||
Console.WriteLine(format, args);
|
||||
}
|
||||
|
||||
internal int Run() {
|
||||
SecurityKeepOptions securityKeepOptions = options.onlySecurityTransparent ? SecurityKeepOptions.OnlyNonCritical : SecurityKeepOptions.All;
|
||||
|
||||
if (options.doBreak) {
|
||||
System.Diagnostics.Debugger.Launch();
|
||||
}
|
||||
|
||||
string assemblyName = null;
|
||||
if (options.GeneralArguments.Count == 1) {
|
||||
assemblyName = options.GeneralArguments[0];
|
||||
}
|
||||
if (assemblyName == null) {
|
||||
errorLogger("Must specify an input file.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
using (var host = new AsmMetaHostEnvironment(options.libPaths.ToArray(), options.searchGAC))
|
||||
{
|
||||
foreach (var p in options.resolvedPaths)
|
||||
{
|
||||
host.AddResolvedPath(p);
|
||||
}
|
||||
|
||||
IAssembly/*?*/ assembly = host.LoadUnitFrom(assemblyName) as IAssembly;
|
||||
if (assembly == null || assembly is Dummy)
|
||||
{
|
||||
errorLogger(assemblyName + " is not a PE file containing a CLR assembly, or an error occurred when loading it.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var rewrittenAttribute = CreateTypeReference(host, assembly, "System.Diagnostics.Contracts.RuntimeContractsAttribute");
|
||||
if (AttributeHelper.Contains(assembly.Attributes, rewrittenAttribute))
|
||||
{
|
||||
errorLogger(assemblyName + " is already rewritten, cannot generate a reference assembly from it.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (options.backwardCompatibility)
|
||||
{ // redundant because RemoveMethodBodies.ctor also does this when the flag is set
|
||||
options.whatToEmit = KeepOptions.ExtVis;
|
||||
options.emitAttributes = false;
|
||||
}
|
||||
|
||||
PdbReader/*?*/ pdbReader = null;
|
||||
if (options.includeSourceTextInContract)
|
||||
{ // No point getting the PDB file unless we want to use it for source text
|
||||
string pdbFile = Path.ChangeExtension(assembly.Location, "pdb");
|
||||
if (File.Exists(pdbFile))
|
||||
{
|
||||
using (var pdbStream = File.OpenRead(pdbFile))
|
||||
{
|
||||
pdbReader = new PdbReader(pdbStream, host);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errorLogger("Could not load the PDB file for the assembly '" + assembly.Name.Value + "' . Source text will not be preserved in the reference assembly. Proceeding anyway.");
|
||||
}
|
||||
}
|
||||
using (pdbReader)
|
||||
{
|
||||
|
||||
|
||||
// We might be working on the assembly that defines the contract class and/or the type System.Void.
|
||||
// (Or any other platform type!)
|
||||
// But the host.PlatformType object has not been duplicated, so its properties will continue to be references to the immutable ones.
|
||||
// This is OK, except if the assembly is being renamed.
|
||||
this.compilerGeneratedAttributeType = host.PlatformType.SystemRuntimeCompilerServicesCompilerGeneratedAttribute;
|
||||
this.contractClassType = host.PlatformType.SystemDiagnosticsContractsContract;
|
||||
this.systemAttributeType = host.PlatformType.SystemAttribute;
|
||||
this.systemBooleanType = host.PlatformType.SystemBoolean;
|
||||
this.systemStringType = host.PlatformType.SystemString;
|
||||
this.systemObjectType = host.PlatformType.SystemObject;
|
||||
this.systemVoidType = host.PlatformType.SystemVoid;
|
||||
//new FindPlatformTypes(this).Traverse(assembly); //update the above fields if any of those types are defined in mutable
|
||||
|
||||
Assembly mutable = new MetadataDeepCopier(host).Copy(assembly);
|
||||
|
||||
#region Rename the assembly in a separate pass because things done in later passes depend on interned keys that are computed based (in part) on the assembly identity
|
||||
|
||||
if (options.rename)
|
||||
{
|
||||
if (options.output != null)
|
||||
mutable.Name = host.NameTable.GetNameFor(Path.GetFileNameWithoutExtension(options.output));
|
||||
else
|
||||
mutable.Name = host.NameTable.GetNameFor(assembly.Name.Value + ".Contracts");
|
||||
mutable.ModuleName = mutable.Name;
|
||||
mutable.Kind = ModuleKind.DynamicallyLinkedLibrary;
|
||||
mutable = (Assembly)RenameAssembly.ReparentAssemblyIdentity(host, assembly.AssemblyIdentity, mutable.AssemblyIdentity, mutable);
|
||||
}
|
||||
|
||||
#endregion Rename the assembly in a separate pass because things done in later passes depend on interned keys that are computed based (in part) on the assembly identity
|
||||
if (!options.renameOnly)
|
||||
{
|
||||
if (options.contracts)
|
||||
{
|
||||
|
||||
if (options.rename)
|
||||
{
|
||||
// We might be working on the assembly that defines the contract class and/or the type System.Void.
|
||||
// (Or any other platform type!)
|
||||
// But the host.PlatformType object has not been duplicated, so its properties will continue to be references to the immutable ones.
|
||||
// This is OK, except if the assembly is being renamed.
|
||||
|
||||
var systemNamespace = GetFirstMatchingNamespace(host, mutable.UnitNamespaceRoot, "System");
|
||||
if (systemNamespace != null)
|
||||
{
|
||||
var typeDefinition = GetFirstMatchingTypeDefinition(host, systemNamespace, "Attribute");
|
||||
if (typeDefinition != null) this.systemAttributeType = typeDefinition;
|
||||
typeDefinition = GetFirstMatchingTypeDefinition(host, systemNamespace, "Boolean");
|
||||
if (typeDefinition != null) this.systemBooleanType = typeDefinition;
|
||||
typeDefinition = GetFirstMatchingTypeDefinition(host, systemNamespace, "Object");
|
||||
if (typeDefinition != null) this.systemObjectType = typeDefinition;
|
||||
typeDefinition = GetFirstMatchingTypeDefinition(host, systemNamespace, "String");
|
||||
if (typeDefinition != null) this.systemStringType = typeDefinition;
|
||||
typeDefinition = GetFirstMatchingTypeDefinition(host, systemNamespace, "Void");
|
||||
if (typeDefinition != null) this.systemVoidType = typeDefinition;
|
||||
|
||||
var systemRuntimeNamespace = GetFirstMatchingNamespace(host, systemNamespace, "Runtime");
|
||||
if (systemRuntimeNamespace != null)
|
||||
{
|
||||
var systemRuntimeCompilerServicesNamespace = GetFirstMatchingNamespace(host, systemRuntimeNamespace, "CompilerServices");
|
||||
if (systemRuntimeCompilerServicesNamespace != null)
|
||||
{
|
||||
typeDefinition = GetFirstMatchingTypeDefinition(host, systemRuntimeCompilerServicesNamespace, "CompilerGeneratedAttribute");
|
||||
if (typeDefinition != null) this.compilerGeneratedAttributeType = typeDefinition;
|
||||
}
|
||||
}
|
||||
|
||||
var systemDiagnosticsNamespace = GetFirstMatchingNamespace(host, systemNamespace, "Diagnostics");
|
||||
if (systemDiagnosticsNamespace != null)
|
||||
{
|
||||
var systemDiagnosticsContractsNamespace = GetFirstMatchingNamespace(host, systemDiagnosticsNamespace, "Contracts");
|
||||
if (systemDiagnosticsContractsNamespace != null)
|
||||
{
|
||||
typeDefinition = GetFirstMatchingTypeDefinition(host, systemDiagnosticsContractsNamespace, "Contract");
|
||||
if (typeDefinition != null) this.contractClassType = typeDefinition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutable = AsmMetaRewriter.RewriteModule(host,
|
||||
pdbReader,
|
||||
mutable,
|
||||
contractClassType,
|
||||
compilerGeneratedAttributeType,
|
||||
systemAttributeType,
|
||||
systemBooleanType,
|
||||
systemObjectType,
|
||||
systemStringType,
|
||||
systemVoidType
|
||||
) as Assembly;
|
||||
}
|
||||
#region Delete things that are not to be kept
|
||||
if (options.backwardCompatibility || options.whatToEmit != KeepOptions.All || !options.emitAttributes || (options.attrs != null && 0 < options.attrs.Count))
|
||||
{
|
||||
DeleteThings thinner = new DeleteThings(host, options.whatToEmit, securityKeepOptions, options.emitAttributes, options.attrs.ToArray(), options.backwardCompatibility);
|
||||
if (securityKeepOptions == SecurityKeepOptions.OnlyNonCritical && host.PlatformType.SystemSecuritySecurityCriticalAttribute.ResolvedType is Dummy)
|
||||
{
|
||||
errorLogger("You asked to remove security critical methods, but the version of mscorlib doesn't support the SecurityCriticalAttribute.");
|
||||
return 1;
|
||||
}
|
||||
thinner.RewriteChildren(mutable);
|
||||
#region Fix up dangling references to things that were deleted
|
||||
FixUpReferences patcher = new FixUpReferences(host, thinner.WhackedMethods, thinner.WhackedTypes);
|
||||
patcher.RewriteChildren(mutable);
|
||||
#endregion Fix up dangling references to things that were deleted
|
||||
}
|
||||
#endregion Delete things that are not to be kept
|
||||
#region Output is always a dll, so mark the assembly as that
|
||||
mutable.EntryPoint = Dummy.MethodReference;
|
||||
mutable.Kind = ModuleKind.DynamicallyLinkedLibrary;
|
||||
#endregion Output is always a dll, so mark the assembly as that
|
||||
}
|
||||
|
||||
assembly = mutable;
|
||||
|
||||
string outputPath;
|
||||
if (options.output != null) // user specified, they'd better make sure it doesn't conflict with anything
|
||||
outputPath = options.output;
|
||||
else if (options.rename) // A.dll ==> A.Contracts.dll (Always! Even if the input is an exe!)
|
||||
outputPath = assembly.Name.Value + ".dll";
|
||||
else // A.dll ==> A.dll.meta
|
||||
outputPath = assembly.Name.Value + Path.GetExtension(assemblyName) + ".meta";
|
||||
// NB: Do *not* pass a pdbWriter to WritePeToStream. No need to create a PDB file and if
|
||||
// it is provided, then it might find things (like constants in a scope) that don't get
|
||||
// visited and so don't have any type references modified as they should be.
|
||||
using (var outputFile = File.Create(outputPath))
|
||||
{
|
||||
if (pdbReader != null && options.writePDB)
|
||||
{
|
||||
using (var pdbWriter = new PdbWriter(Path.ChangeExtension(outputPath, "pdb"), pdbReader))
|
||||
{
|
||||
// Need to not pass in a local scope provider until such time as we have one that will use the mutator
|
||||
// to remap things (like the type of a scope constant) from the original assembly to the mutated one.
|
||||
PeWriter.WritePeToStream(assembly, host, outputFile, pdbReader, null /*pdbReader*/, pdbWriter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PeWriter.WritePeToStream(assembly, host, outputFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
private INamespaceDefinition/*?*/ GetFirstMatchingNamespace(AsmMetaHostEnvironment host, INamespaceDefinition nameSpace, string name) {
|
||||
foreach (var mem in nameSpace.GetMembersNamed(host.NameTable.GetNameFor(name), false)) {
|
||||
var ns = mem as INamespaceDefinition;
|
||||
if (ns != null) return ns;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private INamespaceTypeDefinition/*?*/ GetFirstMatchingTypeDefinition(AsmMetaHostEnvironment host, INamespaceDefinition nameSpace, string name) {
|
||||
foreach (var mem in nameSpace.GetMembersNamed(host.NameTable.GetNameFor(name), false)) {
|
||||
var ntd = mem as INamespaceTypeDefinition;
|
||||
if (ntd != null) return ntd;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a type reference anchored in the given assembly reference and whose names are relative to the given host.
|
||||
/// When the type name has periods in it, a structured reference with nested namespaces is created.
|
||||
/// </summary>
|
||||
private static INamespaceTypeReference CreateTypeReference(IMetadataHost host, IAssemblyReference assemblyReference, string typeName) {
|
||||
IUnitNamespaceReference ns = new Microsoft.Cci.Immutable.RootUnitNamespaceReference(assemblyReference);
|
||||
string[] names = typeName.Split('.');
|
||||
for (int i = 0, n = names.Length - 1; i < n; i++)
|
||||
ns = new Microsoft.Cci.Immutable.NestedUnitNamespaceReference(ns, host.NameTable.GetNameFor(names[i]));
|
||||
return new Microsoft.Cci.Immutable.NamespaceTypeReference(host, ns, host.NameTable.GetNameFor(names[names.Length - 1]), 0, false, false, true, PrimitiveTypeCode.NotPrimitive);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class AsmMetaHostEnvironment : FullyResolvedPathHost {
|
||||
|
||||
internal AsmMetaHostEnvironment(string[] libPaths, bool searchGAC)
|
||||
: base() {
|
||||
foreach (var p in libPaths) {
|
||||
this.AddLibPath(p);
|
||||
}
|
||||
this.SearchInGAC = searchGAC;
|
||||
}
|
||||
|
||||
public override IUnit LoadUnitFrom(string location) {
|
||||
IUnit result = this.peReader.OpenModule(BinaryDocument.GetBinaryDocumentForFile(location, this));
|
||||
this.RegisterAsLatest(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// override this here to not use memory mapped files since we want to use asmmeta in msbuild and it is sticky
|
||||
/// </summary>
|
||||
public override IBinaryDocumentMemoryBlock/*?*/ OpenBinaryDocument(IBinaryDocument sourceDocument) {
|
||||
try {
|
||||
IBinaryDocumentMemoryBlock binDocMemoryBlock = UnmanagedBinaryMemoryBlock.CreateUnmanagedBinaryMemoryBlock(sourceDocument.Location, sourceDocument);
|
||||
this.disposableObjectAllocatedByThisHost.Add((IDisposable)binDocMemoryBlock);
|
||||
return binDocMemoryBlock;
|
||||
} catch (IOException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{469FD908-B6E8-4BF7-8A47-AF541FA8927E}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>AsmMeta</RootNamespace>
|
||||
<AssemblyName>AsmMeta</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation />
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<TargetFrameworkProfile />
|
||||
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<NoWarn>414</NoWarn>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
|
||||
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
|
||||
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
|
||||
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
|
||||
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
|
||||
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
|
||||
<CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
|
||||
<CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
|
||||
<CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
|
||||
<CodeContractsEnumObligations>False</CodeContractsEnumObligations>
|
||||
<CodeContractsPointerObligations>False</CodeContractsPointerObligations>
|
||||
<CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
|
||||
<CodeContractsInferRequires>False</CodeContractsInferRequires>
|
||||
<CodeContractsInferEnsures>False</CodeContractsInferEnsures>
|
||||
<CodeContractsInferObjectInvariants>False</CodeContractsInferObjectInvariants>
|
||||
<CodeContractsSuggestAssumptions>False</CodeContractsSuggestAssumptions>
|
||||
<CodeContractsSuggestRequires>True</CodeContractsSuggestRequires>
|
||||
<CodeContractsSuggestEnsures>False</CodeContractsSuggestEnsures>
|
||||
<CodeContractsSuggestObjectInvariants>False</CodeContractsSuggestObjectInvariants>
|
||||
<CodeContractsDisjunctiveRequires>False</CodeContractsDisjunctiveRequires>
|
||||
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
|
||||
<CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
|
||||
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
|
||||
<CodeContractsEmitXMLDocs>True</CodeContractsEmitXMLDocs>
|
||||
<CodeContractsCustomRewriterAssembly />
|
||||
<CodeContractsCustomRewriterClass />
|
||||
<CodeContractsLibPaths />
|
||||
<CodeContractsExtraRewriteOptions />
|
||||
<CodeContractsExtraAnalysisOptions />
|
||||
<CodeContractsBaseLineFile />
|
||||
<CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
|
||||
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
|
||||
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
|
||||
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>
|
||||
</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
|
||||
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
|
||||
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
|
||||
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
|
||||
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
|
||||
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
|
||||
<CodeContractsNonNullObligations>True</CodeContractsNonNullObligations>
|
||||
<CodeContractsBoundsObligations>True</CodeContractsBoundsObligations>
|
||||
<CodeContractsArithmeticObligations>True</CodeContractsArithmeticObligations>
|
||||
<CodeContractsEnumObligations>True</CodeContractsEnumObligations>
|
||||
<CodeContractsRedundantAssumptions>True</CodeContractsRedundantAssumptions>
|
||||
<CodeContractsAssertsToContractsCheckBox>True</CodeContractsAssertsToContractsCheckBox>
|
||||
<CodeContractsRedundantTests>True</CodeContractsRedundantTests>
|
||||
<CodeContractsMissingPublicRequiresAsWarnings>True</CodeContractsMissingPublicRequiresAsWarnings>
|
||||
<CodeContractsMissingPublicEnsuresAsWarnings>False</CodeContractsMissingPublicEnsuresAsWarnings>
|
||||
<CodeContractsInferRequires>True</CodeContractsInferRequires>
|
||||
<CodeContractsInferEnsures>False</CodeContractsInferEnsures>
|
||||
<CodeContractsInferEnsuresAutoProperties>True</CodeContractsInferEnsuresAutoProperties>
|
||||
<CodeContractsInferObjectInvariants>False</CodeContractsInferObjectInvariants>
|
||||
<CodeContractsSuggestAssumptions>False</CodeContractsSuggestAssumptions>
|
||||
<CodeContractsSuggestAssumptionsForCallees>False</CodeContractsSuggestAssumptionsForCallees>
|
||||
<CodeContractsSuggestRequires>False</CodeContractsSuggestRequires>
|
||||
<CodeContractsNecessaryEnsures>True</CodeContractsNecessaryEnsures>
|
||||
<CodeContractsSuggestObjectInvariants>False</CodeContractsSuggestObjectInvariants>
|
||||
<CodeContractsSuggestReadonly>True</CodeContractsSuggestReadonly>
|
||||
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
|
||||
<CodeContractsShowSquigglies>True</CodeContractsShowSquigglies>
|
||||
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
|
||||
<CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
|
||||
<CodeContractsCustomRewriterAssembly />
|
||||
<CodeContractsCustomRewriterClass />
|
||||
<CodeContractsLibPaths />
|
||||
<CodeContractsExtraRewriteOptions />
|
||||
<CodeContractsExtraAnalysisOptions />
|
||||
<CodeContractsSQLServerOption />
|
||||
<CodeContractsBaseLineFile />
|
||||
<CodeContractsCacheAnalysisResults>True</CodeContractsCacheAnalysisResults>
|
||||
<CodeContractsSkipAnalysisIfCannotConnectToCache>False</CodeContractsSkipAnalysisIfCannotConnectToCache>
|
||||
<CodeContractsFailBuildOnWarnings>False</CodeContractsFailBuildOnWarnings>
|
||||
<CodeContractsBeingOptimisticOnExternal>True</CodeContractsBeingOptimisticOnExternal>
|
||||
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
|
||||
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
|
||||
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CCRefGenTask.cs" />
|
||||
<Compile Include="AsmMeta.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RemoveMethodBodies.cs" />
|
||||
<Compile Include="Rewriter.cs" />
|
||||
<Compile Include="..\..\common\include\Version.cs">
|
||||
<Link>Build\Version.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Converters\ContractExtractor\ContractExtractor.csproj">
|
||||
<Project>{0703D916-A881-45E6-A5CD-6BC50E2E30E2}</Project>
|
||||
<Name>ContractExtractor</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Converters\ILGenerator\ILGenerator.csproj">
|
||||
<Project>{08156C78-403A-4112-AD81-8646AC51CD2F}</Project>
|
||||
<Name>ILGenerator</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\PEReaderAndWriter\PEReader\PeReader.csproj">
|
||||
<Project>{34B9A0CE-DF18-4CBC-8F7A-90C2B74338D5}</Project>
|
||||
<Name>PeReader</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\PEReaderAndWriter\PEWriter\PeWriter.csproj">
|
||||
<Project>{304A8B0B-851B-4AA6-A17D-5F87F39C5E5C}</Project>
|
||||
<Name>PeWriter</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\CoreObjectModel\MutableMetadataModel\MutableMetadataModel.csproj">
|
||||
<Project>{319E151C-8F33-49E7-81C9-30F02F9BA90A}</Project>
|
||||
<Name>MutableMetadataModel</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\CoreObjectModel\MutableCodeModel\MutableCodeModel.csproj">
|
||||
<Project>{319E150C-8F33-49E7-81CA-30F02F9BA90A}</Project>
|
||||
<Name>MutableCodeModel</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\CoreObjectModel\MetadataHelper\MetadataHelper.csproj">
|
||||
<Project>{4A34A3C5-6176-49D7-A4C5-B2B671247F8F}</Project>
|
||||
<Name>MetadataHelper</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\CoreObjectModel\MetadataModel\MetadataModel.csproj">
|
||||
<Project>{33CAB640-0D03-43DF-81BD-22CDC6C0A597}</Project>
|
||||
<Name>MetadataModel</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\PDBReaderAndWriter\PdbReader\PdbReader.csproj">
|
||||
<Project>{A6A31B03-7C3D-4DE6-AA73-BE88116BC40A}</Project>
|
||||
<Name>PdbReader</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\PDBReaderAndWriter\PdbWriter\PdbWriter.csproj">
|
||||
<Project>{6D83F687-ABB5-40B3-915E-CA53DA0EB7F3}</Project>
|
||||
<Name>PdbWriter</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\SourceEmitters\CSharpSourceEmitter\CSharpSourceEmitter.csproj">
|
||||
<Project>{A9103DDA-3A93-441A-8326-6EB20518C251}</Project>
|
||||
<Name>CSharpSourceEmitter</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\CoreObjectModel\SourceModel\SourceModel.csproj">
|
||||
<Project>{4B0054FD-124A-4037-9965-BDB55E6BF389}</Project>
|
||||
<Name>SourceModel</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\CoreObjectModel\CodeModel\CodeModel.csproj">
|
||||
<Project>{035FEA7F-0D36-4AE4-B694-EC45191B9AF2}</Project>
|
||||
<Name>CodeModel</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Build.Engine" />
|
||||
<Reference Include="Microsoft.Build.Framework" />
|
||||
<Reference Include="Microsoft.Build.Tasks" />
|
||||
<Reference Include="Microsoft.Build.Utilities.v3.5">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 3.1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,81 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Build.Utilities;
|
||||
using Microsoft.Build.Framework;
|
||||
|
||||
namespace Microsoft.Research {
|
||||
public class CCRefGen : Task {
|
||||
#region Properties
|
||||
|
||||
bool sourceText = true;
|
||||
public bool IncludeSourceTextInContracts { get { return sourceText; } set { sourceText = value; } }
|
||||
|
||||
public bool Verifiable { get; set; }
|
||||
|
||||
public string Output { get; set; }
|
||||
|
||||
public string Input { get; set; }
|
||||
|
||||
public bool WritePDB { get; set; }
|
||||
|
||||
public ITaskItem[] LibPaths { get; set; }
|
||||
|
||||
public ITaskItem[] ResolvedPaths { get; set; }
|
||||
|
||||
public bool Break { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public override bool Execute() {
|
||||
|
||||
#if DEBUG
|
||||
if (!System.Diagnostics.Debugger.IsAttached)
|
||||
{
|
||||
System.Diagnostics.Debugger.Launch();
|
||||
}
|
||||
#endif
|
||||
|
||||
try {
|
||||
#region Setup parameters
|
||||
|
||||
if (Input == null) { this.Log.LogError("Input parameter must be specified"); return false; }
|
||||
|
||||
AsmMeta.AsmMeta asmmeta = new AsmMeta.AsmMeta(this.ErrorLogger);
|
||||
asmmeta.options.GeneralArguments.Add(Input);
|
||||
asmmeta.options.output = Output;
|
||||
asmmeta.options.includeSourceTextInContract = IncludeSourceTextInContracts;
|
||||
asmmeta.options.writePDB = WritePDB;
|
||||
if (ResolvedPaths!= null) {
|
||||
foreach (var lp in ResolvedPaths)
|
||||
{
|
||||
asmmeta.options.resolvedPaths.Add(lp.ItemSpec);
|
||||
}
|
||||
}
|
||||
if (LibPaths != null)
|
||||
{
|
||||
foreach (var lp in LibPaths)
|
||||
{
|
||||
asmmeta.options.libPaths.Add(lp.ItemSpec);
|
||||
}
|
||||
}
|
||||
asmmeta.options.doBreak = Break;
|
||||
#endregion
|
||||
|
||||
var result = asmmeta.Run();
|
||||
|
||||
return (result == 0);
|
||||
} catch (Exception e) {
|
||||
this.Log.LogError("Exception: {0} caught", e.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorLogger(string format, params string[] args) {
|
||||
this.Log.LogError(format, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("AsmMeta")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("5ec36bc2-06a7-4ed3-8714-3c3cfed37c6c")]
|
||||
|
|
@ -0,0 +1,407 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (C) Microsoft Corporation. All Rights Reserved.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Cci;
|
||||
using Microsoft.Cci.MetadataReader;
|
||||
using Microsoft.Cci.MutableCodeModel;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.Serialization; // needed for defining exception .ctors
|
||||
using System.Text;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace AsmMeta {
|
||||
// For deciding whether to keep a member, there are several interesting axes:
|
||||
// Visibility: Keep everything, or only externally visible items, or external + friends (w/ FriendAccessAllowedAttribute)
|
||||
// Security: Keep all methods, or only methods not marked with the SecurityCriticalAttribute. May add an HPA filter.
|
||||
// Obsolete methods: Keep items marked with ObsoleteAttribute, or only if the ObsoleteAttribute's IsError flag is set, or none.
|
||||
// Inclusion or exclusion list: Did the user tell us via a file to explicitly include or exclude this member?
|
||||
//
|
||||
// Secondary overriding consideration: For a value type appearing in the reference assembly, all of its fields
|
||||
// must also appear in the reference assembly so that managed C++ can get precise size information for the value
|
||||
// type. This may mean including private members that would otherwise be excluded.
|
||||
enum KeepOptions { All, ExtVis, NonPrivate };
|
||||
enum SecurityKeepOptions { All, OnlyNonCritical, /* ExcludeMethodsWithStrictHPAs */ };
|
||||
|
||||
internal class DeleteThings : MetadataRewriter {
|
||||
private KeepOptions WhatToKeep = KeepOptions.All;
|
||||
private SecurityKeepOptions SecurityWhatToKeep = SecurityKeepOptions.All;
|
||||
private bool KeepAttributes = true;
|
||||
private Dictionary<string, bool> ExemptAttributes = new Dictionary<string, bool>();
|
||||
private IMethodReference/*?*/ entryPoint = null;
|
||||
private bool entryPointKept;
|
||||
/// <summary>
|
||||
/// Behave just like the original AsmMeta
|
||||
/// </summary>
|
||||
private bool backwardCompat;
|
||||
|
||||
/// <summary>
|
||||
/// Tables for keeping track of everything that has been whacked. Used for a second pass to fix up references
|
||||
/// to things that have been deleted.
|
||||
/// </summary>
|
||||
internal Dictionary<uint, bool> WhackedTypes = new Dictionary<uint, bool>();
|
||||
internal Dictionary<uint, bool> WhackedMethods = new Dictionary<uint, bool>();
|
||||
|
||||
private AsmMetaHostEnvironment asmMetaHostEnvironment;
|
||||
|
||||
/// <summary>
|
||||
/// Use this constructor when you don't want some things emitted into the output.
|
||||
/// For instance, if <paramref name="e"/> is <code>EmitOptions.ExtVis</code>
|
||||
/// then all methods, types, etc., that are not visible outside of the assembly are not emitted into the output.
|
||||
/// </summary>
|
||||
/// <param name="e">
|
||||
/// Indicates what to emit and what to leave out.
|
||||
/// For instance, if it is <code>EmitOptions.ExtVis</code>
|
||||
/// then all methods, types, etc., that are not visible outside of the assembly
|
||||
/// are not emitted into the output.
|
||||
/// </param>
|
||||
/// <param name="keepAttributes">
|
||||
/// Specify whether to keep custom attributes on types, methods, assembly, etc.
|
||||
/// </param>
|
||||
/// <param name="exemptAttributes">
|
||||
/// A list of attribute names that are exempt from the polarity of <paramref name="keepAttributes"/>.
|
||||
/// For instance, if <paramref name="keepAttributes"/> is true, then if an attribute is in the list, that
|
||||
/// means to not emit it. Conversely, if <paramref name="keepAttributes"/> is false, then if it is in the
|
||||
/// list, it means to emit it.
|
||||
/// </param>
|
||||
/// <param name="backwardCompatibility">
|
||||
/// When true, then this behaves just like the original AsmMeta. That means, among other things, that the argument values
|
||||
/// of <paramref name="e"/> and <paramref name="keepAttributes"/> are ignored and the values KeepOptions.ExtVis and
|
||||
/// false, respectively, are used instead.
|
||||
/// </param>
|
||||
public DeleteThings(AsmMetaHostEnvironment host, KeepOptions e, SecurityKeepOptions transparency, bool keepAttributes, string[] exemptAttributes, bool backwardCompatibility)
|
||||
: base(host) {
|
||||
this.asmMetaHostEnvironment = host;
|
||||
if (backwardCompatibility) {
|
||||
this.WhatToKeep = KeepOptions.ExtVis;
|
||||
this.KeepAttributes = false;
|
||||
this.backwardCompat = true;
|
||||
this.SecurityWhatToKeep = SecurityKeepOptions.All;
|
||||
} else {
|
||||
this.WhatToKeep = e;
|
||||
this.KeepAttributes = keepAttributes;
|
||||
this.SecurityWhatToKeep = transparency;
|
||||
}
|
||||
for (int i = 0, n = exemptAttributes == null ? 0 : exemptAttributes.Length; i < n; i++) {
|
||||
this.ExemptAttributes[exemptAttributes[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
static private bool IsFamilyOrIsFamilyORAssembly(ITypeDefinitionMember typeDefinitionMember) {
|
||||
return typeDefinitionMember.Visibility == TypeMemberVisibility.Family || typeDefinitionMember.Visibility == TypeMemberVisibility.FamilyOrAssembly;
|
||||
}
|
||||
static private bool IsPublic(ITypeDefinition typeDefinition) {
|
||||
INamespaceTypeDefinition namespaceTypeDefinition = typeDefinition as INamespaceTypeDefinition;
|
||||
if (namespaceTypeDefinition != null) return namespaceTypeDefinition.IsPublic;
|
||||
INestedTypeDefinition nestedTypeDefinition = typeDefinition as INestedTypeDefinition;
|
||||
if (nestedTypeDefinition != null) return nestedTypeDefinition.Visibility == TypeMemberVisibility.Public;
|
||||
return false;
|
||||
}
|
||||
|
||||
#region ShouldWhack
|
||||
private bool ShouldWhack(ICustomAttribute a) {
|
||||
string name = TypeHelper.GetTypeName(a.Type);
|
||||
return this.KeepAttributes == this.ExemptAttributes.ContainsKey(name);
|
||||
}
|
||||
private bool ShouldWhack(ITypeDefinition typeDefinition) {
|
||||
if (SecurityWhatToKeep == SecurityKeepOptions.OnlyNonCritical) {
|
||||
if (IsSecurityCritical(typeDefinition))
|
||||
return true;
|
||||
}
|
||||
switch (this.WhatToKeep) {
|
||||
case KeepOptions.All:
|
||||
return false;
|
||||
case KeepOptions.ExtVis:
|
||||
if (typeDefinition is INamespaceTypeDefinition || typeDefinition is INestedTypeDefinition)
|
||||
return !TypeHelper.IsVisibleOutsideAssembly(typeDefinition);
|
||||
return false; // REVIEW: what is the right thing to do here?
|
||||
case KeepOptions.NonPrivate:
|
||||
INamespaceTypeDefinition namespaceTypeDefinition = typeDefinition as INamespaceTypeDefinition;
|
||||
if (namespaceTypeDefinition != null) return !namespaceTypeDefinition.IsPublic;
|
||||
INestedTypeDefinition nestedTypeDefinition = typeDefinition as INestedTypeDefinition;
|
||||
if (nestedTypeDefinition != null) return nestedTypeDefinition.Visibility == TypeMemberVisibility.Private;
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private bool ShouldWhack(ITypeDefinitionMember mem) {
|
||||
if (SecurityWhatToKeep == SecurityKeepOptions.OnlyNonCritical) {
|
||||
if (IsSecurityCritical(mem))
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
((this.WhatToKeep == KeepOptions.ExtVis) && !MemberHelper.IsVisibleOutsideAssembly(mem))
|
||||
||
|
||||
(this.WhatToKeep == KeepOptions.NonPrivate && mem.Visibility == TypeMemberVisibility.Private)
|
||||
);
|
||||
}
|
||||
// Does NOT include methods marked with SecuritySafeCriticalAttribute.
|
||||
private bool IsSecurityCritical(ITypeDefinition type) {
|
||||
return AttributeHelper.Contains(type.Attributes, this.asmMetaHostEnvironment.PlatformType.SystemSecuritySecurityCriticalAttribute);
|
||||
}
|
||||
// Does NOT include methods marked with SecuritySafeCriticalAttribute.
|
||||
private bool IsSecurityCritical(ITypeDefinitionMember member) {
|
||||
return AttributeHelper.Contains(member.Attributes, this.asmMetaHostEnvironment.PlatformType.SystemSecuritySecurityCriticalAttribute);
|
||||
}
|
||||
#endregion ShouldWhack
|
||||
|
||||
public override void RewriteChildren(Assembly assembly) {
|
||||
base.RewriteChildren(assembly);
|
||||
if (this.backwardCompat) {
|
||||
//modifiedAssembly.AssemblyReferences = new List<IAssemblyReference>();
|
||||
assembly.SecurityAttributes = new List<ISecurityAttribute>();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public override void RewriteChildren(Module module) {
|
||||
if (module.EntryPoint is Dummy)
|
||||
this.entryPoint = module.EntryPoint;
|
||||
else
|
||||
this.entryPoint = null;
|
||||
|
||||
base.RewriteChildren(module);
|
||||
|
||||
if (this.entryPoint != null && !this.entryPointKept) module.EntryPoint = Dummy.MethodReference;
|
||||
if (this.backwardCompat) module.TrackDebugData = false; // not preserved by the original AsmMeta
|
||||
return;
|
||||
}
|
||||
|
||||
public override List<INamespaceMember> Rewrite(List<INamespaceMember> namespaceMembers) {
|
||||
List<INamespaceMember> newList = new List<INamespaceMember>();
|
||||
foreach (var namespaceMember in namespaceMembers) {
|
||||
INamespaceTypeDefinition namespaceTypeDefinition = namespaceMember as INamespaceTypeDefinition;
|
||||
if (namespaceTypeDefinition != null) {
|
||||
if (this.ShouldWhack(namespaceTypeDefinition)) {
|
||||
if (!this.WhackedTypes.ContainsKey(namespaceTypeDefinition.InternedKey))
|
||||
this.WhackedTypes.Add(namespaceTypeDefinition.InternedKey, true);
|
||||
continue;
|
||||
}
|
||||
var mutableNamespaceTypeDefinition = (NamespaceTypeDefinition)this.Rewrite(namespaceTypeDefinition);
|
||||
if (this.backwardCompat)
|
||||
mutableNamespaceTypeDefinition.IsBeforeFieldInit = false;
|
||||
newList.Add(mutableNamespaceTypeDefinition);
|
||||
} else {
|
||||
newList.Add(base.Rewrite(namespaceMember));
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public override List<INestedTypeDefinition> Rewrite(List<INestedTypeDefinition> nestedTypes) {
|
||||
List<INestedTypeDefinition> newList = new List<INestedTypeDefinition>();
|
||||
for (int i = 0, n = nestedTypes.Count; i < n; i++) {
|
||||
var nestedTypeDefinition = (NestedTypeDefinition)nestedTypes[i];
|
||||
if (nestedTypeDefinition != null && this.ShouldWhack((ITypeDefinition)nestedTypeDefinition)) {
|
||||
if (!this.WhackedTypes.ContainsKey(nestedTypeDefinition.InternedKey))
|
||||
this.WhackedTypes.Add(nestedTypeDefinition.InternedKey, true);
|
||||
continue;
|
||||
}
|
||||
this.Rewrite(nestedTypeDefinition);
|
||||
if (this.backwardCompat)
|
||||
nestedTypeDefinition.IsBeforeFieldInit = false;
|
||||
newList.Add(nestedTypeDefinition);
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public override List<ICustomAttribute> Rewrite(List<ICustomAttribute> customAttributes) {
|
||||
List<ICustomAttribute> newList = new List<ICustomAttribute>();
|
||||
|
||||
foreach (CustomAttribute customAttribute in customAttributes) {
|
||||
bool keep = true;
|
||||
if (ShouldWhack(customAttribute)) {
|
||||
keep = false; // priority goes to KeepAttribute setting
|
||||
} else {
|
||||
if (this.WhatToKeep != KeepOptions.All) {
|
||||
if (ShouldWhack(customAttribute.Type.ResolvedType)) {
|
||||
keep = false;
|
||||
} else if (customAttribute.Arguments != null) {
|
||||
// need to make sure that if there are any arguments that are types, those
|
||||
// types are public. Otherwise whack the attribute
|
||||
foreach (IMetadataExpression argument in customAttribute.Arguments) {
|
||||
ITypeDefinition typeDefinition = argument.Type as ITypeDefinition;
|
||||
if (typeDefinition != null) {
|
||||
IMetadataConstant ct = argument as IMetadataConstant;
|
||||
if (ct != null) {
|
||||
ITypeDefinition constantValue = ct as ITypeDefinition;
|
||||
if (ShouldWhack(constantValue)) {
|
||||
keep = false;
|
||||
break; // only need to find one to decide to whack attribute
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keep) {
|
||||
newList.Add(customAttribute);
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public override List<IEventDefinition> Rewrite(List<IEventDefinition> events) {
|
||||
List<IEventDefinition> newList = new List<IEventDefinition>();
|
||||
foreach (EventDefinition eventDefinition in events) {
|
||||
if (!ShouldWhack(eventDefinition)) {
|
||||
newList.Add(this.Rewrite(eventDefinition));
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public override List<IFieldDefinition> Rewrite(List<IFieldDefinition> fields) {
|
||||
List<IFieldDefinition> newList = new List<IFieldDefinition>();
|
||||
foreach (FieldDefinition fieldDefinition in fields) {
|
||||
if (!ShouldWhack(fieldDefinition)) {
|
||||
newList.Add(this.Rewrite(fieldDefinition));
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public override List<IMethodDefinition> Rewrite(List<IMethodDefinition> methods) {
|
||||
List<IMethodDefinition> newList = new List<IMethodDefinition>();
|
||||
foreach (MethodDefinition methodDefinition in methods) {
|
||||
bool keep;
|
||||
#region Decide whether to keep method or not
|
||||
if (this.WhatToKeep != KeepOptions.All || this.SecurityWhatToKeep != SecurityKeepOptions.All) {
|
||||
if (false && this.entryPoint != null && this.entryPoint == methodDefinition) { // I just checked the original AsmMeta's behavior and it deletes private Main methods!
|
||||
keep = true; // need entry point even if it is not visible
|
||||
//} else if (method.DeclaringMember != null && method.DeclaringMember.IsVisibleOutsideAssembly) {
|
||||
// keep = true; // believe it or not, one accessor might not be visible, but the other one might be!
|
||||
} else if (IsFamilyOrIsFamilyORAssembly(methodDefinition)
|
||||
&& IsPublic(methodDefinition.ContainingTypeDefinition)
|
||||
&& methodDefinition.ContainingTypeDefinition.IsSealed
|
||||
) {
|
||||
keep = true; // compatibility with AsmMeta's rules...
|
||||
} else {
|
||||
keep = !ShouldWhack(methodDefinition);
|
||||
}
|
||||
} else {
|
||||
keep = true;
|
||||
}
|
||||
#endregion
|
||||
if (keep) { // still need to delete its body
|
||||
if (this.entryPoint == methodDefinition) this.entryPointKept = true;
|
||||
newList.Add(this.Rewrite(methodDefinition));
|
||||
} else {
|
||||
if (!this.WhackedMethods.ContainsKey(methodDefinition.InternedKey))
|
||||
this.WhackedMethods.Add(methodDefinition.InternedKey, true);
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public override List<IPropertyDefinition> Rewrite(List<IPropertyDefinition> properties) {
|
||||
List<IPropertyDefinition> newList = new List<IPropertyDefinition>();
|
||||
foreach (PropertyDefinition propertyDefinition in properties) {
|
||||
if (!ShouldWhack(propertyDefinition)) {
|
||||
newList.Add(this.Rewrite(propertyDefinition));
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
}
|
||||
|
||||
internal class FixUpReferences : MetadataRewriter {
|
||||
|
||||
private Dictionary<uint, bool> whackedMethods;
|
||||
private Dictionary<uint, bool> whackedTypes;
|
||||
|
||||
public FixUpReferences(IMetadataHost host, Dictionary<uint, bool> WhackedMethods, Dictionary<uint, bool> WhackedTypes)
|
||||
: base(host) {
|
||||
this.whackedMethods = WhackedMethods;
|
||||
this.whackedTypes = WhackedTypes;
|
||||
}
|
||||
|
||||
//TODO: what about events?
|
||||
|
||||
public override void RewriteChildren(PropertyDefinition propertyDefinition) {
|
||||
base.RewriteChildren(propertyDefinition);
|
||||
if (propertyDefinition.Accessors != null && 0 < propertyDefinition.Accessors.Count) {
|
||||
var accessors = new List<IMethodReference>(propertyDefinition.Accessors.Count);
|
||||
foreach (var methodReference in propertyDefinition.Accessors)
|
||||
if (!this.whackedMethods.ContainsKey(methodReference.InternedKey))
|
||||
accessors.Add(methodReference);
|
||||
propertyDefinition.Accessors = accessors;
|
||||
}
|
||||
//TODO: what about the getter and setter?
|
||||
return;
|
||||
}
|
||||
|
||||
public override void RewriteChildren(NamespaceTypeDefinition namespaceTypeDefinition) {
|
||||
this.PruneInterfacesAndExplicitImplementationOverrides(namespaceTypeDefinition);
|
||||
base.RewriteChildren(namespaceTypeDefinition);
|
||||
}
|
||||
|
||||
public override void RewriteChildren(NestedTypeDefinition nestedTypeDefinition) {
|
||||
this.PruneInterfacesAndExplicitImplementationOverrides(nestedTypeDefinition);
|
||||
base.RewriteChildren(nestedTypeDefinition);
|
||||
}
|
||||
|
||||
private void PruneInterfacesAndExplicitImplementationOverrides(NamedTypeDefinition typeDefinition) {
|
||||
#region Prune the list of interfaces this type implements (if necessary)
|
||||
if (typeDefinition.Interfaces != null && 0 < typeDefinition.Interfaces.Count) {
|
||||
var newInterfaceList = new List<ITypeReference>();
|
||||
foreach (var iface in typeDefinition.Interfaces) {
|
||||
if (!this.whackedTypes.ContainsKey(iface.InternedKey))
|
||||
newInterfaceList.Add(iface);
|
||||
}
|
||||
typeDefinition.Interfaces = newInterfaceList;
|
||||
}
|
||||
#endregion Prune the list of interfaces this type implements (if necessary)
|
||||
#region Prune the list of explicit implementation overrides (as necessary)
|
||||
if (typeDefinition.ExplicitImplementationOverrides != null && 0 < typeDefinition.ExplicitImplementationOverrides.Count) {
|
||||
var newExplicitImplementationOverrides = new List<IMethodImplementation>();
|
||||
foreach (IMethodImplementation methodImpl in typeDefinition.ExplicitImplementationOverrides) {
|
||||
if (!this.whackedMethods.ContainsKey(methodImpl.ImplementingMethod.InternedKey)) {
|
||||
newExplicitImplementationOverrides.Add(methodImpl);
|
||||
}
|
||||
}
|
||||
typeDefinition.ExplicitImplementationOverrides = newExplicitImplementationOverrides;
|
||||
}
|
||||
#endregion Prune the list of explicit implementation overrides (as necessary)
|
||||
}
|
||||
}
|
||||
|
||||
internal class RenameAssembly : MetadataRewriter {
|
||||
|
||||
private RenameAssembly(IMetadataHost host)
|
||||
: base(host) {
|
||||
}
|
||||
|
||||
private AssemblyIdentity originalAssemblyIdentity = null;
|
||||
private IAssemblyReference replacementAssemblyReference = null;
|
||||
|
||||
public static IUnit ReparentAssemblyIdentity(IMetadataHost host, AssemblyIdentity targetAssemblyIdentity, AssemblyIdentity sourceAssemblyIdentity, IUnit unit) {
|
||||
Contract.Requires(targetAssemblyIdentity != null);
|
||||
Contract.Requires(sourceAssemblyIdentity != null);
|
||||
var rar = new RenameAssembly(host);
|
||||
rar.originalAssemblyIdentity = targetAssemblyIdentity;
|
||||
rar.replacementAssemblyReference = new Microsoft.Cci.Immutable.AssemblyReference(host, sourceAssemblyIdentity);
|
||||
return rar.Rewrite(unit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The object model does not guarantee that the assembly references are shared, so
|
||||
/// since the assembly (which itself can be a reference) is being updated, this method is
|
||||
/// needed in order to guarantee that all references see the update.
|
||||
/// </summary>
|
||||
public override IAssemblyReference Rewrite(IAssemblyReference assemblyReference) {
|
||||
return (assemblyReference.AssemblyIdentity.Equals(originalAssemblyIdentity))
|
||||
?
|
||||
replacementAssemblyReference
|
||||
:
|
||||
base.Rewrite(assemblyReference);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,685 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (C) Microsoft Corporation. All Rights Reserved.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Cci;
|
||||
using Microsoft.Cci.MetadataReader;
|
||||
using Microsoft.Cci.MutableCodeModel;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.Serialization; // needed for defining exception .ctors
|
||||
using System.Text;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace AsmMeta {
|
||||
internal class AsmMetaRewriter : MetadataRewriter {
|
||||
|
||||
private PdbReader pdbReader;
|
||||
private readonly IName MoveNextName;
|
||||
|
||||
/// <summary>
|
||||
/// Maps contract method name to three arg version
|
||||
/// Maps generic Requires method as RequiresE.
|
||||
/// </summary>
|
||||
private Dictionary<string, IMethodReference> threeArgumentVersionofContractMethod = new Dictionary<string, IMethodReference>();
|
||||
private NamespaceTypeDefinition/*?*/ classHoldingThreeArgVersions = null;
|
||||
|
||||
/// <summary>
|
||||
/// Used to recognize calls to methods in the Contract class
|
||||
/// </summary>
|
||||
private readonly ITypeReference compilerGeneratedAttributeType = null;
|
||||
private readonly ITypeReference contractClassType = null;
|
||||
private readonly ITypeReference systemAttributeType = null;
|
||||
private readonly ITypeReference systemBooleanType = null;
|
||||
private readonly ITypeReference systemStringType = null;
|
||||
private readonly ITypeReference systemObjectType = null;
|
||||
private readonly ITypeReference systemVoidType = null;
|
||||
private readonly ITypeReference systemArgumentExceptionType = null;
|
||||
CustomAttribute ContractReferenceAssemblyAttributeInstance;
|
||||
/// <summary>
|
||||
/// The list of all types in the assembly being mutated. Any types introduced to the assembly must be added to this list
|
||||
/// as well as to the members list of their containing namespaces or containing types.
|
||||
/// </summary>
|
||||
List<INamedTypeDefinition> allTypes; // TODO: See if this can be deleted.
|
||||
private IMethodDefinition currentMethod;
|
||||
|
||||
|
||||
private AsmMetaRewriter(
|
||||
IMetadataHost host,
|
||||
PdbReader pdbReader,
|
||||
ITypeReference contractClassType,
|
||||
ITypeReference compilerGeneratedAttributeType,
|
||||
ITypeReference systemAttributeType,
|
||||
ITypeReference systemBooleanType,
|
||||
ITypeReference systemObjectType,
|
||||
ITypeReference systemStringType,
|
||||
ITypeReference systemVoidType
|
||||
)
|
||||
: base(host) {
|
||||
this.pdbReader = pdbReader;
|
||||
this.MoveNextName = host.NameTable.GetNameFor("MoveNext");
|
||||
this.contractClassType = contractClassType;
|
||||
this.compilerGeneratedAttributeType = compilerGeneratedAttributeType;
|
||||
this.systemAttributeType = systemAttributeType;
|
||||
this.systemBooleanType = systemBooleanType;
|
||||
this.systemObjectType = systemObjectType;
|
||||
this.systemStringType = systemStringType;
|
||||
this.systemVoidType = systemVoidType;
|
||||
}
|
||||
|
||||
public static IAssembly RewriteModule(IMetadataHost host, PdbReader pdbReader, IAssembly assembly, ITypeReference contractClassType,
|
||||
ITypeReference compilerGeneratedAttributeType,
|
||||
ITypeReference systemAttributeType,
|
||||
ITypeReference systemBooleanType,
|
||||
ITypeReference systemObjectType,
|
||||
ITypeReference systemStringType,
|
||||
ITypeReference systemVoidType) {
|
||||
var me = new AsmMetaRewriter(host, pdbReader, contractClassType, compilerGeneratedAttributeType, systemAttributeType, systemBooleanType, systemObjectType, systemStringType, systemVoidType);
|
||||
return me.Rewrite(assembly);
|
||||
}
|
||||
|
||||
public override void RewriteChildren(Assembly assembly) {
|
||||
this.allTypes = assembly.AllTypes;
|
||||
base.RewriteChildren(assembly);
|
||||
#region Add assembly-level attribute marking this assembly as a reference assembly
|
||||
if (assembly.AssemblyAttributes == null) assembly.AssemblyAttributes = new List<ICustomAttribute>(1);
|
||||
assembly.AssemblyAttributes.Add(this.ContractReferenceAssemblyAttributeInstance);
|
||||
#endregion Add assembly-level attribute marking this assembly as a reference assembly
|
||||
#region Remove assembly-level attribute marking this as a declarative assembly
|
||||
var contractDeclarativeAssemblyAttribute = UnitHelper.FindType(this.host.NameTable, assembly, "System.Diagnostics.Contracts.ContractDeclarativeAssemblyAttribute")
|
||||
as INamespaceTypeDefinition;
|
||||
if (contractDeclarativeAssemblyAttribute != null) {
|
||||
assembly.AssemblyAttributes.RemoveAll(ca => TypeHelper.TypesAreEquivalent(ca.Type, contractDeclarativeAssemblyAttribute));
|
||||
}
|
||||
|
||||
#endregion
|
||||
return;
|
||||
}
|
||||
|
||||
public override void RewriteChildren(RootUnitNamespace rootUnitNamespace) {
|
||||
this.classHoldingThreeArgVersions = this.GetContractClass(rootUnitNamespace);
|
||||
|
||||
base.RewriteChildren(rootUnitNamespace);
|
||||
|
||||
#region Possibly add class for any contract methods that were defined.
|
||||
if (0 < this.threeArgumentVersionofContractMethod.Count) {
|
||||
// Only add class to assembly if any 3 arg versions were actually created
|
||||
rootUnitNamespace.Members.Add(classHoldingThreeArgVersions);
|
||||
this.allTypes.Add(classHoldingThreeArgVersions);
|
||||
}
|
||||
#endregion Possibly add class for any contract methods that were defined.
|
||||
|
||||
#region Create a reference to [ContractReferenceAssembly] to mark the assembly with
|
||||
INamespaceTypeDefinition contractReferenceAssemblyAttribute = null;
|
||||
#region First see if we can find it in the same assembly as the one we are rewriting
|
||||
var unit = rootUnitNamespace.Unit;
|
||||
contractReferenceAssemblyAttribute = UnitHelper.FindType(this.host.NameTable, unit, "System.Diagnostics.Contracts.ContractReferenceAssemblyAttribute")
|
||||
as INamespaceTypeDefinition;
|
||||
#endregion First see if we can find it in the same assembly as the one we are rewriting
|
||||
#region If it doesn't exist there, then define it in the same place that the three-argument versions are defined
|
||||
if (contractReferenceAssemblyAttribute is Dummy) {
|
||||
contractReferenceAssemblyAttribute = CreateContractReferenceAssemblyAttribute(rootUnitNamespace);
|
||||
}
|
||||
#endregion If it doesn't exist there, then define it in the same place that the three-argument versions are defined
|
||||
#region Create a reference to the ctor
|
||||
var ctorRef = new Microsoft.Cci.MutableCodeModel.MethodReference() {
|
||||
CallingConvention = CallingConvention.HasThis,
|
||||
ContainingType = contractReferenceAssemblyAttribute,
|
||||
InternFactory = this.host.InternFactory,
|
||||
Name = host.NameTable.Ctor,
|
||||
Type = systemVoidType,
|
||||
};
|
||||
var rm = ctorRef.ResolvedMethod;
|
||||
this.ContractReferenceAssemblyAttributeInstance = new CustomAttribute() {
|
||||
Constructor = ctorRef,
|
||||
};
|
||||
#endregion Create a reference to the ctor
|
||||
#endregion Create a reference to [ContractReferenceAssembly] to mark the assembly with
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public override void RewriteChildren(MethodBody methodBody) {
|
||||
|
||||
this.currentMethod = methodBody.MethodDefinition;
|
||||
|
||||
var compilerGenerated = TypeHelper.IsCompilerGenerated(currentMethod.ContainingTypeDefinition);
|
||||
// Method contracts from iterators (and async methods) end up in the MoveNext method in the compiler generated
|
||||
// class that implements the state machine. So they need to be treated specially.
|
||||
var isMoveNextMethodInCompilerGeneratedMethod = compilerGenerated && currentMethod.Name == this.MoveNextName;
|
||||
|
||||
if ((compilerGenerated && !isMoveNextMethodInCompilerGeneratedMethod) || this.IsIteratorOrAsyncMethod(currentMethod)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint lastOffset;
|
||||
if (!TryGetOffsetOfLastContractCall(methodBody.Operations, out lastOffset))
|
||||
return;
|
||||
// And here is the special handling: currently the contract extractors expect to find the contracts
|
||||
// in the MoveNext method. So don't move them to the iterator/async method, just convert all of the
|
||||
// contracts in the MoveNext method into the three-arg version and keep the whole method body. No
|
||||
// point trying to truncate it since the contracts are not in a prefix of the instructions, but are
|
||||
// buried within the state machine.
|
||||
if (isMoveNextMethodInCompilerGeneratedMethod) {
|
||||
var lastIndex = methodBody.Operations.Count - 1;
|
||||
lastOffset = methodBody.Operations[lastIndex].Offset;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
var ilRewriter = new MyILRewriter(this.host, this, lastOffset, isMoveNextMethodInCompilerGeneratedMethod);
|
||||
var rewrittenMethodBody = ilRewriter.Rewrite(methodBody);
|
||||
|
||||
var locals = rewrittenMethodBody.LocalVariables;
|
||||
|
||||
methodBody.LocalVariables = locals as List<ILocalDefinition> ?? new List<ILocalDefinition>(locals);
|
||||
|
||||
var ops = rewrittenMethodBody.Operations;
|
||||
methodBody.Operations = ops as List<IOperation> ?? new List<IOperation>(ops);
|
||||
|
||||
methodBody.OperationExceptionInformation = new List<IOperationExceptionInformation>();
|
||||
|
||||
methodBody.MaxStack = rewrittenMethodBody.MaxStack;
|
||||
methodBody.MaxStack++;
|
||||
|
||||
//// REVIEW: Is this okay to do here? Or does it need to be done in the IL Rewriter?
|
||||
//#region All done: add return statement
|
||||
//if (!isMoveNextMethodInCompilerGeneratedMethod) {
|
||||
// if (currentMethod.Type.TypeCode != PrimitiveTypeCode.Void) {
|
||||
// LocalDefinition ld = new LocalDefinition() {
|
||||
// Type = currentMethod.Type,
|
||||
// };
|
||||
// if (methodBody.LocalVariables == null) methodBody.LocalVariables = new List<ILocalDefinition>();
|
||||
// methodBody.LocalVariables.Add(ld);
|
||||
// methodBody.Operations.Add(new Operation(){ OperationCode= OperationCode.Ldloc, Value = ld, });
|
||||
// methodBody.MaxStack++;
|
||||
// }
|
||||
// methodBody.Operations.Add(new Operation() { OperationCode = OperationCode.Ret, });
|
||||
//}
|
||||
//#endregion All done: add return statement
|
||||
|
||||
return;
|
||||
|
||||
} catch (ExtractorException) {
|
||||
Console.WriteLine("Warning: Unable to extract contract from the method '{0}'.",
|
||||
MemberHelper.GetMemberSignature(currentMethod, NameFormattingOptions.SmartTypeName));
|
||||
methodBody.OperationExceptionInformation = new List<IOperationExceptionInformation>();
|
||||
methodBody.Operations = new List<IOperation>();
|
||||
methodBody.MaxStack = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Methods that are iterators or async methods must have their bodies preserved
|
||||
/// in the reference assembly because (for now) their contracts are left in the
|
||||
/// MoveNext method found in the nested type defined in the containing type of this
|
||||
/// method. The contract extraction that is done by downstream tools depends on
|
||||
/// *this* method containing the preamble that creates an instance of that nested
|
||||
/// type, otherwise they assume the method does *not* have any contracts (which
|
||||
/// is incorrect).
|
||||
/// </summary>
|
||||
private bool IsIteratorOrAsyncMethod(IMethodDefinition currentMethod) {
|
||||
// walk the Operations looking for the first newobj instruction
|
||||
IMethodReference ctor = null;
|
||||
foreach (var op in currentMethod.Body.Operations) {
|
||||
if (op.OperationCode == OperationCode.Newobj) {
|
||||
ctor = op.Value as IMethodReference;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ctor == null) return false;
|
||||
var nestedType = ctor.ContainingType as INestedTypeReference;
|
||||
if (nestedType == null) return false;
|
||||
if (nestedType.ContainingType.InternedKey != currentMethod.ContainingType.InternedKey) return false;
|
||||
if (!TypeHelper.IsCompilerGenerated(ctor.ResolvedMethod.ContainingTypeDefinition)) return false;
|
||||
var m = TypeHelper.GetMethod(nestedType.ResolvedType, this.host.NameTable.GetNameFor("MoveNext"));
|
||||
return !(m is Dummy);
|
||||
}
|
||||
|
||||
private bool TryGetOffsetOfLastContractCall(List<IOperation>/*?*/ instrs, out uint offset) {
|
||||
offset = uint.MaxValue;
|
||||
if (instrs == null) return false; // not found
|
||||
for (int i = instrs.Count - 1; 0 <= i; i--) {
|
||||
IOperation op = instrs[i];
|
||||
if (op.OperationCode != OperationCode.Call) continue;
|
||||
IMethodReference method = op.Value as IMethodReference;
|
||||
if (method == null) continue;
|
||||
if (Microsoft.Cci.MutableContracts.ContractHelper.IsValidatorOrAbbreviator(method)) {
|
||||
offset = op.Offset;
|
||||
return true;
|
||||
}
|
||||
var methodName = method.Name.Value;
|
||||
if (TypeHelper.TypesAreEquivalent(method.ContainingType, this.contractClassType)
|
||||
&& IsNameOfPublicContractMethod(methodName)
|
||||
) {
|
||||
offset = op.Offset;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // not found
|
||||
}
|
||||
|
||||
private bool IsNameOfPublicContractMethod(string methodName) {
|
||||
switch (methodName) {
|
||||
case "Requires":
|
||||
case "RequiresAlways":
|
||||
case "Ensures":
|
||||
case "EnsuresOnThrow":
|
||||
case "Invariant":
|
||||
case "EndContractBlock":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyILRewriter : ILRewriter {
|
||||
private AsmMetaRewriter parent;
|
||||
private uint lastOffset;
|
||||
private bool moveNextMethod;
|
||||
|
||||
public MyILRewriter(IMetadataHost host, AsmMetaRewriter parent, uint lastOffset, bool moveNextMethod)
|
||||
: base(host, parent.pdbReader, parent.pdbReader) {
|
||||
this.parent = parent;
|
||||
this.lastOffset = lastOffset;
|
||||
this.moveNextMethod = moveNextMethod;
|
||||
}
|
||||
|
||||
protected override void EmitOperation(IOperation operation) {
|
||||
if (operation.Offset <= this.lastOffset) {
|
||||
if (this.parent.IsCallToContractMethod(operation)) {
|
||||
EmitContractCall(operation);
|
||||
} else {
|
||||
base.EmitOperation(operation);
|
||||
}
|
||||
if (!this.moveNextMethod && operation.Offset == this.lastOffset) {
|
||||
#region All done: add return statement
|
||||
if (this.parent.currentMethod.Type.TypeCode != PrimitiveTypeCode.Void) {
|
||||
var ld = new LocalDefinition() {
|
||||
Type = this.parent.currentMethod.Type,
|
||||
};
|
||||
base.EmitOperation(new Operation() { OperationCode = OperationCode.Ldloc, Value = ld, });
|
||||
base.TrackLocal(ld);
|
||||
}
|
||||
base.EmitOperation(new Operation() { OperationCode = OperationCode.Ret, });
|
||||
#endregion All done: add return statement
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void EmitContractCall(IOperation op) {
|
||||
IMethodReference originalMethod = op.Value as IMethodReference;
|
||||
IMethodReference methodToUse = this.parent.GetCorrespondingThreeArgContractMethod(originalMethod);
|
||||
string sourceText = null;
|
||||
if (this.parent.pdbReader != null) {
|
||||
int startColumn;
|
||||
string sourceLanguage;
|
||||
this.parent.GetSourceTextFromOperation(op, out sourceText, out startColumn, out sourceLanguage);
|
||||
if (sourceText != null) {
|
||||
int firstSourceTextIndex = sourceText.IndexOf('(');
|
||||
int lastSourceTextIndex = this.parent.GetLastSourceTextIndex(sourceText, originalMethod, firstSourceTextIndex + 1);
|
||||
firstSourceTextIndex = firstSourceTextIndex == -1 ? 0 : firstSourceTextIndex + 1; // the +1 is to skip the opening paren
|
||||
if (lastSourceTextIndex <= firstSourceTextIndex) {
|
||||
//Console.WriteLine(sourceText);
|
||||
lastSourceTextIndex = sourceText.Length; // if something went wrong, at least get the whole source text.
|
||||
}
|
||||
sourceText = sourceText.Substring(firstSourceTextIndex, lastSourceTextIndex - firstSourceTextIndex);
|
||||
var indentSize = firstSourceTextIndex + (startColumn - 1); // -1 because columns start at one, not zero
|
||||
sourceText = AdjustIndentationOfMultilineSourceText(sourceText, indentSize);
|
||||
}
|
||||
}
|
||||
if (originalMethod.ParameterCount == 1) {
|
||||
// add null user message
|
||||
base.EmitOperation(new Operation() { OperationCode = OperationCode.Ldnull, });
|
||||
}
|
||||
if (sourceText == null) {
|
||||
base.EmitOperation(new Operation() { OperationCode = OperationCode.Ldnull });
|
||||
} else {
|
||||
base.EmitOperation(new Operation() { OperationCode = OperationCode.Ldstr, Value = sourceText });
|
||||
}
|
||||
base.EmitOperation(new Operation() { OperationCode = OperationCode.Call, Value = methodToUse });
|
||||
return;
|
||||
}
|
||||
|
||||
private static string AdjustIndentationOfMultilineSourceText(string sourceText, int trimLength) {
|
||||
if (!sourceText.Contains("\n")) return sourceText;
|
||||
var lines = sourceText.Split('\n');
|
||||
if (lines.Length == 1) return sourceText;
|
||||
for (int i = 1; i < lines.Length; i++) {
|
||||
var currentLine = lines[i];
|
||||
if (trimLength < currentLine.Length) {
|
||||
var prefix = currentLine.Substring(0, trimLength);
|
||||
if (All(prefix, ' ')) {
|
||||
lines[i] = currentLine.Substring(trimLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
var numberOfLinesToJoin = String.IsNullOrEmpty(lines[lines.Length - 1].TrimStart(whiteSpace)) ? lines.Length - 1 : lines.Length;
|
||||
return String.Join("\n", lines, 0, numberOfLinesToJoin);
|
||||
}
|
||||
static char[] whiteSpace = { ' ', '\t' };
|
||||
private static bool All(string s, char c) {
|
||||
foreach (var x in s)
|
||||
if (x != c) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private NamespaceTypeDefinition GetContractClass(RootUnitNamespace unitNamespace) {
|
||||
var contractClass = UnitHelper.FindType(this.host.NameTable, (IModule)unitNamespace.Unit, "System.Diagnostics.Contracts.Contract")
|
||||
as NamespaceTypeDefinition;
|
||||
|
||||
if (contractClass != null) return contractClass;
|
||||
return CreateContractClass(unitNamespace);
|
||||
}
|
||||
private NamespaceTypeDefinition CreateContractClass(UnitNamespace unitNamespace) {
|
||||
|
||||
var contractTypeName = this.host.NameTable.GetNameFor("Contract");
|
||||
var contractNamespaceName = this.host.NameTable.GetNameFor("System.Diagnostics.Contracts");
|
||||
|
||||
Microsoft.Cci.MethodReference compilerGeneratedCtor =
|
||||
new Microsoft.Cci.MethodReference(
|
||||
this.host,
|
||||
this.compilerGeneratedAttributeType,
|
||||
CallingConvention.HasThis,
|
||||
this.systemVoidType,
|
||||
this.host.NameTable.Ctor,
|
||||
0);
|
||||
CustomAttribute compilerGeneratedAttribute = new CustomAttribute();
|
||||
compilerGeneratedAttribute.Constructor = compilerGeneratedCtor;
|
||||
|
||||
var contractsNs = new NestedUnitNamespace() {
|
||||
ContainingUnitNamespace = unitNamespace,
|
||||
Name = contractNamespaceName,
|
||||
};
|
||||
NamespaceTypeDefinition result = new NamespaceTypeDefinition() {
|
||||
// NB: The string name must be kept in sync with the code that recognizes contract
|
||||
// methods!!
|
||||
Name = contractTypeName,
|
||||
Attributes = new List<ICustomAttribute>{ compilerGeneratedAttribute },
|
||||
BaseClasses = new List<ITypeReference>{ this.systemObjectType },
|
||||
ContainingUnitNamespace = contractsNs,
|
||||
InternFactory = this.host.InternFactory,
|
||||
IsBeforeFieldInit = true,
|
||||
IsClass = true,
|
||||
IsSealed = true,
|
||||
Layout = LayoutKind.Auto,
|
||||
StringFormat = StringFormatKind.Ansi,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
private NamespaceTypeDefinition CreateContractReferenceAssemblyAttribute(IRootUnitNamespace rootNs) {
|
||||
|
||||
var internFactory = this.host.InternFactory;
|
||||
var nameTable = this.host.NameTable;
|
||||
|
||||
var contractReferenceAssemblyAttributeName = nameTable.GetNameFor("ContractReferenceAssemblyAttribute");
|
||||
var contractNamespaceName = nameTable.GetNameFor("System.Diagnostics.Contracts");
|
||||
|
||||
#region Define type
|
||||
CustomAttribute compilerGeneratedAttribute = new CustomAttribute() {
|
||||
Constructor = new Microsoft.Cci.MethodReference(
|
||||
this.host,
|
||||
this.compilerGeneratedAttributeType,
|
||||
CallingConvention.HasThis,
|
||||
this.systemVoidType,
|
||||
this.host.NameTable.Ctor,
|
||||
0)
|
||||
};
|
||||
|
||||
var contractsNs = new NestedUnitNamespace() {
|
||||
ContainingUnitNamespace = rootNs,
|
||||
Name = contractNamespaceName,
|
||||
};
|
||||
NamespaceTypeDefinition result = new NamespaceTypeDefinition() {
|
||||
Name = contractReferenceAssemblyAttributeName,
|
||||
Attributes = new List<ICustomAttribute>{ compilerGeneratedAttribute },
|
||||
BaseClasses = new List<ITypeReference>{ this.systemAttributeType },
|
||||
ContainingUnitNamespace = contractsNs, //unitNamespace,
|
||||
InternFactory = internFactory,
|
||||
IsBeforeFieldInit = true,
|
||||
IsClass = true,
|
||||
IsSealed = true,
|
||||
Methods = new List<IMethodDefinition>(),
|
||||
Layout = LayoutKind.Auto,
|
||||
StringFormat = StringFormatKind.Ansi,
|
||||
};
|
||||
contractsNs.Members.Add(result);
|
||||
this.allTypes.Add(result);
|
||||
#endregion Define type
|
||||
#region Define the ctor
|
||||
List<IStatement> statements = new List<IStatement>();
|
||||
SourceMethodBody body = new SourceMethodBody(this.host) {
|
||||
LocalsAreZeroed = true,
|
||||
Block = new BlockStatement() { Statements = statements },
|
||||
};
|
||||
MethodDefinition ctor = new MethodDefinition() {
|
||||
Body = body,
|
||||
CallingConvention = CallingConvention.HasThis,
|
||||
ContainingTypeDefinition = result,
|
||||
InternFactory = internFactory,
|
||||
IsRuntimeSpecial = true,
|
||||
IsStatic = false,
|
||||
IsSpecialName = true,
|
||||
Name = nameTable.Ctor,
|
||||
Type = this.systemVoidType,
|
||||
Visibility = TypeMemberVisibility.Public,
|
||||
};
|
||||
body.MethodDefinition = ctor;
|
||||
var thisRef = new ThisReference() { Type = result, };
|
||||
// base();
|
||||
foreach (var baseClass in result.BaseClasses) {
|
||||
var baseCtor = new Microsoft.Cci.MutableCodeModel.MethodReference() {
|
||||
CallingConvention = CallingConvention.HasThis,
|
||||
ContainingType = baseClass,
|
||||
GenericParameterCount = 0,
|
||||
InternFactory = this.host.InternFactory,
|
||||
Name = nameTable.Ctor,
|
||||
Type = this.systemVoidType,
|
||||
};
|
||||
statements.Add(
|
||||
new ExpressionStatement() {
|
||||
Expression = new MethodCall() {
|
||||
MethodToCall = baseCtor,
|
||||
IsStaticCall = false, // REVIEW: Is this needed in addition to setting the ThisArgument?
|
||||
ThisArgument = new ThisReference() { Type = result, },
|
||||
Type = this.systemVoidType, // REVIEW: Is this the right way to do this?
|
||||
Arguments = new List<IExpression>(),
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
// return;
|
||||
statements.Add(new ReturnStatement());
|
||||
result.Methods.Add(ctor);
|
||||
#endregion Define the ctor
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool IsCallToContractMethod(IOperation op) {
|
||||
if (op.OperationCode != OperationCode.Call) return false;
|
||||
IMethodReference method = op.Value as IMethodReference;
|
||||
if (method == null) return false;
|
||||
ITypeReference contractClass = method.ContainingType;
|
||||
if (!TypeHelper.TypesAreEquivalent(contractClass, this.contractClassType)) return false;
|
||||
switch (method.Name.Value) {
|
||||
case "Requires":
|
||||
case "RequiresAlways": // TODO: Remove once RequiresAlways is gone from the library
|
||||
case "Ensures":
|
||||
case "EnsuresOnThrow":
|
||||
case "Invariant":
|
||||
case "Assert":
|
||||
case "Assume":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private IMethodReference GetCorrespondingThreeArgContractMethod(IMethodReference originalMethod) {
|
||||
ushort genericParameters = 0;
|
||||
string contractMethodName = originalMethod.Name.Value;
|
||||
string keyName = contractMethodName;
|
||||
IGenericMethodInstanceReference methodInstance = originalMethod as IGenericMethodInstanceReference;
|
||||
if (methodInstance != null) {
|
||||
originalMethod = methodInstance.GenericMethod;
|
||||
genericParameters = originalMethod.GenericParameterCount;
|
||||
keyName = originalMethod.Name.Value + genericParameters;
|
||||
}
|
||||
|
||||
#region Backward compatibility with v4 Beta 1 which went out with RequiresAlways in it (REMOVE WHEN THAT IS DELETED)
|
||||
bool backwardCompat = false;
|
||||
if (contractMethodName.Equals("RequiresAlways")) {
|
||||
contractMethodName = "Requires1"; // The one is for the generic parameter
|
||||
genericParameters = 1;
|
||||
backwardCompat = true;
|
||||
}
|
||||
#endregion Backward compatibility with v4 Beta 1 which went out with RequiresAlways in it (REMOVE WHEN THAT IS DELETED)
|
||||
|
||||
IMethodReference methodToUse;
|
||||
this.threeArgumentVersionofContractMethod.TryGetValue(keyName, out methodToUse);
|
||||
if (methodToUse == null) {
|
||||
#region Create a method
|
||||
methodToUse = CreateThreeArgVersionOfMethod(contractMethodName, keyName, genericParameters, backwardCompat);
|
||||
#endregion Create a method
|
||||
}
|
||||
if (genericParameters != 0) {
|
||||
// instantiate method to use
|
||||
methodToUse = new Microsoft.Cci.Immutable.GenericMethodInstanceReference(methodToUse,
|
||||
backwardCompat ? IteratorHelper.GetSingletonEnumerable<ITypeReference>(this.systemArgumentExceptionType) : methodInstance.GenericArguments,
|
||||
this.host.InternFactory);
|
||||
var key = methodToUse.InternedKey;
|
||||
}
|
||||
return methodToUse;
|
||||
}
|
||||
|
||||
private IMethodReference CreateThreeArgVersionOfMethod(string originalMethodName, string keyName, ushort genericParameters, bool backwardCompat) {
|
||||
MethodBody body = new MethodBody() {
|
||||
Operations = new List<IOperation>{ new Operation() { OperationCode = OperationCode.Ret, } },
|
||||
};
|
||||
|
||||
MethodDefinition threeArgVersion = new MethodDefinition() {
|
||||
Body = body,
|
||||
CallingConvention = CallingConvention.Default, // Isn't it the default for the calling convention to be the default?
|
||||
ContainingTypeDefinition = this.classHoldingThreeArgVersions,
|
||||
GenericParameters = new List<IGenericMethodParameter>(genericParameters),
|
||||
Name = backwardCompat ? this.host.NameTable.GetNameFor("Requires") : this.host.NameTable.GetNameFor(originalMethodName),
|
||||
Type = this.systemVoidType,
|
||||
Visibility = TypeMemberVisibility.Public,
|
||||
IsStatic = true,
|
||||
InternFactory = this.host.InternFactory, // NB: without this, the method has an interned key of zero, which gets confused with other dummy interned keys!!
|
||||
};
|
||||
if (genericParameters != 0) {
|
||||
threeArgVersion.CallingConvention = CallingConvention.Generic;
|
||||
var typeArg = new GenericMethodParameter() {
|
||||
Name = this.host.NameTable.GetNameFor("TException"),
|
||||
DefiningMethod = threeArgVersion,
|
||||
InternFactory = this.host.InternFactory,
|
||||
};
|
||||
// TODO: add SystemException base type?
|
||||
threeArgVersion.GenericParameters.Add(typeArg);
|
||||
}
|
||||
List<IParameterDefinition> paramList = new List<IParameterDefinition>();
|
||||
paramList.Add(
|
||||
new ParameterDefinition() {
|
||||
ContainingSignature = threeArgVersion,
|
||||
Name = this.host.NameTable.GetNameFor("condition"),
|
||||
Type = this.systemBooleanType,
|
||||
Index = 0,
|
||||
});
|
||||
paramList.Add(
|
||||
new ParameterDefinition() {
|
||||
ContainingSignature = threeArgVersion,
|
||||
Name = this.host.NameTable.GetNameFor("userSuppliedString"),
|
||||
Type = this.systemStringType,
|
||||
Index = 1,
|
||||
});
|
||||
paramList.Add(
|
||||
new ParameterDefinition() {
|
||||
ContainingSignature = threeArgVersion,
|
||||
Name = this.host.NameTable.GetNameFor("sourceText"),
|
||||
Type = this.systemStringType,
|
||||
Index = 2,
|
||||
});
|
||||
threeArgVersion.Parameters = paramList;
|
||||
body.MethodDefinition = threeArgVersion;
|
||||
this.threeArgumentVersionofContractMethod.Add(keyName, threeArgVersion);
|
||||
if (this.classHoldingThreeArgVersions.Methods == null) this.classHoldingThreeArgVersions.Methods = new List<IMethodDefinition>(1);
|
||||
this.classHoldingThreeArgVersions.Methods.Add(threeArgVersion);
|
||||
|
||||
return threeArgVersion;
|
||||
}
|
||||
|
||||
private int GetLastSourceTextIndex(string sourceText, IMethodReference originalMethod, int startSourceTextIndex) {
|
||||
if (originalMethod.ParameterCount == 1) {
|
||||
return sourceText.LastIndexOf(')'); // supposedly the character after the first (and only) argument
|
||||
} else {
|
||||
return IndexOfWhileSkippingBalancedThings(sourceText, startSourceTextIndex, ','); // supposedly the character after the first argument
|
||||
}
|
||||
}
|
||||
|
||||
private int IndexOfWhileSkippingBalancedThings(string source, int startIndex, char targetChar) {
|
||||
int i = startIndex;
|
||||
while (i < source.Length) {
|
||||
if (source[i] == targetChar) break;
|
||||
else if (source[i] == '(') i = IndexOfWhileSkippingBalancedThings(source, i + 1, ')') + 1;
|
||||
else if (source[i] == '"') i = IndexOfWhileSkippingBalancedThings(source, i + 1, '"') + 1;
|
||||
else i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private void GetSourceTextFromOperation(IOperation op, out string sourceText, out int startColumn, out string sourceLanguage) {
|
||||
sourceText = null;
|
||||
startColumn = 0;
|
||||
sourceLanguage = "unknown";
|
||||
foreach (IPrimarySourceLocation psloc in this.pdbReader.GetClosestPrimarySourceLocationsFor(op.Location)) {
|
||||
if (!String.IsNullOrEmpty(psloc.Source)) {
|
||||
sourceText = psloc.Source;
|
||||
startColumn = psloc.StartColumn;
|
||||
if (psloc.SourceDocument != null) {
|
||||
sourceLanguage = psloc.SourceDocument.SourceLanguage;
|
||||
}
|
||||
//Console.WriteLine("[{0}]: {1}", i, psloc.Source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Exceptions thrown during extraction. Should not escape this class.
|
||||
/// </summary>
|
||||
private class ExtractorException : Exception {
|
||||
/// <summary>
|
||||
/// Exception specific to an error occurring in the contract extractor
|
||||
/// </summary>
|
||||
public ExtractorException() { }
|
||||
/// <summary>
|
||||
/// Exception specific to an error occurring in the contract extractor
|
||||
/// </summary>
|
||||
public ExtractorException(string s) : base(s) { }
|
||||
/// <summary>
|
||||
/// Exception specific to an error occurring in the contract extractor
|
||||
/// </summary>
|
||||
public ExtractorException(string s, Exception inner) : base(s, inner) { }
|
||||
/// <summary>
|
||||
/// Exception specific to an error occurring in the contract extractor
|
||||
/// </summary>
|
||||
public ExtractorException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
|
||||
</startup>
|
||||
<runtime>
|
||||
<gcServer enabled="true"/>
|
||||
</runtime>
|
||||
</configuration>
|
Загрузка…
Ссылка в новой задаче