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 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 ReturnStatementSyntax returnStatement)) { return; } if (!(returnStatement.Expression?.WalkDownParentheses() is 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; } 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; } Debug.Assert(declaringSyntax.IsKind(SyntaxKind.VariableDeclarator, SyntaxKind.Parameter), declaringSyntax.Kind().ToString()); } 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); } }
protected override void WriteSymbol( ISymbol symbol, SymbolDisplayFormat format = null, bool removeAttributeSuffix = false) { bool shouldWriteContainingNamespace = false; if (symbol.Kind == SymbolKind.Field && symbol.ContainingType.TypeKind == TypeKind.Enum) { base.WriteSymbol(symbol, format); } else { shouldWriteContainingNamespace = ShouldWriteContainingNamespace(); if (IsExternal(symbol)) { string url = WellKnownExternalUrlProviders.MicrosoftDocs.CreateUrl(symbol).Url; if (url != null) { if (shouldWriteContainingNamespace) { WriteContainingNamespace(symbol); } WriteStartElement("a"); WriteAttributeString("href", url); WriteName(); WriteEndElement(); } else { WriteName(); } } else { if (shouldWriteContainingNamespace) { WriteContainingNamespace(symbol); } WriteStartElement("a"); WriteStartAttribute("href"); Write("#"); WriteLocalLink(symbol); WriteEndAttribute(); WriteName(); WriteEndElement(); } } bool ShouldWriteContainingNamespace() { return(symbol.IsKind(SymbolKind.NamedType) && !symbol.ContainingNamespace.IsGlobalNamespace && Format.Includes(SymbolDefinitionPartFilter.ContainingNamespace) && !CSharpFacts.IsPredefinedType(((INamedTypeSymbol)symbol).SpecialType) && (format == null || format.TypeQualificationStyle == SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)); } void WriteName() { if (symbol.IsKind(SymbolKind.Namespace)) { format = TypeSymbolDisplayFormats.Name_ContainingTypes_Namespaces; } else if (shouldWriteContainingNamespace) { format = TypeSymbolDisplayFormats.Name_ContainingTypes_SpecialTypes; } base.WriteSymbol(symbol, format, removeAttributeSuffix: removeAttributeSuffix); } }
private static void AnalyzeForStatement(SyntaxNodeAnalysisContext context) { var forStatement = (ForStatementSyntax)context.Node; StatementSyntax statement = forStatement.EmbeddedStatement(); if (statement == null) { return; } if (statement.ContainsDirectives) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.AddBraces, statement, CSharpFacts.GetTitle(forStatement)); }
private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context) { var methodDeclaration = (MethodDeclarationSyntax)context.Node; if (methodDeclaration.ContainsDirectives) { return; } if (methodDeclaration.ContainsDiagnostics) { return; } if (methodDeclaration.AttributeLists.Any()) { return; } if (!CheckModifiers(methodDeclaration.Modifiers)) { return; } if (methodDeclaration.HasDocumentationComment()) { return; } if (!methodDeclaration.DescendantTrivia(methodDeclaration.Span).All(f => f.IsWhitespaceOrEndOfLineTrivia())) { return; } ExpressionSyntax expression = GetMethodExpression(methodDeclaration); SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(expression); if (!invocationInfo.Success) { return; } if (invocationInfo.Expression.Kind() != SyntaxKind.BaseExpression) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, cancellationToken); if (methodSymbol == null) { return; } IMethodSymbol overriddenMethod = methodSymbol.OverriddenMethod; if (overriddenMethod == null) { return; } ISymbol symbol = semanticModel.GetSymbol(invocationInfo.Name, cancellationToken); if (!SymbolEqualityComparer.Default.Equals(overriddenMethod, symbol)) { return; } if (!CheckParameters(methodDeclaration.ParameterList, invocationInfo.ArgumentList, semanticModel, cancellationToken)) { return; } if (!CheckDefaultValues(methodSymbol.Parameters, overriddenMethod.Parameters)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.RemoveRedundantOverridingMember, methodDeclaration, CSharpFacts.GetTitle(methodDeclaration)); }
public static void AnalyzeSimpleMemberAccessExpression(SyntaxNodeAnalysisContext context) { var memberAccess = (MemberAccessExpressionSyntax)context.Node; if (memberAccess.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { return; } ExpressionSyntax expression = memberAccess.Expression; if (expression == null) { return; } SyntaxKind kind = expression.Kind(); if (kind == SyntaxKind.IdentifierName) { if (!SupportsPredefinedType((IdentifierNameSyntax)expression)) { return; } } else if (kind == SyntaxKind.SimpleMemberAccessExpression) { memberAccess = (MemberAccessExpressionSyntax)expression; if (!(memberAccess.Name is IdentifierNameSyntax identifierName)) { return; } if (!SupportsPredefinedType(identifierName)) { return; } } else { return; } if (!(context.SemanticModel.GetSymbol(expression, context.CancellationToken) is ITypeSymbol typeSymbol)) { return; } if (!CSharpFacts.IsPredefinedType(typeSymbol.SpecialType)) { return; } IAliasSymbol aliasSymbol = context.SemanticModel.GetAliasInfo(expression, context.CancellationToken); if (aliasSymbol != null) { return; } ReportDiagnostic(context, expression); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsAnyCodeFixEnabled( CodeFixIdentifiers.WrapInUnsafeStatement, CodeFixIdentifiers.MakeContainingDeclarationUnsafe)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindNode(root, context.Span, out SyntaxNode node)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.PointersAndFixedSizeBuffersMayOnlyBeUsedInUnsafeContext: { bool fStatement = false; bool fMemberDeclaration = false; foreach (SyntaxNode ancestor in node.AncestorsAndSelf()) { if (fStatement && fMemberDeclaration) { break; } if (!fStatement && ancestor is StatementSyntax) { fStatement = true; if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.WrapInUnsafeStatement)) { continue; } var statement = (StatementSyntax)ancestor; if (statement.IsKind(SyntaxKind.Block) && statement.Parent is StatementSyntax) { statement = (StatementSyntax)statement.Parent; } if (statement.IsKind(SyntaxKind.UnsafeStatement)) { break; } CodeAction codeAction = CodeAction.Create( "Wrap in unsafe block", cancellationToken => { BlockSyntax block = (statement.IsKind(SyntaxKind.Block)) ? (BlockSyntax)statement : SyntaxFactory.Block(statement); UnsafeStatementSyntax unsafeStatement = SyntaxFactory.UnsafeStatement(block).WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(statement, unsafeStatement, cancellationToken)); }, GetEquivalenceKey(diagnostic, CodeFixIdentifiers.WrapInUnsafeStatement)); context.RegisterCodeFix(codeAction, diagnostic); } else if (!fMemberDeclaration && ancestor is MemberDeclarationSyntax) { fMemberDeclaration = true; if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingDeclarationUnsafe)) { continue; } if (!CSharpFacts.CanHaveModifiers(ancestor.Kind())) { continue; } ModifiersCodeFixRegistrator.AddModifier( context, diagnostic, ancestor, SyntaxKind.UnsafeKeyword, title: "Make containing declaration unsafe", additionalKey: CodeFixIdentifiers.MakeContainingDeclarationUnsafe); } } break; } } } }
private static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.IsSimpleIf()) { return; } StatementSyntax statement = ifStatement.EmbeddedStatement(); if (statement == null) { return; } if (statement.ContainsDirectives) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.AddBracesToIfElse, statement, CSharpFacts.GetTitle(ifStatement)); }
private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context) { var typeDeclaration = (TypeDeclarationSyntax)context.Node; if (typeDeclaration.Modifiers.Contains(SyntaxKind.PartialKeyword)) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ImmutableArray <AttributeData> attributes = default; if (typeDeclaration.IsKind(SyntaxKind.StructDeclaration)) { INamedTypeSymbol declarationSymbol = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken); attributes = declarationSymbol.GetAttributes(); if (attributes.Any(f => f.AttributeClass.HasMetadataName(MetadataNames.System_Runtime_InteropServices_StructLayoutAttribute))) { return; } } SyntaxList <MemberDeclarationSyntax> members = typeDeclaration.Members; UnusedMemberWalker walker = null; foreach (MemberDeclarationSyntax member in members) { if (member.ContainsDiagnostics) { continue; } if (member.ContainsUnbalancedIfElseDirectives(member.Span)) { continue; } switch (member.Kind()) { case SyntaxKind.DelegateDeclaration: { var declaration = (DelegateDeclarationSyntax)member; if (SyntaxAccessibility <DelegateDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddDelegate(declaration.Identifier.ValueText, declaration); } break; } case SyntaxKind.EventDeclaration: { var declaration = (EventDeclarationSyntax)member; if (declaration.ExplicitInterfaceSpecifier == null && SyntaxAccessibility <EventDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddNode(declaration.Identifier.ValueText, declaration); } break; } case SyntaxKind.EventFieldDeclaration: { var declaration = (EventFieldDeclarationSyntax)member; if (SyntaxAccessibility <EventFieldDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddNodes(declaration.Declaration); } break; } case SyntaxKind.FieldDeclaration: { var declaration = (FieldDeclarationSyntax)member; SyntaxTokenList modifiers = declaration.Modifiers; if (SyntaxAccessibility <FieldDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddNodes(declaration.Declaration, isConst: modifiers.Contains(SyntaxKind.ConstKeyword)); } break; } case SyntaxKind.MethodDeclaration: { var declaration = (MethodDeclarationSyntax)member; SyntaxTokenList modifiers = declaration.Modifiers; if (declaration.ExplicitInterfaceSpecifier == null && !declaration.AttributeLists.Any() && SyntaxAccessibility <MethodDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { string methodName = declaration.Identifier.ValueText; if (!IsMainMethod(declaration, modifiers, methodName)) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddNode(methodName, declaration); } } break; } case SyntaxKind.PropertyDeclaration: { var declaration = (PropertyDeclarationSyntax)member; if (declaration.ExplicitInterfaceSpecifier == null && SyntaxAccessibility <PropertyDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddNode(declaration.Identifier.ValueText, declaration); } break; } } } if (walker == null) { return; } Collection <NodeSymbolInfo> nodes = walker.Nodes; if (ShouldAnalyzeDebuggerDisplayAttribute() && nodes.Any(f => f.CanBeInDebuggerDisplayAttribute)) { if (attributes.IsDefault) { attributes = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken).GetAttributes(); } string value = attributes .FirstOrDefault(f => f.AttributeClass.HasMetadataName(MetadataNames.System_Diagnostics_DebuggerDisplayAttribute))? .ConstructorArguments .SingleOrDefault(shouldThrow: false) .Value? .ToString(); if (value != null) { RemoveMethodsAndPropertiesThatAreInDebuggerDisplayAttributeValue(value, ref nodes); } if (nodes.Count == 0) { UnusedMemberWalkerCache.Free(walker); return; } } walker.SemanticModel = semanticModel; walker.CancellationToken = cancellationToken; walker.Visit(typeDeclaration); foreach (NodeSymbolInfo info in nodes) { SyntaxNode node = info.Node; if (node is VariableDeclaratorSyntax variableDeclarator) { var variableDeclaration = (VariableDeclarationSyntax)variableDeclarator.Parent; if (variableDeclaration.Variables.Count == 1) { ReportDiagnostic(context, variableDeclaration.Parent, CSharpFacts.GetTitle(variableDeclaration.Parent)); } else { ReportDiagnostic(context, variableDeclarator, CSharpFacts.GetTitle(variableDeclaration.Parent)); } } else { ReportDiagnostic(context, node, CSharpFacts.GetTitle(node)); } } UnusedMemberWalkerCache.Free(walker); bool ShouldAnalyzeDebuggerDisplayAttribute() { foreach (AttributeListSyntax attributeList in typeDeclaration.AttributeLists) { foreach (AttributeSyntax attribute in attributeList.Attributes) { if (attribute.ArgumentList?.Arguments.Count(f => f.NameEquals == null) == 1) { return(true); } } } return(false); } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.SimplifyBooleanComparison: { CodeAction codeAction = CodeAction.Create( "Simplify boolean comparison", cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.CallSkipAndAnyInsteadOfCount: { CodeAction codeAction = CodeAction.Create( "Call 'Skip' and 'Any' instead of 'Count'", cancellationToken => CallSkipAndAnyInsteadOfCountRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AvoidNullLiteralExpressionOnLeftSideOfBinaryExpression: { CodeAction codeAction = CodeAction.Create( "Swap operands", cancellationToken => CommonRefactorings.SwapBinaryOperandsAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod: { CodeAction codeAction = CodeAction.Create( "Use 'string.IsNullOrEmpty' method", cancellationToken => UseStringIsNullOrEmptyMethodRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SimplifyCoalesceExpression: { ExpressionSyntax expression = binaryExpression.Left; if (expression == null || !context.Span.Contains(expression.Span)) { expression = binaryExpression.Right; } CodeAction codeAction = CodeAction.Create( "Simplify coalesce expression", cancellationToken => SimplifyCoalesceExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, expression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantAsOperator: { CodeAction codeAction = CodeAction.Create( "Remove redundant 'as' operator", cancellationToken => RemoveRedundantAsOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString: { CodeAction codeAction = CodeAction.Create( "Use string.Length", cancellationToken => UseStringLengthInsteadOfComparisonWithEmptyStringRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); CodeAction codeAction = CodeAction.Create( $"Use EqualityComparer<{typeSymbol.Name}>.Default", cancellationToken => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); string title; if (CSharpFacts.IsSimpleType(typeSymbol.SpecialType) || typeSymbol.ContainsMember <IMethodSymbol>(WellKnownMemberNames.EqualityOperatorName)) { ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(semanticModel, binaryExpression.Right.SpanStart); title = $"Replace 'null' with '{expression}'"; } else { title = $"Use EqualityComparer<{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart, SymbolDisplayFormats.Default)}>.Default"; } CodeAction codeAction = CodeAction.Create( title, cancellationToken => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.JoinStringExpressions: { CodeAction codeAction = CodeAction.Create( "Join string expressions", cancellationToken => JoinStringExpressionsRefactoring.RefactorAsync(context.Document, binaryExpression, context.Span, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseExclusiveOrOperator: { CodeAction codeAction = CodeAction.Create( "Use ^ operator", cancellationToken => UseExclusiveOrOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SimplifyBooleanExpression: { CodeAction codeAction = CodeAction.Create( "Simplify boolean expression", cancellationToken => SimplifyBooleanExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ExpressionIsAlwaysEqualToTrueOrFalse: { LiteralExpressionSyntax newNode = BooleanLiteralExpression(binaryExpression.IsKind(SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.LessThanOrEqualExpression)); CodeAction codeAction = CodeAction.Create( $"Replace expression with '{newNode}'", cancellationToken => context.Document.ReplaceNodeAsync(binaryExpression, newNode.WithTriviaFrom(binaryExpression), cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.AddEmptyLineBeforeWhileInDoStatement: { CodeAction codeAction = CodeAction.Create( "Add empty line", ct => AddEmptyLineBeforeWhileInDoStatementAsync(context.Document, statement, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.InlineLazyInitialization: { CodeAction codeAction = CodeAction.Create( "Inline lazy initialization", cancellationToken => { return(InlineLazyInitializationRefactoring.RefactorAsync( context.Document, (IfStatementSyntax)statement, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantDisposeOrCloseCall: { var expressionStatement = (ExpressionStatementSyntax)statement; var invocation = (InvocationExpressionSyntax)expressionStatement.Expression; var memberAccess = (MemberAccessExpressionSyntax)invocation.Expression; CodeAction codeAction = CodeAction.Create( $"Remove redundant '{memberAccess.Name?.Identifier.ValueText}' call", cancellationToken => RemoveRedundantDisposeOrCloseCallRefactoring.RefactorAsync(context.Document, expressionStatement, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantStatement: { CodeAction codeAction = CodeAction.Create( $"Remove redundant {CSharpFacts.GetTitle(statement)}", cancellationToken => RemoveRedundantStatementRefactoring.RefactorAsync(context.Document, statement, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseMethodChaining: { var expressionStatement = (ExpressionStatementSyntax)statement; UseMethodChainingAnalysis analysis; if (expressionStatement.Expression.Kind() == SyntaxKind.InvocationExpression) { analysis = UseMethodChainingAnalysis.WithoutAssignmentAnalysis; } else { analysis = UseMethodChainingAnalysis.WithAssignmentAnalysis; } CodeAction codeAction = CodeAction.Create( "Use method chaining", cancellationToken => UseMethodChainingRefactoring.RefactorAsync(context.Document, analysis, expressionStatement, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
public static async Task <Document> InvertIfAsync( Document document, IfStatementSyntax ifStatement, bool recursive = false, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); StatementSyntax statement = ifStatement.Statement; StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; InvertIfAnalysis analysis = InvertIfAnalysis.Create(ifStatement, statement); int ifStatementIndex = statements.IndexOf(ifStatement); StatementSyntax lastStatement = analysis.LastStatement; int lastStatementIndex = statements.IndexOf(lastStatement); bool isLastStatementRedundant = IsLastStatementRedundant(); bool shouldUseElseClause = !CSharpFacts.IsJumpStatement(lastStatement.Kind()); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); SyntaxList <StatementSyntax> newStatements = statements; if (!recursive) { Refactor(); } else { IfStatementSyntax lastIfStatement; InvertIfAnalysis a = analysis.AnalyzeNextStatement(); do { lastIfStatement = a.IfStatement; a = a.AnalyzeNextStatement(); } while (a.Success); int firstLastStatementIndex = lastStatementIndex; int index = statements.IndexOf(lastIfStatement); int firstIndex = ifStatementIndex; while (index >= firstIndex) { ifStatementIndex = index; ifStatement = (IfStatementSyntax)statements[ifStatementIndex]; statement = ifStatement.Statement; Refactor(); lastStatementIndex = firstLastStatementIndex + newStatements.Count - statements.Count; lastStatement = (statement is BlockSyntax block) ? block.Statements.Last() : statement; index--; } } return(await document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken).ConfigureAwait(false)); void Refactor() { cancellationToken.ThrowIfCancellationRequested(); SyntaxList <StatementSyntax> nextStatements = newStatements .Skip(ifStatementIndex + 1) .Take(lastStatementIndex - ifStatementIndex) .ToSyntaxList() .TrimTrivia(); BlockSyntax newStatement; SyntaxList <StatementSyntax> newNextStatements; if (statement is BlockSyntax block) { newStatement = block.WithStatements(nextStatements); newNextStatements = block.Statements; } else { newStatement = Block(nextStatements); newNextStatements = SingletonList(statement); } if (isLastStatementRedundant) { newNextStatements = newNextStatements.RemoveAt(newNextStatements.Count - 1); } ElseClauseSyntax elseClause = null; if (newNextStatements.Any() && shouldUseElseClause) { elseClause = ElseClause(Block(newNextStatements)); newNextStatements = default; } IfStatementSyntax newIfStatement = ifStatement.Update( ifKeyword: ifStatement.IfKeyword, openParenToken: ifStatement.OpenParenToken, condition: SyntaxInverter.LogicallyInvert(ifStatement.Condition, semanticModel, cancellationToken), closeParenToken: ifStatement.CloseParenToken, statement: newStatement, @else: elseClause); newIfStatement = newIfStatement.WithFormatterAnnotation(); SyntaxList <StatementSyntax> newNodes = newNextStatements.Insert(0, newIfStatement); newStatements = newStatements.ReplaceRange(ifStatementIndex, lastStatementIndex - ifStatementIndex + 1, newNodes); } bool IsLastStatementRedundant() { StatementSyntax jumpStatement = analysis.JumpStatement; switch (jumpStatement.Kind()) { case SyntaxKind.ReturnStatement: { if (((ReturnStatementSyntax)jumpStatement).Expression == null && RemoveRedundantStatementAnalysis.IsFixable(lastStatement, SyntaxKind.ReturnStatement)) { return(true); } break; } case SyntaxKind.ContinueStatement: { if (RemoveRedundantStatementAnalysis.IsFixable(lastStatement, SyntaxKind.ContinueStatement)) { return(true); } break; } } return(false); } }
private static void AnalyzeCompilationUnit(SyntaxNodeAnalysisContext context) { var compilationUnit = (CompilationUnitSyntax)context.Node; SyntaxToken endOfFile = compilationUnit.EndOfFileToken; SyntaxTriviaList.Reversed.Enumerator en = endOfFile.LeadingTrivia.Reverse().GetEnumerator(); bool?preferNewLineAtEndOfFile = context.PreferNewLineAtEndOfFile(); if (preferNewLineAtEndOfFile == null) { return; } if (preferNewLineAtEndOfFile == false) { if (en.MoveNext() && (!en.Current.IsWhitespaceTrivia() || en.MoveNext())) { if (en.Current.IsEndOfLineTrivia()) { ReportDiagnostic(context, endOfFile); } else if (SyntaxFacts.IsPreprocessorDirective(en.Current.Kind()) && en.Current.GetStructure() is DirectiveTriviaSyntax directiveTrivia && directiveTrivia.GetTrailingTrivia().LastOrDefault().IsEndOfLineTrivia()) { ReportDiagnostic(context, endOfFile); } } else { SyntaxTriviaList trailing = endOfFile.GetPreviousToken().TrailingTrivia; if (trailing.Any()) { Debug.Assert(endOfFile.FullSpan.Start == trailing.Span.End); if (endOfFile.FullSpan.Start == trailing.Span.End && trailing.LastOrDefault().IsEndOfLineTrivia()) { ReportDiagnostic(context, endOfFile); } } } } else if (en.MoveNext()) { if (CSharpFacts.IsCommentTrivia(en.Current.Kind()) || SyntaxFacts.IsPreprocessorDirective(en.Current.Kind())) { ReportDiagnostic(context, endOfFile); } else if (en.Current.IsWhitespaceOrEndOfLineTrivia() && endOfFile.LeadingTrivia.Span.Start == 0) { while (en.MoveNext()) { if (!en.Current.IsWhitespaceOrEndOfLineTrivia()) { return; } } ReportDiagnostic(context, endOfFile); } } else if (endOfFile.SpanStart > 0) { SyntaxTriviaList trailing = endOfFile.GetPreviousToken().TrailingTrivia; if (!trailing.Any()) { ReportDiagnostic(context, endOfFile); } else { Debug.Assert(endOfFile.FullSpan.Start == trailing.Span.End); if (endOfFile.FullSpan.Start == trailing.Span.End && !trailing.Last().IsEndOfLineTrivia()) { ReportDiagnostic(context, endOfFile); } } }
private static bool HasConstantValue( ExpressionSyntax expression, ITypeSymbol typeSymbol, SemanticModel semanticModel, CancellationToken cancellationToken = default) { if (expression?.IsMissing != false) { return(false); } switch (typeSymbol.SpecialType) { case SpecialType.System_Boolean: { if (CSharpFacts.IsBooleanLiteralExpression(expression.Kind())) { return(true); } break; } case SpecialType.System_Char: { if (expression.Kind() == SyntaxKind.CharacterLiteralExpression) { return(true); } break; } case SpecialType.System_SByte: case SpecialType.System_Byte: case SpecialType.System_Int16: case SpecialType.System_UInt16: case SpecialType.System_Int32: case SpecialType.System_UInt32: case SpecialType.System_Int64: case SpecialType.System_UInt64: case SpecialType.System_Decimal: case SpecialType.System_Single: case SpecialType.System_Double: { if (expression.Kind() == SyntaxKind.NumericLiteralExpression) { return(true); } break; } case SpecialType.System_String: { if (expression.Kind() == SyntaxKind.StringLiteralExpression) { return(true); } break; } } return(semanticModel.HasConstantValue(expression, cancellationToken)); }
private static (bool containsReturnAwait, bool containsAwaitStatement) AnalyzeAwaitExpressions(SyntaxNode node) { if (node is MethodDeclarationSyntax methodDeclaration) { ArrowExpressionClauseSyntax expressionBody = methodDeclaration.ExpressionBody; if (expressionBody != null) { return(expressionBody.Expression?.Kind() == SyntaxKind.AwaitExpression, false); } node = methodDeclaration.Body; } else { var localFunction = (LocalFunctionStatementSyntax)node; ArrowExpressionClauseSyntax expressionBody = localFunction.ExpressionBody; if (expressionBody != null) { return(expressionBody.Expression?.Kind() == SyntaxKind.AwaitExpression, false); } node = localFunction.Body; } if (node == null) { return(false, false); } var containsReturnAwait = false; var containsAwaitStatement = false; foreach (SyntaxNode descendant in node.DescendantNodes(node.Span, f => !CSharpFacts.IsFunction(f.Kind()))) { switch (descendant) { case ReturnStatementSyntax returnStatement: { if (returnStatement.Expression?.WalkDownParentheses().Kind() == SyntaxKind.AwaitExpression) { containsReturnAwait = true; } break; } case ExpressionStatementSyntax expressionStatement: { if (expressionStatement.Expression?.Kind() == SyntaxKind.AwaitExpression) { containsAwaitStatement = true; } break; } } } return(containsReturnAwait, containsAwaitStatement); }
private static void AnalyzeSingleLineDocumentationCommentTrivia(SyntaxNodeAnalysisContext context) { var documentationComment = (DocumentationCommentTriviaSyntax)context.Node; if (!documentationComment.IsPartOfMemberDeclaration()) { return; } bool?useCorrectDocumentationTagEnabled = null; bool containsInheritDoc = false; bool containsIncludeOrExclude = false; bool containsSummaryElement = false; bool containsContentElement = false; bool isFirst = true; CancellationToken cancellationToken = context.CancellationToken; SyntaxList <XmlNodeSyntax> content = documentationComment.Content; for (int i = 0; i < content.Count; i++) { cancellationToken.ThrowIfCancellationRequested(); XmlElementInfo info = SyntaxInfo.XmlElementInfo(content[i]); if (info.Success) { switch (info.GetTag()) { case XmlTag.Include: case XmlTag.Exclude: { if (isFirst) { containsIncludeOrExclude = true; } break; } case XmlTag.InheritDoc: { containsInheritDoc = true; break; } case XmlTag.Content: { containsContentElement = true; break; } case XmlTag.Summary: { if (info.IsContentEmptyOrWhitespace) { ReportDiagnosticIfNotSuppressed(context, DiagnosticDescriptors.AddSummaryToDocumentationComment, info.Element); } containsSummaryElement = true; if (useCorrectDocumentationTagEnabled ??= !context.IsAnalyzerSuppressed(DiagnosticDescriptors.FixDocumentationCommentTag)) { FixDocumentationCommentTagAnalysis.Analyze(context, info); } break; } case XmlTag.Example: case XmlTag.Remarks: case XmlTag.Returns: case XmlTag.Value: { if (info.IsContentEmptyOrWhitespace) { ReportUnusedElement(context, info.Element, i, content); } if (useCorrectDocumentationTagEnabled ??= !context.IsAnalyzerSuppressed(DiagnosticDescriptors.FixDocumentationCommentTag)) { FixDocumentationCommentTagAnalysis.Analyze(context, info); } break; } case XmlTag.Exception: case XmlTag.List: case XmlTag.Param: case XmlTag.Permission: case XmlTag.TypeParam: { if (useCorrectDocumentationTagEnabled ??= !context.IsAnalyzerSuppressed(DiagnosticDescriptors.FixDocumentationCommentTag)) { FixDocumentationCommentTagAnalysis.Analyze(context, info); } break; } case XmlTag.C: case XmlTag.Code: case XmlTag.Para: case XmlTag.ParamRef: case XmlTag.See: case XmlTag.SeeAlso: case XmlTag.TypeParamRef: { break; } default: { Debug.Fail(info.GetTag().ToString()); break; } } if (isFirst) { isFirst = false; } else { containsIncludeOrExclude = false; } } } if (containsInheritDoc || containsIncludeOrExclude) { return; } if (!containsSummaryElement && !containsContentElement) { ReportDiagnosticIfNotSuppressed(context, DiagnosticDescriptors.AddSummaryElementToDocumentationComment, documentationComment); } SyntaxNode parent = documentationComment.ParentTrivia.Token.Parent; bool unusedElement = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnusedElementInDocumentationComment); bool orderParams = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.OrderElementsInDocumentationComment); bool addParam = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddParamElementToDocumentationComment); bool addTypeParam = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddTypeParamElementToDocumentationComment); if (addParam || orderParams || unusedElement) { SeparatedSyntaxList <ParameterSyntax> parameters = CSharpUtility.GetParameters((CSharpFacts.HasParameterList(parent.Kind())) ? parent : parent.Parent); if (addParam && parameters.Any()) { foreach (ParameterSyntax parameter in parameters) { if (IsMissing(documentationComment, parameter)) { ReportDiagnostic(context, DiagnosticDescriptors.AddParamElementToDocumentationComment, documentationComment); break; } } } if (orderParams || unusedElement) { Analyze(context, documentationComment.Content, parameters, XmlTag.Param, (nodes, name) => nodes.IndexOf(name)); } } if (addTypeParam || orderParams || unusedElement) { SeparatedSyntaxList <TypeParameterSyntax> typeParameters = CSharpUtility.GetTypeParameters((CSharpFacts.HasTypeParameterList(parent.Kind())) ? parent : parent.Parent); if (addTypeParam && typeParameters.Any()) { foreach (TypeParameterSyntax typeParameter in typeParameters) { if (IsMissing(documentationComment, typeParameter)) { ReportDiagnostic(context, DiagnosticDescriptors.AddTypeParamElementToDocumentationComment, documentationComment); break; } } } if (orderParams || unusedElement) { Analyze(context, documentationComment.Content, typeParameters, XmlTag.TypeParam, (nodes, name) => nodes.IndexOf(name)); } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassNonStatic) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveOutModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveRefModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveVirtualModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassUnsealed) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddModifierAbstract) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeMemberReadOnly) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveSealedModifier)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } SyntaxNode node = token.Parent; if (!CSharpFacts.CanHaveModifiers(node.Kind())) { node = node.FirstAncestor(f => CSharpFacts.CanHaveModifiers(f.Kind())); } Debug.Assert(node != null, $"{nameof(node)} is null"); if (node == null) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.ModifierIsNotValidForThisItem: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { break; } SyntaxTokenList modifiers = SyntaxInfo.ModifierListInfo(node).Modifiers; if (modifiers.Contains(token)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, token); break; } else if (IsInterfaceMemberOrExplicitInterfaceImplementation(node)) { ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node, modifiers, f => { switch (f.Kind()) { case SyntaxKind.PublicKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.InternalKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.StaticKeyword: case SyntaxKind.VirtualKeyword: case SyntaxKind.OverrideKeyword: case SyntaxKind.AbstractKeyword: { return(true); } } return(false); }); } else if (node.IsKind(SyntaxKind.IndexerDeclaration)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword); } else if (node.IsKind(SyntaxKind.PropertyDeclaration)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword); } break; } case CompilerDiagnosticIdentifiers.MoreThanOneProtectionModifier: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, token); } break; } case CompilerDiagnosticIdentifiers.AccessibilityModifiersMayNotBeUsedOnAccessorsInInterface: case CompilerDiagnosticIdentifiers.AccessModifiersAreNotAllowedOnStaticConstructors: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveAccessibility(context, diagnostic, node); } break; } case CompilerDiagnosticIdentifiers.ModifiersCannotBePlacedOnEventAccessorDeclarations: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node); } break; } case CompilerDiagnosticIdentifiers.OnlyMethodsClassesStructsOrInterfacesMayBePartial: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword); } break; } case CompilerDiagnosticIdentifiers.ClassCannotBeBothStaticAndSealed: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { break; } ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword, additionalKey: nameof(SyntaxKind.StaticKeyword)); ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.SealedKeyword, additionalKey: nameof(SyntaxKind.SealedKeyword)); break; } case CompilerDiagnosticIdentifiers.FieldCanNotBeBothVolatileAndReadOnly: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { break; } var fieldDeclaration = (FieldDeclarationSyntax)node; ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, fieldDeclaration, SyntaxKind.VolatileKeyword, additionalKey: nameof(SyntaxKind.VolatileKeyword)); ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, additionalKey: nameof(SyntaxKind.ReadOnlyKeyword)); break; } case CompilerDiagnosticIdentifiers.NewProtectedMemberDeclaredInSealedClass: case CompilerDiagnosticIdentifiers.StaticClassesCannotContainProtectedMembers: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility)) { ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrPrivate); } break; } case CompilerDiagnosticIdentifiers.VirtualOrAbstractmembersCannotBePrivate: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility)) { ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected); } break; } case CompilerDiagnosticIdentifiers.AbstractPropertiesCannotHavePrivateAccessors: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveAccessibility(context, diagnostic, node, additionalKey: CodeFixIdentifiers.RemoveInvalidModifier); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility)) { ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected); } break; } case CompilerDiagnosticIdentifiers.StaticMemberCannotBeMarkedOverrideVirtualOrAbstract: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { break; } if (!node.IsParentKind(SyntaxKind.ClassDeclaration) || !((ClassDeclarationSyntax)node.Parent).Modifiers.Contains(SyntaxKind.StaticKeyword)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword, additionalKey: nameof(SyntaxKind.StaticKeyword)); } ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword, additionalKey: nameof(SyntaxKind.OverrideKeyword)); ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.VirtualKeyword, additionalKey: nameof(SyntaxKind.VirtualKeyword)); ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AbstractKeyword, additionalKey: nameof(SyntaxKind.AbstractKeyword)); break; } case CompilerDiagnosticIdentifiers.AsyncModifierCanOnlyBeUsedInMethodsThatHaveBody: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword); } break; } case CompilerDiagnosticIdentifiers.PartialMethodCannotHaveAccessModifiersOrVirtualAbstractOverrideNewSealedOrExternModifiers: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { break; } ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node, f => { switch (f.Kind()) { case SyntaxKind.PublicKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.InternalKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.VirtualKeyword: case SyntaxKind.AbstractKeyword: case SyntaxKind.OverrideKeyword: case SyntaxKind.NewKeyword: case SyntaxKind.SealedKeyword: case SyntaxKind.ExternKeyword: { return(true); } } return(false); }); break; } case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeStatic: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier)) { AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier)) { var methodDeclaration = (MethodDeclarationSyntax)node; ParameterSyntax parameter = methodDeclaration.ParameterList.Parameters.First(); SyntaxToken modifier = parameter.Modifiers.Find(SyntaxKind.ThisKeyword); ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, parameter, modifier, additionalKey: CodeFixIdentifiers.RemoveThisModifier); } break; } case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeDefinedInNonGenericStaticClass: { if (!node.IsKind(SyntaxKind.ClassDeclaration)) { return; } var classDeclaration = (ClassDeclarationSyntax)node; if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier) && !classDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword)) { AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier)) { IEnumerable <ParameterSyntax> thisParameters = classDeclaration.Members .Where(f => f.IsKind(SyntaxKind.MethodDeclaration)) .Cast <MethodDeclarationSyntax>() .Select(f => f.ParameterList?.Parameters.FirstOrDefault()) .Where(f => f?.Modifiers.Contains(SyntaxKind.ThisKeyword) == true); ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, thisParameters, SyntaxKind.ThisKeyword, title: "Remove 'this' modifier from extension methods", additionalKey: CodeFixIdentifiers.RemoveThisModifier); } break; } case CompilerDiagnosticIdentifiers.NoDefiningDeclarationFoundForImplementingDeclarationOfPartialMethod: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword); } break; } case CompilerDiagnosticIdentifiers.MethodHasParameterModifierThisWhichIsNotOnFirstParameter: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, token.Parent, token); } break; } case CompilerDiagnosticIdentifiers.CannotDeclareInstanceMembersInStaticClass: case CompilerDiagnosticIdentifiers.StaticClassesCannotHaveInstanceConstructors: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier)) { AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassNonStatic)) { var classDeclaration = (ClassDeclarationSyntax)node.Parent; ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, classDeclaration, classDeclaration.Modifiers.Find(SyntaxKind.StaticKeyword), title: "Make containing class non-static", additionalKey: CodeFixIdentifiers.MakeContainingClassNonStatic); } break; } case CompilerDiagnosticIdentifiers.ElementsDefinedInNamespaceCannotBeExplicitlyDeclaredAsPrivateProtectedOrProtectedInternal: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility)) { ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternal); } break; } case CompilerDiagnosticIdentifiers.NamespaceAlreadyContainsDefinition: case CompilerDiagnosticIdentifiers.TypeAlreadyContainsDefinition: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier)) { break; } if (!node.IsKind( SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.InterfaceDeclaration, SyntaxKind.MethodDeclaration)) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol symbol = semanticModel.GetDeclaredSymbol(node, context.CancellationToken); ImmutableArray <SyntaxReference> syntaxReferences = symbol.DeclaringSyntaxReferences; if (syntaxReferences.Length <= 1) { break; } ModifiersCodeFixRegistrator.AddModifier( context, diagnostic, ImmutableArray.CreateRange(syntaxReferences, f => f.GetSyntax(context.CancellationToken)), SyntaxKind.PartialKeyword); break; } case CompilerDiagnosticIdentifiers.NoSuitableMethodFoundToOverride: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword); } break; } case CompilerDiagnosticIdentifiers.AsyncMethodsCannotHaveRefOrOutParameters: case CompilerDiagnosticIdentifiers.IteratorsCannotHaveRefOrOutParameters: case CompilerDiagnosticIdentifiers.ReadOnlyFieldCannotBePassedAsRefOrOutValue: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveRefModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.RefKeyword, additionalKey: nameof(SyntaxKind.RefKeyword)); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveOutModifier)) { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OutKeyword, additionalKey: nameof(SyntaxKind.OutKeyword)); } break; } case CompilerDiagnosticIdentifiers.CannotHaveInstancePropertyOrFieldInitializersInStruct: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier)) { AddStaticModifier(context, diagnostic, node); } break; } case CompilerDiagnosticIdentifiers.MemberMustDeclareBodyBecauseItIsNotMarkedAbstractExternOrPartial: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddModifierAbstract) && node.Kind() == SyntaxKind.MethodDeclaration && (node.Parent as ClassDeclarationSyntax)?.Modifiers.Contains(SyntaxKind.AbstractKeyword) == true) { ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.AbstractKeyword); } break; } case CompilerDiagnosticIdentifiers.NewVirtualMemberInSealedClass: { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveVirtualModifier)) { ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, node, SyntaxKind.VirtualKeyword, additionalKey: CodeFixIdentifiers.RemoveVirtualModifier); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassUnsealed) && node.Parent is ClassDeclarationSyntax classDeclaration) { ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, classDeclaration, SyntaxKind.SealedKeyword, title: "Make containing class unsealed", additionalKey: CodeFixIdentifiers.MakeContainingClassUnsealed); } break; } case CompilerDiagnosticIdentifiers.InstanceFieldsOfReadOnlyStructsMustBeReadOnly: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeMemberReadOnly)) { break; } ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.ReadOnlyKeyword); break; } case CompilerDiagnosticIdentifiers.MemberCannotBeSealedBecauseItIsNotOverride: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveSealedModifier)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (semanticModel.GetDiagnostic( CompilerDiagnosticIdentifiers.MemberHidesInheritedMemberToMakeCurrentMethodOverrideThatImplementationAddOverrideKeyword, CSharpUtility.GetIdentifier(node).Span, context.CancellationToken) != null) { break; } ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.SealedKeyword); break; } } } }
public static async Task ComputeRefactoringsAsync(RefactoringContext context, MemberDeclarationSyntax member) { SyntaxKind kind = member.Kind(); switch (kind) { case SyntaxKind.MethodDeclaration: case SyntaxKind.IndexerDeclaration: case SyntaxKind.PropertyDeclaration: case SyntaxKind.OperatorDeclaration: case SyntaxKind.ConversionOperatorDeclaration: case SyntaxKind.ConstructorDeclaration: case SyntaxKind.EventDeclaration: case SyntaxKind.NamespaceDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.RecordDeclaration: case SyntaxKind.StructDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.EnumDeclaration: { if (context.IsAnyRefactoringEnabled( RefactoringIdentifiers.RemoveMember, RefactoringIdentifiers.DuplicateMember, RefactoringIdentifiers.CommentOutMember) && BraceContainsSpan(member, context.Span)) { if (member.IsParentKind( SyntaxKind.NamespaceDeclaration, SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.InterfaceDeclaration, SyntaxKind.CompilationUnit)) { if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveMember)) { context.RegisterRefactoring(CodeActionFactory.RemoveMemberDeclaration(context.Document, member, equivalenceKey: RefactoringIdentifiers.RemoveMember)); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.DuplicateMember)) { context.RegisterRefactoring( $"Duplicate {CSharpFacts.GetTitle(member)}", cancellationToken => DuplicateMemberDeclarationRefactoring.RefactorAsync(context.Document, member, cancellationToken), RefactoringIdentifiers.DuplicateMember); } } if (context.IsRefactoringEnabled(RefactoringIdentifiers.CommentOutMember)) { CommentOutRefactoring.RegisterRefactoring(context, member); } } break; } } if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveAllStatements)) { RemoveAllStatementsRefactoring.ComputeRefactoring(context, member); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveAllMemberDeclarations)) { RemoveAllMemberDeclarationsRefactoring.ComputeRefactoring(context, member); } if (context.IsAnyRefactoringEnabled( RefactoringIdentifiers.SwapMemberDeclarations, RefactoringIdentifiers.RemoveMemberDeclarations) && !member.Span.IntersectsWith(context.Span)) { MemberDeclarationsRefactoring.ComputeRefactoring(context, member); } switch (kind) { case SyntaxKind.NamespaceDeclaration: { var namespaceDeclaration = (NamespaceDeclarationSyntax)member; NamespaceDeclarationRefactoring.ComputeRefactorings(context, namespaceDeclaration); if (MemberDeclarationListSelection.TryCreate(namespaceDeclaration, context.Span, out MemberDeclarationListSelection selectedMembers)) { await SelectedMemberDeclarationsRefactoring.ComputeRefactoringAsync(context, selectedMembers).ConfigureAwait(false); } break; } case SyntaxKind.ClassDeclaration: { var classDeclaration = (ClassDeclarationSyntax)member; await ClassDeclarationRefactoring.ComputeRefactoringsAsync(context, classDeclaration).ConfigureAwait(false); if (MemberDeclarationListSelection.TryCreate(classDeclaration, context.Span, out MemberDeclarationListSelection selectedMembers)) { await SelectedMemberDeclarationsRefactoring.ComputeRefactoringAsync(context, selectedMembers).ConfigureAwait(false); } break; } case SyntaxKind.RecordDeclaration: { var recordDeclaration = (RecordDeclarationSyntax)member; await RecordDeclarationRefactoring.ComputeRefactoringsAsync(context, recordDeclaration).ConfigureAwait(false); if (MemberDeclarationListSelection.TryCreate(recordDeclaration, context.Span, out MemberDeclarationListSelection selectedMembers)) { await SelectedMemberDeclarationsRefactoring.ComputeRefactoringAsync(context, selectedMembers).ConfigureAwait(false); } break; } case SyntaxKind.StructDeclaration: { var structDeclaration = (StructDeclarationSyntax)member; await StructDeclarationRefactoring.ComputeRefactoringsAsync(context, structDeclaration).ConfigureAwait(false); if (MemberDeclarationListSelection.TryCreate(structDeclaration, context.Span, out MemberDeclarationListSelection selectedMembers)) { await SelectedMemberDeclarationsRefactoring.ComputeRefactoringAsync(context, selectedMembers).ConfigureAwait(false); } break; } case SyntaxKind.InterfaceDeclaration: { var interfaceDeclaration = (InterfaceDeclarationSyntax)member; InterfaceDeclarationRefactoring.ComputeRefactorings(context, interfaceDeclaration); if (MemberDeclarationListSelection.TryCreate(interfaceDeclaration, context.Span, out MemberDeclarationListSelection selectedMembers)) { await SelectedMemberDeclarationsRefactoring.ComputeRefactoringAsync(context, selectedMembers).ConfigureAwait(false); } break; } case SyntaxKind.EnumDeclaration: { await EnumDeclarationRefactoring.ComputeRefactoringAsync(context, (EnumDeclarationSyntax)member).ConfigureAwait(false); break; } case SyntaxKind.EnumMemberDeclaration: { await EnumMemberDeclarationRefactoring.ComputeRefactoringAsync(context, (EnumMemberDeclarationSyntax)member).ConfigureAwait(false); break; } case SyntaxKind.DelegateDeclaration: { DelegateDeclarationRefactoring.ComputeRefactorings(context, (DelegateDeclarationSyntax)member); break; } case SyntaxKind.MethodDeclaration: { await MethodDeclarationRefactoring.ComputeRefactoringsAsync(context, (MethodDeclarationSyntax)member).ConfigureAwait(false); break; } case SyntaxKind.ConstructorDeclaration: { await ConstructorDeclarationRefactoring.ComputeRefactoringsAsync(context, (ConstructorDeclarationSyntax)member).ConfigureAwait(false); break; } case SyntaxKind.DestructorDeclaration: { DestructorDeclarationRefactoring.ComputeRefactorings(context, (DestructorDeclarationSyntax)member); break; } case SyntaxKind.IndexerDeclaration: { await IndexerDeclarationRefactoring.ComputeRefactoringsAsync(context, (IndexerDeclarationSyntax)member).ConfigureAwait(false); break; } case SyntaxKind.PropertyDeclaration: { await PropertyDeclarationRefactoring.ComputeRefactoringsAsync(context, (PropertyDeclarationSyntax)member).ConfigureAwait(false); break; } case SyntaxKind.OperatorDeclaration: { ComputeRefactorings(context, (OperatorDeclarationSyntax)member); break; } case SyntaxKind.ConversionOperatorDeclaration: { ComputeRefactorings(context, (ConversionOperatorDeclarationSyntax)member); break; } case SyntaxKind.FieldDeclaration: { await FieldDeclarationRefactoring.ComputeRefactoringsAsync(context, (FieldDeclarationSyntax)member).ConfigureAwait(false); break; } case SyntaxKind.EventDeclaration: { await EventDeclarationRefactoring.ComputeRefactoringsAsync(context, (EventDeclarationSyntax)member).ConfigureAwait(false); break; } case SyntaxKind.EventFieldDeclaration: { await EventFieldDeclarationRefactoring.ComputeRefactoringsAsync(context, (EventFieldDeclarationSyntax)member).ConfigureAwait(false); break; } } if (context.IsRefactoringEnabled(RefactoringIdentifiers.MoveUnsafeContextToContainingDeclaration)) { MoveUnsafeContextToContainingDeclarationRefactoring.ComputeRefactoring(context, member); } }
private static async Task <ExpressionSyntax> CreateNewNodeAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { ExpressionSyntax left = binaryExpression.Left; ExpressionSyntax right = binaryExpression.Right; TextSpan span = TextSpan.FromBounds(left.Span.End, right.SpanStart); IEnumerable <SyntaxTrivia> trivia = binaryExpression.DescendantTrivia(span); bool isWhiteSpaceOrEndOfLine = trivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (CSharpFacts.IsBooleanLiteralExpression(left.Kind())) { SyntaxTriviaList leadingTrivia = binaryExpression.GetLeadingTrivia(); if (!isWhiteSpaceOrEndOfLine) { leadingTrivia = leadingTrivia.AddRange(trivia); } if (right.IsKind(SyntaxKind.LogicalNotExpression)) { var logicalNot = (PrefixUnaryExpressionSyntax)right; ExpressionSyntax operand = logicalNot.Operand; if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean)) { return(binaryExpression .WithLeft(Inverter.LogicallyNegate(left, semanticModel, cancellationToken)) .WithRight(operand.WithTriviaFrom(right))); } } return(Inverter.LogicallyNegate(right, semanticModel, cancellationToken) .WithLeadingTrivia(leadingTrivia)); } else if (CSharpFacts.IsBooleanLiteralExpression(right.Kind())) { SyntaxTriviaList trailingTrivia = binaryExpression.GetTrailingTrivia(); if (!isWhiteSpaceOrEndOfLine) { trailingTrivia = trailingTrivia.InsertRange(0, trivia); } if (left.IsKind(SyntaxKind.LogicalNotExpression)) { var logicalNot = (PrefixUnaryExpressionSyntax)left; ExpressionSyntax operand = logicalNot.Operand; if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean)) { return(binaryExpression .WithLeft(operand.WithTriviaFrom(left)) .WithRight(Inverter.LogicallyNegate(right, semanticModel, cancellationToken))); } } return(Inverter.LogicallyNegate(left, semanticModel, cancellationToken) .WithTrailingTrivia(trailingTrivia)); } Debug.Fail(binaryExpression.ToString()); return(binaryExpression); }
private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext context) { var parenthesizedExpression = (ParenthesizedExpressionSyntax)context.Node; ExpressionSyntax expression = parenthesizedExpression.Expression; if (expression?.IsMissing != false) { return; } SyntaxToken openParen = parenthesizedExpression.OpenParenToken; if (openParen.IsMissing) { return; } SyntaxToken closeParen = parenthesizedExpression.CloseParenToken; if (closeParen.IsMissing) { return; } SyntaxNode parent = parenthesizedExpression.Parent; SyntaxKind parentKind = parent.Kind(); switch (parentKind) { case SyntaxKind.ParenthesizedExpression: case SyntaxKind.ArrowExpressionClause: case SyntaxKind.AttributeArgument: case SyntaxKind.Argument: case SyntaxKind.ExpressionStatement: case SyntaxKind.ReturnStatement: case SyntaxKind.YieldReturnStatement: case SyntaxKind.WhileStatement: case SyntaxKind.DoStatement: case SyntaxKind.UsingStatement: case SyntaxKind.LockStatement: case SyntaxKind.IfStatement: case SyntaxKind.SwitchStatement: case SyntaxKind.ArrayRankSpecifier: { ReportDiagnostic(); break; } case SyntaxKind.LessThanExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: { if (expression.IsKind(SyntaxKind.IdentifierName) || expression is LiteralExpressionSyntax) { ReportDiagnostic(); } break; } case SyntaxKind.MultiplyExpression: case SyntaxKind.DivideExpression: case SyntaxKind.ModuloExpression: case SyntaxKind.AddExpression: case SyntaxKind.SubtractExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.LogicalOrExpression: { SyntaxKind kind = expression.Kind(); if (kind == SyntaxKind.IdentifierName || expression is LiteralExpressionSyntax) { ReportDiagnostic(); } else if (kind == parentKind && ((BinaryExpressionSyntax)parent).Left == parenthesizedExpression) { ReportDiagnostic(); } break; } case SyntaxKind.LogicalNotExpression: { switch (expression.Kind()) { case SyntaxKind.IdentifierName: case SyntaxKind.GenericName: case SyntaxKind.InvocationExpression: case SyntaxKind.SimpleMemberAccessExpression: case SyntaxKind.ElementAccessExpression: case SyntaxKind.ConditionalAccessExpression: { ReportDiagnostic(); break; } } break; } case SyntaxKind.SimpleAssignmentExpression: case SyntaxKind.AddAssignmentExpression: case SyntaxKind.SubtractAssignmentExpression: case SyntaxKind.MultiplyAssignmentExpression: case SyntaxKind.DivideAssignmentExpression: case SyntaxKind.ModuloAssignmentExpression: case SyntaxKind.AndAssignmentExpression: case SyntaxKind.ExclusiveOrAssignmentExpression: case SyntaxKind.OrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression: { if (((AssignmentExpressionSyntax)parent).Left == parenthesizedExpression) { ReportDiagnostic(); } else if (expression.IsKind(SyntaxKind.IdentifierName) || expression is LiteralExpressionSyntax) { ReportDiagnostic(); } break; } case SyntaxKind.Interpolation: { if (!expression.IsKind(SyntaxKind.ConditionalExpression) && !expression.DescendantNodes().Any(f => f.IsKind(SyntaxKind.AliasQualifiedName)) && ((InterpolationSyntax)parent).Expression == parenthesizedExpression) { ReportDiagnostic(); } break; } case SyntaxKind.AwaitExpression: { if (CSharpFacts.GetOperatorPrecedence(expression.Kind()) <= CSharpFacts.GetOperatorPrecedence(SyntaxKind.AwaitExpression)) { ReportDiagnostic(); } break; } case SyntaxKind.ArrayInitializerExpression: case SyntaxKind.CollectionInitializerExpression: { if (!(expression is AssignmentExpressionSyntax)) { ReportDiagnostic(); } break; } } void ReportDiagnostic() { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.RemoveRedundantParentheses, openParen.GetLocation(), additionalLocations: ImmutableArray.Create(closeParen.GetLocation())); DiagnosticHelpers.ReportToken(context, DiagnosticDescriptors.RemoveRedundantParenthesesFadeOut, openParen); DiagnosticHelpers.ReportToken(context, DiagnosticDescriptors.RemoveRedundantParenthesesFadeOut, closeParen); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression)) { return; } Document document = context.Document; foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.ConstantValuesShouldBePlacedOnRightSideOfComparisons: { CodeAction codeAction = CodeAction.Create( "Swap operands", ct => document.ReplaceNodeAsync(binaryExpression, SyntaxRefactorings.SwapBinaryOperands(binaryExpression), ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod: { CodeAction codeAction = CodeAction.Create( "Use 'string.IsNullOrEmpty' method", ct => UseStringIsNullOrEmptyMethodAsync(document, binaryExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SimplifyCoalesceExpression: { ExpressionSyntax expression = binaryExpression.Left; if (expression == null || !context.Span.Contains(expression.Span)) { expression = binaryExpression.Right; } CodeAction codeAction = CodeAction.Create( "Simplify coalesce expression", ct => SimplifyCoalesceExpressionRefactoring.RefactorAsync(document, binaryExpression, expression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantAsOperator: { CodeAction codeAction = CodeAction.Create( "Remove redundant 'as' operator", ct => RemoveRedundantAsOperatorRefactoring.RefactorAsync(document, binaryExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString: { CodeAction codeAction = CodeAction.Create( "Use string.Length", ct => UseStringLengthInsteadOfComparisonWithEmptyStringAsync(document, binaryExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); CodeAction codeAction = CodeAction.Create( $"Use EqualityComparer<{typeSymbol.Name}>.Default", ct => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); string title; if (CSharpFacts.IsSimpleType(typeSymbol.SpecialType) || typeSymbol.ContainsMember <IMethodSymbol>(WellKnownMemberNames.EqualityOperatorName)) { ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions()); title = $"Replace 'null' with '{expression}'"; } else { title = $"Use EqualityComparer<{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart, SymbolDisplayFormats.DisplayName)}>.Default"; } CodeAction codeAction = CodeAction.Create( title, ct => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.JoinStringExpressions: { CodeAction codeAction = CodeAction.Create( "Join string expressions", ct => JoinStringExpressionsRefactoring.RefactorAsync(document, binaryExpression, context.Span, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseExclusiveOrOperator: { CodeAction codeAction = CodeAction.Create( "Use ^ operator", ct => UseExclusiveOrOperatorRefactoring.RefactorAsync(document, binaryExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnnecessaryNullCheck: { CodeAction codeAction = CodeAction.Create( "Remove unnecessary null check", ct => RemoveUnnecessaryNullCheckAsync(document, binaryExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseShortCircuitingOperator: { SyntaxToken operatorToken = binaryExpression.OperatorToken; SyntaxKind kind = binaryExpression.Kind(); SyntaxToken newToken = default; if (kind == SyntaxKind.BitwiseAndExpression) { newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.AmpersandAmpersandToken, operatorToken.TrailingTrivia); } else if (kind == SyntaxKind.BitwiseOrExpression) { newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.BarBarToken, operatorToken.TrailingTrivia); } CodeAction codeAction = CodeAction.Create( $"Use '{newToken.ToString()}' operator", ct => { BinaryExpressionSyntax newBinaryExpression = null; if (kind == SyntaxKind.BitwiseAndExpression) { newBinaryExpression = LogicalAndExpression(binaryExpression.Left, newToken, binaryExpression.Right); } else if (kind == SyntaxKind.BitwiseOrExpression) { newBinaryExpression = LogicalOrExpression(binaryExpression.Left, newToken, binaryExpression.Right); } return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnnecessaryOperator: { CodeAction codeAction = CodeAction.Create( "Use '==' operator", ct => { SyntaxToken operatorToken = binaryExpression.OperatorToken; BinaryExpressionSyntax newBinaryExpression = EqualsExpression( binaryExpression.Left, Token(operatorToken.LeadingTrivia, SyntaxKind.EqualsEqualsToken, operatorToken.TrailingTrivia), binaryExpression.Right); return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
private static void AnalyzeElseClause(SyntaxNodeAnalysisContext context) { var elseClause = (ElseClauseSyntax)context.Node; StatementSyntax statement = elseClause.EmbeddedStatement(allowIfStatement: false); if (statement == null) { return; } if (statement.ContainsDirectives) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.AddBracesToIfElse, statement, CSharpFacts.GetTitle(elseClause)); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { Diagnostic diagnostic = context.Diagnostics[0]; if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMethodReturnType)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement))) { return; } BlockSyntax body = (node is MethodDeclarationSyntax methodDeclaration) ? methodDeclaration.Body : ((LocalFunctionStatementSyntax)node).Body; Debug.Assert(body != null, node.ToString()); if (body == null) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = null; HashSet <ITypeSymbol> typeSymbols = null; INamedTypeSymbol ienumerableOfTSymbol = null; foreach (SyntaxNode descendant in body.DescendantNodes(descendIntoChildren: f => !CSharpFacts.IsFunction(f.Kind()))) { if (!descendant.IsKind(SyntaxKind.YieldReturnStatement)) { continue; } var yieldReturn = (YieldStatementSyntax)descendant; ExpressionSyntax expression = yieldReturn.Expression; if (expression == null) { continue; } var namedTypeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken) as INamedTypeSymbol; if (namedTypeSymbol?.IsErrorType() != false) { continue; } if (typeSymbol == null) { typeSymbol = namedTypeSymbol; } else { if (typeSymbols == null) { typeSymbols = new HashSet <ITypeSymbol>() { typeSymbol }; } if (!typeSymbols.Add(namedTypeSymbol)) { continue; } } if (ienumerableOfTSymbol == null) { ienumerableOfTSymbol = semanticModel.GetTypeByMetadataName("System.Collections.Generic.IEnumerable`1"); } CodeFixRegistrator.ChangeTypeOrReturnType( context, diagnostic, node, ienumerableOfTSymbol.Construct(namedTypeSymbol), semanticModel, additionalKey: SymbolDisplay.ToMinimalDisplayString(namedTypeSymbol, semanticModel, node.SpanStart, SymbolDisplayFormats.Default)); } }
private static void Analyze( SyntaxNodeAnalysisContext context, SyntaxNode declaration, ParameterListSyntax parameterList, CSharpSyntaxNode bodyOrExpressionBody) { if (parameterList == null) { return; } if (bodyOrExpressionBody == null) { return; } if (!parameterList.Parameters.Any()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(declaration, cancellationToken); SyntaxWalker walker = null; foreach (IParameterSymbol parameter in methodSymbol.Parameters) { cancellationToken.ThrowIfCancellationRequested(); ITypeSymbol type = parameter.Type; if (type.Kind == SymbolKind.ErrorType) { continue; } if (CSharpFacts.IsSimpleType(type.SpecialType)) { continue; } if (!type.IsReadOnlyStruct()) { if (parameter.RefKind == RefKind.In && type.TypeKind == TypeKind.Struct) { var parameterSyntax = (ParameterSyntax)parameter.GetSyntax(cancellationToken); Debug.Assert(parameterSyntax.Modifiers.Contains(SyntaxKind.InKeyword), ""); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.DoNotPassNonReadOnlyStructByReadOnlyReference, parameterSyntax.Identifier); } continue; } if (parameter.RefKind != RefKind.None) { continue; } if (walker == null) { if (methodSymbol.ImplementsInterfaceMember(allInterfaces: true)) { break; } walker = SyntaxWalker.GetInstance(); } else if (walker.Parameters.ContainsKey(parameter.Name)) { walker.Parameters.Clear(); break; } walker.Parameters.Add(parameter.Name, parameter); } if (walker == null) { return; } try { if (walker.Parameters.Count > 0) { walker.SemanticModel = semanticModel; walker.CancellationToken = cancellationToken; if (bodyOrExpressionBody.IsKind(SyntaxKind.Block)) { walker.VisitBlock((BlockSyntax)bodyOrExpressionBody); } else { walker.VisitArrowExpressionClause((ArrowExpressionClauseSyntax)bodyOrExpressionBody); } if (walker.Parameters.Count > 0) { DataFlowAnalysis analysis = (bodyOrExpressionBody.IsKind(SyntaxKind.Block)) ? semanticModel.AnalyzeDataFlow((BlockSyntax)bodyOrExpressionBody) : semanticModel.AnalyzeDataFlow(((ArrowExpressionClauseSyntax)bodyOrExpressionBody).Expression); bool?isReferencedAsMethodGroup = null; foreach (KeyValuePair <string, IParameterSymbol> kvp in walker.Parameters) { var isAssigned = false; foreach (ISymbol assignedSymbol in analysis.AlwaysAssigned) { if (SymbolEqualityComparer.Default.Equals(assignedSymbol, kvp.Value)) { isAssigned = true; break; } } if (isAssigned) { continue; } if (isReferencedAsMethodGroup ??= IsReferencedAsMethodGroup()) { break; } if (kvp.Value.GetSyntaxOrDefault(cancellationToken) is ParameterSyntax parameter) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.MakeParameterRefReadOnly, parameter.Identifier); } } } } } finally { SyntaxWalker.Free(walker); } bool IsReferencedAsMethodGroup() { switch (declaration.Kind()) { case SyntaxKind.MethodDeclaration: return(MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(declaration.Parent, methodSymbol, semanticModel, cancellationToken)); case SyntaxKind.LocalFunctionStatement: return(MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(declaration.FirstAncestor <MemberDeclarationSyntax>(), methodSymbol, semanticModel, cancellationToken)); default: return(false); } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.FormatDeclarationBraces: { CodeAction codeAction = CodeAction.Create( "Format braces", cancellationToken => FormatDeclarationBracesRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantOverridingMember: { CodeAction codeAction = CodeAction.Create( $"Remove {CSharpFacts.GetTitle(memberDeclaration)}", cancellationToken => context.Document.RemoveMemberAsync(memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddDefaultAccessModifier: { var accessibility = (Accessibility)Enum.Parse( typeof(Accessibility), diagnostic.Properties[nameof(Accessibility)]); CodeAction codeAction = CodeAction.Create( "Add default access modifier", cancellationToken => AddDefaultAccessModifierRefactoring.RefactorAsync(context.Document, memberDeclaration, accessibility, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantSealedModifier: { ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, memberDeclaration, SyntaxKind.SealedKeyword); break; } case DiagnosticIdentifiers.AvoidSemicolonAtEndOfDeclaration: { CodeAction codeAction = CodeAction.Create( "Remove unnecessary semicolon", cancellationToken => AvoidSemicolonAtEndOfDeclarationRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ReorderModifiers: { CodeAction codeAction = CodeAction.Create( "Reorder modifiers", cancellationToken => ReorderModifiersRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.MarkFieldAsReadOnly: { var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration; SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = fieldDeclaration.Declaration.Variables; string title = (declarators.Count == 1) ? $"Mark '{declarators[0].Identifier.ValueText}' as read-only" : "Mark fields as read-only"; ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, title: title); break; } case DiagnosticIdentifiers.UseConstantInsteadOfField: { CodeAction codeAction = CodeAction.Create( "Use constant instead of field", cancellationToken => UseConstantInsteadOfFieldRefactoring.RefactorAsync(context.Document, (FieldDeclarationSyntax)memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseReadOnlyAutoProperty: { CodeAction codeAction = CodeAction.Create( "Use read-only auto-property", cancellationToken => UseReadOnlyAutoPropertyRefactoring.RefactorAsync(context.Document, (PropertyDeclarationSyntax)memberDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ReplaceCommentWithDocumentationComment: { CodeAction codeAction = CodeAction.Create( ReplaceCommentWithDocumentationCommentRefactoring.Title, cancellationToken => ReplaceCommentWithDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, context.Span, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
private static void AnalyzeAsExpression(SyntaxNodeAnalysisContext context) { var asExpression = (BinaryExpressionSyntax)context.Node; AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(asExpression); if (!asExpressionInfo.Success) { return; } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(asExpression); if (!localInfo.Success) { return; } if (localInfo.Statement.SpanOrTrailingTriviaContainsDirectives()) { return; } if (!(localInfo.Statement.NextStatement() is IfStatementSyntax ifStatement)) { return; } if (!ifStatement.IsSimpleIf()) { return; } if (ifStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } StatementSyntax statement = ifStatement.SingleNonBlockStatementOrDefault(); if (statement == null) { return; } if (!CSharpFacts.IsJumpStatement(statement.Kind())) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.EqualsToNull | NullCheckStyles.IsNull); if (!nullCheck.Success) { return; } if (!string.Equals(localInfo.IdentifierText, (nullCheck.Expression as IdentifierNameSyntax)?.Identifier.ValueText, StringComparison.Ordinal)) { return; } if (!localInfo.Type.IsVar) { SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(asExpressionInfo.Type, cancellationToken); if (typeSymbol.IsNullableType()) { return; } if (!SymbolEqualityComparer.Default.Equals(semanticModel.GetTypeSymbol(localInfo.Type, cancellationToken), typeSymbol)) { return; } } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UsePatternMatchingInsteadOfAsAndNullCheck, localInfo.Statement); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsEnabled(CodeFixIdentifiers.AddDocumentationComment) && !Settings.IsEnabled(CodeFixIdentifiers.ChangeMethodReturnType) && !Settings.IsEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType) && !Settings.IsEnabled(CodeFixIdentifiers.AddPartialModifier) && !Settings.IsEnabled(CodeFixIdentifiers.MakeContainingClassAbstract) && !Settings.IsEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor) && !Settings.IsEnabled(CodeFixIdentifiers.RemoveMemberDeclaration) && !Settings.IsEnabled(CodeFixIdentifiers.RenameDestructorToMatchClassName) && !Settings.IsEnabled(CodeFixIdentifiers.RenameTupleElement) && !Settings.IsEnabled(CodeFixIdentifiers.MarkDeclarationAsNonCLSCompliant)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.MissingXmlCommentForPubliclyVisibleTypeOrMember: { if (!Settings.IsEnabled(CodeFixIdentifiers.AddDocumentationComment)) { break; } CodeAction codeAction = CodeAction.Create( "Add documentation comment", cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, false, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); CodeAction codeAction2 = CodeAction.Create( "Add documentation comment (copy from base if available)", cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, true, cancellationToken), GetEquivalenceKey(diagnostic, "CopyFromBaseIfAvailable")); context.RegisterCodeFix(codeAction2, diagnostic); break; } case CompilerDiagnosticIdentifiers.MethodReturnTypeMustMatchOverriddenMethodReturnType: { if (!Settings.IsEnabled(CodeFixIdentifiers.ChangeMethodReturnType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); ITypeSymbol typeSymbol = methodSymbol.OverriddenMethod.ReturnType; CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel); break; } case CompilerDiagnosticIdentifiers.PartialMethodsMustHaveVoidReturnType: { if (!Settings.IsEnabled(CodeFixIdentifiers.ChangeMethodReturnType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration; MethodDeclarationSyntax otherPart = semanticModel.GetOtherPart(methodDeclaration, context.CancellationToken); if (otherPart == null) { break; } CodeAction codeAction = CodeAction.Create( "Change return type to 'void'", cancellationToken => { return(context.Document.Solution().ReplaceNodesAsync( new MethodDeclarationSyntax[] { methodDeclaration, otherPart }, (node, _) => node.WithReturnType(CSharpFactory.VoidType().WithTriviaFrom(node.ReturnType)), cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.MemberTypeMustMatchOverriddenMemberType: { if (!Settings.IsEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = null; switch (memberDeclaration.Kind()) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.IndexerDeclaration: { var propertySymbol = (IPropertySymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = propertySymbol.OverriddenProperty.Type; break; } case SyntaxKind.EventDeclaration: { var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } case SyntaxKind.EventFieldDeclaration: { VariableDeclaratorSyntax declarator = ((EventFieldDeclarationSyntax)memberDeclaration).Declaration.Variables.First(); var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(declarator, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } } CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel); break; } case CompilerDiagnosticIdentifiers.MissingPartialModifier: case CompilerDiagnosticIdentifiers.PartialMethodMustBeDeclaredInPartialClassOrPartialStruct: { if (!Settings.IsEnabled(CodeFixIdentifiers.AddPartialModifier)) { break; } SyntaxNode node = null; switch (memberDeclaration.Kind()) { case SyntaxKind.MethodDeclaration: { if (memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration)) { node = memberDeclaration.Parent; } break; } case SyntaxKind.ClassDeclaration: case SyntaxKind.StructDeclaration: case SyntaxKind.InterfaceDeclaration: { node = memberDeclaration; break; } } Debug.Assert(node != null, memberDeclaration.ToString()); if (node == null) { break; } ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.PartialKeyword); break; } case CompilerDiagnosticIdentifiers.MemberIsAbstractButItIsContainedInNonAbstractClass: { if (!Settings.IsEnabled(CodeFixIdentifiers.MakeContainingClassAbstract)) { break; } if (!memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration)) { break; } ModifiersCodeFixRegistrator.AddModifier( context, diagnostic, memberDeclaration.Parent, SyntaxKind.AbstractKeyword, title: "Make containing class abstract"); break; } case CompilerDiagnosticIdentifiers.StaticConstructorMustBeParameterless: { if (!Settings.IsEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor)) { break; } var constructorDeclaration = (ConstructorDeclarationSyntax)memberDeclaration; CodeAction codeAction = CodeAction.Create( "Remove parameters", cancellationToken => { ParameterListSyntax parameterList = constructorDeclaration.ParameterList; ParameterListSyntax newParameterList = parameterList .WithParameters(default(SeparatedSyntaxList <ParameterSyntax>)) .WithOpenParenToken(parameterList.OpenParenToken.WithoutTrailingTrivia()) .WithCloseParenToken(parameterList.CloseParenToken.WithoutLeadingTrivia()); ConstructorDeclarationSyntax newNode = constructorDeclaration.WithParameterList(newParameterList); return(context.Document.ReplaceNodeAsync(constructorDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.ExplicitInterfaceDeclarationCanOnlyBeDeclaredInClassOrStruct: case CompilerDiagnosticIdentifiers.InterfacesCannotContainFields: case CompilerDiagnosticIdentifiers.InterfacesCannotContainOperators: case CompilerDiagnosticIdentifiers.InterfacesCannotDeclareTypes: case CompilerDiagnosticIdentifiers.OnlyClassTypesCanContainDestructors: case CompilerDiagnosticIdentifiers.StructsCannotContainExplicitParameterlessConstructors: { if (!Settings.IsEnabled(CodeFixIdentifiers.RemoveMemberDeclaration)) { break; } CodeFixRegistrator.RemoveMemberDeclaration(context, diagnostic, memberDeclaration); break; } case CompilerDiagnosticIdentifiers.NameOfDestructorMustMatchNameOfClass: { if (!Settings.IsEnabled(CodeFixIdentifiers.RenameDestructorToMatchClassName)) { break; } if (!(memberDeclaration is DestructorDeclarationSyntax destructorDeclaration)) { break; } if (!(memberDeclaration.Parent is ClassDeclarationSyntax classDeclaration)) { break; } if (classDeclaration.Identifier.ValueText.Length == 0) { break; } CodeAction codeAction = CodeAction.Create( "Rename destructor to match class name", cancellationToken => { DestructorDeclarationSyntax newNode = destructorDeclaration.WithIdentifier(classDeclaration.Identifier.WithTriviaFrom(destructorDeclaration.Identifier)); return(context.Document.ReplaceNodeAsync(destructorDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CannotChangeTupleElementNameWhenOverridingInheritedMember: { if (!Settings.IsEnabled(CodeFixIdentifiers.RenameTupleElement)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (memberDeclaration is MethodDeclarationSyntax methodDeclaration) { IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken); if (!(methodSymbol.ReturnType is INamedTypeSymbol tupleType)) { break; } if (!tupleType.IsTupleType) { break; } if (!(methodSymbol.OverriddenMethod?.ReturnType is INamedTypeSymbol baseTupleType)) { break; } if (!baseTupleType.IsTupleType) { break; } ImmutableArray <IFieldSymbol> elements = tupleType.TupleElements; ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements; if (elements.Length != baseElements.Length) { break; } int i = 0; while (i < elements.Length) { if (elements[i].Name != baseElements[i].Name) { break; } i++; } if (i == elements.Length) { break; } TupleElementSyntax tupleElement = ((TupleTypeSyntax)methodDeclaration.ReturnType).Elements[i]; CodeAction codeAction = CodeAction.Create( $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'", ct => RenameTupleElementAsync(context.Document, methodDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else if (memberDeclaration is PropertyDeclarationSyntax propertyDeclaration) { IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, context.CancellationToken); if (!(propertySymbol.Type is INamedTypeSymbol tupleType)) { break; } if (!tupleType.IsTupleType) { break; } if (!(propertySymbol.OverriddenProperty?.Type is INamedTypeSymbol baseTupleType)) { break; } if (!baseTupleType.IsTupleType) { break; } ImmutableArray <IFieldSymbol> elements = tupleType.TupleElements; ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements; if (elements.Length != baseElements.Length) { break; } int i = 0; while (i < elements.Length) { if (elements[i].Name != baseElements[i].Name) { break; } i++; } if (i == elements.Length) { break; } TupleElementSyntax tupleElement = ((TupleTypeSyntax)propertyDeclaration.Type).Elements[i]; CodeAction codeAction = CodeAction.Create( $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'", ct => RenameTupleElementAsync(context.Document, propertyDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case CompilerDiagnosticIdentifiers.MethodsWithVariableArgumentsAreNotCLSCompliant: case CompilerDiagnosticIdentifiers.ArgumentTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.ReturnTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.TypeOfVariableIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.IdentifierDifferingOnlyInCaseIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.OverloadedMethodDifferingOnlyInRefOrOutOrInArrayRankIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.OverloadedMethodDifferingOnlyByUnnamedArrayTypesIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.IdentifierIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.BaseTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.ArraysAsAttributeArgumentsIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.ConstraintTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.TypeIsNotCLSCompliantBecauseBaseInterfaceIsNotCLSCompliant: { if (!Settings.IsEnabled(CodeFixIdentifiers.MarkDeclarationAsNonCLSCompliant)) { break; } CodeAction codeAction = CodeAction.Create( $"Mark {CSharpFacts.GetTitle(memberDeclaration)} as non-CLS-compliant", ct => MarkDeclarationAsNonCLSCompliantAsync(context.Document, memberDeclaration, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
private static void AnalyzeFieldDeclaration(SyntaxNodeAnalysisContext context) { var fieldDeclaration = (FieldDeclarationSyntax)context.Node; if (fieldDeclaration.ContainsDiagnostics) { return; } if (fieldDeclaration.Modifiers.Contains(SyntaxKind.ConstKeyword)) { return; } if (fieldDeclaration.IsParentKind(SyntaxKind.StructDeclaration, SyntaxKind.RecordStructDeclaration)) { var structSymbol = context.SemanticModel.GetDeclaredSymbol(fieldDeclaration.Parent, context.CancellationToken) as INamedTypeSymbol; if (structSymbol?.InstanceConstructors.Length > 1) { return; } } VariableDeclarationSyntax declaration = fieldDeclaration.Declaration; if (declaration == null) { return; } foreach (VariableDeclaratorSyntax declarator in declaration.Variables) { EqualsValueClauseSyntax initializer = declarator.Initializer; if (initializer?.ContainsDirectives == false) { ExpressionSyntax value = initializer.Value?.WalkDownParentheses(); if (value is CastExpressionSyntax castExpression) { value = castExpression.Expression.WalkDownParentheses(); } if (CanBeConstantValue(value)) { SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(declaration.Type, cancellationToken); if (typeSymbol != null) { if (CSharpFacts.IsNumericType(typeSymbol.SpecialType) && value.IsNumericLiteralExpression("0")) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantFieldInitialization, initializer); } else if (semanticModel.IsDefaultValue(typeSymbol, value, cancellationToken)) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantFieldInitialization, initializer); } } } } } }
public async Task ComputeRefactoringsAsync(RefactoringContext context, TNode node) { if (!ValidateNode(node, context.Span)) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TSymbol symbol = GetMemberSymbol(node, semanticModel, context.CancellationToken); if (EqualityComparer <TSymbol> .Default.Equals(symbol, default(TSymbol))) { return; } TDeclaration declaration = await GetMemberDeclarationAsync(symbol, context.CancellationToken).ConfigureAwait(false); if (declaration == null) { return; } for (SyntaxNode parent = node.Parent; parent != null; parent = parent.Parent) { if (object.ReferenceEquals(declaration, parent)) { return; } } (ExpressionSyntax expression, SyntaxList <StatementSyntax> statements) = GetExpressionOrStatements(declaration); SyntaxNode nodeIncludingConditionalAccess = node.WalkUp(SyntaxKind.ConditionalAccessExpression); if (expression != null || (statements.Any() && nodeIncludingConditionalAccess.IsParentKind(SyntaxKind.ExpressionStatement))) { ImmutableArray <ParameterInfo> parameterInfos = GetParameterInfos(node, symbol); if (parameterInfos.IsDefault) { return; } INamedTypeSymbol enclosingType = semanticModel.GetEnclosingNamedType(node.SpanStart, context.CancellationToken); SemanticModel declarationSemanticModel = (node.SyntaxTree == declaration.SyntaxTree) ? semanticModel : await context.Solution.GetDocument(declaration.SyntaxTree).GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); InlineRefactoring <TNode, TDeclaration, TSymbol> refactoring = CreateRefactoring(context.Document, nodeIncludingConditionalAccess, enclosingType, symbol, declaration, parameterInfos, semanticModel, declarationSemanticModel, context.CancellationToken); string title = CSharpFacts.GetTitle(declaration); if (expression != null) { context.RegisterRefactoring($"Inline {title}", cancellationToken => refactoring.InlineAsync(nodeIncludingConditionalAccess, expression, cancellationToken)); context.RegisterRefactoring($"Inline and remove {title}", cancellationToken => refactoring.InlineAndRemoveAsync(nodeIncludingConditionalAccess, expression, cancellationToken)); } else { var expressionStatement = (ExpressionStatementSyntax)nodeIncludingConditionalAccess.Parent; context.RegisterRefactoring($"Inline {title}", cancellationToken => refactoring.InlineAsync(expressionStatement, statements, cancellationToken)); context.RegisterRefactoring($"Inline and remove {title}", cancellationToken => refactoring.InlineAndRemoveAsync(expressionStatement, statements, cancellationToken)); } } }