diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpTypeStyleDiagnosticAnalyzerBase.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpTypeStyleDiagnosticAnalyzerBase.cs index 50dae10a5fed8..01229ad796c7a 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpTypeStyleDiagnosticAnalyzerBase.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpTypeStyleDiagnosticAnalyzerBase.cs @@ -83,8 +83,13 @@ private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context) var declaration = (ForEachStatementSyntax)declarationStatement; declaredType = declaration.Type; - state = State.Generate(declarationStatement, semanticModel, optionSet, isVariableDeclarationContext: false, cancellationToken: cancellationToken); - shouldAnalyze = IsStylePreferred(semanticModel, optionSet, state, cancellationToken); + shouldAnalyze = ShouldAnalyzeForEachStatement(declaration, semanticModel, cancellationToken); + + if (shouldAnalyze) + { + state = State.Generate(declarationStatement, semanticModel, optionSet, isVariableDeclarationContext: false, cancellationToken: cancellationToken); + shouldAnalyze = IsStylePreferred(semanticModel, optionSet, state, cancellationToken); + } } else { @@ -107,7 +112,7 @@ private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context) private Diagnostic CreateDiagnostic(DiagnosticDescriptor descriptor, SyntaxNode declaration, TextSpan diagnosticSpan) => Diagnostic.Create(descriptor, declaration.SyntaxTree.GetLocation(diagnosticSpan)); - private bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) + protected virtual bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) { // implict type is applicable only for local variables and // such declarations cannot have multiple declarators and @@ -121,5 +126,8 @@ private bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variable variableDeclaration.Variables.Count == 1 && variableDeclaration.Variables.Single().Initializer.IsKind(SyntaxKind.EqualsValueClause); } + + protected virtual bool ShouldAnalyzeForEachStatement(ForEachStatementSyntax forEachStatement, SemanticModel semanticModel, CancellationToken cancellationToken) + => true; } } \ No newline at end of file diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpUseExplicitTypeDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpUseExplicitTypeDiagnosticAnalyzer.cs index e700aca0bbeed..913146e24e9af 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpUseExplicitTypeDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpUseExplicitTypeDiagnosticAnalyzer.cs @@ -28,6 +28,30 @@ public CSharpUseExplicitTypeDiagnosticAnalyzer() { } + protected override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) + { + if (!variableDeclaration.Type.IsVar) + { + // If the type is not 'var', this analyze has no work to do + return false; + } + + // The base analyzer may impose further limitations + return base.ShouldAnalyzeVariableDeclaration(variableDeclaration, semanticModel, cancellationToken); + } + + protected override bool ShouldAnalyzeForEachStatement(ForEachStatementSyntax forEachStatement, SemanticModel semanticModel, CancellationToken cancellationToken) + { + if (!forEachStatement.Type.IsVar) + { + // If the type is not 'var', this analyze has no work to do + return false; + } + + // The base analyzer may impose further limitations + return base.ShouldAnalyzeForEachStatement(forEachStatement, semanticModel, cancellationToken); + } + protected override bool IsStylePreferred(SemanticModel semanticModel, OptionSet optionSet, State state, CancellationToken cancellationToken) { var stylePreferences = state.TypeStylePreference; diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpUseImplicitTypeDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpUseImplicitTypeDiagnosticAnalyzer.cs index 9a04883bbea9c..f98c356395f2c 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpUseImplicitTypeDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpUseImplicitTypeDiagnosticAnalyzer.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Diagnostics; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; @@ -29,6 +30,30 @@ public CSharpUseImplicitTypeDiagnosticAnalyzer() { } + protected override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) + { + if (variableDeclaration.Type.IsVar) + { + // If the type is already 'var', this analyze has no work to do + return false; + } + + // The base analyzer may impose further limitations + return base.ShouldAnalyzeVariableDeclaration(variableDeclaration, semanticModel, cancellationToken); + } + + protected override bool ShouldAnalyzeForEachStatement(ForEachStatementSyntax forEachStatement, SemanticModel semanticModel, CancellationToken cancellationToken) + { + if (forEachStatement.Type.IsVar) + { + // If the type is already 'var', this analyze has no work to do + return false; + } + + // The base analyzer may impose further limitations + return base.ShouldAnalyzeForEachStatement(forEachStatement, semanticModel, cancellationToken); + } + protected override bool IsStylePreferred(SemanticModel semanticModel, OptionSet optionSet, State state, CancellationToken cancellationToken) { var stylePreferences = state.TypeStylePreference; @@ -56,12 +81,7 @@ protected override bool IsStylePreferred(SemanticModel semanticModel, OptionSet protected override bool TryAnalyzeVariableDeclaration(TypeSyntax typeName, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken, out TextSpan issueSpan) { - // If it is already var, return. - if (typeName.IsTypeInferred(semanticModel)) - { - issueSpan = default(TextSpan); - return false; - } + Debug.Assert(!typeName.IsVar, "'var' special case should have prevented analysis of this variable."); var candidateReplacementNode = SyntaxFactory.IdentifierName("var"); var candidateIssueSpan = typeName.Span;