Esempio n. 1
0
        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));
        }