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); } }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); } }
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); } }
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)); }
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); }
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); }
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); } }
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); }
/// <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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); } }