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