Skip to content

Commit

Permalink
Use explicit type from lambda expression (RCS1008) (dotnet#967)
Browse files Browse the repository at this point in the history
  • Loading branch information
josefpihrt authored and JochemHarmes committed Oct 30, 2023
1 parent 96514c9 commit 16ee8f8
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 7 deletions.
3 changes: 2 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix formatting of argument list ([#952](https://github.com/josefpihrt/roslynator/pull/952).
- Do not remove async/await when 'using declaration' is used ([#953](https://github.com/josefpihrt/roslynator/pull/953).
- Convert if-else to return statement when pattern matching is used ([RCS1073](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1073.md)) ([#956](https://github.com/josefpihrt/roslynator/pull/956).
- Do not simplify 'default' expression if the type is inferred ([RCS1244](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/1244.md)) ([#956](https://github.com/josefpihrt/roslynator/pull/966).
- Do not simplify 'default' expression if the type is inferred ([RCS1244](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1244.md)) ([#966](https://github.com/josefpihrt/roslynator/pull/966).
- Use explicit type from lambda expression ([RCS1008](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1008.md)) ([#967](https://github.com/josefpihrt/roslynator/pull/967).

-----
<!-- Content below does not adhere to 'Keep a Changelog' format -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
Expand Down Expand Up @@ -34,24 +35,45 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(SyntaxKind.VariableDeclaration, SyntaxKind.DeclarationExpression)))
return;

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

if (node is VariableDeclarationSyntax variableDeclaration)
{
TypeSyntax type = variableDeclaration.Type;
ExpressionSyntax value = variableDeclaration.Variables[0].Initializer.Value;
ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(value, context.CancellationToken);

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

ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(variableDeclaration.Variables[0].Initializer.Value, context.CancellationToken);
if (localSymbol is not null)
{
typeSymbol = localSymbol.Type;

RegisterCodeFix(context, type, typeSymbol, semanticModel);
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;
}
}

RegisterCodeFix(context, variableDeclaration.Type, typeSymbol, semanticModel);
}
else
{
var declarationExpression = (DeclarationExpressionSyntax)node;

TypeSyntax type = declarationExpression.Type;

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

var localSymbol = semanticModel.GetDeclaredSymbol(declarationExpression.Designation, context.CancellationToken) as ILocalSymbol;

ITypeSymbol typeSymbol = (localSymbol?.Type) ?? semanticModel.GetTypeSymbol(declarationExpression, context.CancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,66 @@ void M()
");
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitTypeInsteadOfVarWhenTypeIsNotObvious)]
public async Task Test_Func_Lambda()
{
await VerifyDiagnosticAndFixAsync(@"
class C
{
void M()
{
[|var|] x = () =>
{
return default(object);
};
}
}
", @"
class C
{
void M()
{
System.Func<object> x = () =>
{
return default(object);
};
}
}
", options: Options.AddAllowedCompilerDiagnosticId("CS8603"));
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitTypeInsteadOfVarWhenTypeIsNotObvious)]
public async Task Test_Func_Lambda_Nullable()
{
await VerifyDiagnosticAndFixAsync(@"
#nullable enable
class C
{
void M()
{
[|var|] x = () =>
{
return default(object);
};
}
}
", @"
#nullable enable
class C
{
void M()
{
System.Func<object> x = () =>
{
return default(object);
};
}
}
", options: Options.AddAllowedCompilerDiagnosticId("CS8603"));
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseExplicitTypeInsteadOfVarWhenTypeIsNotObvious)]
public async Task TestNoDiagnostic()
{
Expand Down

0 comments on commit 16ee8f8

Please sign in to comment.