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) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddArgumentList)) { 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) && expression.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement)) { 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; } ModifiersCodeFixRegistrator.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); CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, expression, semanticModel); break; } case CompilerDiagnosticIdentifiers.ResultOfExpressionIsAlwaysConstantSinceValueIsNeverEqualToNull: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse)) { break; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(expression, allowedKinds: NullCheckKind.ComparisonToNull); if (!nullCheck.Success) { break; } CodeAction codeAction = CodeAction.Create( "Remove condition", cancellationToken => { cancellationToken.ThrowIfCancellationRequested(); 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.IsCodeFixEnabled(CodeFixIdentifiers.AddArgumentList) && expression.IsKind( SyntaxKind.IdentifierName, SyntaxKind.SimpleMemberAccessExpression)) { SyntaxNode invocationExpression = SyntaxFactory.InvocationExpression(expression); if (semanticModel.GetSpeculativeMethodSymbol(expression.SpanStart, invocationExpression) != null) { CodeAction codeAction = CodeAction.Create( "Add argument list", cancellationToken => context.Document.ReplaceNodeAsync(expression, invocationExpression, cancellationToken), GetEquivalenceKey(diagnostic, CodeFixIdentifiers.AddArgumentList)); context.RegisterCodeFix(codeAction, diagnostic); } } if (Settings.IsAnyCodeFixEnabled( CodeFixIdentifiers.IntroduceLocalVariable, CodeFixIdentifiers.IntroduceField)) { 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) && expression.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement)) { 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; } } } }
public static void AnalyzeUsingStatement(SyntaxNodeAnalysisContext context) { var usingStatement = (UsingStatementSyntax)context.Node; VariableDeclaratorSyntax declarator = usingStatement.Declaration?.Variables.SingleOrDefault(shouldThrow: false); if (declarator == null) { return; } if (!(usingStatement.Statement?.SingleNonBlockStatementOrDefault() is WhileStatementSyntax whileStatement)) { return; } SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(whileStatement.Condition); if (!invocationInfo.Success) { return; } if (invocationInfo.Arguments.Any()) { return; } if (!string.Equals(invocationInfo.NameText, WellKnownMemberNames.MoveNextMethodName, StringComparison.Ordinal)) { return; } if (!string.Equals((invocationInfo.Expression as IdentifierNameSyntax)?.Identifier.ValueText, declarator.Identifier.ValueText, StringComparison.Ordinal)) { return; } SimpleMemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.SimpleMemberInvocationExpressionInfo(declarator.Initializer.Value); if (!invocationInfo2.Success) { return; } if (invocationInfo2.Arguments.Any()) { return; } if (!string.Equals(invocationInfo2.NameText, WellKnownMemberNames.GetEnumeratorMethodName, StringComparison.Ordinal)) { return; } UnnecessaryUsageOfEnumeratorWalker walker = UnnecessaryUsageOfEnumeratorWalker.GetInstance(); walker.SetValues(declarator, context.SemanticModel, context.CancellationToken); walker.Visit(whileStatement.Statement); bool?isFixable = walker.IsFixable; UnnecessaryUsageOfEnumeratorWalker.Free(walker); if (isFixable == true) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UnnecessaryUsageOfEnumerator, usingStatement.UsingKeyword); } }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionOfTSymbol) { 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); ExpressionSyntax expression = nullCheck.Expression; if (expression == null) { return; } SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(ifStatement.SingleNonBlockStatementOrDefault()); ExpressionSyntax expression2 = invocationInfo.Expression; if (expression2 == null) { return; } ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(expression); if (typeSymbol == null) { return; } if (typeSymbol.IsNullableType()) { if (!expression2.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { return; } var memberAccess = (MemberAccessExpressionSyntax)expression2; if (!(memberAccess.Name is IdentifierNameSyntax identifierName)) { return; } if (!string.Equals(identifierName.Identifier.ValueText, "Value", StringComparison.Ordinal)) { return; } expression2 = memberAccess.Expression; } if (!CSharpFactory.AreEquivalent(expression, expression2)) { return; } if (ifStatement.IsInExpressionTree(expressionOfTSymbol, context.SemanticModel, context.CancellationToken)) { return; } context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, ifStatement); }
public static async Task <Document> RefactorAsync( Document document, ArgumentSyntax argument, MemberInvocationExpressionInfo invocationInfo, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); InvocationExpressionSyntax invocation = invocationInfo.InvocationExpression; InvocationExpressionSyntax newInvocation = null; bool isAppendLine = string.Equals(invocationInfo.NameText, "AppendLine", StringComparison.Ordinal); ExpressionSyntax expression = argument.Expression; switch (expression.Kind()) { case SyntaxKind.InterpolatedStringExpression: { newInvocation = ConvertInterpolatedStringExpressionToInvocationExpression((InterpolatedStringExpressionSyntax)argument.Expression, invocationInfo, semanticModel); break; } case SyntaxKind.AddExpression: { ImmutableArray <ExpressionSyntax> expressions = SyntaxInfo.BinaryExpressionChainInfo((BinaryExpressionSyntax)expression).Expressions; newInvocation = invocation .ReplaceNode(invocationInfo.Name, IdentifierName("Append").WithTriviaFrom(invocationInfo.Name)) .WithArgumentList(invocation.ArgumentList.WithArguments(SingletonSeparatedList(Argument(expressions[0]))).WithoutTrailingTrivia()); for (int i = 1; i < expressions.Length; i++) { ExpressionSyntax argumentExpression = expressions[i]; string methodName; if (i == expressions.Length - 1 && isAppendLine && semanticModel .GetTypeInfo(argumentExpression, cancellationToken) .ConvertedType? .SpecialType == SpecialType.System_String) { methodName = "AppendLine"; } else { methodName = "Append"; } newInvocation = SimpleMemberInvocationExpression( newInvocation, IdentifierName(methodName), ArgumentList(Argument(argumentExpression))); if (i == expressions.Length - 1 && isAppendLine && !string.Equals(methodName, "AppendLine", StringComparison.Ordinal)) { newInvocation = SimpleMemberInvocationExpression( newInvocation, IdentifierName("AppendLine"), ArgumentList()); } } break; } default: { newInvocation = CreateInvocationExpression( (InvocationExpressionSyntax)expression, invocation); if (isAppendLine) { newInvocation = SimpleMemberInvocationExpression(newInvocation, IdentifierName("AppendLine"), ArgumentList()); } break; } } newInvocation = newInvocation .WithTriviaFrom(invocation) .WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(invocation, newInvocation, cancellationToken).ConfigureAwait(false)); }
private static SingleLocalDeclarationStatementInfo GetLocalInfo(StatementSyntax statement) { return((statement.IsKind(SyntaxKind.LocalDeclarationStatement)) ? SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statement) : default);
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.IsSimpleIf()) { return; } StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); if (!statementsInfo.Success) { return; } ReturnStatementSyntax returnStatement = FindReturnStatementBelow(statementsInfo.Statements, ifStatement); ExpressionSyntax expression = returnStatement?.Expression; if (expression == null) { return; } if (ifStatement.SpanOrTrailingTriviaContainsDirectives()) { return; } if (returnStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ISymbol symbol = semanticModel.GetSymbol(expression, cancellationToken); if (symbol == null) { return; } if (!IsLocalDeclaredInScopeOrNonRefOrOutParameterOfEnclosingSymbol(symbol, statementsInfo.Parent, semanticModel, cancellationToken)) { return; } foreach (IfStatementOrElseClause ifOrElse in ifStatement.AsCascade()) { StatementSyntax statement = ifOrElse.Statement; if (statement.IsKind(SyntaxKind.Block)) { statement = ((BlockSyntax)statement).Statements.LastOrDefault(); } if (!IsSymbolAssignedInStatement(symbol, statement, semanticModel, cancellationToken)) { return; } } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseReturnInsteadOfAssignment, ifStatement); }
private static InterpolatedStringExpressionSyntax ReplaceInterpolationWithStringLiteralInnerText( SeparatedSyntaxList <ArgumentSyntax> arguments, InterpolatedStringExpressionSyntax interpolatedString, string text) { StringBuilder sb = StringBuilderCache.GetInstance(); int pos = 0; SyntaxList <InterpolatedStringContentSyntax> contents = interpolatedString.Contents; for (int i = 0; i < contents.Count; i++) { if (contents[i].Kind() != SyntaxKind.Interpolation) { continue; } var interpolation = (InterpolationSyntax)contents[i]; ExpressionSyntax expression = interpolation.Expression; if (expression?.Kind() != SyntaxKind.NumericLiteralExpression) { continue; } var index = (int)((LiteralExpressionSyntax)expression).Token.Value; if (index < 0) { continue; } if (index >= arguments.Count) { continue; } ExpressionSyntax argumentExpression = arguments[index + 1].Expression; StringLiteralExpressionInfo stringLiteral = SyntaxInfo.StringLiteralExpressionInfo(argumentExpression); if (!stringLiteral.Success) { continue; } sb.Append(text, pos, interpolation.SpanStart - pos); int startIndex = sb.Length; sb.Append(stringLiteral.InnerText); sb.Replace("{", "{{", startIndex); sb.Replace("}", "}}", startIndex); pos = interpolation.Span.End; } sb.Append(text, pos, text.Length - pos); return((InterpolatedStringExpressionSyntax)ParseExpression(StringBuilderCache.GetStringAndFree(sb))); }
public static async Task <Document> RefactorAsync( Document document, PropertyDeclarationSyntax propertyDeclaration, bool prefixIdentifierWithUnderscore = true, CancellationToken cancellationToken = default) { string fieldName = StringUtility.ToCamelCase( propertyDeclaration.Identifier.ValueText, prefixWithUnderscore: prefixIdentifierWithUnderscore); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); fieldName = NameGenerator.Default.EnsureUniqueName( fieldName, semanticModel, propertyDeclaration.SpanStart); FieldDeclarationSyntax fieldDeclaration = FieldDeclaration( (propertyDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword)) ? Modifiers.Private_Static() : Modifiers.Private(), propertyDeclaration.Type, fieldName, propertyDeclaration.Initializer).WithFormatterAnnotation(); IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken); PropertyDeclarationSyntax newPropertyDeclaration = ExpandAccessors(document, propertyDeclaration, propertySymbol, fieldName, semanticModel) .WithModifiers(propertyDeclaration.Modifiers.Replace(SyntaxKind.AbstractKeyword, SyntaxKind.VirtualKeyword)) .WithTriviaFrom(propertyDeclaration) .WithFormatterAnnotation(); MemberDeclarationListInfo membersInfo = SyntaxInfo.MemberDeclarationListInfo(propertyDeclaration.Parent); SyntaxList <MemberDeclarationSyntax> members = membersInfo.Members; int propertyIndex = membersInfo.IndexOf(propertyDeclaration); AccessorListSyntax accessorList = propertyDeclaration.AccessorList; if (accessorList?.Getter()?.IsAutoImplemented() == true && accessorList.Setter() == null) { ImmutableArray <SyntaxNode> nodes = await SyntaxFinder.FindReferencesAsync(propertySymbol, document, cancellationToken : cancellationToken).ConfigureAwait(false); IdentifierNameSyntax newNode = IdentifierName(fieldName); SyntaxNode newParent = membersInfo.Parent.ReplaceNodes(nodes, (node, _) => { if (node.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) && ((MemberAccessExpressionSyntax)node.Parent).Expression.IsKind(SyntaxKind.BaseExpression)) { return(node); } return(newNode.WithTriviaFrom(node)); }); MemberDeclarationListInfo newMembersInfo = SyntaxInfo.MemberDeclarationListInfo(newParent); members = newMembersInfo.Members; } SyntaxList <MemberDeclarationSyntax> newMembers = members.ReplaceAt(propertyIndex, newPropertyDeclaration); newMembers = MemberDeclarationInserter.Default.Insert(newMembers, fieldDeclaration); return(await document.ReplaceMembersAsync(membersInfo, newMembers, cancellationToken).ConfigureAwait(false)); }
private 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) && ((CSharpCompilation)context.Compilation).LanguageVersion >= LanguageVersion.CSharp6 && 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 void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context, INamedTypeSymbol eventArgsSymbol) { var methodDeclaration = (MethodDeclarationSyntax)context.Node; if (methodDeclaration.ContainsDiagnostics) { return; } if (methodDeclaration.IsParentKind(SyntaxKind.InterfaceDeclaration)) { return; } if (methodDeclaration.Modifiers.ContainsAny(SyntaxKind.AbstractKeyword, SyntaxKind.VirtualKeyword, SyntaxKind.OverrideKeyword)) { return; } ParameterInfo parameterInfo = SyntaxInfo.ParameterInfo(methodDeclaration); if (!parameterInfo.Success) { return; } if (ContainsOnlyThrowNewExpression(parameterInfo.Body)) { return; } IMethodSymbol methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken); if (methodSymbol == null) { return; } if (SymbolUtility.IsEventHandlerMethod(methodSymbol, eventArgsSymbol)) { return; } if (!methodSymbol.ExplicitInterfaceImplementations.IsDefaultOrEmpty) { return; } if (methodSymbol.ImplementsInterfaceMember(allInterfaces: true)) { return; } Dictionary <string, NodeSymbolInfo> unusedNodes = FindUnusedNodes(context, parameterInfo); if (unusedNodes.Count == 0) { return; } if (IsReferencedAsMethodGroup(context, methodDeclaration)) { return; } foreach (KeyValuePair <string, NodeSymbolInfo> kvp in unusedNodes) { ReportDiagnostic(context, kvp.Value.Node); } unusedNodes.Clear(); }
public static async Task ComputeRefactoringAsync( RefactoringContext context, PropertyDeclarationSyntax property) { AccessorDeclarationSyntax setter = property.Setter(); if (setter == null) { return; } ExpressionSyntax expression = GetExpression(); if (expression == null) { return; } SimpleAssignmentExpressionInfo simpleAssignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression); if (!simpleAssignment.Success) { return; } if (!simpleAssignment.Left.IsKind(SyntaxKind.IdentifierName)) { return; } if (!(simpleAssignment.Right is IdentifierNameSyntax identifierName)) { return; } if (identifierName.Identifier.ValueText != "value") { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); INamedTypeSymbol containingType = semanticModel .GetDeclaredSymbol(property, context.CancellationToken)? .ContainingType; if (containingType == null) { return; } if (!containingType.Implements(MetadataNames.System_ComponentModel_INotifyPropertyChanged, allInterfaces: true)) { return; } IMethodSymbol methodSymbol = SymbolUtility.FindMethodThatRaisePropertyChanged(containingType, expression.SpanStart, semanticModel); if (methodSymbol == null) { return; } Document document = context.Document; context.RegisterRefactoring( "Notify when property change", ct => RefactorAsync(document, property, methodSymbol.Name, ct), RefactoringIdentifiers.NotifyWhenPropertyChange); ExpressionSyntax GetExpression() { BlockSyntax body = setter.Body; if (body != null) { if (body.Statements.SingleOrDefault(shouldThrow: false) is ExpressionStatementSyntax expressionStatement) { return(expressionStatement.Expression); } } else { return(setter.ExpressionBody?.Expression); } return(null); } }
public static async Task <Document> InvertIfAsync( Document document, IfStatementSyntax ifStatement, bool recursive = false, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); StatementSyntax statement = ifStatement.Statement; StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; InvertIfAnalysis analysis = InvertIfAnalysis.Create(ifStatement, statement); int ifStatementIndex = statements.IndexOf(ifStatement); StatementSyntax lastStatement = analysis.LastStatement; int lastStatementIndex = statements.IndexOf(lastStatement); bool isLastStatementRedundant = IsLastStatementRedundant(); bool shouldUseElseClause = !CSharpFacts.IsJumpStatement(lastStatement.Kind()); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); SyntaxList <StatementSyntax> newStatements = statements; if (!recursive) { Refactor(); } else { IfStatementSyntax lastIfStatement; InvertIfAnalysis a = analysis.AnalyzeNextStatement(); do { lastIfStatement = a.IfStatement; a = a.AnalyzeNextStatement(); } while (a.Success); int firstLastStatementIndex = lastStatementIndex; int index = statements.IndexOf(lastIfStatement); int firstIndex = ifStatementIndex; while (index >= firstIndex) { ifStatementIndex = index; ifStatement = (IfStatementSyntax)statements[ifStatementIndex]; statement = ifStatement.Statement; Refactor(); lastStatementIndex = firstLastStatementIndex + newStatements.Count - statements.Count; lastStatement = (statement is BlockSyntax block) ? block.Statements.Last() : statement; index--; } } return(await document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken).ConfigureAwait(false)); void Refactor() { cancellationToken.ThrowIfCancellationRequested(); SyntaxList <StatementSyntax> nextStatements = newStatements .Skip(ifStatementIndex + 1) .Take(lastStatementIndex - ifStatementIndex) .ToSyntaxList() .TrimTrivia(); BlockSyntax newStatement; SyntaxList <StatementSyntax> newNextStatements; if (statement is BlockSyntax block) { newStatement = block.WithStatements(nextStatements); newNextStatements = block.Statements; } else { newStatement = Block(nextStatements); newNextStatements = SingletonList(statement); } if (isLastStatementRedundant) { newNextStatements = newNextStatements.RemoveAt(newNextStatements.Count - 1); } ElseClauseSyntax elseClause = null; if (newNextStatements.Any() && shouldUseElseClause) { elseClause = ElseClause(Block(newNextStatements)); newNextStatements = default; } IfStatementSyntax newIfStatement = ifStatement.Update( ifKeyword: ifStatement.IfKeyword, openParenToken: ifStatement.OpenParenToken, condition: SyntaxInverter.LogicallyInvert(ifStatement.Condition, semanticModel, cancellationToken), closeParenToken: ifStatement.CloseParenToken, statement: newStatement, @else: elseClause); newIfStatement = newIfStatement.WithFormatterAnnotation(); SyntaxList <StatementSyntax> newNodes = newNextStatements.Insert(0, newIfStatement); newStatements = newStatements.ReplaceRange(ifStatementIndex, lastStatementIndex - ifStatementIndex + 1, newNodes); } bool IsLastStatementRedundant() { StatementSyntax jumpStatement = analysis.JumpStatement; switch (jumpStatement.Kind()) { case SyntaxKind.ReturnStatement: { if (((ReturnStatementSyntax)jumpStatement).Expression == null && RemoveRedundantStatementAnalysis.IsFixable(lastStatement, SyntaxKind.ReturnStatement)) { return(true); } break; } case SyntaxKind.ContinueStatement: { if (RemoveRedundantStatementAnalysis.IsFixable(lastStatement, SyntaxKind.ContinueStatement)) { return(true); } break; } } return(false); } }
public static async Task <Document> RefactorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync().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; ExpressionSyntax expression = (whenNotNull.IsKind(SyntaxKind.CastExpression)) ? UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, ((CastExpressionSyntax)whenNotNull).Expression) : UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull); bool 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 (newNode == null) { newNode = ParseExpression(whenNotNull.ToString().Insert(expression.Span.End - whenNotNull.SpanStart, "?")); } if (coalesce || !semanticModel.GetTypeSymbol(whenNotNull, cancellationToken).IsReferenceTypeOrNullableType()) { 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; 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 (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 sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out TypeParameterConstraintSyntax constraint)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.NewConstraintMustBeLastConstraintSpecified: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MoveConstraint)) { break; } TypeParameterConstraintInfo constraintInfo = SyntaxInfo.TypeParameterConstraintInfo(constraint); if (!constraintInfo.Success) { break; } MoveConstraint(context, diagnostic, constraintInfo, constraintInfo.Constraints.Count - 1); break; } case CompilerDiagnosticIdentifiers.DuplicateConstraintForTypeParameter: { if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConstraint)) { RemoveConstraint(context, diagnostic, constraint); } break; } case CompilerDiagnosticIdentifiers.ClassOrStructConstraintMustComeBeforeAnyOtherConstraints: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MoveConstraint)) { break; } TypeParameterConstraintInfo constraintInfo = SyntaxInfo.TypeParameterConstraintInfo(constraint); if (!constraintInfo.Success) { break; } if (constraintInfo.IsDuplicateConstraint) { RemoveConstraint(context, diagnostic, constraint); } else { MoveConstraint(context, diagnostic, constraintInfo, 0); } break; } case CompilerDiagnosticIdentifiers.CannotSpecifyBothConstraintClassAndClassOrStructConstraint: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConstraint)) { break; } TypeParameterConstraintInfo constraintInfo = SyntaxInfo.TypeParameterConstraintInfo(constraint); if (!constraintInfo.Success) { break; } RemoveConstraint(context, diagnostic, constraint); TypeParameterConstraintSyntax classConstraint = constraintInfo.Constraints.Find(SyntaxKind.ClassConstraint); if (classConstraint != null) { RemoveConstraint(context, diagnostic, classConstraint); } TypeParameterConstraintSyntax structConstraint = constraintInfo.Constraints.Find(SyntaxKind.StructConstraint); if (structConstraint != null) { RemoveConstraint(context, diagnostic, structConstraint); } break; } case CompilerDiagnosticIdentifiers.NewConstraintCannotBeUsedWithStructConstraint: { if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConstraint)) { break; } RemoveConstraint(context, diagnostic, constraint); TypeParameterConstraintInfo constraintInfo = SyntaxInfo.TypeParameterConstraintInfo(constraint); if (!constraintInfo.Success) { break; } TypeParameterConstraintSyntax structConstraint = constraintInfo.Constraints.Find(SyntaxKind.StructConstraint); RemoveConstraint(context, diagnostic, structConstraint); break; } } } }
public static void AnalyzeLocalDeclarationStatement(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } var localDeclaration = (LocalDeclarationStatementSyntax)context.Node; if (localDeclaration.IsConst) { return; } StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(localDeclaration); if (!statementsInfo.Success) { return; } SyntaxList <StatementSyntax> statements = statementsInfo.Statements; if (statements.Count <= 1) { return; } int index = statements.IndexOf(localDeclaration); if (index == statements.Count - 1) { return; } LocalDeclarationStatementInfo localInfo = SyntaxInfo.LocalDeclarationStatementInfo(localDeclaration); if (!localInfo.Success) { return; } ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(localInfo.Type, context.CancellationToken); if (typeSymbol?.SupportsConstantValue() != true) { return; } foreach (VariableDeclaratorSyntax declarator in localInfo.Variables) { if (!HasConstantValue(declarator.Initializer?.Value, typeSymbol, context.SemanticModel, context.CancellationToken)) { return; } } if (!CanBeMarkedAsConst(localInfo.Variables, statements, index + 1)) { return; } context.ReportDiagnostic(DiagnosticDescriptors.MarkLocalVariableAsConst, localInfo.Type); }
public static void AnalyzeSwitchStatement(SyntaxNodeAnalysisContext context) { var switchStatement = (SwitchStatementSyntax)context.Node; StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(switchStatement); if (!statementsInfo.Success) { return; } ReturnStatementSyntax returnStatement = FindReturnStatementBelow(statementsInfo.Statements, switchStatement); ExpressionSyntax expression = returnStatement?.Expression; if (expression == null) { return; } if (switchStatement.SpanOrTrailingTriviaContainsDirectives()) { return; } if (returnStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ISymbol symbol = semanticModel.GetSymbol(expression, cancellationToken); if (symbol == null) { return; } if (!IsLocalDeclaredInScopeOrNonRefOrOutParameterOfEnclosingSymbol(symbol, statementsInfo.Parent, semanticModel, cancellationToken)) { return; } foreach (SwitchSectionSyntax section in switchStatement.Sections) { SyntaxList <StatementSyntax> statements = section.GetStatements(); if (statements.Count <= 1) { return; } if (!statements.Last().IsKind(SyntaxKind.BreakStatement)) { return; } if (!IsSymbolAssignedInStatement(symbol, statements[statements.Count - 2], semanticModel, cancellationToken)) { return; } } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseReturnInsteadOfAssignment, switchStatement); }
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 bool CanRefactor(SyntaxNode node) { return(node.IsKind(SyntaxKind.LogicalAndExpression, SyntaxKind.LogicalOrExpression) && SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)node).Success); }
public static async Task ComputeRefactoringsAsync(RefactoringContext context, InvocationExpressionSyntax invocation) { SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation); if (!invocationInfo.Success) { return; } switch (invocationInfo.NameText) { case "First": { if (invocationInfo.Arguments.Any()) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!UseElementAccessAnalysis.IsFixableFirst(invocationInfo, semanticModel, context.CancellationToken)) { break; } context.RegisterRefactoring( "Use [] instead of calling 'First'", cancellationToken => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfFirstAsync(context.Document, invocation, cancellationToken), RefactoringIdentifiers.UseElementAccessInsteadOfEnumerableMethod); break; } case "Last": { if (invocationInfo.Arguments.Any()) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!UseElementAccessAnalysis.IsFixableLast(invocationInfo, semanticModel, context.CancellationToken)) { break; } string propertyName = CSharpUtility.GetCountOrLengthPropertyName(invocationInfo.Expression, semanticModel, context.CancellationToken); if (propertyName == null) { break; } context.RegisterRefactoring( "Use [] instead of calling 'Last'", cancellationToken => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfLastAsync(context.Document, invocation, propertyName, cancellationToken), RefactoringIdentifiers.UseElementAccessInsteadOfEnumerableMethod); break; } case "ElementAt": { if (invocationInfo.Arguments.SingleOrDefault(shouldThrow: false)?.Expression?.IsMissing != false) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!UseElementAccessAnalysis.IsFixableElementAt(invocationInfo, semanticModel, context.CancellationToken)) { break; } context.RegisterRefactoring( "Use [] instead of calling 'ElementAt'", cancellationToken => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfElementAtAsync(context.Document, invocation, cancellationToken), RefactoringIdentifiers.UseElementAccessInsteadOfEnumerableMethod); break; } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out InvocationExpressionSyntax invocation)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.CombineEnumerableWhereMethodChain: { CodeAction codeAction = CodeAction.Create( "Combine 'Where' method chain", cancellationToken => CombineEnumerableWhereMethodChainRefactoring.RefactorAsync(context.Document, invocation, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseCountOrLengthPropertyInsteadOfAnyMethod: { string propertyName = diagnostic.Properties["PropertyName"]; CodeAction codeAction = CodeAction.Create( $"Use '{propertyName}' property instead of calling 'Any'", cancellationToken => UseCountOrLengthPropertyInsteadOfAnyMethodRefactoring.RefactorAsync(context.Document, invocation, propertyName, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseCountOrLengthPropertyInsteadOfCountMethod: { string propertyName = diagnostic.Properties["PropertyName"]; CodeAction codeAction = CodeAction.Create( $"Use '{propertyName}' property instead of calling 'Count'", cancellationToken => UseCountOrLengthPropertyInsteadOfCountMethodRefactoring.RefactorAsync(context.Document, invocation, diagnostic.Properties["PropertyName"], cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseBitwiseOperationInsteadOfCallingHasFlag: { CodeAction codeAction = CodeAction.Create( UseBitwiseOperationInsteadOfCallingHasFlagRefactoring.Title, cancellationToken => UseBitwiseOperationInsteadOfCallingHasFlagRefactoring.RefactorAsync(context.Document, invocation, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantToStringCall: { CodeAction codeAction = CodeAction.Create( "Remove redundant 'ToString' call", cancellationToken => context.Document.ReplaceNodeAsync(invocation, RefactoringUtility.RemoveInvocation(invocation).WithFormatterAnnotation(), cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.CallCastInsteadOfSelect: { CodeAction codeAction = CodeAction.Create( "Call 'Cast' instead of 'Select'", cancellationToken => CallCastInsteadOfSelectRefactoring.RefactorAsync(context.Document, invocation, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantStringToCharArrayCall: { CodeAction codeAction = CodeAction.Create( "Remove redundant 'ToCharArray' call", cancellationToken => context.Document.ReplaceNodeAsync(invocation, RefactoringUtility.RemoveInvocation(invocation).WithFormatterAnnotation(), cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.CallFindInsteadOfFirstOrDefault: { CodeAction codeAction = CodeAction.Create( "Call 'Find' instead of 'FirstOrDefault'", cancellationToken => CallFindInsteadOfFirstOrDefaultRefactoring.RefactorAsync(context.Document, invocation, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseElementAccessInsteadOfElementAt: { CodeAction codeAction = CodeAction.Create( "Use [] instead of calling 'ElementAt'", cancellationToken => UseElementAccessInsteadOfElementAtRefactoring.RefactorAsync(context.Document, invocation, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseElementAccessInsteadOfFirst: { CodeAction codeAction = CodeAction.Create( "Use [] instead of calling 'First'", cancellationToken => UseElementAccessInsteadOfFirstRefactoring.RefactorAsync(context.Document, invocation, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.CallStringConcatInsteadOfStringJoin: { CodeAction codeAction = CodeAction.Create( "Call 'Concat' instead of 'Join'", cancellationToken => CallStringConcatInsteadOfStringJoinRefactoring.RefactorAsync(context.Document, invocation, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.CallDebugFailInsteadOfDebugAssert: { CodeAction codeAction = CodeAction.Create( "Call 'Fail' instead of 'Assert'", cancellationToken => CallDebugFailInsteadOfDebugAssertRefactoring.RefactorAsync(context.Document, invocation, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.CallExtensionMethodAsInstanceMethod: { CodeAction codeAction = CodeAction.Create( CallExtensionMethodAsInstanceMethodRefactoring.Title, cancellationToken => CallExtensionMethodAsInstanceMethodRefactoring.RefactorAsync(context.Document, invocation, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.CallThenByInsteadOfOrderBy: { SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation); string oldName = invocationInfo.NameText; string newName = (string.Equals(oldName, "OrderBy", StringComparison.Ordinal)) ? "ThenBy" : "ThenByDescending"; CodeAction codeAction = CodeAction.Create( $"Call '{newName}' instead of '{oldName}'", cancellationToken => CallThenByInsteadOfOrderByRefactoring.RefactorAsync(context.Document, invocation, newName, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
internal static bool IsFixable( PropertyDeclarationSyntax propertyDeclaration, AccessorDeclarationSyntax accessor, SemanticModel semanticModel, CancellationToken cancellationToken) { switch (accessor.Kind()) { case SyntaxKind.GetAccessorDeclaration: { ExpressionSyntax expression = GetGetAccessorExpression(accessor); if (expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) != true) { return(false); } var memberAccess = (MemberAccessExpressionSyntax)expression; if (memberAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true) { return(false); } SimpleNameSyntax simpleName = memberAccess.Name; IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken); if (propertySymbol == null) { return(false); } IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty; if (overriddenProperty == null) { return(false); } ISymbol symbol = semanticModel.GetSymbol(simpleName, cancellationToken); return(overriddenProperty.Equals(symbol)); } case SyntaxKind.SetAccessorDeclaration: { ExpressionSyntax expression = GetSetAccessorExpression(accessor); SimpleAssignmentExpressionInfo assignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression); if (!assignment.Success) { return(false); } if (assignment.Left.Kind() != SyntaxKind.SimpleMemberAccessExpression) { return(false); } var memberAccess = (MemberAccessExpressionSyntax)assignment.Left; if (memberAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true) { return(false); } if (assignment.Right.Kind() != SyntaxKind.IdentifierName) { return(false); } var identifierName = (IdentifierNameSyntax)assignment.Right; if (identifierName.Identifier.ValueText != "value") { return(false); } SimpleNameSyntax simpleName = memberAccess.Name; if (simpleName == null) { return(false); } IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken); if (propertySymbol == null) { return(false); } IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty; if (overriddenProperty == null) { return(false); } ISymbol symbol = semanticModel.GetSymbol(simpleName, cancellationToken); return(overriddenProperty.Equals(symbol)); } case SyntaxKind.UnknownAccessorDeclaration: { return(false); } default: { Debug.Fail(accessor.Kind().ToString()); return(false); } } }
public static void Analyze(SyntaxNodeAnalysisContext context, MemberInvocationExpressionInfo invocationInfo) { INamedTypeSymbol stringBuilderSymbol = context.GetTypeByMetadataName(MetadataNames.System_Text_StringBuilder); if (stringBuilderSymbol != null) { InvocationExpressionSyntax invocationExpression = invocationInfo.InvocationExpression; if (context.SemanticModel.TryGetMethodInfo(invocationExpression, out MethodInfo methodInfo, context.CancellationToken) && !methodInfo.IsExtensionMethod && methodInfo.ContainingType?.Equals(stringBuilderSymbol) == true) { ImmutableArray <IParameterSymbol> parameters = methodInfo.Parameters; SeparatedSyntaxList <ArgumentSyntax> arguments = invocationInfo.Arguments; if (parameters.Length == 1 && arguments.Count == 1 && methodInfo.IsName("Append", "AppendLine")) { ArgumentSyntax argument = arguments.First(); ExpressionSyntax expression = argument.Expression; SyntaxKind expressionKind = expression.Kind(); switch (expressionKind) { case SyntaxKind.InterpolatedStringExpression: { context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodInfo.Name); return; } case SyntaxKind.AddExpression: { StringConcatenationExpressionInfo concatenationInfo = SyntaxInfo.StringConcatenationExpressionInfo((BinaryExpressionSyntax)expression, context.SemanticModel, context.CancellationToken); if (concatenationInfo.Success) { context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodInfo.Name); return; } break; } default: { if (expressionKind == SyntaxKind.InvocationExpression && IsFixable((InvocationExpressionSyntax)expression, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodInfo.Name); return; } if (methodInfo.IsName("Append") && parameters.Length == 1 && parameters[0].Type.IsObject() && context.SemanticModel.GetTypeSymbol(argument.Expression, context.CancellationToken).IsValueType) { context.ReportDiagnostic(DiagnosticDescriptors.AvoidBoxingOfValueType, argument); return; } break; } } } else if (parameters.Length > 1 && methodInfo.IsName("Insert") && methodInfo.HasParameters(SpecialType.System_Int32, SpecialType.System_Object) && context.SemanticModel .GetTypeSymbol(arguments[1].Expression, context.CancellationToken) .IsValueType) { context.ReportDiagnostic(DiagnosticDescriptors.AvoidBoxingOfValueType, arguments[1]); } } } }
private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context) { var methodDeclaration = (MethodDeclarationSyntax)context.Node; if (methodDeclaration.ContainsDirectives) { return; } if (methodDeclaration.ContainsDiagnostics) { return; } if (methodDeclaration.AttributeLists.Any()) { return; } if (!CheckModifiers(methodDeclaration.Modifiers)) { return; } if (methodDeclaration.HasDocumentationComment()) { return; } if (!methodDeclaration.DescendantTrivia(methodDeclaration.Span).All(f => f.IsWhitespaceOrEndOfLineTrivia())) { return; } ExpressionSyntax expression = GetMethodExpression(methodDeclaration); SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(expression); if (!invocationInfo.Success) { return; } if (invocationInfo.Expression.Kind() != SyntaxKind.BaseExpression) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, cancellationToken); if (methodSymbol == null) { return; } IMethodSymbol overriddenMethod = methodSymbol.OverriddenMethod; if (overriddenMethod == null) { return; } ISymbol symbol = semanticModel.GetSymbol(invocationInfo.Name, cancellationToken); if (!overriddenMethod.Equals(symbol)) { return; } if (!CheckParameters(methodDeclaration.ParameterList, invocationInfo.ArgumentList, semanticModel, cancellationToken)) { return; } if (!CheckDefaultValues(methodSymbol.Parameters, overriddenMethod.Parameters)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.RemoveRedundantOverridingMember, methodDeclaration, CSharpFacts.GetTitle(methodDeclaration)); }
private static void AnalyzeWhileStatement(SyntaxNodeAnalysisContext context) { var whileStatement = (WhileStatementSyntax)context.Node; ExpressionSyntax condition = whileStatement.Condition; if (condition.IsMissing) { return; } if (!condition.IsSingleLine()) { return; } StatementSyntax statement = whileStatement.Statement; if (!(statement is BlockSyntax block)) { return; } SyntaxList <StatementSyntax> innerStatements = block.Statements; if (innerStatements.Count <= 1) { return; } ExpressionSyntax incrementedExpression = GetIncrementedExpression(innerStatements.Last()); if (!incrementedExpression.IsKind(SyntaxKind.IdentifierName)) { return; } SyntaxList <StatementSyntax> outerStatements = SyntaxInfo.StatementListInfo(whileStatement).Statements; int index = outerStatements.IndexOf(whileStatement); if (index <= 0) { return; } SingleLocalDeclarationStatementInfo localInfo = GetLocalInfo(outerStatements[index - 1]); if (!localInfo.Success) { return; } if (index > 1) { SingleLocalDeclarationStatementInfo localInfo2 = GetLocalInfo(outerStatements[index - 2]); if (localInfo2.Success) { ExpressionSyntax incrementedExpression2 = GetIncrementedExpression(innerStatements[innerStatements.Count - 2]); if (incrementedExpression2 is IdentifierNameSyntax identifierName2 && string.Equals(localInfo2.Identifier.ValueText, identifierName2.Identifier.ValueText, StringComparison.Ordinal)) { return; } } } var identifierName = (IdentifierNameSyntax)incrementedExpression; if (!string.Equals(localInfo.Identifier.ValueText, identifierName.Identifier.ValueText, StringComparison.Ordinal)) { return; } if (ContainsContinueStatement()) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ISymbol symbol = semanticModel.GetDeclaredSymbol(localInfo.Declarator, cancellationToken); if (symbol?.Kind != SymbolKind.Local) { return; } if (IsLocalVariableReferencedAfterWhileStatement()) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseForStatementInsteadOfWhileStatement, whileStatement.WhileKeyword); bool ContainsContinueStatement() { ContainsContinueStatementWalker walker = ContainsContinueStatementWalker.GetInstance(); walker.ContainsContinueStatement = false; var containsContinueStatement = false; foreach (StatementSyntax innerStatement in innerStatements) { walker.Visit(innerStatement); if (walker.ContainsContinueStatement) { containsContinueStatement = true; break; } } ContainsContinueStatementWalker.Free(walker); return(containsContinueStatement); } bool IsLocalVariableReferencedAfterWhileStatement() { ContainsLocalOrParameterReferenceWalker walker = ContainsLocalOrParameterReferenceWalker.GetInstance(symbol, semanticModel, cancellationToken); walker.VisitList(outerStatements, index + 1); return(ContainsLocalOrParameterReferenceWalker.GetResultAndFree(walker)); } }
internal static bool IsFixable( IndexerDeclarationSyntax indexerDeclaration, AccessorDeclarationSyntax accessor, SemanticModel semanticModel, CancellationToken cancellationToken) { switch (accessor.Kind()) { case SyntaxKind.GetAccessorDeclaration: { ExpressionSyntax expression = GetGetAccessorExpression(accessor); if (!(expression is ElementAccessExpressionSyntax elementAccess)) { return(false); } if (elementAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true) { return(false); } if (elementAccess.ArgumentList == null) { return(false); } IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(indexerDeclaration, cancellationToken); if (propertySymbol == null) { return(false); } IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty; if (overriddenProperty == null) { return(false); } ISymbol symbol = semanticModel.GetSymbol(elementAccess, cancellationToken); return(overriddenProperty.Equals(symbol) && CheckParameters(indexerDeclaration.ParameterList, elementAccess.ArgumentList, semanticModel, cancellationToken) && CheckDefaultValues(propertySymbol.Parameters, overriddenProperty.Parameters)); } case SyntaxKind.SetAccessorDeclaration: { ExpressionSyntax expression = GetSetAccessorExpression(accessor); SimpleAssignmentExpressionInfo assignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression); if (!assignment.Success) { return(false); } if (assignment.Left.Kind() != SyntaxKind.ElementAccessExpression) { return(false); } var elementAccess = (ElementAccessExpressionSyntax)assignment.Left; if (elementAccess.Expression?.IsKind(SyntaxKind.BaseExpression) != true) { return(false); } if (elementAccess.ArgumentList == null) { return(false); } if (assignment.Right.Kind() != SyntaxKind.IdentifierName) { return(false); } var identifierName = (IdentifierNameSyntax)assignment.Right; if (identifierName.Identifier.ValueText != "value") { return(false); } IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(indexerDeclaration, cancellationToken); if (propertySymbol == null) { return(false); } IPropertySymbol overriddenProperty = propertySymbol.OverriddenProperty; if (overriddenProperty == null) { return(false); } ISymbol symbol = semanticModel.GetSymbol(elementAccess, cancellationToken); return(overriddenProperty.Equals(symbol) && CheckParameters(indexerDeclaration.ParameterList, elementAccess.ArgumentList, semanticModel, cancellationToken) && CheckDefaultValues(propertySymbol.Parameters, overriddenProperty.Parameters)); } case SyntaxKind.UnknownAccessorDeclaration: { return(false); } default: { Debug.Fail(accessor.Kind().ToString()); return(false); } } }
private static ReduceIfNestingAnalysisResult AnalyzeCore( IfStatementSyntax ifStatement, SemanticModel semanticModel, SyntaxKind jumpKind, ReduceIfNestingOptions options, INamedTypeSymbol taskSymbol = null, CancellationToken cancellationToken = default(CancellationToken)) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); if (!statementsInfo.Success) { return(Fail(ifStatement)); } SyntaxNode node = statementsInfo.Parent; SyntaxNode parent = node.Parent; SyntaxKind parentKind = parent.Kind(); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; if (statementsInfo.IsParentSwitchSection || parentKind == SyntaxKind.SwitchSection) { SyntaxNode switchSection = (statementsInfo.IsParentSwitchSection) ? node : parent; if (!options.AllowSwitchSection()) { return(Fail(switchSection)); } if (ifStatement != statements.LastButOneOrDefault()) { return(Fail(switchSection)); } if (!IsFixableJumpStatement(statements.Last(), ref jumpKind)) { return(Fail(switchSection)); } if (!options.AllowNestedFix() && IsNestedFix(switchSection.Parent, semanticModel, options, taskSymbol, cancellationToken)) { return(Fail(switchSection)); } return(Success(jumpKind, switchSection)); } if (parentKind.Is( SyntaxKind.ForStatement, SyntaxKind.ForEachStatement, SyntaxKind.DoStatement, SyntaxKind.WhileStatement)) { if (!options.AllowLoop()) { return(Fail(parent)); } StatementSyntax lastStatement = statements.Last(); if (ifStatement == lastStatement) { jumpKind = SyntaxKind.ContinueStatement; } else { if (ifStatement != statements.LastButOneOrDefault()) { return(Fail(parent)); } if (!IsFixableJumpStatement(lastStatement, ref jumpKind)) { return(Fail(parent)); } } if (!options.AllowNestedFix() && IsNestedFix(parent.Parent, semanticModel, options, taskSymbol, cancellationToken)) { return(Fail(parent)); } return(Success(jumpKind, parent)); } if (!IsFixable(ifStatement, statements, ref jumpKind)) { return(Fail(node)); } switch (parentKind) { case SyntaxKind.ConstructorDeclaration: case SyntaxKind.DestructorDeclaration: case SyntaxKind.SetAccessorDeclaration: case SyntaxKind.AddAccessorDeclaration: case SyntaxKind.RemoveAccessorDeclaration: { if (jumpKind == SyntaxKind.None) { jumpKind = SyntaxKind.ReturnStatement; } else if (jumpKind != SyntaxKind.ReturnStatement) { return(Fail(parent)); } return(Success(jumpKind, parent)); } case SyntaxKind.OperatorDeclaration: case SyntaxKind.ConversionOperatorDeclaration: case SyntaxKind.GetAccessorDeclaration: { if (jumpKind == SyntaxKind.None) { return(Fail(parent)); } return(Success(jumpKind, parent)); } case SyntaxKind.MethodDeclaration: { var methodDeclaration = (MethodDeclarationSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } if (methodDeclaration.ReturnsVoid()) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (methodDeclaration.Modifiers.Contains(SyntaxKind.AsyncKeyword) && taskSymbol != null && semanticModel .GetDeclaredSymbol(methodDeclaration, cancellationToken)? .ReturnType .Equals(taskSymbol) == true) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (semanticModel .GetDeclaredSymbol(methodDeclaration, cancellationToken)? .ReturnType .OriginalDefinition .IsIEnumerableOrIEnumerableOfT() == true && methodDeclaration.ContainsYield()) { return(Success(SyntaxKind.YieldBreakStatement, parent)); } break; } case SyntaxKind.LocalFunctionStatement: { var localFunction = (LocalFunctionStatementSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } if (localFunction.ReturnsVoid()) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (localFunction.Modifiers.Contains(SyntaxKind.AsyncKeyword) && taskSymbol != null && semanticModel.GetDeclaredSymbol(localFunction, cancellationToken)? .ReturnType .Equals(taskSymbol) == true) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (semanticModel.GetDeclaredSymbol(localFunction, cancellationToken)? .ReturnType .OriginalDefinition .IsIEnumerableOrIEnumerableOfT() == true && localFunction.ContainsYield()) { return(Success(SyntaxKind.YieldBreakStatement, parent)); } break; } case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.ParenthesizedLambdaExpression: { var anonymousFunction = (AnonymousFunctionExpressionSyntax)parent; if (jumpKind != SyntaxKind.None) { return(Success(jumpKind, parent)); } var methodSymbol = semanticModel.GetSymbol(anonymousFunction, cancellationToken) as IMethodSymbol; if (methodSymbol == null) { return(Fail(parent)); } if (methodSymbol.ReturnsVoid) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (anonymousFunction.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword && methodSymbol.ReturnType.Equals(taskSymbol)) { return(Success(SyntaxKind.ReturnStatement, parent)); } break; } case SyntaxKind.IfStatement: { ifStatement = (IfStatementSyntax)parent; if (ifStatement.Parent is ElseClauseSyntax elseClause) { if (ifStatement.Else != null) { return(Fail(parent)); } if (!options.AllowIfInsideIfElse()) { return(Fail(parent)); } return(AnalyzeCore(ifStatement.GetTopmostIf(), semanticModel, jumpKind, options, taskSymbol, cancellationToken)); } else { if (!IsFixable(ifStatement)) { return(Fail(parent)); } if (!options.AllowNestedFix()) { return(Fail(parent)); } return(AnalyzeCore(ifStatement, semanticModel, jumpKind, options, taskSymbol, cancellationToken)); } } case SyntaxKind.ElseClause: { if (!options.AllowIfInsideIfElse()) { return(Fail(parent)); } var elseClause = (ElseClauseSyntax)parent; return(AnalyzeCore(elseClause.GetTopmostIf(), semanticModel, jumpKind, options, taskSymbol, cancellationToken)); } } return(Fail(parent)); }
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 AnalyzeIsExpression(SyntaxNodeAnalysisContext context) { var isExpression = (BinaryExpressionSyntax)context.Node; IsExpressionInfo isExpressionInfo = SyntaxInfo.IsExpressionInfo(isExpression); if (!isExpressionInfo.Success) { return; } ExpressionSyntax expression = isExpressionInfo.Expression; var identifierName = expression as IdentifierNameSyntax; if (identifierName == null) { if (expression.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccess = (MemberAccessExpressionSyntax)expression; if (memberAccess.Expression.IsKind(SyntaxKind.ThisExpression)) { identifierName = memberAccess.Name as IdentifierNameSyntax; } } if (identifierName == null) { return; } } ExpressionSyntax left = isExpression.WalkUpParentheses(); SyntaxNode node = left.Parent; if (node.ContainsDiagnostics) { return; } switch (node.Kind()) { case SyntaxKind.LogicalAndExpression: { var logicalAnd = (BinaryExpressionSyntax)node; if (left != logicalAnd.Left) { return; } ExpressionSyntax right = logicalAnd.Right; if (right == null) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; if (semanticModel.GetTypeSymbol(isExpressionInfo.Type, cancellationToken).IsNullableType()) { return; } if (logicalAnd.Parent.IsInExpressionTree(semanticModel, cancellationToken)) { return; } if (!IsFixable(right, identifierName, semanticModel, cancellationToken)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UsePatternMatchingInsteadOfIsAndCast, logicalAnd); break; } case SyntaxKind.IfStatement: { var ifStatement = (IfStatementSyntax)node; if (left != ifStatement.Condition) { return; } StatementSyntax statement = ifStatement.Statement; if (statement == null) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; if (semanticModel.GetTypeSymbol(isExpressionInfo.Type, cancellationToken).IsNullableType()) { return; } if (!IsFixable(statement, identifierName, semanticModel, cancellationToken)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UsePatternMatchingInsteadOfIsAndCast, ifStatement.Condition); break; } } }
public static AccessibilityFlags GetAllowedAccessibilityFlags(MemberDeclarationSelection selectedMembers, bool allowOverride = false) { if (selectedMembers.Count < 2) { return(AccessibilityFlags.None); } var allFlags = AccessibilityFlags.None; AccessibilityFlags allowedFlags = AccessibilityFlags.Public | AccessibilityFlags.Internal | AccessibilityFlags.Protected | AccessibilityFlags.Private; foreach (MemberDeclarationSyntax member in selectedMembers) { Accessibility accessibility = SyntaxInfo.AccessibilityInfo(member).Accessibility; if (accessibility == Accessibility.NotApplicable) { accessibility = member.GetDefaultExplicitAccessibility(); if (accessibility == Accessibility.NotApplicable) { return(AccessibilityFlags.None); } } AccessibilityFlags flag = accessibility.GetAccessibilityFlag(); switch (accessibility) { case Accessibility.Private: case Accessibility.Protected: case Accessibility.ProtectedAndInternal: case Accessibility.ProtectedOrInternal: case Accessibility.Internal: case Accessibility.Public: { allFlags |= flag; break; } default: { Debug.Fail(accessibility.ToString()); return(AccessibilityFlags.None); } } foreach (Accessibility accessibility2 in Accessibilities) { if (accessibility != accessibility2 && !CSharpUtility.IsAllowedAccessibility(member, accessibility2, allowOverride: allowOverride)) { allowedFlags &= ~accessibility2.GetAccessibilityFlag(); } } } switch (allFlags) { case AccessibilityFlags.Private: case AccessibilityFlags.Protected: case AccessibilityFlags.Internal: case AccessibilityFlags.Public: { allowedFlags &= ~allFlags; break; } } return(allowedFlags); }