// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.LanguageServices { internal interface ISyntaxFactsService : ILanguageService { bool IsCaseSensitive { get; } StringComparer StringComparer { get; } SyntaxTrivia ElasticMarker { get; } SyntaxTrivia ElasticCarriageReturnLineFeed { get; } ISyntaxKindsService SyntaxKinds { get; } bool SupportsIndexingInitializer(ParseOptions options); bool SupportsThrowExpression(ParseOptions options); SyntaxToken ParseToken(string text); bool IsAwaitKeyword(SyntaxToken token); bool IsIdentifier(SyntaxToken token); bool IsGlobalNamespaceKeyword(SyntaxToken token); bool IsVerbatimIdentifier(SyntaxToken token); bool IsOperator(SyntaxToken token); bool IsPredefinedType(SyntaxToken token); bool IsPredefinedType(SyntaxToken token, PredefinedType type); bool IsPredefinedOperator(SyntaxToken token); bool IsPredefinedOperator(SyntaxToken token, PredefinedOperator op); /// /// Returns 'true' if this a 'reserved' keyword for the language. A 'reserved' keyword is a /// identifier that is always treated as being a special keyword, regardless of where it is /// found in the token stream. Examples of this are tokens like and /// in C# and VB respectively. /// /// Importantly, this does *not* include contextual keywords. If contextual keywords are /// important for your scenario, use or . Also, consider using /// if all you need is the ability to know /// if this is effectively any identifier in the language, regardless of whether the language /// is treating it as a keyword or not. /// bool IsReservedKeyword(SyntaxToken token); /// /// Returns if this a 'contextual' keyword for the language. A /// 'contextual' keyword is a identifier that is only treated as being a special keyword in /// certain *syntactic* contexts. Examples of this is 'yield' in C#. This is only a /// keyword if used as 'yield return' or 'yield break'. Importantly, identifiers like , and are *not* /// 'contextual' keywords. This is because they are not treated as keywords depending on /// the syntactic context around them. Instead, the language always treats them identifiers /// that have special *semantic* meaning if they end up not binding to an existing symbol. /// /// Importantly, if is not in the syntactic construct where the /// language thinks an identifier should be contextually treated as a keyword, then this /// will return . /// /// Or, in other words, the parser must be able to identify these cases in order to be a /// contextual keyword. If identification happens afterwards, it's not contextual. /// bool IsContextualKeyword(SyntaxToken token); /// /// The set of identifiers that have special meaning directly after the `#` token in a /// preprocessor directive. For example `if` or `pragma`. /// bool IsPreprocessorKeyword(SyntaxToken token); bool IsHashToken(SyntaxToken token); bool IsLiteral(SyntaxToken token); bool IsStringLiteralOrInterpolatedStringLiteral(SyntaxToken token); bool IsNumericLiteral(SyntaxToken token); bool IsCharacterLiteral(SyntaxToken token); bool IsStringLiteral(SyntaxToken token); bool IsVerbatimStringLiteral(SyntaxToken token); bool IsInterpolatedStringTextToken(SyntaxToken token); bool IsStringLiteralExpression(SyntaxNode node); bool IsTypeNamedVarInVariableOrFieldDeclaration(SyntaxToken token, SyntaxNode parent); bool IsTypeNamedDynamic(SyntaxToken token, SyntaxNode parent); bool IsUsingOrExternOrImport(SyntaxNode node); bool IsGlobalAttribute(SyntaxNode node); bool IsDeclaration(SyntaxNode node); bool IsTypeDeclaration(SyntaxNode node); bool IsRegularComment(SyntaxTrivia trivia); bool IsDocumentationComment(SyntaxTrivia trivia); bool IsElastic(SyntaxTrivia trivia); bool IsDocumentationComment(SyntaxNode node); bool IsNumericLiteralExpression(SyntaxNode node); bool IsNullLiteralExpression(SyntaxNode node); bool IsDefaultLiteralExpression(SyntaxNode node); bool IsLiteralExpression(SyntaxNode node); bool IsFalseLiteralExpression(SyntaxNode node); bool IsTrueLiteralExpression(SyntaxNode node); bool IsThisExpression(SyntaxNode node); bool IsBaseExpression(SyntaxNode node); string GetText(int kind); bool IsInInactiveRegion(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken); bool IsInNonUserCode(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken); bool IsEntirelyWithinStringOrCharOrNumericLiteral(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken); bool IsPossibleTupleContext(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken); bool TryGetPredefinedType(SyntaxToken token, out PredefinedType type); bool TryGetPredefinedOperator(SyntaxToken token, out PredefinedOperator op); bool TryGetExternalSourceInfo(SyntaxNode directive, out ExternalSourceInfo info); bool IsObjectCreationExpressionType(SyntaxNode node); bool IsObjectCreationExpression(SyntaxNode node); SyntaxNode GetObjectCreationInitializer(SyntaxNode node); SyntaxNode GetObjectCreationType(SyntaxNode node); bool IsBinaryExpression(SyntaxNode node); void GetPartsOfBinaryExpression(SyntaxNode node, out SyntaxNode left, out SyntaxToken operatorToken, out SyntaxNode right); void GetPartsOfConditionalExpression(SyntaxNode node, out SyntaxNode condition, out SyntaxNode whenTrue, out SyntaxNode whenFalse); bool IsCastExpression(SyntaxNode node); void GetPartsOfCastExpression(SyntaxNode node, out SyntaxNode type, out SyntaxNode expression); bool IsInvocationExpression(SyntaxNode node); bool IsExpressionOfInvocationExpression(SyntaxNode node); void GetPartsOfInvocationExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxNode argumentList); SyntaxNode GetExpressionOfExpressionStatement(SyntaxNode node); bool IsAwaitExpression(SyntaxNode node); bool IsExpressionOfAwaitExpression(SyntaxNode node); SyntaxNode GetExpressionOfAwaitExpression(SyntaxNode node); bool IsLogicalAndExpression(SyntaxNode node); bool IsLogicalOrExpression(SyntaxNode node); bool IsLogicalNotExpression(SyntaxNode node); bool IsConditionalAnd(SyntaxNode node); bool IsConditionalOr(SyntaxNode node); bool IsTupleExpression(SyntaxNode node); void GetPartsOfTupleExpression(SyntaxNode node, out SyntaxToken openParen, out SeparatedSyntaxList arguments, out SyntaxToken closeParen) where TArgumentSyntax : SyntaxNode; bool IsTupleType(SyntaxNode node); SyntaxNode GetOperandOfPrefixUnaryExpression(SyntaxNode node); SyntaxToken GetOperatorTokenOfPrefixUnaryExpression(SyntaxNode node); // Left side of = assignment. bool IsLeftSideOfAssignment(SyntaxNode node); bool IsSimpleAssignmentStatement(SyntaxNode statement); void GetPartsOfAssignmentStatement(SyntaxNode statement, out SyntaxNode left, out SyntaxToken operatorToken, out SyntaxNode right); void GetPartsOfAssignmentExpressionOrStatement(SyntaxNode statement, out SyntaxNode left, out SyntaxToken operatorToken, out SyntaxNode right); // Left side of any assignment (for example *= or += ) bool IsLeftSideOfAnyAssignment(SyntaxNode node); SyntaxNode GetRightHandSideOfAssignment(SyntaxNode node); bool IsInferredAnonymousObjectMemberDeclarator(SyntaxNode node); bool IsOperandOfIncrementExpression(SyntaxNode node); bool IsOperandOfIncrementOrDecrementExpression(SyntaxNode node); bool IsLeftSideOfDot(SyntaxNode node); SyntaxNode GetRightSideOfDot(SyntaxNode node); bool IsRightSideOfQualifiedName(SyntaxNode node); bool IsLeftSideOfExplicitInterfaceSpecifier(SyntaxNode node); bool IsNameOfMemberAccessExpression(SyntaxNode node); bool IsExpressionOfMemberAccessExpression(SyntaxNode node); SyntaxNode GetNameOfMemberAccessExpression(SyntaxNode node); /// /// Returns the expression node the member is being accessed off of. If /// is , this will be the node directly to the left of the dot-token. If /// is , then this can return another node in the tree that the member will be accessed /// off of. For example, in VB, if you have a member-access-expression of the form ".Length" then this /// may return the expression in the surrounding With-statement. /// SyntaxNode GetExpressionOfMemberAccessExpression(SyntaxNode node, bool allowImplicitTarget = false); void GetPartsOfMemberAccessExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxToken operatorToken, out SyntaxNode name); SyntaxNode GetTargetOfMemberBinding(SyntaxNode node); bool IsSimpleMemberAccessExpression(SyntaxNode node); bool IsPointerMemberAccessExpression(SyntaxNode node); bool IsNamedParameter(SyntaxNode node); SyntaxToken? GetNameOfParameter(SyntaxNode node); SyntaxNode GetDefaultOfParameter(SyntaxNode node); SyntaxNode GetParameterList(SyntaxNode node); bool IsSkippedTokensTrivia(SyntaxNode node); bool IsWhitespaceTrivia(SyntaxTrivia trivia); bool IsEndOfLineTrivia(SyntaxTrivia trivia); bool IsDocumentationCommentExteriorTrivia(SyntaxTrivia trivia); void GetPartsOfElementAccessExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxNode argumentList); SyntaxNode GetExpressionOfArgument(SyntaxNode node); SyntaxNode GetExpressionOfInterpolation(SyntaxNode node); SyntaxNode GetNameOfAttribute(SyntaxNode node); bool IsConditionalAccessExpression(SyntaxNode node); void GetPartsOfConditionalAccessExpression(SyntaxNode node, out SyntaxNode expression, out SyntaxToken operatorToken, out SyntaxNode whenNotNull); bool IsMemberBindingExpression(SyntaxNode node); bool IsPostfixUnaryExpression(SyntaxNode node); bool IsParenthesizedExpression(SyntaxNode node); SyntaxNode GetExpressionOfParenthesizedExpression(SyntaxNode node); SyntaxToken GetIdentifierOfGenericName(SyntaxNode node); SyntaxToken GetIdentifierOfSimpleName(SyntaxNode node); SyntaxToken GetIdentifierOfVariableDeclarator(SyntaxNode node); SyntaxNode GetTypeOfVariableDeclarator(SyntaxNode node); /// /// True if this is an argument with just an expression and nothing else (i.e. no ref/out, /// no named params, no omitted args). /// bool IsSimpleArgument(SyntaxNode node); bool IsArgument(SyntaxNode node); RefKind GetRefKindOfArgument(SyntaxNode node); bool IsTypeArgumentList(SyntaxNode node); bool IsTypeConstraint(SyntaxNode node); void GetNameAndArityOfSimpleName(SyntaxNode node, out string name, out int arity); bool LooksGeneric(SyntaxNode simpleName); SyntaxList GetContentsOfInterpolatedString(SyntaxNode interpolatedString); SeparatedSyntaxList GetArgumentsOfInvocationExpression(SyntaxNode node); SeparatedSyntaxList GetArgumentsOfObjectCreationExpression(SyntaxNode node); SeparatedSyntaxList GetArgumentsOfArgumentList(SyntaxNode node); bool IsUsingDirectiveName(SyntaxNode node); bool IsIdentifierName(SyntaxNode node); bool IsGenericName(SyntaxNode node); bool IsQualifiedName(SyntaxNode node); bool IsAttribute(SyntaxNode node); bool IsAttributeName(SyntaxNode node); SyntaxList GetAttributeLists(SyntaxNode node); bool IsAttributeNamedArgumentIdentifier(SyntaxNode node); bool IsObjectInitializerNamedAssignmentIdentifier(SyntaxNode node); bool IsObjectInitializerNamedAssignmentIdentifier(SyntaxNode node, out SyntaxNode initializedInstance); bool IsDirective(SyntaxNode node); bool IsForEachStatement(SyntaxNode node); bool IsLockStatement(SyntaxNode node); bool IsUsingStatement(SyntaxNode node); bool IsStatement(SyntaxNode node); bool IsExecutableStatement(SyntaxNode node); bool IsParameter(SyntaxNode node); bool IsVariableDeclarator(SyntaxNode node); bool IsDeconstructionAssignment(SyntaxNode node); bool IsDeconstructionForEachStatement(SyntaxNode node); /// /// Returns true for nodes that represent the body of a method. /// /// For VB this will be /// MethodBlockBaseSyntax. This will be true for things like constructor, method, operator /// bodies as well as accessor bodies. It will not be true for things like sub() function() /// lambdas. /// /// For C# this will be the BlockSyntax or ArrowExpressionSyntax for a /// method/constructor/deconstructor/operator/accessor. It will not be included for local /// functions. /// bool IsMethodBody(SyntaxNode node); bool IsReturnStatement(SyntaxNode node); SyntaxNode GetExpressionOfReturnStatement(SyntaxNode node); bool IsLocalDeclarationStatement(SyntaxNode node); bool IsLocalFunctionStatement(SyntaxNode node); bool IsDeclaratorOfLocalDeclarationStatement(SyntaxNode declarator, SyntaxNode localDeclarationStatement); SeparatedSyntaxList GetVariablesOfLocalDeclarationStatement(SyntaxNode node); SyntaxNode GetInitializerOfVariableDeclarator(SyntaxNode node); SyntaxNode GetValueOfEqualsValueClause(SyntaxNode node); bool IsThisConstructorInitializer(SyntaxToken token); bool IsBaseConstructorInitializer(SyntaxToken token); bool IsQueryExpression(SyntaxNode node); bool IsQueryKeyword(SyntaxToken token); bool IsThrowExpression(SyntaxNode node); bool IsElementAccessExpression(SyntaxNode node); bool IsIndexerMemberCRef(SyntaxNode node); bool IsIdentifierStartCharacter(char c); bool IsIdentifierPartCharacter(char c); bool IsIdentifierEscapeCharacter(char c); bool IsStartOfUnicodeEscapeSequence(char c); bool IsValidIdentifier(string identifier); bool IsVerbatimIdentifier(string identifier); /// /// Returns true if the given character is a character which may be included in an /// identifier to specify the type of a variable. /// bool IsTypeCharacter(char c); bool IsBindableToken(SyntaxToken token); bool IsInStaticContext(SyntaxNode node); bool IsUnsafeContext(SyntaxNode node); bool IsInNamespaceOrTypeContext(SyntaxNode node); bool IsBaseTypeList(SyntaxNode node); bool IsAnonymousFunction(SyntaxNode n); bool IsInConstantContext(SyntaxNode node); bool IsInConstructor(SyntaxNode node); bool IsMethodLevelMember(SyntaxNode node); bool IsTopLevelNodeWithMembers(SyntaxNode node); bool HasIncompleteParentMember(SyntaxNode node); /// /// A block that has no semantics other than introducing a new scope. That is only C# BlockSyntax. /// bool IsScopeBlock(SyntaxNode node); /// /// A node that contains a list of statements. In C#, this is BlockSyntax and SwitchSectionSyntax. /// In VB, this includes all block statements such as a MultiLineIfBlockSyntax. /// bool IsExecutableBlock(SyntaxNode node); SyntaxList GetExecutableBlockStatements(SyntaxNode node); SyntaxNode FindInnermostCommonExecutableBlock(IEnumerable nodes); /// /// A node that can host a list of statements or a single statement. In addition to /// every "executable block", this also includes C# embedded statement owners. /// bool IsStatementContainer(SyntaxNode node); IReadOnlyList GetStatementContainerStatements(SyntaxNode node); bool AreEquivalent(SyntaxToken token1, SyntaxToken token2); bool AreEquivalent(SyntaxNode node1, SyntaxNode node2); string GetDisplayName(SyntaxNode node, DisplayNameOptions options, string rootNamespace = null); SyntaxNode GetContainingTypeDeclaration(SyntaxNode root, int position); SyntaxNode GetContainingMemberDeclaration(SyntaxNode root, int position, bool useFullSpan = true); SyntaxNode GetContainingVariableDeclaratorOfFieldDeclaration(SyntaxNode node); SyntaxToken FindTokenOnLeftOfPosition(SyntaxNode node, int position, bool includeSkipped = true, bool includeDirectives = false, bool includeDocumentationComments = false); SyntaxToken FindTokenOnRightOfPosition(SyntaxNode node, int position, bool includeSkipped = true, bool includeDirectives = false, bool includeDocumentationComments = false); void GetPartsOfParenthesizedExpression(SyntaxNode node, out SyntaxToken openParen, out SyntaxNode expression, out SyntaxToken closeParen); SyntaxNode Parenthesize(SyntaxNode expression, bool includeElasticTrivia = true, bool addSimplifierAnnotation = true); SyntaxNode WalkDownParentheses(SyntaxNode node); SyntaxNode ConvertToSingleLine(SyntaxNode node, bool useElasticTrivia = false); SyntaxToken ToIdentifierToken(string name); List GetMethodLevelMembers(SyntaxNode root); SyntaxList GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration); SyntaxList GetMembersOfNamespaceDeclaration(SyntaxNode namespaceDeclaration); bool ContainsInMemberBody(SyntaxNode node, TextSpan span); int GetMethodLevelMemberId(SyntaxNode root, SyntaxNode node); SyntaxNode GetMethodLevelMember(SyntaxNode root, int memberId); TextSpan GetInactiveRegionSpanAroundPosition(SyntaxTree tree, int position, CancellationToken cancellationToken); /// /// Given a , return the representing the span of the member body /// it is contained within. This is used to determine whether speculative binding should be /// used in performance-critical typing scenarios. Note: if this method fails to find a relevant span, it returns /// an empty at position 0. /// TextSpan GetMemberBodySpanForSpeculativeBinding(SyntaxNode node); /// /// Returns the parent node that binds to the symbols that the IDE prefers for features like /// Quick Info and Find All References. For example, if the token is part of the type of /// an object creation, the parenting object creation expression is returned so that binding /// will return constructor symbols. /// SyntaxNode GetBindableParent(SyntaxToken token); IEnumerable GetConstructors(SyntaxNode root, CancellationToken cancellationToken); bool TryGetCorrespondingOpenBrace(SyntaxToken token, out SyntaxToken openBrace); /// /// Given a , that represents and argument return the string representation of /// that arguments name. /// string GetNameForArgument(SyntaxNode argument); bool IsNameOfSubpattern(SyntaxNode node); bool IsPropertyPatternClause(SyntaxNode node); ImmutableArray GetSelectedFieldsAndProperties(SyntaxNode root, TextSpan textSpan, bool allowPartialSelection); bool IsOnTypeHeader(SyntaxNode root, int position, out SyntaxNode typeDeclaration); bool IsOnPropertyDeclarationHeader(SyntaxNode root, int position, out SyntaxNode propertyDeclaration); bool IsOnParameterHeader(SyntaxNode root, int position, out SyntaxNode parameter); bool IsOnMethodHeader(SyntaxNode root, int position, out SyntaxNode method); bool IsOnLocalFunctionHeader(SyntaxNode root, int position, out SyntaxNode localFunction); bool IsOnLocalDeclarationHeader(SyntaxNode root, int position, out SyntaxNode localDeclaration); bool IsOnIfStatementHeader(SyntaxNode root, int position, out SyntaxNode ifStatement); bool IsBetweenTypeMembers(SourceText sourceText, SyntaxNode root, int position); // Walks the tree, starting from contextNode, looking for the first construct // with a missing close brace. If found, the close brace will be added and the // updates root will be returned. The context node in that new tree will also // be returned. void AddFirstMissingCloseBrace( SyntaxNode root, SyntaxNode contextNode, out SyntaxNode newRoot, out SyntaxNode newContextNode); SyntaxNode GetNextExecutableStatement(SyntaxNode statement); ImmutableArray GetLeadingBlankLines(SyntaxNode node); TSyntaxNode GetNodeWithoutLeadingBlankLines(TSyntaxNode node) where TSyntaxNode : SyntaxNode; ImmutableArray GetFileBanner(SyntaxNode root); ImmutableArray GetFileBanner(SyntaxToken firstToken); bool ContainsInterleavedDirective(SyntaxNode node, CancellationToken cancellationToken); bool ContainsInterleavedDirective(ImmutableArray nodes, CancellationToken cancellationToken); string GetBannerText(SyntaxNode documentationCommentTriviaSyntax, int maxBannerLength, CancellationToken cancellationToken); SyntaxTokenList GetModifiers(SyntaxNode node); SyntaxNode WithModifiers(SyntaxNode node, SyntaxTokenList modifiers); Location GetDeconstructionReferenceLocation(SyntaxNode node); SyntaxToken? GetDeclarationIdentifierIfOverride(SyntaxToken token); bool SpansPreprocessorDirective(IEnumerable nodes); } [Flags] internal enum DisplayNameOptions { None = 0, IncludeMemberKeyword = 1, IncludeNamespaces = 1 << 1, IncludeParameters = 1 << 2, IncludeType = 1 << 3, IncludeTypeParameters = 1 << 4 } }