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); } } } } } }
public ConditionalExpressionInfo Parse() { var rslt = new ConditionalExpressionInfo(this); rslt.Logical_Or_Expression = this.Logical_or_expression.Parse(); if (Second_expression != null) { rslt.Expression = this.Second_expression.Parse(); } if (Third_expression != null) { rslt.ConditionalExpression = this.Third_expression.Parse(); } return rslt; }
public ConditionalExpressionInfo Parse() { var rslt = new ConditionalExpressionInfo(this); rslt.Logical_Or_Expression = this.Logical_or_expression.Parse(); if (Second_expression != null) { rslt.Expression = this.Second_expression.Parse(); } if (Third_expression != null) { rslt.ConditionalExpression = this.Third_expression.Parse(); } return(rslt); }
private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context) { var conditionalExpression = (ConditionalExpressionSyntax)context.Node; if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanContainsDirectives()) { return; } ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); if (!info.Success) { return; } SyntaxKind trueKind = info.WhenTrue.Kind(); if (trueKind == SyntaxKind.TrueLiteralExpression) { if (context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression); } } else { SyntaxKind falseKind = info.WhenFalse.Kind(); if (falseKind == SyntaxKind.FalseLiteralExpression) { if (context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression); } } else if (trueKind == SyntaxKind.FalseLiteralExpression && falseKind == SyntaxKind.TrueLiteralExpression) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression); } } }
public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context) { var conditionalExpression = (ConditionalExpressionSyntax)context.Node; if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanContainsDirectives()) { return; } ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); if (!info.Success) { return; } switch (info.WhenTrue.Kind()) { case SyntaxKind.TrueLiteralExpression: { if (info.WhenFalse.Kind() == SyntaxKind.FalseLiteralExpression) { context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression); } break; } case SyntaxKind.FalseLiteralExpression: { if (info.WhenFalse.Kind() == SyntaxKind.TrueLiteralExpression) { context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression); } break; } } }
public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context) { var conditionalExpression = (ConditionalExpressionSyntax)context.Node; if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanContainsDirectives()) { return; } ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); if (!info.Success) { return; } SyntaxKind trueKind = info.WhenTrue.Kind(); if (trueKind == SyntaxKind.TrueLiteralExpression) { context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression); } else { SyntaxKind falseKind = info.WhenFalse.Kind(); if (falseKind == SyntaxKind.FalseLiteralExpression) { context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression); } else if (trueKind == SyntaxKind.FalseLiteralExpression && falseKind == SyntaxKind.TrueLiteralExpression) { context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression); } } }
private static void Analyze( SyntaxNodeAnalysisContext context, ConditionalExpressionInfo conditionalExpressionInfo, ExpressionSyntax whenNull, ExpressionSyntax whenNotNull, SemanticModel semanticModel, CancellationToken cancellationToken) { ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(whenNotNull, cancellationToken); if (typeSymbol?.IsErrorType() == false && semanticModel.IsDefaultValue(typeSymbol, whenNull, cancellationToken) && !RefactoringHelper.ContainsOutArgumentWithLocal(whenNotNull, semanticModel, cancellationToken) && !conditionalExpressionInfo.Node.IsInExpressionTree(semanticModel, cancellationToken)) { context.ReportDiagnostic( DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression, conditionalExpressionInfo.Node); } }
public static void Analyze(SyntaxNodeAnalysisContext context, ConditionalExpressionSyntax conditionalExpression) { if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanContainsDirectives()) { return; } ConditionalExpressionInfo info; if (ConditionalExpressionInfo.TryCreate(conditionalExpression, out info)) { switch (info.WhenTrue.Kind()) { case SyntaxKind.TrueLiteralExpression: { if (info.WhenFalse.IsKind(SyntaxKind.FalseLiteralExpression)) { context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression); } break; } case SyntaxKind.FalseLiteralExpression: { if (info.WhenFalse.IsKind(SyntaxKind.TrueLiteralExpression)) { context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression); } break; } } } }
private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context) { var conditionalExpression = (ConditionalExpressionSyntax)context.Node; if (conditionalExpression.ContainsDiagnostics) { return; } ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression, walkDownParentheses: false); if (!info.Success) { return; } if (info.Condition.Kind() == SyntaxKind.ParenthesizedExpression) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.ParenthesizeConditionInConditionalExpression, info.Condition); }
private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context) { var conditionalExpression = (ConditionalExpressionSyntax)context.Node; if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanContainsDirectives()) { return; } ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); if (!info.Success) { return; } SyntaxKind trueKind = info.WhenTrue.Kind(); SyntaxKind falseKind = info.WhenFalse.Kind(); if (trueKind == SyntaxKind.TrueLiteralExpression) { // a ? true : false >>> a // a ? true : b >>> a || b if (falseKind == SyntaxKind.FalseLiteralExpression || context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean) { Report(DiagnosticDescriptors.SimplifyConditionalExpression); } } else if (trueKind == SyntaxKind.FalseLiteralExpression) { /// a ? false : true >>> !a if (falseKind == SyntaxKind.TrueLiteralExpression) { Report(DiagnosticDescriptors.SimplifyConditionalExpression); } /// a ? false : b >>> !a && b else if (context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean) { Report(DiagnosticDescriptors.SimplifyConditionalExpression2); } } else if (falseKind == SyntaxKind.TrueLiteralExpression) { // a ? b : true >>> !a || b if (context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean) { Report(DiagnosticDescriptors.SimplifyConditionalExpression2); } } else if (falseKind == SyntaxKind.FalseLiteralExpression) { // a ? b : false >>> a && b if (context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean) { Report(DiagnosticDescriptors.SimplifyConditionalExpression); } } void Report(DiagnosticDescriptor descriptor) { DiagnosticHelpers.ReportDiagnosticIfNotSuppressed(context, descriptor, conditionalExpression); } }
public static async Task <Document> RefactorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken) { ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); ExpressionSyntax whenTrue = info.WhenTrue; ExpressionSyntax whenFalse = info.WhenFalse; SyntaxKind trueKind = whenTrue.Kind(); SyntaxKind falseKind = whenFalse.Kind(); ExpressionSyntax newNode = null; if (trueKind == SyntaxKind.TrueLiteralExpression) { if (falseKind == SyntaxKind.FalseLiteralExpression) { newNode = CreateNewNode(conditionalExpression, info.Condition); } else { SyntaxTriviaList trailingTrivia = info .QuestionToken .LeadingTrivia .AddRange(info.QuestionToken.TrailingTrivia) .AddRange(whenTrue.GetLeadingTrivia()) .EmptyIfWhitespace(); newNode = LogicalOrExpression( conditionalExpression.Condition.Parenthesize().AppendToTrailingTrivia(trailingTrivia), Token(info.ColonToken.LeadingTrivia, SyntaxKind.BarBarToken, info.ColonToken.TrailingTrivia), whenFalse.Parenthesize()); } } else if (falseKind == SyntaxKind.FalseLiteralExpression) { SyntaxTriviaList trailingTrivia = whenTrue .GetTrailingTrivia() .AddRange(info.ColonToken.LeadingTrivia) .AddRange(info.ColonToken.TrailingTrivia) .AddRange(whenFalse.GetLeadingTrivia()) .EmptyIfWhitespace() .AddRange(whenFalse.GetTrailingTrivia()); newNode = LogicalAndExpression( conditionalExpression.Condition.Parenthesize(), Token(info.QuestionToken.LeadingTrivia, SyntaxKind.AmpersandAmpersandToken, info.QuestionToken.TrailingTrivia), whenTrue.WithTrailingTrivia(trailingTrivia).Parenthesize()); } else if (trueKind == SyntaxKind.FalseLiteralExpression && falseKind == SyntaxKind.TrueLiteralExpression) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); newNode = CreateNewNode(conditionalExpression, Inverter.LogicallyNegate(info.Condition, semanticModel, cancellationToken)); } newNode = newNode.Parenthesize(); return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false)); }
public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context) { if (context.Node.SpanContainsDirectives()) { return; } var conditionalExpression = (ConditionalExpressionSyntax)context.Node; ConditionalExpressionInfo conditionalExpressionInfo = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); if (!conditionalExpressionInfo.Success) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(conditionalExpressionInfo.Condition, semanticModel: semanticModel, cancellationToken: cancellationToken); if (!nullCheck.Success) { return; } ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenTrue : conditionalExpressionInfo.WhenFalse; ExpressionSyntax whenNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenFalse : conditionalExpressionInfo.WhenTrue; if (CSharpFactory.AreEquivalent(nullCheck.Expression, whenNotNull)) { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression) && semanticModel .GetTypeSymbol(nullCheck.Expression, cancellationToken)? .IsReferenceTypeOrNullableType() == true) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression, conditionalExpression); } } else if (whenNotNull.IsKind( SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression, SyntaxKind.ConditionalAccessExpression, SyntaxKind.InvocationExpression)) { ExpressionSyntax expression = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed( nullCheck.Expression, whenNotNull, semanticModel, cancellationToken); 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.IsNullableType()) { 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) { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression)) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression, conditionalExpression); } } else { Analyze(context, conditionalExpressionInfo, whenNull, whenNotNull, semanticModel, cancellationToken); } } } } } else if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression) && whenNotNull.IsKind(SyntaxKind.CastExpression) && whenNull.IsKind(SyntaxKind.NullLiteralExpression, SyntaxKind.DefaultLiteralExpression)) { var castExpression = (CastExpressionSyntax)whenNotNull; if (castExpression.Type.IsKind(SyntaxKind.NullableType) && castExpression.Expression.IsKind(SyntaxKind.InvocationExpression, SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression)) { ExpressionSyntax expression = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed( nullCheck.Expression, castExpression.Expression, isNullable: true, semanticModel, cancellationToken); if (expression != null) { ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken); if (typeSymbol?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression, conditionalExpression); } } } } }
public static async Task <Document> RefactorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ConditionalExpressionInfo conditionalExpressionInfo = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(conditionalExpressionInfo.Condition, semanticModel: semanticModel, cancellationToken: cancellationToken); ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenTrue : conditionalExpressionInfo.WhenFalse; ExpressionSyntax whenNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenFalse : conditionalExpressionInfo.WhenTrue; var castExpression = whenNotNull as CastExpressionSyntax; ExpressionSyntax expression = (castExpression != null) ? UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, castExpression.Expression, semanticModel, cancellationToken) : UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull, semanticModel, cancellationToken); var coalesce = false; ExpressionSyntax newNode = null; if (CSharpFactory.AreEquivalent(nullCheck.Expression, whenNotNull)) { //RCS1084 UseCoalesceExpressionInsteadOfConditionalExpression newNode = nullCheck.Expression; coalesce = true; } else if (semanticModel .GetTypeSymbol(nullCheck.Expression, cancellationToken) .IsNullableType()) { 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) { //RCS1084 UseCoalesceExpressionInsteadOfConditionalExpression newNode = nullCheck.Expression; coalesce = true; } else { newNode = ParseExpression($"{expression}?{whenNotNull.ToString().Substring(memberAccessExpression.Span.End - whenNotNull.SpanStart)}"); if (castExpression != null) { newNode = castExpression .WithExpression(newNode.Parenthesize()) .WithSimplifierAnnotation(); } } } } } if (newNode == null) { newNode = ParseExpression(whenNotNull.ToString().Insert(expression.Span.End - whenNotNull.SpanStart, "?")); } if (coalesce || (!semanticModel.GetTypeSymbol(whenNotNull, cancellationToken).IsReferenceTypeOrNullableType() && (whenNull as DefaultExpressionSyntax)?.Type.IsKind(SyntaxKind.NullableType) != true)) { newNode = CoalesceExpression(newNode.Parenthesize(), whenNull.Parenthesize()); } newNode = newNode .WithTriviaFrom(conditionalExpression) .Parenthesize(); return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false)); }
private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanContainsDirectives()) { return; } var conditionalExpression = (ConditionalExpressionSyntax)context.Node; ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); if (!info.Success) { return; } SyntaxKind trueKind = info.WhenTrue.Kind(); SyntaxKind falseKind = info.WhenFalse.Kind(); if (trueKind == SyntaxKind.TrueLiteralExpression) { // a ? true : false >>> a // a ? true : b >>> a || b if (falseKind == SyntaxKind.FalseLiteralExpression || (falseKind != SyntaxKind.ThrowExpression && context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)) { ReportDiagnostic(); } } else if (trueKind == SyntaxKind.FalseLiteralExpression) { /// a ? false : true >>> !a if (falseKind == SyntaxKind.TrueLiteralExpression) { ReportDiagnostic(); } /// a ? false : b >>> !a && b else if (falseKind != SyntaxKind.ThrowExpression && !AnalyzerOptions.DoNotSimplifyConditionalExpressionWhenConditionIsInverted.IsEnabled(context) && context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.SimplifyConditionalExpression, conditionalExpression, AnalyzerOptions.DoNotSimplifyConditionalExpressionWhenConditionIsInverted); } } else if (falseKind == SyntaxKind.TrueLiteralExpression) { // a ? b : true >>> !a || b if (trueKind != SyntaxKind.ThrowExpression && !AnalyzerOptions.DoNotSimplifyConditionalExpressionWhenConditionIsInverted.IsEnabled(context) && context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.SimplifyConditionalExpression, conditionalExpression, AnalyzerOptions.DoNotSimplifyConditionalExpressionWhenConditionIsInverted); } } else if (falseKind == SyntaxKind.FalseLiteralExpression) { // a ? b : false >>> a && b if (trueKind != SyntaxKind.ThrowExpression && context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean) { ReportDiagnostic(); } } void ReportDiagnostic() { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.SimplifyConditionalExpression, conditionalExpression); } }
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 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); } } } } } }
private static (int, int) GetNearestConditionalExpressionIndexes(string source, out ConditionalExpressionInfo conditionalExpressionInfo) { conditionalExpressionInfo = null; int beginIndex = -1, endIndex = -1; // Находим первую конструкцию {ce.LeftSide}...значение...{ce.RightSide} foreach (var ce in conditionalExpressions) { int tempBeginIndex = source.IndexOf(ce.LeftSide); if (tempBeginIndex >= 0) { int tempEndIndex = source.IndexOf(ce.RightSide, tempBeginIndex); if (tempEndIndex >= 0) { // Если это первая итерация или найдена конструкция, находящаяся перед // текущей конструкцией if (beginIndex < 0 || tempBeginIndex < beginIndex) { beginIndex = tempBeginIndex; endIndex = tempEndIndex; conditionalExpressionInfo = ce; } } } } if (beginIndex >= 0 && endIndex > 0) { // Ищем условные конструкции внутри нашей условной конструкции // Если таковые имеются и закрывающая стороная совпадает с нашей конструкцией, // то присваиваем endIndex следующую закрывающую сторону bool wasOffset = false; int lastTempBeginIndex = beginIndex + conditionalExpressionInfo.LeftSide.Length; do { wasOffset = false; // Ищем самую первую условную конструкцию в интервале от [lasTempBeginIndex; endIndex] // Если таковая имеется, тогда присваиваем endIndex индекс следующей закрывающей стороны int?tempBeginIndex = null; foreach (var ce in conditionalExpressions) { int temp = source.IndexOf(ce.LeftSide, lastTempBeginIndex); if (temp > 0) { temp += ce.LeftSide.Length; if (!tempBeginIndex.HasValue && temp <= endIndex) { tempBeginIndex = temp; } else if (temp <= endIndex && temp < tempBeginIndex) { tempBeginIndex = temp; } } } if (tempBeginIndex.HasValue) { lastTempBeginIndex = tempBeginIndex.Value; int tempEndIndex = source.IndexOf(conditionalExpressionInfo.RightSide, endIndex + conditionalExpressionInfo.RightSide.Length); if (tempEndIndex > 0) { endIndex = tempEndIndex; wasOffset = true; } } } while (wasOffset); } return(beginIndex, endIndex); }