private static IdentifierNameSyntax PadMemberAccess( SimpleLambdaExpressionSyntax node, IdentifierNameSyntax memberAccess) { // We want to make the new span var originalSpan = node.GetLocation().GetMappedLineSpan(); // Start by collecting all the trivia 'inside' the expression - we need to tack that on the end, but // if it ends with a newline, don't include that. var innerTrivia = SyntaxFactory.TriviaList(node.DescendantTrivia(descendIntoChildren: n => true)); if (innerTrivia.Count > 0 && innerTrivia[innerTrivia.Count - 1].IsKind(SyntaxKind.EndOfLineTrivia)) { innerTrivia = innerTrivia.RemoveAt(innerTrivia.Count - 1); } memberAccess = memberAccess.WithTrailingTrivia(innerTrivia); // If everything is all on one line, then make sure the spans are the same, to compensate // for the expression potentially being longer than the variable name. var lineSpan = originalSpan.EndLinePosition.Line - originalSpan.StartLinePosition.Line; if (lineSpan == 0) { var padding = node.Span.Length - memberAccess.FullSpan.Length; var trailingTrivia = SyntaxFactory.TriviaList(memberAccess.GetTrailingTrivia()) .Add(SyntaxFactory.Whitespace(new string(' ', padding))) .AddRange(node.GetTrailingTrivia()); return (memberAccess .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(trailingTrivia)); } else { // If everything isn't on the same line, we need to pad out the last line. var padding = originalSpan.EndLinePosition.Character - originalSpan.StartLinePosition.Character; var trailingTrivia = SyntaxFactory.TriviaList(memberAccess.GetTrailingTrivia()) .Add(SyntaxFactory.Whitespace(new string(' ', padding))) .AddRange(node.GetTrailingTrivia()); return (memberAccess .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(trailingTrivia)); } }
public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) { if (node.Initializer == null || IsAnonymousType(node)) { return(base.VisitObjectCreationExpression(node)); } ObjectCreationExpressionSyntax newNode = (ObjectCreationExpressionSyntax)base.VisitObjectCreationExpression(node); var openBrace = newNode.Initializer.OpenBraceToken; var closeBrace = newNode.Initializer.CloseBraceToken; IdentifierNameSyntax obj = IdentifierName("_obj_"); var constructObject = GenerateObject(newNode.Type.WithoutTrailingTrivia(), obj.Identifier, node.ArgumentList) .WithTrailingTrivia(openBrace.TrailingTrivia) .WithLeadingTrivia((newNode.ArgumentList?.GetTrailingTrivia() ?? newNode.Type.GetTrailingTrivia()).AddRange(openBrace.LeadingTrivia)); StatementSyntax[] statements = GetInitialiserFunctionStatements(node, newNode, obj); var returnObject = ReturnStatement(obj.WithLeadingTrivia(Space)).WithLeadingTrivia(closeBrace.LeadingTrivia); var func = GenerateFunction(constructObject, statements, returnObject); requiresSystemUsing = true; return(GenerateInvocation(newNode, func)); }
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) { // We only care about xml doc comments var leadingTrivia = CanHaveDocComments(node) ? VisitList(node.GetLeadingTrivia()) : node.GetLeadingTrivia(); if (_namespaceMembers.Contains(node.Identifier.Text)) { var expanded = Simplifier.Expand <SyntaxNode>(node, _model, _workspace, cancellationToken: _cancellationToken); return(expanded.WithLeadingTrivia(leadingTrivia)); } return(node.WithLeadingTrivia(leadingTrivia)); }
private static IdentifierNameSyntax PadMemberAccess( SimpleLambdaExpressionSyntax node, IdentifierNameSyntax memberAccess) { // We want to make the new span var originalSpan = node.GetLocation().GetMappedLineSpan(); var charactersToExclude = memberAccess.Identifier.Text.Length; var triviaList = new SyntaxTriviaList(); // Go through each token and // 1. Append leading trivia // 2. Append the same number of whitespace as the length of the token text // 3. Append trailing trivia foreach (var token in node.DescendantTokens()) { if (token.HasLeadingTrivia) { triviaList = triviaList.AddRange(token.LeadingTrivia); } // Need to exclude the length of the member name from the padding. var padding = token.Text.Length; if (padding > charactersToExclude) { padding -= charactersToExclude; charactersToExclude = 0; } else { charactersToExclude -= padding; padding = 0; } if (padding > 0) { triviaList = triviaList.Add(SyntaxFactory.Whitespace(new string(' ', padding))); } if (token.HasTrailingTrivia) { triviaList = triviaList.AddRange(token.TrailingTrivia); } } return(memberAccess .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(triviaList)); }
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) { ISymbol referencedSymbol = this.model.GetSymbolInfo(node, this.cancellationToken).Symbol; // Static members don't have to be qualified if (referencedSymbol == null || referencedSymbol.IsStatic) { return(base.VisitIdentifierName(node)); } // Check is the name already qualified. If so, no further action is needed (only top-most identifier may be qualified) // Considers: // a.>b<.foo() -> a.b.foo() if (node.Ancestors().OfType <MemberAccessExpressionSyntax>().Any(n => n.Name.DescendantNodesAndSelf().Contains(node))) { return(base.VisitIdentifierName(node)); } // Considers: // >a<.b.foo() -> newParameter.a.b.foo() if (referencedSymbol.Kind == CommonSymbolKind.Field || referencedSymbol.Kind == CommonSymbolKind.Method || referencedSymbol.Kind == CommonSymbolKind.Property || referencedSymbol.Kind == CommonSymbolKind.Event) { // Special case: constructor of different type is an unqualified and non-static member if (referencedSymbol.Kind == CommonSymbolKind.Method) { MethodSymbol method = (MethodSymbol)referencedSymbol; if (method.MethodKind == MethodKind.Constructor) { return(base.VisitIdentifierName(node)); } } // Create new context with leading trivia of old context IdentifierNameSyntax parameterIdentifier = Syntax.IdentifierName(this.newParameterNameToken) .WithLeadingTrivia(node.GetLeadingTrivia()); // And remove leading trivia from old context IdentifierNameSyntax context = node.WithLeadingTrivia(); return(Syntax.MemberAccessExpression(SyntaxKind.MemberAccessExpression, parameterIdentifier, context)); } return(base.VisitIdentifierName(node)); }
private static ExpressionStatementSyntax ExpressionRewriter( this ExpressionStatementSyntax expression, SemanticModel model, string from = null, string to = null, IdentifierNameSyntax identifier = null, Func <InvocationExpressionSyntax, InvocationExpressionSyntax> func = null) { if (!(expression.Expression is InvocationExpressionSyntax invocation)) { return(expression); } if (invocation.Expression.Kind() != SyntaxKind.SimpleMemberAccessExpression) { return(expression); } if (!invocation.Expression.ToString().Equals(from, StringComparison.OrdinalIgnoreCase)) { return(expression); } if (invocation.Expression is MemberAccessExpressionSyntax mae) { if (identifier != null) { identifier = identifier.WithLeadingTrivia(mae.Expression.GetLeadingTrivia()); expression = expression.ReplaceNode(expression.Expression, expression.Expression.ReplaceNode(mae, mae.WithExpression(identifier))); } expression = expression.ReplaceNode(expression.Expression, invocation.ReplaceNode(mae, mae.WithName(IdentifierName(to)))); } if (func != null) { expression = expression.ReplaceNode(expression.Expression, func((InvocationExpressionSyntax)expression.Expression)); } expression = expression.RewriteAssertMessage(model); return(expression); }
private async Task<Document> AddNullableComment(Document document, TypeConstraintSyntax typeConstraintNode, CancellationToken cancellationToken) { var constraintClause = (TypeParameterConstraintClauseSyntax)typeConstraintNode.Parent; TypeConstraintSyntax[] otherTypeConstraints = constraintClause.ChildNodes().OfType<TypeConstraintSyntax>().Except(new[] { typeConstraintNode }).ToArray(); SyntaxNode root = await document.GetSyntaxRootAsync().ConfigureAwait(false); IdentifierNameSyntax idNameSyntax = constraintClause.ChildNodes().OfType<IdentifierNameSyntax>().First(); SyntaxToken identifierToken = typeConstraintNode.ChildNodes().First().ChildTokens().First(); TypeParameterConstraintClauseSyntax newConstraintClause; if (otherTypeConstraints.Length > 0) { // Only this type constraint must be removed, since the where clause contains others // Adding the starting comment before the type constraint SyntaxToken newIdentifierToken = SyntaxFactory.Identifier(identifierToken.LeadingTrivia.Add(SyntaxFactory.Comment(NullableReferenceTypeAnalyzer.NullableSyntaxMarker.Start)), SyntaxKind.IdentifierName, identifierToken.Text, identifierToken.ValueText, SyntaxTriviaList.Empty); TypeConstraintSyntax newNode = typeConstraintNode.ReplaceToken(identifierToken, newIdentifierToken); // Moving the new type constraint to the first of list SeparatedSyntaxList<TypeParameterConstraintSyntax> newConstraintList = SyntaxFactory.SeparatedList<TypeParameterConstraintSyntax>(otherTypeConstraints.Prepend(newNode)); newConstraintClause = SyntaxFactory.TypeParameterConstraintClause(idNameSyntax.WithLeadingTrivia(SyntaxFactory.Space)).WithConstraints(newConstraintList); // Adding the end type constraint after the first comma. SyntaxToken firstCommaToken = newConstraintClause.ChildTokens().First(token => token.IsKind(SyntaxKind.CommaToken)); SyntaxToken newCommaToken = SyntaxFactory.Token(firstCommaToken.LeadingTrivia, SyntaxKind.CommaToken, firstCommaToken.TrailingTrivia.Insert(0, SyntaxFactory.Comment(NullableReferenceTypeAnalyzer.NullableSyntaxMarker.End))); newConstraintClause = newConstraintClause.ReplaceToken(firstCommaToken, newCommaToken); } else { // the whole where clause needs to be removed, so adding the comments before and after it. SyntaxToken oldWhereKeyword = constraintClause.ChildTokens().First(it => it.IsKind(SyntaxKind.WhereKeyword)); SyntaxToken newWhereKeyword = SyntaxFactory.Token(oldWhereKeyword.LeadingTrivia.Add(SyntaxFactory.Comment(NullableReferenceTypeAnalyzer.NullableSyntaxMarker.Start)), SyntaxKind.WhereKeyword, oldWhereKeyword.TrailingTrivia); SyntaxToken newIdentifierToken = SyntaxFactory.Identifier(identifierToken.LeadingTrivia, SyntaxKind.IdentifierName, identifierToken.Text, identifierToken.ValueText, identifierToken.TrailingTrivia.Insert(0, SyntaxFactory.Comment(NullableReferenceTypeAnalyzer.NullableSyntaxMarker.End))); TypeConstraintSyntax newNode = typeConstraintNode.ReplaceToken(identifierToken, newIdentifierToken); newConstraintClause = SyntaxFactory.TypeParameterConstraintClause(newWhereKeyword, constraintClause.ChildNodes().OfType<IdentifierNameSyntax>().First(), constraintClause.ChildTokens().First(it => it.IsKind(SyntaxKind.ColonToken)), SyntaxFactory.SeparatedList<TypeParameterConstraintSyntax>(new[] { newNode })); } // for some reason Roslyn adds formatting annotations that results in some strange new lines being added // by formatter later in internal CleanupDocumentAsync method of CodeAction class. newConstraintClause = RemoveAnnotationFromDescendantTrivias(newConstraintClause, SyntaxAnnotation.ElasticAnnotation); SyntaxNode newRoot = root.ReplaceNode(constraintClause, newConstraintClause); Document result = document.WithSyntaxRoot(newRoot); return result; }