예제 #1
0
        public void ConcurrentAccess()
        {
            var source =
                @"class A
{
    B F;
    D P { get; set; }
    void M(A a, B b, S s, I i) { }
    delegate void D(S s);
    class B { }
    struct S { }
    interface I { }
}
class B
{
    A M<T, U>() where T : A where U : T, I { return null; }
    event D E;
    delegate void D(S s);
    struct S { }
    interface I { }
}";

            var compilation0 = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source);

            var builder = new List <Symbol>();
            var type    = compilation1.GetMember <NamedTypeSymbol>("A");

            builder.Add(type);
            builder.AddRange(type.GetMembers());
            type = compilation1.GetMember <NamedTypeSymbol>("B");
            builder.Add(type);
            builder.AddRange(type.GetMembers());
            var members = builder.ToImmutableArray();

            Assert.True(members.Length > 10);

            for (int i = 0; i < 10; i++)
            {
                var matcher = new CSharpSymbolMatcher(
                    null,
                    compilation1.SourceAssembly,
                    default(EmitContext),
                    compilation0.SourceAssembly,
                    default(EmitContext),
                    null);

                var tasks = new Task[10];
                for (int j = 0; j < tasks.Length; j++)
                {
                    int startAt = i + j + 1;
                    tasks[j] = Task.Run(() =>
                    {
                        MatchAll(matcher, members, startAt);
                        Thread.Sleep(10);
                    });
                }
                Task.WaitAll(tasks);
            }
        }
예제 #2
0
        public void RefProperty_RefChange()
        {
            var source0 = @"
struct S
{
    int[] ints;
    public ref int X { get => ref ints[0]; }
}";
            var source1 = @"
struct S
{
    int[] ints;
    public int X { get => ints[0]; }
}";
            var compilation0 = CreateStandardCompilation(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember<PropertySymbol>("S.X");
            var other = matcher.MapDefinition(member);
            // If a type changes, we do not expect types to match.
            Assert.Null(other);
        }
예제 #3
0
        public void TupleStructField_TypeChange()
        {
            var source0 = @"
public struct Vector
{
    public (int x, int y) Coordinates;
}";
            var source1 = @"
public struct Vector
{
    public (int x, int y, int z) Coordinates;
}";
            var compilation0 = CreateStandardCompilation(source0, options: TestOptions.DebugDll, references: s_valueTupleRefs);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember<FieldSymbol>("Vector.Coordinates");
            var other = matcher.MapDefinition(member);
            // If a type changes within a tuple, we do not expect types to match.
            Assert.Null(other);
        }
예제 #4
0
        public void TupleMethod_TypeChange()
        {
            var source0      = @"
class C
{  
    public (int a, int b) X() { return null };
}";
            var source1      = @"
class C
{
    public (int a, bool b) X() { return null };
}";
            var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember <MethodSymbol>("C.X");
            var other  = matcher.MapDefinition(member);

            // If a type changes within a tuple, we do not expect types to match.
            Assert.Null(other);
        }
예제 #5
0
        public void TupleField_NameChange()
        {
            var source0      = @"
class C
{  
    public (int a, int b) x;
}";
            var source1      = @"
class C
{
    public (int a, int c) x;
}";
            var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember <FieldSymbol>("C.x");
            var other  = matcher.MapDefinition(member);

            // Types must match because just an element name was changed.
            Assert.NotNull(other);
        }
예제 #6
0
        public void RefMethod_RefChange()
        {
            var source0 = @"
class C
{  
    public ref bool GetFirst(bool[] bools) { return ref bools[0]; } };
}";
            var source1 = @"
class C
{
    public bool GetFirst(bool[] bools) { return bools[0]; } };
}";
            var compilation0 = CreateStandardCompilation(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember<MethodSymbol>("C.GetFirst");
            var other = matcher.MapDefinition(member);
            // If a type changes, we do not expect types to match.
            Assert.Null(other);
        }
예제 #7
0
        public void Method_ParameterNullableChange()
        {
            var source0      = @"
using System.Collections.Generic;
class C
{
    string c;
    ref string M(string? s, (string a, dynamic? b) tuple, List<string?> list) => ref c;
}";
            var source1      = @"
using System.Collections.Generic;
class C
{
    string c;
    ref string? M(string s, (string? a, dynamic b) tuple, List<string> list) => ref c;
}";
            var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember <MethodSymbol>("C.M");
            var other  = matcher.MapDefinition(member);

            Assert.NotNull(other);
        }
예제 #8
0
        public void NoPreviousType_PointerType()
        {
            var source0 = @"
class C
{  
    static void M()
    {
        int x = 0;
    }
}";
            var source1 = @"
class C
{
    static unsafe void M()
    {
        D* x = null;
    }
    struct D {}
}";
            var compilation0 = CreateStandardCompilation(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var elementType = compilation1.GetMember<TypeSymbol>("C.D");
            var member = compilation1.CreatePointerTypeSymbol(elementType);
            var other = matcher.MapReference((Cci.ITypeReference)member);
            // For a newly added type, there is no match in the previous generation.
            Assert.Null(other);
        }
예제 #9
0
        public void TupleProperty_TypeChange()
        {
            var source0 = @"
class C
{  
    public (int a, int b) X { get { return null; } };
}";
            var source1 = @"
class C
{
    public (int a, bool b) X { get { return null; } };
}";
            var compilation0 = CreateStandardCompilation(source0, options: TestOptions.DebugDll, references: s_valueTupleRefs);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember<PropertySymbol>("C.X");
            var other = matcher.MapDefinition(member);
            // If a type changes within a tuple, we do not expect types to match.
            Assert.Null(other);
        }
예제 #10
0
        public void Field_NullableChange()
        {
            var source0      = @"
class C
{
    string S;
}";
            var source1      = @"
class C
{
    string? S;
}";
            var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember <FieldSymbol>("C.S");
            var other  = matcher.MapDefinition(member);

            Assert.NotNull(other);
        }
예제 #11
0
        public void PreviousType_ArrayType()
        {
            var source0 = @"
class C
{  
    static void M()
    {
        int x = 0;
    }
    class D {}
}";
            var source1 = @"
class C
{
    static void M()
    {
        D[] x = null;
    }
    class D {}
}";
            var compilation0 = CreateStandardCompilation(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var elementType = compilation1.GetMember<TypeSymbol>("C.D");
            var member = compilation1.CreateArrayTypeSymbol(elementType);
            var other = matcher.MapReference((Cci.ITypeReference)member);
            Assert.NotNull(other);
        }
예제 #12
0
        public void TupleStructField_NameChange()
        {
            var source0 = @"
public struct Vector
{
    public (int x, int y) Coordinates;
}";
            var source1 = @"
public struct Vector
{
    public (int x, int z) Coordinates;
}";
            var compilation0 = CreateStandardCompilation(source0, options: TestOptions.DebugDll, references: s_valueTupleRefs);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember<FieldSymbol>("Vector.Coordinates");
            var other = matcher.MapDefinition(member);
            // Types must match because just an element name was changed.
            Assert.NotNull(other);
        }
예제 #13
0
        public void TupleDelegate_TypeChange()
        {
            var source0 = @"
public class C
{
    public delegate (int, int) F();
}";
            var source1 = @"
public struct C
{
    public delegate (int, bool) F();
}";
            var compilation0 = CreateStandardCompilation(source0, options: TestOptions.DebugDll, references: s_valueTupleRefs);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember<SourceNamedTypeSymbol>("C.F");
            var other = matcher.MapDefinition(member);
            // Tuple delegate defines a type. We should be able to match old and new types by name.
            Assert.NotNull(other);
        }
예제 #14
0
        public void VaryingCompilationReferences()
        {
            string libSource = @"
public class D { }
";

            string source = @"
public class C
{
    public void F(D a) {}
}
";
            var    lib0   = CreateCompilationWithMscorlib(libSource, options: TestOptions.DebugDll, assemblyName: "Lib");
            var    lib1   = CreateCompilationWithMscorlib(libSource, options: TestOptions.DebugDll, assemblyName: "Lib");

            var compilation0 = CreateCompilationWithMscorlib(source, new[] { lib0.ToMetadataReference() }, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source).WithReferences(MscorlibRef, lib1.ToMetadataReference());

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var f0 = compilation0.GetMember <MethodSymbol>("C.F");
            var f1 = compilation1.GetMember <MethodSymbol>("C.F");

            var mf1 = matcher.MapDefinition(f1);

            Assert.Equal(f0, mf1);
        }
예제 #15
0
        public void Constraints()
        {
            const string source =
                @"interface I<T> where T : I<T>
{
}
class C
{
    static void M<T>(I<T> o) where T : I<T>
    {
    }
}";
            var compilation0 = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var member = compilation1.GetMember <MethodSymbol>("C.M");
            var other  = matcher.MapDefinition(member);

            Assert.NotNull(other);
        }
예제 #16
0
        public void CustomModifiers()
        {
            var ilSource =
                @".class public abstract A
{
  .method public hidebysig specialname rtspecialname instance void .ctor() { ret }
  .method public abstract virtual instance object modopt(A) [] F(int32 modopt(object) *p) { }
}";
            var          metadataRef = CompileIL(ilSource);
            const string source      =
                @"unsafe class B : A
{
    public override object[] F(int* p) { return null; }
}";
            var compilation0 = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll, references: new[] { metadataRef });
            var compilation1 = compilation0.WithSource(source);

            var member1 = compilation1.GetMember <MethodSymbol>("B.F");

            Assert.Equal(((PointerTypeSymbol)member1.Parameters[0].Type).CustomModifiers.Length, 1);
            Assert.Equal(((ArrayTypeSymbol)member1.ReturnType).CustomModifiers.Length, 1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var other = (MethodSymbol)matcher.MapDefinition((Cci.IMethodDefinition)member1);

            Assert.NotNull(other);
            Assert.Equal(((PointerTypeSymbol)other.Parameters[0].Type).CustomModifiers.Length, 1);
            Assert.Equal(((ArrayTypeSymbol)other.ReturnType).CustomModifiers.Length, 1);
        }
예제 #17
0
        public void TupleProperty_NameChange()
        {
            var source0 = @"
class C
{  
    public (int a, int b) X { get { return null; } };
}";
            var source1 = @"
class C
{
    public (int a, int c) X { get { return null; } };
}";
            var compilation0 = CreateStandardCompilation(source0, options: TestOptions.DebugDll, references: s_valueTupleRefs);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember<PropertySymbol>("C.X");
            var other = matcher.MapDefinition(member);
            // Types must match because just an element name was changed.
            Assert.NotNull(other);
        }
예제 #18
0
        public void TupleDeletagate_NameChange()
        {
            var source0 = @"
public class C
{
    public delegate (int, int) F();
}";
            var source1 = @"
public struct C
{
    public delegate (int x, int y) F();
}";
            var compilation0 = CreateStandardCompilation(source0, options: TestOptions.DebugDll, references: s_valueTupleRefs);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var member = compilation1.GetMember<SourceNamedTypeSymbol>("C.F");
            var other = matcher.MapDefinition(member);
            // Types must match because just an element name was changed.
            Assert.NotNull(other);
        }
예제 #19
0
        public void ConcurrentAccess()
        {
            var source =
@"class A
{
    B F;
    D P { get; set; }
    void M(A a, B b, S s, I i) { }
    delegate void D(S s);
    class B { }
    struct S { }
    interface I { }
}
class B
{
    A M<T, U>() where T : A where U : T, I { return null; }
    event D E;
    delegate void D(S s);
    struct S { }
    interface I { }
}";

            var compilation0 = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source);

            var builder = new List<Symbol>();
            var type = compilation1.GetMember<NamedTypeSymbol>("A");
            builder.Add(type);
            builder.AddRange(type.GetMembers());
            type = compilation1.GetMember<NamedTypeSymbol>("B");
            builder.Add(type);
            builder.AddRange(type.GetMembers());
            var members = builder.ToImmutableArray();
            Assert.True(members.Length > 10);

            for (int i = 0; i < 10; i++)
            {
                var matcher = new CSharpSymbolMatcher(
                    null,
                    compilation1.SourceAssembly,
                    default(EmitContext),
                    compilation0.SourceAssembly,
                    default(EmitContext),
                    null);

                var tasks = new Task[10];
                for (int j = 0; j < tasks.Length; j++)
                {
                    int startAt = i + j + 1;
                    tasks[j] = Task.Run(() =>
                    {
                        MatchAll(matcher, members, startAt);
                        Thread.Sleep(10);
                    });
                }
                Task.WaitAll(tasks);
            }
        }
예제 #20
0
 private static void MatchAll(CSharpSymbolMatcher matcher, ImmutableArray<Symbol> members, int startAt)
 {
     int n = members.Length;
     for (int i = 0; i < n; i++)
     {
         var member = members[(i + startAt) % n];
         var other = matcher.MapDefinition((Cci.IDefinition)member);
         Assert.NotNull(other);
     }
 }
예제 #21
0
 private static void MatchAll(CSharpSymbolMatcher matcher, ImmutableArray<Symbol> members, int startAt)
 {
     int n = members.Length;
     for (int i = 0; i < n; i++)
     {
         var member = members[(i + startAt) % n];
         var other = matcher.MapDefinition((Cci.IDefinition)member);
         Assert.NotNull(other);
     }
 }
예제 #22
0
        public PEDeltaAssemblyBuilder(
            SourceAssemblySymbol sourceAssembly,
            EmitOptions emitOptions,
            OutputKind outputKind,
            Cci.ModulePropertiesForSerialization serializationProperties,
            IEnumerable<ResourceDescription> manifestResources,
            EmitBaseline previousGeneration,
            IEnumerable<SemanticEdit> edits,
            Func<ISymbol, bool> isAddedSymbol)
            : base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, additionalTypes: ImmutableArray<NamedTypeSymbol>.Empty)
        {
            var initialBaseline = previousGeneration.InitialBaseline;
            var context = new EmitContext(this, null, new DiagnosticBag());

            // Hydrate symbols from initial metadata. Once we do so it is important to reuse these symbols across all generations,
            // in order for the symbol matcher to be able to use reference equality once it maps symbols to initial metadata.
            var metadataSymbols = GetOrCreateMetadataSymbols(initialBaseline, sourceAssembly.DeclaringCompilation);
            var metadataDecoder = (MetadataDecoder)metadataSymbols.MetadataDecoder;
            var metadataAssembly = (PEAssemblySymbol)metadataDecoder.ModuleSymbol.ContainingAssembly;

            var matchToMetadata = new CSharpSymbolMatcher(metadataSymbols.AnonymousTypes, sourceAssembly, context, metadataAssembly);

            CSharpSymbolMatcher matchToPrevious = null;
            if (previousGeneration.Ordinal > 0)
            {
                var previousAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly;
                var previousContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag());

                matchToPrevious = new CSharpSymbolMatcher(
                    previousGeneration.AnonymousTypeMap,
                    sourceAssembly: sourceAssembly,
                    sourceContext: context,
                    otherAssembly: previousAssembly,
                    otherContext: previousContext,
                    otherSynthesizedMembersOpt: previousGeneration.SynthesizedMembers);
            }

            _previousDefinitions = new CSharpDefinitionMap(previousGeneration.OriginalMetadata.Module, edits, metadataDecoder, matchToMetadata, matchToPrevious);
            _previousGeneration = previousGeneration;
            _changes = new SymbolChanges(_previousDefinitions, edits, isAddedSymbol);

            // Workaround for https://github.com/dotnet/roslyn/issues/3192.
            // When compiling state machine we stash types of awaiters and state-machine hoisted variables,
            // so that next generation can look variables up and reuse their slots if possible.
            //
            // When we are about to allocate a slot for a lifted variable while compiling the next generation
            // we map its type to the previous generation and then check the slot types that we stashed earlier.
            // If the variable type matches we reuse it. In order to compare the previous variable type with the current one
            // both need to be completely lowered (translated). Standard translation only goes one level deep. 
            // Generic arguments are not translated until they are needed by metadata writer. 
            //
            // In order to get the fully lowered form we run the type symbols of stashed variables thru a deep translator
            // that translates the symbol recursively.
            _deepTranslator = new CSharpSymbolMatcher.DeepTranslator(sourceAssembly.GetSpecialType(SpecialType.System_Object));
        }
예제 #23
0
        public void Property_CompilationVsPE()
        {
            var source = @"
using System;

interface I<T, S>
{
	int this[int index] { set; }
}

class C : I<int, bool>
{
    int _current;
	int I<int, bool>.this[int anotherIndex] 
	{
		set { _current = anotherIndex + value; }
	}
}";

            var compilation0 = CreateCompilation(source, options: TestOptions.DebugDll);

            var peRef0            = compilation0.EmitToImageReference();
            var peAssemblySymbol0 = (PEAssemblySymbol)CreateCompilation("", new[] { peRef0 }).GetReferencedAssemblySymbol(peRef0);

            var compilation1 = CreateCompilation(source, options: TestOptions.DebugDll);

            var testData = new CompilationTestData();

            compilation1.EmitToArray(testData: testData);
            var peAssemblyBuilder = (PEAssemblyBuilder)testData.Module;

            var c          = compilation1.GetMember <NamedTypeSymbol>("C");
            var property   = c.GetMember <PropertySymbol>("I<System.Int32,System.Boolean>.this[]");
            var parameters = property.GetParameters().ToArray();

            Assert.Equal(1, parameters.Length);
            Assert.Equal("anotherIndex", parameters[0].Name);

            var emitContext = new EmitContext(peAssemblyBuilder, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true);
            var matcher     = new CSharpSymbolMatcher(null, compilation1.SourceAssembly, emitContext, peAssemblySymbol0);

            var mappedProperty = (Cci.IPropertyDefinition)matcher.MapDefinition(property);

            Assert.Equal("I<System.Int32,System.Boolean>.Item", ((PropertySymbol)mappedProperty).MetadataName);
        }
예제 #24
0
        public PEDeltaAssemblyBuilder(
            SourceAssemblySymbol sourceAssembly,
            EmitOptions emitOptions,
            OutputKind outputKind,
            ModulePropertiesForSerialization serializationProperties,
            IEnumerable<ResourceDescription> manifestResources,
            EmitBaseline previousGeneration,
            IEnumerable<SemanticEdit> edits,
            Func<ISymbol, bool> isAddedSymbol)
            : base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, assemblySymbolMapper: null, additionalTypes: ImmutableArray<NamedTypeSymbol>.Empty)
        {
            var context = new EmitContext(this, null, new DiagnosticBag());
            var module = previousGeneration.OriginalMetadata;
            var compilation = sourceAssembly.DeclaringCompilation;
            var metadataAssembly = compilation.GetBoundReferenceManager().CreatePEAssemblyForAssemblyMetadata(AssemblyMetadata.Create(module), MetadataImportOptions.All);
            var metadataDecoder = new Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE.MetadataDecoder(metadataAssembly.PrimaryModule);

            previousGeneration = EnsureInitialized(previousGeneration, metadataDecoder);

            var matchToMetadata = new CSharpSymbolMatcher(previousGeneration.AnonymousTypeMap, sourceAssembly, context, metadataAssembly);

            CSharpSymbolMatcher matchToPrevious = null;
            if (previousGeneration.Ordinal > 0)
            {
                var previousAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly;
                var previousContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag());

                matchToPrevious = new CSharpSymbolMatcher(
                    previousGeneration.AnonymousTypeMap,
                    sourceAssembly: sourceAssembly,
                    sourceContext: context,
                    otherAssembly: previousAssembly,
                    otherContext: previousContext,
                    otherSynthesizedMembersOpt: previousGeneration.SynthesizedMembers);
            }

            _previousDefinitions = new CSharpDefinitionMap(previousGeneration.OriginalMetadata.Module, edits, metadataDecoder, matchToMetadata, matchToPrevious);
            _previousGeneration = previousGeneration;
            _changes = new SymbolChanges(_previousDefinitions, edits, isAddedSymbol);
        }
예제 #25
0
        public void TypeArguments()
        {
            const string source =
                @"class A<T>
{
    class B<U>
    {
        static A<V> M<V>(A<U>.B<T> x, A<object>.S y)
        {
            return null;
        }
        static A<V> M<V>(A<U>.B<T> x, A<V>.S y)
        {
            return null;
        }
    }
    struct S
    {
    }
}";
            var compilation0 = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var members = compilation1.GetMember <NamedTypeSymbol>("A.B").GetMembers("M");

            Assert.Equal(members.Length, 2);
            foreach (var member in members)
            {
                var other = matcher.MapDefinition((Cci.IMethodDefinition)member);
                Assert.NotNull(other);
            }
        }
예제 #26
0
        public void NoPreviousType_GenericType()
        {
            var source0      = @"
using System.Collections.Generic;
class C
{  
    static void M()
    {
        int x = 0;
    }
}";
            var source1      = @"
using System.Collections.Generic;
class C
{
    static void M()
    {
        List<D> x = null;
    }
    class D {}
    List<D> y;
}";
            var compilation0 = CreateCompilationWithMscorlib(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var member = compilation1.GetMember <FieldSymbol>("C.y");
            var other  = matcher.MapReference((Cci.ITypeReference)member.Type);

            // For a newly added type, there is no match in the previous generation.
            Assert.Null(other);
        }
예제 #27
0
        /// <summary>
        /// Return a version of the baseline with all definitions mapped to this compilation.
        /// Definitions from the initial generation, from metadata, are not mapped since
        /// the initial generation is always included as metadata. That is, the symbols from
        /// types, methods, ... in the TypesAdded, MethodsAdded, ... collections are replaced
        /// by the corresponding symbols from the current compilation.
        /// </summary>
        private static EmitBaseline MapToCompilation(
            CSharpCompilation compilation,
            PEDeltaAssemblyBuilder moduleBeingBuilt)
        {
            var previousGeneration = moduleBeingBuilt.PreviousGeneration;
            Debug.Assert(previousGeneration.Compilation != compilation);

            if (previousGeneration.Ordinal == 0)
            {
                // Initial generation, nothing to map. (Since the initial generation
                // is always loaded from metadata in the context of the current
                // compilation, there's no separate mapping step.)
                return previousGeneration;
            }

            var currentSynthesizedMembers = moduleBeingBuilt.GetSynthesizedMembers();

            // Mapping from previous compilation to the current.
            var anonymousTypeMap = moduleBeingBuilt.GetAnonymousTypeMap();
            var sourceAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly;
            var sourceContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag());
            var otherContext = new EmitContext(moduleBeingBuilt, null, new DiagnosticBag());

            var matcher = new CSharpSymbolMatcher(
                anonymousTypeMap,
                sourceAssembly,
                sourceContext,
                compilation.SourceAssembly,
                otherContext,
                currentSynthesizedMembers);

            var mappedSynthesizedMembers = matcher.MapSynthesizedMembers(previousGeneration.SynthesizedMembers, currentSynthesizedMembers);

            // TODO: can we reuse some data from the previos matcher?
            var matcherWithAllSynthesizedMembers = new CSharpSymbolMatcher(
                anonymousTypeMap,
                sourceAssembly,
                sourceContext,
                compilation.SourceAssembly,
                otherContext,
                mappedSynthesizedMembers);

            return matcherWithAllSynthesizedMembers.MapBaselineToCompilation(
                previousGeneration,
                compilation,
                moduleBeingBuilt,
                mappedSynthesizedMembers);
        }
예제 #28
0
        public void HoistedAnonymousTypes_Complex()
        {
            var source0      = @"
using System;

class C
{
    static void F()
    {
        var x1 = new[] { new { A = new { X = 1 } } };
        var x2 = new[] { new { A = new { Y = 1 } } };
        var y = new Func<int>(() => x1[0].A.X + x2[0].A.Y);
    }
}
";
            var source1      = @"
using System;

class C
{
    static void F()
    {
        var x1 = new[] { new { A = new { X = 1 } } };
        var x2 = new[] { new { A = new { Z = 1 } } };
        var y = new Func<int>(() => x1[0].A.X + x2[0].A.Z);
    }
}";
            var compilation0 = CreateCompilationWithMscorlib(source0, options: TestOptions.DebugDll);

            var peRef0            = compilation0.EmitToImageReference();
            var peAssemblySymbol0 = (PEAssemblySymbol)CreateCompilationWithMscorlib("", new[] { peRef0 }).GetReferencedAssemblySymbol(peRef0);
            var peModule0         = (PEModuleSymbol)peAssemblySymbol0.Modules[0];

            var reader0  = peModule0.Module.MetadataReader;
            var decoder0 = new MetadataDecoder(peModule0);

            var anonymousTypeMap0 = PEDeltaAssemblyBuilder.GetAnonymousTypeMapFromMetadata(reader0, decoder0);

            Assert.Equal("<>f__AnonymousType0", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("A", isKey: false, ignoreCase: false)))].Name);
            Assert.Equal("<>f__AnonymousType1", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("X", isKey: false, ignoreCase: false)))].Name);
            Assert.Equal("<>f__AnonymousType2", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("Y", isKey: false, ignoreCase: false)))].Name);
            Assert.Equal(3, anonymousTypeMap0.Count);

            var compilation1 = CreateCompilationWithMscorlib(source1, options: TestOptions.DebugDll);

            var testData = new CompilationTestData();

            compilation1.EmitToArray(testData: testData);
            var peAssemblyBuilder = (PEAssemblyBuilder)testData.Module;

            var c            = compilation1.GetMember <NamedTypeSymbol>("C");
            var displayClass = peAssemblyBuilder.GetSynthesizedTypes(c).Single();

            Assert.Equal("<>c__DisplayClass0_0", displayClass.Name);

            var emitContext = new EmitContext(peAssemblyBuilder, null, new DiagnosticBag());

            var fields = displayClass.GetFields(emitContext).ToArray();
            var x1     = fields[0];
            var x2     = fields[1];

            Assert.Equal("x1", x1.Name);
            Assert.Equal("x2", x2.Name);

            var matcher = new CSharpSymbolMatcher(anonymousTypeMap0, compilation1.SourceAssembly, emitContext, peAssemblySymbol0);

            var mappedX1 = (Cci.IFieldDefinition)matcher.MapDefinition(x1);
            var mappedX2 = (Cci.IFieldDefinition)matcher.MapDefinition(x2);

            Assert.Equal("x1", mappedX1.Name);
            Assert.Null(mappedX2);
        }
예제 #29
0
        public void Constraints()
        {
            const string source =
@"interface I<T> where T : I<T>
{
}
class C
{
    static void M<T>(I<T> o) where T : I<T>
    {
    }
}";
            var compilation0 = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var member = compilation1.GetMember<MethodSymbol>("C.M");
            var other = matcher.MapDefinition(member);
            Assert.NotNull(other);
        }
예제 #30
0
        public void AnonymousTypesWithNullables()
        {
            var source0      = @"
using System;

class C
{
    static T id<T>(T t) => t;
    static T F<T>(Func<T> f) => f();

    static void M(string? x)
    {
        var y1 = new { A = id(x) };
        var y2 = F(() => new { B = id(x) });
        var z = new Func<string>(() => y1.A + y2.B);
    }
}";
            var source1      = @"
using System;

class C
{
    static T id<T>(T t) => t;
    static T F<T>(Func<T> f) => f();

    static void M(string? x)
    {
        if (x is null) throw new Exception();
        var y1 = new { A = id(x) };
        var y2 = F(() => new { B = id(x) });
        var z = new Func<string>(() => y1.A + y2.B);
    }
}";
            var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll);

            var peRef0            = compilation0.EmitToImageReference();
            var peAssemblySymbol0 = (PEAssemblySymbol)CreateCompilation("", new[] { peRef0 }).GetReferencedAssemblySymbol(peRef0);
            var peModule0         = (PEModuleSymbol)peAssemblySymbol0.Modules[0];

            var reader0  = peModule0.Module.MetadataReader;
            var decoder0 = new MetadataDecoder(peModule0);

            var anonymousTypeMap0 = PEDeltaAssemblyBuilder.GetAnonymousTypeMapFromMetadata(reader0, decoder0);

            Assert.Equal("<>f__AnonymousType0", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("A", isKey: false, ignoreCase: false)))].Name);
            Assert.Equal("<>f__AnonymousType1", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("B", isKey: false, ignoreCase: false)))].Name);
            Assert.Equal(2, anonymousTypeMap0.Count);

            var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll);

            var testData = new CompilationTestData();

            compilation1.EmitToArray(testData: testData);
            var peAssemblyBuilder = (PEAssemblyBuilder)testData.Module;

            var c            = compilation1.GetMember <NamedTypeSymbol>("C");
            var displayClass = peAssemblyBuilder.GetSynthesizedTypes(c).Single();

            Assert.Equal("<>c__DisplayClass2_0", displayClass.Name);

            var emitContext = new EmitContext(peAssemblyBuilder, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true);

            var fields = displayClass.GetFields(emitContext).ToArray();

            AssertEx.SetEqual(fields.Select(f => f.Name), new[] { "x", "y1", "y2" });
            var y1 = fields.Where(f => f.Name == "y1").Single();
            var y2 = fields.Where(f => f.Name == "y2").Single();

            var matcher = new CSharpSymbolMatcher(anonymousTypeMap0, compilation1.SourceAssembly, emitContext, peAssemblySymbol0);

            var mappedY1 = (Cci.IFieldDefinition)matcher.MapDefinition(y1);
            var mappedY2 = (Cci.IFieldDefinition)matcher.MapDefinition(y2);

            Assert.Equal("y1", mappedY1.Name);
            Assert.Equal("y2", mappedY2.Name);
        }
예제 #31
0
        public void VaryingCompilationReferences()
        {
            string libSource = @"
public class D { }
";

            string source = @"
public class C
{
    public void F(D a) {}
}
";
            var lib0 = CreateCompilationWithMscorlib(libSource, options: TestOptions.DebugDll, assemblyName: "Lib");
            var lib1 = CreateCompilationWithMscorlib(libSource, options: TestOptions.DebugDll, assemblyName: "Lib");

            var compilation0 = CreateCompilationWithMscorlib(source, new[] { lib0.ToMetadataReference() }, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source).WithReferences(MscorlibRef, lib1.ToMetadataReference());

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);

            var f0 = compilation0.GetMember<MethodSymbol>("C.F");
            var f1 = compilation1.GetMember<MethodSymbol>("C.F");

            var mf1 = matcher.MapDefinition(f1);
            Assert.Equal(f0, mf1);
        }
예제 #32
0
        public void CustomModifiers()
        {
            var ilSource =
@".class public abstract A
{
  .method public hidebysig specialname rtspecialname instance void .ctor() { ret }
  .method public abstract virtual instance object modopt(A) [] F(int32 modopt(object) *p) { }
}";
            var metadataRef = CompileIL(ilSource);
            const string source =
@"unsafe class B : A
{
    public override object[] F(int* p) { return null; }
}";
            var compilation0 = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll, references: new[] { metadataRef });
            var compilation1 = compilation0.WithSource(source);

            var member1 = compilation1.GetMember<MethodSymbol>("B.F");
            Assert.Equal(((PointerTypeSymbol)member1.Parameters[0].Type).CustomModifiers.Length, 1);
            Assert.Equal(((ArrayTypeSymbol)member1.ReturnType).CustomModifiers.Length, 1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var other = (MethodSymbol)matcher.MapDefinition((Cci.IMethodDefinition)member1);
            Assert.NotNull(other);
            Assert.Equal(((PointerTypeSymbol)other.Parameters[0].Type).CustomModifiers.Length, 1);
            Assert.Equal(((ArrayTypeSymbol)other.ReturnType).CustomModifiers.Length, 1);
        }
예제 #33
0
        public void PreviousType_ArrayType()
        {
            var source0 = @"
class C
{  
    static void M()
    {
        int x = 0;
    }
    class D {}
}";
            var source1 = @"
class C
{
    static void M()
    {
        D[] x = null;
    }
    class D {}
}";
            var compilation0 = CreateCompilationWithMscorlib(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var elementType = compilation1.GetMember<TypeSymbol>("C.D");
            var member = compilation1.CreateArrayTypeSymbol(elementType);
            var other = matcher.MapReference((Cci.ITypeReference)member);
            Assert.NotNull(other);
        }
예제 #34
0
        public void NoPreviousType_PointerType()
        {
            var source0 = @"
class C
{  
    static void M()
    {
        int x = 0;
    }
}";
            var source1 = @"
class C
{
    static unsafe void M()
    {
        D* x = null;
    }
    struct D {}
}";
            var compilation0 = CreateCompilationWithMscorlib(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var elementType = compilation1.GetMember<TypeSymbol>("C.D");
            var member = compilation1.CreatePointerTypeSymbol(elementType);
            var other = matcher.MapReference((Cci.ITypeReference)member);
            // For a newly added type, there is no match in the previous generation.
            Assert.Null(other);
        }
예제 #35
0
        public void NoPreviousType_GenericType()
        {
            var source0 = @"
using System.Collections.Generic;
class C
{  
    static void M()
    {
        int x = 0;
    }
}";
            var source1 = @"
using System.Collections.Generic;
class C
{
    static void M()
    {
        List<D> x = null;
    }
    class D {}
    List<D> y;
}";
            var compilation0 = CreateCompilationWithMscorlib(source0, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source1);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var member = compilation1.GetMember<FieldSymbol>("C.y");
            var other = matcher.MapReference((Cci.ITypeReference)member.Type);
            // For a newly added type, there is no match in the previous generation.
            Assert.Null(other);
        }
예제 #36
0
        public void HoistedAnonymousTypes_Complex()
        {
            var source0 = @"
using System;

class C
{
    static void F()
    {
        var x1 = new[] { new { A = new { X = 1 } } };
        var x2 = new[] { new { A = new { Y = 1 } } };
        var y = new Func<int>(() => x1[0].A.X + x2[0].A.Y);
    }
}
";
            var source1 = @"
using System;

class C
{
    static void F()
    {
        var x1 = new[] { new { A = new { X = 1 } } };
        var x2 = new[] { new { A = new { Z = 1 } } };
        var y = new Func<int>(() => x1[0].A.X + x2[0].A.Z);
    }
}";
            var compilation0 = CreateCompilationWithMscorlib(source0, options: TestOptions.DebugDll);

            var peRef0 = compilation0.EmitToImageReference();
            var peAssemblySymbol0 = (PEAssemblySymbol)CreateCompilationWithMscorlib("", new[] { peRef0 }).GetReferencedAssemblySymbol(peRef0);
            var peModule0 = (PEModuleSymbol)peAssemblySymbol0.Modules[0];

            var reader0 = peModule0.Module.MetadataReader;
            var decoder0 = new MetadataDecoder(peModule0);

            var anonymousTypeMap0 = PEDeltaAssemblyBuilder.GetAnonymousTypeMapFromMetadata(reader0, decoder0);
            Assert.Equal("<>f__AnonymousType0", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("A", isKey: false, ignoreCase: false)))].Name);
            Assert.Equal("<>f__AnonymousType1", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("X", isKey: false, ignoreCase: false)))].Name);
            Assert.Equal("<>f__AnonymousType2", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("Y", isKey: false, ignoreCase: false)))].Name);
            Assert.Equal(3, anonymousTypeMap0.Count);

            var compilation1 = CreateCompilationWithMscorlib(source1, options: TestOptions.DebugDll);

            var testData = new CompilationTestData();
            compilation1.EmitToArray(testData: testData);
            var peAssemblyBuilder = (PEAssemblyBuilder)testData.Module;

            var c = compilation1.GetMember<NamedTypeSymbol>("C");
            var displayClass = peAssemblyBuilder.GetSynthesizedTypes(c).Single();
            Assert.Equal("<>c__DisplayClass0_0", displayClass.Name);

            var emitContext = new EmitContext(peAssemblyBuilder, null, new DiagnosticBag());

            var fields = displayClass.GetFields(emitContext).ToArray();
            var x1 = fields[0];
            var x2 = fields[1];
            Assert.Equal("x1", x1.Name);
            Assert.Equal("x2", x2.Name);

            var matcher = new CSharpSymbolMatcher(anonymousTypeMap0, compilation1.SourceAssembly, emitContext, peAssemblySymbol0);

            var mappedX1 = (Cci.IFieldDefinition)matcher.MapDefinition(x1);
            var mappedX2 = (Cci.IFieldDefinition)matcher.MapDefinition(x2);

            Assert.Equal("x1", mappedX1.Name);
            Assert.Null(mappedX2);
        }
예제 #37
0
        public void TypeArguments()
        {
            const string source =
@"class A<T>
{
    class B<U>
    {
        static A<V> M<V>(A<U>.B<T> x, A<object>.S y)
        {
            return null;
        }
        static A<V> M<V>(A<U>.B<T> x, A<V>.S y)
        {
            return null;
        }
    }
    struct S
    {
    }
}";
            var compilation0 = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll);
            var compilation1 = compilation0.WithSource(source);

            var matcher = new CSharpSymbolMatcher(
                null,
                compilation1.SourceAssembly,
                default(EmitContext),
                compilation0.SourceAssembly,
                default(EmitContext),
                null);
            var members = compilation1.GetMember<NamedTypeSymbol>("A.B").GetMembers("M");
            Assert.Equal(members.Length, 2);
            foreach (var member in members)
            {
                var other = matcher.MapDefinition((Cci.IMethodDefinition)member);
                Assert.NotNull(other);
            }
        }