private static SyntaxKind GetInvertedOperatorKind(SyntaxToken operatorToken) { switch (operatorToken.Kind()) { case SyntaxKind.AmpersandAmpersandToken: return(SyntaxKind.BarBarToken); case SyntaxKind.BarBarToken: return(SyntaxKind.AmpersandAmpersandToken); case SyntaxKind.EqualsEqualsToken: return(SyntaxKind.ExclamationEqualsToken); case SyntaxKind.ExclamationEqualsToken: return(SyntaxKind.EqualsEqualsToken); case SyntaxKind.GreaterThanToken: return(SyntaxKind.LessThanEqualsToken); case SyntaxKind.GreaterThanEqualsToken: return(SyntaxKind.LessThanToken); case SyntaxKind.LessThanToken: return(SyntaxKind.GreaterThanEqualsToken); case SyntaxKind.LessThanEqualsToken: return(SyntaxKind.GreaterThanToken); default: { SyntaxDebug.Fail(operatorToken); return(operatorToken.Kind()); } } }
private static void ReportDiagnostic(SymbolAnalysisContext context, ISymbol member) { SyntaxNode node = member.GetSyntaxOrDefault(context.CancellationToken); Debug.Assert(node != null, member.ToString()); if (node == null) { return; } SyntaxToken identifier = CSharpUtility.GetIdentifier(node); SyntaxDebug.Assert(!identifier.IsKind(SyntaxKind.None), node); if (identifier.IsKind(SyntaxKind.None)) { return; } DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.StaticMemberInGenericTypeShouldUseTypeParameter, identifier); }
private static TypeSyntax DetermineReturnType(SyntaxNode node) { switch (node.Kind()) { case SyntaxKind.LocalFunctionStatement: return(((LocalFunctionStatementSyntax)node).ReturnType); case SyntaxKind.MethodDeclaration: return(((MethodDeclarationSyntax)node).ReturnType); case SyntaxKind.OperatorDeclaration: return(((OperatorDeclarationSyntax)node).ReturnType); case SyntaxKind.ConversionOperatorDeclaration: return(((ConversionOperatorDeclarationSyntax)node).Type); case SyntaxKind.PropertyDeclaration: return(((PropertyDeclarationSyntax)node).Type); case SyntaxKind.IndexerDeclaration: return(((IndexerDeclarationSyntax)node).Type); } if (node is AccessorDeclarationSyntax) { SyntaxDebug.Assert(node.IsParentKind(SyntaxKind.AccessorList), node.Parent); if (node.IsParentKind(SyntaxKind.AccessorList)) { return(DetermineReturnType(node.Parent.Parent)); } } return(null); }
private static void AnalyzeCompilationUnit(SyntaxNodeAnalysisContext context) { var compilationUnit = (CompilationUnitSyntax)context.Node; if (compilationUnit.Span.Length == 0) { return; } SyntaxToken token = compilationUnit.EndOfFileToken; if (token.FullSpan.Start > 0) { token = compilationUnit.GetFirstToken(); SyntaxDebug.Assert(token.FullSpan.Start == 0, token); if (token.FullSpan.Start > 0) { return; } } SyntaxTriviaList.Enumerator en = token.LeadingTrivia.GetEnumerator(); if (en.MoveNext() && en.Current.IsWhitespaceOrEndOfLineTrivia()) { ReportDiagnostic(context, token); }
private static void AnalyzeLocalFunctionStatement(SyntaxNodeAnalysisContext context) { var localFunctionStatement = (LocalFunctionStatementSyntax)context.Node; SyntaxTokenList modifiers = localFunctionStatement.Modifiers; int index = modifiers.IndexOf(SyntaxKind.UnsafeKeyword); if (index == -1) { return; } SyntaxNode parent = localFunctionStatement.Parent; SyntaxDebug.Assert(parent.IsKind(SyntaxKind.Block), parent); if (parent is not BlockSyntax) { return; } parent = parent.Parent; if (!ParentDeclarationsContainsUnsafeModifier(parent)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UnnecessaryUnsafeContext, modifiers[index]); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindNode(root, context.Span, out SyntaxNode node)) { return; } Diagnostic diagnostic = context.Diagnostics[0]; for (SyntaxNode parent = node.Parent; parent != null; parent = parent.Parent) { if (parent is MemberDeclarationSyntax memberDeclaration) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol symbol = semanticModel.GetSymbol(node, context.CancellationToken); if (symbol?.IsErrorType() != false) { return; } SyntaxDebug.Assert(SyntaxInfo.ModifierListInfo(memberDeclaration).IsStatic, memberDeclaration); if (SyntaxInfo.ModifierListInfo(memberDeclaration).IsStatic) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeMemberNonStatic, context.Document, root.SyntaxTree)) { ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, memberDeclaration, SyntaxKind.StaticKeyword, title: $"Make containing {CSharpFacts.GetTitle(memberDeclaration)} non-static", additionalKey: CodeFixIdentifiers.MakeMemberNonStatic); } if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier, context.Document, root.SyntaxTree)) { AddStaticModifier(context, diagnostic, node, semanticModel); } } return; } else if (parent is ConstructorInitializerSyntax) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier, context.Document, root.SyntaxTree)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); AddStaticModifier(context, diagnostic, node, semanticModel); } return; } } }
private static TypeSyntax GetTypeSyntax(SyntaxNode node) { switch (node) { case EventDeclarationSyntax eventDeclaration: { return(eventDeclaration.Type); } case VariableDeclaratorSyntax declarator: { if (declarator.Parent is VariableDeclarationSyntax declaration) { return(declaration.Type); } SyntaxDebug.Fail(declarator.Parent); break; } default: { SyntaxDebug.Fail(node); break; } } return(null); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out ExpressionSyntax expression)) { return; } Document document = context.Document; Diagnostic diagnostic = context.Diagnostics[0]; if (expression is InvocationExpressionSyntax invocationExpression) { CodeAction codeAction = CodeAction.Create( ConvertHasFlagCallToBitwiseOperationRefactoring.Title, ct => ConvertHasFlagCallToBitwiseOperationRefactoring.RefactorAsync(document, invocationExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else { SyntaxDebug.Assert(expression.IsKind(SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression), expression); CodeAction codeAction = CodeAction.Create( "Call 'HasFlag'", ct => ConvertBitwiseOperationToHasFlagCallAsync(document, (BinaryExpressionSyntax)expression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } }
private static async Task <Document> UseStringLengthInsteadOfComparisonWithEmptyStringAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ExpressionSyntax left = binaryExpression.Left; ExpressionSyntax right = binaryExpression.Right; BinaryExpressionSyntax newNode; if (CSharpUtility.IsEmptyStringExpression(left, semanticModel, cancellationToken)) { newNode = binaryExpression .WithLeft(NumericLiteralExpression(0)) .WithRight(CreateConditionalAccess(right)); } else if (CSharpUtility.IsEmptyStringExpression(right, semanticModel, cancellationToken)) { newNode = binaryExpression .WithLeft(CreateConditionalAccess(left)) .WithRight(NumericLiteralExpression(0)); } else { SyntaxDebug.Fail(binaryExpression); return(document); } newNode = newNode.WithTriviaFrom(binaryExpression).WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken).ConfigureAwait(false)); }
public override void VisitInvocationExpression(InvocationExpressionSyntax node) { switch (node.Expression) { case SimpleNameSyntax simpleName: { AnalyzeSimpleName(simpleName); break; } case MemberBindingExpressionSyntax memberBindingExpression: { AnalyzeSimpleName(memberBindingExpression.Name); break; } case MemberAccessExpressionSyntax memberAccessExpression: { AnalyzeSimpleName(memberAccessExpression.Name); break; } default: { SyntaxDebug.Fail(node); break; } } base.VisitInvocationExpression(node); }
public static async Task <Document> RefactorAsync( Document document, AccessorListSyntax accessorList, CancellationToken cancellationToken) { if (accessorList.Accessors.All(f => f.BodyOrExpressionBody() == null)) { SyntaxNode parent = accessorList.Parent; switch (parent) { case PropertyDeclarationSyntax propertyDeclaration: { TextSpan span = TextSpan.FromBounds( propertyDeclaration.Identifier.Span.End, accessorList.CloseBraceToken.SpanStart); PropertyDeclarationSyntax newNode = propertyDeclaration.RemoveWhitespace(span); newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(propertyDeclaration, newNode, cancellationToken).ConfigureAwait(false)); } case IndexerDeclarationSyntax indexerDeclaration: { TextSpan span = TextSpan.FromBounds( indexerDeclaration.ParameterList.CloseBracketToken.Span.End, accessorList.CloseBraceToken.SpanStart); IndexerDeclarationSyntax newNode = indexerDeclaration.RemoveWhitespace(span); newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(indexerDeclaration, newNode, cancellationToken).ConfigureAwait(false)); } default: { SyntaxDebug.Fail(parent); return(document); } } } else { AccessorListSyntax newAccessorList = GetNewAccessorList(accessorList); newAccessorList = AddNewLineAfterFirstAccessorIfNecessary(accessorList, newAccessorList, cancellationToken); newAccessorList = newAccessorList.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(accessorList, newAccessorList, cancellationToken).ConfigureAwait(false)); } }
private static void AddStaticModifier( CodeFixContext context, Diagnostic diagnostic, SyntaxNode node, SemanticModel semanticModel) { ISymbol symbol = semanticModel.GetSymbol(node, context.CancellationToken); if (symbol == null) { return; } SyntaxNode syntax = symbol.GetSyntaxOrDefault(context.CancellationToken); if (syntax == null) { return; } if (syntax.IsKind(SyntaxKind.VariableDeclarator)) { syntax = syntax.Parent?.Parent; } SyntaxDebug.Assert(syntax.IsKind(SyntaxKind.EventDeclaration, SyntaxKind.EventFieldDeclaration, SyntaxKind.FieldDeclaration, SyntaxKind.MethodDeclaration, SyntaxKind.PropertyDeclaration), syntax); if (syntax is not MemberDeclarationSyntax memberDeclaration) { return; } if (SyntaxInfo.ModifierListInfo(memberDeclaration).IsStatic) { return; } Document document = context.Document; SyntaxTree tree = memberDeclaration.SyntaxTree; if (tree != node.SyntaxTree) { document = context.Solution().GetDocument(tree); } ModifiersCodeFixRegistrator.AddModifier( context, document, diagnostic, memberDeclaration, SyntaxKind.StaticKeyword, title: $"Make '{symbol.Name}' static", additionalKey: CodeFixIdentifiers.AddStaticModifier); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindNode( root, context.Span, out ExpressionSyntax expression)) { return; } SyntaxDebug.Assert(expression.IsKind(SyntaxKind.NullLiteralExpression, SyntaxKind.DefaultLiteralExpression, SyntaxKind.DefaultExpression), expression); if (!expression.IsKind(SyntaxKind.NullLiteralExpression, SyntaxKind.DefaultLiteralExpression, SyntaxKind.DefaultExpression)) { return; } if (expression.IsKind(SyntaxKind.NullLiteralExpression) && expression.IsParentKind(SyntaxKind.EqualsValueClause) && expression.Parent.IsParentKind(SyntaxKind.Parameter)) { return; } Diagnostic diagnostic = context.Diagnostics[0]; Document document = context.Document; switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CS8625_CannotConvertNullLiteralToNonNullableReferenceType: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, context.Document, root.SyntaxTree)) { break; } CodeAction codeAction = CodeAction.Create( "Use null-forgiving operator", ct => { PostfixUnaryExpressionSyntax newExpression = SuppressNullableWarningExpression(expression.WithoutTrivia()) .WithTriviaFrom(expression); return(document.ReplaceNodeAsync(expression, newExpression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { Diagnostic diagnostic = context.Diagnostics[0]; SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMethodReturnType, context.Document, root.SyntaxTree)) { return; } if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement))) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(node, context.CancellationToken); SyntaxDebug.Assert(methodSymbol != null, node); ITypeSymbol typeSymbol = methodSymbol.ReturnType; if (typeSymbol.IsErrorType()) { return; } (bool containsReturnAwait, bool containsAwaitStatement) = AnalyzeAwaitExpressions(node); SyntaxDebug.Assert(containsAwaitStatement || containsReturnAwait, node); if (containsAwaitStatement) { INamedTypeSymbol taskSymbol = semanticModel.GetTypeByMetadataName("System.Threading.Tasks.Task"); CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, node, taskSymbol, semanticModel, "Task"); } if (containsReturnAwait) { typeSymbol = semanticModel.GetTypeByMetadataName("System.Threading.Tasks.Task`1").Construct(typeSymbol); CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, node, typeSymbol, semanticModel, "TaskOfT"); } }
private static InvocationExpressionSyntax GetNewInvocation(InvocationExpressionSyntax invocation) { ExpressionSyntax expression = invocation.Expression; ArgumentListSyntax argumentList = invocation.ArgumentList; SeparatedSyntaxList <ArgumentSyntax> arguments = argumentList.Arguments; ArgumentSyntax argument = arguments[0]; MemberAccessExpressionSyntax newMemberAccess = CreateNewMemberAccessExpression(); if (newMemberAccess == null) { return(null); } return(invocation .WithExpression(newMemberAccess) .WithArgumentList(argumentList.WithArguments(arguments.Remove(argument)))); MemberAccessExpressionSyntax CreateNewMemberAccessExpression() { switch (expression.Kind()) { case SyntaxKind.IdentifierName: case SyntaxKind.GenericName: { return(SimpleMemberAccessExpression( ParenthesizedExpression(argument.Expression), (SimpleNameSyntax)expression)); } case SyntaxKind.SimpleMemberAccessExpression: { var memberAccess = (MemberAccessExpressionSyntax)expression; return(memberAccess.WithExpression(ParenthesizedExpression(argument.Expression))); } default: { SyntaxDebug.Fail(expression); return(null); } } } }
public static Task <Document> RefactorAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { ExpressionSyntax left = binaryExpression.Left; ExpressionSyntax right = binaryExpression.Right; ExpressionSyntax newNode = binaryExpression; TextSpan span = TextSpan.FromBounds(left.Span.End, right.SpanStart); IEnumerable <SyntaxTrivia> trivia = binaryExpression.DescendantTrivia(span); bool isWhiteSpaceOrEndOfLine = trivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()); if (IsBooleanLiteralExpression(left.Kind())) { SyntaxTriviaList leadingTrivia = binaryExpression.GetLeadingTrivia(); if (!isWhiteSpaceOrEndOfLine) { leadingTrivia = leadingTrivia.AddRange(trivia); } newNode = right.WithLeadingTrivia(leadingTrivia); } else if (IsBooleanLiteralExpression(right.Kind())) { SyntaxTriviaList trailingTrivia = binaryExpression.GetTrailingTrivia(); if (!isWhiteSpaceOrEndOfLine) { trailingTrivia = trailingTrivia.InsertRange(0, trivia); } newNode = left.WithTrailingTrivia(trailingTrivia); } else { SyntaxDebug.Fail(binaryExpression); } return(document.ReplaceNodeAsync(binaryExpression, newNode.WithFormatterAnnotation(), cancellationToken)); }
public override bool CanBeRenamed(SyntaxToken token) { switch (token.Kind()) { case SyntaxKind.IdentifierToken: return(true); case SyntaxKind.ThisKeyword: case SyntaxKind.BaseKeyword: case SyntaxKind.GetKeyword: case SyntaxKind.SetKeyword: case SyntaxKind.AddKeyword: case SyntaxKind.RemoveKeyword: return(false); } SyntaxDebug.Fail(token); return(false); }
private static void AnalyzeForEachVariableStatement(SyntaxNodeAnalysisContext context) { var forEachStatement = (ForEachVariableStatementSyntax)context.Node; switch (forEachStatement.Variable) { case DeclarationExpressionSyntax declarationExpression: { if (CSharpTypeAnalysis.IsImplicitThatCanBeExplicit(forEachStatement, context.SemanticModel)) { ReportDiagnostic(context, declarationExpression.Type); } break; } case TupleExpressionSyntax tupleExpression: { foreach (ArgumentSyntax argument in tupleExpression.Arguments) { if (argument.Expression is not DeclarationExpressionSyntax declarationExpression) { continue; } if (CSharpTypeAnalysis.IsImplicitThatCanBeExplicit(declarationExpression, context.SemanticModel, context.CancellationToken)) { ReportDiagnostic(context, declarationExpression.Type); } } break; } default: { SyntaxDebug.Assert(forEachStatement.ContainsDiagnostics, forEachStatement.Variable); break; } } }
private static SyntaxKind GetBinaryExpressionKind(AssignmentExpressionSyntax assignmentExpression) { switch (assignmentExpression.Kind()) { case SyntaxKind.AddAssignmentExpression: return(SyntaxKind.AddExpression); case SyntaxKind.SubtractAssignmentExpression: return(SyntaxKind.SubtractExpression); case SyntaxKind.MultiplyAssignmentExpression: return(SyntaxKind.MultiplyExpression); case SyntaxKind.DivideAssignmentExpression: return(SyntaxKind.DivideExpression); case SyntaxKind.ModuloAssignmentExpression: return(SyntaxKind.ModuloExpression); case SyntaxKind.AndAssignmentExpression: return(SyntaxKind.BitwiseAndExpression); case SyntaxKind.OrAssignmentExpression: return(SyntaxKind.BitwiseOrExpression); case SyntaxKind.ExclusiveOrAssignmentExpression: return(SyntaxKind.ExclusiveOrExpression); case SyntaxKind.LeftShiftAssignmentExpression: return(SyntaxKind.LeftShiftExpression); case SyntaxKind.RightShiftAssignmentExpression: return(SyntaxKind.RightShiftExpression); } SyntaxDebug.Fail(assignmentExpression); return(SyntaxKind.None); }
private static void AnalyzeNameEquals(SyntaxNodeAnalysisContext context) { var node = (NameEqualsSyntax)context.Node; switch (node.Parent.Kind()) { case SyntaxKind.AttributeArgument: { var attributeArgument = (AttributeArgumentSyntax)node.Parent; Analyze(context, attributeArgument.NameEquals.EqualsToken, attributeArgument.Expression); break; } case SyntaxKind.AnonymousObjectMemberDeclarator: { var declarator = (AnonymousObjectMemberDeclaratorSyntax)node.Parent; Analyze(context, declarator.NameEquals.EqualsToken, declarator.Expression); break; } case SyntaxKind.UsingDirective: { var usingDirective = (UsingDirectiveSyntax)node.Parent; Analyze(context, usingDirective.Alias.EqualsToken, usingDirective.Name); break; } default: { SyntaxDebug.Fail(node.Parent); break; } } }
private static (ISymbol symbol, ITypeSymbol typeSymbol) GetContainingSymbolAndType( ExpressionSyntax expression, SemanticModel semanticModel, CancellationToken cancellationToken = default) { switch (semanticModel.GetEnclosingSymbol(expression.SpanStart, cancellationToken)) { case IMethodSymbol methodSymbol: { MethodKind methodKind = methodSymbol.MethodKind; if (methodKind == MethodKind.PropertyGet) { var propertySymbol = (IPropertySymbol)methodSymbol.AssociatedSymbol; return(propertySymbol, propertySymbol.Type); } if (methodKind == MethodKind.Ordinary && methodSymbol.PartialImplementationPart != null) { methodSymbol = methodSymbol.PartialImplementationPart; } return(methodSymbol, methodSymbol.ReturnType); } case IFieldSymbol fieldSymbol: { return(fieldSymbol, fieldSymbol.Type); } } SyntaxDebug.Fail(expression); return(default((ISymbol, ITypeSymbol))); }
private static bool ParentDeclarationsContainsUnsafeModifier(SyntaxNode node) { while (node.IsKind(SyntaxKind.LocalFunctionStatement)) { var localFunction = (LocalFunctionStatementSyntax)node; if (localFunction.Modifiers.Contains(SyntaxKind.UnsafeKeyword)) { return(true); } node = node.Parent; SyntaxDebug.Assert(node.IsKind(SyntaxKind.Block), node); if (!node.IsKind(SyntaxKind.Block)) { break; } node = node.Parent; } SyntaxDebug.Assert(node is MemberDeclarationSyntax, node); if (node is MemberDeclarationSyntax memberDeclaration) { if (SyntaxInfo.ModifierListInfo(memberDeclaration).IsUnsafe) { return(true); } return(ParentTypeDeclarationsContainsUnsafeModifier(memberDeclaration)); } return(false); }
public override SyntaxNode VisitYieldStatement(YieldStatementSyntax node) { SyntaxToken keyword = node.ReturnOrBreakKeyword; ExpressionSyntax expression = node.Expression; SyntaxKind kind = node.Kind(); if (kind == SyntaxKind.YieldReturnStatement) { ParenthesizedExpressionSyntax parenthesizedExpression = expression.Parenthesize(); CastExpressionSyntax castExpression = CastExpression( _typeSymbol.ToMinimalTypeSyntax(_semanticModel, node.SpanStart), parenthesizedExpression); InvocationExpressionSyntax invocationExpression = SimpleMemberInvocationExpression( _identifierName, _addName, Argument(castExpression.WithSimplifierAnnotation())); return(ExpressionStatement(invocationExpression.WithoutTrivia()) .WithTriviaFrom(node) .AppendToLeadingTrivia(node.DescendantTrivia(TextSpan.FromBounds(keyword.Span.End, expression.SpanStart)))); } else if (kind == SyntaxKind.YieldBreakStatement) { return(ReturnStatement( Token(keyword.LeadingTrivia, SyntaxKind.ReturnKeyword, keyword.TrailingTrivia), _identifierName, node.SemicolonToken)); } SyntaxDebug.Fail(node); return(base.VisitYieldStatement(node)); }
private static void Analyze(SymbolAnalysisContext context, ISymbol symbol) { if (symbol.IsImplicitlyDeclared) { return; } if (!symbol.IsSealed) { return; } if (symbol.ContainingType?.IsSealed != true) { return; } Debug.Assert(symbol.ContainingType.TypeKind == TypeKind.Class, symbol.ContainingType.TypeKind.ToString()); SyntaxNode node = symbol.GetSyntax(context.CancellationToken); SyntaxDebug.Assert(node.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration), node); ModifierListInfo info = SyntaxInfo.ModifierListInfo(node); Debug.Assert(info.IsSealed, info.Modifiers.ToString()); if (!info.IsSealed) { return; } SyntaxToken sealedKeyword = info.Modifiers.Find(SyntaxKind.SealedKeyword); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantSealedModifier, sealedKeyword); }
private static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanOrTrailingTriviaContainsDirectives()) { return; } var assignment = (AssignmentExpressionSyntax)context.Node; SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(assignment); if (!assignmentInfo.Success) { return; } if (assignmentInfo.Left is not IdentifierNameSyntax identifierName) { return; } StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(assignmentInfo.Statement); if (!statementsInfo.Success) { return; } int index = statementsInfo.IndexOf(assignmentInfo.Statement); if (index == statementsInfo.Count - 1) { return; } if (index > 0) { StatementSyntax previousStatement = statementsInfo[index - 1]; SimpleAssignmentStatementInfo assignmentInfo2 = SyntaxInfo.SimpleAssignmentStatementInfo(previousStatement); if (assignmentInfo2.Success && assignmentInfo2.Left is IdentifierNameSyntax identifierName2 && string.Equals(identifierName.Identifier.ValueText, identifierName2.Identifier.ValueText, StringComparison.Ordinal)) { return; } } StatementSyntax nextStatement = statementsInfo[index + 1]; if (nextStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } if (nextStatement is not ReturnStatementSyntax returnStatement) { return; } if (returnStatement.Expression?.WalkDownParentheses() is not IdentifierNameSyntax identifierName3) { return; } if (!string.Equals(identifierName.Identifier.ValueText, identifierName3.Identifier.ValueText, StringComparison.Ordinal)) { return; } ISymbol symbol = context.SemanticModel.GetSymbol(identifierName, context.CancellationToken); switch (symbol?.Kind) { case SymbolKind.Local: { break; } case SymbolKind.Parameter: { if (((IParameterSymbol)symbol).RefKind != RefKind.None) { return; } break; } default: { return; } } if (IsAssignedInsideAnonymousFunctionButDeclaredOutsideOfIt()) { return; } bool result; RemoveRedundantAssignmentWalker walker = null; try { walker = RemoveRedundantAssignmentWalker.GetInstance(); walker.Symbol = symbol; walker.SemanticModel = context.SemanticModel; walker.CancellationToken = context.CancellationToken; walker.Result = false; walker.Visit(assignmentInfo.Right); result = walker.Result; } finally { if (walker != null) { RemoveRedundantAssignmentWalker.Free(walker); } } if (result) { return; } if (IsDeclaredInTryStatementOrCatchClauseAndReferencedInFinallyClause(context, assignmentInfo.Statement, symbol)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantAssignment, assignment); bool IsAssignedInsideAnonymousFunctionButDeclaredOutsideOfIt() { SyntaxNode declaringSyntax = null; SyntaxNode n = assignment.Parent; do { if (CSharpFacts.IsAnonymousFunctionExpression(n.Kind())) { if (declaringSyntax == null) { declaringSyntax = symbol.GetSyntaxOrDefault(); Debug.Assert(declaringSyntax != null, ""); if (declaringSyntax == null) { break; } SyntaxDebug.Assert(declaringSyntax.IsKind(SyntaxKind.VariableDeclarator, SyntaxKind.Parameter), declaringSyntax); } SyntaxNode n2 = declaringSyntax.Parent; do { if (CSharpFacts.IsAnonymousFunctionExpression(n2.Kind())) { return(!object.ReferenceEquals(n, n2)); } if (n2 is MemberDeclarationSyntax) { break; } n2 = n2.Parent; }while (n2 != null); return(true); } else if (n is MemberDeclarationSyntax) { break; } n = n.Parent; }while (n != null); return(false); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out ExpressionSyntax expression)) { return; } Diagnostic diagnostic = context.Diagnostics[0]; Document document = context.Document; switch (expression) { case SimpleNameSyntax simpleName: { SyntaxDebug.Assert(expression.IsKind(SyntaxKind.IdentifierName, SyntaxKind.GenericName), expression); if (simpleName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccessExpression = (MemberAccessExpressionSyntax)simpleName.Parent; SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression)) { if (!memberAccessExpression.Parent.IsParentKind(SyntaxKind.ConditionalAccessExpression) && IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceInvocationWithMemberAccessOrViceVersa, context.Document, root.SyntaxTree)) { var invocationExpression = (InvocationExpressionSyntax)memberAccessExpression.Parent; if (!invocationExpression.ArgumentList.Arguments.Any()) { ReplaceInvocationWithMemberAccess(context, diagnostic, memberAccessExpression, invocationExpression, semanticModel); } } } else { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.FixMemberAccessName, context.Document, root.SyntaxTree)) { CodeFixRegistrationResult result = ReplaceCountWithLengthOrViceVersa(context, diagnostic, memberAccessExpression.Expression, simpleName, semanticModel); if (result.Success) { break; } } if (!memberAccessExpression.IsParentKind(SyntaxKind.ConditionalAccessExpression) && IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceInvocationWithMemberAccessOrViceVersa, context.Document, root.SyntaxTree)) { ReplaceMemberAccessWithInvocation(context, diagnostic, memberAccessExpression, semanticModel); } } } break; } case MemberBindingExpressionSyntax memberBindingExpression: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.FixMemberAccessName, context.Document, root.SyntaxTree)) { break; } if (memberBindingExpression.Parent is not ConditionalAccessExpressionSyntax conditionalAccessExpression) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); CodeFixRegistrationResult result = ReplaceCountWithLengthOrViceVersa(context, diagnostic, conditionalAccessExpression.Expression, memberBindingExpression.Name, semanticModel); break; } case AwaitExpressionSyntax awaitExpression: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveAwaitKeyword, context.Document, root.SyntaxTree)) { break; } CodeAction codeAction = CodeAction.Create( "Remove 'await'", ct => { ExpressionSyntax expression2 = awaitExpression.Expression; SyntaxTriviaList leadingTrivia = awaitExpression .GetLeadingTrivia() .AddRange(awaitExpression.AwaitKeyword.TrailingTrivia.EmptyIfWhitespace()) .AddRange(expression2.GetLeadingTrivia().EmptyIfWhitespace()); ExpressionSyntax newNode = expression2.WithLeadingTrivia(leadingTrivia); return(document.ReplaceNodeAsync(awaitExpression, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }
private static SyntaxNode Refactor(SyntaxNode node) { switch (node.Kind()) { case SyntaxKind.MethodDeclaration: { var methodDeclaration = (MethodDeclarationSyntax)node; BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(methodDeclaration.Body); return(methodDeclaration .WithExpressionBody(CreateExpressionBody(analysis, methodDeclaration)) .WithSemicolonToken(CreateSemicolonToken(methodDeclaration.Body, analysis)) .WithBody(null)); } case SyntaxKind.ConstructorDeclaration: { var constructorDeclaration = (ConstructorDeclarationSyntax)node; BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(constructorDeclaration.Body); return(constructorDeclaration .WithExpressionBody(CreateExpressionBody(analysis, constructorDeclaration)) .WithSemicolonToken(CreateSemicolonToken(constructorDeclaration.Body, analysis)) .WithBody(null)); } case SyntaxKind.DestructorDeclaration: { var destructorDeclaration = (DestructorDeclarationSyntax)node; BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(destructorDeclaration.Body); return(destructorDeclaration .WithExpressionBody(CreateExpressionBody(analysis, destructorDeclaration)) .WithSemicolonToken(CreateSemicolonToken(destructorDeclaration.Body, analysis)) .WithBody(null)); } case SyntaxKind.LocalFunctionStatement: { var localFunction = (LocalFunctionStatementSyntax)node; BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(localFunction.Body); return(localFunction .WithExpressionBody(CreateExpressionBody(analysis, localFunction)) .WithSemicolonToken(CreateSemicolonToken(localFunction.Body, analysis)) .WithBody(null)); } case SyntaxKind.OperatorDeclaration: { var operatorDeclaration = (OperatorDeclarationSyntax)node; BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(operatorDeclaration.Body); return(operatorDeclaration .WithExpressionBody(CreateExpressionBody(analysis, operatorDeclaration)) .WithSemicolonToken(CreateSemicolonToken(operatorDeclaration.Body, analysis)) .WithBody(null)); } case SyntaxKind.ConversionOperatorDeclaration: { var operatorDeclaration = (ConversionOperatorDeclarationSyntax)node; BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(operatorDeclaration.Body); return(operatorDeclaration .WithExpressionBody(CreateExpressionBody(analysis, operatorDeclaration)) .WithSemicolonToken(CreateSemicolonToken(operatorDeclaration.Body, analysis)) .WithBody(null)); } case SyntaxKind.PropertyDeclaration: { var propertyDeclaration = (PropertyDeclarationSyntax)node; BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(propertyDeclaration.AccessorList); return(propertyDeclaration .WithExpressionBody(CreateExpressionBody(analysis, propertyDeclaration)) .WithSemicolonToken(CreateSemicolonToken(analysis.Block, analysis)) .WithAccessorList(null)); } case SyntaxKind.IndexerDeclaration: { var indexerDeclaration = (IndexerDeclarationSyntax)node; BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(indexerDeclaration.AccessorList); return(indexerDeclaration .WithExpressionBody(CreateExpressionBody(analysis, indexerDeclaration)) .WithSemicolonToken(CreateSemicolonToken(analysis.Block, analysis)) .WithAccessorList(null)); } case SyntaxKind.GetAccessorDeclaration: case SyntaxKind.SetAccessorDeclaration: case SyntaxKind.InitAccessorDeclaration: case SyntaxKind.AddAccessorDeclaration: case SyntaxKind.RemoveAccessorDeclaration: { var accessor = (AccessorDeclarationSyntax)node; BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(accessor); return(accessor .WithExpressionBody(CreateExpressionBody(analysis, accessor)) .WithSemicolonToken(CreateSemicolonToken(analysis.Block, analysis)) .WithBody(null)); } default: { SyntaxDebug.Fail(node); return(node); } } }
public virtual void VisitStatement(StatementSyntax node) { switch (node.Kind()) { case SyntaxKind.Block: { VisitBlock((BlockSyntax)node); break; } case SyntaxKind.BreakStatement: { VisitBreakStatement((BreakStatementSyntax)node); break; } case SyntaxKind.ContinueStatement: { VisitContinueStatement((ContinueStatementSyntax)node); break; } case SyntaxKind.DoStatement: { VisitDoStatement((DoStatementSyntax)node); break; } case SyntaxKind.EmptyStatement: { VisitEmptyStatement((EmptyStatementSyntax)node); break; } case SyntaxKind.ExpressionStatement: { VisitExpressionStatement((ExpressionStatementSyntax)node); break; } case SyntaxKind.FixedStatement: { VisitFixedStatement((FixedStatementSyntax)node); break; } case SyntaxKind.ForEachStatement: { VisitForEachStatement((ForEachStatementSyntax)node); break; } case SyntaxKind.ForEachVariableStatement: { VisitForEachVariableStatement((ForEachVariableStatementSyntax)node); break; } case SyntaxKind.ForStatement: { VisitForStatement((ForStatementSyntax)node); break; } case SyntaxKind.GotoStatement: case SyntaxKind.GotoCaseStatement: case SyntaxKind.GotoDefaultStatement: { VisitGotoStatement((GotoStatementSyntax)node); break; } case SyntaxKind.CheckedStatement: case SyntaxKind.UncheckedStatement: { VisitCheckedStatement((CheckedStatementSyntax)node); break; } case SyntaxKind.IfStatement: { VisitIfStatement((IfStatementSyntax)node); break; } case SyntaxKind.LabeledStatement: { VisitLabeledStatement((LabeledStatementSyntax)node); break; } case SyntaxKind.LocalDeclarationStatement: { VisitLocalDeclarationStatement((LocalDeclarationStatementSyntax)node); break; } case SyntaxKind.LocalFunctionStatement: { VisitLocalFunctionStatement((LocalFunctionStatementSyntax)node); break; } case SyntaxKind.LockStatement: { VisitLockStatement((LockStatementSyntax)node); break; } case SyntaxKind.ReturnStatement: { VisitReturnStatement((ReturnStatementSyntax)node); break; } case SyntaxKind.SwitchStatement: { VisitSwitchStatement((SwitchStatementSyntax)node); break; } case SyntaxKind.ThrowStatement: { VisitThrowStatement((ThrowStatementSyntax)node); break; } case SyntaxKind.TryStatement: { VisitTryStatement((TryStatementSyntax)node); break; } case SyntaxKind.UnsafeStatement: { VisitUnsafeStatement((UnsafeStatementSyntax)node); break; } case SyntaxKind.UsingStatement: { VisitUsingStatement((UsingStatementSyntax)node); break; } case SyntaxKind.WhileStatement: { VisitWhileStatement((WhileStatementSyntax)node); break; } case SyntaxKind.YieldBreakStatement: case SyntaxKind.YieldReturnStatement: { VisitYieldStatement((YieldStatementSyntax)node); break; } default: { SyntaxDebug.Fail(node); Visit(node); break; } } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { Diagnostic diagnostic = context.Diagnostics[0]; SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveUnreachableCode, context.Document, root.SyntaxTree)) { return; } if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement)) { return; } SyntaxDebug.Assert(context.Span.Start == statement.SpanStart, statement); if (context.Span.Start != statement.SpanStart) { return; } CodeAction codeAction = CreateCodeActionForIfElse(context.Document, diagnostic, statement.Parent); if (codeAction != null) { context.RegisterCodeFix(codeAction, diagnostic); return; } StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(statement); if (statementsInfo.Success) { codeAction = CodeAction.Create( Title, ct => { SyntaxList <StatementSyntax> statements = statementsInfo.Statements; int index = statements.IndexOf(statement); if (index == statements.Count - 1) { return(context.Document.RemoveStatementAsync(statement, ct)); } else { int lastIndex = statements.LastIndexOf(f => !f.IsKind(SyntaxKind.LocalFunctionStatement)); SyntaxList <StatementSyntax> nodes = RemoveRange(statements, index, lastIndex - index + 1, f => !f.IsKind(SyntaxKind.LocalFunctionStatement)); return(context.Document.ReplaceStatementsAsync( statementsInfo, nodes, ct)); } }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { Diagnostic diagnostic = context.Diagnostics[0]; SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemovePropertyOrFieldInitializer, context.Document, root.SyntaxTree)) { return; } if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } SyntaxDebug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token); if (!token.IsKind(SyntaxKind.IdentifierToken)) { return; } switch (token.Parent) { case PropertyDeclarationSyntax propertyDeclaration: { EqualsValueClauseSyntax initializer = propertyDeclaration.Initializer; CodeAction codeAction = CodeAction.Create( Title, ct => { PropertyDeclarationSyntax newNode = propertyDeclaration .RemoveNode(initializer) .WithSemicolonToken(default(SyntaxToken)) .AppendToTrailingTrivia(propertyDeclaration.SemicolonToken.GetAllTrivia()) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(propertyDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemovePropertyOrFieldInitializer)); context.RegisterCodeFix(codeAction, diagnostic); break; } case VariableDeclaratorSyntax variableDeclarator: { EqualsValueClauseSyntax initializer = variableDeclarator.Initializer; CodeAction codeAction = CodeAction.Create( Title, ct => { VariableDeclaratorSyntax newNode = variableDeclarator .RemoveNode(initializer) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(variableDeclarator, newNode, ct)); }, GetEquivalenceKey(CompilerDiagnosticIdentifiers.CS0573_CannotHaveInstancePropertyOrFieldInitializersInStruct, CodeFixIdentifiers.RemovePropertyOrFieldInitializer)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }