internal AliasSymbol ToNewSubmission(CSharpCompilation compilation) { Debug.Assert(_binder.Compilation.IsSubmission); // We can pass basesBeingResolved: null because base type cycles can't cross // submission boundaries - there's no way to depend on a subsequent submission. var previousTarget = GetAliasTarget(basesBeingResolved: null); if (previousTarget.Kind != SymbolKind.Namespace) { return(this); } var expandedGlobalNamespace = compilation.GlobalNamespace; var expandedNamespace = Imports.ExpandPreviousSubmissionNamespace( (NamespaceSymbol)previousTarget, expandedGlobalNamespace ); var binder = new InContainerBinder( expandedGlobalNamespace, new BuckStopsHereBinder(compilation) ); return(new AliasSymbol(binder, expandedNamespace, _aliasName, _locations)); }
private AliasSymbol(InContainerBinder binder, NamespaceOrTypeSymbol target, SyntaxToken aliasName, ImmutableArray <Location> locations) { _aliasName = aliasName; _locations = locations; _aliasTarget = target; _binder = binder; _state.NotePartComplete(CompletionPart.AliasTarget); }
private static ImmutableArray <AliasAndExternAliasDirective> BuildExternAliases( ImmutableArray <ExternAliasDirective> directiveList, InContainerBinder binder, DiagnosticBag diagnostics) { LanguageCompilation compilation = binder.Compilation; SyntaxFacts syntaxFacts = compilation.Language.SyntaxFacts; var builder = ArrayBuilder <AliasAndExternAliasDirective> .GetInstance(); foreach (ExternAliasDirective aliasSyntax in directiveList) { compilation.RecordImport(aliasSyntax); // Extern aliases not allowed in interactive submissions: if (compilation.IsSubmission) { diagnostics.Add(InternalErrorCode.ERR_ExternAliasNotAllowed, aliasSyntax.Location); continue; } string aliasName = syntaxFacts.ExtractName(aliasSyntax.AliasName); // some n^2 action, but n should be very small. foreach (var existingAlias in builder) { if (existingAlias.Alias.Name == aliasName) { diagnostics.Add(InternalErrorCode.ERR_DuplicateAlias, existingAlias.Alias.Locations[0], existingAlias.Alias.Name); break; } } /* TODO:MetaDslx? * if (aliasSyntax.Identifier.ContextualKind() == SyntaxKind.GlobalKeyword) * { * diagnostics.Add(InternalErrorCode.ERR_GlobalExternAlias, aliasSyntax.Identifier.GetLocation()); * } */ builder.Add(new AliasAndExternAliasDirective(AliasSymbol.CreateExternAlias(aliasName, aliasSyntax, binder), aliasSyntax)); } return(builder.ToImmutableAndFree()); }
private static Binder CreateBinderChain( CSharpCompilation compilation, PEModuleSymbol module, NamespaceSymbol @namespace, ImmutableArray<ImmutableArray<ImportRecord>> importRecordGroups) { var stack = ArrayBuilder<string>.GetInstance(); while ((object)@namespace != null) { stack.Push(@namespace.Name); @namespace = @namespace.ContainingNamespace; } Binder binder = new BuckStopsHereBinder(compilation); var hasImports = !importRecordGroups.IsDefaultOrEmpty; var numImportStringGroups = hasImports ? importRecordGroups.Length : 0; var currentStringGroup = numImportStringGroups - 1; // PERF: We used to call compilation.GetCompilationNamespace on every iteration, // but that involved walking up to the global namespace, which we have to do // anyway. Instead, we'll inline the functionality into our own walk of the // namespace chain. @namespace = compilation.GlobalNamespace; while (stack.Count > 0) { var namespaceName = stack.Pop(); if (namespaceName.Length > 0) { // We're re-getting the namespace, rather than using the one containing // the current frame method, because we want the merged namespace. @namespace = @namespace.GetNestedNamespace(namespaceName); Debug.Assert((object)@namespace != null, $"We worked backwards from symbols to names, but no symbol exists for name '{namespaceName}'"); } else { Debug.Assert((object)@namespace == (object)compilation.GlobalNamespace); } Imports imports = null; if (hasImports) { if (currentStringGroup < 0) { Debug.WriteLine($"No import string group for namespace '{@namespace}'"); break; } var importsBinder = new InContainerBinder(@namespace, binder); imports = BuildImports(compilation, module, importRecordGroups[currentStringGroup], importsBinder); currentStringGroup--; } binder = new InContainerBinder(@namespace, binder, imports); } stack.Free(); if (currentStringGroup >= 0) { // CONSIDER: We could lump these into the outermost namespace. It's probably not worthwhile since // the usings are already for the wrong method. Debug.WriteLine($"Found {currentStringGroup + 1} import string groups without corresponding namespaces"); } return binder; }
private static bool TryAddImport( string alias, NamespaceOrTypeSymbol targetSymbol, ArrayBuilder<NamespaceOrTypeAndUsingDirective> usingsBuilder, ImmutableDictionary<string, AliasAndUsingDirective>.Builder usingAliases, InContainerBinder binder, ImportRecord importRecord) { if (alias == null) { usingsBuilder.Add(new NamespaceOrTypeAndUsingDirective(targetSymbol, usingDirective: null)); } else { IdentifierNameSyntax aliasSyntax; if (!TryParseIdentifierNameSyntax(alias, out aliasSyntax)) { Debug.WriteLine($"Import record '{importRecord}' has syntactically invalid alias '{alias}'"); return false; } var aliasSymbol = AliasSymbol.CreateCustomDebugInfoAlias(targetSymbol, aliasSyntax.Identifier, binder); usingAliases.Add(alias, new AliasAndUsingDirective(aliasSymbol, usingDirective: null)); } return true; }
internal static AliasSymbol CreateCustomDebugInfoAlias(NamespaceOrTypeSymbol targetSymbol, SyntaxToken aliasToken, InContainerBinder binder) { return(new AliasSymbol(binder, targetSymbol, aliasToken, ImmutableArray.Create(aliasToken.GetLocation()))); }
// For the purposes of SemanticModel, it is convenient to have an AliasSymbol for the "global" namespace that "global::" binds // to. This alias symbol is returned only when binding "global::" (special case code). internal static AliasSymbol CreateGlobalNamespaceAlias(NamespaceSymbol globalNamespace, InContainerBinder globalNamespaceBinder) { SyntaxToken aliasName = SyntaxFactory.Identifier(SyntaxFactory.TriviaList(), SyntaxKind.GlobalKeyword, "global", "global", SyntaxFactory.TriviaList()); return(new AliasSymbol(globalNamespaceBinder, globalNamespace, aliasName, ImmutableArray <Location> .Empty)); }
internal AliasSymbol(InContainerBinder binder, ExternAliasDirectiveSyntax syntax) : this(binder, syntax.Identifier) { _isExtern = true; }
internal AliasSymbol(InContainerBinder binder, UsingDirectiveSyntax syntax) : this(binder, syntax.Alias.Name.Identifier) { _aliasTargetName = syntax.Name; }
private static bool TryAddImport( string alias, NameSyntax targetSyntax, NamespaceOrTypeSymbol targetSymbol, ArrayBuilder<NamespaceOrTypeAndUsingDirective> usingsBuilder, Dictionary<string, AliasAndUsingDirective> usingAliases, InContainerBinder binder, string importString) { if (alias == null) { var usingSyntax = SyntaxFactory.UsingDirective(targetSyntax); usingsBuilder.Add(new NamespaceOrTypeAndUsingDirective(targetSymbol, usingSyntax)); } else { IdentifierNameSyntax aliasSyntax; if (!TryParseIdentifierNameSyntax(alias, out aliasSyntax)) { Debug.WriteLine("Import string '{0}' has syntactically invalid alias '{1}'", importString, alias); return false; } var usingSyntax = SyntaxFactory.UsingDirective(SyntaxFactory.NameEquals(aliasSyntax), targetSyntax); var aliasSymbol = AliasSymbol.CreateCustomDebugInfoAlias(targetSymbol, aliasSyntax.Identifier, binder); usingAliases.Add(alias, new AliasAndUsingDirective(aliasSymbol, usingSyntax)); } return true; }
private static Binder CreateBinderChain( CSharpCompilation compilation, NamespaceSymbol @namespace, ImmutableArray<ImmutableArray<string>> importStringGroups, MetadataDecoder metadataDecoder) { var stack = ArrayBuilder<string>.GetInstance(); while ((object)@namespace != null) { stack.Push(@namespace.Name); @namespace = @namespace.ContainingNamespace; } var binder = (new BuckStopsHereBinder(compilation)).WithAdditionalFlags( BinderFlags.SuppressObsoleteChecks | BinderFlags.SuppressAccessChecks | BinderFlags.UnsafeRegion | BinderFlags.UncheckedRegion | BinderFlags.AllowManagedAddressOf | BinderFlags.AllowAwaitInUnsafeContext); var hasImports = !importStringGroups.IsDefault; var numImportStringGroups = hasImports ? importStringGroups.Length : 0; var currentStringGroup = numImportStringGroups - 1; // PERF: We used to call compilation.GetCompilationNamespace on every iteration, // but that involved walking up to the global namespace, which we have to do // anyway. Instead, we'll inline the functionality into our own walk of the // namespace chain. @namespace = compilation.GlobalNamespace; while (stack.Count > 0) { var namespaceName = stack.Pop(); if (namespaceName.Length > 0) { // We're re-getting the namespace, rather than using the one containing // the current frame method, because we want the merged namespace. @namespace = @namespace.GetNestedNamespace(namespaceName); Debug.Assert((object)@namespace != null, "We worked backwards from symbols to names, but no symbol exists for name '" + namespaceName + "'"); } else { Debug.Assert((object)@namespace == (object)compilation.GlobalNamespace); } Imports imports = null; if (hasImports) { if (currentStringGroup < 0) { Debug.WriteLine("No import string group for namespace '{0}'", @namespace); break; } var importsBinder = new InContainerBinder(@namespace, binder); imports = BuildImports(compilation, importStringGroups[currentStringGroup], importsBinder, metadataDecoder); currentStringGroup--; } binder = new InContainerBinder(@namespace, binder, imports); } stack.Free(); if (currentStringGroup >= 0) { // CONSIDER: We could lump these into the outermost namespace. It's probably not worthwhile since // the usings are already for the wrong method. Debug.WriteLine("Found {0} import string groups without corresponding namespaces", currentStringGroup + 1); } return binder; }
private static NamespaceOrTypeSymbol ResolveAliasTarget(InContainerBinder binder, NameSyntax syntax, DiagnosticBag diagnostics, ConsList <Symbol> basesBeingResolved) { var declarationBinder = binder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks | BinderFlags.SuppressObsoleteChecks); return(declarationBinder.BindNamespaceOrTypeSymbol(syntax, diagnostics, basesBeingResolved)); }
internal override BoundBlock CreateBody(DiagnosticBag diagnostics) { var syntax = DummySyntax(); var compilation = _containingType.DeclaringCompilation; // Creates a new top-level binder that just contains the global imports for the compilation. // The imports are required if a consumer of the scripting API is using a Task implementation // that uses extension methods. var binder = new InContainerBinder( container: null, next: new BuckStopsHereBinder(compilation), imports: compilation.GlobalImports); binder = new InContainerBinder(compilation.GlobalNamespace, binder); var ctor = _containingType.GetScriptConstructor(); Debug.Assert(ctor.ParameterCount == 0); var initializer = _containingType.GetScriptInitializer(); Debug.Assert(initializer.ParameterCount == 0); var scriptLocal = new BoundLocal( syntax, new SynthesizedLocal(this, TypeWithAnnotations.Create(_containingType), SynthesizedLocalKind.LoweringTemp), null, _containingType) { WasCompilerGenerated = true }; Debug.Assert(!initializer.ReturnType.IsDynamic()); var initializeCall = CreateParameterlessCall(syntax, scriptLocal, initializer); BoundExpression getAwaiterGetResultCall; if (!binder.GetAwaitableExpressionInfo(initializeCall, out getAwaiterGetResultCall, syntax, diagnostics)) { return new BoundBlock( syntax: syntax, locals: ImmutableArray<LocalSymbol>.Empty, statements: ImmutableArray<BoundStatement>.Empty, hasErrors: true); } return new BoundBlock(syntax, ImmutableArray.Create<LocalSymbol>(scriptLocal.LocalSymbol), ImmutableArray.Create<BoundStatement>( // var script = new Script(); new BoundExpressionStatement( syntax, new BoundAssignmentOperator( syntax, scriptLocal, new BoundObjectCreationExpression( syntax, ctor, null) { WasCompilerGenerated = true }, _containingType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }, // script.<Initialize>().GetAwaiter().GetResult(); new BoundExpressionStatement(syntax, getAwaiterGetResultCall) { WasCompilerGenerated = true }, // return; new BoundReturnStatement( syntax, RefKind.None, null) { WasCompilerGenerated = true })) { WasCompilerGenerated = true }; }
public static Imports FromSyntax( LanguageSyntaxNode declarationSyntax, InContainerBinder binder, ConsList <TypeSymbol> basesBeingResolved, bool inUsing) { SyntaxFacts syntaxFacts = declarationSyntax.Language.SyntaxFacts; ImmutableArray <UsingDirective> usingDirectives = inUsing ? ImmutableArray <UsingDirective> .Empty : syntaxFacts.GetUsingDirectives(declarationSyntax); ImmutableArray <ExternAliasDirective> externAliasDirectives = syntaxFacts.GetExternAliasDirectives(declarationSyntax); if (usingDirectives.Length == 0 && externAliasDirectives.Length == 0) { return(Empty); } // define all of the extern aliases first. They may used by the target of a using // using Bar=Goo::Bar; // using Goo::Baz; // extern alias Goo; var diagnostics = new DiagnosticBag(); var compilation = binder.Compilation; var externAliases = BuildExternAliases(externAliasDirectives, binder, diagnostics); var usings = ArrayBuilder <NamespaceOrTypeAndUsingDirective> .GetInstance(); ImmutableDictionary <string, AliasAndUsingDirective> .Builder usingAliases = null; if (usingDirectives.Length > 0) { // A binder that contains the extern aliases but not the usings. The resolution of the target of a using directive or alias // should not make use of other peer usings. Binder usingsBinder; if (declarationSyntax.SyntaxTree.Options.Kind != SourceCodeKind.Regular) { usingsBinder = compilation.GetBinderFactory(declarationSyntax.SyntaxTree).GetImportsBinder(declarationSyntax, inUsing: true); } else { var imports = externAliases.Length == 0 ? Empty : new Imports( compilation, ImmutableDictionary <string, AliasAndUsingDirective> .Empty, ImmutableArray <NamespaceOrTypeAndUsingDirective> .Empty, externAliases, diagnostics: null); usingsBinder = new InContainerBinder(binder.Container, binder.Next, imports); } var uniqueUsings = PooledHashSet <NamespaceOrTypeSymbol> .GetInstance(); foreach (var usingDirective in usingDirectives) { compilation.RecordImport(usingDirective); if (usingDirective.AliasName != null) { if (usingDirective.IsGlobal) { diagnostics.Add(InternalErrorCode.WRN_GlobalAliasDefn, usingDirective.AliasName.GetLocation()); } if (usingDirective.IsStatic) { diagnostics.Add(InternalErrorCode.ERR_NoAliasHere, usingDirective.AliasName.GetLocation()); } string identifierValueText = syntaxFacts.ExtractName(usingDirective.AliasName); if (usingAliases != null && usingAliases.ContainsKey(identifierValueText)) { // Suppress diagnostics if we're already broken. if (!usingDirective.TargetName.IsMissing) { // The using alias '{0}' appeared previously in this namespace diagnostics.Add(InternalErrorCode.ERR_DuplicateAlias, usingDirective.AliasName.GetLocation(), identifierValueText); } } else { // an O(m*n) algorithm here but n (number of extern aliases) will likely be very small. foreach (var externAlias in externAliases) { if (externAlias.Alias.Name == identifierValueText) { // The using alias '{0}' appeared previously in this namespace diagnostics.Add(InternalErrorCode.ERR_DuplicateAlias, usingDirective.Location, identifierValueText); break; } } if (usingAliases == null) { usingAliases = ImmutableDictionary.CreateBuilder <string, AliasAndUsingDirective>(); } // construct the alias sym with the binder for which we are building imports. That // way the alias target can make use of extern alias definitions. usingAliases.Add(identifierValueText, new AliasAndUsingDirective(AliasSymbol.CreateUsing(identifierValueText, usingDirective, usingsBinder), usingDirective)); } } else { if (usingDirective.TargetName.IsMissing) { //don't try to lookup namespaces inserted by parser error recovery continue; } var declarationBinder = usingsBinder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks); var imported = declarationBinder.BindNamespaceOrTypeSymbol(usingDirective.TargetName, diagnostics, basesBeingResolved); if (imported.Kind == LanguageSymbolKind.Namespace) { if (usingDirective.IsStatic) { diagnostics.Add(InternalErrorCode.ERR_BadUsingType, usingDirective.TargetName.GetLocation(), imported); } else if (uniqueUsings.Contains(imported)) { diagnostics.Add(InternalErrorCode.WRN_DuplicateUsing, usingDirective.TargetName.GetLocation(), imported); } else { uniqueUsings.Add(imported); usings.Add(new NamespaceOrTypeAndUsingDirective(imported, usingDirective)); } } else if (imported.Kind == LanguageSymbolKind.NamedType) { if (usingDirective.IsStatic) { diagnostics.Add(InternalErrorCode.ERR_BadUsingNamespace, usingDirective.TargetName.GetLocation(), imported); } else { var importedType = (NamedTypeSymbol)imported; if (uniqueUsings.Contains(importedType)) { diagnostics.Add(InternalErrorCode.WRN_DuplicateUsing, usingDirective.TargetName.GetLocation(), importedType); } else { declarationBinder.ReportDiagnosticsIfObsolete(diagnostics, importedType, usingDirective.TargetName, hasBaseReceiver: false); uniqueUsings.Add(importedType); usings.Add(new NamespaceOrTypeAndUsingDirective(importedType, usingDirective)); } } } else if (imported.Kind != LanguageSymbolKind.ErrorType) { // Do not report additional error if the symbol itself is erroneous. // error: '<symbol>' is a '<symbol kind>' but is used as 'type or namespace' diagnostics.Add(InternalErrorCode.ERR_BadSKknown, usingDirective.TargetName.GetLocation(), usingDirective.TargetName, imported.GetKindText(), "type or namespace"); } } } uniqueUsings.Free(); } var boundSymbolDef = compilation.GetBoundNode <BoundSymbolDef>(declarationSyntax); if (boundSymbolDef != null) { foreach (var symbol in boundSymbolDef.Symbols) { var importProps = symbol.ModelSymbolInfo.Properties.Where(p => p.IsImport).ToImmutableArray(); foreach (var prop in importProps) { var boundProps = boundSymbolDef.GetChildProperties(prop.Name); foreach (var boundProp in boundProps) { foreach (var boundValue in boundProp.BoundValues) { foreach (var value in boundValue.Values) { var importedSymbol = value as NamespaceOrTypeSymbol; if (symbol != null) { bool isStaticImport = importedSymbol is NamedTypeSymbol; usings.Add(new NamespaceOrTypeAndUsingDirective(importedSymbol, new UsingDirective(declarationSyntax, null, boundValue.Syntax, isStaticImport, false))); } else { diagnostics.Add(ModelErrorCode.ERR_InvalidImport, boundValue.Syntax.Location, value); } } } } } } } if (diagnostics.IsEmptyWithoutResolution) { diagnostics = null; } return(new Imports(compilation, usingAliases.ToImmutableDictionaryOrEmpty(), usings.ToImmutableAndFree(), externAliases, diagnostics)); }
public static Imports FromGlobalUsings(LanguageCompilation compilation) { var usings = compilation.Options.Usings; if (usings.Length == 0 && compilation.PreviousSubmission == null) { return(Empty); } var diagnostics = new DiagnosticBag(); var usingsBinder = new InContainerBinder(compilation.GlobalNamespace, new BuckStopsHereBinder(compilation)); var boundUsings = ArrayBuilder <NamespaceOrTypeAndUsingDirective> .GetInstance(); var uniqueUsings = PooledHashSet <NamespaceOrTypeSymbol> .GetInstance(); var syntaxFacts = compilation.Language.SyntaxFacts; foreach (string @using in usings) { if ([email protected]()) { continue; } var qualifiedName = syntaxFacts.ExtractQualifiedName(@using); var imported = usingsBinder.BindNamespaceOrTypeSymbol(qualifiedName, diagnostics); if (uniqueUsings.Add(imported)) { boundUsings.Add(new NamespaceOrTypeAndUsingDirective(imported, null)); } } if (diagnostics.IsEmptyWithoutResolution) { diagnostics = null; } var previousSubmissionImports = compilation.PreviousSubmission?.GlobalImports; if (previousSubmissionImports != null) { // Currently, only usings are supported. Debug.Assert(previousSubmissionImports.UsingAliases.IsEmpty); Debug.Assert(previousSubmissionImports.ExternAliases.IsEmpty); var expandedImports = ExpandPreviousSubmissionImports(previousSubmissionImports, compilation); foreach (var previousUsing in expandedImports.Usings) { if (uniqueUsings.Add(previousUsing.NamespaceOrType)) { boundUsings.Add(previousUsing); } } } uniqueUsings.Free(); if (boundUsings.Count == 0) { boundUsings.Free(); return(Empty); } return(new Imports(compilation, ImmutableDictionary <string, AliasAndUsingDirective> .Empty, boundUsings.ToImmutableAndFree(), ImmutableArray <AliasAndExternAliasDirective> .Empty, diagnostics)); }
private static Binder ExtendBinderChain( CSharpSyntaxNode syntax, ImmutableArray<Alias> aliases, EEMethodSymbol method, Binder binder, bool hasDisplayClassThis, bool methodNotType, out ImmutableArray<LocalSymbol> declaredLocals) { var substitutedSourceMethod = GetSubstitutedSourceMethod(method.SubstitutedSourceMethod, hasDisplayClassThis); var substitutedSourceType = substitutedSourceMethod.ContainingType; var stack = ArrayBuilder<NamedTypeSymbol>.GetInstance(); for (var type = substitutedSourceType; (object)type != null; type = type.ContainingType) { stack.Add(type); } while (stack.Count > 0) { substitutedSourceType = stack.Pop(); binder = new InContainerBinder(substitutedSourceType, binder); if (substitutedSourceType.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceType.TypeArguments, binder); } } stack.Free(); if (substitutedSourceMethod.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceMethod.TypeArguments, binder); } // Method locals and parameters shadow pseudo-variables. // That is why we place PlaceholderLocalBinder and ExecutableCodeBinder before EEMethodBinder. if (methodNotType) { var typeNameDecoder = new EETypeNameDecoder(binder.Compilation, (PEModuleSymbol)substitutedSourceMethod.ContainingModule); binder = new PlaceholderLocalBinder( syntax, aliases, method, typeNameDecoder, binder); } Binder originalRootBinder = null; SyntaxNode declaredLocalsScopeDesignator = null; var executableBinder = new ExecutableCodeBinder(syntax, substitutedSourceMethod, binder, (rootBinder, declaredLocalsScopeDesignatorOpt) => { originalRootBinder = rootBinder; declaredLocalsScopeDesignator = declaredLocalsScopeDesignatorOpt; binder = new EEMethodBinder(method, substitutedSourceMethod, rootBinder); if (methodNotType) { binder = new SimpleLocalScopeBinder(method.LocalsForBinding, binder); } return binder; }); // We just need to trigger the process of building the binder map // so that the lambda above was executed. executableBinder.GetBinder(syntax); Debug.Assert(originalRootBinder != null); Debug.Assert(executableBinder.Next != binder); if (declaredLocalsScopeDesignator != null) { declaredLocals = originalRootBinder.GetDeclaredLocalsForScope(declaredLocalsScopeDesignator); } else { declaredLocals = ImmutableArray<LocalSymbol>.Empty; } return binder; }
private static Binder ExtendBinderChain( CSharpSyntaxNode syntax, ImmutableArray<Alias> aliases, EEMethodSymbol method, Binder binder, bool hasDisplayClassThis, bool methodNotType) { var substitutedSourceMethod = GetSubstitutedSourceMethod(method.SubstitutedSourceMethod, hasDisplayClassThis); var substitutedSourceType = substitutedSourceMethod.ContainingType; var stack = ArrayBuilder<NamedTypeSymbol>.GetInstance(); for (var type = substitutedSourceType; (object)type != null; type = type.ContainingType) { stack.Add(type); } while (stack.Count > 0) { substitutedSourceType = stack.Pop(); binder = new InContainerBinder(substitutedSourceType, binder); if (substitutedSourceType.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceType.TypeArguments, binder); } } stack.Free(); if (substitutedSourceMethod.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceMethod.TypeArguments, binder); } if (methodNotType) { // Method locals and parameters shadow pseudo-variables. var typeNameDecoder = new EETypeNameDecoder(binder.Compilation, (PEModuleSymbol)substitutedSourceMethod.ContainingModule); binder = new PlaceholderLocalBinder( syntax, aliases, method, typeNameDecoder, binder); } binder = new EEMethodBinder(method, substitutedSourceMethod, binder); if (methodNotType) { binder = new SimpleLocalScopeBinder(method.LocalsForBinding, binder); } return binder; }
private AliasSymbol(InContainerBinder binder, SyntaxToken aliasName) { _aliasName = aliasName; _locations = ImmutableArray.Create(aliasName.GetLocation()); _binder = binder; }
private static Imports BuildImports(CSharpCompilation compilation, PEModuleSymbol module, ImmutableArray<ImportRecord> importRecords, InContainerBinder binder) { // We make a first pass to extract all of the extern aliases because other imports may depend on them. var externsBuilder = ArrayBuilder<AliasAndExternAliasDirective>.GetInstance(); foreach (var importRecord in importRecords) { if (importRecord.TargetKind != ImportTargetKind.Assembly) { continue; } var alias = importRecord.Alias; IdentifierNameSyntax aliasNameSyntax; if (!TryParseIdentifierNameSyntax(alias, out aliasNameSyntax)) { Debug.WriteLine($"Import record '{importRecord}' has syntactically invalid extern alias '{alias}'"); continue; } var externAliasSyntax = SyntaxFactory.ExternAliasDirective(aliasNameSyntax.Identifier); var aliasSymbol = new AliasSymbol(binder, externAliasSyntax); // Binder is only used to access compilation. externsBuilder.Add(new AliasAndExternAliasDirective(aliasSymbol, externAliasDirective: null)); // We have one, but we pass null for consistency. } var externs = externsBuilder.ToImmutableAndFree(); if (externs.Any()) { // NB: This binder (and corresponding Imports) is only used to bind the other imports. // We'll merge the externs into a final Imports object and return that to be used in // the actual binder chain. binder = new InContainerBinder( binder.Container, binder, Imports.FromCustomDebugInfo(binder.Compilation, ImmutableDictionary<string, AliasAndUsingDirective>.Empty, ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty, externs)); } var usingAliases = ImmutableDictionary.CreateBuilder<string, AliasAndUsingDirective>(); var usingsBuilder = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance(); foreach (var importRecord in importRecords) { switch (importRecord.TargetKind) { case ImportTargetKind.Type: { TypeSymbol typeSymbol = (TypeSymbol)importRecord.TargetType; Debug.Assert((object)typeSymbol != null); if (typeSymbol.IsErrorType()) { // Type is unrecognized. The import may have been // valid in the original source but unnecessary. continue; // Don't add anything for this import. } else if (importRecord.Alias == null && !typeSymbol.IsStatic) { // Only static types can be directly imported. continue; } if (!TryAddImport(importRecord.Alias, typeSymbol, usingsBuilder, usingAliases, binder, importRecord)) { continue; } break; } case ImportTargetKind.Namespace: { var namespaceName = importRecord.TargetString; NameSyntax targetSyntax; if (!SyntaxHelpers.TryParseDottedName(namespaceName, out targetSyntax)) { // DevDiv #999086: Some previous version of VS apparently generated type aliases as "UA{alias} T{alias-qualified type name}". // Neither Roslyn nor Dev12 parses such imports. However, Roslyn discards them, rather than interpreting them as "UA{alias}" // (which will rarely work and never be correct). Debug.WriteLine($"Import record '{importRecord}' has syntactically invalid target '{importRecord.TargetString}'"); continue; } NamespaceSymbol globalNamespace; AssemblySymbol targetAssembly = (AssemblySymbol)importRecord.TargetAssembly; if (targetAssembly != null) { if (targetAssembly.IsMissing) { Debug.WriteLine($"Import record '{importRecord}' has invalid assembly reference '{targetAssembly.Identity}'"); continue; } globalNamespace = targetAssembly.GlobalNamespace; } else if (importRecord.TargetAssemblyAlias != null) { IdentifierNameSyntax externAliasSyntax = null; if (!TryParseIdentifierNameSyntax(importRecord.TargetAssemblyAlias, out externAliasSyntax)) { Debug.WriteLine($"Import record '{importRecord}' has syntactically invalid extern alias '{importRecord.TargetAssemblyAlias}'"); continue; } var unusedDiagnostics = DiagnosticBag.GetInstance(); var aliasSymbol = (AliasSymbol)binder.BindNamespaceAliasSymbol(externAliasSyntax, unusedDiagnostics); unusedDiagnostics.Free(); if ((object)aliasSymbol == null) { Debug.WriteLine($"Import record '{importRecord}' requires unknown extern alias '{importRecord.TargetAssemblyAlias}'"); continue; } globalNamespace = (NamespaceSymbol)aliasSymbol.Target; } else { globalNamespace = compilation.GlobalNamespace; } var namespaceSymbol = BindNamespace(namespaceName, globalNamespace); if ((object)namespaceSymbol == null) { // Namespace is unrecognized. The import may have been // valid in the original source but unnecessary. continue; // Don't add anything for this import. } if (!TryAddImport(importRecord.Alias, namespaceSymbol, usingsBuilder, usingAliases, binder, importRecord)) { continue; } break; } case ImportTargetKind.Assembly: { // Handled in first pass (above). break; } default: { throw ExceptionUtilities.UnexpectedValue(importRecord.TargetKind); } } } return Imports.FromCustomDebugInfo(binder.Compilation, usingAliases.ToImmutableDictionary(), usingsBuilder.ToImmutableAndFree(), externs); }
private static Imports BuildImports(CSharpCompilation compilation, ImmutableArray<string> importStrings, InContainerBinder binder, MetadataDecoder metadataDecoder) { // We make a first pass to extract all of the extern aliases because other imports may depend on them. var externsBuilder = ArrayBuilder<AliasAndExternAliasDirective>.GetInstance(); foreach (var importString in importStrings) { string alias; string externAlias; string target; ImportTargetKind kind; if (!CustomDebugInfoReader.TryParseCSharpImportString(importString, out alias, out externAlias, out target, out kind)) { Debug.WriteLine("Unable to parse import string '{0}'", (object)importString); continue; } else if (kind != ImportTargetKind.Assembly) { continue; } Debug.Assert(alias == null); Debug.Assert(externAlias != null); Debug.Assert(target == null); NameSyntax aliasNameSyntax; if (!SyntaxHelpers.TryParseDottedName(externAlias, out aliasNameSyntax) || aliasNameSyntax.Kind() != SyntaxKind.IdentifierName) { Debug.WriteLine("Import string '{0}' has syntactically invalid extern alias '{1}'", importString, externAlias); continue; } var aliasToken = ((IdentifierNameSyntax)aliasNameSyntax).Identifier; var externAliasSyntax = SyntaxFactory.ExternAliasDirective(aliasToken); var aliasSymbol = new AliasSymbol(binder, externAliasSyntax); // Binder is only used to access compilation. externsBuilder.Add(new AliasAndExternAliasDirective(aliasSymbol, externAliasSyntax)); } var externs = externsBuilder.ToImmutableAndFree(); if (externs.Any()) { // NB: This binder (and corresponding Imports) is only used to bind the other imports. // We'll merge the externs into a final Imports object and return that to be used in // the actual binder chain. binder = new InContainerBinder( binder.Container, binder, Imports.FromCustomDebugInfo(binder.Compilation, new Dictionary<string, AliasAndUsingDirective>(), ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty, externs)); } var usingAliases = new Dictionary<string, AliasAndUsingDirective>(); var usingsBuilder = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance(); foreach (var importString in importStrings) { string alias; string externAlias; string target; ImportTargetKind kind; if (!CustomDebugInfoReader.TryParseCSharpImportString(importString, out alias, out externAlias, out target, out kind)) { Debug.WriteLine("Unable to parse import string '{0}'", (object)importString); continue; } switch (kind) { case ImportTargetKind.Type: { Debug.Assert(target != null, string.Format("Type import string '{0}' has no target", importString)); Debug.Assert(externAlias == null, string.Format("Type import string '{0}' has an extern alias (should be folded into target)", importString)); TypeSymbol typeSymbol = metadataDecoder.GetTypeSymbolForSerializedType(target); Debug.Assert((object)typeSymbol != null); if (typeSymbol.IsErrorType()) { // Type is unrecognized. The import may have been // valid in the original source but unnecessary. continue; // Don't add anything for this import. } else if (alias == null && !typeSymbol.IsStatic) { // Only static types can be directly imported. continue; } NameSyntax typeSyntax = SyntaxFactory.ParseName(typeSymbol.ToDisplayString(s_fullNameFormat)); if (!TryAddImport(alias, typeSyntax, typeSymbol, usingsBuilder, usingAliases, binder, importString)) { continue; } break; } case ImportTargetKind.Namespace: { Debug.Assert(target != null, string.Format("Namespace import string '{0}' has no target", importString)); NameSyntax targetSyntax; if (!SyntaxHelpers.TryParseDottedName(target, out targetSyntax)) { // DevDiv #999086: Some previous version of VS apparently generated type aliases as "UA{alias} T{alias-qualified type name}". // Neither Roslyn nor Dev12 parses such imports. However, Roslyn discards them, rather than interpreting them as "UA{alias}" // (which will rarely work and never be correct). Debug.WriteLine("Import string '{0}' has syntactically invalid target '{1}'", importString, target); continue; } if (externAlias != null) { IdentifierNameSyntax externAliasSyntax; if (!TryParseIdentifierNameSyntax(externAlias, out externAliasSyntax)) { Debug.WriteLine("Import string '{0}' has syntactically invalid extern alias '{1}'", importString, externAlias); continue; } // This is the case that requires the binder to already know about extern aliases. targetSyntax = SyntaxHelpers.PrependExternAlias(externAliasSyntax, targetSyntax); } var unusedDiagnostics = DiagnosticBag.GetInstance(); var namespaceSymbol = binder.BindNamespaceOrType(targetSyntax, unusedDiagnostics).ExpressionSymbol as NamespaceSymbol; unusedDiagnostics.Free(); if ((object)namespaceSymbol == null) { // Namespace is unrecognized. The import may have been // valid in the original source but unnecessary. continue; // Don't add anything for this import. } if (!TryAddImport(alias, targetSyntax, namespaceSymbol, usingsBuilder, usingAliases, binder, importString)) { continue; } break; } case ImportTargetKind.Assembly: { // Handled in first pass (above). break; } default: { throw ExceptionUtilities.UnexpectedValue(kind); } } } return Imports.FromCustomDebugInfo(binder.Compilation, usingAliases, usingsBuilder.ToImmutableAndFree(), externs); }