public static async Task ComputeRefactoringsAsync(RefactoringContext context, BinaryExpressionSyntax binaryExpression) { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, NullCheckStyles.ComparisonToNull); if (!nullCheck.Success) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (semanticModel .GetTypeInfo(nullCheck.Expression, context.CancellationToken) .ConvertedType? .SpecialType != SpecialType.System_String) { return; } if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceEqualsExpressionWithStringIsNullOrEmpty)) { ReplaceEqualsExpressionWithStringIsNullOrEmptyRefactoring.Instance.RegisterRefactoring(context, nullCheck); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceEqualsExpressionWithStringIsNullOrWhiteSpace)) { ReplaceEqualsExpressionWithStringIsNullOrWhiteSpaceRefactoring.Instance.RegisterRefactoring(context, nullCheck); } }
private static bool NullCheckExists(ExpressionSyntax expression, StatementSyntax statement) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(statement); if (!statementsInfo.Success) { return(false); } SyntaxList <StatementSyntax> statements = statementsInfo.Statements; int index = statements.IndexOf(statement); if (index >= statements.Count - 1) { return(false); } StatementSyntax nextStatement = statements[index + 1]; if (!(nextStatement is IfStatementSyntax ifStatement)) { return(false); } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.NotEqualsToNull); if (!nullCheck.Success) { return(false); } return(CSharpFactory.AreEquivalent(expression, nullCheck.Expression)); }
public static void AnalyzeLogicalAndExpression(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType) { var logicalAndExpression = (BinaryExpressionSyntax)context.Node; if (!logicalAndExpression.ContainsDiagnostics) { ExpressionSyntax expression = SyntaxInfo.NullCheckExpressionInfo(logicalAndExpression.Left, allowedKinds: NullCheckKind.NotEqualsToNull).Expression; if (expression != null && context.SemanticModel .GetTypeSymbol(expression, context.CancellationToken)? .IsReferenceType == true) { ExpressionSyntax right = logicalAndExpression.Right?.WalkDownParentheses(); if (right != null && ValidateRightExpression(right, context.SemanticModel, context.CancellationToken) && !RefactoringHelper.ContainsOutArgumentWithLocal(right, context.SemanticModel, context.CancellationToken)) { ExpressionSyntax expression2 = FindExpressionThatCanBeConditionallyAccessed(expression, right); if (expression2?.SpanContainsDirectives() == false && !logicalAndExpression.IsInExpressionTree(expressionType, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, logicalAndExpression); } } } } }
private static void Analyze(SyntaxNodeAnalysisContext context, BinaryExpressionSyntax binaryExpression, NullCheckStyles allowedStyles) { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, allowedStyles: allowedStyles); if (nullCheck.Success && IsUnconstrainedTypeParameter(context.SemanticModel.GetTypeSymbol(nullCheck.Expression, context.CancellationToken)) && !binaryExpression.SpanContainsDirectives()) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UnconstrainedTypeParameterCheckedForNull, binaryExpression); } }
private static async Task <Document> RemoveUnnecessaryNullCheckAsync( Document document, BinaryExpressionSyntax logicalAnd, CancellationToken cancellationToken) { BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo(logicalAnd); ExpressionSyntax right = binaryExpressionInfo.Right; SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpressionInfo.Left, semanticModel, NullCheckStyles.HasValue | NullCheckStyles.NotEqualsToNull); var binaryExpression = right as BinaryExpressionSyntax; ExpressionSyntax newRight; switch (right.Kind()) { case SyntaxKind.SimpleMemberAccessExpression: { newRight = TrueLiteralExpression().WithTriviaFrom(right); break; } case SyntaxKind.LogicalNotExpression: { newRight = FalseLiteralExpression().WithTriviaFrom(right); break; } default: { newRight = binaryExpression.Right; break; } } BinaryExpressionSyntax newBinaryExpression = BinaryExpression( (binaryExpression != null) ? right.Kind() : SyntaxKind.EqualsExpression, nullCheck.Expression.WithLeadingTrivia(logicalAnd.GetLeadingTrivia()), (binaryExpression != null) ? ((BinaryExpressionSyntax)right).OperatorToken : Token(SyntaxKind.EqualsEqualsToken).WithTriviaFrom(logicalAnd.OperatorToken), newRight) .WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(logicalAnd, newBinaryExpression, cancellationToken).ConfigureAwait(false)); }
private static bool IsFixable( ExpressionSyntax left, ExpressionSyntax right, SyntaxKind binaryExpressionKind, SemanticModel semanticModel, CancellationToken cancellationToken) { NullCheckStyles allowedStyles = (binaryExpressionKind == SyntaxKind.LogicalAndExpression) ? NullCheckStyles.NotEqualsToNull : NullCheckStyles.EqualsToNull; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(left, allowedStyles: allowedStyles); ExpressionSyntax expression = nullCheck.Expression; if (expression == null) { return(false); } ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, cancellationToken); if (typeSymbol == null) { return(false); } if (!typeSymbol.IsReferenceTypeOrNullableType()) { return(false); } if (right == null) { return(false); } if (!ValidateRightExpression(right, binaryExpressionKind, semanticModel, cancellationToken)) { return(false); } if (RefactoringUtility.ContainsOutArgumentWithLocal(right, semanticModel, cancellationToken)) { return(false); } ExpressionSyntax expression2 = FindExpressionThatCanBeConditionallyAccessed(expression, right, isNullable: !typeSymbol.IsReferenceType); return(expression2?.SpanContainsDirectives() == false); }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.IsSimpleIf() && !ifStatement.ContainsDiagnostics && ifStatement.TryGetContainingList(out SyntaxList <StatementSyntax> statements) && !IsPartOfLazyInitialization(ifStatement, statements)) { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, semanticModel: context.SemanticModel, cancellationToken: context.CancellationToken); if (nullCheck.Success) { SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(ifStatement.GetSingleStatementOrDefault()); if (assignmentInfo.Success && SyntaxComparer.AreEquivalent(assignmentInfo.Left, nullCheck.Expression) && assignmentInfo.Right.IsSingleLine() && !ifStatement.SpanContainsDirectives()) { int index = statements.IndexOf(ifStatement); if (index > 0) { StatementSyntax previousStatement = statements[index - 1]; if (!previousStatement.ContainsDiagnostics && CanRefactor(previousStatement, ifStatement, nullCheck.Expression, ifStatement.Parent)) { context.ReportDiagnostic(DiagnosticDescriptors.UseCoalesceExpression, previousStatement); } } if (index < statements.Count - 1) { StatementSyntax nextStatement = statements[index + 1]; if (!nextStatement.ContainsDiagnostics) { MemberInvocationStatementInfo invocationInfo = SyntaxInfo.MemberInvocationStatementInfo(nextStatement); if (invocationInfo.Success && SyntaxComparer.AreEquivalent(nullCheck.Expression, invocationInfo.Expression) && !ifStatement.Parent.ContainsDirectives(TextSpan.FromBounds(ifStatement.SpanStart, nextStatement.Span.End))) { context.ReportDiagnostic(DiagnosticDescriptors.InlineLazyInitialization, ifStatement); } } } } } } }
private static Task <Document> UseIsNullPatternInsteadOfComparisonAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, NullCheckStyles.ComparisonToNull, walkDownParentheses: false); ExpressionSyntax expression = nullCheck.Expression; ExpressionSyntax nullLiteral; if (object.ReferenceEquals(expression, binaryExpression.Left)) { nullLiteral = binaryExpression.Right; } else { expression = expression.WithTrailingTrivia(binaryExpression.Left.GetTrailingTrivia()); nullLiteral = binaryExpression.Left.WithLeadingTrivia(expression.GetLeadingTrivia()); } bool useIsNotNull = !AnalyzerOptions.UseLogicalNegationAndPatternMatchingToCheckForNull.IsEnabled(document, binaryExpression); PatternSyntax pattern = ConstantPattern(nullLiteral); if (binaryExpression.IsKind(SyntaxKind.NotEqualsExpression) && useIsNotNull) { pattern = NotPattern(pattern); } ExpressionSyntax newExpression = IsPatternExpression( expression, Token(binaryExpression.OperatorToken.LeadingTrivia, SyntaxKind.IsKeyword, binaryExpression.OperatorToken.TrailingTrivia), pattern); if (binaryExpression.IsKind(SyntaxKind.NotEqualsExpression) && !useIsNotNull) { newExpression = LogicalNotExpression(ParenthesizedExpression(newExpression.WithoutTrivia())); } newExpression = newExpression .WithTriviaFrom(binaryExpression) .WithFormatterAnnotation(); return(document.ReplaceNodeAsync(binaryExpression, newExpression, cancellationToken)); }
private static async Task <Document> UseStringIsNullOrEmptyMethodAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { if (binaryExpression.IsKind(SyntaxKind.EqualsExpression)) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo(binaryExpression); ExpressionSyntax expression = (CSharpUtility.IsEmptyStringExpression(binaryExpressionInfo.Left, semanticModel, cancellationToken)) ? binaryExpressionInfo.Right : binaryExpressionInfo.Left; ExpressionSyntax newNode = SimpleMemberInvocationExpression( CSharpTypeFactory.StringType(), IdentifierName("IsNullOrEmpty"), Argument(expression)); newNode = newNode .WithTriviaFrom(binaryExpression) .WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken).ConfigureAwait(false)); } else { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression.Left); ExpressionSyntax newNode = SimpleMemberInvocationExpression( CSharpTypeFactory.StringType(), IdentifierName("IsNullOrEmpty"), Argument(nullCheck.Expression)); if (nullCheck.IsCheckingNotNull) { newNode = LogicalNotExpression(newNode); } newNode = newNode .WithTriviaFrom(binaryExpression) .WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken).ConfigureAwait(false)); } }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType) { var ifStatement = (IfStatementSyntax)context.Node; if (!ifStatement.IsSimpleIf()) { return; } if (ifStatement.ContainsDiagnostics) { return; } if (ifStatement.SpanContainsDirectives()) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, allowedStyles: NullCheckStyles.NotEqualsToNull); if (!nullCheck.Success) { return; } SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(ifStatement.SingleNonBlockStatementOrDefault()); if (!invocationInfo.Success) { return; } if (!CSharpFactory.AreEquivalent(nullCheck.Expression, invocationInfo.Expression)) { return; } if (ifStatement.IsInExpressionTree(expressionType, context.SemanticModel, context.CancellationToken)) { return; } context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, ifStatement); }
public static void AnalyzeFirstOrDefault(SyntaxNodeAnalysisContext context, SimpleMemberInvocationExpressionInfo invocationInfo) { InvocationExpressionSyntax invocation = invocationInfo.InvocationExpression; SyntaxNode parent = invocation.WalkUpParentheses().Parent; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(parent, NullCheckStyles.ComparisonToNull | NullCheckStyles.IsNull); if (!nullCheck.Success) { return; } SyntaxNode node = nullCheck.NullCheckExpression; if (node.ContainsDirectives) { return; } ExtensionMethodSymbolInfo extensionMethodSymbolInfo = context.SemanticModel.GetReducedExtensionMethodInfo(invocation, context.CancellationToken); IMethodSymbol methodSymbol = extensionMethodSymbolInfo.Symbol; if (methodSymbol == null) { return; } if (!SymbolUtility.IsLinqExtensionOfIEnumerableOfTWithPredicate(methodSymbol, context.SemanticModel, name: invocationInfo.NameText, allowImmutableArrayExtension: true)) { return; } if (!extensionMethodSymbolInfo .ReducedSymbol .ReturnType .IsReferenceTypeOrNullableType()) { return; } context.ReportDiagnostic(DiagnosticDescriptors.SimplifyLinqMethodChain, node); }
public static async Task <Document> RefactorAsync( Document document, IfStatementSyntax ifStatement, CancellationToken cancellationToken) { var statement = (ExpressionStatementSyntax)ifStatement.SingleNonBlockStatementOrDefault(); StatementSyntax newStatement = statement; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.NotEqualsToNull); SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(statement); ExpressionSyntax expression = invocationInfo.Expression; SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken).IsNullableType()) { var memberAccess = (MemberAccessExpressionSyntax)invocationInfo.Expression; newStatement = statement.ReplaceNode(memberAccess, memberAccess.Expression.WithTrailingTrivia(memberAccess.GetTrailingTrivia())); expression = memberAccess.Expression; } int insertIndex = expression.Span.End - statement.FullSpan.Start; newStatement = SyntaxFactory.ParseStatement(newStatement.ToFullString().Insert(insertIndex, "?")); IEnumerable <SyntaxTrivia> leading = ifStatement.DescendantTrivia(TextSpan.FromBounds(ifStatement.SpanStart, statement.SpanStart)); newStatement = (leading.All(f => f.IsWhitespaceOrEndOfLineTrivia())) ? newStatement.WithLeadingTrivia(ifStatement.GetLeadingTrivia()) : newStatement.WithLeadingTrivia(ifStatement.GetLeadingTrivia().Concat(leading)); IEnumerable <SyntaxTrivia> trailing = ifStatement.DescendantTrivia(TextSpan.FromBounds(statement.Span.End, ifStatement.Span.End)); newStatement = (leading.All(f => f.IsWhitespaceOrEndOfLineTrivia())) ? newStatement.WithTrailingTrivia(ifStatement.GetTrailingTrivia()) : newStatement.WithTrailingTrivia(trailing.Concat(ifStatement.GetTrailingTrivia())); return(await document.ReplaceNodeAsync(ifStatement, newStatement, cancellationToken).ConfigureAwait(false)); }
private static void AnalyzeLogicalOrExpression(SyntaxNodeAnalysisContext context) { var binaryExpression = (BinaryExpressionSyntax)context.Node; if (binaryExpression.ContainsDiagnostics) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression.Left, context.SemanticModel, allowedStyles: NullCheckStyles.CheckingNull); ExpressionSyntax expression = nullCheck.Expression; if (expression == null) { return; } ExpressionSyntax right = binaryExpression.Right.WalkDownParentheses(); if (!right.IsKind(SyntaxKind.LogicalAndExpression)) { return; } var logicalAndExpression = (BinaryExpressionSyntax)right; ExpressionChain.Enumerator en = logicalAndExpression.AsChain().GetEnumerator(); if (!en.MoveNext()) { return; } NullCheckExpressionInfo nullCheck2 = SyntaxInfo.NullCheckExpressionInfo(en.Current, context.SemanticModel, allowedStyles: NullCheckStyles.CheckingNotNull); if (!CSharpFactory.AreEquivalent(expression, nullCheck2.Expression)) { return; } ReportExpressionAlwaysEqualToTrueOrFalse(context, nullCheck2.NullCheckExpression, "true"); }
private static void AnalyzeNotEqualsExpression(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } var binaryExpression = (BinaryExpressionSyntax)context.Node; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, allowedStyles: NullCheckStyles.NotEqualsToNull); if (nullCheck.Success) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.UsePatternMatchingToCheckForNullOrViceVersa, binaryExpression, "!="); } }
private static void AnalyzeNotEqualsExpression(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } var binaryExpression = (BinaryExpressionSyntax)context.Node; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, allowedStyles: NullCheckStyles.NotEqualsToNull); if (nullCheck.Success) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.UseIsNullPatternInsteadOfComparisonOrViceVersa, binaryExpression, "!="); } }
private static void AnalyzeEqualsExpression(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } var binaryExpression = (BinaryExpressionSyntax)context.Node; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, allowedStyles: NullCheckStyles.EqualsToNull, walkDownParentheses: false); if (nullCheck.Success) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.UsePatternMatchingToCheckForNullOrViceVersa, binaryExpression, AnalyzerOptions.UseComparisonInsteadPatternMatchingToCheckForNull, "=="); } }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType) { var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.IsSimpleIf() && !ifStatement.ContainsDiagnostics) { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, allowedKinds: NullCheckKind.NotEqualsToNull); if (nullCheck.Success) { MemberInvocationStatementInfo invocationInfo = SyntaxInfo.MemberInvocationStatementInfo(ifStatement.GetSingleStatementOrDefault()); if (invocationInfo.Success && SyntaxComparer.AreEquivalent(nullCheck.Expression, invocationInfo.Expression) && !ifStatement.IsInExpressionTree(expressionType, context.SemanticModel, context.CancellationToken) && !ifStatement.SpanContainsDirectives()) { context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, ifStatement); } } } }
public static Task <Document> RefactorAsync( Document document, SyntaxNode node, CancellationToken cancellationToken) { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(node); AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(nullCheck.Expression); ExpressionSyntax newNode = IsExpression(asExpressionInfo.Expression, asExpressionInfo.Type); if (nullCheck.IsCheckingNull) { newNode = LogicalNotExpression(newNode.WithoutTrivia().Parenthesize()).WithTriviaFrom(newNode); } newNode = newNode .Parenthesize() .WithFormatterAnnotation(); return(document.ReplaceNodeAsync(node, newNode, cancellationToken)); }
private static bool IsFixable( ExpressionSyntax left, BinaryExpressionSyntax right, SemanticModel semanticModel, CancellationToken cancellationToken = default) { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(left); if (!nullCheck.Success) { return(false); } ExpressionSyntax expression = nullCheck.Expression; if (CSharpFactory.AreEquivalent(expression, right.Left)) { return(right.IsKind(SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression) && SymbolEquals(expression, right.Left, semanticModel, cancellationToken) && CSharpUtility.IsEmptyStringExpression(right.Right, semanticModel, cancellationToken)); } if (right.Left.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccess = (MemberAccessExpressionSyntax)right.Left; return(string.Equals(memberAccess.Name.Identifier.ValueText, "Length", StringComparison.Ordinal) && right.Right.IsNumericLiteralExpression("0") && semanticModel.GetSymbol(memberAccess, cancellationToken) is IPropertySymbol propertySymbol && !propertySymbol.IsIndexer && SymbolUtility.IsPublicInstance(propertySymbol, "Length") && propertySymbol.Type.SpecialType == SpecialType.System_Int32 && propertySymbol.ContainingType?.SpecialType == SpecialType.System_String && CSharpFactory.AreEquivalent(expression, memberAccess.Expression) && SymbolEquals(expression, memberAccess.Expression, semanticModel, cancellationToken)); } return(false); }
private static Task <Document> UseStringIsNullOrEmptyMethodAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression.Left); ExpressionSyntax newNode = SimpleMemberInvocationExpression( CSharpTypeFactory.StringType(), IdentifierName("IsNullOrEmpty"), Argument(nullCheck.Expression)); if (nullCheck.IsCheckingNotNull) { newNode = LogicalNotExpression(newNode); } newNode = newNode .WithTriviaFrom(binaryExpression) .WithFormatterAnnotation(); return(document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken)); }
private static void Analyze(SyntaxNodeAnalysisContext context, SyntaxNode node) { if (node.SpanContainsDirectives()) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(node); if (!nullCheck.Success) { return; } AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(nullCheck.Expression); if (!asExpressionInfo.Success) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseIsOperatorInsteadOfAsOperator, node); }
private static void AnalyzeNotEqualsExpression(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } var binaryExpression = (BinaryExpressionSyntax)context.Node; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, allowedStyles: NullCheckStyles.NotEqualsToNull); if (!nullCheck.Success) { return; } if (binaryExpression.IsInExpressionTree(context.SemanticModel, context.CancellationToken)) { return; } ReportDiagnostic(context, binaryExpression, "pattern matching"); }
private static bool IsNullCheck( StatementSyntax statement, SemanticModel semanticModel, CancellationToken cancellationToken = default(CancellationToken)) { if (!(statement is IfStatementSyntax ifStatement)) { return(false); } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.EqualsToNull | NullCheckStyles.IsNull); if (!nullCheck.Success) { return(false); } if (nullCheck.Expression.Kind() != SyntaxKind.IdentifierName) { return(false); } var throwStatement = ifStatement.SingleNonBlockStatementOrDefault() as ThrowStatementSyntax; if (throwStatement?.Expression?.Kind() != SyntaxKind.ObjectCreationExpression) { return(false); } var objectCreation = (ObjectCreationExpressionSyntax)throwStatement.Expression; INamedTypeSymbol exceptionType = semanticModel.GetTypeByMetadataName(MetadataNames.System_ArgumentNullException); ISymbol type = semanticModel.GetSymbol(objectCreation.Type, cancellationToken); return(type?.Equals(exceptionType) == true); }
private static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.ContainsDiagnostics) { return; } if (ifStatement.SpanContainsDirectives()) { return; } if (!ifStatement.IsSimpleIf()) { return; } SyntaxList <StatementSyntax> statements = SyntaxInfo.StatementListInfo(ifStatement).Statements; if (!statements.Any()) { return; } if (IsPartOfLazyInitialization()) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo( ifStatement.Condition, semanticModel: context.SemanticModel, allowedStyles: NullCheckStyles.CheckingNull, cancellationToken: context.CancellationToken); if (!nullCheck.Success) { return; } SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(ifStatement.SingleNonBlockStatementOrDefault()); if (!assignmentInfo.Success) { return; } if (!CSharpFactory.AreEquivalent(assignmentInfo.Left, nullCheck.Expression)) { return; } if (!assignmentInfo.Right.IsSingleLine()) { return; } int index = statements.IndexOf(ifStatement); if (index > 0 && !context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpression)) { StatementSyntax previousStatement = statements[index - 1]; if (!previousStatement.ContainsDiagnostics && !previousStatement.GetTrailingTrivia().Any(f => f.IsDirective) && !ifStatement.GetLeadingTrivia().Any(f => f.IsDirective) && CanUseCoalesceExpression(previousStatement, nullCheck.Expression)) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCoalesceExpression, previousStatement); } } if (context.IsAnalyzerSuppressed(DiagnosticDescriptors.InlineLazyInitialization)) { return; } if (index == statements.Count - 1) { return; } StatementSyntax nextStatement = statements[index + 1]; if (nextStatement.ContainsDiagnostics) { return; } SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(nextStatement); if (!invocationInfo.Success) { return; } if (!CSharpFactory.AreEquivalent(nullCheck.Expression, invocationInfo.Expression)) { return; } if (ifStatement.GetTrailingTrivia().Any(f => f.IsDirective)) { return; } if (nextStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.InlineLazyInitialization, ifStatement); bool IsPartOfLazyInitialization() { return(statements.Count == 2 && statements.IndexOf(ifStatement) == 0 && statements[1].IsKind(SyntaxKind.ReturnStatement)); } }
private static ImmutableArray <IfRefactoring> Analyze( IfStatementSyntax ifStatement, ExpressionSyntax condition, ExpressionStatementSyntax expressionStatement1, ExpressionStatementSyntax expressionStatement2, IfAnalysisOptions options, SemanticModel semanticModel, CancellationToken cancellationToken) { SimpleAssignmentStatementInfo assignment1 = SyntaxInfo.SimpleAssignmentStatementInfo(expressionStatement1); if (!assignment1.Success) { return(Empty); } SimpleAssignmentStatementInfo assignment2 = SyntaxInfo.SimpleAssignmentStatementInfo(expressionStatement2); if (!assignment2.Success) { return(Empty); } ExpressionSyntax left1 = assignment1.Left; ExpressionSyntax left2 = assignment2.Left; ExpressionSyntax right1 = assignment1.Right; ExpressionSyntax right2 = assignment2.Right; if (!SyntaxComparer.AreEquivalent(left1, left2)) { return(Empty); } if (options.UseCoalesceExpression || options.UseExpression) { SyntaxKind kind1 = right1.Kind(); SyntaxKind kind2 = right2.Kind(); if (kind1.IsBooleanLiteralExpression() && kind2.IsBooleanLiteralExpression() && kind1 != kind2) { if (options.UseExpression) { return(new IfElseToAssignmentWithCondition(ifStatement, left1, condition, negate: kind1 == SyntaxKind.FalseLiteralExpression).ToImmutableArray()); } return(Empty); } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(condition, semanticModel: semanticModel, cancellationToken: cancellationToken); if (nullCheck.Success) { IfRefactoring refactoring = CreateIfToAssignment( ifStatement, left1, (nullCheck.IsCheckingNull) ? right2 : right1, (nullCheck.IsCheckingNull) ? right1 : right2, nullCheck, options, semanticModel, cancellationToken); if (refactoring != null) { return(refactoring.ToImmutableArray()); } } } if (options.UseConditionalExpression) { return(new IfElseToAssignmentWithConditionalExpression(ifStatement, left1, right1, right2).ToImmutableArray()); } return(Empty); }
private static ImmutableArray <IfRefactoring> Analyze( IfStatementSyntax ifStatement, ExpressionSyntax condition, ExpressionSyntax expression1, ExpressionSyntax expression2, IfAnalysisOptions options, bool isYield, SemanticModel semanticModel, CancellationToken cancellationToken) { if (expression1?.IsMissing != false) { return(Empty); } if (expression2?.IsMissing != false) { return(Empty); } if (options.UseCoalesceExpression || options.UseExpression) { SyntaxKind kind1 = expression1.Kind(); SyntaxKind kind2 = expression2.Kind(); if (kind1.IsBooleanLiteralExpression() && kind2.IsBooleanLiteralExpression() && kind1 != kind2) { if (options.UseExpression) { if (ifStatement.IsSimpleIf() && (ifStatement.PreviousStatementOrDefault() is IfStatementSyntax previousIf) && previousIf.IsSimpleIf() && (previousIf.GetSingleStatementOrDefault() is ReturnStatementSyntax returnStatement) && returnStatement.Expression?.WalkDownParentheses().Kind() == kind1) { return(Empty); } return(new IfToReturnWithExpression(ifStatement, condition, isYield, negate: kind1 == SyntaxKind.FalseLiteralExpression).ToImmutableArray()); } return(Empty); } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(condition, semanticModel: semanticModel, cancellationToken: cancellationToken); if (nullCheck.Success) { IfRefactoring refactoring = CreateIfToReturnStatement( ifStatement, (nullCheck.IsCheckingNull) ? expression2 : expression1, (nullCheck.IsCheckingNull) ? expression1 : expression2, nullCheck, options, isYield, semanticModel, cancellationToken); if (refactoring != null) { return(refactoring.ToImmutableArray()); } } } IfToReturnWithBooleanExpression ifToReturnWithBooleanExpression = null; if (options.UseBooleanExpression && (expression1.Kind().IsBooleanLiteralExpression() || expression2.Kind().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.Kind().IsBooleanLiteralExpression() || !expression2.Kind().IsBooleanLiteralExpression())) { ifToReturnWithConditionalExpression = IfToReturnWithConditionalExpression.Create(ifStatement, expression1, expression2, isYield); } return(ToImmutableArray(ifToReturnWithBooleanExpression, ifToReturnWithConditionalExpression)); }
private static ExpressionSyntax CreateExpressionWithConditionalAccess(BinaryExpressionSyntax logicalAnd) { ExpressionSyntax expression = SyntaxInfo.NullCheckExpressionInfo(logicalAnd.Left, allowedStyles: NullCheckStyles.NotEqualsToNull).Expression; ExpressionSyntax right = logicalAnd.Right?.WalkDownParentheses(); ExpressionSyntax expression2 = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed( expression, right); SyntaxKind kind = right.Kind(); if (kind == SyntaxKind.LogicalNotExpression) { var logicalNot = (PrefixUnaryExpressionSyntax)right; ExpressionSyntax operand = logicalNot.Operand; string s = operand.ToFullString(); int length = expression2.Span.End - operand.FullSpan.Start; int trailingLength = operand.GetTrailingTrivia().Span.Length; var sb = new StringBuilder(); sb.Append(s, 0, length); sb.Append("?"); sb.Append(s, length, s.Length - length - trailingLength); sb.Append(" == false"); sb.Append(s, s.Length - trailingLength, trailingLength); return(SyntaxFactory.ParseExpression(sb.ToString())); } else { string s = right.ToFullString(); int length = expression2.Span.End - right.FullSpan.Start; int trailingLength = right.GetTrailingTrivia().Span.Length; var sb = new StringBuilder(); sb.Append(s, 0, length); sb.Append("?"); sb.Append(s, length, s.Length - length - trailingLength); switch (kind) { case SyntaxKind.LogicalOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.IsExpression: case SyntaxKind.AsExpression: case SyntaxKind.IsPatternExpression: break; default: { sb.Append(" == true"); break; } } sb.Append(s, s.Length - trailingLength, trailingLength); return(SyntaxFactory.ParseExpression(sb.ToString())); } }
private static void AnalyzeAsExpression(SyntaxNodeAnalysisContext context) { var asExpression = (BinaryExpressionSyntax)context.Node; AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(asExpression); if (!asExpressionInfo.Success) { return; } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(asExpression); if (!localInfo.Success) { return; } if (localInfo.Statement.SpanOrTrailingTriviaContainsDirectives()) { return; } if (!(localInfo.Statement.NextStatement() is IfStatementSyntax ifStatement)) { return; } if (!ifStatement.IsSimpleIf()) { return; } if (ifStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } StatementSyntax statement = ifStatement.SingleNonBlockStatementOrDefault(); if (statement == null) { return; } if (!CSharpFacts.IsJumpStatement(statement.Kind())) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.EqualsToNull | NullCheckStyles.IsNull); if (!nullCheck.Success) { return; } if (!string.Equals(localInfo.IdentifierText, (nullCheck.Expression as IdentifierNameSyntax)?.Identifier.ValueText, StringComparison.Ordinal)) { return; } if (!localInfo.Type.IsVar) { SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(asExpressionInfo.Type, cancellationToken); if (typeSymbol.IsNullableType()) { return; } if (!SymbolEqualityComparer.Default.Equals(semanticModel.GetTypeSymbol(localInfo.Type, cancellationToken), typeSymbol)) { return; } } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UsePatternMatchingInsteadOfAsAndNullCheck, localInfo.Statement); }
private static void AnalyzeLogicalAndExpression(SyntaxNodeAnalysisContext context) { var logicalAnd = (BinaryExpressionSyntax)context.Node; if (logicalAnd.SpanContainsDirectives()) { return; } BinaryExpressionInfo logicalAndInfo = SyntaxInfo.BinaryExpressionInfo(logicalAnd); if (!logicalAndInfo.Success) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo( logicalAndInfo.Left, context.SemanticModel, NullCheckStyles.NotEqualsToNull | NullCheckStyles.HasValue, cancellationToken: context.CancellationToken); if (!nullCheck.Success) { return; } ExpressionSyntax right = logicalAndInfo.Right; switch (right.Kind()) { case SyntaxKind.LogicalNotExpression: { var logicalNot = (PrefixUnaryExpressionSyntax)right; Analyze(nullCheck.Expression, logicalNot.Operand?.WalkDownParentheses(), null); break; } case SyntaxKind.EqualsExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.GreaterThanOrEqualExpression: { BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)right); if (!binaryExpressionInfo.Success) { break; } ExpressionSyntax left = binaryExpressionInfo.Left; Analyze(nullCheck.Expression, left, binaryExpressionInfo.Right); break; } case SyntaxKind.SimpleMemberAccessExpression: { AnalyzeSimpleMemberAccessExpression(nullCheck.Expression, (MemberAccessExpressionSyntax)right, null); break; } } void Analyze(ExpressionSyntax expression1, ExpressionSyntax expression2, ExpressionSyntax expression3) { if (expression2.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { AnalyzeSimpleMemberAccessExpression(expression1, (MemberAccessExpressionSyntax)expression2, expression3); } } void AnalyzeSimpleMemberAccessExpression(ExpressionSyntax expression, MemberAccessExpressionSyntax memberAccessExpression, ExpressionSyntax expression3) { if (memberAccessExpression.Name is not IdentifierNameSyntax identifierName || !string.Equals(identifierName.Identifier.ValueText, "Value", StringComparison.Ordinal)) { return; } if (!SyntaxUtility.IsPropertyOfNullableOfT(memberAccessExpression, "Value", context.SemanticModel, context.CancellationToken)) { return; } if (!AreEquivalent(expression, memberAccessExpression.Expression)) { return; } if (expression3 != null) { switch (expression3.Kind()) { case SyntaxKind.NumericLiteralExpression: case SyntaxKind.StringLiteralExpression: case SyntaxKind.CharacterLiteralExpression: case SyntaxKind.TrueLiteralExpression: case SyntaxKind.FalseLiteralExpression: { break; } case SyntaxKind.NullLiteralExpression: case SyntaxKind.DefaultLiteralExpression: { return; } default: { if (context.SemanticModel.GetTypeSymbol(expression3, context.CancellationToken).IsNullableType()) { return; } break; } } } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UnnecessaryNullCheck, logicalAnd); } }
private static void Analyze(SyntaxNodeAnalysisContext context, SyntaxNode node, BlockSyntax body) { if (body == null) { return; } if (body.ContainsDiagnostics) { return; } SyntaxList <StatementSyntax> statements = body.Statements; if (statements.Count != 2) { return; } if (!(statements[0] is IfStatementSyntax ifStatement)) { return; } if (!(statements[1] is ReturnStatementSyntax returnStatement)) { return; } ExpressionSyntax returnExpression = returnStatement.Expression; if (returnExpression?.IsKind(SyntaxKind.IdentifierName, SyntaxKind.SimpleMemberAccessExpression) != true) { return; } if (ifStatement.SpanOrTrailingTriviaContainsDirectives()) { return; } if (returnStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } SimpleIfStatementInfo simpleIf = SyntaxInfo.SimpleIfStatementInfo(ifStatement); if (!simpleIf.Success) { return; } StatementSyntax statement = simpleIf.IfStatement.SingleNonBlockStatementOrDefault(); if (statement == null) { return; } SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(statement); if (!assignmentInfo.Success) { return; } if (!assignmentInfo.Left.IsKind(SyntaxKind.IdentifierName, SyntaxKind.SimpleMemberAccessExpression)) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(simpleIf.Condition, semanticModel: semanticModel, allowedStyles: NullCheckStyles.CheckingNull, cancellationToken: cancellationToken); if (!nullCheck.Success) { return; } ExpressionSyntax expression = nullCheck.Expression; if (!expression.IsKind(SyntaxKind.IdentifierName, SyntaxKind.SimpleMemberAccessExpression)) { return; } if (!(semanticModel.GetSymbol(expression, cancellationToken) is IFieldSymbol fieldSymbol)) { return; } if (!ExpressionEquals(expression, assignmentInfo.Left)) { return; } if (fieldSymbol.Type.IsNullableType() && returnExpression.Kind() == SyntaxKind.SimpleMemberAccessExpression) { var memberAccessExpression = (MemberAccessExpressionSyntax)returnExpression; if (memberAccessExpression.Name is IdentifierNameSyntax identifierName && string.Equals(identifierName.Identifier.ValueText, "Value", StringComparison.Ordinal)) { returnExpression = memberAccessExpression.Expression; } } if (!ExpressionEquals(expression, returnExpression)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyLazyInitialization, Location.Create(node.SyntaxTree, TextSpan.FromBounds(ifStatement.SpanStart, returnStatement.Span.End))); }