private static async Task <Document> RefactorAsync( Document document, AttributeSyntax attribute, CancellationToken cancellationToken) { TypeDeclarationSyntax typeDeclaration = attribute.FirstAncestor <TypeDeclarationSyntax>(); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); string propertyName = NameGenerator.Default.EnsureUniqueName(DefaultNames.DebuggerDisplayPropertyName, semanticModel, typeDeclaration.OpenBraceToken.Span.End); AttributeArgumentSyntax argument = attribute.ArgumentList.Arguments.First(); TypeDeclarationSyntax newTypeDeclaration = typeDeclaration.ReplaceNode( argument, argument.WithExpression( StringLiteralExpression($"{{{propertyName},nq}}")).WithTriviaFrom(argument.Expression)); string value = semanticModel .GetDeclaredSymbol(typeDeclaration, cancellationToken) .GetAttribute(MetadataNames.System_Diagnostics_DebuggerDisplayAttribute) .ConstructorArguments[0] .Value .ToString(); bool isVerbatim = SyntaxInfo.StringLiteralExpressionInfo(argument.Expression).IsVerbatim; ExpressionSyntax returnExpression = GetReturnExpression(value, isVerbatim); PropertyDeclarationSyntax propertyDeclaration = MarkTypeWithDebuggerDisplayAttributeRefactoring.DebuggerDisplayPropertyDeclaration(propertyName, returnExpression); newTypeDeclaration = MemberDeclarationInserter.Default.Insert(newTypeDeclaration, propertyDeclaration); return(await document.ReplaceNodeAsync(typeDeclaration, newTypeDeclaration, cancellationToken).ConfigureAwait(false)); }
private static bool CanReplaceInterpolationWithStringLiteralInnerText(SeparatedSyntaxList <ArgumentSyntax> arguments, bool isVerbatim) { bool result = false; for (int i = 1; i < arguments.Count; i++) { ExpressionSyntax expression = arguments[i].Expression; StringLiteralExpressionInfo info = SyntaxInfo.StringLiteralExpressionInfo(expression); if (info.Success) { if (isVerbatim == info.IsVerbatim && info.Expression.GetLeadingTrivia().IsEmptyOrWhitespace() && info.Expression.GetTrailingTrivia().IsEmptyOrWhitespace()) { result = true; } else { return(false); } } } return(result); }
public static void AnalyzeInterpolation(SyntaxNodeAnalysisContext context) { var interpolation = (InterpolationSyntax)context.Node; if (interpolation.AlignmentClause != null) { return; } if (interpolation.FormatClause != null) { return; } StringLiteralExpressionInfo stringLiteralInfo = SyntaxInfo.StringLiteralExpressionInfo(interpolation.Expression); if (!stringLiteralInfo.Success) { return; } if (!(interpolation.Parent is InterpolatedStringExpressionSyntax interpolatedString)) { return; } if (interpolatedString.StringStartToken.ValueText.Contains("@") != stringLiteralInfo.IsVerbatim) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UnnecessaryInterpolation, interpolation); }
public static Task <Document> RefactorAsync( Document document, BinaryExpressionSyntax binaryExpression, TextSpan span, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ExpressionSyntax[] expressions = binaryExpression.AsChain(span).ToArray(); ExpressionSyntax firstExpression = expressions[0]; bool isVerbatim; var isInterpolated = false; if (firstExpression is InterpolatedStringExpressionSyntax interpolatedString) { isVerbatim = interpolatedString.IsVerbatim(); isInterpolated = true; } else { isVerbatim = SyntaxInfo.StringLiteralExpressionInfo(firstExpression).IsVerbatim; } StringBuilder sb = StringBuilderCache.GetInstance(); var builder = new StringLiteralTextBuilder(sb, isVerbatim: isVerbatim, isInterpolated: isInterpolated); builder.AppendStart(); foreach (ExpressionSyntax expression in expressions) { switch (expression.Kind()) { case SyntaxKind.StringLiteralExpression: { builder.Append((LiteralExpressionSyntax)expression); break; } case SyntaxKind.InterpolatedStringExpression: { builder.Append((InterpolatedStringExpressionSyntax)expression); break; } } } builder.AppendEnd(); string newText = builder.ToString(); StringBuilderCache.Free(sb); TextSpan changedSpan = TextSpan.FromBounds(firstExpression.SpanStart, expressions.Last().Span.End); return(document.WithTextChangeAsync(changedSpan, newText, cancellationToken)); }
private static async Task <Document> RefactorAsync( Document document, AttributeSyntax attribute, CancellationToken cancellationToken) { TypeDeclarationSyntax typeDeclaration = attribute.FirstAncestor <TypeDeclarationSyntax>(); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); string propertyName = NameGenerator.Default.EnsureUniqueMemberName(PropertyName, semanticModel, typeDeclaration.OpenBraceToken.Span.End, cancellationToken: cancellationToken); AttributeArgumentSyntax argument = attribute.ArgumentList.Arguments.First(); TypeDeclarationSyntax newTypeDeclaration = typeDeclaration.ReplaceNode( argument, argument.WithExpression( StringLiteralExpression($"{{{propertyName},nq}}")).WithTriviaFrom(argument.Expression)); string value = semanticModel .GetDeclaredSymbol(typeDeclaration, cancellationToken) .GetAttribute(semanticModel.GetTypeByMetadataName(MetadataNames.System_Diagnostics_DebuggerDisplayAttribute)) .ConstructorArguments[0] .Value .ToString(); ExpressionSyntax returnExpression = GetReturnExpression(value, SyntaxInfo.StringLiteralExpressionInfo(argument.Expression).IsVerbatim); PropertyDeclarationSyntax propertyDeclaration = PropertyDeclaration( SingletonList( AttributeList( Attribute( ParseName("System.Diagnostics.DebuggerBrowsableAttribute"), AttributeArgument( SimpleMemberAccessExpression( ParseName("System.Diagnostics.DebuggerBrowsableState").WithSimplifierAnnotation(), IdentifierName("Never")) ) ).WithSimplifierAnnotation() ) ), Modifiers.Private(), CSharpTypeFactory.StringType(), default(ExplicitInterfaceSpecifierSyntax), Identifier(propertyName).WithRenameAnnotation(), AccessorList( GetAccessorDeclaration( Block( ReturnStatement(returnExpression))))); propertyDeclaration = propertyDeclaration.WithFormatterAnnotation(); newTypeDeclaration = MemberDeclarationInserter.Default.Insert(newTypeDeclaration, propertyDeclaration); return(await document.ReplaceNodeAsync(typeDeclaration, newTypeDeclaration, cancellationToken).ConfigureAwait(false)); }
public static Task <Document> RefactorAsync( Document document, InterpolationSyntax interpolation, CancellationToken cancellationToken = default(CancellationToken)) { var interpolatedString = (InterpolatedStringExpressionSyntax)interpolation.Parent; string s = interpolatedString.ToString(); s = s.Substring(0, interpolation.SpanStart - interpolatedString.SpanStart) + StringUtility.DoubleBraces(SyntaxInfo.StringLiteralExpressionInfo(interpolation.Expression).InnerText) + s.Substring(interpolation.Span.End - interpolatedString.SpanStart); var newInterpolatedString = (InterpolatedStringExpressionSyntax)SyntaxFactory.ParseExpression(s) .WithTriviaFrom(interpolatedString); return(document.ReplaceNodeAsync(interpolatedString, newInterpolatedString, cancellationToken)); }
public static void AnalyzeAddExpression(SyntaxNodeAnalysisContext context) { SyntaxNode node = context.Node; if (node.ContainsDiagnostics) { return; } if (node.SpanContainsDirectives()) { return; } if (node.IsParentKind(SyntaxKind.AddExpression)) { return; } var addExpression = (BinaryExpressionSyntax)node; ExpressionSyntax firstExpression = null; ExpressionSyntax lastExpression = null; bool isLiteral = false; bool isVerbatim = false; foreach (ExpressionSyntax expression in addExpression.AsChain().Reverse()) { context.ThrowIfCancellationRequested(); switch (expression.Kind()) { case SyntaxKind.StringLiteralExpression: { bool isVerbatim2 = SyntaxInfo.StringLiteralExpressionInfo(expression).IsVerbatim; if (firstExpression == null) { firstExpression = expression; isLiteral = true; isVerbatim = isVerbatim2; } else if (!isLiteral || isVerbatim != isVerbatim2) { if (lastExpression != null) { Analyze(context, firstExpression, lastExpression, isVerbatim); } firstExpression = null; lastExpression = null; } else { lastExpression = expression; } break; } case SyntaxKind.InterpolatedStringExpression: { bool isVerbatim2 = ((InterpolatedStringExpressionSyntax)expression).IsVerbatim(); if (firstExpression == null) { firstExpression = expression; isLiteral = false; isVerbatim = isVerbatim2; } else if (isLiteral || isVerbatim != isVerbatim2) { if (lastExpression != null) { Analyze(context, firstExpression, lastExpression, isVerbatim); } firstExpression = null; lastExpression = null; } else { lastExpression = expression; } break; } default: { if (lastExpression != null) { Analyze(context, firstExpression, lastExpression, isVerbatim); } firstExpression = null; lastExpression = null; break; } } } if (lastExpression != null) { Analyze(context, firstExpression, lastExpression, isVerbatim); } }
private static InterpolatedStringExpressionSyntax ReplaceInterpolationWithStringLiteralInnerText( SeparatedSyntaxList <ArgumentSyntax> arguments, InterpolatedStringExpressionSyntax interpolatedString, string text) { StringBuilder sb = StringBuilderCache.GetInstance(); int pos = 0; SyntaxList <InterpolatedStringContentSyntax> contents = interpolatedString.Contents; for (int i = 0; i < contents.Count; i++) { if (contents[i].Kind() != SyntaxKind.Interpolation) { continue; } var interpolation = (InterpolationSyntax)contents[i]; ExpressionSyntax expression = interpolation.Expression; if (expression?.Kind() != SyntaxKind.NumericLiteralExpression) { continue; } var index = (int)((LiteralExpressionSyntax)expression).Token.Value; if (index < 0) { continue; } if (index >= arguments.Count) { continue; } ExpressionSyntax argumentExpression = arguments[index + 1].Expression; StringLiteralExpressionInfo stringLiteral = SyntaxInfo.StringLiteralExpressionInfo(argumentExpression); if (!stringLiteral.Success) { continue; } sb.Append(text, pos, interpolation.SpanStart - pos); int startIndex = sb.Length; sb.Append(stringLiteral.InnerText); sb.Replace("{", "{{", startIndex); sb.Replace("}", "}}", startIndex); pos = interpolation.Span.End; } sb.Append(text, pos, text.Length - pos); return((InterpolatedStringExpressionSyntax)ParseExpression(StringBuilderCache.GetStringAndFree(sb))); }
private static void AnalyzeAddExpression(SyntaxNodeAnalysisContext context) { SyntaxNode node = context.Node; if (node.ContainsDiagnostics) { return; } if (node.SpanContainsDirectives()) { return; } if (node.IsParentKind(SyntaxKind.AddExpression)) { return; } var addExpression = (BinaryExpressionSyntax)node; ExpressionSyntax firstExpression = null; ExpressionSyntax lastExpression = null; var isLiteral = false; var isVerbatim = false; int startLine = -1; foreach (ExpressionSyntax expression in addExpression.AsChain().Reverse()) { context.CancellationToken.ThrowIfCancellationRequested(); switch (expression.Kind()) { case SyntaxKind.StringLiteralExpression: { StringLiteralExpressionInfo stringLiteral = SyntaxInfo.StringLiteralExpressionInfo(expression); bool isVerbatim2 = stringLiteral.IsVerbatim; if (firstExpression == null) { firstExpression = expression; isLiteral = true; isVerbatim = isVerbatim2; if (isVerbatim) { startLine = expression.SyntaxTree.GetLineSpan(expression.GetSpan()).StartLine(); } } else if (!isLiteral || isVerbatim != isVerbatim2 || (!isVerbatim && !CheckHexadecimalEscapeSequence(stringLiteral))) { if (lastExpression != null) { Analyze(context, firstExpression, lastExpression, isVerbatim); } firstExpression = null; lastExpression = null; } else { lastExpression = expression; if (isVerbatim) { FileLinePositionSpan lineSpan = expression.SyntaxTree.GetLineSpan(expression.GetSpan()); if (startLine != lineSpan.EndLine()) { firstExpression = null; lastExpression = null; } else { startLine = lineSpan.StartLine(); } } } break; } case SyntaxKind.InterpolatedStringExpression: { var interpolatedString = ((InterpolatedStringExpressionSyntax)expression); bool isVerbatim2 = interpolatedString.IsVerbatim(); if (firstExpression == null) { firstExpression = expression; isLiteral = false; isVerbatim = isVerbatim2; if (isVerbatim) { startLine = expression.SyntaxTree.GetLineSpan(expression.GetSpan()).StartLine(); } } else if (isLiteral || isVerbatim != isVerbatim2 || (!isVerbatim && !CheckHexadecimalEscapeSequence(interpolatedString))) { if (lastExpression != null) { Analyze(context, firstExpression, lastExpression, isVerbatim); } firstExpression = null; lastExpression = null; } else { lastExpression = expression; if (isVerbatim) { FileLinePositionSpan lineSpan = expression.SyntaxTree.GetLineSpan(expression.GetSpan()); if (startLine != lineSpan.EndLine()) { firstExpression = null; lastExpression = null; } else { startLine = lineSpan.StartLine(); } } } break; } default: { if (lastExpression != null) { Analyze(context, firstExpression, lastExpression, isVerbatim); } firstExpression = null; lastExpression = null; break; } } } if (lastExpression != null) { Analyze(context, firstExpression, lastExpression, isVerbatim); } }
public static async Task ComputeRefactoringsAsync(RefactoringContext context, LiteralExpressionSyntax literalExpression) { StringLiteralExpressionInfo info = SyntaxInfo.StringLiteralExpressionInfo(literalExpression); Debug.Assert(info.Success); if (!info.Success) { return; } if (context.IsRefactoringEnabled(RefactoringIdentifiers.InsertStringInterpolation) && context.SupportsCSharp6 && context.Span.End < literalExpression.Span.End) { int startIndex = GetStartIndex(info, context.Span); if (startIndex != -1) { context.RegisterRefactoring( "Insert interpolation", cancellationToken => { return(ReplaceWithInterpolatedStringAsync( context.Document, literalExpression, startIndex, context.Span.Length, addNameOf: false, cancellationToken: cancellationToken)); }); if (!context.Span.IsEmpty) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); string name = StringLiteralParser.Parse(literalExpression.Token.Text, startIndex, context.Span.Length, info.IsVerbatim, isInterpolatedText: false); foreach (ISymbol symbol in semanticModel.LookupSymbols(literalExpression.SpanStart)) { if (string.Equals(name, symbol.MetadataName, StringComparison.Ordinal)) { context.RegisterRefactoring( "Insert interpolation with nameof", cancellationToken => { return(ReplaceWithInterpolatedStringAsync( context.Document, literalExpression, startIndex, context.Span.Length, addNameOf: true, cancellationToken: cancellationToken)); }); break; } } } } } if (context.Span.IsBetweenSpans(literalExpression)) { if (info.IsVerbatim) { if (info.ContainsEscapeSequence) { if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceVerbatimStringLiteralWithRegularStringLiteral)) { context.RegisterRefactoring( "Replace verbatim string literal with regular string literal", ct => ReplaceWithRegularStringLiteralAsync(context.Document, literalExpression, ct)); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceVerbatimStringLiteralWithRegularStringLiterals) && info.ContainsLinefeed) { context.RegisterRefactoring( "Replace verbatim string literal with regular string literals", ct => ReplaceWithRegularStringLiteralsAsync(context.Document, literalExpression, ct)); } } } else if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceRegularStringLiteralWithVerbatimStringLiteral) && info.ContainsEscapeSequence) { context.RegisterRefactoring( "Replace regular string literal with verbatim string literal", ct => ReplaceWithVerbatimStringLiteralAsync(context.Document, literalExpression, ct)); } } if (context.IsRefactoringEnabled(RefactoringIdentifiers.UseStringEmptyInsteadOfEmptyStringLiteral) && CanReplaceWithStringEmpty(literalExpression)) { context.RegisterRefactoring( "Replace \"\" with 'string.Empty'", ct => ReplaceWithStringEmptyAsync(context.Document, literalExpression, ct)); } }