Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
014f7a7
Move code out so it can be shared
CyrusNajmabadi Dec 10, 2024
9b96857
Downstream
CyrusNajmabadi Dec 10, 2024
0c6ed22
Downstream
CyrusNajmabadi Dec 10, 2024
3d063e8
Fix
CyrusNajmabadi Dec 10, 2024
16197f3
in progress
CyrusNajmabadi Dec 10, 2024
c23a1ad
in progress
CyrusNajmabadi Dec 10, 2024
afff4ea
in progress
CyrusNajmabadi Dec 10, 2024
a2e1dc6
in progress
CyrusNajmabadi Dec 10, 2024
3b7ba92
Add service type
CyrusNajmabadi Dec 10, 2024
0dfe25f
In progress
CyrusNajmabadi Dec 10, 2024
ccd0232
simplify
CyrusNajmabadi Dec 10, 2024
caa7fa9
simplify
CyrusNajmabadi Dec 10, 2024
442d804
simplify
CyrusNajmabadi Dec 10, 2024
944b95a
move around
CyrusNajmabadi Dec 10, 2024
308f4f9
Compiling
CyrusNajmabadi Dec 10, 2024
8e75cd7
Share code
CyrusNajmabadi Dec 10, 2024
b2a603d
simplify
CyrusNajmabadi Dec 10, 2024
fdd79de
Remove
CyrusNajmabadi Dec 10, 2024
27d3ebf
Add tests
CyrusNajmabadi Dec 10, 2024
56c6b4b
Do it as last setp
CyrusNajmabadi Dec 10, 2024
cf335ac
Find more names
CyrusNajmabadi Dec 10, 2024
11201fc
indent
CyrusNajmabadi Dec 10, 2024
01684b8
cleanup
CyrusNajmabadi Dec 10, 2024
db59036
simplify
CyrusNajmabadi Dec 10, 2024
84a05c0
Naming lookup
CyrusNajmabadi Dec 10, 2024
2ef3ba0
Remove functional changes
CyrusNajmabadi Dec 10, 2024
f2901c8
Remove more
CyrusNajmabadi Dec 10, 2024
501d705
Remove tests
CyrusNajmabadi Dec 10, 2024
aea888e
Merge branch 'main' into genConstructorInitializeFieldNoFunctional
CyrusNajmabadi Dec 10, 2024
ba61429
Update src/Analyzers/Core/CodeFixes/AddParameter/AddParameterService.cs
CyrusNajmabadi Dec 10, 2024
223fe46
Apply suggestions from code review
CyrusNajmabadi Dec 10, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
using System.Threading;
using Microsoft.CodeAnalysis.AddParameter;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.CSharp.GenerateConstructor;
using Microsoft.CodeAnalysis.CSharp.InitializeParameter;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;

Expand All @@ -23,6 +25,7 @@ internal sealed class CSharpAddParameterCodeFixProvider() : AbstractAddParameter
AttributeArgumentSyntax,
ArgumentListSyntax,
AttributeArgumentListSyntax,
ExpressionSyntax,
InvocationExpressionSyntax,
BaseObjectCreationExpressionSyntax>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
using System.Composition;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.InitializeParameter;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor;
using Microsoft.CodeAnalysis.Host.Mef;
Expand All @@ -19,15 +21,11 @@
namespace Microsoft.CodeAnalysis.CSharp.GenerateConstructor;

[ExportLanguageService(typeof(IGenerateConstructorService), LanguageNames.CSharp), Shared]
internal class CSharpGenerateConstructorService
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class CSharpGenerateConstructorService()
: AbstractGenerateConstructorService<CSharpGenerateConstructorService, ExpressionSyntax>
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public CSharpGenerateConstructorService()
{
}

protected override bool ContainingTypesOrSelfHasUnsafeKeyword(INamedTypeSymbol containingType)
=> containingType.ContainingTypesOrSelfHasUnsafeKeyword();

Expand All @@ -45,7 +43,7 @@ protected override bool TryInitializeConstructorInitializerGeneration(
SyntaxNode node,
CancellationToken cancellationToken,
out SyntaxToken token,
out ImmutableArray<Argument> arguments,
out ImmutableArray<Argument<ExpressionSyntax>> arguments,
out INamedTypeSymbol typeToGenerateIn)
{
var constructorInitializer = (ConstructorInitializerSyntax)node;
Expand All @@ -69,11 +67,11 @@ protected override bool TryInitializeConstructorInitializerGeneration(
return false;
}

private static ImmutableArray<Argument> GetArguments(SeparatedSyntaxList<ArgumentSyntax> arguments)
=> arguments.SelectAsArray(a => new Argument(a.GetRefKind(), a.NameColon?.Name.Identifier.ValueText, a.Expression));
private static ImmutableArray<Argument<ExpressionSyntax>> GetArguments(SeparatedSyntaxList<ArgumentSyntax> arguments)
=> arguments.SelectAsArray(InitializeParameterHelpers.GetArgument);

private static ImmutableArray<Argument> GetArguments(SeparatedSyntaxList<AttributeArgumentSyntax> arguments)
=> arguments.SelectAsArray(a => new Argument(
private static ImmutableArray<Argument<ExpressionSyntax>> GetArguments(SeparatedSyntaxList<AttributeArgumentSyntax> arguments)
=> arguments.SelectAsArray(a => new Argument<ExpressionSyntax>(
refKind: RefKind.None,
a.NameEquals?.Name.Identifier.ValueText ?? a.NameColon?.Name.Identifier.ValueText,
a.Expression));
Expand All @@ -83,7 +81,7 @@ protected override bool TryInitializeSimpleNameGenerationState(
SyntaxNode node,
CancellationToken cancellationToken,
out SyntaxToken token,
out ImmutableArray<Argument> arguments,
out ImmutableArray<Argument<ExpressionSyntax>> arguments,
out INamedTypeSymbol typeToGenerateIn)
{
var simpleName = (SimpleNameSyntax)node;
Expand Down Expand Up @@ -115,7 +113,7 @@ protected override bool TryInitializeSimpleAttributeNameGenerationState(
SyntaxNode node,
CancellationToken cancellationToken,
out SyntaxToken token,
out ImmutableArray<Argument> arguments,
out ImmutableArray<Argument<ExpressionSyntax>> arguments,
out INamedTypeSymbol typeToGenerateIn)
{
var simpleName = (SimpleNameSyntax)node;
Expand Down Expand Up @@ -150,7 +148,7 @@ protected override bool TryInitializeImplicitObjectCreation(SemanticDocument doc
SyntaxNode node,
CancellationToken cancellationToken,
out SyntaxToken token,
out ImmutableArray<Argument> arguments,
out ImmutableArray<Argument<ExpressionSyntax>> arguments,
out INamedTypeSymbol typeToGenerateIn)
{
var implicitObjectCreation = (ImplicitObjectCreationExpressionSyntax)node;
Expand All @@ -176,7 +174,7 @@ protected override bool TryInitializeImplicitObjectCreation(SemanticDocument doc
protected override string GenerateNameForExpression(SemanticModel semanticModel, ExpressionSyntax expression, CancellationToken cancellationToken)
=> semanticModel.GenerateNameForExpression(expression, capitalize: false, cancellationToken: cancellationToken);

protected override ITypeSymbol GetArgumentType(SemanticModel semanticModel, Argument argument, CancellationToken cancellationToken)
protected override ITypeSymbol GetArgumentType(SemanticModel semanticModel, Argument<ExpressionSyntax> argument, CancellationToken cancellationToken)
=> InternalExtensions.DetermineParameterType(argument.Expression, semanticModel, cancellationToken);

protected override bool IsConversionImplicit(Compilation compilation, ITypeSymbol sourceType, ITypeSymbol targetType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.AddParameter;
using Microsoft.CodeAnalysis.CSharp.Shared.Extensions;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
Expand All @@ -20,13 +19,9 @@
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.AddParameter;

[Trait(Traits.Feature, Traits.Features.CodeActionsAddParameter)]
public class AddParameterTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor
public sealed class AddParameterTests(ITestOutputHelper logger)
: AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor(logger)
{
public AddParameterTests(ITestOutputHelper logger)
: base(logger)
{
}

internal override (DiagnosticAnalyzer?, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (null, new CSharpAddParameterCodeFixProvider());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Collections;
Expand All @@ -24,13 +24,15 @@ internal abstract class AbstractAddParameterCodeFixProvider<
TAttributeArgumentSyntax,
TArgumentListSyntax,
TAttributeArgumentListSyntax,
TExpressionSyntax,
TInvocationExpressionSyntax,
TObjectCreationExpressionSyntax> : CodeFixProvider
where TArgumentSyntax : SyntaxNode
where TArgumentListSyntax : SyntaxNode
where TAttributeArgumentListSyntax : SyntaxNode
where TInvocationExpressionSyntax : SyntaxNode
where TObjectCreationExpressionSyntax : SyntaxNode
where TExpressionSyntax : SyntaxNode
where TInvocationExpressionSyntax : TExpressionSyntax
where TObjectCreationExpressionSyntax : TExpressionSyntax
{
protected abstract ImmutableArray<string> TooManyArgumentsDiagnosticIds { get; }
protected abstract ImmutableArray<string> CannotConvertDiagnosticIds { get; }
Expand Down Expand Up @@ -188,7 +190,7 @@ private static ImmutableArray<ArgumentInsertPositionData<TArgumentSyntax>> GetAr
ImmutableArray<IMethodSymbol> methodCandidates)
{
var comparer = syntaxFacts.StringComparer;
var methodsAndArgumentToAdd = ArrayBuilder<ArgumentInsertPositionData<TArgumentSyntax>>.GetInstance();
using var _ = ArrayBuilder<ArgumentInsertPositionData<TArgumentSyntax>>.GetInstance(out var methodsAndArgumentToAdd);

foreach (var method in methodCandidates.OrderBy(m => m.Parameters.Length))
{
Expand Down Expand Up @@ -220,7 +222,7 @@ private static ImmutableArray<ArgumentInsertPositionData<TArgumentSyntax>> GetAr
}
}

return methodsAndArgumentToAdd.ToImmutableAndFree();
return methodsAndArgumentToAdd.ToImmutableAndClear();
}

private static int NonParamsParameterCount(IMethodSymbol method)
Expand Down Expand Up @@ -333,15 +335,13 @@ private ImmutableArray<CodeFixData> PrepareCreationOfCodeActions(
var argumentToInsert = argumentInsertPositionData.ArgumentToInsert;

var cascadingFix = AddParameterService.HasCascadingDeclarations(methodToUpdate)
? new Func<CancellationToken, Task<Solution>>(c => FixAsync(document, methodToUpdate, argumentToInsert, arguments, fixAllReferences: true, c))
? new Func<CancellationToken, Task<Solution>>(cancellationToken => FixAsync(document, methodToUpdate, argumentToInsert, arguments, fixAllReferences: true, cancellationToken))
: null;

var codeFixData = new CodeFixData(
builder.Add(new CodeFixData(
methodToUpdate,
c => FixAsync(document, methodToUpdate, argumentToInsert, arguments, fixAllReferences: false, c),
cascadingFix);

builder.Add(codeFixData);
cancellationToken => FixAsync(document, methodToUpdate, argumentToInsert, arguments, fixAllReferences: false, cancellationToken),
cascadingFix));
}

return builder.MoveToImmutable();
Expand Down Expand Up @@ -379,12 +379,12 @@ private async Task<Solution> FixAsync(
invocationDocument, argument, method.ContainingType, cancellationToken).ConfigureAwait(false);

var newParameterIndex = isNamedArgument ? (int?)null : argumentList.IndexOf(argument);
return await AddParameterService.AddParameterAsync(
return await AddParameterService.AddParameterAsync<TExpressionSyntax>(
invocationDocument,
method,
argumentType,
refKind,
argumentNameSuggestion,
new ParameterName(argumentNameSuggestion, isNamedArgument, tryMakeCamelCase: !method.ContainingType.IsRecord),
newParameterIndex,
fixAllReferences,
cancellationToken).ConfigureAwait(false);
Expand Down
31 changes: 18 additions & 13 deletions src/Analyzers/Core/CodeFixes/AddParameter/AddParameterService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor;
using Microsoft.CodeAnalysis.InitializeParameter;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.AddParameter;

Expand Down Expand Up @@ -70,15 +74,16 @@ public static bool HasCascadingDeclarations(IMethodSymbol method)
/// </summary>
/// <param name="newParameterIndex"><see langword="null"/> to add as the final parameter</param>
/// <returns></returns>
public static async Task<Solution> AddParameterAsync(
public static async Task<Solution> AddParameterAsync<TExpressionSyntax>(
Document invocationDocument,
IMethodSymbol method,
ITypeSymbol newParameterType,
RefKind refKind,
string parameterName,
ParameterName parameterName,
int? newParameterIndex,
bool fixAllReferences,
CancellationToken cancellationToken)
where TExpressionSyntax : SyntaxNode
{
var solution = invocationDocument.Project.Solution;

Expand All @@ -91,8 +96,8 @@ public static async Task<Solution> AddParameterAsync(

// Indexing Locations[0] is valid because IMethodSymbols have one location at most
// and IsFromSource() tests if there is at least one location.
var locationsByDocument = locationsInSource.ToLookup(declarationLocation
=> solution.GetRequiredDocument(declarationLocation.Locations[0].SourceTree!));
var locationsByDocument = locationsInSource.ToLookup(
declarationLocation => solution.GetRequiredDocument(declarationLocation.Locations[0].SourceTree!));

foreach (var documentLookup in locationsByDocument)
{
Expand All @@ -106,9 +111,9 @@ public static async Task<Solution> AddParameterAsync(
var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var editor = new SyntaxEditor(syntaxRoot, solution.Services);
var generator = editor.Generator;
foreach (var methodDeclaration in documentLookup)
foreach (var currentMethodToUpdate in documentLookup)
{
var methodNode = syntaxRoot.FindNode(methodDeclaration.Locations[0].SourceSpan, getInnermostNodeForTie: true);
var methodNode = syntaxRoot.FindNode(currentMethodToUpdate.Locations[0].SourceSpan, getInnermostNodeForTie: true);
var existingParameters = generator.GetParameters(methodNode);
var insertionIndex = newParameterIndex ?? existingParameters.Count;

Expand All @@ -118,23 +123,23 @@ public static async Task<Solution> AddParameterAsync(
syntaxFacts.GetDefaultOfParameter(existingParameters[insertionIndex - 1]) != null;

var parameterSymbol = CreateParameterSymbol(
methodDeclaration, newParameterType, refKind, parameterMustBeOptional, parameterName);
currentMethodToUpdate, newParameterType, refKind, parameterMustBeOptional, parameterName.BestNameForParameter);

var argumentInitializer = parameterMustBeOptional ? generator.DefaultExpression(newParameterType) : null;
var parameterDeclaration = generator.ParameterDeclaration(parameterSymbol, argumentInitializer)
.WithAdditionalAnnotations(Formatter.Annotation);
if (anySymbolReferencesNotInSource && methodDeclaration == method)
var parameterDeclaration = generator
.ParameterDeclaration(parameterSymbol, argumentInitializer);

if (anySymbolReferencesNotInSource && currentMethodToUpdate == method)
{
parameterDeclaration = parameterDeclaration.WithAdditionalAnnotations(
ConflictAnnotation.Create(CodeFixesResources.Related_method_signatures_found_in_metadata_will_not_be_updated));
}

if (method.MethodKind == MethodKind.ReducedExtension && insertionIndex < existingParameters.Count)
{
insertionIndex++;
}

AddParameterEditor.AddParameter(syntaxFacts, editor, methodNode, insertionIndex, parameterDeclaration, cancellationToken);
AddParameterEditor.AddParameter(
syntaxFacts, editor, methodNode, insertionIndex, parameterDeclaration, cancellationToken);
}

var newRoot = editor.GetChangedRoot();
Expand Down
1 change: 0 additions & 1 deletion src/Analyzers/Core/CodeFixes/CodeFixes.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Formatting\FormattingCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GenerateConstructor\AbstractGenerateConstructorService.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GenerateConstructor\AbstractGenerateConstructorService.State.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GenerateConstructor\Argument.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GenerateConstructor\GenerateConstructorHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GenerateConstructor\IGenerateConstructorService.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GenerateDefaultConstructors\AbstractGenerateDefaultConstructorCodeFixProvider.cs" />
Expand Down
Loading
Loading