private static IfRefactoring CreateIfToReturnWithCoalesceExpression( IfStatementSyntax ifStatement, ExpressionSyntax expression1, ExpressionSyntax expression2, NullCheckExpression nullCheck, bool isYield, SemanticModel semanticModel, CancellationToken cancellationToken) { if (nullCheck.Kind == NullCheckKind.EqualsToNull || nullCheck.Kind == NullCheckKind.NotEqualsToNull) { if (SyntaxComparer.AreEquivalent(nullCheck.Expression, expression1, requireNotNull: true)) { return(IfToReturnWithCoalesceExpression.Create(ifStatement, expression1, expression2, isYield)); } } if (expression1.IsKind(SyntaxKind.SimpleMemberAccessExpression) && SyntaxUtility.IsPropertyOfNullableOfT(expression1, "Value", semanticModel, cancellationToken)) { expression1 = ((MemberAccessExpressionSyntax)expression1).Expression; if (SyntaxComparer.AreEquivalent(nullCheck.Expression, expression1, requireNotNull: true)) { return(IfToReturnWithCoalesceExpression.Create(ifStatement, expression1, expression2, isYield)); } } return(null); }
private static IfRefactoring CreateIfToAssignmentWithWithCoalesceExpression( IfStatementSyntax ifStatement, ExpressionSyntax left, ExpressionSyntax expression1, ExpressionSyntax expression2, NullCheckExpression nullCheck, SemanticModel semanticModel, CancellationToken cancellationToken) { if (nullCheck.Kind == NullCheckKind.EqualsToNull || nullCheck.Kind == NullCheckKind.NotEqualsToNull) { if (IsEquivalent(nullCheck.Expression, expression1)) { return(new IfElseToAssignmentWithCoalesceExpression(ifStatement, left, expression1, expression2)); } } if (expression1.IsKind(SyntaxKind.SimpleMemberAccessExpression) && SemanticUtilities.IsPropertyOfNullableOfT(expression1, "Value", semanticModel, cancellationToken)) { expression1 = ((MemberAccessExpressionSyntax)expression1).Expression; if (IsEquivalent(nullCheck.Expression, expression1)) { return(new IfElseToAssignmentWithCoalesceExpression(ifStatement, left, expression1, expression2)); } } return(null); }
public bool VisitNullCheckExpression(NullCheckExpression expression) { VisitNode(expression.Expression); VisitExpression(expression); return(true); }
private static ImmutableArray <IfRefactoring> Analyze( IfStatementSyntax ifStatement, ExpressionSyntax condition, ExpressionSyntax expression1, ExpressionSyntax expression2, SemanticModel semanticModel, CancellationToken cancellationToken, IfAnalysisOptions options, bool isYield) { if (expression1?.IsMissing == false && expression2?.IsMissing == false) { if (options.UseCoalesceExpression) { NullCheckExpression nullCheck; if (NullCheckExpression.TryCreate(condition, semanticModel, out nullCheck, cancellationToken)) { IfRefactoring refactoring = CreateIfToReturnWithCoalesceExpression( ifStatement, (nullCheck.IsCheckingNull) ? expression2 : expression1, (nullCheck.IsCheckingNull) ? expression1 : expression2, nullCheck, isYield, semanticModel, cancellationToken); if (refactoring != null) { return(refactoring.ToImmutableArray()); } } } IfToReturnWithBooleanExpression ifToReturnWithBooleanExpression = null; if (options.UseBooleanExpression && (expression1.IsBooleanLiteralExpression() || expression2.IsBooleanLiteralExpression()) && semanticModel.GetTypeSymbol(expression1, cancellationToken)?.IsBoolean() == true && semanticModel.GetTypeSymbol(expression2, cancellationToken)?.IsBoolean() == true) { ifToReturnWithBooleanExpression = IfToReturnWithBooleanExpression.Create(ifStatement, expression1, expression2, isYield); } IfToReturnWithConditionalExpression ifToReturnWithConditionalExpression = null; if (options.UseConditionalExpression && (!expression1.IsBooleanLiteralExpression() || !expression2.IsBooleanLiteralExpression())) { ifToReturnWithConditionalExpression = IfToReturnWithConditionalExpression.Create(ifStatement, expression1, expression2, isYield); } return(ToImmutableArray(ifToReturnWithBooleanExpression, ifToReturnWithConditionalExpression)); } return(ImmutableArray <IfRefactoring> .Empty); }
public static async Task <Document> RefactorAsync( Document document, ConditionalExpressionSyntax conditionalExpressionSyntax, CancellationToken cancellationToken) { ConditionalExpressionInfo conditionalExpression; if (ConditionalExpressionInfo.TryCreate(conditionalExpressionSyntax, out conditionalExpression)) { SemanticModel semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false); NullCheckExpression nullCheck; if (NullCheckExpression.TryCreate(conditionalExpression.Condition, semanticModel, out nullCheck, cancellationToken)) { ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpression.WhenTrue : conditionalExpression.WhenFalse; ExpressionSyntax whenNull = (nullCheck.IsCheckingNull) ? conditionalExpression.WhenTrue : conditionalExpression.WhenFalse; ExpressionSyntax expression = FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull); ExpressionSyntax newNode; if (expression.Parent == whenNotNull && whenNotNull.IsKind(SyntaxKind.SimpleMemberAccessExpression) && SemanticUtilities.IsPropertyOfNullableOfT(whenNotNull, "Value", semanticModel, cancellationToken)) { newNode = expression; } else { newNode = SyntaxFactory.ParseExpression(whenNotNull.ToString().Insert(expression.Span.End - whenNotNull.SpanStart, "?")); } if (!semanticModel.GetTypeSymbol(whenNotNull, cancellationToken).IsReferenceType) { newNode = CSharpFactory.CoalesceExpression(newNode.Parenthesize(), whenNull.Parenthesize()); } newNode = newNode .WithTriviaFrom(conditionalExpressionSyntax) .Parenthesize(); return(await document.ReplaceNodeAsync(conditionalExpressionSyntax, newNode, cancellationToken).ConfigureAwait(false)); } } Debug.Fail(conditionalExpressionSyntax.ToString()); return(document); }
public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType) { if (context.Node.SpanContainsDirectives()) { return; } ConditionalExpressionInfo conditionalExpression; if (ConditionalExpressionInfo.TryCreate((ConditionalExpressionSyntax)context.Node, out conditionalExpression)) { SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; NullCheckExpression nullCheck; if (NullCheckExpression.TryCreate(conditionalExpression.Condition, semanticModel, out nullCheck, cancellationToken)) { ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpression.WhenTrue : conditionalExpression.WhenFalse; if (whenNotNull.IsKind( SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression, SyntaxKind.ConditionalAccessExpression, SyntaxKind.InvocationExpression) && semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken)?.IsReferenceTypeOrNullableType() == true && !ContainsOutArgumentWithLocal(whenNotNull, semanticModel, cancellationToken)) { ExpressionSyntax expression = FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull); if (expression != null) { ExpressionSyntax whenNull = (nullCheck.IsCheckingNull) ? conditionalExpression.WhenTrue : conditionalExpression.WhenFalse; ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(whenNotNull, cancellationToken); if (semanticModel.IsDefaultValue(typeSymbol, whenNull, cancellationToken) && !conditionalExpression.Node.IsInExpressionTree(expressionType, semanticModel, cancellationToken)) { context.ReportDiagnostic( DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression, conditionalExpression.Node); } } } } } }
private static ImmutableArray <IfRefactoring> Analyze( IfStatementSyntax ifStatement, ExpressionSyntax condition, ExpressionStatementSyntax expressionStatement1, ExpressionStatementSyntax expressionStatement2, SemanticModel semanticModel, CancellationToken cancellationToken, IfAnalysisOptions options) { ExpressionSyntax expression1 = expressionStatement1.Expression; if (IsSimpleAssignment(expression1)) { ExpressionSyntax expression2 = expressionStatement2.Expression; if (IsSimpleAssignment(expression2)) { var assignment1 = (AssignmentExpressionSyntax)expression1; var assignment2 = (AssignmentExpressionSyntax)expression2; ExpressionSyntax left1 = assignment1.Left; ExpressionSyntax right1 = assignment1.Right; if (left1?.IsMissing == false && right1?.IsMissing == false) { ExpressionSyntax left2 = assignment2.Left; ExpressionSyntax right2 = assignment2.Right; if (left2?.IsMissing == false && right2?.IsMissing == false && IsEquivalent(left1, left2)) { if (options.UseCoalesceExpression) { NullCheckExpression nullCheck; if (NullCheckExpression.TryCreate(condition, semanticModel, out nullCheck, cancellationToken)) { IfRefactoring refactoring = CreateIfToAssignmentWithWithCoalesceExpression( ifStatement, left1, (nullCheck.IsCheckingNull) ? right2 : right1, (nullCheck.IsCheckingNull) ? right1 : right2, nullCheck, semanticModel, cancellationToken); if (refactoring != null) { return(refactoring.ToImmutableArray()); } } } if (options.UseConditionalExpression) { return(new IfElseToAssignmentWithConditionalExpression(ifStatement, left1, right1, right2).ToImmutableArray()); } } } } } return(ImmutableArray <IfRefactoring> .Empty); }
public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context) { if (context.Node.SpanContainsDirectives()) { return; } var conditionalExpression = (ConditionalExpressionSyntax)context.Node; if (!ConditionalExpressionInfo.TryCreate(conditionalExpression, out ConditionalExpressionInfo conditionalExpressionInfo)) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; if (!NullCheckExpression.TryCreate(conditionalExpressionInfo.Condition, semanticModel, out NullCheckExpression nullCheck, cancellationToken)) { return; } ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenTrue : conditionalExpressionInfo.WhenFalse; ExpressionSyntax whenNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenFalse : conditionalExpressionInfo.WhenTrue; if (SyntaxComparer.AreEquivalent(nullCheck.Expression, whenNotNull)) { if (semanticModel .GetTypeSymbol(nullCheck.Expression, cancellationToken)? .IsReferenceTypeOrNullableType() == true) { context.ReportDiagnostic( DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression, conditionalExpression); } } else if (whenNotNull.IsKind( SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression, SyntaxKind.ConditionalAccessExpression, SyntaxKind.InvocationExpression)) { ExpressionSyntax expression = UseConditionalAccessRefactoring.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull); if (expression == null) { return; } ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken); if (typeSymbol == null) { return; } if (typeSymbol.IsReferenceType) { Analyze(context, conditionalExpressionInfo, whenNull, whenNotNull, semanticModel, cancellationToken); } else if (typeSymbol.IsConstructedFrom(SpecialType.System_Nullable_T)) { if (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccessExpression = (MemberAccessExpressionSyntax)expression.Parent; if (!memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression) && (memberAccessExpression.Name as IdentifierNameSyntax)?.Identifier.ValueText == "Value") { if (memberAccessExpression == whenNotNull) { context.ReportDiagnostic( DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression, conditionalExpression); } else { Analyze(context, conditionalExpressionInfo, whenNull, whenNotNull, semanticModel, cancellationToken); } } } } } }
public static async Task <Document> RefactorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false); ConditionalExpressionInfo.TryCreate(conditionalExpression, out ConditionalExpressionInfo conditionalExpressionInfo); NullCheckExpression.TryCreate(conditionalExpressionInfo.Condition, semanticModel, out NullCheckExpression nullCheck, cancellationToken); ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenTrue : conditionalExpressionInfo.WhenFalse; ExpressionSyntax whenNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenFalse : conditionalExpressionInfo.WhenTrue; ExpressionSyntax expression = UseConditionalAccessRefactoring.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull); bool coalesce = false; ExpressionSyntax newNode = null; if (SyntaxComparer.AreEquivalent(nullCheck.Expression, whenNotNull)) { newNode = nullCheck.Expression; coalesce = true; } else if (semanticModel .GetTypeSymbol(nullCheck.Expression, cancellationToken) .IsConstructedFrom(SpecialType.System_Nullable_T)) { if (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccessExpression = (MemberAccessExpressionSyntax)expression.Parent; if (!memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression) && (memberAccessExpression.Name as IdentifierNameSyntax)?.Identifier.ValueText == "Value") { if (memberAccessExpression == whenNotNull) { newNode = nullCheck.Expression; coalesce = true; } else { newNode = ParseExpression($"{expression}?{whenNotNull.ToString().Substring(memberAccessExpression.Span.End - whenNotNull.SpanStart)}"); } } } } if (newNode == null) { newNode = ParseExpression(whenNotNull.ToString().Insert(expression.Span.End - whenNotNull.SpanStart, "?")); } if (coalesce || !semanticModel.GetTypeSymbol(whenNotNull, cancellationToken).IsReferenceType) { newNode = CoalesceExpression(newNode.Parenthesize(), whenNull.Parenthesize()); } newNode = newNode .WithTriviaFrom(conditionalExpression) .Parenthesize(); return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false)); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddComparisonWithBooleanLiteral) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseUncheckedExpression) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseCoalesceExpression) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse)) { return; } 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?.IsNamedType() == true) { var namedType = (INamedTypeSymbol)type; if (namedType.ConstructedFrom.SpecialType == SpecialType.System_Nullable_T) { if (convertedType?.IsBoolean() == true || AddComparisonWithBooleanLiteralRefactoring.IsCondition(expression)) { if (Settings.IsCodeFixEnabled(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 (namedType.TypeArguments[0].Equals(convertedType)) { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseCoalesceExpression)) { CodeAction codeAction = CodeAction.Create( "Use coalesce expression", cancellationToken => { ExpressionSyntax defaultValue = convertedType.ToDefaultValueSyntax(semanticModel, expression.SpanStart); 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.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) && type?.IsErrorType() == false && !type.Equals(convertedType) && convertedType.IsArrayType()) { var arrayType = (IArrayTypeSymbol)convertedType; if (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.IsCodeFixEnabled(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: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier)) { break; } LocalDeclarationStatementSyntax localDeclarationStatement = GetLocalDeclarationStatement(expression); if (localDeclarationStatement == null) { break; } SyntaxTokenList modifiers = localDeclarationStatement.Modifiers; if (!modifiers.Contains(SyntaxKind.ConstKeyword)) { break; } ModifiersCodeFixes.RemoveModifier(context, diagnostic, localDeclarationStatement, SyntaxKind.ConstKeyword); break; } case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeBecauseItIsNonNullableValueType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeInfo(expression, context.CancellationToken).ConvertedType; if (typeSymbol?.SupportsExplicitDeclaration() == true) { CodeAction codeAction = CodeAction.Create( "Replace 'null' with default value", cancellationToken => { ExpressionSyntax newNode = typeSymbol.ToDefaultValueSyntax(semanticModel, expression.SpanStart); return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case CompilerDiagnosticIdentifiers.ResultOfExpressionIsAlwaysConstantSinceValueIsNeverEqualToNull: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!NullCheckExpression.TryCreate(expression, semanticModel, out NullCheckExpression nullCheck, context.CancellationToken)) { break; } if (nullCheck.Kind != NullCheckKind.EqualsToNull && nullCheck.Kind != NullCheckKind.NotEqualsToNull) { break; } CodeAction codeAction = CodeAction.Create( "Remove condition", cancellationToken => { SyntaxNode newRoot = RemoveHelper.RemoveCondition(root, expression, nullCheck.Kind == NullCheckKind.NotEqualsToNull); return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot))); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddComparisonWithBooleanLiteral) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseUncheckedExpression) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseCoalesceExpression) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceLocalVariable) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceField) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseYieldReturnInsteadOfReturn) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression) ) { return; } 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.ConstructedFrom.SpecialType == SpecialType.System_Nullable_T) { if (convertedType?.IsBoolean() == true || AddComparisonWithBooleanLiteralRefactoring.IsCondition(expression)) { if (Settings.IsCodeFixEnabled(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 (namedType.TypeArguments[0].Equals(convertedType)) { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseCoalesceExpression)) { CodeAction codeAction = CodeAction.Create( "Use coalesce expression", cancellationToken => { ExpressionSyntax defaultValue = convertedType.ToDefaultValueSyntax(semanticModel, expression.SpanStart); 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.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression)) { ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddCastExpression)) { CodeFixRegistrator.AddCastExpression(context, diagnostic, expression, convertedType, semanticModel); } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) && type?.IsErrorType() == false && !type.Equals(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.IsCodeFixEnabled(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: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier)) { break; } LocalDeclarationStatementSyntax localDeclarationStatement = GetLocalDeclarationStatement(expression); if (localDeclarationStatement == null) { break; } SyntaxTokenList modifiers = localDeclarationStatement.Modifiers; if (!modifiers.Contains(SyntaxKind.ConstKeyword)) { break; } ModifiersCodeFixes.RemoveModifier(context, diagnostic, localDeclarationStatement, SyntaxKind.ConstKeyword); break; } case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeBecauseItIsNonNullableValueType: case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeParameterBecauseItCouldBeNonNullableValueType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeInfo(expression, context.CancellationToken).ConvertedType; if (typeSymbol?.SupportsExplicitDeclaration() != true) { break; } CodeAction codeAction = CodeAction.Create( "Replace 'null' with default value", cancellationToken => { ExpressionSyntax newNode = typeSymbol.ToDefaultValueSyntax(semanticModel, expression.SpanStart); return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.ResultOfExpressionIsAlwaysConstantSinceValueIsNeverEqualToNull: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!NullCheckExpression.TryCreate(expression, semanticModel, out NullCheckExpression nullCheck, context.CancellationToken)) { break; } if (nullCheck.Kind != NullCheckKind.EqualsToNull && nullCheck.Kind != NullCheckKind.NotEqualsToNull) { break; } CodeAction codeAction = CodeAction.Create( "Remove condition", cancellationToken => { SyntaxNode newRoot = RemoveHelper.RemoveCondition(root, expression, nullCheck.Kind == NullCheckKind.NotEqualsToNull); return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot))); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.OnlyAssignmentCallIncrementDecrementAndNewObjectExpressionsCanBeUsedAsStatement: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (expression.Parent is ArrowExpressionClauseSyntax arrowExpresssionClause) { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression)) { break; } ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel); } else if (expression.Parent is ExpressionStatementSyntax expressionStatement) { if (!Settings.IsAnyCodeFixEnabled( CodeFixIdentifiers.IntroduceLocalVariable, CodeFixIdentifiers.IntroduceField)) { break; } if (semanticModel.GetSymbol(expression, context.CancellationToken)?.IsErrorType() != false) { break; } ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken); if (typeSymbol?.IsErrorType() != false) { break; } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceLocalVariable) && !expressionStatement.IsEmbedded()) { bool addAwait = typeSymbol.IsConstructedFromTaskOfT(semanticModel) && 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.IsCodeFixEnabled(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.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel); break; } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral) && expression?.IsKind(SyntaxKind.StringLiteralExpression) == true) { var literalExpression = (LiteralExpressionSyntax)expression; if (literalExpression.Token.ValueText.Length == 1) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (semanticModel.GetTypeInfo(expression, context.CancellationToken).ConvertedType?.IsChar() == true) { 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.IsCodeFixEnabled(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?.IsKind(SymbolKind.Method) == true && ((IMethodSymbol)containingSymbol).ReturnType?.IsIEnumerableOrConstructedFromIEnumerableOfT() == true) { 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; } } } }