public static bool IsMemberDeclarationContext( this SyntaxTree syntaxTree, int position, CSharpSyntaxContext contextOpt, ISet<SyntaxKind> validModifiers, ISet<SyntaxKind> validTypeDeclarations, bool canBePartial, CancellationToken cancellationToken) { var typeDecl = contextOpt != null ? contextOpt.ContainingTypeOrEnumDeclaration : syntaxTree.GetContainingTypeOrEnumDeclaration(position, cancellationToken); if (typeDecl == null) { return false; } if (!validTypeDeclarations.Contains(typeDecl.Kind())) { return false; } validTypeDeclarations = validTypeDeclarations ?? SpecializedCollections.EmptySet<SyntaxKind>(); // Check many of the simple cases first. var leftToken = contextOpt != null ? contextOpt.LeftToken : syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken); if (syntaxTree.IsMemberDeclarationContext(position, leftToken, cancellationToken)) { return true; } var token = contextOpt != null ? contextOpt.TargetToken : leftToken.GetPreviousTokenIfTouchingWord(position); // A member can also show up after certain types of modifiers if (canBePartial && token.IsKindOrHasMatchingText(SyntaxKind.PartialKeyword)) { return true; } var modifierTokens = contextOpt != null ? contextOpt.PrecedingModifiers : syntaxTree.GetPrecedingModifiers(position, leftToken, cancellationToken); if (!modifierTokens.Any()) { return false; } validModifiers = validModifiers ?? SpecializedCollections.EmptySet<SyntaxKind>(); if (modifierTokens.IsSubsetOf(validModifiers)) { var member = token.Parent; if (token.HasMatchingText(SyntaxKind.AsyncKeyword)) { // second appearance of "async", not followed by modifier: treat it as type if (syntaxTree.GetPrecedingModifiers(token.SpanStart, token, cancellationToken).Any(x => x == SyntaxKind.AsyncKeyword)) { return false; } // rule out async lambdas inside a method if (token.GetAncestor<StatementSyntax>() == null) { member = token.GetAncestor<MemberDeclarationSyntax>(); } } // cases: // public | // async | // public async | return member != null && member.Parent is BaseTypeDeclarationSyntax; } return false; }
public static bool IsTypeDeclarationContext( this SyntaxTree syntaxTree, int position, CSharpSyntaxContext contextOpt, ISet<SyntaxKind> validModifiers, ISet<SyntaxKind> validTypeDeclarations, bool canBePartial, CancellationToken cancellationToken) { // We only allow nested types inside a class or struct, not inside a // an interface or enum. var typeDecl = contextOpt != null ? contextOpt.ContainingTypeDeclaration : syntaxTree.GetContainingTypeDeclaration(position, cancellationToken); validTypeDeclarations = validTypeDeclarations ?? SpecializedCollections.EmptySet<SyntaxKind>(); if (typeDecl != null) { if (!validTypeDeclarations.Contains(typeDecl.Kind())) { return false; } } // Check many of the simple cases first. var leftToken = contextOpt != null ? contextOpt.LeftToken : syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken); if (syntaxTree.IsTypeDeclarationContext(position, leftToken, cancellationToken)) { return true; } // If we're touching the right of an identifier, move back to // previous token. var token = contextOpt != null ? contextOpt.TargetToken : leftToken.GetPreviousTokenIfTouchingWord(position); // A type can also show up after certain types of modifiers if (canBePartial && token.IsKindOrHasMatchingText(SyntaxKind.PartialKeyword)) { return true; } // using static | is never a type declaration context if (token.IsStaticKeywordInUsingDirective()) { return false; } var modifierTokens = contextOpt != null ? contextOpt.PrecedingModifiers : syntaxTree.GetPrecedingModifiers(position, leftToken, cancellationToken); if (!modifierTokens.Any()) { return false; } validModifiers = validModifiers ?? SpecializedCollections.EmptySet<SyntaxKind>(); if (modifierTokens.IsProperSubsetOf(validModifiers)) { // the parent is the member // the grandparent is the container of the member var container = token.Parent.GetParent(); if (container.IsKind(SyntaxKind.CompilationUnit) || container.IsKind(SyntaxKind.NamespaceDeclaration) || container.IsKind(SyntaxKind.ClassDeclaration) || container.IsKind(SyntaxKind.StructDeclaration)) { return true; } } return false; }
SyntaxContext(CSharpSyntaxContext ctx, List<ITypeSymbol> inferredTypes) { this.inferredTypes = inferredTypes; this.ctx = ctx; }