diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs index b4074e7f041c7bc4fe5c7634a4bd9e75185b9868..70b1786a564d6790a9075a220cffb6faface07f9 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs @@ -23,7 +23,6 @@ internal struct ProcessedFieldInitializers SourceMemberContainerTypeSymbol typeSymbol, MethodSymbol scriptCtor, ImmutableArray> fieldInitializers, - bool generateDebugInfo, DiagnosticBag diagnostics, ref ProcessedFieldInitializers processedInitializers) //by ref so that we can store the results of lowering { @@ -33,7 +32,7 @@ internal struct ProcessedFieldInitializers ImportChain firstImportChain; processedInitializers.BoundInitializers = BindFieldInitializers(typeSymbol, scriptCtor, fieldInitializers, - diagsForInstanceInitializers, generateDebugInfo, out firstImportChain); + diagsForInstanceInitializers, out firstImportChain); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstImportChain = firstImportChain; @@ -50,7 +49,6 @@ internal struct ProcessedFieldInitializers MethodSymbol scriptCtor, ImmutableArray> initializers, DiagnosticBag diagnostics, - bool generateDebugInfo, out ImportChain firstImportChain) { if (initializers.IsEmpty) @@ -64,11 +62,11 @@ internal struct ProcessedFieldInitializers if ((object)scriptCtor == null) { - BindRegularCSharpFieldInitializers(compilation, initializers, boundInitializers, diagnostics, generateDebugInfo, out firstImportChain); + BindRegularCSharpFieldInitializers(compilation, initializers, boundInitializers, diagnostics, out firstImportChain); } else { - BindScriptFieldInitializers(compilation, scriptCtor, initializers, boundInitializers, diagnostics, generateDebugInfo, out firstImportChain); + BindScriptFieldInitializers(compilation, scriptCtor, initializers, boundInitializers, diagnostics, out firstImportChain); } return boundInitializers.ToImmutableAndFree(); @@ -83,7 +81,6 @@ internal struct ProcessedFieldInitializers ImmutableArray> initializers, ArrayBuilder boundInitializers, DiagnosticBag diagnostics, - bool generateDebugInfo, out ImportChain firstDebugImports) { firstDebugImports = null; @@ -118,7 +115,7 @@ internal struct ProcessedFieldInitializers Debug.Assert(parentBinder.ContainingMemberOrLambda == fieldSymbol.ContainingType || //should be the binder for the type fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios - if (generateDebugInfo && firstDebugImports == null) + if (firstDebugImports == null) { firstDebugImports = parentBinder.ImportChain; } @@ -138,7 +135,7 @@ internal struct ProcessedFieldInitializers /// private static void BindScriptFieldInitializers(CSharpCompilation compilation, MethodSymbol scriptCtor, ImmutableArray> initializers, ArrayBuilder boundInitializers, DiagnosticBag diagnostics, - bool generateDebugInfo, out ImportChain firstDebugImports) + out ImportChain firstDebugImports) { Debug.Assert((object)scriptCtor != null); @@ -177,7 +174,7 @@ internal struct ProcessedFieldInitializers Binder scriptClassBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(((ImplicitNamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass); - if (generateDebugInfo && firstDebugImports == null) + if (firstDebugImports == null) { firstDebugImports = scriptClassBinder.ImportChain; } diff --git a/src/Compilers/CSharp/Portable/Binder/ImportChain.cs b/src/Compilers/CSharp/Portable/Binder/ImportChain.cs index 3539233473afdd9c208c0af39179953f4c2af7cd..ab3c873006a3877d51c30e7729100fffb1dc13c0 100644 --- a/src/Compilers/CSharp/Portable/Binder/ImportChain.cs +++ b/src/Compilers/CSharp/Portable/Binder/ImportChain.cs @@ -1,14 +1,9 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Linq; -using System.Threading; using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.Emit; namespace Microsoft.CodeAnalysis.CSharp { @@ -27,17 +22,29 @@ public ImportChain(Imports imports, ImportChain parentOpt) ParentOpt = parentOpt; } - ImmutableArray Cci.IImportScope.GetUsedNamespaces(EmitContext context) + ImmutableArray Cci.IImportScope.GetUsedNamespaces() { - if (_lazyTranslatedImports.IsDefault) + // The imports should have been translated during code gen. + Debug.Assert(!_lazyTranslatedImports.IsDefault); + return _lazyTranslatedImports; + } + + public Cci.IImportScope Translate(Emit.PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics) + { + for (var scope = this; scope != null; scope = scope.ParentOpt) { - ImmutableInterlocked.InterlockedInitialize(ref _lazyTranslatedImports, TranslateImports(context)); + if (!scope._lazyTranslatedImports.IsDefault) + { + break; + } + + ImmutableInterlocked.InterlockedInitialize(ref scope._lazyTranslatedImports, scope.TranslateImports(moduleBuilder, diagnostics)); } - return _lazyTranslatedImports; + return this; } - private ImmutableArray TranslateImports(EmitContext context) + private ImmutableArray TranslateImports(Emit.PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics) { var usedNamespaces = ArrayBuilder.GetInstance(); @@ -61,12 +68,13 @@ private ImmutableArray TranslateImports(EmitContext con if (namespaceOrType.IsNamespace) { var ns = (NamespaceSymbol)namespaceOrType; - var assemblyRef = TryGetAssemblyScope(context, ns); + var assemblyRef = TryGetAssemblyScope(ns, moduleBuilder, diagnostics); usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateNamespace(ns, assemblyRef)); } - else + else if (!namespaceOrType.ContainingAssembly.IsLinked) { - var typeRef = GetTypeReference(context, (TypeSymbol)namespaceOrType); + // We skip alias imports of embedded types to be consistent with imports of aliased embedded types and with VB. + var typeRef = GetTypeReference((TypeSymbol)namespaceOrType, nsOrType.UsingDirective, moduleBuilder, diagnostics); usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateType(typeRef)); } } @@ -79,18 +87,21 @@ private ImmutableArray TranslateImports(EmitContext con { var alias = pair.Key; var symbol = pair.Value.Alias; + var syntax = pair.Value.UsingDirective; Debug.Assert(!symbol.IsExtern); NamespaceOrTypeSymbol target = symbol.Target; if (target.Kind == SymbolKind.Namespace) { var ns = (NamespaceSymbol)target; - var assemblyRef = TryGetAssemblyScope(context, ns); + var assemblyRef = TryGetAssemblyScope(ns, moduleBuilder, diagnostics); usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateNamespace(ns, assemblyRef, alias)); } - else + else if (!target.ContainingAssembly.IsLinked) { - var typeRef = GetTypeReference(context, (TypeSymbol)target); + // We skip alias imports of embedded types to avoid breaking existing code that + // imports types that can't be embedded but doesn't use them anywhere else in the code. + var typeRef = GetTypeReference((TypeSymbol)target, syntax, moduleBuilder, diagnostics); usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateType(typeRef, alias)); } } @@ -99,17 +110,17 @@ private ImmutableArray TranslateImports(EmitContext con return usedNamespaces.ToImmutableAndFree(); } - private static Cci.ITypeReference GetTypeReference(EmitContext context, TypeSymbol type) + private static Cci.ITypeReference GetTypeReference(TypeSymbol type, SyntaxNode syntaxNode, Emit.PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics) { - return context.ModuleBuilder.Translate(type, context.SyntaxNodeOpt, context.Diagnostics); + return moduleBuilder.Translate(type, syntaxNode, diagnostics); } - private Cci.IAssemblyReference TryGetAssemblyScope(EmitContext context, NamespaceSymbol @namespace) + private Cci.IAssemblyReference TryGetAssemblyScope(NamespaceSymbol @namespace, Emit.PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics) { AssemblySymbol containingAssembly = @namespace.ContainingAssembly; - if ((object)containingAssembly != null && (object)containingAssembly != context.ModuleBuilder.CommonCompilation.Assembly) + if ((object)containingAssembly != null && (object)containingAssembly != moduleBuilder.CommonCompilation.Assembly) { - var referenceManager = ((CSharpCompilation)context.ModuleBuilder.CommonCompilation).GetBoundReferenceManager(); + var referenceManager = ((CSharpCompilation)moduleBuilder.CommonCompilation).GetBoundReferenceManager(); foreach (var referencedAssembly in referenceManager.ReferencedAssembliesMap.Values) { @@ -117,7 +128,7 @@ private Cci.IAssemblyReference TryGetAssemblyScope(EmitContext context, Namespac { if (!referencedAssembly.DeclarationsAccessibleWithoutAlias()) { - return context.ModuleBuilder.Translate(containingAssembly, context.Diagnostics); + return moduleBuilder.Translate(containingAssembly, diagnostics); } } } diff --git a/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs b/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs index 129100844d6587b042c7a31a531b4f1473d7a67f..907442cb5e34fa78c6dd70d1f275d6a3f3fdb407 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs @@ -70,7 +70,7 @@ private enum IndirectReturnState : byte PEModuleBuilder moduleBuilder, DiagnosticBag diagnostics, OptimizationLevel optimizations, - bool emittingPdbs) + bool emittingPdb) { Debug.Assert((object)method != null); Debug.Assert(boundBody != null); @@ -98,7 +98,7 @@ private enum IndirectReturnState : byte // user code that can be stepped thru, or changed during EnC. // // This setting only affects generating PDB sequence points, it shall not affect generated IL in any way. - _emitPdbSequencePoints = emittingPdbs && method.GenerateDebugInfo; + _emitPdbSequencePoints = emittingPdb && method.GenerateDebugInfo; if (_optimizations == OptimizationLevel.Release) { diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 8c4ea41289c09bc262ada7a4766b9ee65d82eb56..f3e665ac1b390b5381e64c48a6902f9cc88c37d5 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2322,7 +2322,7 @@ internal override StrongNameKeys StrongNameKeys CommonPEModuleBuilder moduleBuilder, Stream win32Resources, Stream xmlDocStream, - bool generateDebugInfo, + bool emittingPdb, DiagnosticBag diagnostics, Predicate filterOpt, CancellationToken cancellationToken) @@ -2354,12 +2354,9 @@ internal override StrongNameKeys StrongNameKeys } else { - if (generateDebugInfo && moduleBeingBuilt != null) + if (emittingPdb && !StartSourceChecksumCalculation(moduleBeingBuilt, diagnostics)) { - if (!StartSourceChecksumCalculation(moduleBeingBuilt, diagnostics)) - { - return false; - } + return false; } // Perform initial bind of method bodies in spite of earlier errors. This is the same @@ -2371,7 +2368,7 @@ internal override StrongNameKeys StrongNameKeys MethodCompiler.CompileMethodBodies( this, moduleBeingBuilt, - generateDebugInfo, + emittingPdb, hasDeclarationErrors, diagnostics: methodBodyDiagnosticBag, filterOpt: filterOpt, diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 8bbf8cfd252bf1dfcd7d20d7516665a8d5271fe5..e65d3c78b9557241643896194403248c9aa734ac 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.CSharp internal sealed class MethodCompiler : CSharpSymbolVisitor { private readonly CSharpCompilation _compilation; - private readonly bool _generateDebugInfo; + private readonly bool _emittingPdb; private readonly CancellationToken _cancellationToken; private readonly DiagnosticBag _diagnostics; private readonly bool _hasDeclarationErrors; @@ -73,7 +73,7 @@ private void SetGlobalErrorIfTrue(bool arg) } // Internal for testing only. - internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuiltOpt, bool generateDebugInfo, bool hasDeclarationErrors, + internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuiltOpt, bool emittingPdb, bool hasDeclarationErrors, DiagnosticBag diagnostics, Predicate filterOpt, CancellationToken cancellationToken) { Debug.Assert(compilation != null); @@ -81,7 +81,7 @@ private void SetGlobalErrorIfTrue(bool arg) _compilation = compilation; _moduleBeingBuiltOpt = moduleBeingBuiltOpt; - _generateDebugInfo = generateDebugInfo; + _emittingPdb = emittingPdb; _cancellationToken = cancellationToken; _diagnostics = diagnostics; _filterOpt = filterOpt; @@ -89,7 +89,7 @@ private void SetGlobalErrorIfTrue(bool arg) _hasDeclarationErrors = hasDeclarationErrors; SetGlobalErrorIfTrue(hasDeclarationErrors); - if (generateDebugInfo) + if (emittingPdb) { _debugDocumentProvider = (path, basePath) => moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, CreateDebugDocumentForFile); } @@ -233,7 +233,7 @@ internal static MethodSymbol DefineScriptEntryPoint(CSharpCompilation compilatio diagnostics: diagnostics, debugDocumentProvider: null, importChainOpt: null, - generateDebugInfo: false); + emittingPdb: false); moduleBeingBuilt.SetMethodBody(scriptEntryPoint, emittedBody); moduleBeingBuilt.AddSynthesizedDefinition(compilation.ScriptClass, scriptEntryPoint); @@ -376,10 +376,10 @@ private void CompileNamedType(NamedTypeSymbol symbol) if ((object)sourceTypeSymbol != null) { _cancellationToken.ThrowIfCancellationRequested(); - Binder.BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.StaticInitializers, _generateDebugInfo, _diagnostics, ref processedStaticInitializers); + Binder.BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.StaticInitializers, _diagnostics, ref processedStaticInitializers); _cancellationToken.ThrowIfCancellationRequested(); - Binder.BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.InstanceInitializers, _generateDebugInfo, _diagnostics, ref processedInstanceInitializers); + Binder.BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.InstanceInitializers, _diagnostics, ref processedInstanceInitializers); if (compilationState.Emitting) { @@ -625,7 +625,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) diagnosticsThisMethod, _debugDocumentProvider, methodWithBody.ImportChainOpt, - generateDebugInfo: _generateDebugInfo && method.GenerateDebugInfo); + emittingPdb: _emittingPdb); } _diagnostics.AddRange(diagnosticsThisMethod); @@ -719,7 +719,7 @@ private void CompileFieldLikeEventAccessor(SourceEventSymbol eventSymbol, bool i diagnostics: diagnosticsThisMethod, debugDocumentProvider: _debugDocumentProvider, importChainOpt: null, - generateDebugInfo: false); + emittingPdb: false); _moduleBeingBuiltOpt.SetMethodBody(accessor, emittedBody); // Definition is already in the symbol table, so don't call moduleBeingBuilt.AddCompilerGeneratedDefinition @@ -841,7 +841,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum includeInitializersInBody = !processedInitializers.BoundInitializers.IsDefaultOrEmpty && !HasThisConstructorInitializer(methodSymbol); - body = BindMethodBody(methodSymbol, compilationState, diagsForCurrentMethod, _generateDebugInfo, out importChain); + body = BindMethodBody(methodSymbol, compilationState, diagsForCurrentMethod, out importChain); // lower initializers just once. the lowered tree will be reused when emitting all constructors // with field initializers. Once lowered, these initializers will be stashed in processedInitializers.LoweredInitializers @@ -869,22 +869,18 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum } } - #if DEBUG // If the method is a synthesized static or instance constructor, then debugImports will be null and we will use the value // from the first field initializer. - if (_generateDebugInfo) + if ((methodSymbol.MethodKind == MethodKind.Constructor || methodSymbol.MethodKind == MethodKind.StaticConstructor) && + methodSymbol.IsImplicitlyDeclared && body == null) { - if ((methodSymbol.MethodKind == MethodKind.Constructor || methodSymbol.MethodKind == MethodKind.StaticConstructor) && - methodSymbol.IsImplicitlyDeclared && body == null) - { - // There was no body to bind, so we didn't get anything from BindMethodBody. - Debug.Assert(importChain == null); - } - - // Either there were no field initializers or we grabbed debug imports from the first one. - Debug.Assert(processedInitializers.BoundInitializers.IsDefaultOrEmpty || processedInitializers.FirstImportChain != null); + // There was no body to bind, so we didn't get anything from BindMethodBody. + Debug.Assert(importChain == null); } + + // Either there were no field initializers or we grabbed debug imports from the first one. + Debug.Assert(processedInitializers.BoundInitializers.IsDefaultOrEmpty || processedInitializers.FirstImportChain != null); #endif importChain = importChain ?? processedInitializers.FirstImportChain; @@ -1082,7 +1078,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum diagsForCurrentMethod, _debugDocumentProvider, importChain, - _generateDebugInfo && methodSymbol.GenerateDebugInfo); + _emittingPdb); _moduleBeingBuiltOpt.SetMethodBody(methodSymbol.PartialDefinitionPart ?? methodSymbol, emittedBody); } @@ -1242,7 +1238,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, ImportChain importChainOpt, - bool generateDebugInfo) + bool emittingPdb) { // Note: don't call diagnostics.HasAnyErrors() in release; could be expensive if compilation has many warnings. Debug.Assert(!diagnostics.HasAnyErrors(), "Running code generator when errors exist might be dangerous; code generator not expecting errors"); @@ -1257,7 +1253,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol, { Cci.AsyncMethodBodyDebugInfo asyncDebugInfo = null; - var codeGen = new CodeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnosticsForThisMethod, optimizations, generateDebugInfo); + var codeGen = new CodeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnosticsForThisMethod, optimizations, emittingPdb); // We need to save additional debugging information for MoveNext of an async state machine. var stateMachineMethod = method as SynthesizedStateMachineMethod; @@ -1284,6 +1280,11 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol, codeGen.Generate(); } + // Translate the imports even if we are not writing PDBs. The translation has an impact on generated metadata + // and we don't want to emit different metadata depending on whether or we emit with PDB stream. + // TODO (https://github.com/dotnet/roslyn/issues/2846): This will need to change for member initializers in partial class. + var importScopeOpt = importChainOpt?.Translate(moduleBuilder, diagnosticsForThisMethod); + var localVariables = builder.LocalSlotManager.LocalsInOrder(); if (localVariables.Length > 0xFFFE) @@ -1329,7 +1330,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol, builder.RealizedExceptionHandlers, builder.GetAllScopes(), builder.HasDynamicLocal, - importChainOpt, + importScopeOpt, lambdaDebugInfo, closureDebugInfo, stateMachineTypeOpt?.Name, @@ -1395,11 +1396,11 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol, internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics) { ImportChain unused; - return BindMethodBody(method, compilationState, diagnostics, false, out unused); + return BindMethodBody(method, compilationState, diagnostics, out unused); } // NOTE: can return null if the method has no body. - private static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo, out ImportChain importChain) + private static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, out ImportChain importChain) { importChain = null; @@ -1457,10 +1458,7 @@ private static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationSta Binder binder = new ExecutableCodeBinder(blockSyntax, sourceMethod, inMethodBinder); body = binder.BindBlock(blockSyntax, diagnostics); - if (generateDebugInfo) - { - importChain = binder.ImportChain; - } + importChain = binder.ImportChain; if (inMethodBinder.IsDirectlyInIterator) { diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs index 79bf8ece258bf2b257f7ff6252fafa8cbc43a8fe..ae4fbcec5bc67796eca55b8421af3ddcdcc84d00 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs @@ -72,7 +72,7 @@ internal static class EmitHelpers moduleBeingBuilt, win32Resources: null, xmlDocStream: null, - generateDebugInfo: true, + emittingPdb: true, diagnostics: diagnostics, filterOpt: changes.RequiresCompilation, cancellationToken: cancellationToken)) diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index b9ef3c3aea3ea07db2684bb1ccc53169a27e79a2..a563efb74a4942c26a2a1a555aa37f0d0a6ef22e 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -117,7 +117,7 @@ internal sealed override AssemblySymbol CorLibrary protected sealed override IEnumerable LinkedAssembliesDebugInfo => SpecializedCollections.EmptyEnumerable(); // C# currently doesn't emit compilation level imports (TODO: scripting). - protected override ImmutableArray GetImports(EmitContext context) => ImmutableArray.Empty; + protected override ImmutableArray GetImports() => ImmutableArray.Empty; // C# doesn't allow to define default namespace for compilation. protected override string DefaultNamespace => null; diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs index 22e9ec8f673e22d447f7a46e9da5847d3e034c42..8d00fc9cb1acf48d47469ad9e05788f8e666845a 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs @@ -12570,7 +12570,7 @@ static System.Action M() var methodBodyCompiler = new MethodCompiler( compilation: compilation, moduleBeingBuiltOpt: module, - generateDebugInfo: false, + emittingPdb: false, hasDeclarationErrors: false, diagnostics: diagnostics, filterOpt: null, diff --git a/src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs b/src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs index 2abdd0f5bb20a73e9fcf23767a77e637bc2c981b..d8d97d058a07da1d19621c8b5ddfa6c3476f26eb 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/PDBUsingTests.cs @@ -3,9 +3,13 @@ using System.Collections.Immutable; using System.IO; using System.Linq; +using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; +using System.Text; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.MetadataUtilities; using Roslyn.Test.Utilities; using Xunit; using ProprietaryTestResources = Microsoft.CodeAnalysis.Test.Resources.Proprietary; @@ -2130,5 +2134,208 @@ static void Main() Assert.Equal(1, reader.GetTableRowCount(TableIndex.TypeSpec)); }); } + + [Fact] + public void EmittingPdbVsNot() + { + string source = @" +using System; +using X = System.IO.FileStream; + +class C +{ + int x = 1; + static int y = 1; + + C() + { + Console.WriteLine(); + } +} +"; + + var c = CreateCompilationWithMscorlib(source, assemblyName: "EmittingPdbVsNot", options: TestOptions.ReleaseDll); + + var peStream1 = new MemoryStream(); + var peStream2 = new MemoryStream(); + var pdbStream = new MemoryStream(); + + var emitResult1 = c.Emit(peStream: peStream1, pdbStream: pdbStream); + var emitResult2 = c.Emit(peStream: peStream2); + + SharedCompilationUtils.VerifyMetadataEqualModuloMvid(peStream1, peStream2); + } + + [Fact] + public void ImportedNoPiaTypes() + { + var sourceLib = @" +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: Guid(""11111111-1111-1111-1111-111111111111"")] +[assembly: ImportedFromTypeLib(""Foo"")] +[assembly: TypeLibVersion(1, 0)] + +namespace N +{ + public enum E + { + Value1 = 1 + } + + public struct S1 + { + public int A1; + public int A2; + } + + public struct S2 + { + public const int Value2 = 2; + } + + public struct SBad + { + public int A3; + public const int Value3 = 3; + } + + [ComImport, Guid(""22222222-2222-2222-2222-222222222222"")] + public interface I + { + void F(); + } + + public interface IBad + { + void F(); + } +} +"; + var source = @" +using System; + +using static N.E; +using static N.SBad; +using Z1 = N.S1; +using Z2 = N.S2; +using ZBad = N.SBad; +using NI = N.I; +using NIBad = N.IBad; + +class C +{ + NI i; + + void M() + { + Console.WriteLine(Value1); + Console.WriteLine(Z2.Value2); + Console.WriteLine(new Z1()); + } +} +"; + var libRef = CreateCompilationWithMscorlib(sourceLib, assemblyName: "ImportedNoPiaTypesAssemblyName").EmitToImageReference(embedInteropTypes: true); + var compilation = CreateCompilationWithMscorlib(source, new[] { libRef }); + var v = CompileAndVerify(compilation); + + v.Diagnostics.Verify( + // (14,8): warning CS0169: The field 'C.i' is never used + // NI i; + Diagnostic(ErrorCode.WRN_UnreferencedField, "i").WithArguments("C.i"), + // (5,1): hidden CS8019: Unnecessary using directive. + // using static N.SBad; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static N.SBad;"), + // (10,1): hidden CS8019: Unnecessary using directive. + // using NIBad = N.IBad; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using NIBad = N.IBad;"), + // (8,1): hidden CS8019: Unnecessary using directive. + // using ZBad = N.SBad; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using ZBad = N.SBad;")); + + // Usings of embedded types are currently ommitted: + v.VerifyPdb("C.M", @" + + + + + + + + + + + + + + + + + + + +"); + } + + [Fact] + public void ImportedTypeWithUnknownBase() + { + var sourceLib1 = @" +namespace N +{ + public class A { } +} +"; + var sourceLib2 = @" +namespace N +{ + public class B : A { } +} +"; + var source = @" +using System; +using X = N.B; + +class C +{ + void M() + { + Console.WriteLine(); + } +} +"; + var libRef1 = CreateCompilationWithMscorlib(sourceLib1).EmitToImageReference(); + var libRef2 = CreateCompilationWithMscorlib(sourceLib2, new[] { libRef1 }, assemblyName: "LibRef2").EmitToImageReference(); + var compilation = CreateCompilationWithMscorlib(source, new[] { libRef2 }); + var v = CompileAndVerify(compilation, emitters: TestEmitters.CCI); + + v.Diagnostics.Verify( + // (3,1): hidden CS8019: Unnecessary using directive. + // using X = N.B; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using X = N.B;")); + + v.VerifyPdb("C.M", @" + + + + + + + + + + + + + + + + + + +"); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/FieldInitializerBindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/FieldInitializerBindingTests.cs index 0295ae41f343f95e9b6a24b9697ce580ecfe22a6..4f3f395cca8d1f3a5b3f23579cb9dc20e5a1e2c6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/FieldInitializerBindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/FieldInitializerBindingTests.cs @@ -293,16 +293,9 @@ private static ImmutableArray BindInitializersWithoutDiagnosti scriptCtor: null, initializers: initializers, diagnostics: diagnostics, - generateDebugInfo: false, firstImportChain: out unused); - var filteredDiag = diagnostics.AsEnumerable(); - foreach (var diagnostic in filteredDiag) - { - Console.WriteLine(diagnostic); - } - - Assert.True(filteredDiag.IsEmpty()); + diagnostics.Verify(); return boundInitializers; } diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index 7cd65e576a0dcb247151790cf781a3149e099bca..0b83e3eaeae053395a8e3c1bba1f872d3279041d 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -1250,7 +1250,7 @@ internal bool IsRealSigned CommonPEModuleBuilder moduleBuilder, Stream win32Resources, Stream xmlDocStream, - bool generateDebugInfo, + bool emittingPdb, DiagnosticBag diagnostics, Predicate filterOpt, CancellationToken cancellationToken); @@ -1259,7 +1259,7 @@ internal bool IsRealSigned CommonPEModuleBuilder moduleBuilder, Stream win32Resources, Stream xmlDocStream, - bool generateDebugInfo, + bool emittingPdb, DiagnosticBag diagnostics, Predicate filterOpt, CancellationToken cancellationToken) @@ -1270,7 +1270,7 @@ internal bool IsRealSigned moduleBuilder, win32Resources, xmlDocStream, - generateDebugInfo, + emittingPdb, diagnostics, filterOpt, cancellationToken); @@ -1303,7 +1303,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken) moduleBeingBuilt, win32Resources: null, xmlDocStream: null, - generateDebugInfo: false, + emittingPdb: false, diagnostics: discardedDiagnostics, filterOpt: null, cancellationToken: cancellationToken); @@ -1576,7 +1576,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken) moduleBeingBuilt, win32Resources, xmlDocumentationStream, - generateDebugInfo: pdbStreamProvider != null, + emittingPdb: pdbStreamProvider != null, diagnostics: diagnostics, filterOpt: null, cancellationToken: cancellationToken)) diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index 7c1304293fa5324ab0711bf0102ccd496921bc78..9a2e0588642272af7c0bafe256d4e4f5d49ec556 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.Emit.NoPia; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Emit @@ -24,6 +25,7 @@ internal abstract class CommonPEModuleBuilder internal abstract CommonModuleCompilationState CommonModuleCompilationState { get; } internal abstract void CompilationFinished(); internal abstract ImmutableDictionary> GetSynthesizedMembers(); + internal abstract CommonEmbeddedTypesManager CommonEmbeddedTypesManagerOpt { get; } } /// @@ -237,54 +239,16 @@ internal sealed override Cci.ITypeReference Translate(ITypeSymbol symbol, Syntax return Translate((TTypeSymbol)symbol, (TSyntaxNode)syntaxNodeOpt, diagnostics); } - internal OutputKind OutputKind - { - get - { - return _outputKind; - } - } + internal OutputKind OutputKind => _outputKind; + internal TSourceModuleSymbol SourceModule => _sourceModule; + internal TCompilation Compilation => _compilation; - internal TSourceModuleSymbol SourceModule - { - get - { - return _sourceModule; - } - } - - internal TCompilation Compilation - { - get - { - return _compilation; - } - } - - internal override Compilation CommonCompilation - { - get - { - return _compilation; - } - } - - internal override CommonModuleCompilationState CommonModuleCompilationState - { - get - { - return this.CompilationState; - } - } + internal sealed override Compilation CommonCompilation => _compilation; + internal sealed override CommonModuleCompilationState CommonModuleCompilationState => CompilationState; + internal sealed override CommonEmbeddedTypesManager CommonEmbeddedTypesManagerOpt => EmbeddedTypesManagerOpt; // General entry point method. May be a PE entry point or a submission entry point. - internal sealed override Cci.IMethodReference EntryPoint - { - get - { - return _entryPoint; - } - } + internal sealed override Cci.IMethodReference EntryPoint => _entryPoint; internal void SetEntryPoint(TMethodSymbol value) { @@ -778,8 +742,8 @@ ImmutableArray Cci.IModule.GetAssemblyReferenceAlias IEnumerable Cci.IModule.LinkedAssembliesDebugInfo => LinkedAssembliesDebugInfo; protected abstract IEnumerable LinkedAssembliesDebugInfo { get; } - ImmutableArray Cci.IModule.GetImports(EmitContext context) => GetImports(context); - protected abstract ImmutableArray GetImports(EmitContext context); + ImmutableArray Cci.IModule.GetImports() => GetImports(); + protected abstract ImmutableArray GetImports(); string Cci.IModule.DefaultNamespace => DefaultNamespace; protected abstract string DefaultNamespace { get; } diff --git a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs index bd55c4a1de9be5da28a1bea4ec1b8461ec5a9262..527188c5faf193357ae324a6389984229c43491e 100644 --- a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs +++ b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs @@ -305,7 +305,7 @@ public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, // NOTE: This is an attempt to match Dev10's apparent behavior. For iterator methods (i.e. the method // that appears in source, not the synthesized ones), Dev10 only emits the ForwardIterator and IteratorLocal // custom debug info (e.g. there will be no information about the usings that were in scope). - if (!isIterator) + if (!isIterator && methodBody.ImportScope != null) { IMethodDefinition forwardToMethod; if (customDebugInfoWriter.ShouldForwardNamespaceScopes(Context, methodBody, methodToken, out forwardToMethod)) @@ -375,7 +375,7 @@ private void DefineNamespaceScopes(IMethodBody methodBody) { for (var scope = namespaceScopes; scope != null; scope = scope.Parent) { - foreach (var import in scope.GetUsedNamespaces(Context)) + foreach (var import in scope.GetUsedNamespaces()) { if (import.TargetNamespaceOpt == null && import.TargetTypeOpt == null) { @@ -396,7 +396,7 @@ private void DefineNamespaceScopes(IMethodBody methodBody) // file and namespace level for (IImportScope scope = namespaceScopes; scope != null; scope = scope.Parent) { - foreach (UsedNamespaceOrType import in scope.GetUsedNamespaces(Context)) + foreach (UsedNamespaceOrType import in scope.GetUsedNamespaces()) { var importString = TryEncodeImport(import, lazyDeclaredExternAliases, isProjectLevel: false); if (importString != null) @@ -424,7 +424,7 @@ private void DefineNamespaceScopes(IMethodBody methodBody) UsingNamespace("&" + assemblyName, module); } - foreach (UsedNamespaceOrType import in module.GetImports(Context)) + foreach (UsedNamespaceOrType import in module.GetImports()) { var importString = TryEncodeImport(import, null, isProjectLevel: true); if (importString != null) diff --git a/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs b/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs index 36c4689e9ebc2579c8cf3eb0ca54bc142faf55b3..32f2488f2ca83202124a4bd241f183d7f15d3e3f 100644 --- a/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs @@ -34,7 +34,7 @@ public CustomDebugInfoWriter(PdbWriter pdbWriter) /// public bool ShouldForwardNamespaceScopes(EmitContext context, IMethodBody methodBody, uint methodToken, out IMethodDefinition forwardToMethod) { - if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody) || methodBody.ImportScope == null) + if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody)) { // SerializeNamespaceScopeMetadata will do the actual forwarding in case this is a CSharp method. // VB on the other hand adds a "@methodtoken" to the scopes instead. @@ -351,7 +351,7 @@ private void SerializeNamespaceScopeMetadata(EmitContext context, IMethodBody me BinaryWriter cmw = new BinaryWriter(customMetadata); for (IImportScope scope = methodBody.ImportScope; scope != null; scope = scope.Parent) { - usingCounts.Add((ushort)scope.GetUsedNamespaces(context).Length); + usingCounts.Add((ushort)scope.GetUsedNamespaces().Length); } // ACASEY: This originally wrote (uint)12, (ushort)1, (ushort)0 in the @@ -414,7 +414,7 @@ private bool ShouldForwardToPreviousMethodWithUsingInfo(EmitContext context, IMe var s2 = previousScopes; while (s1 != null && s2 != null) { - if (!s1.GetUsedNamespaces(context).SequenceEqual(s2.GetUsedNamespaces(context))) + if (!s1.GetUsedNamespaces().SequenceEqual(s2.GetUsedNamespaces())) { return false; } diff --git a/src/Compilers/Core/Portable/PEWriter/IImportScope.cs b/src/Compilers/Core/Portable/PEWriter/IImportScope.cs index 19ae2976430c2c2aef33ea92f00642e0bf15bd00..44132d966b86d0bff48dca644532f8981e7c96e3 100644 --- a/src/Compilers/Core/Portable/PEWriter/IImportScope.cs +++ b/src/Compilers/Core/Portable/PEWriter/IImportScope.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Emit; namespace Microsoft.Cci { @@ -13,7 +12,7 @@ internal interface IImportScope /// /// Zero or more used namespaces. These correspond to using directives in C# or Imports syntax in VB. /// - ImmutableArray GetUsedNamespaces(EmitContext context); + ImmutableArray GetUsedNamespaces(); /// /// Parent import scope, or null. diff --git a/src/Compilers/Core/Portable/PEWriter/ReferenceIndexer.cs b/src/Compilers/Core/Portable/PEWriter/ReferenceIndexer.cs index 10057f3e56c155484c6d689c6259d5c3c0483a63..c125f36e21fe2e99056a0b39da606452c786fd06 100644 --- a/src/Compilers/Core/Portable/PEWriter/ReferenceIndexer.cs +++ b/src/Compilers/Core/Portable/PEWriter/ReferenceIndexer.cs @@ -47,7 +47,7 @@ public override void Visit(IModule module) this.Visit(module.GetResources(Context)); } - VisitImports(module.GetImports(Context)); + VisitImports(module.GetImports()); } public void VisitMethodBodyReference(IReference reference) @@ -101,7 +101,7 @@ protected override void ProcessMethodBody(IMethodDefinition method) { if (_alreadySeenScopes.Add(scope)) { - VisitImports(scope.GetUsedNamespaces(Context)); + VisitImports(scope.GetUsedNamespaces()); } else { diff --git a/src/Compilers/Core/Portable/PEWriter/Units.cs b/src/Compilers/Core/Portable/PEWriter/Units.cs index 0bd208e1f53d94ce780bd8ae0d34a23c2fc7eaa9..21f7a629144af988c8d5ac2d207fd8217b9e671a 100644 --- a/src/Compilers/Core/Portable/PEWriter/Units.cs +++ b/src/Compilers/Core/Portable/PEWriter/Units.cs @@ -414,7 +414,7 @@ ulong SizeOfStackReserve /// /// Project level imports (VB only, TODO: C# scripts). /// - ImmutableArray GetImports(EmitContext context); + ImmutableArray GetImports(); /// /// Default namespace (VB only). diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/CodeGenerator.vb b/src/Compilers/VisualBasic/Portable/CodeGen/CodeGenerator.vb index 5201f56541ef8cfbec530e4b5ef1916a550beac1..727560974a1e0b7305272e8a706bf4f13fab9cb6 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/CodeGenerator.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/CodeGenerator.vb @@ -47,7 +47,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen moduleBuilder As PEModuleBuilder, diagnostics As DiagnosticBag, optimizations As OptimizationLevel, - emittingPdbs As Boolean) + emittingPdb As Boolean) Debug.Assert(method IsNot Nothing) Debug.Assert(boundBody IsNot Nothing) @@ -55,14 +55,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen Debug.Assert(moduleBuilder IsNot Nothing) Debug.Assert(diagnostics IsNot Nothing) - Me._method = method - Me._block = boundBody - Me._builder = builder - Me._module = moduleBuilder - Me._diagnostics = diagnostics + _method = method + _block = boundBody + _builder = builder + _module = moduleBuilder + _diagnostics = diagnostics ' Always optimize synthesized methods that don't contain user code. - Me._optimizations = If(method.GenerateDebugInfo, optimizations, OptimizationLevel.Release) + _optimizations = If(method.GenerateDebugInfo, optimizations, OptimizationLevel.Release) ' Emit sequence points unless ' - the PDBs are not being generated @@ -70,14 +70,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen ' user code that can be stepped thru, or changed during EnC. ' ' This setting only affects generating PDB sequence points, it shall Not affect generated IL in any way. - Me._emitPdbSequencePoints = emittingPdbs AndAlso method.GenerateDebugInfo + _emitPdbSequencePoints = emittingPdb AndAlso method.GenerateDebugInfo - If Me._optimizations = OptimizationLevel.Release Then - Me._block = Optimizer.Optimize(method, boundBody, Me._stackLocals) + If _optimizations = OptimizationLevel.Release Then + _block = Optimizer.Optimize(method, boundBody, _stackLocals) End If - Me._checkCallsForUnsafeJITOptimization = (Me._method.ImplementationAttributes And MethodSymbol.DisableJITOptimizationFlags) <> MethodSymbol.DisableJITOptimizationFlags - Debug.Assert(Not Me._module.JITOptimizationIsDisabled(Me._method)) + _checkCallsForUnsafeJITOptimization = (_method.ImplementationAttributes And MethodSymbol.DisableJITOptimizationFlags) <> MethodSymbol.DisableJITOptimizationFlags + Debug.Assert(Not _module.JITOptimizationIsDisabled(_method)) End Sub Public Sub Generate() diff --git a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb index 21211bf65766b3a1572c35477f3961d7833ec84a..e2823dd4e2ee824d91638d21902d0493e31eab23 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb @@ -20,7 +20,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Private ReadOnly _compilation As VisualBasicCompilation Private ReadOnly _cancellationToken As CancellationToken - Private ReadOnly _generateDebugInfo As Boolean + Private ReadOnly _emittingPdb As Boolean Private ReadOnly _diagnostics As DiagnosticBag Private ReadOnly _hasDeclarationErrors As Boolean Private ReadOnly _namespaceScopeBuilder As NamespaceScopeBuilder @@ -78,28 +78,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' moduleBeingBuilt can be Nothing in order to just analyze methods for errors. Private Sub New(compilation As VisualBasicCompilation, moduleBeingBuiltOpt As PEModuleBuilder, - generateDebugInfo As Boolean, + emittingPdb As Boolean, doEmitPhase As Boolean, hasDeclarationErrors As Boolean, diagnostics As DiagnosticBag, filter As Predicate(Of Symbol), cancellationToken As CancellationToken) - Me._compilation = compilation - Me._moduleBeingBuiltOpt = moduleBeingBuiltOpt - Me._diagnostics = diagnostics - Me._hasDeclarationErrors = hasDeclarationErrors - Me._cancellationToken = cancellationToken - Me._doEmitPhase = doEmitPhase - Me._generateDebugInfo = generateDebugInfo - Me._filterOpt = filter - - If generateDebugInfo Then - Me._debugDocumentProvider = Function(path As String, basePath As String) moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, AddressOf CreateDebugDocumentForFile) + _compilation = compilation + _moduleBeingBuiltOpt = moduleBeingBuiltOpt + _diagnostics = diagnostics + _hasDeclarationErrors = hasDeclarationErrors + _cancellationToken = cancellationToken + _doEmitPhase = doEmitPhase + _emittingPdb = emittingPdb + _filterOpt = filter + + If emittingPdb Then + _debugDocumentProvider = Function(path As String, basePath As String) moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, AddressOf CreateDebugDocumentForFile) End If If compilation.Options.ConcurrentBuild Then - Me._compilerTasks = New ConcurrentStack(Of Task)() + _compilerTasks = New ConcurrentStack(Of Task)() End If End Sub @@ -155,7 +155,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim compiler = New MethodCompiler(compilation, moduleBeingBuiltOpt:=Nothing, - generateDebugInfo:=False, + emittingPdb:=False, doEmitPhase:=doEmitPhase, hasDeclarationErrors:=hasDeclarationErrors, diagnostics:=diagnostics, @@ -187,7 +187,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Friend Shared Sub CompileMethodBodies(compilation As VisualBasicCompilation, moduleBeingBuiltOpt As PEModuleBuilder, - generateDebugInfo As Boolean, + emittingPdb As Boolean, hasDeclarationErrors As Boolean, filter As Predicate(Of Symbol), diagnostics As DiagnosticBag, @@ -208,13 +208,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic #End If Dim compiler = New MethodCompiler(compilation, - moduleBeingBuiltOpt, - generateDebugInfo, - doEmitPhase:=True, - hasDeclarationErrors:=hasDeclarationErrors, - diagnostics:=diagnostics, - filter:=filter, - cancellationToken:=cancellationToken) + moduleBeingBuiltOpt, + emittingPdb, + doEmitPhase:=True, + hasDeclarationErrors:=hasDeclarationErrors, + diagnostics:=diagnostics, + filter:=filter, + cancellationToken:=cancellationToken) compilation.SourceModule.GlobalNamespace.Accept(compiler) compiler.WaitForWorkers() @@ -305,7 +305,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic variableSlotAllocatorOpt:=Nothing, debugDocumentProvider:=Nothing, diagnostics:=diagnostics, - generateDebugInfo:=False) + emittingPdb:=False) moduleBeingBuilt.SetMethodBody(scriptEntryPoint, emittedBody) moduleBeingBuilt.AddSynthesizedDefinition(compilation.ScriptClass, scriptEntryPoint) @@ -855,7 +855,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic variableSlotAllocatorOpt:=Nothing, debugDocumentProvider:=Nothing, diagnostics:=diagnosticsThisMethod, - generateDebugInfo:=False) + emittingPdb:=False) _diagnostics.AddRange(diagnosticsThisMethod) diagnosticsThisMethod.Free() @@ -919,7 +919,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic lazyVariableSlotAllocator, debugDocumentProvider:=Nothing, diagnostics:=diagnosticsThisMethod, - generateDebugInfo:=False) + emittingPdb:=False) End If lambdaDebugInfoBuilder.Free() @@ -968,7 +968,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic variableSlotAllocatorOpt:=Nothing, debugDocumentProvider:=_debugDocumentProvider, diagnostics:=diagnosticsThisMethod, - generateDebugInfo:=_generateDebugInfo AndAlso method.GenerateDebugInfo) + emittingPdb:=_emittingPdb) _diagnostics.AddRange(diagnosticsThisMethod) diagnosticsThisMethod.Free() @@ -1451,7 +1451,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic lazyVariableSlotAllocator, _debugDocumentProvider, diagnostics, - generateDebugInfo:=_generateDebugInfo AndAlso method.GenerateDebugInfo) + emittingPdb:=_emittingPdb) If diagnostics IsNot diagsForCurrentMethod Then DirectCast(method.AssociatedSymbol, SynthesizedMyGroupCollectionPropertySymbol).RelocateDiagnostics(diagnostics, diagsForCurrentMethod) @@ -1474,10 +1474,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic variableSlotAllocatorOpt As VariableSlotAllocator, debugDocumentProvider As DebugDocumentProvider, diagnostics As DiagnosticBag, - generateDebugInfo As Boolean) As MethodBody + emittingPdb As Boolean) As MethodBody Dim compilation = moduleBuilder.Compilation - Dim localSlotManager = New localSlotManager(variableSlotAllocatorOpt) + Dim localSlotManager = New LocalSlotManager(variableSlotAllocatorOpt) Dim optimizations = compilation.Options.OptimizationLevel If method.IsEmbedded Then @@ -1490,7 +1490,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Debug.Assert(Not diagnostics.HasAnyErrors) Dim asyncDebugInfo As Cci.AsyncMethodBodyDebugInfo = Nothing - Dim codeGen = New codeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnostics, optimizations, generateDebugInfo) + Dim codeGen = New CodeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnostics, optimizations, emittingPdb) ' We need to save additional debugging information for MoveNext of an async state machine. Dim stateMachineMethod = TryCast(method, SynthesizedStateMachineMethod) @@ -1523,6 +1523,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic codeGen.Generate() End If + ' Translate the imports even if we are not writing PDBs. The translation has an impact on generated metadata + ' and we don't want to emit different metadata depending on whether or we emit with PDB stream. + ' TODO (https://github.com/dotnet/roslyn/issues/2846): This will need to change for member initializers in partial class. + Dim importScopeOpt = If(method.Syntax IsNot Nothing AndAlso method.Syntax.SyntaxTree IsNot VisualBasicSyntaxTree.DummySyntaxTree.Dummy, + moduleBuilder.SourceModule.GetSourceFile(method.Syntax.SyntaxTree).Translate(moduleBuilder, diagnostics), + Nothing) + If diagnostics.HasAnyErrors() Then Return Nothing End If @@ -1539,29 +1546,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic GetStateMachineSlotDebugInfo(moduleBuilder.GetSynthesizedFields(stateMachineTypeOpt), stateMachineHoistedLocalSlots, stateMachineAwaiterSlots) End If - Dim namespaceScopes = If(generateDebugInfo, moduleBuilder.SourceModule.GetSourceFile(method.Syntax.SyntaxTree), Nothing) - - ' edgeInclusive must be true as that is what VB EE expects. - - ' - 'HRESULT() - 'PdbUtil::IsScopeInOffset( - ' _In_ ISymUnmanagedScope* pScope, - ' _In_ DWORD offset, - ' _Out_ bool* inOffset) - '{ - ' VerifyInPtr(pScope); - ' VerifyOutPtr(inOffset); - - ' HRESULT hr; - ' ULONG32 start, end; - - ' IfFailGo( pScope->GetStartOffset(&start) ); - ' IfFailGo( pScope->GetEndOffset(&end) ); - ' *inOffset = (end >= offset) && (offset >= start); <==== HERE - 'Error: - ' return hr; - '} Dim localScopes = builder.GetAllScopes() Return New MethodBody(builder.RealizedIL, @@ -1574,7 +1558,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic builder.RealizedExceptionHandlers, localScopes, hasDynamicLocalVariables:=False, - importScopeOpt:=namespaceScopes, + importScopeOpt:=importScopeOpt, lambdaDebugInfo:=lambdaDebugInfo, closureDebugInfo:=closureDebugInfo, stateMachineTypeNameOpt:=stateMachineTypeOpt?.Name, ' TODO: remove or update AddedOrChangedMethodInfo diff --git a/src/Compilers/VisualBasic/Portable/Compilation/NamespaceScopeBuilder.vb b/src/Compilers/VisualBasic/Portable/Compilation/NamespaceScopeBuilder.vb index daeace009d75551c12fed23307d0f40de279ff00..4e06ca8c82dd2b962a75ac5f2166b8dc18f04e34 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/NamespaceScopeBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/NamespaceScopeBuilder.vb @@ -11,10 +11,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Sub Public Shared Function BuildNamespaceScope( - context As EmitContext, + moduleBuilder As Emit.PEModuleBuilder, xmlNamespaces As Dictionary(Of String, XmlNamespaceAndImportsClausePosition), aliasImports As IEnumerable(Of AliasAndImportsClausePosition), - memberImports As ImmutableArray(Of NamespaceOrTypeAndImportsClausePosition) + memberImports As ImmutableArray(Of NamespaceOrTypeAndImportsClausePosition), + diagnostics As DiagnosticBag ) As ImmutableArray(Of Cci.UsedNamespaceOrType) Dim scopeBuilder = ArrayBuilder(Of Cci.UsedNamespaceOrType).GetInstance @@ -31,8 +32,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim target = aliasImport.Alias.Target If target.IsNamespace Then scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateNamespace(DirectCast(target, NamespaceSymbol), aliasOpt:=aliasImport.Alias.Name)) - Else - Dim typeRef = GetTypeReference(context, DirectCast(target, NamedTypeSymbol)) + ElseIf Not target.ContainingAssembly.IsLinked + ' We skip alias imports of embedded types to avoid breaking existing code that + ' imports types that can't be embedded but doesn't use them anywhere else in the code. + Dim typeRef = GetTypeReference(DirectCast(target, NamedTypeSymbol), moduleBuilder, diagnostics) scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateType(typeRef, aliasOpt:=aliasImport.Alias.Name)) End If Next @@ -44,8 +47,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim target = import.NamespaceOrType If target.IsNamespace Then scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateNamespace(DirectCast(target, NamespaceSymbol))) - Else - Dim typeRef = GetTypeReference(context, DirectCast(target, NamedTypeSymbol)) + ElseIf Not target.ContainingAssembly.IsLinked + ' We skip imports of embedded types to avoid breaking existing code that + ' imports types that can't be embedded but doesn't use them anywhere else in the code. + Dim typeRef = GetTypeReference(DirectCast(target, NamedTypeSymbol), moduleBuilder, diagnostics) scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateType(typeRef)) End If Next @@ -54,8 +59,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return scopeBuilder.ToImmutableAndFree() End Function - Private Shared Function GetTypeReference(context As EmitContext, type As TypeSymbol) As Cci.ITypeReference - Return context.ModuleBuilder.Translate(type, context.SyntaxNodeOpt, context.Diagnostics) + Private Shared Function GetTypeReference(type As TypeSymbol, moduleBuilder As CommonPEModuleBuilder, diagnostics As DiagnosticBag) As Cci.ITypeReference + Return moduleBuilder.Translate(type, Nothing, diagnostics) End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb index 652b06be24e8572f4361a0c00048e57e5198a256..be29c0d75a4ead458f154bc08eeb2676c2ad03ef 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb @@ -2207,7 +2207,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic moduleBuilder As CommonPEModuleBuilder, win32Resources As Stream, xmlDocStream As Stream, - generateDebugInfo As Boolean, + emittingPdb As Boolean, diagnostics As DiagnosticBag, filterOpt As Predicate(Of ISymbol), cancellationToken As CancellationToken) As Boolean @@ -2220,6 +2220,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Me.EmbeddedSymbolManager.MarkAllDeferredSymbolsAsReferenced(Me) + moduleBeingBuilt.TranslateImports(diagnostics) + If moduleBeingBuilt.EmitOptions.EmitMetadataOnly Then If hasDeclarationErrors Then Return False @@ -2233,12 +2235,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic SynthesizedMetadataCompiler.ProcessSynthesizedMembers(Me, moduleBeingBuilt, cancellationToken) Else - ' start generating PDB checksums if we need to emit PDBs - If generateDebugInfo AndAlso moduleBeingBuilt IsNot Nothing Then - If Not StartSourceChecksumCalculation(moduleBeingBuilt, diagnostics) Then - Return False - End If + If emittingPdb AndAlso Not StartSourceChecksumCalculation(moduleBeingBuilt, diagnostics) Then + Return False End If ' Perform initial bind of method bodies in spite of earlier errors. This is the same @@ -2250,13 +2249,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic MethodCompiler.CompileMethodBodies( Me, moduleBeingBuilt, - generateDebugInfo, + emittingPdb, hasDeclarationErrors, filterOpt, methodBodyDiagnosticBag, cancellationToken) - Dim assemblyName = FileNameUtilities.ChangeExtension(moduleBeingBuilt.EmitOptions.OutputNameOverride, extension:=Nothing) DocumentationCommentCompiler.WriteDocumentationCommentXml(Me, assemblyName, xmlDocStream, methodBodyDiagnosticBag, cancellationToken) diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb index e27cd190bf8b3bce8b9aeb2a4f687bde8d9ffb54..3c8338928c75e4a92a604ba0e1aecd118fb78d23 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb @@ -63,7 +63,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit If compilation.Compile(moduleBeingBuilt, win32Resources:=Nothing, xmlDocStream:=Nothing, - generateDebugInfo:=True, + emittingPdb:=True, diagnostics:=diagnostics, filterOpt:=AddressOf changes.RequiresCompilation, cancellationToken:=cancellationToken) Then diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb index 4d93c36fd07f14c012ec4029ff8365e117530c03..8b1e99569e4f9f5c434dccfd4f0d454b5c364421 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb @@ -22,7 +22,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Private ReadOnly _metadataName As String Private _lazyExportedTypes As ImmutableArray(Of TypeExport(Of NamedTypeSymbol)) - Private _lazyImports As ImmutableArray(Of Cci.UsedNamespaceOrType) + Private _lazyTranslatedImports As ImmutableArray(Of Cci.UsedNamespaceOrType) Private _lazyDefaultNamespace As String ' These fields will only be set when running tests. They allow realized IL for a given method to be looked up by method display name. @@ -99,15 +99,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Get End Property - Protected NotOverridable Overrides Function GetImports(context As EmitContext) As ImmutableArray(Of Cci.UsedNamespaceOrType) - If _lazyImports.IsDefault Then + Protected NotOverridable Overrides Function GetImports() As ImmutableArray(Of Cci.UsedNamespaceOrType) + ' Imports should have been translated in code gen phase. + Debug.Assert(Not _lazyTranslatedImports.IsDefault) + Return _lazyTranslatedImports + End Function + + Public Sub TranslateImports(diagnostics As DiagnosticBag) + If _lazyTranslatedImports.IsDefault Then ImmutableInterlocked.InterlockedInitialize( - _lazyImports, - NamespaceScopeBuilder.BuildNamespaceScope(context, SourceModule.XmlNamespaces, SourceModule.AliasImports, SourceModule.MemberImports)) + _lazyTranslatedImports, + NamespaceScopeBuilder.BuildNamespaceScope(Me, SourceModule.XmlNamespaces, SourceModule.AliasImports, SourceModule.MemberImports, diagnostics)) End If - - Return _lazyImports - End Function + End Sub Protected NotOverridable Overrides ReadOnly Property DefaultNamespace As String Get diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFile.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFile.vb index 36bacbeeea73bee7ffc6106e4c38f8157c157db0..02bab60cf022fc6d439fe80ab2ba647aeffcde95 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFile.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFile.vb @@ -430,19 +430,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Public Function GetUsedNamespaces(context As EmitContext) As ImmutableArray(Of Cci.UsedNamespaceOrType) Implements Cci.IImportScope.GetUsedNamespaces + Public Function Translate(moduleBuilder As Emit.PEModuleBuilder, diagnostics As DiagnosticBag) As Cci.IImportScope If _lazyTranslatedImports.IsDefault Then - ImmutableInterlocked.InterlockedInitialize(_lazyTranslatedImports, TranslateImports(context)) + ImmutableInterlocked.InterlockedInitialize(_lazyTranslatedImports, TranslateImports(moduleBuilder, diagnostics)) End If + Return Me + End Function + + Public Function GetUsedNamespaces() As ImmutableArray(Of Cci.UsedNamespaceOrType) Implements Cci.IImportScope.GetUsedNamespaces + ' The imports should have been translated during code gen. + Debug.Assert(Not _lazyTranslatedImports.IsDefault) Return _lazyTranslatedImports End Function - Private Function TranslateImports(context As EmitContext) As ImmutableArray(Of Cci.UsedNamespaceOrType) - Return NamespaceScopeBuilder.BuildNamespaceScope(context, + Private Function TranslateImports(moduleBuilder As Emit.PEModuleBuilder, diagnostics As DiagnosticBag) As ImmutableArray(Of Cci.UsedNamespaceOrType) + Return NamespaceScopeBuilder.BuildNamespaceScope(moduleBuilder, XmlNamespaces, If(AliasImports IsNot Nothing, AliasImports.Values, Nothing), - MemberImports) + MemberImports, + diagnostics) End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBNamespaceScopes.vb b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBNamespaceScopes.vb index 8b99b29d1aacc9b274ec411e06fc1f31c652bb06..8a2b24c3b34cc6d1450b5eda35ee18b643901a3a 100644 --- a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBNamespaceScopes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBNamespaceScopes.vb @@ -1,5 +1,6 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +Imports System.IO Imports Microsoft.CodeAnalysis.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.PDB @@ -354,6 +355,207 @@ End Namespace ) End Sub + + Public Sub EmittingPdbVsNot() + Dim source = + + +Imports System +Imports X = System.IO.FileStream + +Class C + Dim x As Integer = 1 + Shared y As Integer = 1 + + Sub New() + Console.WriteLine() + End Sub +End Class + + + + Dim c = CreateCompilationWithMscorlib(source, options:=TestOptions.ReleaseDll) + + Dim peStream1 = New MemoryStream() + Dim peStream2 = New MemoryStream() + Dim pdbStream = New MemoryStream() + + Dim emitResult1 = c.Emit(peStream:=peStream1, pdbStream:=pdbStream) + Dim emitResult2 = c.Emit(peStream:=peStream2) + + SharedCompilationUtils.VerifyMetadataEqualModuloMvid(peStream1, peStream2) + End Sub + + + Public Sub ImportedNoPiaTypes() + Dim sourceLib = + + + + + +Namespace N + Public Enum E + Value1 = 1 + End Enum + + Public Structure S1 + Public A1 As Integer + Public A2 As Integer + End Structure + + Public Structure S2 + Public Const Value2 As Integer = 2 + End Structure + + Public Structure SBad + Public A3 As Integer + Public Const Value3 As Integer = 3 + End Structure + + + Public Interface I + Sub F() + End Interface + + Public Interface IBad + Sub F() + End Interface +End Namespace +]]> + + + + Dim source = + + +Imports System +Imports N.E +Imports N.SBad +Imports Z1 = N.S1 +Imports Z2 = N.S2 +Imports ZBad = N.SBad +Imports NI = N.I +Imports NIBad = N.IBad + +Class C + Dim i As NI + + Sub M + Console.WriteLine(Value1) + Console.WriteLine(Z2.Value2) + Console.WriteLine(New Z1()) + End Sub +End Class + + + + Dim globalImports = GlobalImport.Parse( + "GlobalNIBad = N.IBad", + "GlobalZ1 = N.S1", + "GlobalZ2 = N.S2", + "GlobalZBad = N.SBad", + "GlobalNI = N.I") + + Dim libRef = CreateCompilationWithMscorlib(sourceLib).EmitToImageReference(embedInteropTypes:=True) + Dim compilation = CreateCompilationWithMscorlibAndReferences(source, {libRef}, options:=TestOptions.DebugDll.WithGlobalImports(globalImports)) + Dim v = CompileAndVerify(compilation) + + v.Diagnostics.Verify( + Diagnostic(ERRID.HDN_UnusedImportStatement, "Imports N.SBad"), + Diagnostic(ERRID.HDN_UnusedImportStatement, "Imports ZBad = N.SBad"), + Diagnostic(ERRID.HDN_UnusedImportStatement, "Imports NIBad = N.IBad")) + + ' Imports of embedded types are currently ommitted: + v.VerifyPdb("C.M", + + + + + + + + + + + + + + + + + +) + End Sub + + + Public Sub ImportedTypeWithUnknownBase() + Dim sourceLib1 = + + +Namespace N + Public Class A + End Class +End Namespace + + + + Dim sourceLib2 = + + +Namespace N + Public Class B + Inherits A + End Class +End Namespace + + + + Dim source = + + +Imports System +Imports X = N.B + +Class C + Sub M() + Console.WriteLine() + End Sub +End Class + + + + Dim libRef1 = CreateCompilationWithMscorlib(sourceLib1).EmitToImageReference() + Dim libRef2 = CreateCompilationWithMscorlibAndReferences(sourceLib2, {libRef1}).EmitToImageReference() + Dim compilation = CreateCompilationWithMscorlibAndReferences(source, {libRef2}) + + Dim v = CompileAndVerify(compilation, emitters:=TestEmitters.CCI) + + v.Diagnostics.Verify( + Diagnostic(ERRID.HDN_UnusedImportStatement, "Imports X = N.B")) + + v.VerifyPdb("C.M", + + + + + + + + + + + + + + +) + End Sub End Class End Namespace diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs index b9d0f92aa1faadc6f5076fb697596d6e1e9c7ec3..ac51f15420a4dc9020faa5287580dbaa29f2a0b9 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs @@ -157,7 +157,7 @@ internal sealed class CompilationContext module, win32Resources: null, xmlDocStream: null, - generateDebugInfo: false, + emittingPdb: false, diagnostics: diagnostics, filterOpt: null, cancellationToken: CancellationToken.None); @@ -220,7 +220,7 @@ internal sealed class CompilationContext module, win32Resources: null, xmlDocStream: null, - generateDebugInfo: false, + emittingPdb: false, diagnostics: diagnostics, filterOpt: null, cancellationToken: CancellationToken.None); @@ -405,7 +405,7 @@ private static string GetNextMethodName(ArrayBuilder builder) module, win32Resources: null, xmlDocStream: null, - generateDebugInfo: false, + emittingPdb: false, diagnostics: diagnostics, filterOpt: null, cancellationToken: CancellationToken.None); diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb index fc75df565e5cc2713838ffe03d91059ebc1ea976..1bd4a51843970b984b41f5f3af46612ece650c07 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb @@ -154,7 +154,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator moduleBuilder, win32Resources:=Nothing, xmlDocStream:=Nothing, - generateDebugInfo:=False, + emittingPdb:=False, diagnostics:=diagnostics, filterOpt:=Nothing, cancellationToken:=CancellationToken.None) @@ -250,15 +250,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator ' "Me" for non-shared methods that are not display class methods ' or display class methods where the display class contains "$VB$Me". If Not m.IsShared AndAlso (Not m.ContainingType.IsClosureOrStateMachineType() OrElse _displayClassVariables.ContainsKey(GeneratedNames.MakeStateMachineCapturedMeName())) Then - Dim methodName = GetNextMethodName(methodBuilder) - Dim method = Me.GetMeMethod(container, methodName) - localBuilder.Add(New VisualBasicLocalAndMethod("Me", "Me", methodName, DkmClrCompilationResultFlags.None)) ' NOTE: writable in Dev11. - methodBuilder.Add(method) - End If + Dim methodName = GetNextMethodName(methodBuilder) + Dim method = Me.GetMeMethod(container, methodName) + localBuilder.Add(New VisualBasicLocalAndMethod("Me", "Me", methodName, DkmClrCompilationResultFlags.None)) ' NOTE: writable in Dev11. + methodBuilder.Add(method) End If + End If - ' Hoisted method parameters (represented as locals in the EE). - If Not _hoistedParameterNames.IsEmpty Then + ' Hoisted method parameters (represented as locals in the EE). + If Not _hoistedParameterNames.IsEmpty Then Dim localIndex As Integer = 0 For Each local In _localsForBinding @@ -327,7 +327,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator moduleBuilder, win32Resources:=Nothing, xmlDocStream:=Nothing, - generateDebugInfo:=False, + emittingPdb:=False, diagnostics:=diagnostics, filterOpt:=Nothing, cancellationToken:=CancellationToken.None) diff --git a/src/Scripting/Core/Emit/CommonCompilationExtensions.cs b/src/Scripting/Core/Emit/CommonCompilationExtensions.cs index 20f03163ed3be8146589be53d72bbd7cf867dffa..cefece669aeb11508ac8934c7ded81b263873a60 100644 --- a/src/Scripting/Core/Emit/CommonCompilationExtensions.cs +++ b/src/Scripting/Core/Emit/CommonCompilationExtensions.cs @@ -84,7 +84,7 @@ internal static class CommonCompilationExtensions moduleBeingBuilt, win32Resources: null, xmlDocStream: null, - generateDebugInfo: false, + emittingPdb: false, diagnostics: diagnostics, filterOpt: null, cancellationToken: cancellationToken)) diff --git a/src/Test/Utilities/AssertEx.cs b/src/Test/Utilities/AssertEx.cs index 9b76fc9a8494c89e6c2ed005bd48a3c0ddf9f495..f1c92177c94003365b970663a8d87981a26910f7 100644 --- a/src/Test/Utilities/AssertEx.cs +++ b/src/Test/Utilities/AssertEx.cs @@ -381,6 +381,7 @@ public static void ThrowsArgumentException(string parameterName, Action del) throw new Exception("No exception was thrown."); } + // compares against a baseline public static void AssertEqualToleratingWhitespaceDifferences( string expected, string actual, @@ -397,6 +398,32 @@ public static void ThrowsArgumentException(string parameterName, Action del) } } + // compares two results (no baseline) + public static void AssertResultsEqual(string result1, string result2) + { + if (result1 != result2) + { + string message; + + if (DiffToolAvailable) + { + string file1 = Path.GetTempFileName(); + File.WriteAllText(file1, result1); + + string file2 = Path.GetTempFileName(); + File.WriteAllText(file2, result2); + + message = MakeDiffToolLink(file1, file2); + } + else + { + message = GetAssertMessage(result1, result2); + } + + Assert.True(false, message); + } + } + public static void AssertContainsToleratingWhitespaceDifferences(string expectedSubString, string actualString) { expectedSubString = NormalizeWhitespace(expectedSubString); @@ -481,7 +508,7 @@ public static string GetAssertMessage(IEnumerable expected, IEnumerable message.AppendLine(DiffUtil.DiffReport(expected, actual, comparer, itemInspector, itemSeparator)); string link; - if (TryGenerateExpectedSourceFielAndGetDiffLink(actualString, expected.Count(), expectedValueSourcePath, expectedValueSourceLine, out link)) + if (TryGenerateExpectedSourceFileAndGetDiffLink(actualString, expected.Count(), expectedValueSourcePath, expectedValueSourceLine, out link)) { message.AppendLine(link); } @@ -489,10 +516,10 @@ public static string GetAssertMessage(IEnumerable expected, IEnumerable return message.ToString(); } - internal static bool TryGenerateExpectedSourceFielAndGetDiffLink(string actualString, int expectedLineCount, string expectedValueSourcePath, int expectedValueSourceLine, out string link) + internal static bool TryGenerateExpectedSourceFileAndGetDiffLink(string actualString, int expectedLineCount, string expectedValueSourcePath, int expectedValueSourceLine, out string link) { // add a link to a .cmd file that opens a diff tool: - if (!string.IsNullOrEmpty(s_diffToolPath) && expectedValueSourcePath != null && expectedValueSourceLine != 0) + if (DiffToolAvailable && expectedValueSourcePath != null && expectedValueSourceLine != 0) { var actualFile = Path.GetTempFileName(); var testFileLines = File.ReadAllLines(expectedValueSourcePath); @@ -501,10 +528,7 @@ internal static bool TryGenerateExpectedSourceFielAndGetDiffLink(string actualSt File.AppendAllText(actualFile, actualString); File.AppendAllLines(actualFile, testFileLines.Skip(expectedValueSourceLine + expectedLineCount)); - var compareCmd = Path.GetTempFileName() + ".cmd"; - File.WriteAllText(compareCmd, string.Format("\"{0}\" \"{1}\" \"{2}\"", s_diffToolPath, actualFile, expectedValueSourcePath)); - - link = "file://" + compareCmd; + link = MakeDiffToolLink(actualFile, expectedValueSourcePath); s_diffLinks.Value.Add(Tuple.Create(expectedValueSourcePath, expectedValueSourceLine, link)); return true; @@ -514,6 +538,16 @@ internal static bool TryGenerateExpectedSourceFielAndGetDiffLink(string actualSt return false; } + internal static bool DiffToolAvailable => !string.IsNullOrEmpty(s_diffToolPath); + + internal static string MakeDiffToolLink(string actualFilePath, string expectedFilePath) + { + var compareCmd = Path.GetTempFileName() + ".cmd"; + File.WriteAllText(compareCmd, string.Format("\"{0}\" \"{1}\" \"{2}\"", s_diffToolPath, actualFilePath, expectedFilePath)); + + return "file://" + compareCmd; + } + private static readonly Lazy>> s_diffLinks = new Lazy>>(() => { AppDomain.CurrentDomain.DomainUnload += (_, __) => diff --git a/src/Test/Utilities/AssertXml.cs b/src/Test/Utilities/AssertXml.cs index b5c5c6126651913e004fd114266fa57138c1514d..38485bd5c7a4798ffbd47f80072031ffb13f11bf 100644 --- a/src/Test/Utilities/AssertXml.cs +++ b/src/Test/Utilities/AssertXml.cs @@ -84,7 +84,7 @@ private static string GetXmlString(XElement node, bool expectedIsXmlLiteral) string expectedString = expectedIsXmlLiteral ? expected.Replace(" />\r\n", "/>\r\n") : string.Format("@\"{0}\"", expected.Replace("\"", "\"\"")); string link; - if (AssertEx.TryGenerateExpectedSourceFielAndGetDiffLink(actualString, expectedString.Count(c => c == '\n') + 1, expectedValueSourcePath, expectedValueSourceLine, out link)) + if (AssertEx.TryGenerateExpectedSourceFileAndGetDiffLink(actualString, expectedString.Count(c => c == '\n') + 1, expectedValueSourcePath, expectedValueSourceLine, out link)) { assertText.AppendLine(link); } diff --git a/src/Test/Utilities/CompilationExtensions.cs b/src/Test/Utilities/CompilationExtensions.cs index 5ed9d54d4dd872c7f8485bd0ab0602802fa1e382..57573613628f801225435da8b29e9216dcc83d72 100644 --- a/src/Test/Utilities/CompilationExtensions.cs +++ b/src/Test/Utilities/CompilationExtensions.cs @@ -38,7 +38,7 @@ public static class CompilationExtensions getHostDiagnostics: null, cancellationToken: default(CancellationToken)); - Assert.True(emitResult.Success, "Diagnostics:\r\n" + string.Join("\r\n, ", emitResult.Diagnostics.Select(d => d.ToString()))); + Assert.True(emitResult.Success, "Diagnostics:\r\n" + string.Join("\r\n", emitResult.Diagnostics.Select(d => d.ToString()))); if (expectedWarnings != null) { diff --git a/src/Test/Utilities/SharedCompilationUtils.cs b/src/Test/Utilities/SharedCompilationUtils.cs index 80bbe45f00bbf183a1ebcebfe286756b87fb66c7..3c1aa0583ff72d00611e027e7dd0b8f1e5cbcc1c 100644 --- a/src/Test/Utilities/SharedCompilationUtils.cs +++ b/src/Test/Utilities/SharedCompilationUtils.cs @@ -8,12 +8,14 @@ using System.Linq; using System.Reflection; using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; using System.Runtime.CompilerServices; using System.Text; using System.Xml.Linq; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit; +using PDB::Roslyn.Test.MetadataUtilities; using PDB::Roslyn.Test.PdbUtilities; using Roslyn.Test.Utilities; using Xunit; @@ -54,7 +56,7 @@ internal static CompilationTestData.MethodData GetMethodData(this CompilationTes return methodData; } - + internal static void VerifyIL( this CompilationTestData.MethodData method, string expectedIL, @@ -194,6 +196,39 @@ public static void ValidateDebugDirectory(Stream peStream, string pdbPath) Assert.Equal(0, reader.ReadByte()); } + public static void VerifyMetadataEqualModuloMvid(Stream peStream1, Stream peStream2) + { + peStream1.Position = 0; + peStream2.Position = 0; + + var peReader1 = new PEReader(peStream1); + var peReader2 = new PEReader(peStream2); + + var md1 = peReader1.GetMetadata().GetContent(); + var md2 = peReader2.GetMetadata().GetContent(); + + var mdReader1 = peReader1.GetMetadataReader(); + var mdReader2 = peReader2.GetMetadataReader(); + + var mvidIndex1 = mdReader1.GetModuleDefinition().Mvid; + var mvidIndex2 = mdReader2.GetModuleDefinition().Mvid; + + var mvidOffset1 = mdReader1.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex1) - 1); + var mvidOffset2 = mdReader2.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex2) - 1); + + if (!md1.RemoveRange(mvidOffset1, 16).SequenceEqual(md1.RemoveRange(mvidOffset2, 16))) + { + var mdw1 = new StringWriter(); + var mdw2 = new StringWriter(); + new MetadataVisualizer(mdReader1, mdw1).Visualize(); + new MetadataVisualizer(mdReader2, mdw2).Visualize(); + mdw1.Flush(); + mdw2.Flush(); + + AssertEx.AssertResultsEqual(mdw1.ToString(), mdw2.ToString()); + } + } + internal static string GetMethodIL(this CompilationTestData.MethodData method) { return ILBuilderVisualizer.ILBuilderToString(method.ILBuilder);