Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add analyzer "Add/remove blank line between switch sections" ([RCS0061](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS0061)) ([PR](https://github.com/dotnet/roslynator/pull/1302))
- Option (required): `roslynator_blank_line_between_switch_sections = include|omit|omit_after_block`
- Make analyzer [RCS0014](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS0014) obsolete
- Add analyzer "Declare explicit/implicit type" ([RCS1264](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1264)) ([PR](https://github.com/dotnet/roslynator/pull/1335))
- Required option: `roslynator_use_var = always | never | when_type_is_obvious`
- This analyzer consolidates following analyzers (which are made obsolete):
- [RCS1008](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1008)
- [RCS1009](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1009)
- [RCS1010](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1010)
- [RCS1012](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1012)
- [RCS1176](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1176)
- [RCS1177](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1177)
- Add code fix "Declare as nullable" ([PR](https://github.com/dotnet/roslynator/pull/1333))
- Applicable to: `CS8600`, `CS8610`, `CS8765` and `CS8767`
- Add option `roslynator_use_collection_expression = true|false` ([PR](https://github.com/dotnet/roslynator/pull/1325))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
Expand All @@ -14,6 +15,7 @@

namespace Roslynator.CSharp.CodeFixes;

[Obsolete("Use code fix provider 'UseVarOrExplicitTypeCodeFixProvider' instead.")]
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseExplicitTypeInsteadOfVarCodeFixProvider))]
[Shared]
public sealed class UseExplicitTypeInsteadOfVarCodeFixProvider : BaseCodeFixProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace Roslynator.CSharp.CodeFixes;

[Obsolete("Use code fix provider 'UseVarOrExplicitTypeCodeFixProvider' instead.")]
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseExplicitTypeInsteadOfVarInForEachCodeFixProvider))]
[Shared]
public sealed class UseExplicitTypeInsteadOfVarInForEachCodeFixProvider : BaseCodeFixProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace Roslynator.CSharp.CodeFixes;

[Obsolete("Use code fix provider 'UseVarOrExplicitTypeCodeFixProvider' instead.")]
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseVarInsteadOfExplicitTypeCodeFixProvider))]
[Shared]
public sealed class UseVarInsteadOfExplicitTypeCodeFixProvider : BaseCodeFixProvider
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslynator.CodeFixes;
using Roslynator.CSharp;
using static Roslynator.CSharp.CodeActionFactory;

namespace Roslynator.CSharp.CodeFixes;

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseVarOrExplicitTypeCodeFixProvider))]
[Shared]
public sealed class UseVarOrExplicitTypeCodeFixProvider : BaseCodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds
{
get { return ImmutableArray.Create(DiagnosticIdentifiers.UseVarOrExplicitType); }
}

public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

if (!TryFindFirstAncestorOrSelf(
root,
context.Span,
out SyntaxNode node,
predicate: f => f is TypeSyntax
|| f.IsKind(
SyntaxKind.VariableDeclaration,
SyntaxKind.DeclarationExpression,
SyntaxKind.ForEachStatement,
SyntaxKind.ForEachVariableStatement,
SyntaxKind.TupleExpression)))
{
return;
}

Document document = context.Document;
Diagnostic diagnostic = context.Diagnostics[0];

SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

if (node is TypeSyntax type)
{
if (type.IsVar)
{
if (node.IsParentKind(SyntaxKind.VariableDeclaration, SyntaxKind.ForEachStatement))
{
node = node.Parent;
}
else if (node.IsParentKind(SyntaxKind.DeclarationExpression))
{
node = node.Parent;

if (node.IsParentKind(SyntaxKind.ForEachVariableStatement))
node = node.Parent;
}
}
else
{
CodeAction codeAction = ChangeTypeToVar(document, type, equivalenceKey: GetEquivalenceKey(diagnostic, "ToImplicit"));
context.RegisterCodeFix(codeAction, diagnostic);
return;
}
}

switch (node)
{
case TupleExpressionSyntax tupleExpression:
{
CodeAction codeAction = ChangeTypeToVar(document, tupleExpression, equivalenceKey: GetEquivalenceKey(diagnostic, "ToImplicit"));
context.RegisterCodeFix(codeAction, diagnostic);
break;
}
case VariableDeclarationSyntax variableDeclaration:
{
ExpressionSyntax value = variableDeclaration.Variables[0].Initializer.Value;
ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(value, context.CancellationToken);

if (typeSymbol is null)
{
var localSymbol = semanticModel.GetDeclaredSymbol(variableDeclaration.Variables[0], context.CancellationToken) as ILocalSymbol;

if (localSymbol is not null)
{
typeSymbol = localSymbol.Type;
value = value.WalkDownParentheses();

Debug.Assert(
value.IsKind(SyntaxKind.SimpleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression),
value.Kind().ToString());

if (value.IsKind(SyntaxKind.SimpleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression))
typeSymbol = typeSymbol.WithNullableAnnotation(NullableAnnotation.NotAnnotated);
}
else
{
SyntaxDebug.Fail(variableDeclaration.Variables[0]);
return;
}
}

CodeAction codeAction = UseExplicitType(document, variableDeclaration.Type, typeSymbol, semanticModel, equivalenceKey: GetEquivalenceKey(diagnostic, "ToExplicit"));
context.RegisterCodeFix(codeAction, diagnostic);
break;
}
case DeclarationExpressionSyntax declarationExpression:
{
ITypeSymbol typeSymbol = null;
if (declarationExpression.Parent is AssignmentExpressionSyntax assignment)
{
typeSymbol = semanticModel.GetTypeSymbol(assignment.Right, context.CancellationToken);
}
else if (declarationExpression.Parent is ArgumentSyntax argument)
{
IParameterSymbol parameterSymbol = DetermineParameterHelper.DetermineParameter(argument, semanticModel, cancellationToken: context.CancellationToken);
typeSymbol = parameterSymbol?.Type;
}

if (typeSymbol is null)
{
var localSymbol = semanticModel.GetDeclaredSymbol(declarationExpression.Designation, context.CancellationToken) as ILocalSymbol;
typeSymbol = (localSymbol?.Type) ?? semanticModel.GetTypeSymbol(declarationExpression, context.CancellationToken);
}

CodeAction codeAction = UseExplicitType(document, declarationExpression.Type, typeSymbol, semanticModel, equivalenceKey: GetEquivalenceKey(diagnostic, "ToExplicit"));
context.RegisterCodeFix(codeAction, diagnostic);
break;
}
case ForEachStatementSyntax forEachStatement:
{
ITypeSymbol typeSymbol = semanticModel.GetForEachStatementInfo((CommonForEachStatementSyntax)node).ElementType;

CodeAction codeAction = UseExplicitType(document, forEachStatement.Type, typeSymbol, semanticModel, equivalenceKey: GetEquivalenceKey(diagnostic, "ToExplicit"));
context.RegisterCodeFix(codeAction, diagnostic);
break;
}
case ForEachVariableStatementSyntax forEachVariableStatement:
{
var declarationExpression = (DeclarationExpressionSyntax)forEachVariableStatement.Variable;
ITypeSymbol typeSymbol = semanticModel.GetForEachStatementInfo((CommonForEachStatementSyntax)node).ElementType;

CodeAction codeAction = UseExplicitType(document, declarationExpression.Type, typeSymbol, semanticModel, equivalenceKey: GetEquivalenceKey(diagnostic, "ToExplicit"));
context.RegisterCodeFix(codeAction, diagnostic);
break;
}
}
}
}
23 changes: 23 additions & 0 deletions src/Analyzers.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,8 @@ else if (condition2)
<Analyzer>
<Id>RCS1008</Id>
<Identifier>UseExplicitTypeInsteadOfVarWhenTypeIsNotObvious</Identifier>
<Status>Obsolete</Status>
<ObsoleteMessage>Use RCS1264 instead</ObsoleteMessage>
<Title>Use explicit type instead of 'var' (when the type is not obvious)</Title>
<MessageFormat>Use explicit type instead of 'var'</MessageFormat>
<DefaultSeverity>Hidden</DefaultSeverity>
Expand All @@ -1814,6 +1816,8 @@ else if (condition2)
<Id>RCS1009</Id>
<Identifier>UseExplicitTypeInsteadOfVarInForEach</Identifier>
<Title>Use explicit type instead of 'var' (foreach variable)</Title>
<Status>Obsolete</Status>
<ObsoleteMessage>Use RCS1264 instead</ObsoleteMessage>
<MessageFormat>Use explicit type instead of 'var'</MessageFormat>
<DefaultSeverity>Hidden</DefaultSeverity>
<IsEnabledByDefault>false</IsEnabledByDefault>
Expand All @@ -1835,6 +1839,8 @@ foreach (var item in items)
<Analyzer>
<Id>RCS1010</Id>
<Identifier>UseVarInsteadOfExplicitTypeWhenTypeIsObvious</Identifier>
<Status>Obsolete</Status>
<ObsoleteMessage>Use RCS1264 instead</ObsoleteMessage>
<Title>Use 'var' instead of explicit type (when the type is obvious)</Title>
<MessageFormat>Use 'var' instead of explicit type</MessageFormat>
<DefaultSeverity>Hidden</DefaultSeverity>
Expand All @@ -1850,6 +1856,8 @@ foreach (var item in items)
<Analyzer>
<Id>RCS1012</Id>
<Identifier>UseExplicitTypeInsteadOfVarWhenTypeIsObvious</Identifier>
<Status>Obsolete</Status>
<ObsoleteMessage>Use RCS1264 instead</ObsoleteMessage>
<Title>Use explicit type instead of 'var' (when the type is obvious)</Title>
<MessageFormat>Use explicit type instead of 'var'</MessageFormat>
<DefaultSeverity>Hidden</DefaultSeverity>
Expand Down Expand Up @@ -5411,6 +5419,8 @@ else
<Analyzer>
<Id>RCS1176</Id>
<Identifier>UseVarInsteadOfExplicitTypeWhenTypeIsNotObvious</Identifier>
<Status>Obsolete</Status>
<ObsoleteMessage>Use RCS1264 instead</ObsoleteMessage>
<Title>Use 'var' instead of explicit type (when the type is not obvious)</Title>
<MessageFormat>Use 'var' instead of explicit type</MessageFormat>
<DefaultSeverity>Hidden</DefaultSeverity>
Expand All @@ -5425,6 +5435,8 @@ else
<Analyzer>
<Id>RCS1177</Id>
<Identifier>UseVarInsteadOfExplicitTypeInForEach</Identifier>
<Status>Obsolete</Status>
<ObsoleteMessage>Use RCS1264 instead</ObsoleteMessage>
<Title>Use 'var' instead of explicit type (in foreach)</Title>
<MessageFormat>Use 'var' instead of explicit type</MessageFormat>
<DefaultSeverity>Hidden</DefaultSeverity>
Expand Down Expand Up @@ -7633,6 +7645,17 @@ public string Foo(string bar)
</Sample>
</Samples>
</Analyzer>
<Analyzer>
<Id>RCS1264</Id>
<Identifier>UseVarOrExplicitType</Identifier>
<Title>Use 'var' or explicit type</Title>
<MessageFormat>{0}</MessageFormat>
<DefaultSeverity>Info</DefaultSeverity>
<IsEnabledByDefault>false</IsEnabledByDefault>
<ConfigOptions>
<Option Key="use_var" IsRequired="true" />
</ConfigOptions>
</Analyzer>
<Analyzer>
<Id>RCS9001</Id>
<Identifier>UsePatternMatching</Identifier>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -8,6 +9,7 @@

namespace Roslynator.CSharp.Analysis;

[Obsolete("Use analyzer 'UseVarOrExplicitTypeAnalyzer' instead.")]
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class UseExplicitTypeInsteadOfVarInForEachAnalyzer : BaseDiagnosticAnalyzer
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -8,6 +9,7 @@

namespace Roslynator.CSharp.Analysis;

[Obsolete("Use analyzer 'UseVarOrExplicitTypeAnalyzer' instead.")]
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class UseExplicitTypeInsteadOfVarWhenTypeIsNotObviousAnalyzer : BaseDiagnosticAnalyzer
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -8,6 +9,7 @@

namespace Roslynator.CSharp.Analysis;

[Obsolete("Use analyzer 'UseVarOrExplicitTypeAnalyzer' instead.")]
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class UseExplicitTypeInsteadOfVarWhenTypeIsObviousAnalyzer : BaseDiagnosticAnalyzer
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -8,6 +9,7 @@

namespace Roslynator.CSharp.Analysis;

[Obsolete("Use analyzer 'UseVarOrExplicitTypeAnalyzer' instead.")]
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class UseVarInsteadOfExplicitTypeInForEachAnalyzer : BaseDiagnosticAnalyzer
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -8,6 +9,7 @@

namespace Roslynator.CSharp.Analysis;

[Obsolete("Use analyzer 'UseVarOrExplicitTypeAnalyzer' instead.")]
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class UseVarInsteadOfExplicitTypeWhenTypeIsNotObviousAnalyzer : BaseDiagnosticAnalyzer
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -8,6 +9,7 @@

namespace Roslynator.CSharp.Analysis;

[Obsolete("Use analyzer 'UseVarOrExplicitTypeAnalyzer' instead.")]
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class UseVarInsteadOfExplicitTypeWhenTypeIsObviousAnalyzer : BaseDiagnosticAnalyzer
{
Expand Down
Loading