internal static bool IsLoop(this SyntaxKind kind) { return(kind.Is( SyntaxKind.ForStatement, SyntaxKind.ForEachStatement, SyntaxKind.WhileStatement, SyntaxKind.DoStatement)); }
/// <summary> /// Returns true if a syntax of the specified kind if local function or anonymous function. /// </summary> /// <param name="kind"></param> /// <returns></returns> public static bool IsFunction(SyntaxKind kind) { return(kind.Is( SyntaxKind.SimpleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression, SyntaxKind.AnonymousMethodExpression, SyntaxKind.LocalFunctionStatement)); }
/// <summary> /// Returns true if a syntax of the specified kind is pre/post increment/decrement expression. /// </summary> /// <param name="kind"></param> /// <returns></returns> public static bool IsIncrementOrDecrementExpression(SyntaxKind kind) { return(kind.Is( SyntaxKind.PreIncrementExpression, SyntaxKind.PreDecrementExpression, SyntaxKind.PostIncrementExpression, SyntaxKind.PostDecrementExpression)); }
/// <summary> /// Returns true if a syntax of the specified kind is a constraint. /// </summary> /// <param name="kind"></param> /// <returns></returns> public static bool IsConstraint(SyntaxKind kind) { return(kind.Is( SyntaxKind.ClassConstraint, SyntaxKind.ConstructorConstraint, SyntaxKind.StructConstraint, SyntaxKind.TypeConstraint)); }
/// <summary> /// Returns true if a syntax of the specified kind is comment trivia. /// </summary> /// <param name="kind"></param> /// <returns></returns> public static bool IsCommentTrivia(SyntaxKind kind) { return(kind.Is( SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.SingleLineDocumentationCommentTrivia, SyntaxKind.MultiLineDocumentationCommentTrivia)); }
private static bool IsFormattableKind(SyntaxKind kind) { return(kind.Is( SyntaxKind.LogicalAndExpression, SyntaxKind.LogicalOrExpression, SyntaxKind.BitwiseAndExpression, SyntaxKind.BitwiseOrExpression)); }
internal static bool IsNestedMethod(this SyntaxKind kind) { return(kind.Is( SyntaxKind.SimpleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression, SyntaxKind.AnonymousMethodExpression, SyntaxKind.LocalFunctionStatement)); }
internal static bool CanContainContinueStatement(this SyntaxKind kind) { return(kind.Is( SyntaxKind.WhileStatement, SyntaxKind.DoStatement, SyntaxKind.ForStatement, SyntaxKind.ForEachStatement)); }
/// <summary> /// Returns true if a syntax of the specified kind can have members. /// </summary> /// <param name="kind"></param> /// <returns></returns> public static bool CanHaveMembers(SyntaxKind kind) { return(kind.Is( SyntaxKind.CompilationUnit, SyntaxKind.NamespaceDeclaration, SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.InterfaceDeclaration)); }
/// <summary> /// Returns true if a syntax of the specified kind is a for, foreach, while or do statement. /// </summary> /// <param name="kind"></param> public static bool IsIterationStatement(SyntaxKind kind) { return(kind.Is( SyntaxKind.ForStatement, SyntaxKind.ForEachStatement, SyntaxKind.ForEachVariableStatement, SyntaxKind.WhileStatement, SyntaxKind.DoStatement)); }
public static bool CanCreate(SyntaxKind kind) { return(kind.Is( SyntaxKind.MethodDeclaration, SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration, SyntaxKind.EventDeclaration, SyntaxKind.VariableDeclarator)); }
internal static bool IsJumpStatement(this SyntaxKind kind) { return kind.Is( SyntaxKind.BreakStatement, SyntaxKind.ContinueStatement, SyntaxKind.GotoCaseStatement, SyntaxKind.GotoDefaultStatement, SyntaxKind.ReturnStatement, SyntaxKind.ThrowStatement); }
internal static SyntaxKind GetJumpKind(StatementSyntax statement) { switch (statement) { case BreakStatementSyntax _: { return(SyntaxKind.BreakStatement); } case ContinueStatementSyntax _: { return(SyntaxKind.ContinueStatement); } case ReturnStatementSyntax returnStatement: { ExpressionSyntax expression = returnStatement.Expression; if (expression == null) { return(SyntaxKind.ReturnStatement); } SyntaxKind kind = expression.Kind(); if (kind.Is( SyntaxKind.NullLiteralExpression, SyntaxKind.DefaultLiteralExpression, SyntaxKind.TrueLiteralExpression, SyntaxKind.FalseLiteralExpression)) { return(kind); } return(SyntaxKind.None); } case ThrowStatementSyntax throwStatement: { ExpressionSyntax expression = throwStatement.Expression; if (expression == null) { return(SyntaxKind.ThrowStatement); } return(SyntaxKind.None); } default: { return(SyntaxKind.None); } } }
public static void ComputeRefactorings(RefactoringContext context, SyntaxTrivia trivia) { SyntaxKind kind = trivia.Kind(); Document document = context.Document; TextSpan span = context.Span; if (context.IsRootCompilationUnit && trivia.FullSpan.Contains(span) && CSharpFacts.IsCommentTrivia(kind)) { if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveComment)) { context.RegisterRefactoring( "Remove comment", ct => { SyntaxToken newToken = RemoveCommentHelper.GetReplacementToken(trivia).WithFormatterAnnotation(); return(document.ReplaceTokenAsync(trivia.Token, newToken, ct)); }, RefactoringIdentifiers.RemoveComment); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveAllComments)) { context.RegisterRefactoring( "Remove all comments", ct => document.RemoveCommentsAsync(CommentFilter.All, ct), RefactoringIdentifiers.RemoveAllComments); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveAllCommentsExceptDocumentationComments) && kind.Is(SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia)) { context.RegisterRefactoring( "Remove all comments (except documentation comments)", ct => document.RemoveCommentsAsync(CommentFilter.NonDocumentation, ct), RefactoringIdentifiers.RemoveAllCommentsExceptDocumentationComments); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveAllDocumentationComments) && SyntaxFacts.IsDocumentationCommentTrivia(kind)) { context.RegisterRefactoring( "Remove all documentation comments", ct => document.RemoveCommentsAsync(CommentFilter.Documentation, ct), RefactoringIdentifiers.RemoveAllDocumentationComments); } } }
protected override bool IsFixable(StatementSyntax statement, BlockSyntax block, SyntaxKind parentKind) { if (!parentKind.Is( SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement)) { return(false); } TextSpan span = TextSpan.FromBounds(block.SpanStart, statement.FullSpan.Start); //XTODO: Walker return(block .DescendantNodes(span, f => !f.IsNestedMethod()) .Any(f => f.Kind().IsYieldStatement())); }
protected override bool IsFixable(StatementSyntax statement, BlockSyntax block, SyntaxKind parentKind) { if (!parentKind.Is( SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement)) { return(false); } if (object.ReferenceEquals(block.Statements.SingleOrDefault(ignoreLocalFunctions: true, shouldThrow: false), statement)) { return(false); } TextSpan span = TextSpan.FromBounds(block.SpanStart, statement.FullSpan.Start); return(block.ContainsYield(span)); }
public override void VisitYieldStatement(YieldStatementSyntax node) { SyntaxKind kind = node.Kind(); Debug.Assert(kind.Is(SyntaxKind.YieldBreakStatement, SyntaxKind.YieldReturnStatement), kind.ToString()); if (kind == SyntaxKind.YieldReturnStatement) { if (SearchForYieldReturn) { YieldStatement = node; } } else if (kind == SyntaxKind.YieldBreakStatement) { if (SearchForYieldBreak) { YieldStatement = node; } } }
protected override bool IsFixable(StatementSyntax statement, StatementSyntax containingStatement, BlockSyntax block, SyntaxKind parentKind) { if (!parentKind.Is( SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement)) { return(false); } SyntaxList <StatementSyntax> statements = block.Statements; if (object.ReferenceEquals(statements.SingleOrDefault(ignoreLocalFunctions: true, shouldThrow: false), containingStatement)) { return(false); } ContainsYieldWalker walker = ContainsYieldWalker.GetInstance(); bool success = false; int index = statements.IndexOf(containingStatement); for (int i = 0; i < index; i++) { walker.VisitStatement(statements[i]); success = walker.YieldStatement != null; if (success) { break; } } ContainsYieldWalker.Free(walker); return(success); }
protected override bool IsFixable(StatementSyntax statement, BlockSyntax block, SyntaxKind parentKind) { if (!parentKind.Is( SyntaxKind.ConstructorDeclaration, SyntaxKind.DestructorDeclaration, SyntaxKind.MethodDeclaration, SyntaxKind.SetAccessorDeclaration, SyntaxKind.LocalFunctionStatement)) { return(false); } if (parentKind == SyntaxKind.MethodDeclaration) { return(((MethodDeclarationSyntax)block.Parent).ReturnType?.IsVoid() == true); } if (parentKind == SyntaxKind.LocalFunctionStatement) { return(((LocalFunctionStatementSyntax)block.Parent).ReturnType?.IsVoid() == true); } return(true); }
/// <summary> /// Returns true if a syntax of the specified kind is a lambda expression. /// </summary> /// <param name="kind"></param> public static bool IsLambdaExpression(SyntaxKind kind) { return(kind.Is( SyntaxKind.SimpleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression)); }
/// <summary> /// Returns true if a syntax of the specified kind is true or false literal expression. /// </summary> /// <param name="kind"></param> public static bool IsBooleanLiteralExpression(SyntaxKind kind) { return(kind.Is( SyntaxKind.TrueLiteralExpression, SyntaxKind.FalseLiteralExpression)); }
/// <summary> /// Returns true if a syntax of the specified kind can have statements. It can be either <see cref="BlockSyntax"/> or <see cref="SwitchSectionSyntax"/>. /// </summary> /// <param name="kind"></param> public static bool CanHaveStatements(SyntaxKind kind) { return(kind.Is(SyntaxKind.Block, SyntaxKind.SwitchSection)); }
private Dictionary <SyntaxNode, object> GetReplacementMap(SyntaxNode node, Dictionary <ISymbol, string> symbolMap) { var replacementMap = new Dictionary <SyntaxNode, object>(); foreach (SyntaxNode descendant in node.DescendantNodesAndSelf(node.Span)) { SyntaxKind kind = descendant.Kind(); if (kind == SyntaxKind.IdentifierName) { var identifierName = (IdentifierNameSyntax)descendant; ISymbol symbol = DeclarationSemanticModel.GetSymbol(identifierName, CancellationToken); if (symbol != null) { if (symbol.IsParameter()) { foreach (ParameterInfo parameterInfo in ParameterInfos) { if (parameterInfo.ParameterSymbol.OriginalDefinition.Equals(symbol)) { replacementMap.Add(identifierName, parameterInfo.Expression); break; } } } else if (symbol.IsTypeParameter()) { var typeParameter = (ITypeParameterSymbol)symbol; ImmutableArray <ITypeSymbol> typeArguments = MethodSymbol.TypeArguments; if (typeArguments.Length > typeParameter.Ordinal) { replacementMap.Add(identifierName, typeArguments[typeParameter.Ordinal].ToMinimalTypeSyntax(DeclarationSemanticModel, identifierName.SpanStart)); } } else if (symbol.IsStatic && !identifierName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { INamedTypeSymbol containingType = symbol.ContainingType; if (!InvocationEnclosingType .BaseTypesAndSelf() .Any(f => f.Equals(containingType))) { replacementMap.Add(identifierName, CSharpFactory.SimpleMemberAccessExpression(containingType.ToTypeSyntax().WithSimplifierAnnotation(), identifierName)); } } if (symbolMap != null && symbolMap.TryGetValue(symbol, out string name)) { replacementMap.Add(identifierName, SyntaxFactory.IdentifierName(name)); } } } else if (symbolMap != null) { if (kind.Is( SyntaxKind.VariableDeclarator, SyntaxKind.SingleVariableDesignation, SyntaxKind.Parameter, SyntaxKind.TypeParameter, SyntaxKind.ForEachStatement, SyntaxKind.ForEachVariableStatement)) { ISymbol symbol = DeclarationSemanticModel.GetDeclaredSymbol(descendant, CancellationToken); Debug.Assert(symbol != null || (descendant as ForEachVariableStatementSyntax)?.Variable?.Kind() == SyntaxKind.TupleExpression, kind.ToString()); if (symbol != null && symbolMap.TryGetValue(symbol, out string name)) { replacementMap.Add(descendant, name); } } } } return(replacementMap); }
public static ImmutableArray <IfRefactoring> Analyze( IfStatementSyntax ifStatement, IfAnalysisOptions options, SemanticModel semanticModel, CancellationToken cancellationToken = default(CancellationToken)) { if (!ifStatement.IsTopmostIf()) { return(Empty); } ExpressionSyntax condition = ifStatement.Condition?.WalkDownParentheses(); if (condition == null) { return(Empty); } ElseClauseSyntax elseClause = ifStatement.Else; if (elseClause != null) { if (!options.CheckSpanDirectives(ifStatement)) { return(Empty); } StatementSyntax statement1 = ifStatement.GetSingleStatementOrDefault(); if (statement1 == null) { return(Empty); } SyntaxKind kind1 = statement1.Kind(); if (kind1.Is( SyntaxKind.ExpressionStatement, SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement)) { StatementSyntax statement2 = elseClause.GetSingleStatementOrDefault(); if (statement2?.Kind() == kind1) { switch (kind1) { case SyntaxKind.ExpressionStatement: { return(Analyze( ifStatement, condition, (ExpressionStatementSyntax)statement1, (ExpressionStatementSyntax)statement2, options, semanticModel, cancellationToken)); } case SyntaxKind.ReturnStatement: { return(Analyze( ifStatement, condition, ((ReturnStatementSyntax)statement1).Expression?.WalkDownParentheses(), ((ReturnStatementSyntax)statement2).Expression?.WalkDownParentheses(), options, isYield: false, semanticModel: semanticModel, cancellationToken: cancellationToken)); } case SyntaxKind.YieldReturnStatement: { return(Analyze( ifStatement, condition, ((YieldStatementSyntax)statement1).Expression?.WalkDownParentheses(), ((YieldStatementSyntax)statement2).Expression?.WalkDownParentheses(), options, isYield: true, semanticModel: semanticModel, cancellationToken: cancellationToken)); } } } } } else if (ifStatement.NextStatementOrDefault() is ReturnStatementSyntax returnStatement) { return(Analyze(ifStatement, returnStatement, options, semanticModel, cancellationToken)); } return(Empty); }
public static void Analyze(SyntaxNodeAnalysisContext context, SimpleMemberInvocationExpressionInfo invocationInfo) { InvocationExpressionSyntax invocationExpression = invocationInfo.InvocationExpression; SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; IMethodSymbol methodSymbol = semanticModel.GetReducedExtensionMethodInfo(invocationExpression, cancellationToken).Symbol; if (methodSymbol == null) { return; } if (!SymbolUtility.IsLinqExtensionOfIEnumerableOfTWithoutParameters(methodSymbol, "Count", semanticModel)) { return; } string propertyName = CSharpUtility.GetCountOrLengthPropertyName(invocationInfo.Expression, semanticModel, cancellationToken); if (propertyName != null) { context.ReportDiagnostic( DiagnosticDescriptors.UseCountOrLengthPropertyInsteadOfCountMethod, Location.Create(context.Node.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End)), ImmutableDictionary.CreateRange(new KeyValuePair <string, string>[] { new KeyValuePair <string, string>("PropertyName", propertyName) }), propertyName); } else { bool isFixable = false; SyntaxNode parent = invocationExpression.Parent; SyntaxKind kind = parent.Kind(); if (kind.Is( SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression)) { var equalsExpression = (BinaryExpressionSyntax)parent; if (equalsExpression.Left == invocationExpression) { if (equalsExpression.Right.IsNumericLiteralExpression("0")) { isFixable = true; } } else if (equalsExpression.Left.IsNumericLiteralExpression("0")) { isFixable = true; } } else if (kind.Is( SyntaxKind.GreaterThanExpression, SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.LessThanExpression, SyntaxKind.LessThanOrEqualExpression)) { isFixable = true; } if (isFixable) { context.ReportDiagnostic(DiagnosticDescriptors.CallAnyInsteadOfCount, parent); } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf( root, context.Span, out SyntaxNode node, predicate: f => f.IsKind( SyntaxKind.InvocationExpression, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression, SyntaxKind.IsPatternExpression, SyntaxKind.ConditionalExpression))) { return; } Diagnostic diagnostic = context.Diagnostics[0]; Document document = context.Document; CancellationToken cancellationToken = context.CancellationToken; SyntaxKind kind = node.Kind(); if (kind == SyntaxKind.InvocationExpression) { var invocation = (InvocationExpressionSyntax)node; SimpleMemberInvocationExpressionInfo invocationInfo = SimpleMemberInvocationExpressionInfo(invocation); if (diagnostic.Properties.TryGetValue("Name", out string name) && name == "SimplifyLinqMethodChain") { SimpleMemberInvocationExpressionInfo invocationInfo2 = SimpleMemberInvocationExpressionInfo(invocationInfo.Expression); CodeAction codeAction = CodeAction.Create( $"Combine '{invocationInfo2.NameText}' and '{invocationInfo.NameText}'", ct => SimplifyLinqMethodChainAsync(document, invocationInfo, ct), GetEquivalenceKey(diagnostic, "SimplifyLinqMethodChain")); context.RegisterCodeFix(codeAction, diagnostic); return; } switch (invocationInfo.NameText) { case "Cast": { CodeAction codeAction = CodeAction.Create( "Call 'OfType' instead of 'Where' and 'Cast'", ct => CallOfTypeInsteadOfWhereAndCastAsync(document, invocationInfo, ct), GetEquivalenceKey(diagnostic, "CallOfTypeInsteadOfWhereAndCast")); context.RegisterCodeFix(codeAction, diagnostic); return; } case "Any": { CodeAction codeAction = CodeAction.Create( "Combine 'Where' and 'Any'", ct => CombineWhereAndAnyAsync(document, invocationInfo, ct), GetEquivalenceKey(diagnostic, "CombineWhereAndAny")); context.RegisterCodeFix(codeAction, diagnostic); return; } case "OfType": { TypeSyntax typeArgument = ((GenericNameSyntax)invocationInfo.Name).TypeArgumentList.Arguments.Single(); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (semanticModel.GetTypeSymbol(typeArgument, cancellationToken).IsValueType) { CodeAction codeAction = CodeAction.Create( "Remove redundant 'OfType' call", ct => { ExpressionSyntax newNode = invocationInfo.Expression.WithTrailingTrivia(invocation.GetTrailingTrivia()); return(document.ReplaceNodeAsync(invocation, newNode, ct)); }, GetEquivalenceKey(diagnostic, "RemoveRedundantOfTypeCall")); context.RegisterCodeFix(codeAction, diagnostic); } else { CodeAction codeAction = CodeAction.Create( "Call 'Where' instead of 'OfType'", ct => CallWhereInsteadOfOfTypeAsync(document, invocationInfo, ct), GetEquivalenceKey(diagnostic, "CallWhereInsteadOfOfType")); context.RegisterCodeFix(codeAction, diagnostic); } return; } case "Reverse": { CodeAction codeAction = CodeAction.Create( "Call 'OrderByDescending", ct => CallOrderByDescendingInsteadOfOrderByAndReverseAsync(document, invocationInfo, ct), GetEquivalenceKey(diagnostic, "CallOrderByDescendingInsteadOfOrderByAndReverse")); context.RegisterCodeFix(codeAction, diagnostic); return; } case "Select": { CodeAction codeAction = CodeAction.Create( "Call 'Cast' instead of 'Select'", ct => CallCastInsteadOfSelectAsync(document, invocation, ct), GetEquivalenceKey(diagnostic, "CallCastInsteadOfSelect")); context.RegisterCodeFix(codeAction, diagnostic); return; } case "FirstOrDefault": { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); CodeAction codeAction = CodeAction.Create( "Call 'Find' instead of 'FirstOrDefault'", ct => CallFindInsteadOfFirstOrDefaultAsync(document, invocationInfo, semanticModel, ct), GetEquivalenceKey(diagnostic, "CallFindInsteadOfFirstOrDefault")); context.RegisterCodeFix(codeAction, diagnostic); return; } case "First": { if (diagnostic.Properties.TryGetValue("MethodName", out string methodName) && methodName == "Peek") { CodeAction codeAction = CodeAction.Create( "Call 'Peek' instead of 'First'", ct => document.ReplaceNodeAsync(invocation, ChangeInvokedMethodName(invocation, "Peek"), ct), GetEquivalenceKey(diagnostic, "CallPeekInsteadOfFirst")); context.RegisterCodeFix(codeAction, diagnostic); } else { CodeAction codeAction = CodeAction.Create( "Use [] instead of calling 'First'", ct => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfFirstAsync(context.Document, invocation, ct), GetEquivalenceKey(diagnostic, "UseElementAccessInsteadOfFirst")); context.RegisterCodeFix(codeAction, diagnostic); } return; } case "Count": { if (diagnostic.Properties.TryGetValue("PropertyName", out string propertyName)) { if (diagnostic.Properties.TryGetValue("MethodName", out string methodName) && methodName == "Sum") { CodeAction codeAction = CodeAction.Create( "Call 'Sum'", ct => CallSumInsteadOfSelectManyAndCountAsync(document, invocationInfo, propertyName, ct), GetEquivalenceKey(diagnostic, "CallSumInsteadOfSelectManyAndCount")); context.RegisterCodeFix(codeAction, diagnostic); } else { CodeAction codeAction = CodeAction.Create( $"Use '{propertyName}' property instead of calling 'Count'", ct => UseCountOrLengthPropertyInsteadOfCountMethodAsync(document, invocation, diagnostic.Properties["PropertyName"], ct), GetEquivalenceKey(diagnostic, "UseCountOrLengthPropertyInsteadOfCountMethod")); context.RegisterCodeFix(codeAction, diagnostic); } } else if (invocation.Parent is BinaryExpressionSyntax binaryExpression) { CodeAction codeAction = CodeAction.Create( "Call 'Any' instead of 'Count'", ct => CallAnyInsteadOfCountAsync(document, invocation, binaryExpression, ct), GetEquivalenceKey(diagnostic, "CallAnyInsteadOfCount")); context.RegisterCodeFix(codeAction, diagnostic); } return; } case "ElementAt": { CodeAction codeAction = CodeAction.Create( "Use [] instead of calling 'ElementAt'", ct => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfElementAtAsync(document, invocation, ct), GetEquivalenceKey(diagnostic, "UseElementAccessInsteadOfElementAt")); context.RegisterCodeFix(codeAction, diagnostic); return; } } } else if (kind == SyntaxKind.ConditionalExpression) { CodeAction codeAction = CodeAction.Create( "Call 'FirstOrDefault' instead of ?:", ct => CallFirstOrDeafultInsteadOfConditionalExpressionAsync(document, (ConditionalExpressionSyntax)node, ct), GetEquivalenceKey(diagnostic, "CallFirstOrDefaultInsteadOfConditionalExpression")); context.RegisterCodeFix(codeAction, diagnostic); } else if (kind.Is( SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression, SyntaxKind.IsPatternExpression)) { CodeAction codeAction = CodeAction.Create( "Call 'Any' instead of 'FirstOrDefault'", ct => CallAnyInsteadOfFirstOrDefaultAsync(document, node, ct), GetEquivalenceKey(diagnostic, "CallAnyInsteadOfFirstOrDefault")); context.RegisterCodeFix(codeAction, diagnostic); } }
private static ReduceIfNestingAnalysisResult AnalyzeCore( IfStatementSyntax ifStatement, SemanticModel semanticModel, SyntaxKind jumpKind, ReduceIfNestingOptions options, 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, 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, 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) && semanticModel .GetDeclaredSymbol(methodDeclaration, cancellationToken)? .ReturnType .HasMetadataName(MetadataNames.System_Threading_Tasks_Task) == 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) && semanticModel.GetDeclaredSymbol(localFunction, cancellationToken)? .ReturnType .HasMetadataName(MetadataNames.System_Threading_Tasks_Task) == 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)); } if (!(semanticModel.GetSymbol(anonymousFunction, cancellationToken) is IMethodSymbol methodSymbol)) { return(Fail(parent)); } if (methodSymbol.ReturnsVoid) { return(Success(SyntaxKind.ReturnStatement, parent)); } if (anonymousFunction.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword && methodSymbol.ReturnType.HasMetadataName(MetadataNames.System_Threading_Tasks_Task)) { 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, cancellationToken)); } else { if (!IsFixable(ifStatement)) { return(Fail(parent)); } if (!options.AllowNestedFix()) { return(Fail(parent)); } return(AnalyzeCore(ifStatement, semanticModel, jumpKind, options, cancellationToken)); } } case SyntaxKind.ElseClause: { if (!options.AllowIfInsideIfElse()) { return(Fail(parent)); } var elseClause = (ElseClauseSyntax)parent; return(AnalyzeCore(elseClause.GetTopmostIf(), semanticModel, jumpKind, options, cancellationToken)); } } return(Fail(parent)); }
public static void ComputeRefactoring(RefactoringContext context, ExpressionSyntax expression) { SyntaxNode parent = expression.Parent; if (parent == null) { return; } SyntaxKind kind = parent.Kind(); if (!kind.Is(SyntaxKind.LogicalAndExpression, SyntaxKind.LogicalOrExpression)) { return; } BinaryExpressionSyntax binaryExpression = GetCondition((BinaryExpressionSyntax)parent); if (binaryExpression == null) { return; } parent = binaryExpression.Parent; switch (parent?.Kind()) { case SyntaxKind.IfStatement: { if (kind == SyntaxKind.LogicalAndExpression) { ExtractConditionFromIfToNestedIfRefactoring refactoring = ExtractConditionFromIfToNestedIfRefactoring.Instance; context.RegisterRefactoring( refactoring.Title, cancellationToken => refactoring.RefactorAsync(context.Document, binaryExpression, expression, cancellationToken)); } else if (kind == SyntaxKind.LogicalOrExpression) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo((StatementSyntax)parent); if (statementsInfo.Success) { ExtractConditionFromIfToIfRefactoring refactoring = ExtractConditionFromIfToIfRefactoring.Instance; context.RegisterRefactoring( refactoring.Title, cancellationToken => refactoring.RefactorAsync(context.Document, statementsInfo, binaryExpression, expression, cancellationToken)); } } break; } case SyntaxKind.WhileStatement: { if (kind == SyntaxKind.LogicalAndExpression) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo((StatementSyntax)parent); if (statementsInfo.Success) { ExtractConditionFromWhileToNestedIfRefactoring refactoring = ExtractConditionFromWhileToNestedIfRefactoring.Instance; context.RegisterRefactoring( refactoring.Title, cancellationToken => refactoring.RefactorAsync(context.Document, (WhileStatementSyntax)parent, binaryExpression, expression, cancellationToken)); } } break; } } }
internal static void ComputeRefactoring(RefactoringContext context, BinaryExpressionSelection binaryExpressionSelection) { BinaryExpressionSyntax binaryExpression = binaryExpressionSelection.BinaryExpression; SyntaxKind kind = binaryExpression.Kind(); if (!kind.Is(SyntaxKind.LogicalAndExpression, SyntaxKind.LogicalOrExpression)) { return; } BinaryExpressionSyntax condition = GetCondition(binaryExpression); if (condition == null) { return; } SyntaxNode parent = condition.Parent; switch (parent?.Kind()) { case SyntaxKind.IfStatement: { if (kind == SyntaxKind.LogicalAndExpression) { ExtractConditionFromIfToNestedIfRefactoring refactoring = ExtractConditionFromIfToNestedIfRefactoring.Instance; context.RegisterRefactoring( refactoring.Title, cancellationToken => refactoring.RefactorAsync(context.Document, (IfStatementSyntax)parent, condition, binaryExpressionSelection, cancellationToken), RefactoringIdentifiers.ExtractExpressionFromCondition); } else if (kind == SyntaxKind.LogicalOrExpression) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo((StatementSyntax)parent); if (statementsInfo.Success) { ExtractConditionFromIfToIfRefactoring refactoring = ExtractConditionFromIfToIfRefactoring.Instance; context.RegisterRefactoring( refactoring.Title, cancellationToken => refactoring.RefactorAsync(context.Document, statementsInfo, condition, binaryExpressionSelection, cancellationToken), RefactoringIdentifiers.ExtractExpressionFromCondition); } } break; } case SyntaxKind.WhileStatement: { if (kind == SyntaxKind.LogicalAndExpression) { ExtractConditionFromWhileToNestedIfRefactoring refactoring = ExtractConditionFromWhileToNestedIfRefactoring.Instance; context.RegisterRefactoring( refactoring.Title, cancellationToken => refactoring.RefactorAsync(context.Document, (WhileStatementSyntax)parent, condition, binaryExpressionSelection, cancellationToken), RefactoringIdentifiers.ExtractExpressionFromCondition); } break; } } }
private Dictionary <SyntaxNode, object> GetReplacementMap(SyntaxNode node, Dictionary <ISymbol, string> symbolMap) { var replacementMap = new Dictionary <SyntaxNode, object>(); foreach (SyntaxNode descendant in node.DescendantNodesAndSelf(node.Span)) { SyntaxKind kind = descendant.Kind(); if (kind == SyntaxKind.IdentifierName) { var identifierName = (IdentifierNameSyntax)descendant; ISymbol symbol = DeclarationSemanticModel.GetSymbol(identifierName, CancellationToken); if (symbol != null) { if (symbol is IParameterSymbol parameterSymbol) { foreach (ParameterInfo parameterInfo in ParameterInfos) { if (ParameterEquals(parameterInfo, parameterSymbol)) { ExpressionSyntax expression = parameterInfo.Expression; if (expression == null && parameterInfo.ParameterSymbol.HasExplicitDefaultValue) { expression = parameterInfo.ParameterSymbol.GetDefaultValueMinimalSyntax(InvocationSemanticModel, Node.SpanStart); } replacementMap.Add(identifierName, expression); break; } } } else if (symbol.Kind == SymbolKind.TypeParameter) { var typeParameter = (ITypeParameterSymbol)symbol; ImmutableArray <ITypeSymbol> typeArguments = TypeArguments; if (typeArguments.Length > typeParameter.Ordinal) { replacementMap.Add(identifierName, typeArguments[typeParameter.Ordinal].ToMinimalTypeSyntax(DeclarationSemanticModel, identifierName.SpanStart)); } } else if (symbol.IsStatic && !identifierName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.QualifiedName)) { INamedTypeSymbol containingType = symbol.ContainingType; if (containingType != null) { if (!NodeEnclosingType .BaseTypesAndSelf() .Any(f => f.Equals(containingType))) { replacementMap.Add(identifierName, CSharpFactory.SimpleMemberAccessExpression(containingType.ToTypeSyntax().WithSimplifierAnnotation(), identifierName)); } } else if (symbol is ITypeSymbol typeSymbol) { replacementMap.Add(identifierName, typeSymbol.ToMinimalTypeSyntax(InvocationSemanticModel, Node.SpanStart)); } } if (symbolMap != null && symbolMap.TryGetValue(symbol, out string name)) { replacementMap.Add(identifierName, IdentifierName(name)); } } } else if (symbolMap != null) { if (kind.Is( SyntaxKind.VariableDeclarator, SyntaxKind.SingleVariableDesignation, SyntaxKind.Parameter, SyntaxKind.TypeParameter, SyntaxKind.ForEachStatement, SyntaxKind.ForEachVariableStatement)) { ISymbol symbol = DeclarationSemanticModel.GetDeclaredSymbol(descendant, CancellationToken); Debug.Assert(symbol != null || (descendant as ForEachVariableStatementSyntax)?.Variable?.Kind() == SyntaxKind.TupleExpression, kind.ToString()); if (symbol != null && symbolMap.TryGetValue(symbol, out string name)) { replacementMap.Add(descendant, name); } } } } return(replacementMap); bool ParameterEquals(in ParameterInfo parameterInfo, IParameterSymbol parameterSymbol2) { IParameterSymbol parameterSymbol = parameterInfo.ParameterSymbol; if (parameterSymbol.ContainingSymbol is IMethodSymbol methodSymbol) { if (parameterInfo.IsThis || methodSymbol.MethodKind == MethodKind.ReducedExtension) { int ordinal = parameterSymbol.Ordinal; if (methodSymbol.MethodKind == MethodKind.ReducedExtension) { ordinal++; } return(ordinal == parameterSymbol2.Ordinal && string.Equals(parameterSymbol.Name, parameterSymbol2.Name, StringComparison.Ordinal)); } } return(parameterSymbol.OriginalDefinition.Equals(parameterSymbol2)); } }