private static void AnalyzeLocalFunctionStatement(SyntaxNodeAnalysisContext context) { var localFunctionStatement = (LocalFunctionStatementSyntax)context.Node; SyntaxTokenList modifiers = localFunctionStatement.Modifiers; int index = modifiers.IndexOf(SyntaxKind.UnsafeKeyword); if (index == -1) { return; } SyntaxNode parent = localFunctionStatement.Parent; SyntaxDebug.Assert(parent.IsKind(SyntaxKind.Block), parent); if (parent is not BlockSyntax) { return; } parent = parent.Parent; if (!ParentDeclarationsContainsUnsafeModifier(parent)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UnnecessaryUnsafeContext, modifiers[index]); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindNode(root, context.Span, out SyntaxNode node)) { return; } Diagnostic diagnostic = context.Diagnostics[0]; for (SyntaxNode parent = node.Parent; parent != null; parent = parent.Parent) { if (parent is MemberDeclarationSyntax memberDeclaration) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol symbol = semanticModel.GetSymbol(node, context.CancellationToken); if (symbol?.IsErrorType() != false) { return; } SyntaxDebug.Assert(SyntaxInfo.ModifierListInfo(memberDeclaration).IsStatic, memberDeclaration); if (SyntaxInfo.ModifierListInfo(memberDeclaration).IsStatic) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeMemberNonStatic, context.Document, root.SyntaxTree)) { ModifiersCodeFixRegistrator.RemoveModifier( context, diagnostic, memberDeclaration, SyntaxKind.StaticKeyword, title: $"Make containing {CSharpFacts.GetTitle(memberDeclaration)} non-static", additionalKey: CodeFixIdentifiers.MakeMemberNonStatic); } if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier, context.Document, root.SyntaxTree)) { AddStaticModifier(context, diagnostic, node, semanticModel); } } return; } else if (parent is ConstructorInitializerSyntax) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier, context.Document, root.SyntaxTree)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); AddStaticModifier(context, diagnostic, node, semanticModel); } return; } } }
private static void AnalyzeCompilationUnit(SyntaxNodeAnalysisContext context) { var compilationUnit = (CompilationUnitSyntax)context.Node; if (compilationUnit.Span.Length == 0) { return; } SyntaxToken token = compilationUnit.EndOfFileToken; if (token.FullSpan.Start > 0) { token = compilationUnit.GetFirstToken(); SyntaxDebug.Assert(token.FullSpan.Start == 0, token); if (token.FullSpan.Start > 0) { return; } } SyntaxTriviaList.Enumerator en = token.LeadingTrivia.GetEnumerator(); if (en.MoveNext() && en.Current.IsWhitespaceOrEndOfLineTrivia()) { ReportDiagnostic(context, token); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out ExpressionSyntax expression)) { return; } Document document = context.Document; Diagnostic diagnostic = context.Diagnostics[0]; if (expression is InvocationExpressionSyntax invocationExpression) { CodeAction codeAction = CodeAction.Create( ConvertHasFlagCallToBitwiseOperationRefactoring.Title, ct => ConvertHasFlagCallToBitwiseOperationRefactoring.RefactorAsync(document, invocationExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else { SyntaxDebug.Assert(expression.IsKind(SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression), expression); CodeAction codeAction = CodeAction.Create( "Call 'HasFlag'", ct => ConvertBitwiseOperationToHasFlagCallAsync(document, (BinaryExpressionSyntax)expression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } }
private static void ReportDiagnostic(SymbolAnalysisContext context, ISymbol member) { SyntaxNode node = member.GetSyntaxOrDefault(context.CancellationToken); Debug.Assert(node != null, member.ToString()); if (node == null) { return; } SyntaxToken identifier = CSharpUtility.GetIdentifier(node); SyntaxDebug.Assert(!identifier.IsKind(SyntaxKind.None), node); if (identifier.IsKind(SyntaxKind.None)) { return; } DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.StaticMemberInGenericTypeShouldUseTypeParameter, identifier); }
private static TypeSyntax DetermineReturnType(SyntaxNode node) { switch (node.Kind()) { case SyntaxKind.LocalFunctionStatement: return(((LocalFunctionStatementSyntax)node).ReturnType); case SyntaxKind.MethodDeclaration: return(((MethodDeclarationSyntax)node).ReturnType); case SyntaxKind.OperatorDeclaration: return(((OperatorDeclarationSyntax)node).ReturnType); case SyntaxKind.ConversionOperatorDeclaration: return(((ConversionOperatorDeclarationSyntax)node).Type); case SyntaxKind.PropertyDeclaration: return(((PropertyDeclarationSyntax)node).Type); case SyntaxKind.IndexerDeclaration: return(((IndexerDeclarationSyntax)node).Type); } if (node is AccessorDeclarationSyntax) { SyntaxDebug.Assert(node.IsParentKind(SyntaxKind.AccessorList), node.Parent); if (node.IsParentKind(SyntaxKind.AccessorList)) { return(DetermineReturnType(node.Parent.Parent)); } } return(null); }
private static void AddStaticModifier( CodeFixContext context, Diagnostic diagnostic, SyntaxNode node, SemanticModel semanticModel) { ISymbol symbol = semanticModel.GetSymbol(node, context.CancellationToken); if (symbol == null) { return; } SyntaxNode syntax = symbol.GetSyntaxOrDefault(context.CancellationToken); if (syntax == null) { return; } if (syntax.IsKind(SyntaxKind.VariableDeclarator)) { syntax = syntax.Parent?.Parent; } SyntaxDebug.Assert(syntax.IsKind(SyntaxKind.EventDeclaration, SyntaxKind.EventFieldDeclaration, SyntaxKind.FieldDeclaration, SyntaxKind.MethodDeclaration, SyntaxKind.PropertyDeclaration), syntax); if (syntax is not MemberDeclarationSyntax memberDeclaration) { return; } if (SyntaxInfo.ModifierListInfo(memberDeclaration).IsStatic) { return; } Document document = context.Document; SyntaxTree tree = memberDeclaration.SyntaxTree; if (tree != node.SyntaxTree) { document = context.Solution().GetDocument(tree); } ModifiersCodeFixRegistrator.AddModifier( context, document, diagnostic, memberDeclaration, SyntaxKind.StaticKeyword, title: $"Make '{symbol.Name}' static", additionalKey: CodeFixIdentifiers.AddStaticModifier); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindNode( root, context.Span, out ExpressionSyntax expression)) { return; } SyntaxDebug.Assert(expression.IsKind(SyntaxKind.NullLiteralExpression, SyntaxKind.DefaultLiteralExpression, SyntaxKind.DefaultExpression), expression); if (!expression.IsKind(SyntaxKind.NullLiteralExpression, SyntaxKind.DefaultLiteralExpression, SyntaxKind.DefaultExpression)) { return; } if (expression.IsKind(SyntaxKind.NullLiteralExpression) && expression.IsParentKind(SyntaxKind.EqualsValueClause) && expression.Parent.IsParentKind(SyntaxKind.Parameter)) { return; } Diagnostic diagnostic = context.Diagnostics[0]; Document document = context.Document; switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CS8625_CannotConvertNullLiteralToNonNullableReferenceType: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, context.Document, root.SyntaxTree)) { break; } CodeAction codeAction = CodeAction.Create( "Use null-forgiving operator", ct => { PostfixUnaryExpressionSyntax newExpression = SuppressNullableWarningExpression(expression.WithoutTrivia()) .WithTriviaFrom(expression); return(document.ReplaceNodeAsync(expression, newExpression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { Diagnostic diagnostic = context.Diagnostics[0]; SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMethodReturnType, context.Document, root.SyntaxTree)) { return; } if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement))) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(node, context.CancellationToken); SyntaxDebug.Assert(methodSymbol != null, node); ITypeSymbol typeSymbol = methodSymbol.ReturnType; if (typeSymbol.IsErrorType()) { return; } (bool containsReturnAwait, bool containsAwaitStatement) = AnalyzeAwaitExpressions(node); SyntaxDebug.Assert(containsAwaitStatement || containsReturnAwait, node); if (containsAwaitStatement) { INamedTypeSymbol taskSymbol = semanticModel.GetTypeByMetadataName("System.Threading.Tasks.Task"); CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, node, taskSymbol, semanticModel, "Task"); } if (containsReturnAwait) { typeSymbol = semanticModel.GetTypeByMetadataName("System.Threading.Tasks.Task`1").Construct(typeSymbol); CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, node, typeSymbol, semanticModel, "TaskOfT"); } }
private static void AnalyzeForEachVariableStatement(SyntaxNodeAnalysisContext context) { var forEachStatement = (ForEachVariableStatementSyntax)context.Node; switch (forEachStatement.Variable) { case DeclarationExpressionSyntax declarationExpression: { if (CSharpTypeAnalysis.IsImplicitThatCanBeExplicit(forEachStatement, context.SemanticModel)) { ReportDiagnostic(context, declarationExpression.Type); } break; } case TupleExpressionSyntax tupleExpression: { foreach (ArgumentSyntax argument in tupleExpression.Arguments) { if (argument.Expression is not DeclarationExpressionSyntax declarationExpression) { continue; } if (CSharpTypeAnalysis.IsImplicitThatCanBeExplicit(declarationExpression, context.SemanticModel, context.CancellationToken)) { ReportDiagnostic(context, declarationExpression.Type); } } break; } default: { SyntaxDebug.Assert(forEachStatement.ContainsDiagnostics, forEachStatement.Variable); break; } } }
private static bool ParentDeclarationsContainsUnsafeModifier(SyntaxNode node) { while (node.IsKind(SyntaxKind.LocalFunctionStatement)) { var localFunction = (LocalFunctionStatementSyntax)node; if (localFunction.Modifiers.Contains(SyntaxKind.UnsafeKeyword)) { return(true); } node = node.Parent; SyntaxDebug.Assert(node.IsKind(SyntaxKind.Block), node); if (!node.IsKind(SyntaxKind.Block)) { break; } node = node.Parent; } SyntaxDebug.Assert(node is MemberDeclarationSyntax, node); if (node is MemberDeclarationSyntax memberDeclaration) { if (SyntaxInfo.ModifierListInfo(memberDeclaration).IsUnsafe) { return(true); } return(ParentTypeDeclarationsContainsUnsafeModifier(memberDeclaration)); } return(false); }
private static void Analyze(SymbolAnalysisContext context, ISymbol symbol) { if (symbol.IsImplicitlyDeclared) { return; } if (!symbol.IsSealed) { return; } if (symbol.ContainingType?.IsSealed != true) { return; } Debug.Assert(symbol.ContainingType.TypeKind == TypeKind.Class, symbol.ContainingType.TypeKind.ToString()); SyntaxNode node = symbol.GetSyntax(context.CancellationToken); SyntaxDebug.Assert(node.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration), node); ModifierListInfo info = SyntaxInfo.ModifierListInfo(node); Debug.Assert(info.IsSealed, info.Modifiers.ToString()); if (!info.IsSealed) { return; } SyntaxToken sealedKeyword = info.Modifiers.Find(SyntaxKind.SealedKeyword); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantSealedModifier, sealedKeyword); }
private static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context) { if (context.Node.ContainsDiagnostics) { return; } if (context.Node.SpanOrTrailingTriviaContainsDirectives()) { return; } var assignment = (AssignmentExpressionSyntax)context.Node; SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(assignment); if (!assignmentInfo.Success) { return; } if (assignmentInfo.Left is not IdentifierNameSyntax identifierName) { return; } StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(assignmentInfo.Statement); if (!statementsInfo.Success) { return; } int index = statementsInfo.IndexOf(assignmentInfo.Statement); if (index == statementsInfo.Count - 1) { return; } if (index > 0) { StatementSyntax previousStatement = statementsInfo[index - 1]; SimpleAssignmentStatementInfo assignmentInfo2 = SyntaxInfo.SimpleAssignmentStatementInfo(previousStatement); if (assignmentInfo2.Success && assignmentInfo2.Left is IdentifierNameSyntax identifierName2 && string.Equals(identifierName.Identifier.ValueText, identifierName2.Identifier.ValueText, StringComparison.Ordinal)) { return; } } StatementSyntax nextStatement = statementsInfo[index + 1]; if (nextStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } if (nextStatement is not ReturnStatementSyntax returnStatement) { return; } if (returnStatement.Expression?.WalkDownParentheses() is not IdentifierNameSyntax identifierName3) { return; } if (!string.Equals(identifierName.Identifier.ValueText, identifierName3.Identifier.ValueText, StringComparison.Ordinal)) { return; } ISymbol symbol = context.SemanticModel.GetSymbol(identifierName, context.CancellationToken); switch (symbol?.Kind) { case SymbolKind.Local: { break; } case SymbolKind.Parameter: { if (((IParameterSymbol)symbol).RefKind != RefKind.None) { return; } break; } default: { return; } } if (IsAssignedInsideAnonymousFunctionButDeclaredOutsideOfIt()) { return; } bool result; RemoveRedundantAssignmentWalker walker = null; try { walker = RemoveRedundantAssignmentWalker.GetInstance(); walker.Symbol = symbol; walker.SemanticModel = context.SemanticModel; walker.CancellationToken = context.CancellationToken; walker.Result = false; walker.Visit(assignmentInfo.Right); result = walker.Result; } finally { if (walker != null) { RemoveRedundantAssignmentWalker.Free(walker); } } if (result) { return; } if (IsDeclaredInTryStatementOrCatchClauseAndReferencedInFinallyClause(context, assignmentInfo.Statement, symbol)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantAssignment, assignment); bool IsAssignedInsideAnonymousFunctionButDeclaredOutsideOfIt() { SyntaxNode declaringSyntax = null; SyntaxNode n = assignment.Parent; do { if (CSharpFacts.IsAnonymousFunctionExpression(n.Kind())) { if (declaringSyntax == null) { declaringSyntax = symbol.GetSyntaxOrDefault(); Debug.Assert(declaringSyntax != null, ""); if (declaringSyntax == null) { break; } SyntaxDebug.Assert(declaringSyntax.IsKind(SyntaxKind.VariableDeclarator, SyntaxKind.Parameter), declaringSyntax); } SyntaxNode n2 = declaringSyntax.Parent; do { if (CSharpFacts.IsAnonymousFunctionExpression(n2.Kind())) { return(!object.ReferenceEquals(n, n2)); } if (n2 is MemberDeclarationSyntax) { break; } n2 = n2.Parent; }while (n2 != null); return(true); } else if (n is MemberDeclarationSyntax) { break; } n = n.Parent; }while (n != null); return(false); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out ExpressionSyntax expression)) { return; } Diagnostic diagnostic = context.Diagnostics[0]; Document document = context.Document; switch (expression) { case SimpleNameSyntax simpleName: { SyntaxDebug.Assert(expression.IsKind(SyntaxKind.IdentifierName, SyntaxKind.GenericName), expression); if (simpleName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccessExpression = (MemberAccessExpressionSyntax)simpleName.Parent; SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression)) { if (!memberAccessExpression.Parent.IsParentKind(SyntaxKind.ConditionalAccessExpression) && IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceInvocationWithMemberAccessOrViceVersa, context.Document, root.SyntaxTree)) { var invocationExpression = (InvocationExpressionSyntax)memberAccessExpression.Parent; if (!invocationExpression.ArgumentList.Arguments.Any()) { ReplaceInvocationWithMemberAccess(context, diagnostic, memberAccessExpression, invocationExpression, semanticModel); } } } else { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.FixMemberAccessName, context.Document, root.SyntaxTree)) { CodeFixRegistrationResult result = ReplaceCountWithLengthOrViceVersa(context, diagnostic, memberAccessExpression.Expression, simpleName, semanticModel); if (result.Success) { break; } } if (!memberAccessExpression.IsParentKind(SyntaxKind.ConditionalAccessExpression) && IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceInvocationWithMemberAccessOrViceVersa, context.Document, root.SyntaxTree)) { ReplaceMemberAccessWithInvocation(context, diagnostic, memberAccessExpression, semanticModel); } } } break; } case MemberBindingExpressionSyntax memberBindingExpression: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.FixMemberAccessName, context.Document, root.SyntaxTree)) { break; } if (memberBindingExpression.Parent is not ConditionalAccessExpressionSyntax conditionalAccessExpression) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); CodeFixRegistrationResult result = ReplaceCountWithLengthOrViceVersa(context, diagnostic, conditionalAccessExpression.Expression, memberBindingExpression.Name, semanticModel); break; } case AwaitExpressionSyntax awaitExpression: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveAwaitKeyword, context.Document, root.SyntaxTree)) { break; } CodeAction codeAction = CodeAction.Create( "Remove 'await'", ct => { ExpressionSyntax expression2 = awaitExpression.Expression; SyntaxTriviaList leadingTrivia = awaitExpression .GetLeadingTrivia() .AddRange(awaitExpression.AwaitKeyword.TrailingTrivia.EmptyIfWhitespace()) .AddRange(expression2.GetLeadingTrivia().EmptyIfWhitespace()); ExpressionSyntax newNode = expression2.WithLeadingTrivia(leadingTrivia); return(document.ReplaceNodeAsync(awaitExpression, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } SyntaxKind kind = token.Kind(); Diagnostic diagnostic = context.Diagnostics[0]; Document document = context.Document; switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CS0023_OperatorCannotBeAppliedToOperand: { if (kind == SyntaxKind.QuestionToken && token.Parent is ConditionalAccessExpressionSyntax conditionalAccess) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(conditionalAccess.Expression, context.CancellationToken); if (typeSymbol?.IsErrorType() == false && !typeSymbol.IsNullableType()) { if (typeSymbol.IsValueType) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConditionalAccess, document, root.SyntaxTree)) { CodeAction codeAction = CodeAction.Create( "Remove '?' operator", ct => document.WithTextChangeAsync(token.Span, "", ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } else if (typeSymbol.IsReferenceType) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddArgumentList, document, root.SyntaxTree) && conditionalAccess.WhenNotNull is MemberBindingExpressionSyntax memberBindingExpression) { ConditionalAccessExpressionSyntax newNode = conditionalAccess.WithWhenNotNull( InvocationExpression( memberBindingExpression.WithoutTrailingTrivia(), ArgumentList().WithTrailingTrivia(memberBindingExpression.GetTrailingTrivia()))); CodeAction codeAction = CodeAction.Create( "Add argument list", ct => document.ReplaceNodeAsync(conditionalAccess, newNode, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } } } break; } case CompilerDiagnosticIdentifiers.CS0267_PartialModifierCanOnlyAppearImmediatelyBeforeClassStructInterfaceOrVoid: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.OrderModifiers, document, root.SyntaxTree)) { break; } ModifiersCodeFixRegistrator.MoveModifier(context, diagnostic, token.Parent, token); break; } case CompilerDiagnosticIdentifiers.CS1750_ValueCannotBeUsedAsDefaultParameter: { if (token.Parent is not ParameterSyntax parameter) { break; } ExpressionSyntax value = parameter.Default?.Value; if (value == null) { break; } if (value.IsKind(SyntaxKind.NullLiteralExpression)) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue, document, root.SyntaxTree)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, value, semanticModel); } } else if (!value.IsKind(SyntaxKind.DefaultExpression, SyntaxKind.DefaultLiteralExpression)) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeParameterType, document, root.SyntaxTree)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(value, context.CancellationToken); if (!typeSymbol.IsKind(SymbolKind.ErrorType)) { CodeFixRegistrator.ChangeType(context, diagnostic, parameter.Type, typeSymbol, semanticModel); } } } break; } case CompilerDiagnosticIdentifiers.CS0126_ObjectOfTypeConvertibleToTypeIsRequired: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReturnDefaultValue, document, root.SyntaxTree)) { break; } if (!token.IsKind(SyntaxKind.ReturnKeyword)) { break; } if (!token.IsParentKind(SyntaxKind.ReturnStatement)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol symbol = semanticModel.GetEnclosingSymbol(token.SpanStart, context.CancellationToken); if (symbol == null) { break; } SymbolKind symbolKind = symbol.Kind; ITypeSymbol typeSymbol = null; if (symbolKind == SymbolKind.Method) { var methodSymbol = (IMethodSymbol)symbol; typeSymbol = methodSymbol.ReturnType; if (methodSymbol.IsAsync && (typeSymbol is INamedTypeSymbol namedTypeSymbol)) { ImmutableArray <ITypeSymbol> typeArguments = namedTypeSymbol.TypeArguments; if (typeArguments.Any()) { typeSymbol = typeArguments[0]; } } } else if (symbolKind == SymbolKind.Property) { typeSymbol = ((IPropertySymbol)symbol).Type; } else { Debug.Fail(symbolKind.ToString()); } if (typeSymbol == null) { break; } if (typeSymbol.Kind == SymbolKind.ErrorType) { break; } if (!typeSymbol.SupportsExplicitDeclaration()) { break; } var returnStatement = (ReturnStatementSyntax)token.Parent; CodeAction codeAction = CodeAction.Create( "Return default value", ct => { ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions()); if (expression.IsKind(SyntaxKind.DefaultExpression) && document.SupportsLanguageFeature(CSharpLanguageFeature.DefaultLiteral)) { expression = CSharpFactory.DefaultLiteralExpression().WithTriviaFrom(expression); } ReturnStatementSyntax newNode = returnStatement.WithExpression(expression); return(document.ReplaceNodeAsync(returnStatement, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS1031_TypeExpected: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddMissingType, document, root.SyntaxTree)) { break; } if (!token.IsKind(SyntaxKind.CloseParenToken)) { break; } if (token.Parent is not DefaultExpressionSyntax defaultExpression) { break; } if (defaultExpression.Type is not IdentifierNameSyntax identifierName) { break; } if (!identifierName.IsMissing) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TypeInfo typeInfo = semanticModel.GetTypeInfo(defaultExpression, context.CancellationToken); ITypeSymbol convertedType = typeInfo.ConvertedType; if (convertedType?.SupportsExplicitDeclaration() != true) { break; } CodeAction codeAction = CodeAction.Create( $"Add type '{SymbolDisplay.ToMinimalDisplayString(convertedType, semanticModel, defaultExpression.SpanStart, SymbolDisplayFormats.DisplayName)}'", ct => { TypeSyntax newType = convertedType.ToTypeSyntax() .WithTriviaFrom(identifierName) .WithFormatterAndSimplifierAnnotation(); return(document.ReplaceNodeAsync(identifierName, newType, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS1597_SemicolonAfterMethodOrAccessorBlockIsNotValid: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveSemicolon, document, root.SyntaxTree)) { break; } if (!token.IsKind(SyntaxKind.SemicolonToken)) { break; } switch (token.Parent) { case MethodDeclarationSyntax methodDeclaration: { BlockSyntax body = methodDeclaration.Body; if (body == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", ct => { SyntaxTriviaList trivia = body .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); MethodDeclarationSyntax newNode = methodDeclaration .WithBody(body.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(document.ReplaceNodeAsync(methodDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case PropertyDeclarationSyntax propertyDeclaration: { AccessorListSyntax accessorList = propertyDeclaration.AccessorList; if (accessorList == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", ct => { SyntaxTriviaList trivia = accessorList .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); PropertyDeclarationSyntax newNode = propertyDeclaration .WithAccessorList(accessorList.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(document.ReplaceNodeAsync(propertyDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case AccessorDeclarationSyntax accessorDeclaration: { BlockSyntax body = accessorDeclaration.Body; if (body == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", ct => { SyntaxTriviaList trivia = body .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); AccessorDeclarationSyntax newNode = accessorDeclaration .WithBody(body.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(document.ReplaceNodeAsync(accessorDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } break; } case CompilerDiagnosticIdentifiers.CS0030_CannotConvertType: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeForEachType, document, root.SyntaxTree)) { break; } if (!token.IsKind(SyntaxKind.ForEachKeyword)) { break; } if (token.Parent is not ForEachStatementSyntax forEachStatement) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ForEachStatementInfo info = semanticModel.GetForEachStatementInfo(forEachStatement); ITypeSymbol typeSymbol = info.ElementType; if (typeSymbol.SupportsExplicitDeclaration()) { CodeFixRegistrator.ChangeType(context, diagnostic, forEachStatement.Type, typeSymbol, semanticModel, CodeFixIdentifiers.ChangeForEachType); } CodeFixRegistrator.ChangeTypeToVar(context, diagnostic, forEachStatement.Type, CodeFixIdentifiers.ChangeTypeToVar); break; } case CompilerDiagnosticIdentifiers.CS1737_OptionalParametersMustAppearAfterAllRequiredParameters: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddDefaultValueToParameter, document, root.SyntaxTree)) { break; } if (token.Parent is not BaseParameterListSyntax parameterList) { break; } SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters; ParameterSyntax parameter = null; for (int i = 0; i < parameters.Count; i++) { ParameterSyntax p = parameters[i]; if (p.FullSpan.End <= token.SpanStart) { parameter = p; } else { break; } } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); IParameterSymbol parameterSymbol = semanticModel.GetDeclaredSymbol(parameter, context.CancellationToken); ITypeSymbol typeSymbol = parameterSymbol.Type; if (typeSymbol.Kind == SymbolKind.ErrorType) { break; } CodeAction codeAction = CodeAction.Create( "Add default value", ct => { ExpressionSyntax defaultValue = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions()); ParameterSyntax newParameter = parameter .WithDefault(EqualsValueClause(defaultValue).WithTrailingTrivia(parameter.GetTrailingTrivia())) .WithoutTrailingTrivia() .WithFormatterAnnotation(); return(document.ReplaceNodeAsync(parameter, newParameter, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS8632_AnnotationForNullableReferenceTypesShouldOnlyBeUsedWithinNullableAnnotationsContext: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveAnnotationForNullableReferenceTypes, document, root.SyntaxTree)) { break; } if (!token.IsKind(SyntaxKind.QuestionToken)) { return; } CodeAction codeAction = CodeAction.Create( "Remove 'nullable' annotation", ct => { var textChange = new TextChange(token.Span, ""); return(document.WithTextChangeAsync(textChange, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS8602_DereferenceOfPossiblyNullReference: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, document, root.SyntaxTree)) { break; } Debug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token.Kind().ToString()); if (!token.IsKind(SyntaxKind.IdentifierToken)) { return; } if (!token.IsParentKind(SyntaxKind.IdentifierName)) { return; } SyntaxNode node = token.Parent .WalkUp(f => f.IsKind(SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.InvocationExpression, SyntaxKind.ElementAccessExpression)) .Parent; if (node.IsKind(SyntaxKind.ExpressionStatement) && token.SpanStart == node.SpanStart) { CodeAction codeAction = CodeAction.Create( "Use null propagation operator", ct => { var textChange = new TextChange(new TextSpan(token.Span.End, 0), "?"); return(document.WithTextChangeAsync(textChange, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } return; } case CompilerDiagnosticIdentifiers.CS8604_PossibleNullReferenceArgumentForParameter: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, document, root.SyntaxTree)) { break; } Debug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token.Kind().ToString()); if (!token.IsKind(SyntaxKind.IdentifierToken)) { return; } if (!token.IsParentKind(SyntaxKind.IdentifierName)) { return; } CodeAction codeAction = CodeAction.Create( "Use null-forgiving operator", ct => { var identifierName = (IdentifierNameSyntax)token.Parent; PostfixUnaryExpressionSyntax newExpression = SuppressNullableWarningExpression(identifierName.WithoutTrivia()) .WithTriviaFrom(identifierName); return(document.ReplaceNodeAsync(identifierName, newExpression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); return; } case CompilerDiagnosticIdentifiers.CS8618_NonNullableMemberIsUninitialized: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, document, root.SyntaxTree)) { break; } Debug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token.Kind().ToString()); if (!token.IsKind(SyntaxKind.IdentifierToken)) { return; } if (token.IsParentKind(SyntaxKind.PropertyDeclaration)) { CodeAction codeAction = CodeAction.Create( "Use null-forgiving operator", ct => { var property = (PropertyDeclarationSyntax)token.Parent; PropertyDeclarationSyntax newProperty = property .WithoutTrailingTrivia() .WithInitializer(EqualsValueClause(SuppressNullableWarningExpression(NullLiteralExpression()))) .WithSemicolonToken(SemicolonToken().WithTrailingTrivia(property.GetTrailingTrivia())); return(document.ReplaceNodeAsync(property, newProperty, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else { SyntaxDebug.Assert( (token.IsParentKind(SyntaxKind.VariableDeclarator) && token.Parent.IsParentKind(SyntaxKind.VariableDeclaration) && token.Parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.EventFieldDeclaration)) || token.IsParentKind(SyntaxKind.ConstructorDeclaration), token); if (token.IsParentKind(SyntaxKind.VariableDeclarator) && token.Parent.IsParentKind(SyntaxKind.VariableDeclaration) && token.Parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration)) { CodeAction codeAction = CodeAction.Create( "Use null-forgiving operator", ct => { var declarator = (VariableDeclaratorSyntax)token.Parent; VariableDeclaratorSyntax newDeclarator = declarator .WithoutTrailingTrivia() .WithInitializer( EqualsValueClause(SuppressNullableWarningExpression(NullLiteralExpression())) .WithTrailingTrivia(declarator.GetTrailingTrivia())); return(document.ReplaceNodeAsync(declarator, newDeclarator, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } break; } case CompilerDiagnosticIdentifiers.CS8403_MethodWithIteratorBlockMustBeAsyncToReturnIAsyncEnumerableOfT: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddAsyncModifier, document, root.SyntaxTree)) { break; } SyntaxDebug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token); SyntaxDebug.Assert(token.IsParentKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement), token.Parent); if (token.IsParentKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement)) { ModifiersCodeFixRegistrator.AddModifier( context, diagnostic, token.Parent, SyntaxKind.AsyncKeyword, additionalKey: CodeFixIdentifiers.AddAsyncModifier); } break; } } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { Diagnostic diagnostic = context.Diagnostics[0]; SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveUnreachableCode, context.Document, root.SyntaxTree)) { return; } if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement)) { return; } SyntaxDebug.Assert(context.Span.Start == statement.SpanStart, statement); if (context.Span.Start != statement.SpanStart) { return; } CodeAction codeAction = CreateCodeActionForIfElse(context.Document, diagnostic, statement.Parent); if (codeAction != null) { context.RegisterCodeFix(codeAction, diagnostic); return; } StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(statement); if (statementsInfo.Success) { codeAction = CodeAction.Create( Title, ct => { SyntaxList <StatementSyntax> statements = statementsInfo.Statements; int index = statements.IndexOf(statement); if (index == statements.Count - 1) { return(context.Document.RemoveStatementAsync(statement, ct)); } else { int lastIndex = statements.LastIndexOf(f => !f.IsKind(SyntaxKind.LocalFunctionStatement)); SyntaxList <StatementSyntax> nodes = RemoveRange(statements, index, lastIndex - index + 1, f => !f.IsKind(SyntaxKind.LocalFunctionStatement)); return(context.Document.ReplaceStatementsAsync( statementsInfo, nodes, ct)); } }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { Diagnostic diagnostic = context.Diagnostics[0]; SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemovePropertyOrFieldInitializer, context.Document, root.SyntaxTree)) { return; } if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } SyntaxDebug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token); if (!token.IsKind(SyntaxKind.IdentifierToken)) { return; } switch (token.Parent) { case PropertyDeclarationSyntax propertyDeclaration: { EqualsValueClauseSyntax initializer = propertyDeclaration.Initializer; CodeAction codeAction = CodeAction.Create( Title, ct => { PropertyDeclarationSyntax newNode = propertyDeclaration .RemoveNode(initializer) .WithSemicolonToken(default(SyntaxToken)) .AppendToTrailingTrivia(propertyDeclaration.SemicolonToken.GetAllTrivia()) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(propertyDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemovePropertyOrFieldInitializer)); context.RegisterCodeFix(codeAction, diagnostic); break; } case VariableDeclaratorSyntax variableDeclarator: { EqualsValueClauseSyntax initializer = variableDeclarator.Initializer; CodeAction codeAction = CodeAction.Create( Title, ct => { VariableDeclaratorSyntax newNode = variableDeclarator .RemoveNode(initializer) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(variableDeclarator, newNode, ct)); }, GetEquivalenceKey(CompilerDiagnosticIdentifiers.CS0573_CannotHaveInstancePropertyOrFieldInitializersInStruct, CodeFixIdentifiers.RemovePropertyOrFieldInitializer)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }
public static void ComputeCodeFix( CodeFixContext context, Diagnostic diagnostic, ExpressionSyntax expression, SemanticModel semanticModel) { TypeInfo typeInfo = semanticModel.GetTypeInfo(expression, context.CancellationToken); ITypeSymbol expressionTypeSymbol = typeInfo.Type; if (expressionTypeSymbol == null) { return; } if (!expressionTypeSymbol.SupportsExplicitDeclaration()) { return; } (ISymbol symbol, ITypeSymbol typeSymbol) = GetContainingSymbolAndType(expression, semanticModel, context.CancellationToken); SyntaxDebug.Assert(symbol != null, expression); if (symbol == null) { return; } if (symbol.IsOverride) { return; } if (symbol.ImplementsInterfaceMember()) { return; } SyntaxNode node = symbol.GetSyntax(context.CancellationToken); if (node.IsKind(SyntaxKind.VariableDeclarator)) { node = node.Parent.Parent; } TypeSyntax type = CSharpUtility.GetTypeOrReturnType(node); if (type == null) { return; } ITypeSymbol newTypeSymbol = expressionTypeSymbol; string additionalKey = null; var isAsyncMethod = false; var insertAwait = false; var isYield = false; if (symbol.IsAsyncMethod()) { isAsyncMethod = true; INamedTypeSymbol taskOfT = semanticModel.GetTypeByMetadataName("System.Threading.Tasks.Task`1"); if (taskOfT == null) { return; } if (expression.Kind() == SyntaxKind.AwaitExpression) { newTypeSymbol = taskOfT.Construct(expressionTypeSymbol); } else if (SymbolEqualityComparer.Default.Equals(expressionTypeSymbol, taskOfT)) { insertAwait = true; additionalKey = "InsertAwait"; } else if (expressionTypeSymbol.HasMetadataName(MetadataNames.System_Threading_Tasks_Task)) { return; } } else if (expression.IsParentKind(SyntaxKind.YieldReturnStatement)) { isYield = true; newTypeSymbol = semanticModel .Compilation .GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T) .Construct(expressionTypeSymbol); } if (!isYield && !isAsyncMethod && !typeSymbol.OriginalDefinition.IsIEnumerableOfT() && newTypeSymbol.OriginalDefinition.HasMetadataName(MetadataNames.System_Linq_IOrderedEnumerable_T)) { INamedTypeSymbol constructedEnumerableSymbol = semanticModel .Compilation .GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T) .Construct(((INamedTypeSymbol)newTypeSymbol).TypeArguments.ToArray()); RegisterCodeFix(context, diagnostic, node, type, expression, constructedEnumerableSymbol, semanticModel, insertAwait: false); additionalKey = "IOrderedEnumerable<T>"; } RegisterCodeFix(context, diagnostic, node, type, expression, newTypeSymbol, semanticModel, insertAwait: insertAwait, additionalKey: additionalKey); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CS1591_MissingXmlCommentForPubliclyVisibleTypeOrMember: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddDocumentationComment, context.Document, root.SyntaxTree)) { break; } CodeAction codeAction = CodeAction.Create( "Add documentation comment", ct => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, false, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); CodeAction codeAction2 = CodeAction.Create( "Add documentation comment (copy from base if available)", ct => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, true, ct), GetEquivalenceKey(diagnostic, "CopyFromBaseIfAvailable")); context.RegisterCodeFix(codeAction2, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS0508_MethodReturnTypeMustMatchOverriddenMethodReturnType: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMethodReturnType, context.Document, root.SyntaxTree)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); ITypeSymbol typeSymbol = methodSymbol.OverriddenMethod.ReturnType; CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel); break; } case CompilerDiagnosticIdentifiers.CS0766_PartialMethodsMustHaveVoidReturnType: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMethodReturnType, context.Document, root.SyntaxTree)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration; MethodDeclarationSyntax otherPart = semanticModel.GetOtherPart(methodDeclaration, context.CancellationToken); if (otherPart == null) { break; } CodeAction codeAction = CodeAction.Create( "Change return type to 'void'", ct => { return(context.Document.Solution().ReplaceNodesAsync( new MethodDeclarationSyntax[] { methodDeclaration, otherPart }, (node, _) => node.WithReturnType(CSharpFactory.VoidType().WithTriviaFrom(node.ReturnType)), ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS1715_MemberTypeMustMatchOverriddenMemberType: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType, context.Document, root.SyntaxTree)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = null; switch (memberDeclaration.Kind()) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.IndexerDeclaration: { var propertySymbol = (IPropertySymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = propertySymbol.OverriddenProperty.Type; break; } case SyntaxKind.EventDeclaration: { var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } case SyntaxKind.EventFieldDeclaration: { VariableDeclaratorSyntax declarator = ((EventFieldDeclarationSyntax)memberDeclaration).Declaration.Variables[0]; var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(declarator, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } } CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel); break; } case CompilerDiagnosticIdentifiers.CS0260_MissingPartialModifier: case CompilerDiagnosticIdentifiers.CS0751_PartialMethodMustBeDeclaredInPartialClassOrPartialStruct: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddPartialModifier, context.Document, root.SyntaxTree)) { break; } SyntaxNode node = null; switch (memberDeclaration.Kind()) { case SyntaxKind.MethodDeclaration: { if (memberDeclaration.IsParentKind( SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.RecordDeclaration, SyntaxKind.RecordStructDeclaration)) { node = memberDeclaration.Parent; } break; } case SyntaxKind.ClassDeclaration: case SyntaxKind.StructDeclaration: case SyntaxKind.RecordStructDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.RecordDeclaration: { node = memberDeclaration; break; } } SyntaxDebug.Assert(node != null, memberDeclaration); if (node == null) { break; } ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.PartialKeyword, title: $"Make {CSharpFacts.GetTitle(node)} partial"); break; } case CompilerDiagnosticIdentifiers.CS0513_MemberIsAbstractButItIsContainedInNonAbstractClass: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeContainingClassAbstract, context.Document, root.SyntaxTree)) { break; } if (!memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration)) { break; } ModifiersCodeFixRegistrator.AddModifier( context, diagnostic, memberDeclaration.Parent, SyntaxKind.AbstractKeyword, title: "Make containing class abstract"); break; } case CompilerDiagnosticIdentifiers.CS0132_StaticConstructorMustBeParameterless: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveParametersFromStaticConstructor, context.Document, root.SyntaxTree)) { break; } var constructorDeclaration = (ConstructorDeclarationSyntax)memberDeclaration; CodeAction codeAction = CodeAction.Create( "Remove parameters", ct => { ParameterListSyntax parameterList = constructorDeclaration.ParameterList; ParameterListSyntax newParameterList = parameterList .WithParameters(default(SeparatedSyntaxList <ParameterSyntax>)) .WithOpenParenToken(parameterList.OpenParenToken.WithoutTrailingTrivia()) .WithCloseParenToken(parameterList.CloseParenToken.WithoutLeadingTrivia()); ConstructorDeclarationSyntax newNode = constructorDeclaration.WithParameterList(newParameterList); return(context.Document.ReplaceNodeAsync(constructorDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS0541_ExplicitInterfaceDeclarationCanOnlyBeDeclaredInClassOrStruct: case CompilerDiagnosticIdentifiers.CS0525_InterfacesCannotContainFields: case CompilerDiagnosticIdentifiers.CS0567_InterfacesCannotContainOperators: case CompilerDiagnosticIdentifiers.CS0524_InterfacesCannotDeclareTypes: case CompilerDiagnosticIdentifiers.CS0575_OnlyClassTypesCanContainDestructors: case CompilerDiagnosticIdentifiers.CS0568_StructsCannotContainExplicitParameterlessConstructors: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveMemberDeclaration, context.Document, root.SyntaxTree)) { break; } CodeFixRegistrator.RemoveMemberDeclaration(context, diagnostic, memberDeclaration); break; } case CompilerDiagnosticIdentifiers.CS0574_NameOfDestructorMustMatchNameOfClass: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RenameDestructorToMatchClassName, context.Document, root.SyntaxTree)) { break; } if (memberDeclaration is not DestructorDeclarationSyntax destructorDeclaration) { break; } if (memberDeclaration.Parent is not ClassDeclarationSyntax classDeclaration) { break; } if (classDeclaration.Identifier.ValueText.Length == 0) { break; } CodeAction codeAction = CodeAction.Create( "Rename destructor to match class name", ct => { DestructorDeclarationSyntax newNode = destructorDeclaration.WithIdentifier(classDeclaration.Identifier.WithTriviaFrom(destructorDeclaration.Identifier)); return(context.Document.ReplaceNodeAsync(destructorDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS8139_CannotChangeTupleElementNameWhenOverridingInheritedMember: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RenameTupleElement, context.Document, root.SyntaxTree)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (memberDeclaration is MethodDeclarationSyntax methodDeclaration) { IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken); if (methodSymbol.ReturnType is not INamedTypeSymbol tupleType) { break; } if (!tupleType.IsTupleType) { break; } if (methodSymbol.OverriddenMethod?.ReturnType is not INamedTypeSymbol baseTupleType) { break; } if (!baseTupleType.IsTupleType) { break; } ImmutableArray <IFieldSymbol> elements = tupleType.TupleElements; ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements; if (elements.Length != baseElements.Length) { break; } int i = 0; while (i < elements.Length) { if (elements[i].Name != baseElements[i].Name) { break; } i++; } if (i == elements.Length) { break; } TupleElementSyntax tupleElement = ((TupleTypeSyntax)methodDeclaration.ReturnType).Elements[i]; CodeAction codeAction = CodeAction.Create( $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'", ct => RenameTupleElementAsync(context.Document, methodDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else if (memberDeclaration is PropertyDeclarationSyntax propertyDeclaration) { IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, context.CancellationToken); if (propertySymbol.Type is not INamedTypeSymbol tupleType) { break; } if (!tupleType.IsTupleType) { break; } if (propertySymbol.OverriddenProperty?.Type is not INamedTypeSymbol baseTupleType) { break; } if (!baseTupleType.IsTupleType) { break; } ImmutableArray <IFieldSymbol> elements = tupleType.TupleElements; ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements; if (elements.Length != baseElements.Length) { break; } int i = 0; while (i < elements.Length) { if (elements[i].Name != baseElements[i].Name) { break; } i++; } if (i == elements.Length) { break; } TupleElementSyntax tupleElement = ((TupleTypeSyntax)propertyDeclaration.Type).Elements[i]; CodeAction codeAction = CodeAction.Create( $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'", ct => RenameTupleElementAsync(context.Document, propertyDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case CompilerDiagnosticIdentifiers.CS3000_MethodsWithVariableArgumentsAreNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3001_ArgumentTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3002_ReturnTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3003_TypeOfVariableIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3005_IdentifierDifferingOnlyInCaseIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3006_OverloadedMethodDifferingOnlyInRefOrOutOrInArrayRankIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3007_OverloadedMethodDifferingOnlyByUnnamedArrayTypesIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3008_IdentifierIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3009_BaseTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3016_ArraysAsAttributeArgumentsIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3024_ConstraintTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3027_TypeIsNotCLSCompliantBecauseBaseInterfaceIsNotCLSCompliant: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.MarkDeclarationAsNonCLSCompliant, context.Document, root.SyntaxTree)) { break; } CodeAction codeAction = CodeAction.Create( $"Mark {CSharpFacts.GetTitle(memberDeclaration)} as non-CLS-compliant", ct => MarkDeclarationAsNonCLSCompliantAsync(context.Document, memberDeclaration, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS0539_ExplicitInterfaceDeclarationIsNotMemberOfInterface: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddParameterToExplicitlyImplementedInterfaceMember, context.Document, root.SyntaxTree)) { break; } var context2 = new CommonFixContext( context.Document, GetEquivalenceKey(diagnostic), await context.GetSemanticModelAsync().ConfigureAwait(false), context.CancellationToken); CodeAction codeAction = AddParameterToInterfaceMemberRefactoring.ComputeRefactoringForExplicitImplementation(context2, memberDeclaration); if (codeAction != null) { context.RegisterCodeFix(codeAction, diagnostic); } break; } } } }
public static async Task <Document> RefactorAsync( Document document, MemberDeclarationSyntax member, bool copyAfter = true, CancellationToken cancellationToken = default) { MemberDeclarationSyntax newMember = member; SyntaxToken identifier = GetIdentifier(member); if (identifier != default) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); string newName = identifier.ValueText; if (!member.IsKind(SyntaxKind.ConstructorDeclaration)) { newName = NameGenerator.Default.EnsureUniqueName(newName, semanticModel, member.SpanStart); ISymbol symbol = semanticModel.GetDeclaredSymbol(member, cancellationToken); ImmutableArray <SyntaxNode> references = await SyntaxFinder.FindReferencesAsync(symbol, document.Solution(), documents : ImmutableHashSet.Create(document), cancellationToken : cancellationToken).ConfigureAwait(false); SyntaxToken newIdentifier = SyntaxFactory.Identifier(newName); newMember = member.ReplaceNodes( references.Where(n => member.Contains(n)), (n, _) => { if (n is IdentifierNameSyntax identifierName) { return(identifierName.WithIdentifier(newIdentifier.WithTriviaFrom(identifierName.Identifier))); } else { SyntaxDebug.Assert(n.IsKind(SyntaxKind.ThisConstructorInitializer, SyntaxKind.BaseConstructorInitializer), n); return(n); } }); newMember = SetIdentifier(newMember, newIdentifier.WithRenameAnnotation()); } } else { newMember = newMember.WithNavigationAnnotation(); } MemberDeclarationListInfo memberList = SyntaxInfo.MemberDeclarationListInfo(member.Parent); int index = memberList.IndexOf(member); if (index == 0) { if (copyAfter) { SyntaxToken?openBrace = memberList.OpenBraceToken; if (openBrace != null && openBrace.Value.GetFullSpanEndLine() == member.GetFullSpanStartLine()) { newMember = newMember.WithLeadingTrivia(member.GetLeadingTrivia().Insert(0, NewLine())); } } else { SyntaxToken?closeBrace = memberList.CloseBraceToken; if (closeBrace != null) { newMember = newMember.WithTrailingTrivia(member.GetTrailingTrivia().Add(NewLine())); } } } int insertIndex = (copyAfter) ? index + 1 : index; return(await document.ReplaceMembersAsync(memberList, memberList.Members.Insert(insertIndex, newMember), cancellationToken).ConfigureAwait(false)); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { Diagnostic diagnostic = context.Diagnostics[0]; SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMethodReturnType, context.Document, root.SyntaxTree)) { return; } if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement))) { return; } BlockSyntax body = (node is MethodDeclarationSyntax methodDeclaration) ? methodDeclaration.Body : ((LocalFunctionStatementSyntax)node).Body; SyntaxDebug.Assert(body != null, node); if (body == null) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = null; HashSet <ITypeSymbol> typeSymbols = null; INamedTypeSymbol ienumerableOfTSymbol = null; foreach (SyntaxNode descendant in body.DescendantNodes(descendIntoChildren: f => !CSharpFacts.IsFunction(f.Kind()))) { if (!descendant.IsKind(SyntaxKind.YieldReturnStatement)) { continue; } var yieldReturn = (YieldStatementSyntax)descendant; ExpressionSyntax expression = yieldReturn.Expression; if (expression == null) { continue; } var namedTypeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken) as INamedTypeSymbol; if (namedTypeSymbol?.IsErrorType() != false) { continue; } if (typeSymbol == null) { typeSymbol = namedTypeSymbol; } else { if (typeSymbols == null) { typeSymbols = new HashSet <ITypeSymbol>() { typeSymbol }; } if (!typeSymbols.Add(namedTypeSymbol)) { continue; } } if (ienumerableOfTSymbol == null) { ienumerableOfTSymbol = semanticModel.GetTypeByMetadataName("System.Collections.Generic.IEnumerable`1"); } CodeFixRegistrator.ChangeTypeOrReturnType( context, diagnostic, node, ienumerableOfTSymbol.Construct(namedTypeSymbol), semanticModel, additionalKey: SymbolDisplay.ToMinimalDisplayString(namedTypeSymbol, semanticModel, node.SpanStart, SymbolDisplayFormats.DisplayName)); } }
public static SyntaxList <AttributeListSyntax> GetAttributeLists(this SyntaxNode node) { if (node == null) { throw new ArgumentNullException(nameof(node)); } switch (node.Kind()) { case SyntaxKind.EnumDeclaration: return(((EnumDeclarationSyntax)node).AttributeLists); case SyntaxKind.DelegateDeclaration: return(((DelegateDeclarationSyntax)node).AttributeLists); case SyntaxKind.ClassDeclaration: return(((ClassDeclarationSyntax)node).AttributeLists); case SyntaxKind.TypeParameter: return(((TypeParameterSyntax)node).AttributeLists); case SyntaxKind.RecordDeclaration: case SyntaxKind.RecordStructDeclaration: return(((RecordDeclarationSyntax)node).AttributeLists); case SyntaxKind.StructDeclaration: return(((StructDeclarationSyntax)node).AttributeLists); case SyntaxKind.PropertyDeclaration: return(((PropertyDeclarationSyntax)node).AttributeLists); case SyntaxKind.Parameter: return(((ParameterSyntax)node).AttributeLists); case SyntaxKind.OperatorDeclaration: return(((OperatorDeclarationSyntax)node).AttributeLists); case SyntaxKind.MethodDeclaration: return(((MethodDeclarationSyntax)node).AttributeLists); case SyntaxKind.InterfaceDeclaration: return(((InterfaceDeclarationSyntax)node).AttributeLists); case SyntaxKind.IndexerDeclaration: return(((IndexerDeclarationSyntax)node).AttributeLists); case SyntaxKind.FieldDeclaration: return(((FieldDeclarationSyntax)node).AttributeLists); case SyntaxKind.EventFieldDeclaration: return(((EventFieldDeclarationSyntax)node).AttributeLists); case SyntaxKind.EventDeclaration: return(((EventDeclarationSyntax)node).AttributeLists); case SyntaxKind.EnumMemberDeclaration: return(((EnumMemberDeclarationSyntax)node).AttributeLists); case SyntaxKind.DestructorDeclaration: return(((DestructorDeclarationSyntax)node).AttributeLists); case SyntaxKind.ConversionOperatorDeclaration: return(((ConversionOperatorDeclarationSyntax)node).AttributeLists); case SyntaxKind.ConstructorDeclaration: return(((ConstructorDeclarationSyntax)node).AttributeLists); case SyntaxKind.IncompleteMember: return(((IncompleteMemberSyntax)node).AttributeLists); case SyntaxKind.GetAccessorDeclaration: case SyntaxKind.SetAccessorDeclaration: case SyntaxKind.AddAccessorDeclaration: case SyntaxKind.RemoveAccessorDeclaration: return(((AccessorDeclarationSyntax)node).AttributeLists); default: { SyntaxDebug.Assert(node.IsKind(SyntaxKind.GlobalStatement), node); return(default); } }
private static void AnalyzeSuppressNullableWarningExpression(SyntaxNodeAnalysisContext context) { var suppressExpression = (PostfixUnaryExpressionSyntax)context.Node; SyntaxNode node = suppressExpression.WalkUpParentheses().Parent; if (node is ArgumentSyntax argument) { IParameterSymbol parameterSymbol = context.SemanticModel.DetermineParameter( argument, cancellationToken: context.CancellationToken); if (parameterSymbol?.Type.IsErrorType() == false && parameterSymbol.Type.IsReferenceType && parameterSymbol.Type.NullableAnnotation == NullableAnnotation.Annotated) { foreach (AttributeData attribute in parameterSymbol.GetAttributes()) { INamedTypeSymbol attributeClass = attribute.AttributeClass; if (attributeClass.HasMetadataName(System_Diagnostics_CodeAnalysis_MaybeNullWhenAttribute) || attributeClass.HasMetadataName(System_Diagnostics_CodeAnalysis_NotNullIfNotNullAttribute) || attributeClass.HasMetadataName(System_Diagnostics_CodeAnalysis_NotNullWhenAttribute)) { return; } } context.ReportDiagnostic(DiagnosticRules.UnnecessaryNullForgivingOperator, suppressExpression.OperatorToken); } } else if (node.IsKind(SyntaxKind.EqualsValueClause)) { if (suppressExpression.Operand.WalkDownParentheses().IsKind( SyntaxKind.NullLiteralExpression, SyntaxKind.DefaultLiteralExpression, SyntaxKind.DefaultExpression)) { SyntaxNode parent = node.Parent; if (parent.IsKind(SyntaxKind.PropertyDeclaration)) { var property = (PropertyDeclarationSyntax)node.Parent; if (IsNullableReferenceType(context, property.Type)) { context.ReportDiagnostic(DiagnosticRules.UnnecessaryNullForgivingOperator, node); } } else if (parent.IsKind(SyntaxKind.VariableDeclarator)) { SyntaxDebug.Assert( parent.IsParentKind(SyntaxKind.VariableDeclaration) && parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.EventFieldDeclaration, SyntaxKind.LocalDeclarationStatement), parent); if (parent.IsParentKind(SyntaxKind.VariableDeclaration) && parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.EventFieldDeclaration, SyntaxKind.LocalDeclarationStatement)) { var variableDeclaration = (VariableDeclarationSyntax)parent.Parent; if (IsNullableReferenceType(context, variableDeclaration.Type)) { if (parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration)) { context.ReportDiagnostic(DiagnosticRules.UnnecessaryNullForgivingOperator, node); } else { context.ReportDiagnostic(DiagnosticRules.UnnecessaryNullForgivingOperator, suppressExpression.OperatorToken); } } } } } }
private static void AnalyzeObjectCreationExpression(SyntaxNodeAnalysisContext context) { var objectCreation = (ObjectCreationExpressionSyntax)context.Node; SyntaxNode parent = objectCreation.Parent; switch (parent.Kind()) { case SyntaxKind.ThrowExpression: case SyntaxKind.ThrowStatement: { if (UseImplicitObjectCreation(context) && context.SemanticModel.GetTypeSymbol(objectCreation, context.CancellationToken)? .HasMetadataName(MetadataNames.System_Exception) == true) { ReportDiagnostic(context, objectCreation); } break; } case SyntaxKind.EqualsValueClause: { if (!UseImplicitObjectCreation(context)) { return; } parent = parent.Parent; SyntaxDebug.Assert(parent.IsKind(SyntaxKind.VariableDeclarator, SyntaxKind.PropertyDeclaration), parent); if (parent.IsKind(SyntaxKind.VariableDeclarator)) { parent = parent.Parent; if (parent is VariableDeclarationSyntax variableDeclaration) { SyntaxDebug.Assert(parent.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.LocalDeclarationStatement, SyntaxKind.UsingStatement), parent.Parent); if (parent.IsParentKind(SyntaxKind.FieldDeclaration)) { AnalyzeType(context, objectCreation, variableDeclaration.Type); } else if (parent.IsParentKind(SyntaxKind.LocalDeclarationStatement, SyntaxKind.UsingStatement)) { if (context.UseVarInsteadOfImplicitObjectCreation() == false) { if (variableDeclaration.Type.IsVar) { ReportDiagnostic(context, objectCreation); } else { AnalyzeType(context, objectCreation, variableDeclaration.Type); } } } } } else if (parent.IsKind(SyntaxKind.PropertyDeclaration)) { AnalyzeType(context, objectCreation, ((PropertyDeclarationSyntax)parent).Type); } break; } case SyntaxKind.ArrowExpressionClause: { if (UseImplicitObjectCreation(context)) { TypeSyntax type = DetermineReturnType(parent.Parent); SyntaxDebug.Assert(type is not null, parent); if (type is not null) { AnalyzeType(context, objectCreation, type); } } break; } case SyntaxKind.ArrayInitializerExpression: { SyntaxDebug.Assert(parent.IsParentKind(SyntaxKind.ArrayCreationExpression, SyntaxKind.ImplicitArrayCreationExpression), parent.Parent); if (UseImplicitObjectCreation(context) && parent.IsParentKind(SyntaxKind.ArrayCreationExpression)) { var arrayCreationExpression = (ArrayCreationExpressionSyntax)parent.Parent; AnalyzeType(context, objectCreation, arrayCreationExpression.Type.ElementType); } break; } case SyntaxKind.ReturnStatement: case SyntaxKind.YieldReturnStatement: { if (!UseImplicitObjectCreationWhenTypeIsNotObvious(context)) { return; } for (SyntaxNode node = parent.Parent; node is not null; node = node.Parent) { if (CSharpFacts.IsAnonymousFunctionExpression(node.Kind())) { return; } TypeSyntax type = DetermineReturnType(node); if (type is not null) { if (parent.IsKind(SyntaxKind.YieldReturnStatement)) { ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(type, context.CancellationToken); if (typeSymbol?.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T) { var ienumerableOfT = (INamedTypeSymbol)typeSymbol; ITypeSymbol typeSymbol2 = ienumerableOfT.TypeArguments.Single(); AnalyzeTypeSymbol(context, objectCreation, typeSymbol2); } } else { AnalyzeType(context, objectCreation, type); } return; } } break; } case SyntaxKind.SimpleAssignmentExpression: case SyntaxKind.CoalesceAssignmentExpression: case SyntaxKind.AddAssignmentExpression: case SyntaxKind.SubtractAssignmentExpression: { if (UseImplicitObjectCreationWhenTypeIsNotObvious(context)) { var assignment = (AssignmentExpressionSyntax)parent; AnalyzeExpression(context, objectCreation, assignment.Left); } break; } case SyntaxKind.CoalesceExpression: { if (UseImplicitObjectCreationWhenTypeIsNotObvious(context)) { var coalesceExpression = (BinaryExpressionSyntax)parent; AnalyzeExpression(context, objectCreation, coalesceExpression.Left); } break; } case SyntaxKind.CollectionInitializerExpression: { SyntaxDebug.Assert(parent.IsParentKind(SyntaxKind.ObjectCreationExpression, SyntaxKind.ImplicitObjectCreationExpression, SyntaxKind.SimpleAssignmentExpression), parent.Parent); if (!UseImplicitObjectCreation(context)) { return; } parent = parent.Parent; if (parent.IsKind(SyntaxKind.ObjectCreationExpression, SyntaxKind.ImplicitObjectCreationExpression)) { SyntaxNode parentObjectCreation = parent; parent = parent.Parent; if (parent.IsKind(SyntaxKind.EqualsValueClause)) { parent = parent.Parent; if (parent.IsKind(SyntaxKind.VariableDeclarator)) { parent = parent.Parent; if (parent is VariableDeclarationSyntax variableDeclaration && parent.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.LocalDeclarationStatement)) { if (parentObjectCreation is ExpressionSyntax parentObjectCreationExpression) { AnalyzeExpression(context, objectCreation, parentObjectCreationExpression, isGenericType: true); } else { AnalyzeType(context, objectCreation, variableDeclaration.Type, isGenericType: true); } } } else if (parent.IsKind(SyntaxKind.PropertyDeclaration)) { AnalyzeType(context, objectCreation, ((PropertyDeclarationSyntax)parent).Type); } } } break; } case SyntaxKind.ComplexElementInitializerExpression: { break; } } }
private void AnalyzeImplicitObjectCreationExpression(SyntaxNodeAnalysisContext context) { var implicitObjectCreation = (ImplicitObjectCreationExpressionSyntax)context.Node; SyntaxNode parent = implicitObjectCreation.Parent; switch (parent.Kind()) { case SyntaxKind.ThrowExpression: case SyntaxKind.ThrowStatement: { if (UseExplicitObjectCreation(context) && context.SemanticModel.GetTypeSymbol(implicitObjectCreation, context.CancellationToken)? .HasMetadataName(MetadataNames.System_Exception) == true) { ReportDiagnostic(context, implicitObjectCreation); } break; } case SyntaxKind.EqualsValueClause: { parent = parent.Parent; SyntaxDebug.Assert(parent.IsKind(SyntaxKind.VariableDeclarator, SyntaxKind.PropertyDeclaration), parent); if (parent.IsKind(SyntaxKind.VariableDeclarator)) { parent = parent.Parent; if (parent is VariableDeclarationSyntax variableDeclaration) { SyntaxDebug.Assert(!variableDeclaration.Type.IsVar, variableDeclaration); SyntaxDebug.Assert(parent.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.LocalDeclarationStatement, SyntaxKind.UsingStatement), parent.Parent); if (UseExplicitObjectCreation(context)) { ReportDiagnostic(context, implicitObjectCreation); } else if (parent.IsParentKind(SyntaxKind.LocalDeclarationStatement, SyntaxKind.UsingStatement) && variableDeclaration.Variables.Count == 1 && !variableDeclaration.Type.IsVar && context.UseVarInsteadOfImplicitObjectCreation() == true) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseImplicitOrExplicitObjectCreation, variableDeclaration, "explicit"); } } } else if (parent.IsKind(SyntaxKind.PropertyDeclaration)) { if (UseExplicitObjectCreation(context)) { ReportDiagnostic(context, implicitObjectCreation); } } break; } case SyntaxKind.ArrowExpressionClause: { if (UseExplicitObjectCreation(context)) { TypeSyntax type = DetermineReturnType(parent.Parent); SyntaxDebug.Assert(type is not null, parent); if (type is not null) { ReportDiagnostic(context, implicitObjectCreation); } } return; } case SyntaxKind.ArrayInitializerExpression: { SyntaxDebug.Assert(parent.IsParentKind(SyntaxKind.ArrayCreationExpression, SyntaxKind.ImplicitArrayCreationExpression), parent.Parent); if (UseExplicitObjectCreation(context) && parent.IsParentKind(SyntaxKind.ArrayCreationExpression)) { ReportDiagnostic(context, implicitObjectCreation); } break; } case SyntaxKind.ReturnStatement: case SyntaxKind.YieldReturnStatement: { if (!UseExplicitObjectCreationWhenTypeIsNotObvious(context)) { return; } for (SyntaxNode node = parent.Parent; node is not null; node = node.Parent) { if (CSharpFacts.IsAnonymousFunctionExpression(node.Kind())) { return; } TypeSyntax type = DetermineReturnType(node); if (type is not null) { if (parent.IsKind(SyntaxKind.YieldReturnStatement)) { ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(type, context.CancellationToken); if (typeSymbol?.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T) { ReportDiagnostic(context, implicitObjectCreation); } } else { ReportDiagnostic(context, implicitObjectCreation); } } } break; } case SyntaxKind.SimpleAssignmentExpression: case SyntaxKind.CoalesceAssignmentExpression: case SyntaxKind.AddAssignmentExpression: case SyntaxKind.SubtractAssignmentExpression: case SyntaxKind.CoalesceExpression: { if (UseExplicitObjectCreationWhenTypeIsNotObvious(context)) { ReportDiagnostic(context, implicitObjectCreation); } break; } case SyntaxKind.CollectionInitializerExpression: { SyntaxDebug.Assert(parent.IsParentKind(SyntaxKind.ObjectCreationExpression, SyntaxKind.ImplicitObjectCreationExpression, SyntaxKind.SimpleAssignmentExpression), parent.Parent); if (!UseExplicitObjectCreation(context)) { return; } parent = parent.Parent; if (parent.IsKind(SyntaxKind.ObjectCreationExpression, SyntaxKind.ImplicitObjectCreationExpression)) { parent = parent.Parent; if (parent.IsKind(SyntaxKind.EqualsValueClause)) { parent = parent.Parent; if (parent.IsKind(SyntaxKind.VariableDeclarator)) { parent = parent.Parent; if (parent is VariableDeclarationSyntax) { SyntaxDebug.Assert(parent.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.LocalDeclarationStatement, SyntaxKind.UsingStatement), parent.Parent); if (UseExplicitObjectCreation(context)) { ReportDiagnostic(context, implicitObjectCreation); } } } else if (parent.IsKind(SyntaxKind.PropertyDeclaration)) { if (UseExplicitObjectCreation(context)) { ReportDiagnostic(context, implicitObjectCreation); } } } } break; } case SyntaxKind.ComplexElementInitializerExpression: { break; } } }