提交 2e2e8ee8 编写于 作者: T TomasMatousek

PDB import scopes refactoring.

Changes:

To enable producing both Portable and native PDB formats we need to move the format specific imports encoding down to the PdbWriter. Instead of constructing NamespaceScope objects containing strings that encode usings/imports the C# and VB constructs that hold on to bound imports (ImportChain in C#, SourceFile in VB) now implement a new CCI-level interface IImportScope that provides an array of UsedTypeOrNamespace for each import scope. UsedTypeOrNamespace struct now doesn’t contain strings but symbols that represent the entities that re referenced in usings/Imports. IImportScope only represents imports on file level and below. Project level imports are exposed via new API on Cci.IModule (GetImports method). To represent a namespace a new CCI-level interface INamespace is introduced and implemented by NamespaceSymbol. In future we could replace usage of qualified namespace strings with this interface in other places in the compiler-CCI interface, but to minimize the impact I have not done so in this change.

Background:

Currently C# and VB compilers build a list of namespace scopes in NamespaceScopeBuilder that are then passed via MethodBody to the MetadataWriter, which then passes them to the PdbWriter. The NamespaceScopeBuilder encodes various forms of usings, extern aliases and imports in specially formatted strings that the EE understands how to decode. It constructs a list of all usings/imports/extern-aliases/etc. for each method. The PdbWriter then writes these string lists to PDB namespace scope records and implements a forwarding optimization – within a set of methods that have the same usings we designate one that we associate the strings with and the others forward to it. The forwarding is implemented differently by VB and C#. VB also defines some additional namespace scope records for default namespace, NoPia assembly names and method namespace.

The new portable PDB format has a different, simpler and more efficient representation of import scopes with the same encoding for C# and VB. Import scopes are first class entities that have parent pointer and thus form a tree. The structure of the tree is language specific. The root of the tree represents a project/compilation-wide import scope. For C# this scope contains assembly reference aliases (/r:Alias=Reference.dll). For VB this scope declares project level imports. The import scope tree for VB is 2 level deep – file level and project level. C# may define deeper trees as namespaces may define their own usings.
Also some information that Dev12 encodes in PDB namespace scopes is not used anymore by our new EEs (such as VB NoPia names, VB method namespace). These are not emitted to Portable PDB since the old EEs won’t be able to consume the new format anyways.
 (changeset 1410225)
上级 2df0ed5c
......@@ -265,11 +265,11 @@ public virtual ConsList<LocalSymbol> ImplicitlyTypedLocalsBeingBound
/// <summary>
/// The Imports for all containing namespace declarations (innermost-to-outermost, including global).
/// </summary>
internal virtual ConsList<Imports> ImportsList
internal virtual ImportChain ImportChain
{
get
{
return _next.ImportsList;
return _next.ImportChain;
}
}
......@@ -285,7 +285,7 @@ internal NamedTypeSymbol ContainingType
return (object)member == null
? null
: member.Kind == SymbolKind.NamedType
? (NamedTypeSymbol)member
? (NamedTypeSymbol)member
: member.ContainingType;
}
}
......
......@@ -4380,9 +4380,9 @@ private BoundExpression BindLeftOfPotentialColorColorMemberAccess(ExpressionSynt
private bool IsUsingAliasInScope(string name)
{
var isSemanticModel = this.IsSemanticModelBinder;
foreach (var importsList in this.ImportsList)
for (var chain = this.ImportChain; chain != null; chain = chain.ParentOpt)
{
if (importsList.IsUsingAlias(name, isSemanticModel))
if (chain.Imports.IsUsingAlias(name, isSemanticModel))
{
return true;
}
......
......@@ -16,7 +16,7 @@ internal struct ProcessedFieldInitializers
internal ImmutableArray<BoundInitializer> BoundInitializers { get; set; }
internal BoundStatementList LoweredInitializers { get; set; }
internal bool HasErrors { get; set; }
internal ConsList<Imports> FirstDebugImports { get; set; }
internal ImportChain FirstImportChain { get; set; }
}
internal static void BindFieldInitializers(
......@@ -30,13 +30,13 @@ internal struct ProcessedFieldInitializers
DiagnosticBag diagsForInstanceInitializers = DiagnosticBag.GetInstance();
try
{
ConsList<Imports> firstDebugImports;
ImportChain firstImportChain;
processedInitializers.BoundInitializers = BindFieldInitializers(typeSymbol, scriptCtor, fieldInitializers,
diagsForInstanceInitializers, generateDebugInfo, out firstDebugImports);
diagsForInstanceInitializers, generateDebugInfo, out firstImportChain);
processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors();
processedInitializers.FirstDebugImports = firstDebugImports;
processedInitializers.FirstImportChain = firstImportChain;
}
finally
{
......@@ -51,11 +51,11 @@ internal struct ProcessedFieldInitializers
ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> initializers,
DiagnosticBag diagnostics,
bool generateDebugInfo,
out ConsList<Imports> firstDebugImports)
out ImportChain firstImportChain)
{
if (initializers.IsEmpty)
{
firstDebugImports = null;
firstImportChain = null;
return ImmutableArray<BoundInitializer>.Empty;
}
......@@ -64,11 +64,11 @@ internal struct ProcessedFieldInitializers
if ((object)scriptCtor == null)
{
BindRegularCSharpFieldInitializers(compilation, initializers, boundInitializers, diagnostics, generateDebugInfo, out firstDebugImports);
BindRegularCSharpFieldInitializers(compilation, initializers, boundInitializers, diagnostics, generateDebugInfo, out firstImportChain);
}
else
{
BindScriptFieldInitializers(compilation, scriptCtor, initializers, boundInitializers, diagnostics, generateDebugInfo, out firstDebugImports);
BindScriptFieldInitializers(compilation, scriptCtor, initializers, boundInitializers, diagnostics, generateDebugInfo, out firstImportChain);
}
return boundInitializers.ToImmutableAndFree();
......@@ -84,7 +84,7 @@ internal struct ProcessedFieldInitializers
ArrayBuilder<BoundInitializer> boundInitializers,
DiagnosticBag diagnostics,
bool generateDebugInfo,
out ConsList<Imports> firstDebugImports)
out ImportChain firstDebugImports)
{
firstDebugImports = null;
......@@ -120,7 +120,7 @@ internal struct ProcessedFieldInitializers
if (generateDebugInfo && firstDebugImports == null)
{
firstDebugImports = parentBinder.ImportsList;
firstDebugImports = parentBinder.ImportChain;
}
parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol);
......@@ -138,7 +138,7 @@ internal struct ProcessedFieldInitializers
/// </summary>
private static void BindScriptFieldInitializers(CSharpCompilation compilation, MethodSymbol scriptCtor,
ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> initializers, ArrayBuilder<BoundInitializer> boundInitializers, DiagnosticBag diagnostics,
bool generateDebugInfo, out ConsList<Imports> firstDebugImports)
bool generateDebugInfo, out ImportChain firstDebugImports)
{
Debug.Assert((object)scriptCtor != null);
......@@ -179,7 +179,7 @@ internal struct ProcessedFieldInitializers
if (generateDebugInfo && firstDebugImports == null)
{
firstDebugImports = scriptClassBinder.ImportsList;
firstDebugImports = scriptClassBinder.ImportChain;
}
Binder parentBinder = new ExecutableCodeBinder((CSharpSyntaxNode)syntaxRef.SyntaxTree.GetRoot(), scriptCtor, scriptClassBinder);
......
......@@ -27,11 +27,11 @@ public override ConsList<LocalSymbol> ImplicitlyTypedLocalsBeingBound
}
}
internal override ConsList<Imports> ImportsList
internal override ImportChain ImportChain
{
get
{
return ConsList<Imports>.Empty;
return null;
}
}
......
// 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.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Emit;
namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed class ImportChain : Cci.IImportScope
{
public readonly Imports Imports;
public readonly ImportChain ParentOpt;
private ImmutableArray<Cci.UsedNamespaceOrType> _lazyTranslatedImports;
public ImportChain(Imports imports, ImportChain parentOpt)
{
Debug.Assert(imports != null);
Imports = imports;
ParentOpt = parentOpt;
}
ImmutableArray<Cci.UsedNamespaceOrType> Cci.IImportScope.GetUsedNamespaces(EmitContext context)
{
if (_lazyTranslatedImports.IsDefault)
{
ImmutableInterlocked.InterlockedInitialize(ref _lazyTranslatedImports, TranslateImports(context));
}
return _lazyTranslatedImports;
}
private ImmutableArray<Cci.UsedNamespaceOrType> TranslateImports(EmitContext context)
{
var usedNamespaces = ArrayBuilder<Cci.UsedNamespaceOrType>.GetInstance();
// NOTE: order based on dev12: extern aliases, then usings, then aliases namespaces and types
ImmutableArray<AliasAndExternAliasDirective> externAliases = Imports.ExternAliases;
if (!externAliases.IsDefault)
{
foreach (var alias in externAliases)
{
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateExternAlias(alias.Alias.Name));
}
}
ImmutableArray<NamespaceOrTypeAndUsingDirective> usings = Imports.Usings;
if (!usings.IsDefault)
{
foreach (var nsOrType in usings)
{
NamespaceOrTypeSymbol namespaceOrType = nsOrType.NamespaceOrType;
if (namespaceOrType.IsNamespace)
{
var ns = (NamespaceSymbol)namespaceOrType;
var assemblyRef = TryGetAssemblyScope(context, ns);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateNamespace(ns, assemblyRef));
}
else
{
var typeRef = GetTypeReference(context, (TypeSymbol)namespaceOrType);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateType(typeRef));
}
}
}
Dictionary<string, AliasAndUsingDirective> aliasSymbols = Imports.UsingAliases;
if (aliasSymbols != null)
{
foreach (var pair in aliasSymbols)
{
var alias = pair.Key;
var symbol = pair.Value.Alias;
Debug.Assert(!symbol.IsExtern);
NamespaceOrTypeSymbol target = symbol.Target;
if (target.Kind == SymbolKind.Namespace)
{
var ns = (NamespaceSymbol)target;
var assemblyRef = TryGetAssemblyScope(context, ns);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateNamespace(ns, assemblyRef, alias));
}
else
{
var typeRef = GetTypeReference(context, (TypeSymbol)target);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateType(typeRef, alias));
}
}
}
return usedNamespaces.ToImmutableAndFree();
}
private static Cci.ITypeReference GetTypeReference(EmitContext context, TypeSymbol type)
{
return context.ModuleBuilder.Translate(type, context.SyntaxNodeOpt, context.Diagnostics);
}
private Cci.IAssemblyReference TryGetAssemblyScope(EmitContext context, NamespaceSymbol @namespace)
{
AssemblySymbol containingAssembly = @namespace.ContainingAssembly;
if ((object)containingAssembly != null && (object)containingAssembly != context.ModuleBuilder.CommonCompilation.Assembly)
{
MetadataReference reference = context.ModuleBuilder.CommonCompilation.GetMetadataReference(containingAssembly);
if (reference != null &&
!reference.Properties.Aliases.IsDefault &&
!reference.Properties.Aliases.Contains(MetadataReferenceProperties.GlobalAlias))
{
return context.ModuleBuilder.Translate(containingAssembly, context.Diagnostics);
}
}
return null;
}
Cci.IImportScope Cci.IImportScope.Parent => ParentOpt;
}
}
......@@ -18,7 +18,7 @@ internal sealed class InContainerBinder : Binder
private readonly CSharpSyntaxNode _declarationSyntax;
private readonly bool _allowStaticClassUsings;
private Imports _imports; // might be initialized lazily
private ConsList<Imports> _lazyImportsList;
private ImportChain _lazyImportChain;
private readonly bool _inUsing;
/// <summary>
......@@ -80,23 +80,24 @@ private Imports GetImports(ConsList<Symbol> basesBeingResolved)
return _imports;
}
internal override ConsList<Imports> ImportsList
internal override ImportChain ImportChain
{
get
{
if (_lazyImportsList == null)
if (_lazyImportChain == null)
{
ConsList<Imports> importsList = this.Next.ImportsList;
ImportChain importChain = this.Next.ImportChain;
if (_container.Kind == SymbolKind.Namespace)
{
importsList = new ConsList<Imports>(GetImports(), importsList);
importChain = new ImportChain(GetImports(), importChain);
}
Interlocked.CompareExchange(ref _lazyImportsList, importsList, null);
Interlocked.CompareExchange(ref _lazyImportChain, importChain, null);
}
Debug.Assert(_lazyImportsList != null);
Debug.Assert(_lazyImportChain != null);
return _lazyImportsList;
return _lazyImportChain;
}
}
......
......@@ -127,6 +127,7 @@
<Compile Include="Binder\HostObjectModeBinder.cs" />
<Compile Include="Binder\ImplicitlyTypedFieldBinder.cs" />
<Compile Include="Binder\ImplicitlyTypedLocalBinder.cs" />
<Compile Include="Binder\ImportChain.cs" />
<Compile Include="Binder\Imports.cs" />
<Compile Include="Binder\InContainerBinder.cs" />
<Compile Include="Binder\InMethodBinder.cs" />
......@@ -256,7 +257,6 @@
<Compile Include="Compiler\MethodBodySynthesizer.cs" />
<Compile Include="Compiler\MethodBodySynthesizer.Lowered.cs" />
<Compile Include="Compiler\ModuleCompilationState.cs" />
<Compile Include="Compiler\NamespaceScopeBuilder.cs" />
<Compile Include="Compiler\SynthesizedMetadataCompiler.cs" />
<Compile Include="Compiler\TypeCompilationState.cs" />
<Compile Include="Compiler\UnprocessedDocumentationCommentFinder.cs" />
......@@ -307,6 +307,7 @@
<Compile Include="Emitter\Model\ModuleReference.cs" />
<Compile Include="Emitter\Model\NamedTypeReference.cs" />
<Compile Include="Emitter\Model\NamedTypeSymbolAdapter.cs" />
<Compile Include="Emitter\Model\NamespaceSymbolAdapter.cs" />
<Compile Include="Emitter\Model\ParameterSymbolAdapter.cs">
<SubType>Code</SubType>
</Compile>
......
......@@ -26,7 +26,6 @@ internal sealed class MethodCompiler : CSharpSymbolVisitor<TypeCompilationState,
private readonly CancellationToken _cancellationToken;
private readonly DiagnosticBag _diagnostics;
private readonly bool _hasDeclarationErrors;
private readonly NamespaceScopeBuilder _namespaceScopeBuilder;
private readonly PEModuleBuilder _moduleBeingBuiltOpt; // Null if compiling for diagnostics
private readonly Predicate<Symbol> _filterOpt; // If not null, limit analysis to specific symbols
private readonly DebugDocumentProvider _debugDocumentProvider;
......@@ -94,7 +93,6 @@ private void SetGlobalErrorIfTrue(bool arg)
if (generateDebugInfo)
{
_debugDocumentProvider = (path, basePath) => moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, CreateDebugDocumentForFile);
_namespaceScopeBuilder = new NamespaceScopeBuilder(compilation, new EmitContext(moduleBeingBuiltOpt, null, diagnostics));
}
}
......@@ -238,7 +236,8 @@ internal static MethodSymbol DefineScriptEntryPoint(CSharpCompilation compilatio
variableSlotAllocatorOpt: null,
diagnostics: diagnostics,
debugDocumentProvider: null,
namespaceScopes: default(ImmutableArray<Cci.NamespaceScope>));
importChainOpt: null,
generateDebugInfo: false);
moduleBeingBuilt.SetMethodBody(scriptEntryPoint, emittedBody);
moduleBeingBuilt.AddSynthesizedDefinition(compilation.ScriptClass, scriptEntryPoint);
......@@ -294,15 +293,15 @@ public override object VisitNamespace(NamespaceSymbol symbol, TypeCompilationSta
private Task CompileNamespaceAsTask(NamespaceSymbol symbol)
{
return Task.Run(UICultureUtilities.WithCurrentUICulture(() =>
{
try
{
CompileNamespace(symbol);
}
catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
{
throw ExceptionUtilities.Unreachable;
}
try
{
CompileNamespace(symbol);
}
catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
{
throw ExceptionUtilities.Unreachable;
}
}), _cancellationToken);
}
......@@ -340,15 +339,15 @@ public override object VisitNamedType(NamedTypeSymbol symbol, TypeCompilationSta
private Task CompileNamedTypeAsTask(NamedTypeSymbol symbol)
{
return Task.Run(UICultureUtilities.WithCurrentUICulture(() =>
{
try
{
CompileNamedType(symbol);
}
catch (Exception e) when(FatalError.Report(e))
{
throw ExceptionUtilities.Unreachable;
}
try
{
CompileNamedType(symbol);
}
catch (Exception e) when(FatalError.Report(e))
{
throw ExceptionUtilities.Unreachable;
}
}), _cancellationToken);
}
......@@ -422,7 +421,7 @@ private void CompileNamedType(NamedTypeSymbol symbol)
submissionCtorOrdinal = memberOrdinal;
continue;
}
if (IsFieldLikeEventAccessor(method))
{
continue;
......@@ -623,7 +622,8 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
variableSlotAllocatorOpt,
diagnosticsThisMethod,
_debugDocumentProvider,
GetNamespaceScopes(method, methodWithBody.DebugImports));
methodWithBody.ImportChainOpt,
generateDebugInfo: _generateDebugInfo && method.GenerateDebugInfo);
}
_diagnostics.AddRange(diagnosticsThisMethod);
......@@ -639,14 +639,6 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
}
}
private ImmutableArray<Cci.NamespaceScope> GetNamespaceScopes(MethodSymbol method, ConsList<Imports> debugImports)
{
Debug.Assert(_generateDebugInfo == (_namespaceScopeBuilder != null));
return (_generateDebugInfo && method.GenerateDebugInfo) ?
_namespaceScopeBuilder.GetNamespaceScopes(debugImports) : default(ImmutableArray<Cci.NamespaceScope>);
}
private static bool IsFieldLikeEventAccessor(MethodSymbol method)
{
Symbol associatedPropertyOrEvent = method.AssociatedSymbol;
......@@ -724,7 +716,8 @@ private void CompileFieldLikeEventAccessor(SourceEventSymbol eventSymbol, bool i
variableSlotAllocatorOpt: null,
diagnostics: diagnosticsThisMethod,
debugDocumentProvider: _debugDocumentProvider,
namespaceScopes: default(ImmutableArray<Cci.NamespaceScope>));
importChainOpt: null,
generateDebugInfo: false);
_moduleBeingBuiltOpt.SetMethodBody(accessor, emittedBody);
// Definition is already in the symbol table, so don't call moduleBeingBuilt.AddCompilerGeneratedDefinition
......@@ -794,7 +787,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
}
}
ConsList<Imports> oldDebugImports = compilationState.CurrentDebugImports;
ImportChain oldImportChain = compilationState.CurrentImportChain;
// In order to avoid generating code for methods with errors, we create a diagnostic bag just for this method.
DiagnosticBag diagsForCurrentMethod = DiagnosticBag.GetInstance();
......@@ -825,7 +818,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
// initializers that have been analyzed but not yet lowered.
BoundStatementList analyzedInitializers = null;
ConsList<Imports> debugImports;
ImportChain importChain;
if (methodSymbol.IsScriptConstructor)
{
......@@ -836,17 +829,17 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
body = new BoundBlock(initializerStatements.Syntax, ImmutableArray<LocalSymbol>.Empty, initializerStatements.Statements) { WasCompilerGenerated = true };
includeInitializersInBody = false;
debugImports = null;
importChain = null;
}
else
{
// Do not emit initializers if we are invoking another constructor of this class.
SourceMemberContainerTypeSymbol container = methodSymbol.ContainingType as SourceMemberContainerTypeSymbol;
includeInitializersInBody = !processedInitializers.BoundInitializers.IsDefaultOrEmpty &&
includeInitializersInBody = !processedInitializers.BoundInitializers.IsDefaultOrEmpty &&
!HasThisConstructorInitializer(methodSymbol);
body = BindMethodBody(methodSymbol, compilationState, diagsForCurrentMethod, _generateDebugInfo, out debugImports);
body = BindMethodBody(methodSymbol, compilationState, diagsForCurrentMethod, _generateDebugInfo, 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
......@@ -880,22 +873,22 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
// from the first field initializer.
if (_generateDebugInfo)
{
if ((methodSymbol.MethodKind == MethodKind.Constructor || methodSymbol.MethodKind == MethodKind.StaticConstructor) &&
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(debugImports == null);
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.FirstDebugImports != null);
Debug.Assert(processedInitializers.BoundInitializers.IsDefaultOrEmpty || processedInitializers.FirstImportChain != null);
}
#endif
debugImports = debugImports ?? processedInitializers.FirstDebugImports;
importChain = importChain ?? processedInitializers.FirstImportChain;
// Associate these debug imports with all methods generated from this one.
compilationState.CurrentDebugImports = debugImports;
compilationState.CurrentImportChain = importChain;
if (body != null)
{
......@@ -1086,7 +1079,8 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
lazyVariableSlotAllocator,
diagsForCurrentMethod,
_debugDocumentProvider,
GetNamespaceScopes(methodSymbol, debugImports));
importChain,
_generateDebugInfo && methodSymbol.GenerateDebugInfo);
_moduleBeingBuiltOpt.SetMethodBody(methodSymbol.PartialDefinitionPart ?? methodSymbol, emittedBody);
}
......@@ -1102,7 +1096,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
finally
{
diagsForCurrentMethod.Free();
compilationState.CurrentDebugImports = oldDebugImports;
compilationState.CurrentImportChain = oldImportChain;
}
}
......@@ -1238,19 +1232,19 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
PEModuleBuilder moduleBuilder,
MethodSymbol method,
int methodOrdinal,
BoundStatement block,
BoundStatement block,
ImmutableArray<LambdaDebugInfo> lambdaDebugInfo,
ImmutableArray<ClosureDebugInfo> closureDebugInfo,
StateMachineTypeSymbol stateMachineTypeOpt,
VariableSlotAllocator variableSlotAllocatorOpt,
DiagnosticBag diagnostics,
DebugDocumentProvider debugDocumentProvider,
ImmutableArray<Cci.NamespaceScope> namespaceScopes)
ImportChain importChainOpt,
bool generateDebugInfo)
{
// 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");
bool emittingPdbs = !namespaceScopes.IsDefault;
var compilation = moduleBuilder.Compilation;
var localSlotManager = new LocalSlotManager(variableSlotAllocatorOpt);
var optimizations = compilation.Options.OptimizationLevel;
......@@ -1261,7 +1255,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
{
Cci.AsyncMethodBodyDebugInfo asyncDebugInfo = null;
var codeGen = new CodeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnosticsForThisMethod, optimizations, emittingPdbs);
var codeGen = new CodeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnosticsForThisMethod, optimizations, generateDebugInfo);
// We need to save additional debugging information for MoveNext of an async state machine.
var stateMachineMethod = method as SynthesizedStateMachineMethod;
......@@ -1334,8 +1328,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
builder.RealizedExceptionHandlers,
builder.GetAllScopes(),
builder.HasDynamicLocal,
namespaceScopes,
Cci.NamespaceScopeEncoding.InPlace,
importChainOpt,
lambdaDebugInfo,
closureDebugInfo,
stateMachineTypeOpt?.Name,
......@@ -1357,7 +1350,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
}
private static void GetStateMachineSlotDebugInfo(
IEnumerable<Cci.IFieldDefinition> fieldDefs,
IEnumerable<Cci.IFieldDefinition> fieldDefs,
out ImmutableArray<EncHoistedLocalInfo> hoistedVariableSlots,
out ImmutableArray<Cci.ITypeReference> awaiterSlots)
{
......@@ -1400,14 +1393,14 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
// NOTE: can return null if the method has no body.
internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics)
{
ConsList<Imports> unused;
ImportChain unused;
return BindMethodBody(method, compilationState, diagnostics, false, 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 ConsList<Imports> debugImports)
private static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo, out ImportChain importChain)
{
debugImports = null;
importChain = null;
var compilation = method.DeclaringCompilation;
BoundStatement constructorInitializer = null;
......@@ -1458,7 +1451,7 @@ private static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationSta
body = binder.BindBlock(blockSyntax, diagnostics);
if (generateDebugInfo)
{
debugImports = binder.ImportsList;
importChain = binder.ImportChain;
}
if (inMethodBinder.IsDirectlyInIterator)
......
// 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.Linq;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Text;
using Microsoft.Cci;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Emit;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
/// <summary>
/// Class to cache and build namespace scopes. Should be released and collected once all namespace scopes
/// are built, since it contains caches that won't be needed anymore.
/// </summary>
internal sealed class NamespaceScopeBuilder
{
// Cache to map from ConsList<Imports> to ImmutableArray<NamespaceScope>. Currently we just use
// identity comparison on the key. We could implement our own comparer to detect equivalent ConsList<Imports>,
// but that only provides benefit when many file share the exactly same set of Imports in the same order. This would
// be a complex comparer to implement, and the benefit wouldn't be very high.
private readonly ConcurrentDictionary<ConsList<Imports>, ImmutableArray<Cci.NamespaceScope>> _cache = new ConcurrentDictionary<ConsList<Imports>, ImmutableArray<Cci.NamespaceScope>>();
// Cache to map from namespace or type to the string used to represent that namespace/type in the debug info.
private readonly ConcurrentDictionary<NamespaceOrTypeSymbol, string> _stringCache = new ConcurrentDictionary<NamespaceOrTypeSymbol, string>();
private readonly CSharpCompilation _compilation;
private readonly EmitContext _context;
// Cached delegates.
private Func<ConsList<Imports>, ImmutableArray<Cci.NamespaceScope>> _buildNamespaceScopes;
private Func<NamespaceOrTypeSymbol, string> _buildNamespaceOrTypeString;
public NamespaceScopeBuilder(CSharpCompilation compilation, EmitContext context)
{
_compilation = compilation;
_context = context;
_buildNamespaceScopes = BuildNamespaceScopes;
_buildNamespaceOrTypeString = BuildNamespaceOrTypeString;
}
/// <remarks>
/// CONSIDER: in the case of field initializers, it is possible that different parts of a method could have different
/// namespace scopes (i.e. if they come from different parts of a partial type). Currently, we're following Dev10's
/// approach of using the context of the (possibly synthesized) constructor into which the field initializers are
/// inserted. It might be possible to give field initializers their own scopes, assuming the EE supports it.
/// </remarks>
public ImmutableArray<Cci.NamespaceScope> GetNamespaceScopes(ConsList<Imports> debugImports)
{
if (debugImports == null)
{
return ImmutableArray<Cci.NamespaceScope>.Empty;
}
else
{
return _cache.GetOrAdd(debugImports, _buildNamespaceScopes);
}
}
private ImmutableArray<Cci.NamespaceScope> BuildNamespaceScopes(ConsList<Imports> debugImports)
{
var namespaceScopes = ArrayBuilder<Cci.NamespaceScope>.GetInstance();
// NOTE: All extern aliases are stored on the outermost Imports object.
var validExternAliases = PooledHashSet<string>.GetInstance();
foreach (AliasAndExternAliasDirective externAlias in debugImports.Last().ExternAliases.NullToEmpty())
{
validExternAliases.Add(externAlias.Alias.Name);
}
foreach (Imports imports in debugImports)
{
var usedNamespaces = ArrayBuilder<Cci.UsedNamespaceOrType>.GetInstance();
// NOTE: order based on dev10: extern aliases, then usings, then aliases namespaces and types
ImmutableArray<AliasAndExternAliasDirective> externAliases = imports.ExternAliases;
if (!externAliases.IsDefault)
{
foreach (var alias in externAliases)
{
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateCSharpExternNamespace(alias.Alias.Name));
}
}
ImmutableArray<NamespaceOrTypeAndUsingDirective> usings = imports.Usings;
if (!usings.IsDefault)
{
foreach (var nsOrType in usings)
{
NamespaceOrTypeSymbol namespaceOrType = nsOrType.NamespaceOrType;
string namespaceOrTypeString = GetNamespaceOrTypeString(namespaceOrType);
if (namespaceOrType.IsNamespace)
{
string externAlias = GuessExternAlias((NamespaceSymbol)namespaceOrType, validExternAliases);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateCSharpNamespace(namespaceOrTypeString, externAlias));
}
else
{
Debug.Assert(namespaceOrType is TypeSymbol);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateCSharpType(namespaceOrTypeString));
}
}
}
Dictionary<string, AliasAndUsingDirective> aliasSymbols = imports.UsingAliases;
if (aliasSymbols != null)
{
foreach (var pair in aliasSymbols)
{
var alias = pair.Key;
var symbol = pair.Value.Alias;
Debug.Assert(!symbol.IsExtern);
var target = symbol.Target;
var targetString = GetNamespaceOrTypeString(target);
if (target.Kind == SymbolKind.Namespace)
{
string externAlias = GuessExternAlias((NamespaceSymbol)target, validExternAliases);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateCSharpNamespaceAlias(targetString, alias, externAlias));
}
else
{
Debug.Assert(target is TypeSymbol);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateCSharpTypeAlias(targetString, alias));
}
}
}
namespaceScopes.Add(new Cci.NamespaceScope(usedNamespaces.ToImmutableAndFree()));
}
validExternAliases.Free();
return namespaceScopes.ToImmutableAndFree(); //NOTE: inner-to-outer order matches dev10
}
private string GuessExternAlias(NamespaceSymbol @namespace, HashSet<string> validAliases)
{
AssemblySymbol containingAssembly = @namespace.ContainingAssembly;
if ((object)containingAssembly != null && containingAssembly != _compilation.Assembly)
{
MetadataReference reference = _compilation.GetMetadataReference(containingAssembly);
if (reference != null)
{
ImmutableArray<string> aliases = reference.Properties.Aliases;
if (!aliases.IsDefaultOrEmpty)
{
if (aliases.Contains(MetadataReferenceProperties.GlobalAlias))
{
// If the namespace can be referenced without alias qualification, don't use any.
return null;
}
foreach (string alias in aliases)
{
if (validAliases.Contains(alias))
{
// CONSIDER: Dev12 uses the one that appeared in source, whereas we use
// the first one that COULD have appeared in source. (DevDiv #913022)
// NOTE: The reason we're not just using the alias from the syntax is that
// it is non-trivial to locate. In particular, since "." may be used in
// place of "::", determining whether the first identifier in the name is
// the alias requires binding. For example, "using A.B;" could refer to
// either "A::B" or "global::A.B".
return alias;
}
}
Debug.Assert(false, $"None of the aliases of {@namespace} is valid in this scope");
}
}
}
return null;
}
private string GetNamespaceOrTypeString(NamespaceOrTypeSymbol symbol)
{
return _stringCache.GetOrAdd(symbol, _buildNamespaceOrTypeString);
}
private string BuildNamespaceOrTypeString(NamespaceOrTypeSymbol symbol)
{
if (symbol.IsNamespace)
{
return BuildNamespaceString((NamespaceSymbol)symbol, isContainer: false);
}
else
{
var context = _context;
return context.ModuleBuilder.Translate((ITypeSymbol)symbol, context.SyntaxNodeOpt, context.Diagnostics).GetSerializedTypeName(context);
}
}
/// <summary>
/// Qualified name of namespace.
/// e.g. "A.B.C"
/// </summary>
private static string BuildNamespaceString(NamespaceSymbol symbol, bool isContainer)
{
Debug.Assert((object)symbol != null);
if (symbol.IsGlobalNamespace)
{
return "";
}
ArrayBuilder<string> parts = ArrayBuilder<string>.GetInstance();
for (NamespaceSymbol curr = symbol; !curr.IsGlobalNamespace; curr = curr.ContainingNamespace)
{
parts.Add(curr.Name);
}
parts.ReverseContents();
PooledStringBuilder pooled = PooledStringBuilder.GetInstance();
StringBuilder builder = pooled.Builder;
bool first = true;
foreach (string part in parts)
{
if (!first)
{
builder.Append(".");
}
first = false;
builder.Append(part);
}
if (isContainer)
{
builder.Append(".");
}
parts.Free();
return pooled.ToStringAndFree();
}
}
}
......@@ -25,13 +25,16 @@ internal struct MethodWithBody
{
public readonly MethodSymbol Method;
public readonly BoundStatement Body;
public readonly ConsList<Imports> DebugImports;
public readonly ImportChain ImportChainOpt;
internal MethodWithBody(MethodSymbol method, BoundStatement body, ConsList<Imports> debugImports)
internal MethodWithBody(MethodSymbol method, BoundStatement body, ImportChain importChainOpt)
{
Debug.Assert(method != null);
Debug.Assert(body != null);
this.Method = method;
this.Body = body;
this.DebugImports = debugImports;
this.ImportChainOpt = importChainOpt;
}
}
......@@ -44,7 +47,7 @@ internal MethodWithBody(MethodSymbol method, BoundStatement body, ConsList<Impor
/// only need one wrapper to call it non-virtually.
/// </summary>
private Dictionary<MethodSymbol, MethodSymbol> _wrappers;
private readonly NamedTypeSymbol _type;
/// <summary>
......@@ -56,7 +59,7 @@ internal MethodWithBody(MethodSymbol method, BoundStatement body, ConsList<Impor
/// Any generated methods that don't suppress debug info will use this
/// list of debug imports.
/// </summary>
public ConsList<Imports> CurrentDebugImports { get; set; }
public ImportChain CurrentImportChain { get; set; }
public readonly CSharpCompilation Compilation;
......@@ -108,7 +111,7 @@ public void AddSynthesizedMethod(MethodSymbol method, BoundStatement body)
_synthesizedMethods = ArrayBuilder<MethodWithBody>.GetInstance();
}
_synthesizedMethods.Add(new MethodWithBody(method, body, method.GenerateDebugInfo ? CurrentDebugImports : null));
_synthesizedMethods.Add(new MethodWithBody(method, body, method.GenerateDebugInfo ? CurrentImportChain : null));
}
/// <summary>
......
......@@ -73,6 +73,11 @@ Version Cci.IAssemblyReference.Version
get { return MetadataIdentity.Version; }
}
string Cci.IAssemblyReference.GetDisplayName()
{
return MetadataIdentity.GetDisplayName();
}
string Cci.INamedEntity.Name
{
get { return MetadataIdentity.Name; }
......
// 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.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
......@@ -635,5 +636,13 @@ internal virtual ImmutableArray<byte> ReturnValueMarshallingDescriptor
return default(ImmutableArray<byte>);
}
}
Cci.INamespace Cci.IMethodDefinition.ContainingNamespace
{
get
{
return ContainingNamespace;
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
partial class NamespaceSymbol : Cci.INamespace
{
Cci.INamespace Cci.INamespace.ContainingNamespace => ContainingNamespace;
string Cci.INamedEntity.Name => MetadataName;
}
}
......@@ -196,6 +196,11 @@ Version Cci.IAssemblyReference.Version
get { return _sourceAssembly.Identity.Version; }
}
string Cci.IAssemblyReference.GetDisplayName()
{
return _sourceAssembly.Identity.GetDisplayName();
}
internal override string Name
{
get { return _metadataName; }
......
......@@ -111,6 +111,17 @@ internal sealed override AssemblySymbol CorLibrary
get { return SourceModule.ContainingSourceAssembly.CorLibrary; }
}
protected sealed override bool GenerateVisualBasicStylePdb => false;
// C# doesn't emit linked assembly names into PDBs.
protected sealed override IEnumerable<string> LinkedAssembliesDebugInfo => SpecializedCollections.EmptyEnumerable<string>();
// C# currently doesn't emit compilation level imports (TODO: scripting).
protected override ImmutableArray<Cci.UsedNamespaceOrType> GetImports(EmitContext context) => ImmutableArray<Cci.UsedNamespaceOrType>.Empty;
// C# doesn't allow to define default namespace for compilation.
protected override string DefaultNamespace => null;
protected override IEnumerable<Cci.IAssemblyReference> GetAssemblyReferencesFromAddedModules(DiagnosticBag diagnostics)
{
ImmutableArray<ModuleSymbol> modules = SourceModule.ContainingAssembly.Modules;
......
......@@ -200,5 +200,13 @@ protected override Cci.ISignature UnderlyingMethodSignature
return (Cci.ISignature)UnderlyingMethod;
}
}
protected override Cci.INamespace ContainingNamespace
{
get
{
return UnderlyingMethod.ContainingNamespace;
}
}
}
}
......@@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
/// <summary>
/// Represents a namespace.
/// </summary>
internal abstract class NamespaceSymbol : NamespaceOrTypeSymbol, INamespaceSymbol
internal abstract partial class NamespaceSymbol : NamespaceOrTypeSymbol, INamespaceSymbol
{
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Changes to the public interface of this class should remain synchronized with the VB version.
......
......@@ -486,6 +486,7 @@ class C { void M() { } }
new CSharpCompilationReference(dummyCompilation1, ImmutableArray.Create("global", "A")),
new CSharpCompilationReference(dummyCompilation2, ImmutableArray.Create("B", "global"))
});
compilation.VerifyDiagnostics(
// (5,1): hidden CS8019: Unnecessary using directive.
// using Y = B::N;
......@@ -497,8 +498,7 @@ class C { void M() { } }
// using Z = global::N;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using Z = global::N;").WithLocation(6, 1));
string actual = GetPdbXml(compilation);
string expected = @"
compilation.VerifyPdb(@"
<symbols>
<methods>
<method containingType=""C"" name=""M"">
......@@ -523,8 +523,7 @@ class C { void M() { } }
</scope>
</method>
</methods>
</symbols>";
AssertXmlEqual(expected, actual);
</symbols>");
}
[Fact]
......
......@@ -287,14 +287,14 @@ private static ImmutableArray<BoundInitializer> BindInitializersWithoutDiagnosti
DiagnosticBag diagnostics = DiagnosticBag.GetInstance();
try
{
ConsList<Imports> unused;
ImportChain unused;
var boundInitializers = Binder.BindFieldInitializers(
containingType: typeSymbol,
scriptCtor: null,
initializers: initializers,
diagnostics: diagnostics,
generateDebugInfo: false,
firstDebugImports: out unused);
firstImportChain: out unused);
var filteredDiag = diagnostics.AsEnumerable();
foreach (var diagnostic in filteredDiag)
......
......@@ -356,7 +356,7 @@
<Compile Include="PEWriter\DirectoryEntry.cs" />
<Compile Include="PEWriter\ExceptionHandlerRegion.cs" />
<Compile Include="PEWriter\Expressions.cs" />
<Compile Include="PEWriter\ExternNamespace.cs" />
<Compile Include="PEWriter\AssemblyReferenceAlias.cs" />
<Compile Include="PEWriter\FullMetadataWriter.cs" />
<Compile Include="PEWriter\ICustomAttribute.cs" />
<Compile Include="PEWriter\IFileReference.cs" />
......@@ -374,7 +374,7 @@
<Compile Include="PEWriter\MethodSpecComparer.cs" />
<Compile Include="PEWriter\Miscellaneous.cs" />
<Compile Include="PEWriter\ModifiedTypeReference.cs" />
<Compile Include="PEWriter\NamespaceScope.cs" />
<Compile Include="PEWriter\IImportScope.cs" />
<Compile Include="PEWriter\NtHeader.cs" />
<Compile Include="PEWriter\PdbMetadataWrapper.cs" />
<Compile Include="PEWriter\PdbWriter.cs" />
......@@ -391,7 +391,6 @@
<Compile Include="PEWriter\TypeSpecComparer.cs" />
<Compile Include="PEWriter\Units.cs" />
<Compile Include="PEWriter\UsedNamespaceOrType.cs" />
<Compile Include="PEWriter\UsedNamespaceOrTypeKind.cs" />
<Compile Include="PrimitiveTypeCodeExtensions.cs" />
<Compile Include="ReferenceManager\AssemblyData.cs" />
<Compile Include="ReferenceManager\AssemblyDataForAssemblyBeingBuilt.cs" />
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.Cci
{
/// <summary>
/// Represents an assembly reference with an alias (i.e. an extern alias in C#).
/// </summary>
internal struct ExternNamespace
{
private readonly string _namespaceAlias;
private readonly string _assemblyName;
internal ExternNamespace(string namespaceAlias, string assemblyName)
{
_namespaceAlias = namespaceAlias;
_assemblyName = assemblyName;
}
/// <summary>
/// An alias for the global namespace of the assembly.
/// </summary>
public string NamespaceAlias { get { return _namespaceAlias; } }
/// <summary>
/// The name of the referenced assembly.
/// </summary>
public string AssemblyName { get { return _assemblyName; } }
}
}
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
// 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 System.Diagnostics;
namespace Microsoft.Cci
{
/// <summary>
/// This is a list of the using directives (including aliases) in a lexical scope.
/// </summary>
/// <remarks>
/// This scope is tied to a particular method body, so that partial types can be accommodated.
/// </remarks>
internal class NamespaceScope
{
public static readonly NamespaceScope Empty = new NamespaceScope(ImmutableArray<UsedNamespaceOrType>.Empty);
private readonly ImmutableArray<UsedNamespaceOrType> _usedNamespaces;
internal NamespaceScope(ImmutableArray<UsedNamespaceOrType> usedNamespaces)
{
Debug.Assert(!usedNamespaces.IsDefault);
_usedNamespaces = usedNamespaces;
}
/// <summary>
/// Zero or more used namespaces. These correspond to using clauses in C#.
/// </summary>
public ImmutableArray<UsedNamespaceOrType> UsedNamespaces
{
get
{
return _usedNamespaces;
}
}
}
}
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
B// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.Cci
{
internal enum UsedNamespaceOrTypeKind
{
CSNamespace, // e.g. using System;
CSNamespaceAlias, // e.g. using S = System;
CSExternNamespace, //e.g. extern alias CorLib;
CSType, // e.g. using System.Math;
CSTypeAlias, // e.g. using IntList = System.Collections.Generic.List<int>;
VBNamespace, // e.g. Imports System.Collection
VBType, // e.g. Imports System.Collection.ArrayList
VBNamespaceOrTypeAlias, // e.g. Imports Foo=System.Collection or Imports Foo=System.Collection.ArrayList
VBXmlNamespace, // e.g. Imports <xmlns:ns="http://NewNamespace"> (VB only)
VBCurrentNamespace, // the current namespace of the method's container
VBDefaultNamespace, // the default namespace of the project
VBEmbeddedPia, // indicates that a type has been embedded from a given PIA
}
}
......@@ -393,6 +393,7 @@
<Compile Include="Emit\ModuleReference.vb" />
<Compile Include="Emit\NamedTypeReference.vb" />
<Compile Include="Emit\NamedTypeSymbolAdapter.vb" />
<Compile Include="Emit\NamespaceSymbolAdapter.vb" />
<Compile Include="Emit\NoPia\EmbeddedEvent.vb" />
<Compile Include="Emit\NoPia\EmbeddedField.vb" />
<Compile Include="Emit\NoPia\EmbeddedMethod.vb" />
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
' 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
Imports System.Collections.Concurrent
......@@ -97,7 +97,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
If generateDebugInfo Then
Me._debugDocumentProvider = Function(path As String, basePath As String) moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, AddressOf CreateDebugDocumentForFile)
Me._namespaceScopeBuilder = New NamespaceScopeBuilder()
End If
If compilation.Options.ConcurrentBuild Then
......@@ -306,7 +305,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
variableSlotAllocatorOpt:=Nothing,
debugDocumentProvider:=Nothing,
diagnostics:=diagnostics,
namespaceScopes:=Nothing)
generateDebugInfo:=False)
moduleBeingBuilt.SetMethodBody(scriptEntryPoint, emittedBody)
moduleBeingBuilt.AddSynthesizedDefinition(compilation.ScriptClass, scriptEntryPoint)
......@@ -362,7 +361,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
For index = 0 To builder.Count - 1
Dim symbol As Symbol = builder(index)
Dim symbol As symbol = builder(index)
processedSymbols.Add(symbol)
#If DEBUG Then
......@@ -537,7 +536,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim processedStaticInitializers = Binder.ProcessedFieldOrPropertyInitializers.Empty
Dim processedInstanceInitializers = Binder.ProcessedFieldOrPropertyInitializers.Empty
Dim synthesizedSubmissionFields = If(symbol.IsSubmissionClass, New SynthesizedSubmissionFields(_compilation, symbol), Nothing)
Dim synthesizedSubmissionFields = If(symbol.IsSubmissionClass, New synthesizedSubmissionFields(_compilation, symbol), Nothing)
' if this is a type symbol from source we'll try to bind the field initializers as well
Dim sourceTypeSymbol = TryCast(symbol, SourceMemberContainerTypeSymbol)
......@@ -732,7 +731,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
If sourceMethod IsNot Nothing AndAlso
sourceMethod.MethodKind = MethodKind.Constructor AndAlso
Not compilationState.CallsInitializeComponent(sourceMethod) Then
Dim location As Location = sourceMethod.NonMergedLocation
Dim location As location = sourceMethod.NonMergedLocation
Debug.Assert(location IsNot Nothing)
If location IsNot Nothing Then
......@@ -853,7 +852,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
variableSlotAllocatorOpt:=Nothing,
debugDocumentProvider:=Nothing,
diagnostics:=diagnosticsThisMethod,
namespaceScopes:=Nothing)
generateDebugInfo:=False)
_diagnostics.AddRange(diagnosticsThisMethod)
diagnosticsThisMethod.Free()
......@@ -912,7 +911,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
variableSlotAllocatorOpt,
debugDocumentProvider:=Nothing,
diagnostics:=diagnosticsThisMethod,
namespaceScopes:=Nothing)
generateDebugInfo:=False)
End If
End If
......@@ -955,7 +954,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
variableSlotAllocatorOpt:=Nothing,
debugDocumentProvider:=_debugDocumentProvider,
diagnostics:=diagnosticsThisMethod,
namespaceScopes:=GetNamespaceScopes(methodWithBody.Method))
generateDebugInfo:=_generateDebugInfo AndAlso method.GenerateDebugInfo)
_diagnostics.AddRange(diagnosticsThisMethod)
diagnosticsThisMethod.Free()
......@@ -1214,7 +1213,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
processedInitializers,
previousSubmissionFields,
If(injectConstructorCall, referencedConstructor, Nothing),
GetNamespaceScopes(method),
delegateRelaxationIdDispenser)
' if method happen to handle events of a base WithEvents, ensure that we have an overriding WithEvents property
......@@ -1235,16 +1233,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
diagsForCurrentMethod.Free()
End Sub
Private Function GetNamespaceScopes(method As MethodSymbol) As ImmutableArray(Of Cci.NamespaceScope)
Debug.Assert(Me._generateDebugInfo = (_namespaceScopeBuilder IsNot Nothing))
If _generateDebugInfo AndAlso method.GenerateDebugInfo Then
Return _namespaceScopeBuilder.GetNamespaceScopes(method)
End If
Return Nothing
End Function
''' <summary>
''' If any of the "Handles" in the list have synthetic WithEvent override
''' as a container, then this method will (if not done already) inject
......@@ -1349,7 +1337,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
processedInitializers As Binder.ProcessedFieldOrPropertyInitializers,
previousSubmissionFields As SynthesizedSubmissionFields,
constructorToInject As MethodSymbol,
namespaceScopes As ImmutableArray(Of Cci.NamespaceScope),
ByRef delegateRelaxationIdDispenser As Integer
)
Dim constructorInitializerOpt = If(constructorToInject Is Nothing,
......@@ -1437,14 +1424,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
' NOTE: additional check for statement.HasErrors is needed to identify parse errors which didn't get into diagsForCurrentMethod
Dim methodBody As MethodBody = GenerateMethodBody(_moduleBeingBuiltOpt,
Dim methodBody As methodBody = GenerateMethodBody(_moduleBeingBuiltOpt,
method,
body,
stateMachineTypeOpt,
variableSlotAllocatorOpt,
_debugDocumentProvider,
diagnostics,
namespaceScopes)
generateDebugInfo:=_generateDebugInfo AndAlso method.GenerateDebugInfo)
If diagnostics IsNot diagsForCurrentMethod Then
DirectCast(method.AssociatedSymbol, SynthesizedMyGroupCollectionPropertySymbol).RelocateDiagnostics(diagnostics, diagsForCurrentMethod)
......@@ -1461,10 +1448,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
variableSlotAllocatorOpt As VariableSlotAllocator,
debugDocumentProvider As DebugDocumentProvider,
diagnostics As DiagnosticBag,
namespaceScopes As ImmutableArray(Of Cci.NamespaceScope)) As MethodBody
generateDebugInfo 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
......@@ -1472,13 +1459,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
Dim builder As ILBuilder = New ILBuilder(moduleBuilder, localSlotManager, optimizations)
Dim emittingPdbs = Not namespaceScopes.IsDefault
Try
Debug.Assert(Not diagnostics.HasAnyErrors)
Dim asyncDebugInfo As Cci.AsyncMethodBodyDebugInfo = Nothing
Dim codeGen = New CodeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnostics, optimizations, emittingPdbs)
Dim codeGen = New codeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnostics, optimizations, generateDebugInfo)
' We need to save additional debugging information for MoveNext of an async state machine.
Dim stateMachineMethod = TryCast(method, SynthesizedStateMachineMethod)
......@@ -1527,6 +1513,8 @@ 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.
'<PdbUtil.cpp>
......@@ -1548,6 +1536,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
'Error:
' return hr;
'}
Dim localScopes = builder.GetAllScopes(edgeInclusive:=True)
Return New MethodBody(builder.RealizedIL,
builder.MaxStack,
......@@ -1557,10 +1546,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
builder.RealizedSequencePoints,
debugDocumentProvider,
builder.RealizedExceptionHandlers,
builder.GetAllScopes(edgeInclusive:=True),
localScopes,
hasDynamicLocalVariables:=False,
namespaceScopes:=namespaceScopes,
namespaceScopeEncoding:=Cci.NamespaceScopeEncoding.Forwarding,
importScopeOpt:=namespaceScopes,
lambdaDebugInfo:=ImmutableArray(Of LambdaDebugInfo).Empty,
closureDebugInfo:=ImmutableArray(Of ClosureDebugInfo).Empty,
stateMachineTypeNameOpt:=stateMachineTypeOpt?.Name, ' TODO: remove or update AddedOrChangedMethodInfo
......
' 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.Collections.Concurrent
Imports System.Collections.Immutable
Imports System.Threading
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.Emit
Namespace Microsoft.CodeAnalysis.VisualBasic
''' <summary>
''' This class is used to generate the namespace scopes used by CCI when writing out the import lists.
''' Because the content is nearly the same for each method (most of it is file and project level) this class
''' has an internal cache.
''' </summary>
Friend Class NamespaceScopeBuilder
' lazy embedded PIA imports
Private m_lazyEmbeddedPIAImports As Cci.NamespaceScope
' lazy project level imports
Private m_lazyProjectLevelImports As Cci.NamespaceScope
' lazy default/root namespace
Private m_lazyDefaultNamespaceImport As Cci.NamespaceScope
' delegate for adding an element to the file level imports cache
Private ReadOnly m_buildFileLevelImports As Func(Of SourceFile, Cci.NamespaceScope)
' delegate for adding an element to the name string cache
Private ReadOnly m_buildNamespaceOrTypeString As Func(Of NamespaceOrTypeSymbol, String)
' cache to map from source file to namespace scopes
Private ReadOnly m_sourceLevelImportsCache As ConcurrentDictionary(Of SourceFile, Cci.NamespaceScope)
' Cache to map from namespace or type to the string used to represent that namespace/type in the debug info.
Private ReadOnly m_stringCache As ConcurrentDictionary(Of NamespaceOrTypeSymbol, String)
Private Shared ReadOnly m_debugFormat As New SymbolDisplayFormat(globalNamespaceStyle:=SymbolDisplayGlobalNamespaceStyle.Omitted,
typeQualificationStyle:=SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)
Public Sub New()
m_sourceLevelImportsCache = New ConcurrentDictionary(Of SourceFile, Cci.NamespaceScope)()
m_stringCache = New ConcurrentDictionary(Of NamespaceOrTypeSymbol, String)()
m_buildFileLevelImports = AddressOf BuildFileLevelImports
m_buildNamespaceOrTypeString = AddressOf BuildNamespaceOrTypeString
Friend NotInheritable Class NamespaceScopeBuilder
Private Sub New()
End Sub
Public Function GetNamespaceScopes(method As MethodSymbol) As ImmutableArray(Of Cci.NamespaceScope)
Dim sourceModule = DirectCast(method.ContainingModule, SourceModuleSymbol)
If m_lazyEmbeddedPIAImports Is Nothing Then
Interlocked.CompareExchange(m_lazyEmbeddedPIAImports, BuildEmbeddedPiaImports(sourceModule), Nothing)
End If
If m_lazyProjectLevelImports Is Nothing Then
Interlocked.CompareExchange(m_lazyProjectLevelImports, BuildProjectLevelImports(sourceModule), Nothing)
End If
If m_lazyDefaultNamespaceImport Is Nothing Then
Interlocked.CompareExchange(m_lazyDefaultNamespaceImport, BuildDefaultNamespace(sourceModule), Nothing)
End If
' Dev11 outputs them in LIFO order, which we can't do this exactly the same way because we store parts of the
' needed information in trees.
' The order should be irrelevant because at the end it's a flat list, however we still output file level imports
' before project level imports the same way as Dev11 did.
Dim sourceLevelImports As Cci.NamespaceScope
sourceLevelImports = m_sourceLevelImportsCache.GetOrAdd(sourceModule.GetSourceFile(method.Syntax.SyntaxTree),
m_buildFileLevelImports)
Return ImmutableArray.Create(sourceLevelImports,
m_lazyDefaultNamespaceImport,
m_lazyEmbeddedPIAImports,
m_lazyProjectLevelImports,
BuildCurrentNamespace(method))
End Function
''' <remarks>
''' Roslyn does not consume this information - it is only emitted for the benefit of legacy EEs.
''' See Builder::WriteNoPiaPdbList.
''' </remarks>
Private Function BuildEmbeddedPiaImports([module] As SourceModuleSymbol) As Cci.NamespaceScope
Dim embeddedPiasBuilder As ArrayBuilder(Of Cci.UsedNamespaceOrType) = Nothing
For Each referencedAssembly In [module].ReferencedAssemblySymbols
If referencedAssembly.IsLinked Then
If embeddedPiasBuilder Is Nothing Then
embeddedPiasBuilder = ArrayBuilder(Of Cci.UsedNamespaceOrType).GetInstance()
End If
' NOTE: Dev12 does not seem to emit anything but the name (i.e. no version, token, etc).
embeddedPiasBuilder.Add(Cci.UsedNamespaceOrType.CreateVisualBasicEmbeddedPia(referencedAssembly.Name))
End If
Next
Dim embeddedPias = If(embeddedPiasBuilder Is Nothing, ImmutableArray(Of Cci.UsedNamespaceOrType).Empty, embeddedPiasBuilder.ToImmutableAndFree())
Return New Cci.NamespaceScope(embeddedPias)
End Function
Private Function BuildProjectLevelImports([module] As SourceModuleSymbol) As Cci.NamespaceScope
Return BuildNamespaceScope([module].XmlNamespaces,
[module].AliasImports,
[module].MemberImports,
isProjectLevel:=True)
End Function
Private Function BuildFileLevelImports(file As SourceFile) As Cci.NamespaceScope
Return BuildNamespaceScope(file.XmlNamespaces,
If(file.AliasImports IsNot Nothing, file.AliasImports.Values, Nothing),
file.MemberImports,
isProjectLevel:=False)
End Function
Private Function BuildCurrentNamespace(method As MethodSymbol) As Cci.NamespaceScope
Return New Cci.NamespaceScope(ImmutableArray.Create(
Cci.UsedNamespaceOrType.CreateVisualBasicCurrentNamespace(GetNamespaceOrTypeString(method.ContainingNamespace))))
End Function
Private Function BuildDefaultNamespace([module] As SourceModuleSymbol) As Cci.NamespaceScope
Dim rootNamespace = [module].RootNamespace
If rootNamespace IsNot Nothing AndAlso Not rootNamespace.IsGlobalNamespace Then
Return New Cci.NamespaceScope(ImmutableArray.Create(
Cci.UsedNamespaceOrType.CreateVisualBasicDefaultNamespace(GetNamespaceOrTypeString(rootNamespace))))
Else
Return Cci.NamespaceScope.Empty
End If
End Function
Private Function BuildNamespaceScope(
Public Shared Function BuildNamespaceScope(
context As EmitContext,
xmlNamespaces As Dictionary(Of String, XmlNamespaceAndImportsClausePosition),
aliasImports As IEnumerable(Of AliasAndImportsClausePosition),
memberImports As ImmutableArray(Of NamespaceOrTypeAndImportsClausePosition),
isProjectLevel As Boolean
) As Cci.NamespaceScope
memberImports As ImmutableArray(Of NamespaceOrTypeAndImportsClausePosition)
) As ImmutableArray(Of Cci.UsedNamespaceOrType)
Dim scopeBuilder = ArrayBuilder(Of Cci.UsedNamespaceOrType).GetInstance
' first come xml imports
If xmlNamespaces IsNot Nothing Then
For Each xmlImport In xmlNamespaces
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateVisualBasicXmlNamespace(xmlImport.Value.XmlNamespace,
xmlImport.Key,
isProjectLevel))
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateXmlNamespace(xmlImport.Key, xmlImport.Value.XmlNamespace))
Next
End If
......@@ -150,10 +29,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
If aliasImports IsNot Nothing Then
For Each aliasImport In aliasImports
Dim target = aliasImport.Alias.Target
If target.IsNamespace OrElse DirectCast(target, NamedTypeSymbol).Arity = 0 Then
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateVisualBasicNamespaceOrTypeAlias(GetNamespaceOrTypeString(target),
aliasImport.Alias.Name,
isProjectLevel))
If target.IsNamespace Then
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateNamespace(DirectCast(target, NamespaceSymbol), aliasOpt:=aliasImport.Alias.Name))
Else
Dim typeRef = GetTypeReference(context, DirectCast(target, NamedTypeSymbol))
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateType(typeRef, aliasOpt:=aliasImport.Alias.Name))
End If
Next
End If
......@@ -161,32 +41,21 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' then come the imports
If Not memberImports.IsEmpty Then
For Each import In memberImports
If import.NamespaceOrType.IsNamespace Then
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateVisualBasicNamespace(GetNamespaceOrTypeString(import.NamespaceOrType),
isProjectLevel))
Dim target = import.NamespaceOrType
If target.IsNamespace Then
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateNamespace(DirectCast(target, NamespaceSymbol)))
Else
If DirectCast(import.NamespaceOrType, NamedTypeSymbol).Arity = 0 Then
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateVisualBasicType(GetNamespaceOrTypeString(import.NamespaceOrType),
isProjectLevel))
End If
Dim typeRef = GetTypeReference(context, DirectCast(target, NamedTypeSymbol))
scopeBuilder.Add(Cci.UsedNamespaceOrType.CreateType(typeRef))
End If
Next
End If
Dim scope = If(scopeBuilder.Count = 0, Cci.NamespaceScope.Empty, New Cci.NamespaceScope(scopeBuilder.ToImmutable()))
scopeBuilder.Free()
Return scope
End Function
Private Function GetNamespaceOrTypeString(symbol As NamespaceOrTypeSymbol) As String
Return m_stringCache.GetOrAdd(symbol, m_buildNamespaceOrTypeString)
Return scopeBuilder.ToImmutableAndFree()
End Function
Private Function BuildNamespaceOrTypeString(symbol As NamespaceOrTypeSymbol) As String
Return symbol.ToDisplayString(m_debugFormat)
Private Shared Function GetTypeReference(context As EmitContext, type As TypeSymbol) As Cci.ITypeReference
Return context.ModuleBuilder.Translate(type, context.SyntaxNodeOpt, context.Diagnostics)
End Function
End Class
End Namespace
......@@ -57,6 +57,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
End Get
End Property
Private Function IAssemblyReferenceGetDisplayName() As String Implements Cci.IAssemblyReference.GetDisplayName
Return MetadataIdentity.GetDisplayName()
End Function
Private ReadOnly Property INamedEntityName As String Implements Cci.INamedEntity.Name
Get
Return MetadataIdentity.Name
......
......@@ -217,5 +217,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
Return True
End Get
End Property
Protected Overrides ReadOnly Property LinkedAssembliesDebugInfo As IEnumerable(Of String)
Get
' This debug information is only emitted for the benefit of legacy EE.
' Since EnC requires Roslyn and Roslyn doesn't need this information we don't emit it during EnC.
Return SpecializedCollections.EmptyEnumerable(Of String)()
End Get
End Property
End Class
End Namespace
......@@ -502,5 +502,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Return securityAttributes
End Get
End Property
Private ReadOnly Property IMethodDefinition_ContainingNamespace As Cci.INamespace Implements Cci.IMethodDefinition.ContainingNamespace
Get
Return ContainingNamespace
End Get
End Property
End Class
End Namespace
' 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 Microsoft.Cci
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Partial Friend MustInherit Class NamespaceSymbol
Implements Cci.INamespace
Private ReadOnly Property INamedEntity_Name As String Implements INamedEntity.Name
Get
Return Me.MetadataName
End Get
End Property
Private ReadOnly Property INamespaceSymbol_ContainingNamespace As Cci.INamespace Implements Cci.INamespace.ContainingNamespace
Get
Return Me.ContainingNamespace
End Get
End Property
End Class
End Namespace
' 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.Collections.Immutable
Imports Microsoft.Cci
Imports Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
......@@ -155,6 +156,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia
End Get
End Property
Protected Overrides ReadOnly Property ContainingNamespace As INamespace
Get
Return UnderlyingMethod.ContainingNamespace
End Get
End Property
End Class
End Namespace
......@@ -11,7 +11,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
Inherits PEModuleBuilder
Implements Cci.IAssembly
Private ReadOnly m_SourceAssembly As SourceAssemblySymbol
Protected ReadOnly m_SourceAssembly As SourceAssemblySymbol
Private ReadOnly m_AdditionalTypes As ImmutableArray(Of NamedTypeSymbol)
Private m_LazyFiles As ImmutableArray(Of Cci.IFileReference)
......@@ -167,6 +167,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
End Get
End Property
Private Function IAssemblyReferenceGetDisplayName() As String Implements Cci.IAssemblyReference.GetDisplayName
Return m_SourceAssembly.Identity.GetDisplayName()
End Function
Friend Overrides ReadOnly Property Name As String
Get
Return m_MetadataName
......@@ -206,5 +210,4 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
End Get
End Property
End Class
End Namespace
......@@ -4,6 +4,7 @@ Imports System.Collections.Concurrent
Imports System.Collections.Immutable
Imports System.Reflection.PortableExecutable
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeGen
Imports Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
......@@ -21,6 +22,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
Private ReadOnly m_MetadataName As String
Private m_LazyExportedTypes As ImmutableArray(Of TypeExport(Of NamedTypeSymbol))
Private m_lazyImports As ImmutableArray(Of Cci.UsedNamespaceOrType)
Private m_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.
Private m_TestData As ConcurrentDictionary(Of String, CompilationTestData.MethodData)
......@@ -82,6 +85,46 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
End Get
End Property
Protected Overrides ReadOnly Property GenerateVisualBasicStylePdb As Boolean
Get
Return True
End Get
End Property
Protected Overrides ReadOnly Property LinkedAssembliesDebugInfo As IEnumerable(Of String)
Get
' NOTE: Dev12 does not seem to emit anything but the name (i.e. no version, token, etc).
' See Builder::WriteNoPiaPdbList
Return SourceModule.ReferencedAssemblySymbols.Where(Function(a) a.IsLinked).Select(Function(a) a.Name)
End Get
End Property
Protected NotOverridable Overrides Function GetImports(context As EmitContext) As ImmutableArray(Of Cci.UsedNamespaceOrType)
If m_lazyImports.IsDefault Then
ImmutableInterlocked.InterlockedInitialize(
m_lazyImports,
NamespaceScopeBuilder.BuildNamespaceScope(context, SourceModule.XmlNamespaces, SourceModule.AliasImports, SourceModule.MemberImports))
End If
Return m_lazyImports
End Function
Protected NotOverridable Overrides ReadOnly Property DefaultNamespace As String
Get
If m_lazyDefaultNamespace IsNot Nothing Then
Return m_lazyDefaultNamespace
End If
Dim rootNamespace = SourceModule.RootNamespace
If rootNamespace Is Nothing OrElse rootNamespace.IsGlobalNamespace Then
Return Nothing
End If
m_lazyDefaultNamespace = rootNamespace.ToDisplayString(SymbolDisplayFormat.QualifiedNameOnlyFormat)
Return m_lazyDefaultNamespace
End Get
End Property
Protected Overrides Iterator Function GetAssemblyReferencesFromAddedModules(diagnostics As DiagnosticBag) As IEnumerable(Of Cci.IAssemblyReference)
Dim modules As ImmutableArray(Of ModuleSymbol) = SourceModule.ContainingAssembly.Modules
......@@ -120,7 +163,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
Not (refMachine = Machine.I386 AndAlso Not assembly.Bit32Required) Then
Dim machine = SourceModule.Machine
If Not (machine = Machine.I386 AndAlso Not SourceModule.Bit32Required) AndAlso
If Not (machine = machine.I386 AndAlso Not SourceModule.Bit32Required) AndAlso
machine <> refMachine Then
' Different machine types, and neither is agnostic
diagnostics.Add(ErrorFactory.ErrorInfo(ERRID.WRN_ConflictingMachineAssembly, assembly), NoLocation.Singleton)
......
' 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.Collections.Generic
Imports System.Collections.Immutable
Imports System.Collections.ObjectModel
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports TypeKind = Microsoft.CodeAnalysis.TypeKind
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Friend Class SourceFile
Implements Cci.IImportScope
Private ReadOnly m_sourceModule As SourceModuleSymbol
Private ReadOnly m_syntaxTree As SyntaxTree
......@@ -30,6 +30,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
' lazily populate with quick attribute checker that is initialized with the imports.
Private m_lazyQuickAttributeChecker As QuickAttributeChecker
Private m_lazyTranslatedImports As ImmutableArray(Of Cci.UsedNamespaceOrType)
''' <summary>
''' The bound information from a file.
''' </summary>
......@@ -265,7 +267,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End If
cancellationToken.ThrowIfCancellationRequested()
Binder.BindImportClause(clause, data, diagBag)
binder.BindImportClause(clause, data, diagBag)
Next
Next
......@@ -421,6 +423,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
BindFileInformation(diagBag, cancellationToken, filterSpan)
Return diagBag.ToReadOnlyAndFree()
End Function
Public ReadOnly Property Parent As Cci.IImportScope Implements Cci.IImportScope.Parent
Get
Return Nothing
End Get
End Property
Public Function GetUsedNamespaces(context As EmitContext) As ImmutableArray(Of Cci.UsedNamespaceOrType) Implements Cci.IImportScope.GetUsedNamespaces
If m_lazyTranslatedImports.IsDefault Then
ImmutableInterlocked.InterlockedInitialize(m_lazyTranslatedImports, TranslateImports(context))
End If
Return m_lazyTranslatedImports
End Function
Private Function TranslateImports(context As EmitContext) As ImmutableArray(Of Cci.UsedNamespaceOrType)
Return NamespaceScopeBuilder.BuildNamespaceScope(context,
XmlNamespaces,
If(AliasImports IsNot Nothing, AliasImports.Values, Nothing),
MemberImports)
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册