Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature to convert from an explicitly typed lambda to an implicitly typed one. #76770

Merged
merged 148 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from 144 commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
5ef8b62
Support ref lambdas
CyrusNajmabadi Oct 4, 2024
377fd39
parsing and tests
CyrusNajmabadi Oct 4, 2024
71258cb
Update tests
CyrusNajmabadi Oct 4, 2024
fc3889c
Parsing
CyrusNajmabadi Oct 4, 2024
df0fcd3
IN progress
CyrusNajmabadi Oct 4, 2024
9be9229
IN progress
CyrusNajmabadi Oct 4, 2024
7b8a22a
IN progress
CyrusNajmabadi Oct 4, 2024
5ac1ae3
IN progress
CyrusNajmabadi Oct 4, 2024
da298d8
Simplify
CyrusNajmabadi Oct 4, 2024
fcced9f
Update tst
CyrusNajmabadi Oct 4, 2024
1ff139d
Add tests
CyrusNajmabadi Oct 4, 2024
a5ac0b2
Merge branch 'main' into refLambdas
CyrusNajmabadi Oct 4, 2024
1381610
Fix tests
CyrusNajmabadi Oct 5, 2024
30dde1f
Merge remote-tracking branch 'upstream/main' into refLambdas
CyrusNajmabadi Oct 7, 2024
138cc1b
Fix tests
CyrusNajmabadi Oct 7, 2024
4e3d787
remove
CyrusNajmabadi Oct 7, 2024
06a65d4
restore
CyrusNajmabadi Oct 7, 2024
2bf5192
Fix tests
CyrusNajmabadi Oct 7, 2024
ec0f272
reorder
CyrusNajmabadi Oct 7, 2024
480eacb
simplify
CyrusNajmabadi Oct 7, 2024
987928e
simplify
CyrusNajmabadi Oct 7, 2024
08cdb3b
REvert
CyrusNajmabadi Oct 7, 2024
86b9cda
Simplify parsing
CyrusNajmabadi Oct 7, 2024
6c07d0c
remove unused usings
CyrusNajmabadi Oct 7, 2024
fbc0b05
Doc and rename
CyrusNajmabadi Oct 7, 2024
ec51315
Rename
CyrusNajmabadi Oct 7, 2024
b7edb45
Docs
CyrusNajmabadi Oct 7, 2024
66ed2a0
Fix errors
CyrusNajmabadi Oct 7, 2024
223641a
Fix errors
CyrusNajmabadi Oct 7, 2024
7995a7e
Fixup tests
CyrusNajmabadi Oct 7, 2024
c60680d
Simplify
CyrusNajmabadi Oct 7, 2024
922ec4f
Reorder
CyrusNajmabadi Oct 7, 2024
b0e61fb
Test fixes
CyrusNajmabadi Oct 8, 2024
3d5bd38
Fix tests
CyrusNajmabadi Oct 8, 2024
0fa7e52
Fix tests
CyrusNajmabadi Oct 9, 2024
4d888f6
Merge branch 'main' into refLambdas
CyrusNajmabadi Nov 4, 2024
5b7ac1a
Merge branch 'main' into refLambdas
CyrusNajmabadi Nov 26, 2024
b1c0415
Merge remote-tracking branch 'upstream/main' into refLambdas
CyrusNajmabadi Nov 27, 2024
0c62f86
Fix
CyrusNajmabadi Nov 27, 2024
02376ed
Update src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs
CyrusNajmabadi Nov 28, 2024
8d112ba
Update src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs
CyrusNajmabadi Nov 28, 2024
72cc5f2
Merge remote-tracking branch 'upstream/main' into refLambdas
CyrusNajmabadi Nov 28, 2024
b6cd56c
Add test
CyrusNajmabadi Nov 28, 2024
5624428
Fix
CyrusNajmabadi Nov 28, 2024
e93792e
docs
CyrusNajmabadi Nov 28, 2024
955d4fa
docs
CyrusNajmabadi Nov 28, 2024
b5f28b7
revert
CyrusNajmabadi Nov 28, 2024
bb74038
Ad test
CyrusNajmabadi Nov 28, 2024
47ed0e4
Simplify check
CyrusNajmabadi Nov 28, 2024
314d807
Fix comment
CyrusNajmabadi Nov 28, 2024
163a667
Add assert
CyrusNajmabadi Nov 28, 2024
c0c55ce
Use proper check
CyrusNajmabadi Nov 28, 2024
e7b4200
Add test
CyrusNajmabadi Nov 28, 2024
5654594
Add test
CyrusNajmabadi Nov 28, 2024
a6caa89
add teest
CyrusNajmabadi Nov 28, 2024
e0f855f
Merge remote-tracking branch 'upstream/main' into refLambdas
CyrusNajmabadi Dec 2, 2024
a690f4a
Merge remote-tracking branch 'upstream/main' into refLambdas
CyrusNajmabadi Dec 2, 2024
08b804f
Move check inwards
CyrusNajmabadi Dec 2, 2024
55f8a48
Support 'params'
CyrusNajmabadi Dec 2, 2024
7e7cd11
Update test
CyrusNajmabadi Dec 2, 2024
980ff5e
Add tests
CyrusNajmabadi Dec 2, 2024
6975e28
Revert
CyrusNajmabadi Dec 2, 2024
ee34ba8
Add c# 13 tests for params
CyrusNajmabadi Dec 2, 2024
e4e33aa
Fix
CyrusNajmabadi Dec 2, 2024
111ec5f
Simplify
CyrusNajmabadi Dec 2, 2024
06a8fca
Add assert back in
CyrusNajmabadi Dec 2, 2024
d9766a7
Update src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
CyrusNajmabadi Dec 2, 2024
47ab140
Fix comment
CyrusNajmabadi Dec 2, 2024
dee332d
Merge branch 'refLambdas' of https://github.com/CyrusNajmabadi/roslyn…
CyrusNajmabadi Dec 2, 2024
d2cdfc3
Update src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
CyrusNajmabadi Dec 2, 2024
e4464e0
Merge remote-tracking branch 'upstream/main' into refLambdas
CyrusNajmabadi Dec 3, 2024
b058429
Upda tecomment
CyrusNajmabadi Dec 3, 2024
f150417
Rename and add comments
CyrusNajmabadi Dec 3, 2024
729c639
Merge remote-tracking branch 'upstream/main' into refLambdas
CyrusNajmabadi Dec 3, 2024
ccf7bbc
Simplify
CyrusNajmabadi Dec 3, 2024
f65ff60
Update src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs
CyrusNajmabadi Dec 3, 2024
bd64fc2
Make theory
CyrusNajmabadi Dec 3, 2024
f4dc8f5
Merge branch 'main' into refLambdas
CyrusNajmabadi Dec 20, 2024
72b419d
Add testS
CyrusNajmabadi Dec 20, 2024
ea65299
Make 'scoped' always a lambda modifier in C# 14 and above
CyrusNajmabadi Dec 20, 2024
acb0f81
Add tests
CyrusNajmabadi Dec 20, 2024
c65d771
Add tests
CyrusNajmabadi Dec 20, 2024
da06993
Add tests
CyrusNajmabadi Dec 20, 2024
d45d1af
Add tests
CyrusNajmabadi Dec 20, 2024
79db98b
Add tests
CyrusNajmabadi Dec 20, 2024
6c7b931
Add tests
CyrusNajmabadi Dec 20, 2024
11a9e71
Add tests
CyrusNajmabadi Dec 20, 2024
63f688a
Add tests
CyrusNajmabadi Dec 20, 2024
fde87ac
Add tests
CyrusNajmabadi Dec 20, 2024
99482d3
Add tests
CyrusNajmabadi Dec 20, 2024
1596d26
Add tests
CyrusNajmabadi Dec 20, 2024
ef569dc
Add tests
CyrusNajmabadi Dec 20, 2024
005511f
Add tests
CyrusNajmabadi Dec 20, 2024
622efc9
Add tests
CyrusNajmabadi Dec 20, 2024
e6ba439
Add tests
CyrusNajmabadi Dec 20, 2024
09c0d2f
Add tests
CyrusNajmabadi Dec 20, 2024
48a8d96
Add tests
CyrusNajmabadi Dec 20, 2024
5a517e8
Add tests
CyrusNajmabadi Dec 20, 2024
1f0d95a
Add tests
CyrusNajmabadi Dec 20, 2024
62fed3a
Add tests
CyrusNajmabadi Dec 20, 2024
819ac94
Add tests
CyrusNajmabadi Dec 20, 2024
d1f8026
Merge branch 'main' into refLambdas
CyrusNajmabadi Jan 13, 2025
1e5d00e
Merge remote-tracking branch 'upstream/main' into refLambdas
CyrusNajmabadi Jan 13, 2025
87d005d
Explicit preview check
CyrusNajmabadi Jan 13, 2025
f43f02b
REmove usings
CyrusNajmabadi Jan 13, 2025
38b7c98
NRT
CyrusNajmabadi Jan 13, 2025
7851db3
Break into separate tests
CyrusNajmabadi Jan 13, 2025
2093c05
Add output tests
CyrusNajmabadi Jan 13, 2025
1aa702c
Update src/Compilers/CSharp/Test/Semantic/Semantics/SimpleLambdaParam…
CyrusNajmabadi Jan 13, 2025
cf775df
Add ioptree
CyrusNajmabadi Jan 13, 2025
7c9ed31
Merge branch 'refLambdas' of https://github.com/CyrusNajmabadi/roslyn…
CyrusNajmabadi Jan 13, 2025
2b89528
lint
CyrusNajmabadi Jan 13, 2025
0b34018
Merge remote-tracking branch 'upstream/main' into refLambdas
CyrusNajmabadi Jan 15, 2025
34fc6e6
Disallow implicit lambdas with 'params'
CyrusNajmabadi Jan 15, 2025
a6f45d5
Add tests
CyrusNajmabadi Jan 15, 2025
44ed91b
Update breaking change doc
CyrusNajmabadi Jan 15, 2025
41bd895
Apply suggestions from code review
CyrusNajmabadi Jan 15, 2025
2906eb6
Update docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md
CyrusNajmabadi Jan 15, 2025
84bfaa8
Apply suggestions from code review
CyrusNajmabadi Jan 15, 2025
b7aebc9
Merge remote-tracking branch 'upstream/main' into refLambdas
CyrusNajmabadi Jan 15, 2025
50fde01
In progress
CyrusNajmabadi Jan 15, 2025
34de5f2
Fix doc comment
CyrusNajmabadi Jan 15, 2025
d3a4b0b
Add more scoped tests
CyrusNajmabadi Jan 15, 2025
e6d9d31
Add asserts
CyrusNajmabadi Jan 15, 2025
e51345c
Remove unnecessary test
CyrusNajmabadi Jan 15, 2025
eef4e94
Update src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems
CyrusNajmabadi Jan 15, 2025
952fc5a
Add test
CyrusNajmabadi Jan 15, 2025
e6ba415
Merge branch 'refLambdas' into implicitlyTypedLambda
CyrusNajmabadi Jan 15, 2025
c1242c4
In progress
CyrusNajmabadi Jan 16, 2025
4f7ca49
Add teests
CyrusNajmabadi Jan 16, 2025
0f18fc1
Add tests
CyrusNajmabadi Jan 16, 2025
96f4187
Flesh out
CyrusNajmabadi Jan 16, 2025
fd5ea88
Flesh out
CyrusNajmabadi Jan 16, 2025
3fd2e56
Add fixes
CyrusNajmabadi Jan 16, 2025
bbd499c
Use helper
CyrusNajmabadi Jan 16, 2025
6b653fb
Handle params
CyrusNajmabadi Jan 16, 2025
a0e07c0
Handle params
CyrusNajmabadi Jan 16, 2025
30e4fdc
Fix trivia
CyrusNajmabadi Jan 16, 2025
6d3ed92
Merge remote-tracking branch 'upstream/main' into implicitlyTypedLambda
CyrusNajmabadi Jan 16, 2025
3ab5828
Add test
CyrusNajmabadi Jan 16, 2025
537704c
Update tests
CyrusNajmabadi Jan 16, 2025
c64c573
fixup options
CyrusNajmabadi Jan 16, 2025
2536433
Fixup tests
CyrusNajmabadi Jan 16, 2025
d552ea5
Update options
CyrusNajmabadi Jan 16, 2025
77586b0
Update src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems
CyrusNajmabadi Jan 16, 2025
150cda8
invert
CyrusNajmabadi Jan 16, 2025
43b3ec3
Merge branch 'implicitlyTypedLambda' of https://github.com/CyrusNajma…
CyrusNajmabadi Jan 16, 2025
e5d47df
Add docs
CyrusNajmabadi Jan 16, 2025
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
1 change: 1 addition & 0 deletions src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnusedMembers\CSharpRemoveUnusedMembersDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnusedParametersAndValues\CSharpRemoveUnusedParametersAndValuesDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseCollectionInitializer\CSharpUseCollectionInitializerDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseImplicitlyTypedLambdaExpression\CSharpUseImplicitlyTypedLambdaExpressionDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseImplicitObjectCreation\CSharpUseImplicitObjectCreationDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseImplicitOrExplicitType\CSharpTypeStyleDiagnosticAnalyzerBase.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UseImplicitOrExplicitType\CSharpUseExplicitTypeDiagnosticAnalyzer.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@
<data name="new_expression_can_be_simplified" xml:space="preserve">
<value>'new' expression can be simplified</value>
</data>
<data name="Lambda_expression_can_be_simplified" xml:space="preserve">
<value>Lambda expression can be simplified</value>
</data>
<data name="Use_implicitly_typed_lambda" xml:space="preserve">
<value>Use implicitly typed lambda</value>
</data>
<data name="Discard_can_be_removed" xml:space="preserve">
<value>Discard can be removed</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ internal CSharpSimplifierOptions GetSimplifierOptions()
public CodeStyleOption2<bool> PreferPatternMatchingOverIsWithCastCheck => GetOption(CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck);
public CodeStyleOption2<bool> PreferNotPattern => GetOption(CSharpCodeStyleOptions.PreferNotPattern);
public CodeStyleOption2<bool> PreferExtendedPropertyPattern => GetOption(CSharpCodeStyleOptions.PreferExtendedPropertyPattern);
public CodeStyleOption2<bool> PreferImplicitlyTypedLambdaExpression => GetOption(CSharpCodeStyleOptions.PreferImplicitlyTypedLambdaExpression);
public CodeStyleOption2<bool> PreferInlinedVariableDeclaration => GetOption(CSharpCodeStyleOptions.PreferInlinedVariableDeclaration);
public CodeStyleOption2<bool> PreferDeconstructedVariableDeclaration => GetOption(CSharpCodeStyleOptions.PreferDeconstructedVariableDeclaration);
public CodeStyleOption2<bool> PreferIndexOperator => GetOption(CSharpCodeStyleOptions.PreferIndexOperator);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Shared.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.UseImplicitlyTypedLambdaExpression;

using static SyntaxFactory;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class CSharpUseImplicitlyTypedLambdaExpressionDiagnosticAnalyzer()
: AbstractBuiltInCodeStyleDiagnosticAnalyzer(IDEDiagnosticIds.UseImplicitlyTypedLambdaExpressionDiagnosticId,
EnforceOnBuildValues.UseImplicitObjectCreation,
CSharpCodeStyleOptions.PreferImplicitlyTypedLambdaExpression,
new LocalizableResourceString(nameof(CSharpAnalyzersResources.Use_implicitly_typed_lambda), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources)),
new LocalizableResourceString(nameof(CSharpAnalyzersResources.Lambda_expression_can_be_simplified), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources)))
{
public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
=> DiagnosticAnalyzerCategory.SemanticSpanAnalysis;

protected override void InitializeWorker(AnalysisContext context)
=> context.RegisterSyntaxNodeAction(AnalyzeIfEnabled,
SyntaxKind.ParenthesizedLambdaExpression);

private void AnalyzeIfEnabled(SyntaxNodeAnalysisContext context)
{
var cancellationToken = context.CancellationToken;
var analyzerOptions = context.Options;
var semanticModel = context.SemanticModel;
var option = analyzerOptions.GetCSharpAnalyzerOptions(semanticModel.SyntaxTree).PreferImplicitlyTypedLambdaExpression;
if (!option.Value || ShouldSkipAnalysis(context, option.Notification))
return;

var explicitLambda = (ParenthesizedLambdaExpressionSyntax)context.Node;
if (!Analyze(semanticModel, explicitLambda, cancellationToken))
return;

context.ReportDiagnostic(DiagnosticHelper.Create(
Descriptor,
explicitLambda.ParameterList.OpenParenToken.GetLocation(),
option.Notification,
context.Options,
[explicitLambda.GetLocation()],
properties: null));
}

public static bool Analyze(
SemanticModel semanticModel,
ParenthesizedLambdaExpressionSyntax explicitLambda,
CancellationToken cancellationToken)
{
// If the lambda has an explicit return type, then do not offer the feature. Explicit return types are used to
// provide full semantic information to the compiler so it does not need to perform speculative lambda binding.
// Removing may cause code compilation performance to regress.
if (explicitLambda.ReturnType != null)
return false;

// Needs to have at least one parameter, all parameters need to have a provided type, and no parameters can have a
// default value provided.
if (explicitLambda.ParameterList.Parameters.Count == 0 ||
explicitLambda.ParameterList.Parameters.Any(p => p.Type is null || p.Default != null))
{
return false;
}

// Prior to C# 14, implicitly typed lambdas can't have modifiers on parameters.
var languageVersion = semanticModel.Compilation.LanguageVersion();
if (!languageVersion.IsCSharp14OrAbove() && explicitLambda.ParameterList.Parameters.Any(p => p.Modifiers.Count > 0))
return false;

var implicitLambda = ConvertToImplicitlyTypedLambda(explicitLambda);

var analyzer = new SpeculationAnalyzer(
explicitLambda, implicitLambda, semanticModel, cancellationToken);
if (analyzer.ReplacementChangesSemantics())
return false;

if (semanticModel.GetSymbolInfo(explicitLambda, cancellationToken).Symbol is not IMethodSymbol explicitLambdaMethod ||
analyzer.SpeculativeSemanticModel.GetSymbolInfo(analyzer.ReplacedExpression, cancellationToken).Symbol is not IMethodSymbol implicitLambdaMethod)
{
return false;
}

if (!SignatureComparer.Instance.HaveSameSignature(explicitLambdaMethod, implicitLambdaMethod, caseSensitive: true))
return false;

return true;
}

public static LambdaExpressionSyntax ConvertToImplicitlyTypedLambda(ParenthesizedLambdaExpressionSyntax explicitLambda)
{
var implicitLambda = explicitLambda.ReplaceNodes(
explicitLambda.ParameterList.Parameters,
(parameter, _) => RemoveParamsModifier(
parameter.WithType(null)
.WithIdentifier(parameter.Identifier.WithPrependedLeadingTrivia(parameter.Type!.GetLeadingTrivia()))));

// If the lambda only has one parameter, then convert it to the non-parenthesized form.
if (implicitLambda.ParameterList.Parameters is [{ AttributeLists.Count: 0, Modifiers.Count: 0 } parameter])
{
return SimpleLambdaExpression(
explicitLambda.AttributeLists,
explicitLambda.Modifiers,
parameter.WithTriviaFrom(explicitLambda.ParameterList),
explicitLambda.Block,
explicitLambda.ExpressionBody);
}

return implicitLambda;
}

private static ParameterSyntax RemoveParamsModifier(ParameterSyntax parameter)
{
// Implicitly typed lambdas aren't ever allowed to have the 'params' modifier.
var paramsModifierIndex = parameter.Modifiers.IndexOf(SyntaxKind.ParamsKeyword);
return paramsModifierIndex >= 0 ? parameter.WithModifiers(parameter.Modifiers.RemoveAt(paramsModifierIndex)) : parameter;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading