protected override SyntaxNode GetSyntax(SyntaxToken token) { return token.GetAncestor<EventFieldDeclarationSyntax>() ?? token.GetAncestor<EventDeclarationSyntax>() ?? token.GetAncestor<PropertyDeclarationSyntax>() ?? token.GetAncestor<IndexerDeclarationSyntax>() ?? (SyntaxNode)token.GetAncestor<MethodDeclarationSyntax>(); }
private static InterpolatedStringExpressionSyntax TryGetInterpolatedStringExpression( SyntaxToken token, int position) { if (token.IsKind(SyntaxKind.InterpolatedStringTextToken) || token.IsKind(SyntaxKind.InterpolatedStringEndToken) || IsInterpolationOpenBrace(token, position)) { return token.GetAncestor<InterpolatedStringExpressionSyntax>(); } return null; }
internal IList<string> Do(CancellationToken cancellationToken) { // First, find the containing statement. We'll want to add the expressions in this // statement to the result. _token = _syntaxTree.GetRoot(cancellationToken).FindToken(_position); _parentStatement = _token.GetAncestor<StatementSyntax>(); if (_parentStatement == null) { return null; } AddRelevantExpressions(_parentStatement, _expressions, includeDeclarations: false); AddPrecedingRelevantExpressions(); AddFollowingRelevantExpressions(cancellationToken); AddCurrentDeclaration(); AddMethodParameters(); AddIndexerParameters(); AddCatchParameters(); AddThisExpression(); AddValueExpression(); var result = _expressions.Distinct().Where(e => e.Length > 0).ToList(); return result.Count == 0 ? null : result; }
private static SyntaxNode GetExpansionTarget(SyntaxToken token) { // get the directly enclosing statement var enclosingStatement = token.GetAncestors(n => n is StatementSyntax).FirstOrDefault(); // see if there's an enclosing lambda expression SyntaxNode possibleLambdaExpression = enclosingStatement == null ? token.GetAncestors(n => n is SimpleLambdaExpressionSyntax || n is ParenthesizedLambdaExpressionSyntax).FirstOrDefault() : null; var enclosingNameMemberCrefOrnull = token.GetAncestors(n => n is NameMemberCrefSyntax).LastOrDefault(); if (enclosingNameMemberCrefOrnull != null) { if (token.Parent is TypeSyntax && token.Parent.Parent is TypeSyntax) { enclosingNameMemberCrefOrnull = null; } } var enclosingXmlNameAttr = token.GetAncestors(n => n is XmlNameAttributeSyntax).FirstOrDefault(); if (enclosingXmlNameAttr != null) { return null; } var enclosingInitializer = token.GetAncestors<EqualsValueClauseSyntax>().FirstOrDefault(); if (enclosingStatement == null && enclosingInitializer != null && enclosingInitializer.Parent is VariableDeclaratorSyntax) { return enclosingInitializer.Value; } var attributeSyntax = token.GetAncestor<AttributeSyntax>(); if (attributeSyntax != null) { return attributeSyntax; } // there seems to be no statement above this one. Let's see if we can at least get an SimpleNameSyntax return enclosingStatement ?? enclosingNameMemberCrefOrnull ?? token.GetAncestors(n => n is SimpleNameSyntax).FirstOrDefault(); }
private IEnumerable<CompletionItem> GetTagsForMethod(IMethodSymbol symbol, TextSpan itemSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token) { var items = new List<CompletionItem>(); var parameters = symbol.GetParameters().Select(p => p.Name).ToSet(); var typeParameters = symbol.TypeParameters.Select(t => t.Name).ToSet(); // User is trying to write a name, try to suggest only names. if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) || (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute))) { string parentElementName = null; var emptyElement = token.GetAncestor<XmlEmptyElementSyntax>(); if (emptyElement != null) { parentElementName = emptyElement.Name.LocalName.Text; } // We're writing the name of a paramref or typeparamref if (parentElementName == ParamRefTagName) { items.AddRange(parameters.Select(p => CreateCompletionItem(itemSpan, p))); } else if (parentElementName == TypeParamRefTagName) { items.AddRange(typeParameters.Select(t => CreateCompletionItem(itemSpan, t))); } return items; } RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, ParamTagName)); RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, TypeParamTagName)); items.AddRange(parameters.Select(p => CreateCompletionItem(itemSpan, FormatParameter(ParamTagName, p)))); items.AddRange(typeParameters.Select(t => CreateCompletionItem(itemSpan, FormatParameter(TypeParamTagName, t)))); // Provide a return completion item in case the function returns something var returns = true; foreach (var node in trivia.Content) { var element = node as XmlElementSyntax; if (element != null && !element.StartTag.IsMissing && !element.EndTag.IsMissing) { var startTag = element.StartTag; if (startTag.Name.LocalName.ValueText == ReturnsTagName) { returns = false; break; } } } if (returns && !symbol.ReturnsVoid) { items.Add(CreateCompletionItem(itemSpan, ReturnsTagName)); } return items; }
// copied from compiler formatter to have same base forced format private int LineBreaksAfter(SyntaxToken previousToken, SyntaxToken currentToken) { if (currentToken.Kind() == SyntaxKind.None) { return 0; } switch (previousToken.Kind()) { case SyntaxKind.None: return 0; case SyntaxKind.OpenBraceToken: case SyntaxKind.FinallyKeyword: return 1; case SyntaxKind.CloseBraceToken: return LineBreaksAfterCloseBrace(currentToken); case SyntaxKind.CloseParenToken: return (((previousToken.Parent is StatementSyntax) && currentToken.Parent != previousToken.Parent) || currentToken.Kind() == SyntaxKind.OpenBraceToken) ? 1 : 0; case SyntaxKind.CloseBracketToken: if (previousToken.Parent is AttributeListSyntax) { // Assembly and module-level attributes followed by non-attributes should have // a blank line after them. var parent = (AttributeListSyntax)previousToken.Parent; if (parent.Target != null && (parent.Target.Identifier.IsKindOrHasMatchingText(SyntaxKind.AssemblyKeyword) || parent.Target.Identifier.IsKindOrHasMatchingText(SyntaxKind.ModuleKeyword))) { if (!(currentToken.Parent is AttributeListSyntax)) { return 2; } } if (previousToken.GetAncestor<ParameterSyntax>() == null) { return 1; } } break; case SyntaxKind.SemicolonToken: return LineBreaksAfterSemicolon(previousToken, currentToken); case SyntaxKind.CommaToken: return previousToken.Parent is EnumDeclarationSyntax ? 1 : 0; case SyntaxKind.ElseKeyword: return currentToken.Kind() != SyntaxKind.IfKeyword ? 1 : 0; case SyntaxKind.ColonToken: if (previousToken.Parent is LabeledStatementSyntax || previousToken.Parent is SwitchLabelSyntax) { return 1; } break; } if ((currentToken.Kind() == SyntaxKind.FromKeyword && currentToken.Parent.Kind() == SyntaxKind.FromClause) || (currentToken.Kind() == SyntaxKind.LetKeyword && currentToken.Parent.Kind() == SyntaxKind.LetClause) || (currentToken.Kind() == SyntaxKind.WhereKeyword && currentToken.Parent.Kind() == SyntaxKind.WhereClause) || (currentToken.Kind() == SyntaxKind.JoinKeyword && currentToken.Parent.Kind() == SyntaxKind.JoinClause) || (currentToken.Kind() == SyntaxKind.JoinKeyword && currentToken.Parent.Kind() == SyntaxKind.JoinIntoClause) || (currentToken.Kind() == SyntaxKind.OrderByKeyword && currentToken.Parent.Kind() == SyntaxKind.OrderByClause) || (currentToken.Kind() == SyntaxKind.SelectKeyword && currentToken.Parent.Kind() == SyntaxKind.SelectClause) || (currentToken.Kind() == SyntaxKind.GroupKeyword && currentToken.Parent.Kind() == SyntaxKind.GroupClause)) { return 1; } switch (currentToken.Kind()) { case SyntaxKind.OpenBraceToken: case SyntaxKind.CloseBraceToken: case SyntaxKind.ElseKeyword: case SyntaxKind.FinallyKeyword: return 1; case SyntaxKind.OpenBracketToken: if (currentToken.Parent is AttributeListSyntax) { // Assembly and module-level attributes preceded by non-attributes should have // a blank line separating them. var parent = (AttributeListSyntax)currentToken.Parent; if (parent.Target != null) { if (parent.Target.Identifier == SyntaxFactory.Token(SyntaxKind.AssemblyKeyword) || parent.Target.Identifier == SyntaxFactory.Token(SyntaxKind.ModuleKeyword)) { if (!(previousToken.Parent is AttributeListSyntax)) { return 2; } } } // Attributes on parameters should have no lines between them. if (parent.Parent is ParameterSyntax) { return 0; } return 1; } break; case SyntaxKind.WhereKeyword: return previousToken.Parent is TypeParameterListSyntax ? 1 : 0; } return 0; }
private static bool IsLeftSideOfUsingAliasDirective(SyntaxToken leftToken, CancellationToken cancellationToken) { var usingDirective = leftToken.GetAncestor<UsingDirectiveSyntax>(); if (usingDirective != null) { // No = token: if (usingDirective.Alias == null || usingDirective.Alias.EqualsToken.IsMissing) { return true; } return leftToken.SpanStart < usingDirective.Alias.EqualsToken.SpanStart; } return false; }
protected override SyntaxNode GetContainingStatement(SyntaxToken token) // If we can't get a containing statement, such as for expression bodied members, then // return the arrow clause instead => (SyntaxNode)token.GetAncestor <StatementSyntax>() ?? token.GetAncestor <ArrowExpressionClauseSyntax>();
private bool TryGetTextForPreProcessor(SyntaxToken token, Document document, ISyntaxFactsService syntaxFacts, out string text) { if (syntaxFacts.IsPreprocessorKeyword(token)) { text = "#" + token.Text; return true; } if (token.IsKind(SyntaxKind.EndOfDirectiveToken) && token.GetAncestor<RegionDirectiveTriviaSyntax>() != null) { text = "#region"; return true; } text = null; return false; }
public static bool IsLastTokenOfNode <T>(this SyntaxToken token, [NotNullWhen(true)] out T node) where T : SyntaxNode { node = token.GetAncestor <T>(); return(node != null && token == node.GetLastToken(includeZeroWidth: true)); }
// LookupSymbols doesn't return indexers or operators because they can't be referred to by name, so we'll have to try to // find the innermost type declaration and return its operators and indexers private IEnumerable<ISymbol> GetOperatorsAndIndexers(SyntaxToken token, SemanticModel semanticModel, CancellationToken cancellationToken) { var typeDeclaration = token.GetAncestor<TypeDeclarationSyntax>(); var result = new List<ISymbol>(); if (typeDeclaration != null) { var type = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken); result.AddRange(type.GetMembers().OfType<IPropertySymbol>().Where(p => p.IsIndexer)); result.AddRange(type.GetAccessibleMembersInThisAndBaseTypes<IMethodSymbol>(type) .Where(m => m.MethodKind == MethodKind.UserDefinedOperator)); } return result; }
protected override IndentationResult GetDesiredIndentationWorker( SyntaxToken token, TextLine previousLine, int lastNonWhitespacePosition) { // okay, now check whether the text we found is trivia or actual token. if (token.Span.Contains(lastNonWhitespacePosition)) { // okay, it is a token case, do special work based on type of last token on previous line return(GetIndentationBasedOnToken(token)); } else { // there must be trivia that contains or touch this position Debug.Assert(token.FullSpan.Contains(lastNonWhitespacePosition)); // okay, now check whether the trivia is at the beginning of the line var firstNonWhitespacePosition = previousLine.GetFirstNonWhitespacePosition(); if (!firstNonWhitespacePosition.HasValue) { return(IndentFromStartOfLine(0)); } var trivia = Root.FindTrivia(firstNonWhitespacePosition.Value, findInsideTrivia: true); if (trivia.Kind() == SyntaxKind.None || this.LineToBeIndented.LineNumber > previousLine.LineNumber + 1) { // If the token belongs to the next statement and is also the first token of the statement, then it means the user wants // to start type a new statement. So get indentation from the start of the line but not based on the token. // Case: // static void Main(string[] args) // { // // A // // B // // $$ // return; // } var containingStatement = token.GetAncestor <StatementSyntax>(); if (containingStatement != null && containingStatement.GetFirstToken() == token) { var position = GetCurrentPositionNotBelongToEndOfFileToken(LineToBeIndented.Start); return(IndentFromStartOfLine(Finder.GetIndentationOfCurrentPosition(Tree, token, position, CancellationToken))); } // If the token previous of the base token happens to be a Comma from a separation list then we need to handle it different // Case: // var s = new List<string> // { // """", // """",/*sdfsdfsdfsdf*/ // // dfsdfsdfsdfsdf // // $$ // }; var previousToken = token.GetPreviousToken(); if (previousToken.IsKind(SyntaxKind.CommaToken)) { return(GetIndentationFromCommaSeparatedList(previousToken)); } else if (!previousToken.IsKind(SyntaxKind.None)) { // okay, beginning of the line is not trivia, use the last token on the line as base token return(GetIndentationBasedOnToken(token)); } } // this case we will keep the indentation of this trivia line // this trivia can't be preprocessor by the way. return(GetIndentationOfLine(previousLine)); } }
private static IndentationResult GetIndentationBasedOnToken(Indenter indenter, SyntaxToken token) { Contract.ThrowIfNull(indenter.Tree); Contract.ThrowIfTrue(token.Kind() == SyntaxKind.None); var sourceText = indenter.LineToBeIndented.Text; RoslynDebug.AssertNotNull(sourceText); // case: """$$ // """ if (token.IsKind(SyntaxKind.MultiLineRawStringLiteralToken)) { var endLine = sourceText.Lines.GetLineFromPosition(token.Span.End); var minimumOffset = endLine.GetFirstNonWhitespaceOffset(); Contract.ThrowIfNull(minimumOffset); // If possible, indent to match the indentation of the previous non-whitespace line contained in the // same raw string. Otherwise, indent to match the ending line of the raw string. var startLine = sourceText.Lines.GetLineFromPosition(token.SpanStart); for (var currentLineNumber = indenter.LineToBeIndented.LineNumber - 1; currentLineNumber >= startLine.LineNumber + 1; currentLineNumber--) { var currentLine = sourceText.Lines[currentLineNumber]; if (currentLine.GetFirstNonWhitespaceOffset() is { } priorLineOffset) { if (priorLineOffset >= minimumOffset.Value) { return(indenter.GetIndentationOfLine(currentLine)); } else { // The prior line is not sufficiently indented, so use the ending delimiter for the indent break; } } } return(indenter.GetIndentationOfLine(endLine)); } // case 1: $"""$$ // """ // case 2: $""" // text$$ // """ // case 3: $""" // {value}$$ // """ if (token.Kind() is SyntaxKind.InterpolatedMultiLineRawStringStartToken or SyntaxKind.InterpolatedStringTextToken || (token.IsKind(SyntaxKind.CloseBraceToken) && token.Parent.IsKind(SyntaxKind.Interpolation))) { var interpolatedExpression = token.GetAncestor <InterpolatedStringExpressionSyntax>(); Contract.ThrowIfNull(interpolatedExpression); if (interpolatedExpression.StringStartToken.IsKind(SyntaxKind.InterpolatedMultiLineRawStringStartToken)) { var endLine = sourceText.Lines.GetLineFromPosition(interpolatedExpression.StringEndToken.Span.End); var minimumOffset = endLine.GetFirstNonWhitespaceOffset(); Contract.ThrowIfNull(minimumOffset); // If possible, indent to match the indentation of the previous non-whitespace line contained in the // same raw string. Otherwise, indent to match the ending line of the raw string. var startLine = sourceText.Lines.GetLineFromPosition(interpolatedExpression.StringStartToken.SpanStart); for (var currentLineNumber = indenter.LineToBeIndented.LineNumber - 1; currentLineNumber >= startLine.LineNumber + 1; currentLineNumber--) { var currentLine = sourceText.Lines[currentLineNumber]; if (!indenter.Root.FindToken(currentLine.Start, findInsideTrivia: true).IsKind(SyntaxKind.InterpolatedStringTextToken)) { // Avoid trying to indent to match the content of an interpolation. Example: // // _ = $""" // { // 0} <-- the start of this line is not part of the text content // """ // continue; } if (currentLine.GetFirstNonWhitespaceOffset() is { } priorLineOffset) { if (priorLineOffset >= minimumOffset.Value) { return(indenter.GetIndentationOfLine(currentLine)); } else { // The prior line is not sufficiently indented, so use the ending delimiter for the indent break; } } } return(indenter.GetIndentationOfLine(endLine)); } } // special cases // case 1: token belongs to verbatim token literal // case 2: $@"$${0}" // case 3: $@"Comment$$ in-between{0}" // case 4: $@"{0}$$" if (token.IsVerbatimStringLiteral() || token.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken) || token.IsKind(SyntaxKind.InterpolatedStringTextToken) || (token.IsKind(SyntaxKind.CloseBraceToken) && token.Parent.IsKind(SyntaxKind.Interpolation))) { return(indenter.IndentFromStartOfLine(0)); } // if previous statement belong to labeled statement, don't follow label's indentation // but its previous one. if (token.Parent is LabeledStatementSyntax || token.IsLastTokenInLabelStatement()) { token = token.GetAncestor <LabeledStatementSyntax>() !.GetFirstToken(includeZeroWidth: true).GetPreviousToken(includeZeroWidth: true); } var position = indenter.GetCurrentPositionNotBelongToEndOfFileToken(indenter.LineToBeIndented.Start); // first check operation service to see whether we can determine indentation from it var indentation = indenter.Finder.FromIndentBlockOperations(indenter.Tree, token, position, indenter.CancellationToken); if (indentation.HasValue) { return(indenter.IndentFromStartOfLine(indentation.Value)); } var alignmentTokenIndentation = indenter.Finder.FromAlignTokensOperations(indenter.Tree, token); if (alignmentTokenIndentation.HasValue) { return(indenter.IndentFromStartOfLine(alignmentTokenIndentation.Value)); } // if we couldn't determine indentation from the service, use heuristic to find indentation. // If this is the last token of an embedded statement, walk up to the top-most parenting embedded // statement owner and use its indentation. // // cases: // if (true) // if (false) // Goo(); // // if (true) // { } if (token.IsSemicolonOfEmbeddedStatement() || token.IsCloseBraceOfEmbeddedBlock()) { RoslynDebug.Assert( token.Parent != null && (token.Parent.Parent is StatementSyntax || token.Parent.Parent is ElseClauseSyntax)); var embeddedStatementOwner = token.Parent.Parent; while (embeddedStatementOwner.IsEmbeddedStatement()) { RoslynDebug.AssertNotNull(embeddedStatementOwner.Parent); embeddedStatementOwner = embeddedStatementOwner.Parent; } return(indenter.GetIndentationOfLine(sourceText.Lines.GetLineFromPosition(embeddedStatementOwner.GetFirstToken(includeZeroWidth: true).SpanStart))); } switch (token.Kind()) { case SyntaxKind.SemicolonToken: { // special cases if (token.IsSemicolonInForStatement()) { return(GetDefaultIndentationFromToken(indenter, token)); } return(indenter.IndentFromStartOfLine(indenter.Finder.GetIndentationOfCurrentPosition(indenter.Tree, token, position, indenter.CancellationToken))); } case SyntaxKind.CloseBraceToken: { if (token.Parent.IsKind(SyntaxKind.AccessorList) && token.Parent.Parent.IsKind(SyntaxKind.PropertyDeclaration)) { if (token.GetNextToken().IsEqualsTokenInAutoPropertyInitializers()) { return(GetDefaultIndentationFromToken(indenter, token)); } } return(indenter.IndentFromStartOfLine(indenter.Finder.GetIndentationOfCurrentPosition(indenter.Tree, token, position, indenter.CancellationToken))); } case SyntaxKind.OpenBraceToken: { return(indenter.IndentFromStartOfLine(indenter.Finder.GetIndentationOfCurrentPosition(indenter.Tree, token, position, indenter.CancellationToken))); } case SyntaxKind.ColonToken: { var nonTerminalNode = token.Parent; Contract.ThrowIfNull(nonTerminalNode, @"Malformed code or bug in parser???"); if (nonTerminalNode is SwitchLabelSyntax) { return(indenter.GetIndentationOfLine(sourceText.Lines.GetLineFromPosition(nonTerminalNode.GetFirstToken(includeZeroWidth: true).SpanStart), indenter.Options.FormattingOptions.IndentationSize)); } goto default; } case SyntaxKind.CloseBracketToken: { var nonTerminalNode = token.Parent; Contract.ThrowIfNull(nonTerminalNode, @"Malformed code or bug in parser???"); // if this is closing an attribute, we shouldn't indent. if (nonTerminalNode is AttributeListSyntax) { return(indenter.GetIndentationOfLine(sourceText.Lines.GetLineFromPosition(nonTerminalNode.GetFirstToken(includeZeroWidth: true).SpanStart))); } goto default; } case SyntaxKind.XmlTextLiteralToken: { return(indenter.GetIndentationOfLine(sourceText.Lines.GetLineFromPosition(token.SpanStart))); } case SyntaxKind.CommaToken: { return(GetIndentationFromCommaSeparatedList(indenter, token)); } case SyntaxKind.CloseParenToken: { if (token.Parent.IsKind(SyntaxKind.ArgumentList)) { return(GetDefaultIndentationFromToken(indenter, token.Parent.GetFirstToken(includeZeroWidth: true))); } goto default; } default: { return(GetDefaultIndentationFromToken(indenter, token)); } } }
private IndentationResult?GetIndentationBasedOnToken(SyntaxToken token) { Contract.ThrowIfNull(LineToBeIndented); Contract.ThrowIfNull(Tree); Contract.ThrowIfTrue(token.Kind() == SyntaxKind.None); // special cases // if token belongs to verbatim token literal if (token.IsVerbatimStringLiteral()) { return(IndentFromStartOfLine(0)); } // if previous statement belong to labeled statement, don't follow label's indentation // but its previous one. if (token.Parent is LabeledStatementSyntax || token.IsLastTokenInLabelStatement()) { token = token.GetAncestor <LabeledStatementSyntax>().GetFirstToken(includeZeroWidth: true).GetPreviousToken(includeZeroWidth: true); } var position = GetCurrentPositionNotBelongToEndOfFileToken(LineToBeIndented.Start); // first check operation service to see whether we can determine indentation from it var indentation = Finder.FromIndentBlockOperations(Tree, token, position, CancellationToken); if (indentation.HasValue) { return(IndentFromStartOfLine(indentation.Value)); } var alignmentTokenIndentation = Finder.FromAlignTokensOperations(Tree, token); if (alignmentTokenIndentation.HasValue) { return(IndentFromStartOfLine(alignmentTokenIndentation.Value)); } // if we couldn't determine indentation from the service, use hueristic to find indentation. var snapshot = LineToBeIndented.Snapshot; // If this is the last token of an embedded statement, walk up to the top-most parenting embedded // statement owner and use its indentation. // // cases: // if (true) // if (false) // Foo(); // // if (true) // { } if (token.IsSemicolonOfEmbeddedStatement() || token.IsCloseBraceOfEmbeddedBlock()) { Contract.Requires( token.Parent != null && (token.Parent.Parent is StatementSyntax || token.Parent.Parent is ElseClauseSyntax)); var embeddedStatementOwner = token.Parent.Parent; while (embeddedStatementOwner.IsEmbeddedStatement()) { embeddedStatementOwner = embeddedStatementOwner.Parent; } return(GetIndentationOfLine(snapshot.GetLineFromPosition(embeddedStatementOwner.GetFirstToken(includeZeroWidth: true).SpanStart))); } switch (token.Kind()) { case SyntaxKind.SemicolonToken: { // special cases if (token.IsSemicolonInForStatement()) { return(GetDefaultIndentationFromToken(token)); } return(IndentFromStartOfLine(Finder.GetIndentationOfCurrentPosition(Tree, token, position, CancellationToken))); } case SyntaxKind.CloseBraceToken: { return(IndentFromStartOfLine(Finder.GetIndentationOfCurrentPosition(Tree, token, position, CancellationToken))); } case SyntaxKind.OpenBraceToken: { return(IndentFromStartOfLine(Finder.GetIndentationOfCurrentPosition(Tree, token, position, CancellationToken))); } case SyntaxKind.ColonToken: { var nonTerminalNode = token.Parent; Contract.ThrowIfNull(nonTerminalNode, @"Malformed code or bug in parser???"); if (nonTerminalNode is SwitchLabelSyntax) { return(GetIndentationOfLine(snapshot.GetLineFromPosition(nonTerminalNode.GetFirstToken(includeZeroWidth: true).SpanStart), OptionSet.GetOption(FormattingOptions.IndentationSize, token.Language))); } // default case return(GetDefaultIndentationFromToken(token)); } case SyntaxKind.CloseBracketToken: { var nonTerminalNode = token.Parent; Contract.ThrowIfNull(nonTerminalNode, @"Malformed code or bug in parser???"); // if this is closing an attribute, we shouldn't indent. if (nonTerminalNode is AttributeListSyntax) { return(GetIndentationOfLine(snapshot.GetLineFromPosition(nonTerminalNode.GetFirstToken(includeZeroWidth: true).SpanStart))); } // default case return(GetDefaultIndentationFromToken(token)); } case SyntaxKind.XmlTextLiteralToken: { return(GetIndentationOfLine(snapshot.GetLineFromPosition(token.SpanStart))); } case SyntaxKind.CommaToken: { return(GetIndentationFromCommaSeparatedList(token)); } default: { return(GetDefaultIndentationFromToken(token)); } } }
internal static bool IsTriggerParenOrComma <TSyntaxNode>(SyntaxToken token, Func <char, bool> isTriggerCharacter) where TSyntaxNode : SyntaxNode { // Don't dismiss if the user types ( to start a parenthesized expression or tuple // Note that the tuple initially parses as a parenthesized expression if (token.IsKind(SyntaxKind.OpenParenToken) && token.Parent.IsKind(SyntaxKind.ParenthesizedExpression)) { var parenthesizedExpr = ((ParenthesizedExpressionSyntax)token.Parent).WalkUpParentheses(); if (parenthesizedExpr.Parent is ArgumentSyntax) { var parent = parenthesizedExpr.Parent; var grandParent = parent.Parent; if (grandParent is ArgumentListSyntax && grandParent.Parent is TSyntaxNode) { // Argument to TSyntaxNode's argument list return(true); } else { // Argument to a tuple in TSyntaxNode's argument list return(grandParent is TupleExpressionSyntax && parenthesizedExpr.GetAncestor <TSyntaxNode>() != null); } } else { // Not an argument return(false); } } // Don't dismiss if the user types ',' to add a member to a tuple if (token.IsKind(SyntaxKind.CommaToken) && token.Parent is TupleExpressionSyntax && token.GetAncestor <TSyntaxNode>() != null) { return(true); } return(!token.IsKind(SyntaxKind.None) && token.ValueText.Length == 1 && isTriggerCharacter(token.ValueText[0]) && token.Parent is ArgumentListSyntax && token.Parent.Parent is TSyntaxNode); }
public static bool IsBeginningOfGlobalStatementContext(this SyntaxToken token) { // cases: // } // | // ...; // | // extern alias Goo; // using System; // | // [assembly: Goo] // | if (token.Kind() == SyntaxKind.CloseBraceToken) { var memberDeclaration = token.GetAncestor <MemberDeclarationSyntax>(); if (memberDeclaration != null && memberDeclaration.GetLastToken(includeZeroWidth: true) == token && memberDeclaration.IsParentKind(SyntaxKind.CompilationUnit)) { return(true); } } if (token.Kind() == SyntaxKind.SemicolonToken) { var globalStatement = token.GetAncestor <GlobalStatementSyntax>(); if (globalStatement != null && globalStatement.GetLastToken(includeZeroWidth: true) == token) { return(true); } // Need this check to check file scoped namespace declarations prior to a catch-all of // member declarations since otherwise it would return true. if (token.Parent is FileScopedNamespaceDeclarationSyntax namespaceDeclaration && namespaceDeclaration.SemicolonToken == token) { return(false); } var memberDeclaration = token.GetAncestor <MemberDeclarationSyntax>(); if (memberDeclaration != null && memberDeclaration.GetLastToken(includeZeroWidth: true) == token && memberDeclaration.IsParentKind(SyntaxKind.CompilationUnit)) { return(true); } var compUnit = token.GetAncestor <CompilationUnitSyntax>(); if (compUnit != null) { if (compUnit.Usings.Count > 0 && compUnit.Usings.Last().GetLastToken(includeZeroWidth: true) == token) { return(true); } if (compUnit.Externs.Count > 0 && compUnit.Externs.Last().GetLastToken(includeZeroWidth: true) == token) { return(true); } } } if (token.Kind() == SyntaxKind.CloseBracketToken) { var compUnit = token.GetAncestor <CompilationUnitSyntax>(); if (compUnit != null) { if (compUnit.AttributeLists.Count > 0 && compUnit.AttributeLists.Last().GetLastToken(includeZeroWidth: true) == token) { return(true); } } if (token.Parent.IsKind(SyntaxKind.AttributeList)) { var container = token.Parent.Parent; if (container is IncompleteMemberSyntax && container.Parent is CompilationUnitSyntax) { return(true); } } } return(false); }
protected override IMethodSymbol GetCurrentConstructor(SemanticModel semanticModel, SyntaxToken token, CancellationToken cancellationToken) => token.GetAncestor <ConstructorDeclarationSyntax>() is {
private static bool IsValidElseKeywordContext(SyntaxToken token) { var statement = token.GetAncestor<StatementSyntax>(); var ifStatement = statement.GetAncestorOrThis<IfStatementSyntax>(); if (statement == null || ifStatement == null) return false; // cases: // if (foo) // Console.WriteLine(); // | // if (foo) // Console.WriteLine(); // e| if (token.IsKind(SyntaxKind.SemiToken) && ifStatement.Statement.GetLastToken(includeSkippedTokens: true) == token) return true; // if (foo) { // Console.WriteLine(); // } | // if (foo) { // Console.WriteLine(); // } e| if (token.IsKind(SyntaxKind.CloseBraceToken) && ifStatement.Statement is BlockSyntax && token == ((BlockSyntax) ifStatement.Statement).CloseBraceToken) return true; return false; }
public static bool IsBeginningOfStatementContext(this SyntaxToken token) { // cases: // { // | // } // | // Note, the following is *not* a legal statement context: // do { } | // ...; // | // case 0: // | // default: // | // label: // | // if (goo) // | // while (true) // | // do // | // for (;;) // | // foreach (var v in c) // | // else // | // using (expr) // | // fixed (void* v = &expr) // | // lock (expr) // | // for ( ; ; Goo(), | // After attribute lists on a statement: // [Bar] // | switch (token.Kind()) { case SyntaxKind.OpenBraceToken when token.Parent.IsKind(SyntaxKind.Block): return(true); case SyntaxKind.SemicolonToken: var statement = token.GetAncestor <StatementSyntax>(); return(statement != null && !statement.IsParentKind(SyntaxKind.GlobalStatement) && statement.GetLastToken(includeZeroWidth: true) == token); case SyntaxKind.CloseBraceToken: if (token.Parent.IsKind(SyntaxKind.Block)) { if (token.Parent.Parent is StatementSyntax) { // Most blocks that are the child of statement are places // that we can follow with another statement. i.e.: // if { } // while () { } // There are two exceptions. // try {} // do {} if (!token.Parent.IsParentKind(SyntaxKind.TryStatement) && !token.Parent.IsParentKind(SyntaxKind.DoStatement)) { return(true); } } else if ( token.Parent.IsParentKind(SyntaxKind.ElseClause) || token.Parent.IsParentKind(SyntaxKind.FinallyClause) || token.Parent.IsParentKind(SyntaxKind.CatchClause) || token.Parent.IsParentKind(SyntaxKind.SwitchSection)) { return(true); } } if (token.Parent.IsKind(SyntaxKind.SwitchStatement)) { return(true); } return(false); case SyntaxKind.ColonToken: return(token.Parent.IsKind(SyntaxKind.CaseSwitchLabel, SyntaxKind.DefaultSwitchLabel, SyntaxKind.CasePatternSwitchLabel, SyntaxKind.LabeledStatement)); case SyntaxKind.DoKeyword when token.Parent.IsKind(SyntaxKind.DoStatement): return(true); case SyntaxKind.CloseParenToken: var parent = token.Parent; return(parent.IsKind(SyntaxKind.ForStatement) || parent.IsKind(SyntaxKind.ForEachStatement) || parent.IsKind(SyntaxKind.ForEachVariableStatement) || parent.IsKind(SyntaxKind.WhileStatement) || parent.IsKind(SyntaxKind.IfStatement) || parent.IsKind(SyntaxKind.LockStatement) || parent.IsKind(SyntaxKind.UsingStatement) || parent.IsKind(SyntaxKind.FixedStatement)); case SyntaxKind.ElseKeyword: return(token.Parent.IsKind(SyntaxKind.ElseClause)); case SyntaxKind.CloseBracketToken: if (token.Parent.IsKind(SyntaxKind.AttributeList)) { // attributes can belong to a statement var container = token.Parent.Parent; if (container is StatementSyntax) { return(true); } } return(false); } return(false); }
// copied from compiler formatter to have same base forced format private int LineBreaksAfter(SyntaxToken previousToken, SyntaxToken currentToken) { if (currentToken.Kind() == SyntaxKind.None) { return(0); } switch (previousToken.Kind()) { case SyntaxKind.None: return(0); case SyntaxKind.OpenBraceToken: case SyntaxKind.FinallyKeyword: return(1); case SyntaxKind.CloseBraceToken: return(LineBreaksAfterCloseBrace(currentToken)); case SyntaxKind.CloseParenToken: return((((previousToken.Parent is StatementSyntax) && currentToken.Parent != previousToken.Parent) || currentToken.Kind() == SyntaxKind.OpenBraceToken) ? 1 : 0); case SyntaxKind.CloseBracketToken: // Assembly and module-level attributes followed by non-attributes should have // a blank line after them. if (previousToken.Parent is AttributeSyntax parent) { if (parent.Target != null && (parent.Target.Identifier.IsKindOrHasMatchingText(SyntaxKind.AssemblyKeyword))) { if (!(currentToken.Parent is AttributeSyntax)) { return(2); } } if (previousToken.GetAncestor <ParameterSyntax>() == null) { return(1); } } break; case SyntaxKind.SemicolonToken: return(LineBreaksAfterSemicolon(previousToken, currentToken)); case SyntaxKind.CommaToken: return(previousToken.Parent is EnumDeclarationSyntax ? 1 : 0); case SyntaxKind.ElseKeyword: return(currentToken.Kind() != SyntaxKind.IfKeyword ? 1 : 0); case SyntaxKind.ColonToken: if (previousToken.Parent is LabeledStatementSyntax || previousToken.Parent is SwitchLabelSyntax) { return(1); } break; } if ((currentToken.Kind() == SyntaxKind.FromKeyword && currentToken.Parent.Kind() == SyntaxKind.FromClause) || (currentToken.Kind() == SyntaxKind.LetKeyword && currentToken.Parent.Kind() == SyntaxKind.LetClause) || (currentToken.Kind() == SyntaxKind.WhereKeyword && currentToken.Parent.Kind() == SyntaxKind.WhereClause) || (currentToken.Kind() == SyntaxKind.JoinKeyword && currentToken.Parent.Kind() == SyntaxKind.JoinClause) || (currentToken.Kind() == SyntaxKind.JoinKeyword && currentToken.Parent.Kind() == SyntaxKind.JoinIntoClause) || (currentToken.Kind() == SyntaxKind.OrderByKeyword && currentToken.Parent.Kind() == SyntaxKind.OrderByClause) || (currentToken.Kind() == SyntaxKind.SelectKeyword && currentToken.Parent.Kind() == SyntaxKind.SelectClause) || (currentToken.Kind() == SyntaxKind.GroupKeyword && currentToken.Parent.Kind() == SyntaxKind.GroupClause)) { return(1); } switch (currentToken.Kind()) { case SyntaxKind.OpenBraceToken: case SyntaxKind.CloseBraceToken: case SyntaxKind.ElseKeyword: case SyntaxKind.FinallyKeyword: return(1); case SyntaxKind.OpenBracketToken: // Assembly and module-level attributes preceded by non-attributes should have // a blank line separating them. if (currentToken.Parent is AttributeSyntax parent) { if (parent.Target != null) { if (parent.Target.Identifier == SyntaxFactory.Token(SyntaxKind.AssemblyKeyword)) { if (!(previousToken.Parent is AttributeSyntax)) { return(2); } } } // Attributes on parameters should have no lines between them. if (parent.Parent is ParameterSyntax) { return(0); } return(1); } break; case SyntaxKind.WhereKeyword: return(previousToken.Parent is TypeParameterListSyntax ? 1 : 0); } return(0); }
public static SyntaxNode GetAncestor(this SyntaxToken token, Func <SyntaxNode, bool> predicate) { return(token.GetAncestor <SyntaxNode>(predicate)); }
// Copied from // https://github.com/dotnet/roslyn/blob/fb5d0b2a0daa2cbc66c88c1ff483b52d0ed4b9d5/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTokenExtensions.cs#L51 public static bool IsBeginningOfStatementContext(this SyntaxToken token) { // cases: // { // | // } // | // Note, the following is *not* a legal statement context: // do { } | // ...; // | // case 0: // | // default: // | // if (foo) // | // while (true) // | // do // | // for (;;) // | // else // | // for ( ; ; Foo(), | if (token.Kind == SyntaxKind.OpenBraceToken && token.Parent.IsKind(SyntaxKind.Block)) { return(true); } if (token.Kind == SyntaxKind.SemiToken) { var statement = token.GetAncestor <StatementSyntax>(); if (statement != null && !statement.IsParentKind(SyntaxKind.GlobalStatement) && statement.GetLastToken(includeSkippedTokens: true) == token) { return(true); } } if (token.Kind == SyntaxKind.CloseBraceToken && token.Parent.IsKind(SyntaxKind.Block)) { if (token.Parent.Parent is StatementSyntax) { // Most blocks that are the child of statement are places // that we can follow with another statement. i.e.: // if { } // while () { } // There is one exception. // do {} if (!token.Parent.IsParentKind(SyntaxKind.DoStatement)) { return(true); } } else if ( token.Parent.IsParentKind(SyntaxKind.ElseClause) || token.Parent.IsParentKind(SyntaxKind.SwitchSection)) { return(true); } } if (token.Kind == SyntaxKind.CloseBraceToken && token.Parent.IsKind(SyntaxKind.SwitchStatement)) { return(true); } if (token.Kind == SyntaxKind.ColonToken) { if (token.Parent.IsKind(SyntaxKind.CaseSwitchLabel, SyntaxKind.DefaultSwitchLabel)) { return(true); } } if (token.Kind == SyntaxKind.DoKeyword && token.Parent.IsKind(SyntaxKind.DoStatement)) { return(true); } if (token.Kind == SyntaxKind.CloseParenToken) { var parent = token.Parent; if (parent.IsKind(SyntaxKind.ForStatement) || parent.IsKind(SyntaxKind.WhileStatement) || parent.IsKind(SyntaxKind.IfStatement)) { return(true); } } if (token.Kind == SyntaxKind.ElseKeyword) { return(true); } return(false); }
private IEnumerable<CompletionItem> GetTagsForMethod(IMethodSymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token) { var items = new List<CompletionItem>(); var parameters = symbol.GetParameters().Select(p => p.Name).ToSet(); var typeParameters = symbol.TypeParameters.Select(t => t.Name).ToSet(); // User is trying to write a name, try to suggest only names. if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) || (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute))) { string parentElementName = null; var emptyElement = token.GetAncestor<XmlEmptyElementSyntax>(); if (emptyElement != null) { parentElementName = emptyElement.Name.LocalName.Text; } // We're writing the name of a paramref or typeparamref if (parentElementName == "paramref") { items.AddRange(parameters.Select(p => new XmlDocCommentCompletionItem(this, filterSpan, p, GetCompletionItemRules()))); } else if (parentElementName == "typeparamref") { items.AddRange(typeParameters.Select(t => new XmlDocCommentCompletionItem(this, filterSpan, t, GetCompletionItemRules()))); } return items; } var returns = true; RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, "param")); RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, "typeparam")); foreach (var node in trivia.Content) { var element = node as XmlElementSyntax; if (element != null && !element.StartTag.IsMissing && !element.EndTag.IsMissing) { var startTag = element.StartTag; if (startTag.Name.LocalName.ValueText == "returns") { returns = false; break; } } } items.AddRange(parameters.Select(p => new XmlDocCommentCompletionItem(this, filterSpan, FormatParameter("param", p), GetCompletionItemRules()))); items.AddRange(typeParameters.Select(t => new XmlDocCommentCompletionItem(this, filterSpan, FormatParameter("typeparam", t), GetCompletionItemRules()))); if (returns && !symbol.ReturnsVoid) { items.Add(new XmlDocCommentCompletionItem(this, filterSpan, "returns", GetCompletionItemRules())); } return items; }
private bool IsPartOfQueryExpression(SyntaxToken token) { var queryExpression = token.GetAncestor <QueryExpressionSyntax>(); return(queryExpression != null); }
private bool TryGetTextForSymbol(SyntaxToken token, SemanticModel semanticModel, Document document, CancellationToken cancellationToken, out string text) { ISymbol symbol; if (token.Parent is TypeArgumentListSyntax) { var genericName = token.GetAncestor<GenericNameSyntax>(); symbol = semanticModel.GetSymbolInfo(genericName, cancellationToken).Symbol ?? semanticModel.GetTypeInfo(genericName, cancellationToken).Type; } else if (token.Parent is NullableTypeSyntax && token.IsKind(SyntaxKind.QuestionToken)) { text = "System.Nullable`1"; return true; } else { var symbols = semanticModel.GetSymbols(token, document.Project.Solution.Workspace, bindLiteralsToUnderlyingType: true, cancellationToken: cancellationToken); symbol = symbols.FirstOrDefault(); if (symbol == null) { var bindableParent = document.GetLanguageService<ISyntaxFactsService>().GetBindableParent(token); var overloads = semanticModel.GetMemberGroup(bindableParent); symbol = overloads.FirstOrDefault(); } } // Local: return the name if it's the declaration, otherwise the type if (symbol is ILocalSymbol && !symbol.DeclaringSyntaxReferences.Any(d => d.GetSyntax().DescendantTokens().Contains(token))) { symbol = ((ILocalSymbol)symbol).Type; } // Range variable: use the type if (symbol is IRangeVariableSymbol) { var info = semanticModel.GetTypeInfo(token.Parent, cancellationToken); symbol = info.Type; } // Just use syntaxfacts for operators if (symbol is IMethodSymbol && ((IMethodSymbol)symbol).MethodKind == MethodKind.BuiltinOperator) { text = null; return false; } text = symbol != null ? Format(symbol) : null; return symbol != null; }
private bool TryGetTextForSymbol( SyntaxToken token, SemanticModel semanticModel, Document document, CancellationToken cancellationToken, [NotNullWhen(true)] out string?text) { ISymbol?symbol = null; if (token.Parent is TypeArgumentListSyntax) { var genericName = token.GetAncestor <GenericNameSyntax>(); if (genericName != null) { symbol = semanticModel.GetSymbolInfo(genericName, cancellationToken).Symbol ?? semanticModel.GetTypeInfo(genericName, cancellationToken).Type; } } else if (token.Parent is NullableTypeSyntax && token.IsKind(SyntaxKind.QuestionToken)) { text = "System.Nullable`1"; return(true); } else { symbol = semanticModel.GetSemanticInfo(token, document.Project.Solution.Workspace.Services, cancellationToken) .GetAnySymbol(includeType: true); if (symbol == null) { var bindableParent = document.GetRequiredLanguageService <ISyntaxFactsService>().TryGetBindableParent(token); var overloads = bindableParent != null?semanticModel.GetMemberGroup(bindableParent) : ImmutableArray <ISymbol> .Empty; symbol = overloads.FirstOrDefault(); } } // Local: return the name if it's the declaration, otherwise the type if (symbol is ILocalSymbol localSymbol && !symbol.DeclaringSyntaxReferences.Any(d => d.GetSyntax().DescendantTokens().Contains(token))) { symbol = localSymbol.Type; } // Range variable: use the type if (symbol is IRangeVariableSymbol) { var info = semanticModel.GetTypeInfo(token.GetRequiredParent(), cancellationToken); symbol = info.Type; } // Just use syntaxfacts for operators if (symbol is IMethodSymbol method && method.MethodKind == MethodKind.BuiltinOperator) { text = null; return(false); } if (symbol is IDiscardSymbol) { text = Keyword("discard"); return(true); } text = FormatSymbol(symbol); return(text != null); }
private bool TryGetTextForKeyword(SyntaxToken token, Document document, ISyntaxFactsService syntaxFacts, out string text) { if (token.Kind() == SyntaxKind.InKeyword) { if (token.GetAncestor<FromClauseSyntax>() != null) { text = "from_CSharpKeyword"; return true; } if (token.GetAncestor<JoinClauseSyntax>() != null) { text = "join_CSharpKeyword"; return true; } } if (token.IsKeyword()) { text = Keyword(token.Text); return true; } if (token.ValueText == "var" && token.IsKind(SyntaxKind.IdentifierToken) && token.Parent.Parent is VariableDeclarationSyntax && token.Parent == ((VariableDeclarationSyntax)token.Parent.Parent).Type) { text = "var_CSharpKeyword"; return true; } if (syntaxFacts.IsTypeNamedDynamic(token, token.Parent)) { text = "dynamic_CSharpKeyword"; return true; } text = null; return false; }
private IEnumerable <CompletionData> GetTagsForMethod(CompletionEngine engine, IMethodSymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token) { var items = new List <CompletionData>(); var parameters = symbol.GetParameters().Select(p => p.Name).ToSet(); var typeParameters = symbol.TypeParameters.Select(t => t.Name).ToSet(); // User is trying to write a name, try to suggest only names. if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) || (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute))) { string parentElementName = null; var emptyElement = token.GetAncestor <XmlEmptyElementSyntax>(); if (emptyElement != null) { parentElementName = emptyElement.Name.LocalName.Text; } // We're writing the name of a paramref or typeparamref if (parentElementName == "paramref") { items.AddRange(parameters.Select(p => engine.Factory.CreateXmlDocCompletionData(this, p))); } else if (parentElementName == "typeparamref") { items.AddRange(typeParameters.Select(t => engine.Factory.CreateXmlDocCompletionData(this, t))); } return(items); } var returns = true; RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, "param")); RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, "typeparam")); foreach (var node in trivia.Content) { var element = node as XmlElementSyntax; if (element != null && !element.StartTag.IsMissing && !element.EndTag.IsMissing) { var startTag = element.StartTag; if (startTag.Name.LocalName.ValueText == "returns") { returns = false; break; } } } items.AddRange(parameters.Select(p => engine.Factory.CreateXmlDocCompletionData(this, FormatParameter("param", p)))); items.AddRange(typeParameters.Select(t => engine.Factory.CreateXmlDocCompletionData(this, FormatParameter("typeparam", t)))); if (returns && !symbol.ReturnsVoid) { items.Add(engine.Factory.CreateXmlDocCompletionData(this, "returns")); } return(items); }
private static IndentationResult GetIndentationBasedOnToken( Indenter indenter, SyntaxToken token ) { Contract.ThrowIfNull(indenter.Tree); Contract.ThrowIfTrue(token.Kind() == SyntaxKind.None); // special cases // case 1: token belongs to verbatim token literal // case 2: $@"$${0}" // case 3: $@"Comment$$ in-between{0}" // case 4: $@"{0}$$" if ( token.IsVerbatimStringLiteral() || token.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken) || token.IsKind(SyntaxKind.InterpolatedStringTextToken) || ( token.IsKind(SyntaxKind.CloseBraceToken) && token.Parent.IsKind(SyntaxKind.Interpolation) ) ) { return(indenter.IndentFromStartOfLine(0)); } // if previous statement belong to labeled statement, don't follow label's indentation // but its previous one. if (token.Parent is LabeledStatementSyntax || token.IsLastTokenInLabelStatement()) { token = token.GetAncestor <LabeledStatementSyntax>() ! .GetFirstToken(includeZeroWidth: true) .GetPreviousToken(includeZeroWidth: true); } var position = indenter.GetCurrentPositionNotBelongToEndOfFileToken( indenter.LineToBeIndented.Start ); // first check operation service to see whether we can determine indentation from it var indentation = indenter.Finder.FromIndentBlockOperations( indenter.Tree, token, position, indenter.CancellationToken ); if (indentation.HasValue) { return(indenter.IndentFromStartOfLine(indentation.Value)); } var alignmentTokenIndentation = indenter.Finder.FromAlignTokensOperations( indenter.Tree, token ); if (alignmentTokenIndentation.HasValue) { return(indenter.IndentFromStartOfLine(alignmentTokenIndentation.Value)); } // if we couldn't determine indentation from the service, use heuristic to find indentation. var sourceText = indenter.LineToBeIndented.Text; RoslynDebug.AssertNotNull(sourceText); // If this is the last token of an embedded statement, walk up to the top-most parenting embedded // statement owner and use its indentation. // // cases: // if (true) // if (false) // Goo(); // // if (true) // { } if (token.IsSemicolonOfEmbeddedStatement() || token.IsCloseBraceOfEmbeddedBlock()) { Debug.Assert( token.Parent != null && ( token.Parent.Parent is StatementSyntax || token.Parent.Parent is ElseClauseSyntax ) ); var embeddedStatementOwner = token.Parent.Parent; while (embeddedStatementOwner.IsEmbeddedStatement()) { RoslynDebug.AssertNotNull(embeddedStatementOwner.Parent); embeddedStatementOwner = embeddedStatementOwner.Parent; } return(indenter.GetIndentationOfLine( sourceText.Lines.GetLineFromPosition( embeddedStatementOwner.GetFirstToken(includeZeroWidth: true).SpanStart ) )); } switch (token.Kind()) { case SyntaxKind.SemicolonToken: { // special cases if (token.IsSemicolonInForStatement()) { return(GetDefaultIndentationFromToken(indenter, token)); } return(indenter.IndentFromStartOfLine( indenter.Finder.GetIndentationOfCurrentPosition( indenter.Tree, token, position, indenter.CancellationToken ) )); } case SyntaxKind.CloseBraceToken: { if ( token.Parent.IsKind(SyntaxKind.AccessorList) && token.Parent.Parent.IsKind(SyntaxKind.PropertyDeclaration) ) { if (token.GetNextToken().IsEqualsTokenInAutoPropertyInitializers()) { return(GetDefaultIndentationFromToken(indenter, token)); } } return(indenter.IndentFromStartOfLine( indenter.Finder.GetIndentationOfCurrentPosition( indenter.Tree, token, position, indenter.CancellationToken ) )); } case SyntaxKind.OpenBraceToken: { return(indenter.IndentFromStartOfLine( indenter.Finder.GetIndentationOfCurrentPosition( indenter.Tree, token, position, indenter.CancellationToken ) )); } case SyntaxKind.ColonToken: { var nonTerminalNode = token.Parent; Contract.ThrowIfNull(nonTerminalNode, @"Malformed code or bug in parser???"); if (nonTerminalNode is SwitchLabelSyntax) { return(indenter.GetIndentationOfLine( sourceText.Lines.GetLineFromPosition( nonTerminalNode.GetFirstToken(includeZeroWidth: true).SpanStart ), indenter.OptionSet.GetOption( FormattingOptions.IndentationSize, token.Language ) )); } goto default; } case SyntaxKind.CloseBracketToken: { var nonTerminalNode = token.Parent; Contract.ThrowIfNull(nonTerminalNode, @"Malformed code or bug in parser???"); // if this is closing an attribute, we shouldn't indent. if (nonTerminalNode is AttributeListSyntax) { return(indenter.GetIndentationOfLine( sourceText.Lines.GetLineFromPosition( nonTerminalNode.GetFirstToken(includeZeroWidth: true).SpanStart ) )); } goto default; } case SyntaxKind.XmlTextLiteralToken: { return(indenter.GetIndentationOfLine( sourceText.Lines.GetLineFromPosition(token.SpanStart) )); } case SyntaxKind.CommaToken: { return(GetIndentationFromCommaSeparatedList(indenter, token)); } case SyntaxKind.CloseParenToken: { if (token.Parent.IsKind(SyntaxKind.ArgumentList)) { return(GetDefaultIndentationFromToken( indenter, token.Parent.GetFirstToken(includeZeroWidth: true) )); } goto default; } default: { return(GetDefaultIndentationFromToken(indenter, token)); } } }
public static SyntaxNode?GetAncestor(this SyntaxToken token, Func <SyntaxNode, bool>?predicate) => token.GetAncestor <SyntaxNode>(predicate);
public override AdjustNewLinesOperation GetAdjustNewLinesOperation(SyntaxToken previousToken, SyntaxToken currentToken, OptionSet optionSet, NextOperation<AdjustNewLinesOperation> nextOperation) { if (previousToken.IsNestedQueryExpression()) { return CreateAdjustNewLinesOperation(0, AdjustNewLinesOption.PreserveLines); } // skip the very first from keyword if (currentToken.IsFirstFromKeywordInExpression()) { return nextOperation.Invoke(); } switch (currentToken.Kind()) { case SyntaxKind.FromKeyword: case SyntaxKind.WhereKeyword: case SyntaxKind.LetKeyword: case SyntaxKind.JoinKeyword: case SyntaxKind.OrderByKeyword: case SyntaxKind.GroupKeyword: case SyntaxKind.SelectKeyword: if (currentToken.GetAncestor<QueryExpressionSyntax>() != null) { if (optionSet.GetOption(CSharpFormattingOptions.NewLineForClausesInQuery)) { return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines); } else { return CreateAdjustNewLinesOperation(0, AdjustNewLinesOption.PreserveLines); } } break; } return nextOperation.Invoke(); }
public static bool IsBeginningOfStatementContext(this SyntaxToken token) { // cases: // { // | // } // | // Note, the following is *not* a legal statement context: // do { } | // ...; // | // case 0: // | // default: // | // label: // | // if (foo) // | // while (true) // | // do // | // for (;;) // | // foreach (var v in c) // | // else // | // using (expr) // | // fixed (void* v = &expr) // | // lock (expr) // | // for ( ; ; Foo(), | if (token.Kind() == SyntaxKind.OpenBraceToken && token.Parent.IsKind(SyntaxKind.Block)) { return(true); } if (token.Kind() == SyntaxKind.SemicolonToken) { var statement = token.GetAncestor <StatementSyntax>(); if (statement != null && !statement.IsParentKind(SyntaxKind.GlobalStatement) && statement.GetLastToken(includeZeroWidth: true) == token) { return(true); } } if (token.Kind() == SyntaxKind.CloseBraceToken && token.Parent.IsKind(SyntaxKind.Block)) { if (token.Parent.Parent is StatementSyntax) { // Most blocks that are the child of statement are places // that we can follow with another statement. i.e.: // if { } // while () { } // There are two exceptions. // try {} // do {} if (!token.Parent.IsParentKind(SyntaxKind.TryStatement) && !token.Parent.IsParentKind(SyntaxKind.DoStatement)) { return(true); } } else if ( token.Parent.IsParentKind(SyntaxKind.ElseClause) || token.Parent.IsParentKind(SyntaxKind.FinallyClause) || token.Parent.IsParentKind(SyntaxKind.CatchClause) || token.Parent.IsParentKind(SyntaxKind.SwitchSection)) { return(true); } } if (token.Kind() == SyntaxKind.CloseBraceToken && token.Parent.IsKind(SyntaxKind.SwitchStatement)) { return(true); } if (token.Kind() == SyntaxKind.ColonToken) { if (token.Parent.IsKind(SyntaxKind.CaseSwitchLabel, SyntaxKind.DefaultSwitchLabel, SyntaxKind.LabeledStatement)) { return(true); } } if (token.Kind() == SyntaxKind.DoKeyword && token.Parent.IsKind(SyntaxKind.DoStatement)) { return(true); } if (token.Kind() == SyntaxKind.CloseParenToken) { var parent = token.Parent; if (parent.IsKind(SyntaxKind.ForStatement) || parent.IsKind(SyntaxKind.ForEachStatement) || parent.IsKind(SyntaxKind.ForEachComponentStatement) || parent.IsKind(SyntaxKind.WhileStatement) || parent.IsKind(SyntaxKind.IfStatement) || parent.IsKind(SyntaxKind.LockStatement) || parent.IsKind(SyntaxKind.UsingStatement) || parent.IsKind(SyntaxKind.FixedStatement)) { return(true); } } if (token.Kind() == SyntaxKind.ElseKeyword) { return(true); } return(false); }
private IEnumerable<CompletionItem> GetTagsForProperty(IPropertySymbol symbol, TextSpan itemSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token) { var items = new List<CompletionItem>(); if (symbol.IsIndexer) { var parameters = symbol.GetParameters().Select(p => p.Name).ToSet(); // User is trying to write a name, try to suggest only names. if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) || (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute))) { string parentElementName = null; var emptyElement = token.GetAncestor<XmlEmptyElementSyntax>(); if (emptyElement != null) { parentElementName = emptyElement.Name.LocalName.Text; } // We're writing the name of a paramref if (parentElementName == ParamRefTagName) { items.AddRange(parameters.Select(p => CreateCompletionItem(itemSpan, p))); } return items; } RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, ParamTagName)); items.AddRange(parameters.Select(p => CreateCompletionItem(itemSpan, FormatParameter(ParamTagName, p)))); } var typeParameters = symbol.GetTypeArguments().Select(p => p.Name).ToSet(); items.AddRange(typeParameters.Select(t => CreateCompletionItem(itemSpan, TypeParamTagName, NameAttributeName, t))); items.Add(CreateCompletionItem(itemSpan, "value")); return items; }
public static bool IsBeginningOfGlobalStatementContext(this SyntaxToken token) { // cases: // } // | // ...; // | // extern alias Goo; // using System; // | // [assembly: Goo] // | if (token.Kind() == SyntaxKind.CloseBraceToken) { var memberDeclaration = token.GetAncestor <MemberDeclarationSyntax>(); if (memberDeclaration != null && memberDeclaration.GetLastToken(includeZeroWidth: true) == token && memberDeclaration.IsParentKind(SyntaxKind.CompilationUnit)) { return(true); } } if (token.Kind() == SyntaxKind.SemicolonToken) { var globalStatement = token.GetAncestor <GlobalStatementSyntax>(); if (globalStatement != null && globalStatement.GetLastToken(includeZeroWidth: true) == token) { return(true); } if (token.Parent is FileScopedNamespaceDeclarationSyntax namespaceDeclaration && namespaceDeclaration.SemicolonToken == token) { return(true); } var memberDeclaration = token.GetAncestor <MemberDeclarationSyntax>(); if (memberDeclaration != null && memberDeclaration.GetLastToken(includeZeroWidth: true) == token && memberDeclaration.IsParentKind(SyntaxKind.CompilationUnit)) { return(true); } var compUnit = token.GetAncestor <CompilationUnitSyntax>(); if (compUnit != null) { if (compUnit.Usings.Count > 0 && compUnit.Usings.Last().GetLastToken(includeZeroWidth: true) == token) { return(true); } if (compUnit.Externs.Count > 0 && compUnit.Externs.Last().GetLastToken(includeZeroWidth: true) == token) { return(true); } } } if (token.Kind() == SyntaxKind.CloseBracketToken) { var compUnit = token.GetAncestor <CompilationUnitSyntax>(); if (compUnit != null) { if (compUnit.AttributeLists.Count > 0 && compUnit.AttributeLists.Last().GetLastToken(includeZeroWidth: true) == token) { return(true); } } } return(false); }
private static SyntaxNode GetExpansionTarget(SyntaxToken token) { // get the directly enclosing statement var enclosingStatement = token.GetAncestors(n => n is StatementSyntax).FirstOrDefault(); // System.Func<int, int> myFunc = arg => X; SyntaxNode possibleLambdaExpression = enclosingStatement == null ? token.GetAncestors(n => n is SimpleLambdaExpressionSyntax || n is ParenthesizedLambdaExpressionSyntax).FirstOrDefault() : null; if (possibleLambdaExpression != null) { var lambdaExpression = ((LambdaExpressionSyntax)possibleLambdaExpression); if (lambdaExpression.Body is ExpressionSyntax) { return lambdaExpression.Body; } } // int M() => X; var possibleArrowExpressionClause = enclosingStatement == null ? token.GetAncestors<ArrowExpressionClauseSyntax>().FirstOrDefault() : null; if (possibleArrowExpressionClause != null) { return possibleArrowExpressionClause.Expression; } var enclosingNameMemberCrefOrnull = token.GetAncestors(n => n is NameMemberCrefSyntax).LastOrDefault(); if (enclosingNameMemberCrefOrnull != null) { if (token.Parent is TypeSyntax && token.Parent.Parent is TypeSyntax) { enclosingNameMemberCrefOrnull = null; } } var enclosingXmlNameAttr = token.GetAncestors(n => n is XmlNameAttributeSyntax).FirstOrDefault(); if (enclosingXmlNameAttr != null) { return null; } var enclosingInitializer = token.GetAncestors<EqualsValueClauseSyntax>().FirstOrDefault(); if (enclosingStatement == null && enclosingInitializer != null && enclosingInitializer.Parent is VariableDeclaratorSyntax) { return enclosingInitializer.Value; } var attributeSyntax = token.GetAncestor<AttributeSyntax>(); if (attributeSyntax != null) { return attributeSyntax; } // there seems to be no statement above this one. Let's see if we can at least get an SimpleNameSyntax return enclosingStatement ?? enclosingNameMemberCrefOrnull ?? token.GetAncestors(n => n is SimpleNameSyntax).FirstOrDefault(); }
private IEnumerable <CompletionItem> GetTagsForMethod(IMethodSymbol symbol, TextSpan itemSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token) { var items = new List <CompletionItem>(); var parameters = symbol.GetParameters().Select(p => p.Name).ToSet(); var typeParameters = symbol.TypeParameters.Select(t => t.Name).ToSet(); // User is trying to write a name, try to suggest only names. if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) || (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute))) { string parentElementName = null; var emptyElement = token.GetAncestor <XmlEmptyElementSyntax>(); if (emptyElement != null) { parentElementName = emptyElement.Name.LocalName.Text; } // We're writing the name of a paramref or typeparamref if (parentElementName == ParamRefTagName) { items.AddRange(parameters.Select(p => CreateCompletionItem(itemSpan, p))); } else if (parentElementName == TypeParamRefTagName) { items.AddRange(typeParameters.Select(t => CreateCompletionItem(itemSpan, t))); } return(items); } RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, ParamTagName)); RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, TypeParamTagName)); items.AddRange(parameters.Select(p => CreateCompletionItem(itemSpan, FormatParameter(ParamTagName, p)))); items.AddRange(typeParameters.Select(t => CreateCompletionItem(itemSpan, FormatParameter(TypeParamTagName, t)))); // Provide a return completion item in case the function returns something var returns = true; foreach (var node in trivia.Content) { var element = node as XmlElementSyntax; if (element != null && !element.StartTag.IsMissing && !element.EndTag.IsMissing) { var startTag = element.StartTag; if (startTag.Name.LocalName.ValueText == ReturnsTagName) { returns = false; break; } } } if (returns && !symbol.ReturnsVoid) { items.Add(CreateCompletionItem(itemSpan, ReturnsTagName)); } return(items); }