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