protected override IParameterSymbol GetParameterSymbolCore(SemanticModel semanticModel, CancellationToken cancellationToken) { SyntaxNode parent = Node.Parent; if (parent?.Kind() != SyntaxKind.CoalesceExpression) { return(null); } SimpleAssignmentExpressionInfo simpleAssignment = SyntaxInfo.SimpleAssignmentExpressionInfo(parent.Parent); ISymbol leftSymbol = semanticModel.GetSymbol(simpleAssignment.Left, cancellationToken); if (leftSymbol?.Kind != SymbolKind.Parameter) { return(null); } if (leftSymbol.ContainingSymbol?.Equals(DeclarationSymbol) != true) { return(null); } return((IParameterSymbol)leftSymbol); }
protected override IParameterSymbol GetParameterSymbolCore(SemanticModel semanticModel, CancellationToken cancellationToken) { SyntaxNode parent = Node.Parent; if (!parent.IsKind(SyntaxKind.CoalesceExpression)) { return(null); } SimpleAssignmentExpressionInfo simpleAssignment = SyntaxInfo.SimpleAssignmentExpressionInfo(parent.Parent); if (!simpleAssignment.Success) { return(null); } ISymbol leftSymbol = semanticModel.GetSymbol(simpleAssignment.Left, cancellationToken); if (leftSymbol?.Kind != SymbolKind.Parameter) { return(null); } if (!SymbolEqualityComparer.Default.Equals(leftSymbol.ContainingSymbol, DeclarationSymbol)) { return(null); } return((IParameterSymbol)leftSymbol); }
public static bool IsFixable(AssignmentExpressionSyntax assignmentExpression) { SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(assignmentExpression); if (!assignmentInfo.Success) { return(false); } if (assignmentExpression.IsParentKind(SyntaxKind.ObjectInitializerExpression)) { return(false); } if (!IsFixableBinaryExpression(assignmentInfo.Right.Kind())) { return(false); } BinaryExpressionInfo binaryInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)assignmentInfo.Right); if (!binaryInfo.Success) { return(false); } if (!CSharpFactory.AreEquivalent(assignmentInfo.Left, binaryInfo.Left)) { return(false); } return(true); }
private static void Analyze( SyntaxNodeAnalysisContext context, SyntaxList <StatementSyntax> statements, SingleLocalDeclarationStatementInfo localDeclarationInfo, int index, ExpressionStatementSyntax expressionStatement) { SimpleAssignmentExpressionInfo assignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expressionStatement.Expression); if (!assignment.Success) { return; } if (assignment.Right.Kind() != SyntaxKind.IdentifierName) { return; } var identifierName = (IdentifierNameSyntax)assignment.Right; string name = localDeclarationInfo.IdentifierText; if (!string.Equals(name, identifierName.Identifier.ValueText, StringComparison.Ordinal)) { return; } VariableDeclaratorSyntax declarator = localDeclarationInfo.Declarator; ISymbol localSymbol = context.SemanticModel.GetDeclaredSymbol(declarator, context.CancellationToken); if (localSymbol?.IsErrorType() != false) { return; } bool isReferenced = IsLocalVariableReferenced(localSymbol, name, assignment.Left, assignment.Left.Span, context.SemanticModel, context.CancellationToken); if (!isReferenced && index < statements.Count - 2) { TextSpan span = TextSpan.FromBounds(statements[index + 2].SpanStart, statements.Last().Span.End); isReferenced = IsLocalVariableReferenced(localSymbol, name, localDeclarationInfo.Statement.Parent, span, context.SemanticModel, context.CancellationToken); } if (isReferenced) { return; } if (expressionStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } ReportDiagnostic(context, localDeclarationInfo, assignment.Right); }
public static async Task ComputeRefactoringsAsync(RefactoringContext context, AssignmentExpressionSyntax assignmentExpression) { if (context.IsRefactoringEnabled(RefactoringIdentifiers.ExpandCompoundAssignmentOperator) && context.Span.IsEmptyAndContainedInSpanOrBetweenSpans(assignmentExpression.OperatorToken) && CSharpFacts.IsCompoundAssignmentExpression(assignmentExpression.Kind()) && SyntaxInfo.AssignmentExpressionInfo(assignmentExpression).Success) { context.RegisterRefactoring( $"Expand {assignmentExpression.OperatorToken}", ct => ExpandCompoundAssignmentOperatorRefactoring.RefactorAsync(context.Document, assignmentExpression, ct)); } if (context.IsAnyRefactoringEnabled(RefactoringIdentifiers.AddCastExpression, RefactoringIdentifiers.CallToMethod) && assignmentExpression.IsKind(SyntaxKind.SimpleAssignmentExpression)) { SimpleAssignmentExpressionInfo simpleAssignment = SyntaxInfo.SimpleAssignmentExpressionInfo(assignmentExpression); ExpressionSyntax right = simpleAssignment.Right; if (simpleAssignment.Success && right.Span.Contains(context.Span)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol leftSymbol = semanticModel.GetTypeSymbol(simpleAssignment.Left, context.CancellationToken); if (leftSymbol?.IsErrorType() == false) { ITypeSymbol rightSymbol = semanticModel.GetTypeSymbol(right, context.CancellationToken); if (rightSymbol?.IsErrorType() == false && !leftSymbol.Equals(rightSymbol)) { ModifyExpressionRefactoring.ComputeRefactoring(context, right, leftSymbol, semanticModel); } } } } if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceMethodGroupWithLambda) && context.SupportsSemanticModel) { await ReplaceMethodGroupWithLambdaRefactoring.ComputeRefactoringAsync(context, assignmentExpression).ConfigureAwait(false); } }
private static void AnalyzeCoalesceExpression(SyntaxNodeAnalysisContext context) { var coalesceExpression = (BinaryExpressionSyntax)context.Node; BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo(coalesceExpression, walkDownParentheses: false); if (!binaryExpressionInfo.Success) { return; } ExpressionSyntax right = binaryExpressionInfo.Right; if (!right.IsKind(SyntaxKind.ParenthesizedExpression)) { return; } var parenthesizedExpression = (ParenthesizedExpressionSyntax)right; ExpressionSyntax expression = parenthesizedExpression.Expression; if (!expression.IsKind(SyntaxKind.SimpleAssignmentExpression)) { return; } SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo((AssignmentExpressionSyntax)expression); if (!assignmentInfo.Success) { return; } if (!CSharpFactory.AreEquivalent(binaryExpressionInfo.Left, assignmentInfo.Left)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCompoundAssignment, coalesceExpression); DiagnosticHelpers.ReportToken(context, DiagnosticDescriptors.UseCompoundAssignmentFadeOut, parenthesizedExpression.OpenParenToken); DiagnosticHelpers.ReportNode(context, DiagnosticDescriptors.UseCompoundAssignmentFadeOut, assignmentInfo.Left); DiagnosticHelpers.ReportToken(context, DiagnosticDescriptors.UseCompoundAssignmentFadeOut, parenthesizedExpression.CloseParenToken); }
private static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context) { var assignmentExpression = (AssignmentExpressionSyntax)context.Node; SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(assignmentExpression); if (!assignmentInfo.Success) { return; } if (assignmentExpression.IsParentKind(SyntaxKind.ObjectInitializerExpression)) { return; } ExpressionSyntax right = assignmentInfo.Right; if (!CanBeReplacedWithCompoundAssignment(right.Kind())) { return; } BinaryExpressionInfo binaryInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)right); if (!binaryInfo.Success) { return; } if (!CSharpFactory.AreEquivalent(assignmentInfo.Left, binaryInfo.Left)) { return; } var binaryExpression = (BinaryExpressionSyntax)right; context.ReportDiagnostic(DiagnosticDescriptors.UseCompoundAssignment, assignmentExpression, GetCompoundAssignmentOperatorText(binaryExpression)); context.ReportNode(DiagnosticDescriptors.UseCompoundAssignmentFadeOut, binaryExpression.Left); }
private static async Task <bool> CanRefactorAsync( RefactoringContext context, PropertyDeclarationSyntax property, ExpressionSyntax expression) { SimpleAssignmentExpressionInfo simpleAssignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression); if (!simpleAssignment.Success) { return(false); } if (simpleAssignment.Left.Kind() != SyntaxKind.IdentifierName) { return(false); } if (simpleAssignment.Right.Kind() != SyntaxKind.IdentifierName) { return(false); } var identifierName = (IdentifierNameSyntax)simpleAssignment.Right; if (identifierName.Identifier.ValueText != "value") { return(false); } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); return(semanticModel .GetDeclaredSymbol(property, context.CancellationToken)? .ContainingType? .Implements(MetadataNames.System_ComponentModel_INotifyPropertyChanged, allInterfaces: true) == true); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindNode(root, context.Span, out ExpressionSyntax expression)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertTypeExplicitConversionExists: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TypeInfo typeInfo = semanticModel.GetTypeInfo(expression, context.CancellationToken); ITypeSymbol type = typeInfo.Type; ITypeSymbol convertedType = typeInfo.ConvertedType; if ((type is INamedTypeSymbol namedType) && namedType.IsNullableType()) { if (convertedType?.SpecialType == SpecialType.System_Boolean || AddComparisonWithBooleanLiteralRefactoring.IsCondition(expression)) { if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddComparisonWithBooleanLiteral)) { CodeAction codeAction = CodeAction.Create( AddComparisonWithBooleanLiteralRefactoring.GetTitle(expression), cancellationToken => AddComparisonWithBooleanLiteralRefactoring.RefactorAsync(context.Document, expression, cancellationToken), GetEquivalenceKey(diagnostic, CodeFixIdentifiers.AddComparisonWithBooleanLiteral)); context.RegisterCodeFix(codeAction, diagnostic); } } else if (SymbolEqualityComparer.Default.Equals(namedType.TypeArguments[0], convertedType)) { if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseCoalesceExpression)) { CodeAction codeAction = CodeAction.Create( "Use coalesce expression", cancellationToken => { ExpressionSyntax defaultValue = convertedType.GetDefaultValueSyntax(context.Document.GetDefaultSyntaxOptions()); ExpressionSyntax newNode = CoalesceExpression(expression.WithoutTrivia(), defaultValue) .WithTriviaFrom(expression) .Parenthesize() .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic, CodeFixIdentifiers.UseCoalesceExpression)); context.RegisterCodeFix(codeAction, diagnostic); } } } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression) && expression.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement)) { ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel); } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddCastExpression)) { CodeFixRegistrator.AddCastExpression(context, diagnostic, expression, convertedType, semanticModel); } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeTypeAccordingToInitializer)) { ChangeTypeAccordingToInitializerRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel); } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.CreateSingletonArray) && type?.IsErrorType() == false && !SymbolEqualityComparer.Default.Equals(type, convertedType) && (convertedType is IArrayTypeSymbol arrayType) && semanticModel.IsImplicitConversion(expression, arrayType.ElementType)) { CodeAction codeAction = CodeAction.Create( "Create singleton array", cancellationToken => CreateSingletonArrayRefactoring.RefactorAsync(context.Document, expression, arrayType.ElementType, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic, CodeFixIdentifiers.CreateSingletonArray)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case CompilerDiagnosticIdentifiers.ConstantValueCannotBeConverted: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseUncheckedExpression)) { break; } CodeAction codeAction = CodeAction.Create( "Use 'unchecked'", cancellationToken => { CheckedExpressionSyntax newNode = CSharpFactory.UncheckedExpression(expression.WithoutTrivia()); newNode = newNode.WithTriviaFrom(expression); return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.ExpressionBeingAssignedMustBeConstant: { SyntaxNode parent = expression.Parent; if (parent?.IsKind(SyntaxKind.EqualsValueClause) != true) { break; } parent = parent.Parent; if (parent?.IsKind(SyntaxKind.VariableDeclarator) != true) { break; } parent = parent.Parent; if (!(parent is VariableDeclarationSyntax variableDeclaration)) { break; } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConstModifier) && variableDeclaration.Parent is LocalDeclarationStatementSyntax localDeclarationStatement) { SyntaxTokenList modifiers = localDeclarationStatement.Modifiers; if (!modifiers.Contains(SyntaxKind.ConstKeyword)) { break; } ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, localDeclarationStatement, SyntaxKind.ConstKeyword); } else if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceConstantWithField) && variableDeclaration.Variables.Count == 1 && (variableDeclaration.Parent is FieldDeclarationSyntax fieldDeclaration) && fieldDeclaration.Modifiers.Contains(SyntaxKind.ConstKeyword)) { CodeAction codeAction = CodeAction.Create( ReplaceConstantWithFieldRefactoring.Title, cancellationToken => ReplaceConstantWithFieldRefactoring.RefactorAsync(context.Document, fieldDeclaration, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } break; } case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeBecauseItIsNonNullableValueType: case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeParameterBecauseItCouldBeNonNullableValueType: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, expression, semanticModel); break; } case CompilerDiagnosticIdentifiers.ResultOfExpressionIsAlwaysConstantSinceValueIsNeverEqualToNull: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse)) { break; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(expression, allowedStyles: NullCheckStyles.ComparisonToNull); if (!nullCheck.Success) { break; } CodeAction codeAction = CodeAction.Create( "Remove condition", cancellationToken => { cancellationToken.ThrowIfCancellationRequested(); SyntaxNode newRoot = RemoveCondition(root, expression, nullCheck.Style == NullCheckStyles.NotEqualsToNull); cancellationToken.ThrowIfCancellationRequested(); return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot))); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.OnlyAssignmentCallIncrementDecrementAndNewObjectExpressionsCanBeUsedAsStatement: { if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveParentheses) && expression is ParenthesizedExpressionSyntax parenthesizedExpression && parenthesizedExpression?.IsMissing == false) { CodeAction codeAction = CodeActionFactory.RemoveParentheses(context.Document, parenthesizedExpression, equivalenceKey: GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (expression.Parent is ArrowExpressionClauseSyntax arrowExpresssionClause) { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression)) { break; } ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel); } else if (expression.Parent is ExpressionStatementSyntax expressionStatement) { if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddArgumentList) && expression.IsKind( SyntaxKind.IdentifierName, SyntaxKind.SimpleMemberAccessExpression)) { SyntaxNode invocationExpression = InvocationExpression(expression); if (semanticModel.GetSpeculativeMethodSymbol(expression.SpanStart, invocationExpression) != null) { CodeAction codeAction = CodeAction.Create( "Add argument list", cancellationToken => context.Document.ReplaceNodeAsync(expression, invocationExpression, cancellationToken), GetEquivalenceKey(diagnostic, CodeFixIdentifiers.AddArgumentList)); context.RegisterCodeFix(codeAction, diagnostic); } } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceComparisonWithAssignment) && expression.IsKind(SyntaxKind.EqualsExpression)) { BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(expression); if (!info.Success) { break; } ITypeSymbol leftTypeSymbol = semanticModel.GetTypeSymbol(info.Left, context.CancellationToken); if (leftTypeSymbol?.IsErrorType() != false) { break; } if (!semanticModel.IsImplicitConversion(info.Right, leftTypeSymbol)) { break; } CodeAction codeAction = CodeAction.Create( "Replace comparison with assignment", cancellationToken => { AssignmentExpressionSyntax simpleAssignment = SimpleAssignmentExpression(info.Left, info.Right).WithTriviaFrom(expression); return(context.Document.ReplaceNodeAsync(expression, simpleAssignment, cancellationToken)); }, GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceComparisonWithAssignment)); context.RegisterCodeFix(codeAction, diagnostic); } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceConditionalExpressionWithIfElse) && (expression is ConditionalExpressionSyntax conditionalExpression) && conditionalExpression.Condition != null) { ExpressionSyntax whenTrue = conditionalExpression.WhenTrue; ExpressionSyntax whenFalse = conditionalExpression.WhenFalse; if (whenTrue != null && whenFalse != null && semanticModel.GetTypeSymbol(whenTrue, context.CancellationToken)?.SpecialType == SpecialType.System_Void && semanticModel.GetTypeSymbol(whenFalse, context.CancellationToken)?.SpecialType == SpecialType.System_Void) { CodeAction codeAction = CodeAction.Create( "Replace ?: with if-else", cancellationToken => { IfStatementSyntax newNode = IfStatement( conditionalExpression.Condition.WalkDownParentheses(), Block(ExpressionStatement(whenTrue)), ElseClause(Block(ExpressionStatement(whenFalse)))); newNode = newNode .WithTriviaFrom(expressionStatement) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(expressionStatement, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceConditionalExpressionWithIfElse)); context.RegisterCodeFix(codeAction, diagnostic); } } if (semanticModel.GetSymbol(expression, context.CancellationToken)?.IsErrorType() != false) { break; } ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken); if (typeSymbol?.IsErrorType() != false) { break; } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.IntroduceLocalVariable) && !expressionStatement.IsEmbedded()) { bool addAwait = typeSymbol.OriginalDefinition.EqualsOrInheritsFromTaskOfT() && semanticModel.GetEnclosingSymbol(expressionStatement.SpanStart, context.CancellationToken).IsAsyncMethod(); CodeAction codeAction = CodeAction.Create( IntroduceLocalVariableRefactoring.GetTitle(expression), cancellationToken => IntroduceLocalVariableRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, addAwait, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic, CodeFixIdentifiers.IntroduceLocalVariable)); context.RegisterCodeFix(codeAction, diagnostic); } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.IntroduceField)) { CodeAction codeAction = CodeAction.Create( $"Introduce field for '{expression}'", cancellationToken => IntroduceFieldRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic, CodeFixIdentifiers.IntroduceField)); context.RegisterCodeFix(codeAction, diagnostic); } } break; } case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertType: { if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceYieldReturnWithForEach) && expression.IsParentKind(SyntaxKind.YieldReturnStatement)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ReplaceYieldReturnWithForEachRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel); break; } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression) && expression.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement, SyntaxKind.ArrowExpressionClause)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel); break; } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeTypeAccordingToInitializer)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); CodeFixRegistrationResult result = ChangeTypeAccordingToInitializerRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel); if (!result.Success) { RemoveAssignmentOfVoidExpression(context, diagnostic, expression, semanticModel); } break; } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral) && expression?.Kind() == SyntaxKind.StringLiteralExpression) { var literalExpression = (LiteralExpressionSyntax)expression; if (literalExpression.Token.ValueText.Length == 1) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (semanticModel.GetTypeInfo(expression, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Char) { CodeAction codeAction = CodeAction.Create( "Replace string literal with character literal", cancellationToken => ReplaceStringLiteralWithCharacterLiteralRefactoring.RefactorAsync(context.Document, literalExpression, cancellationToken), GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral)); context.RegisterCodeFix(codeAction, diagnostic); } } } if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseYieldReturnInsteadOfReturn) && expression.IsParentKind(SyntaxKind.ReturnStatement)) { var returnStatement = (ReturnStatementSyntax)expression.Parent; SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol containingSymbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken); if (containingSymbol?.Kind == SymbolKind.Method && ((IMethodSymbol)containingSymbol).ReturnType.OriginalDefinition.IsIEnumerableOrIEnumerableOfT()) { CodeAction codeAction = CodeAction.Create( "Use yield return instead of return", cancellationToken => UseYieldReturnInsteadOfReturnRefactoring.RefactorAsync(context.Document, returnStatement, SyntaxKind.YieldReturnStatement, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic, CodeFixIdentifiers.UseYieldReturnInsteadOfReturn)); context.RegisterCodeFix(codeAction, diagnostic); } } break; } case CompilerDiagnosticIdentifiers.LeftHandSideOfAssignmentMustBeVariablePropertyOrIndexer: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConstModifier)) { return; } if (!expression.IsKind(SyntaxKind.IdentifierName)) { return; } if (!expression.IsParentKind(SyntaxKind.SimpleAssignmentExpression)) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(expression, context.CancellationToken); if (symbolInfo.CandidateReason != CandidateReason.NotAVariable) { return; } if (!(symbolInfo.CandidateSymbols.SingleOrDefault(shouldThrow: false) is ILocalSymbol localSymbol)) { return; } if (!localSymbol.IsConst) { return; } SyntaxNode node = localSymbol.GetSyntaxOrDefault(context.CancellationToken); if (!node.IsKind(SyntaxKind.VariableDeclarator)) { return; } node = node.Parent; if (!node.IsKind(SyntaxKind.VariableDeclaration)) { return; } node = node.Parent; if (!(node is LocalDeclarationStatementSyntax localDeclaration)) { return; } SyntaxToken constModifier = localDeclaration.Modifiers.Find(SyntaxKind.ConstKeyword); if (!constModifier.IsKind(SyntaxKind.ConstKeyword)) { return; } ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, localDeclaration, constModifier); break; } case CompilerDiagnosticIdentifiers.ReadOnlyFieldCannotBeAssignedTo: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeFieldWritable)) { break; } SimpleAssignmentExpressionInfo simpleAssignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression.Parent); if (!simpleAssignment.Success) { return; } if (simpleAssignment.Left != expression) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(expression, context.CancellationToken); if (symbolInfo.CandidateReason != CandidateReason.NotAVariable) { return; } if (!(symbolInfo.CandidateSymbols.SingleOrDefault(shouldThrow: false) is IFieldSymbol fieldSymbol)) { return; } if (fieldSymbol.DeclaredAccessibility != Accessibility.Private) { return; } if (!(fieldSymbol.GetSyntax().Parent.Parent is FieldDeclarationSyntax fieldDeclaration)) { return; } TypeDeclarationSyntax containingTypeDeclaration = fieldDeclaration.FirstAncestor <TypeDeclarationSyntax>(); if (!expression.Ancestors().Any(f => f == containingTypeDeclaration)) { return; } ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, title: $"Make '{fieldSymbol.Name}' writable"); break; } } } }
public static async Task ComputeRefactoringAsync( RefactoringContext context, PropertyDeclarationSyntax property) { AccessorDeclarationSyntax setter = property.Setter(); if (setter == null) { return; } ExpressionSyntax expression = GetExpression(); if (expression == null) { return; } SimpleAssignmentExpressionInfo simpleAssignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression); if (!simpleAssignment.Success) { return; } if (!simpleAssignment.Left.IsKind(SyntaxKind.IdentifierName)) { return; } if (!(simpleAssignment.Right is IdentifierNameSyntax identifierName)) { return; } if (identifierName.Identifier.ValueText != "value") { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); INamedTypeSymbol containingType = semanticModel .GetDeclaredSymbol(property, context.CancellationToken)? .ContainingType; if (containingType == null) { return; } if (!containingType.Implements(MetadataNames.System_ComponentModel_INotifyPropertyChanged, allInterfaces: true)) { return; } IMethodSymbol methodSymbol = SymbolUtility.FindMethodThatRaisePropertyChanged(containingType, expression.SpanStart, semanticModel); if (methodSymbol == null) { return; } Document document = context.Document; context.RegisterRefactoring( "Notify when property change", ct => RefactorAsync(document, property, methodSymbol.Name, ct), RefactoringIdentifiers.NotifyWhenPropertyChange); ExpressionSyntax GetExpression() { BlockSyntax body = setter.Body; if (body != null) { if (body.Statements.SingleOrDefault(shouldThrow: false) is ExpressionStatementSyntax expressionStatement) { return(expressionStatement.Expression); } } else { return(setter.ExpressionBody?.Expression); } return(null); } }
internal static bool IsFixable( IndexerDeclarationSyntax indexerDeclaration, AccessorDeclarationSyntax accessor, SemanticModel semanticModel, CancellationToken cancellationToken) { switch (accessor.Kind()) { case SyntaxKind.GetAccessorDeclaration: { ExpressionSyntax expression = GetGetAccessorExpression(accessor); if (expression?.IsKind(SyntaxKind.ElementAccessExpression) != true) { return(false); } var elementAccess = (ElementAccessExpressionSyntax)expression; if (elementAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true) { return(false); } if (elementAccess.ArgumentList == null) { return(false); } IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(indexerDeclaration, cancellationToken); if (propertySymbol == null) { return(false); } IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty; if (overriddenProperty == null) { return(false); } ISymbol symbol = semanticModel.GetSymbol(elementAccess, cancellationToken); return(overriddenProperty.Equals(symbol) && CheckParameters(indexerDeclaration.ParameterList, elementAccess.ArgumentList, semanticModel, cancellationToken) && CheckDefaultValues(propertySymbol.Parameters, overriddenProperty.Parameters)); } case SyntaxKind.SetAccessorDeclaration: { ExpressionSyntax expression = GetSetAccessorExpression(accessor); SimpleAssignmentExpressionInfo assignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression); if (!assignment.Success) { return(false); } if (assignment.Left.Kind() != SyntaxKind.ElementAccessExpression) { return(false); } var elementAccess = (ElementAccessExpressionSyntax)assignment.Left; if (elementAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true) { return(false); } if (elementAccess.ArgumentList == null) { return(false); } if (assignment.Right.Kind() != SyntaxKind.IdentifierName) { return(false); } var identifierName = (IdentifierNameSyntax)assignment.Right; if (identifierName.Identifier.ValueText != "value") { return(false); } IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(indexerDeclaration, cancellationToken); if (propertySymbol == null) { return(false); } IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty; if (overriddenProperty == null) { return(false); } ISymbol symbol = semanticModel.GetSymbol(elementAccess, cancellationToken); return(overriddenProperty.Equals(symbol) && CheckParameters(indexerDeclaration.ParameterList, elementAccess.ArgumentList, semanticModel, cancellationToken) && CheckDefaultValues(propertySymbol.Parameters, overriddenProperty.Parameters)); } case SyntaxKind.UnknownAccessorDeclaration: { return(false); } default: { Debug.Fail(accessor.Kind().ToString()); return(false); } } }
internal static bool IsFixable( PropertyDeclarationSyntax propertyDeclaration, AccessorDeclarationSyntax accessor, SemanticModel semanticModel, CancellationToken cancellationToken) { switch (accessor.Kind()) { case SyntaxKind.GetAccessorDeclaration: { ExpressionSyntax expression = GetGetAccessorExpression(accessor); if (expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) != true) { return(false); } var memberAccess = (MemberAccessExpressionSyntax)expression; if (memberAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true) { return(false); } SimpleNameSyntax simpleName = memberAccess.Name; IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken); if (propertySymbol == null) { return(false); } IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty; if (overriddenProperty == null) { return(false); } ISymbol symbol = semanticModel.GetSymbol(simpleName, cancellationToken); return(overriddenProperty.Equals(symbol)); } case SyntaxKind.SetAccessorDeclaration: { ExpressionSyntax expression = GetSetAccessorExpression(accessor); SimpleAssignmentExpressionInfo assignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression); if (!assignment.Success) { return(false); } if (assignment.Left.Kind() != SyntaxKind.SimpleMemberAccessExpression) { return(false); } var memberAccess = (MemberAccessExpressionSyntax)assignment.Left; if (memberAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true) { return(false); } if (assignment.Right.Kind() != SyntaxKind.IdentifierName) { return(false); } var identifierName = (IdentifierNameSyntax)assignment.Right; if (identifierName.Identifier.ValueText != "value") { return(false); } SimpleNameSyntax simpleName = memberAccess.Name; if (simpleName == null) { return(false); } IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken); if (propertySymbol == null) { return(false); } IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty; if (overriddenProperty == null) { return(false); } ISymbol symbol = semanticModel.GetSymbol(simpleName, cancellationToken); return(overriddenProperty.Equals(symbol)); } case SyntaxKind.UnknownAccessorDeclaration: { return(false); } default: { Debug.Fail(accessor.Kind().ToString()); return(false); } } }
private static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context) { var assignmentExpression = (AssignmentExpressionSyntax)context.Node; SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(assignmentExpression); if (!assignmentInfo.Success) { return; } if (assignmentExpression.IsParentKind(SyntaxKind.ObjectInitializerExpression)) { return; } ExpressionSyntax right = assignmentInfo.Right; if (!CanBeReplacedWithCompoundAssignment(right.Kind())) { return; } BinaryExpressionInfo binaryInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)right); if (!binaryInfo.Success) { return; } if (!CSharpFactory.AreEquivalent(assignmentInfo.Left, binaryInfo.Left)) { return; } var binaryExpression = (BinaryExpressionSyntax)right; DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCompoundAssignment, assignmentExpression, GetCompoundAssignmentOperatorText(binaryExpression)); DiagnosticHelpers.ReportNode(context, DiagnosticDescriptors.UseCompoundAssignmentFadeOut, binaryExpression.Left); bool CanBeReplacedWithCompoundAssignment(SyntaxKind kind) { switch (kind) { case SyntaxKind.AddExpression: case SyntaxKind.SubtractExpression: case SyntaxKind.MultiplyExpression: case SyntaxKind.DivideExpression: case SyntaxKind.ModuloExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: return(true); case SyntaxKind.CoalesceExpression: return(((CSharpCompilation)context.Compilation).LanguageVersion >= LanguageVersion.CSharp8); default: return(false); } } }
public static void ComputeRefactorings( RefactoringContext context, InitializerExpressionSyntax initializer, SemanticModel semanticModel) { Debug.Assert(initializer.IsKind(SyntaxKind.ObjectInitializerExpression, SyntaxKind.WithInitializerExpression), initializer.Kind().ToString()); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(initializer.Parent, context.CancellationToken); if (typeSymbol?.IsErrorType() != false) { return; } if (typeSymbol.IsAnonymousType) { return; } int position = initializer.OpenBraceToken.Span.End; ImmutableArray <ISymbol> symbols = semanticModel.LookupSymbols(position, typeSymbol); if (!symbols.Any()) { return; } SeparatedSyntaxList <ExpressionSyntax> expressions = initializer.Expressions; if (expressions.Any()) { var initializedPropertyNames = new HashSet <string>(); foreach (ExpressionSyntax expression in expressions) { Debug.Assert(expression.IsKind(SyntaxKind.SimpleAssignmentExpression), expression.Kind().ToString()); if (expression.IsKind(SyntaxKind.SimpleAssignmentExpression)) { SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo((AssignmentExpressionSyntax)expression); if (assignmentInfo.Success) { ExpressionSyntax left = assignmentInfo.Left; Debug.Assert(left.IsKind(SyntaxKind.IdentifierName), left.Kind().ToString()); if (left is IdentifierNameSyntax identifierName) { initializedPropertyNames.Add(identifierName.Identifier.ValueText); } } } } Dictionary <string, IPropertySymbol> namesToProperties = null; foreach (ISymbol symbol in symbols) { if (initializedPropertyNames.Contains(symbol.Name)) { continue; } IPropertySymbol propertySymbol = GetInitializableProperty(symbol, position, semanticModel); if (propertySymbol == null) { continue; } if (namesToProperties != null) { if (namesToProperties.ContainsKey(propertySymbol.Name)) { continue; } } else { namesToProperties = new Dictionary <string, IPropertySymbol>(); } namesToProperties.Add(propertySymbol.Name, propertySymbol); } if (namesToProperties != null) { Document document = context.Document; context.RegisterRefactoring( "Initialize all properties", ct => { IEnumerable <IPropertySymbol> propertySymbols = namesToProperties.Select(f => f.Value); return(RefactorAsync(document, initializer, propertySymbols, initializeToDefault: false, ct)); }, RefactoringDescriptors.AddAllPropertiesToInitializer); } } else if (HasAccessiblePropertySetter()) { Document document = context.Document; context.RegisterRefactoring( "Initialize all properties", ct => { IEnumerable <IPropertySymbol> propertySymbols = GetInitializableProperties(initializer, symbols, semanticModel); return(RefactorAsync(document, initializer, propertySymbols, initializeToDefault: false, ct)); }, RefactoringDescriptors.AddAllPropertiesToInitializer); } bool HasAccessiblePropertySetter() { foreach (ISymbol symbol in symbols) { if (GetInitializableProperty(symbol, position, semanticModel) != null) { return(true); } } return(false); } }
protected override bool IsFixableStatement( StatementSyntax statement, string name, ITypeSymbol typeSymbol, SemanticModel semanticModel, CancellationToken cancellationToken) { if (statement.SpanOrLeadingTriviaContainsDirectives()) { return(false); } if (!(statement is ExpressionStatementSyntax expressionStatement)) { return(false); } SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(expressionStatement.Expression); if (!assignmentInfo.Success) { return(false); } if (name != (assignmentInfo.Left as IdentifierNameSyntax)?.Identifier.ValueText) { return(false); } MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(assignmentInfo.Right); if (!invocationInfo.Success) { return(false); } if (!(WalkDownMethodChain(invocationInfo).Expression is IdentifierNameSyntax identifierName)) { return(false); } if (name != identifierName.Identifier.ValueText) { return(false); } if (!semanticModel.TryGetMethodInfo(invocationInfo.InvocationExpression, out MethodInfo methodInfo, cancellationToken)) { return(false); } if (!methodInfo.ReturnType.Equals(typeSymbol)) { return(false); } if (IsReferenced(invocationInfo.InvocationExpression, identifierName, name, semanticModel, cancellationToken)) { return(false); } return(true); }
public override bool IsFixableStatement( StatementSyntax statement, string name, ITypeSymbol typeSymbol, SemanticModel semanticModel, CancellationToken cancellationToken) { if (statement.SpanOrLeadingTriviaContainsDirectives()) { return(false); } if (statement is not ExpressionStatementSyntax expressionStatement) { return(false); } SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(expressionStatement.Expression); if (!assignmentInfo.Success) { return(false); } if (name != (assignmentInfo.Left as IdentifierNameSyntax)?.Identifier.ValueText) { return(false); } SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(assignmentInfo.Right); if (!invocationInfo.Success) { return(false); } if (WalkDownMethodChain(invocationInfo).Expression is not IdentifierNameSyntax identifierName) { return(false); } if (name != identifierName.Identifier.ValueText) { return(false); } IMethodSymbol methodSymbol = semanticModel.GetMethodSymbol(invocationInfo.InvocationExpression, cancellationToken); if (methodSymbol == null) { return(false); } if (!SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, typeSymbol)) { return(false); } if (IsReferenced(invocationInfo.InvocationExpression, identifierName, name, semanticModel, cancellationToken)) { return(false); } return(true); }