示例#1
0
        internal static bool IsValidScopeDesignator(this ExpressionSyntax expression)
        {
            // All these nodes are valid scope designators due to the pattern matching and out vars features.
            CSharpSyntaxNode parent = expression?.Parent;

            switch (parent?.Kind())
            {
            case SyntaxKind.SimpleLambdaExpression:
            case SyntaxKind.ParenthesizedLambdaExpression:
                return(((LambdaExpressionSyntax)parent).Body == expression);

            case SyntaxKind.SwitchStatement:
                return(((SwitchStatementSyntax)parent).Expression == expression);

            case SyntaxKind.ForStatement:
                return(((ForStatementSyntax)parent).Expression == expression);

            default:
                return(false);
            }
        }
示例#2
0
        private void VisitLambdaExpression(LambdaExpressionSyntax node)
        {
            // Do not descend into a lambda unless it is a root node
            if (_root != node)
            {
                return;
            }

            CSharpSyntaxNode body = node.Body;

            if (body.Kind() == SyntaxKind.Block)
            {
                VisitBlock((BlockSyntax)body);
            }
            else
            {
                var binder = new ExpressionVariableBinder(body, _enclosing);
                AddToMap(body, binder);
                Visit(body, binder);
            }
        }
        internal protected override CSharpSyntaxNode GetBindableSyntaxNode(CSharpSyntaxNode node)
        {
            switch (node.Kind())
            {
            case SyntaxKind.Attribute:
                return(node);

            case SyntaxKind.AttributeArgument:
                // Try to walk up to the AttributeSyntax
                var parent = node.Parent;
                if (parent != null)
                {
                    parent = parent.Parent;
                    if (parent != null)
                    {
                        return(parent);
                    }
                }
                break;
            }

            return(base.GetBindableSyntaxNode(node));
        }
示例#4
0
        // An anonymous function can be of the form:
        //
        // delegate { }              (missing parameter list)
        // delegate (int x) { }      (typed parameter list)
        // x => ...                  (type-inferred parameter list)
        // (x) => ...                (type-inferred parameter list)
        // (x, y) => ...             (type-inferred parameter list)
        // ( ) => ...                (typed parameter list)
        // (ref int x) => ...        (typed parameter list)
        // (int x, out int y) => ... (typed parameter list)
        //
        // and so on. We want to canonicalize these various ways of writing the signatures.
        //
        // If we are in the first case then the name, modifier and type arrays are all null.
        // If we have a parameter list then the names array is non-null, but possibly empty.
        // If we have types then the types array is non-null, but possibly empty.
        // If we have no modifiers then the modifiers array is null; if we have any modifiers
        // then the modifiers array is non-null and not empty.

        private Tuple <ImmutableArray <RefKind>, ImmutableArray <TypeSymbolWithAnnotations>, ImmutableArray <string>, bool> AnalyzeAnonymousFunction(
            CSharpSyntaxNode syntax, DiagnosticBag diagnostics)
        {
            Debug.Assert(syntax != null);
            Debug.Assert(syntax.IsAnonymousFunction());

            var  names    = default(ImmutableArray <string>);
            var  refKinds = default(ImmutableArray <RefKind>);
            var  types    = default(ImmutableArray <TypeSymbolWithAnnotations>);
            bool isAsync  = false;

            var namesBuilder = ArrayBuilder <string> .GetInstance();

            SeparatedSyntaxList <ParameterSyntax>?parameterSyntaxList = null;
            bool hasSignature;

            switch (syntax.Kind())
            {
            default:
            case SyntaxKind.SimpleLambdaExpression:
                // x => ...
                hasSignature = true;
                var simple = (SimpleLambdaExpressionSyntax)syntax;
                namesBuilder.Add(simple.Parameter.Identifier.ValueText);
                isAsync = (simple.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword);
                break;

            case SyntaxKind.ParenthesizedLambdaExpression:
                // (T x, U y) => ...
                // (x, y) => ...
                hasSignature = true;
                var paren = (ParenthesizedLambdaExpressionSyntax)syntax;
                parameterSyntaxList = paren.ParameterList.Parameters;
                CheckParenthesizedLambdaParameters(parameterSyntaxList.Value, diagnostics);
                isAsync = (paren.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword);
                break;

            case SyntaxKind.AnonymousMethodExpression:
                // delegate (int x) { }
                // delegate { }
                var anon = (AnonymousMethodExpressionSyntax)syntax;
                hasSignature = anon.ParameterList != null;
                if (hasSignature)
                {
                    parameterSyntaxList = anon.ParameterList.Parameters;
                }
                isAsync = (anon.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword);
                break;
            }

            if (parameterSyntaxList != null)
            {
                var hasExplicitlyTypedParameterList = true;
                var allValue = true;

                var typesBuilder = ArrayBuilder <TypeSymbolWithAnnotations> .GetInstance();

                var refKindsBuilder = ArrayBuilder <RefKind> .GetInstance();

                // In the batch compiler case we probably should have given a syntax error if the
                // user did something like (int x, y)=>x+y -- but in the IDE scenario we might be in
                // this case. If we are, then rather than try to make partial deductions from the
                // typed formal parameters, simply bail out and treat it as an untyped lambda.
                //
                // However, we still want to give errors on every bad type in the list, even if one
                // is missing.

                foreach (var p in parameterSyntaxList.Value)
                {
                    foreach (var attributeList in p.AttributeLists)
                    {
                        Error(diagnostics, ErrorCode.ERR_AttributesNotAllowed, attributeList);
                    }

                    if (p.Default != null)
                    {
                        Error(diagnostics, ErrorCode.ERR_DefaultValueNotAllowed, p.Default.EqualsToken);
                    }

                    if (p.IsArgList)
                    {
                        Error(diagnostics, ErrorCode.ERR_IllegalVarArgs, p);
                        continue;
                    }

                    var typeSyntax = p.Type;
                    TypeSymbolWithAnnotations type = default;
                    var refKind = RefKind.None;

                    if (typeSyntax == null)
                    {
                        hasExplicitlyTypedParameterList = false;
                    }
                    else
                    {
                        var extendedSyntax = typeSyntax as ExtendedTypeSyntax;
                        type = BindType(typeSyntax, diagnostics);
                        if (extendedSyntax != null)
                        {
                            foreach (var modifier in extendedSyntax.Modifiers)
                            {
                                switch (modifier.Kind())
                                {
                                case SyntaxKind.RefKeyword:
                                    refKind  = RefKind.Ref;
                                    allValue = false;
                                    break;

                                case SyntaxKind.OutKeyword:
                                    refKind  = RefKind.Out;
                                    allValue = false;
                                    break;

                                case SyntaxKind.InKeyword:
                                    refKind  = RefKind.In;
                                    allValue = false;
                                    break;

                                case SyntaxKind.ParamsKeyword:
                                    // This was a parse error in the native compiler;
                                    // it is a semantic analysis error in Roslyn. See comments to
                                    // changeset 1674 for details.
                                    Error(diagnostics, ErrorCode.ERR_IllegalParams, p);
                                    break;

                                case SyntaxKind.ThisKeyword:
                                    Error(diagnostics, ErrorCode.ERR_ThisInBadContext, modifier);
                                    break;
                                }
                            }
                        }
                    }

                    namesBuilder.Add(p.Identifier.ValueText);
                    typesBuilder.Add(type);
                    refKindsBuilder.Add(refKind);
                }

                if (hasExplicitlyTypedParameterList)
                {
                    types = typesBuilder.ToImmutable();
                }

                if (!allValue)
                {
                    refKinds = refKindsBuilder.ToImmutable();
                }

                typesBuilder.Free();
                refKindsBuilder.Free();
            }

            if (hasSignature)
            {
                names = namesBuilder.ToImmutable();
            }

            namesBuilder.Free();

            return(Tuple.Create(refKinds, types, names, isAsync));
        }
示例#5
0
        internal static ImmutableArray <DocumentationCommentTriviaSyntax> GetDocumentationCommentTriviaFromSyntaxNode(CSharpSyntaxNode syntaxNode, DiagnosticBag diagnostics)
        {
            if (syntaxNode.SyntaxTree.Options.DocumentationMode < DocumentationMode.Parse)
            {
                return(ImmutableArray <DocumentationCommentTriviaSyntax> .Empty);
            }

            // All declarators in a declaration get the same doc comment.
            // (As a consequence, the same duplicate diagnostics are produced for each declarator.)
            if (syntaxNode.Kind() == SyntaxKind.VariableDeclaration)
            {
                CSharpSyntaxNode curr = syntaxNode;
                while ((object)curr != null)
                {
                    SyntaxKind kind = curr.Kind();
                    if (kind == SyntaxKind.FieldDeclaration || kind == SyntaxKind.EventFieldDeclaration)
                    {
                        break;
                    }

                    curr = curr.Parent;
                }

                if ((object)curr != null)
                {
                    syntaxNode = curr;
                }
            }

            ArrayBuilder <DocumentationCommentTriviaSyntax> builder = null;
            bool seenOtherTrivia = false;

            foreach (var trivia in syntaxNode.GetLeadingTrivia().Reverse())
            {
                switch (trivia.Kind())
                {
                case SyntaxKind.SingleLineDocumentationCommentTrivia:
                case SyntaxKind.MultiLineDocumentationCommentTrivia:
                {
                    if (seenOtherTrivia)
                    {
                        // In most cases, unprocessed doc comments are reported by UnprocessedDocumentationCommentFinder.
                        // However, in places where doc comments *are* allowed, it's easier to determine which will
                        // be unprocessed here.
                        var tree = (SyntaxTree)trivia.SyntaxTree;
                        if (tree.ReportDocumentationCommentDiagnostics())
                        {
                            int       start  = trivia.Position; // FullSpan start to include /** or ///
                            const int length = 1;               //Match dev11: span is just one character
                            diagnostics.Add(ErrorCode.WRN_UnprocessedXMLComment, new SourceLocation(tree, new TextSpan(start, length)));
                        }
                    }
                    else
                    {
                        if (builder == null)
                        {
                            builder = ArrayBuilder <DocumentationCommentTriviaSyntax> .GetInstance();
                        }

                        builder.Add((DocumentationCommentTriviaSyntax)trivia.GetStructure());
                    }
                    break;
                }

                case SyntaxKind.WhitespaceTrivia:
                case SyntaxKind.EndOfLineTrivia:
                    // These can legally appear between doc comments.
                    break;

                default:
                    // For some reason, dev11 ignores trivia between the last doc comment and the
                    // symbol declaration.  (e.g. can have regular comment between doc comment and decl).
                    if (builder != null)
                    {
                        seenOtherTrivia = true;
                    }
                    break;
                }
            }

            if (builder == null)
            {
                return(ImmutableArray <DocumentationCommentTriviaSyntax> .Empty);
            }

            builder.ReverseContents();
            return(builder.ToImmutableAndFree());
        }
示例#6
0
        public static Imports FromSyntax(
            CSharpSyntaxNode declarationSyntax,
            InContainerBinder binder,
            ConsList <TypeSymbol> basesBeingResolved,
            bool inUsing)
        {
            SyntaxList <ImportDirectiveSyntax>      usingDirectives;
            SyntaxList <ExternAliasDirectiveSyntax> externAliasDirectives;

            if (declarationSyntax.Kind() == SyntaxKind.CompilationUnit)
            {
                var compilationUnit = (CompilationUnitSyntax)declarationSyntax;
                // using directives are not in scope within using directives
                usingDirectives       = inUsing ? default(SyntaxList <ImportDirectiveSyntax>) : compilationUnit.Usings;
                externAliasDirectives = compilationUnit.Externs;
            }
            else if (declarationSyntax.Kind() == SyntaxKind.NamespaceDeclaration)
            {
                var namespaceDecl = (NamespaceDeclarationSyntax)declarationSyntax;
                // using directives are not in scope within using directives
                usingDirectives       = inUsing ? default(SyntaxList <ImportDirectiveSyntax>) : namespaceDecl.Usings;
                externAliasDirectives = namespaceDecl.Externs;
            }
            else
            {
                return(Empty);
            }

            if (usingDirectives.Count == 0 && externAliasDirectives.Count == 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 <NamespaceOrTypeAndImportDirective> .GetInstance();

            ImmutableDictionary <string, AliasAndImportDirective> .Builder usingAliases = null;
            if (usingDirectives.Count > 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, AliasAndImportDirective> .Empty,
                        ImmutableArray <NamespaceOrTypeAndImportDirective> .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.Alias != null)
                    {
                        if (usingDirective.Alias.Name.Identifier.ContextualKind() == SyntaxKind.GlobalKeyword)
                        {
                            diagnostics.Add(ErrorCode.WRN_GlobalAliasDefn, usingDirective.Alias.Name.Location);
                        }

                        if (usingDirective.StaticKeyword != default(SyntaxToken))
                        {
                            diagnostics.Add(ErrorCode.ERR_NoAliasHere, usingDirective.Alias.Name.Location);
                        }

                        string identifierValueText = usingDirective.Alias.Name.Identifier.ValueText;
                        if (usingAliases != null && usingAliases.ContainsKey(identifierValueText))
                        {
                            // Suppress diagnostics if we're already broken.
                            if (!usingDirective.Name.IsMissing)
                            {
                                // The using alias '{0}' appeared previously in this namespace
                                diagnostics.Add(ErrorCode.ERR_DuplicateAlias, usingDirective.Alias.Name.Location, 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(ErrorCode.ERR_DuplicateAlias, usingDirective.Location, identifierValueText);
                                    break;
                                }
                            }

                            if (usingAliases == null)
                            {
                                usingAliases = ImmutableDictionary.CreateBuilder <string, AliasAndImportDirective>();
                            }

                            // 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 AliasAndImportDirective(new AliasSymbol(usingsBinder, usingDirective), usingDirective));
                        }
                    }
                    else
                    {
                        if (usingDirective.Name.IsMissing)
                        {
                            //don't try to lookup namespaces inserted by parser error recovery
                            continue;
                        }

                        var declarationBinder = usingsBinder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks);
                        var imported          = declarationBinder.BindNamespaceOrTypeSymbol(usingDirective.Name, diagnostics, basesBeingResolved).NamespaceOrTypeSymbol;
                        if (imported.Kind == SymbolKind.Namespace)
                        {
                            if (usingDirective.StaticKeyword != default(SyntaxToken))
                            {
                                diagnostics.Add(ErrorCode.ERR_BadUsingType, usingDirective.Name.Location, imported);
                            }
                            else if (uniqueUsings.Contains(imported))
                            {
                                diagnostics.Add(ErrorCode.WRN_DuplicateUsing, usingDirective.Name.Location, imported);
                            }
                            else
                            {
                                uniqueUsings.Add(imported);
                                usings.Add(new NamespaceOrTypeAndImportDirective(imported, usingDirective));
                            }
                        }
                        else if (imported.Kind == SymbolKind.NamedType)
                        {
                            var importedType = (NamedTypeSymbol)imported;
                            if (uniqueUsings.Contains(importedType))
                            {
                                diagnostics.Add(ErrorCode.WRN_DuplicateUsing, usingDirective.Name.Location, importedType);
                            }
                            else
                            {
                                declarationBinder.ReportDiagnosticsIfObsolete(diagnostics, importedType, usingDirective.Name, hasBaseReceiver: false);

                                uniqueUsings.Add(importedType);
                                usings.Add(new NamespaceOrTypeAndImportDirective(importedType, usingDirective));
                            }
                        }
                        else if (imported.Kind != SymbolKind.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(ErrorCode.ERR_BadSKknown, usingDirective.Name.Location,
                                            usingDirective.Name,
                                            imported.GetKindText(),
                                            MessageID.IDS_SK_TYPE_OR_NAMESPACE.Localize());
                        }
                    }
                }

                uniqueUsings.Free();
            }

            if (diagnostics.IsEmptyWithoutResolution)
            {
                diagnostics = null;
            }

            return(new Imports(compilation, usingAliases.ToImmutableDictionaryOrEmpty(), usings.ToImmutableAndFree(), externAliases, diagnostics));
        }