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
Original file line number Diff line number Diff line change
Expand Up @@ -2606,6 +2606,32 @@ void M(object o)
}
""", "customers");

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79417")]
public Task TestNestedParameter1()
=> VerifyItemExistsAsync("""
class C
{
void M(MyWidget myWidget)
{
void LocalFunction(MyWidget $$) { }
}
}
""", "myWidget");

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79417")]
public Task TestNestedParameter2()
=> VerifyItemExistsAsync("""
class MyWidget { }
class C(MyWidget myWidget)
{
class D(MyWidget $$) { }
}
""", "myWidget");

#if false

#endif

private static NamingStylePreferences MultipleCamelCaseLocalRules()
{
var styles = new[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@

namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers;

[ExportCompletionProvider(nameof(DeclarationNameCompletionProvider), LanguageNames.CSharp)]
[ExportCompletionProvider(nameof(DeclarationNameCompletionProvider), LanguageNames.CSharp), Shared]
[ExtensionOrder(After = nameof(TupleNameCompletionProvider))]
[Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed partial class DeclarationNameCompletionProvider([ImportMany] IEnumerable<Lazy<IDeclarationNameRecommender, OrderableMetadata>> recommenders) : LSPCompletionProvider
internal sealed partial class DeclarationNameCompletionProvider(
[ImportMany] IEnumerable<Lazy<IDeclarationNameRecommender, OrderableMetadata>> recommenders) : LSPCompletionProvider
{
private ImmutableArray<Lazy<IDeclarationNameRecommender, OrderableMetadata>> Recommenders { get; } = [.. ExtensionOrderer.Order(recommenders)];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,10 @@
namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers.DeclarationName;

[ExportDeclarationNameRecommender(nameof(DeclarationNameRecommender)), Shared]
internal sealed partial class DeclarationNameRecommender : IDeclarationNameRecommender
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed partial class DeclarationNameRecommender() : IDeclarationNameRecommender
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public DeclarationNameRecommender()
{ }

public async Task<ImmutableArray<(string name, Glyph glyph)>> ProvideRecommendedNamesAsync(
CompletionContext completionContext,
Document document,
Expand Down Expand Up @@ -255,9 +252,9 @@ static void ProcessRules(
context.TargetToken.GetRequiredParent(),
container: null,
baseName: name,
filter: s => IsRelevantSymbolKind(s),
filter: IsRelevantSymbolKind,
usedNames: [],
cancellationToken: cancellationToken);
cancellationToken);

if (seenUniqueNames.Add(uniqueName.Text))
{
Expand Down Expand Up @@ -331,9 +328,5 @@ static ImmutableArray<IMethodSymbol> GetOverloads(INamedTypeSymbol namedType, Ba
/// Only relevant if symbol could cause a conflict with a local variable.
/// </summary>
private static bool IsRelevantSymbolKind(ISymbol symbol)
{
return symbol.Kind is SymbolKind.Local or
SymbolKind.Parameter or
SymbolKind.RangeVariable;
}
=> symbol.Kind is SymbolKind.Local or SymbolKind.Parameter or SymbolKind.RangeVariable;
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,25 @@ private CSharpSemanticFactsService()
protected override SyntaxToken ToIdentifierToken(string identifier)
=> identifier.ToIdentifierToken();

protected override IEnumerable<ISymbol> GetCollidableSymbols(SemanticModel semanticModel, SyntaxNode location, SyntaxNode container, CancellationToken cancellationToken)
protected override IEnumerable<ISymbol> GetCollidableSymbols(SemanticModel semanticModel, SyntaxNode location, SyntaxNode? container, CancellationToken cancellationToken)
{
// Get all the symbols visible to the current location.
var visibleSymbols = semanticModel.LookupSymbols(location.SpanStart);

// Local function parameter is allowed to shadow variables since C# 8.
if (semanticModel.Compilation.LanguageVersion().MapSpecifiedToEffectiveVersion() >= LanguageVersion.CSharp8)
// Similarly, a nested primary constructor parameter list can shadow outer parameters in outer types.
var languageVersion = semanticModel.Compilation.LanguageVersion().MapSpecifiedToEffectiveVersion();
var isLanguageVersionGreaterOrEqualToCSharp8 = languageVersion >= LanguageVersion.CSharp8;
if (isLanguageVersionGreaterOrEqualToCSharp8 &&
SyntaxFacts.IsParameterList(container))
{
if (SyntaxFacts.IsParameterList(container) && SyntaxFacts.IsLocalFunctionStatement(container.Parent))
{
if (container.Parent is LocalFunctionStatementSyntax or TypeDeclarationSyntax)
visibleSymbols = visibleSymbols.WhereAsArray(s => !s.MatchesKind(SymbolKind.Local, SymbolKind.Parameter));
}
}

// Some symbols in the enclosing block could cause conflicts even if they are not available at the location.
// E.g. symbols inside if statements / try catch statements.
var symbolsInBlock = semanticModel.GetAllDeclaredSymbols(container, cancellationToken,
descendInto: n => ShouldDescendInto(n));
var symbolsInBlock = semanticModel.GetAllDeclaredSymbols(container, cancellationToken, descendInto: ShouldDescendInto);

return symbolsInBlock.Concat(visibleSymbols);

Expand All @@ -60,10 +61,7 @@ protected override IEnumerable<ISymbol> GetCollidableSymbols(SemanticModel seman
// b) Symbols declared inside the local function do not cause collisions with symbols declared outside them, so avoid considering those symbols.
// Exclude lambdas as well when the language version is C# 8 or higher because symbols declared inside no longer collide with outer variables.
bool ShouldDescendInto(SyntaxNode node)
{
var isLanguageVersionGreaterOrEqualToCSharp8 = (semanticModel.Compilation as CSharpCompilation)?.LanguageVersion >= LanguageVersion.CSharp8;
return isLanguageVersionGreaterOrEqualToCSharp8 ? !SyntaxFacts.IsAnonymousOrLocalFunction(node) : !SyntaxFacts.IsLocalFunctionStatement(node);
}
=> isLanguageVersionGreaterOrEqualToCSharp8 ? !SyntaxFacts.IsAnonymousOrLocalFunction(node) : !SyntaxFacts.IsLocalFunctionStatement(node);
}

public bool IsExpressionContext(SemanticModel semanticModel, int position, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
Expand Down Expand Up @@ -38,31 +36,31 @@ SymbolKind.Field or
s is { Kind: SymbolKind.NamedType, IsStatic: true };

public SyntaxToken GenerateUniqueName(
SemanticModel semanticModel, SyntaxNode location, SyntaxNode containerOpt,
SemanticModel semanticModel, SyntaxNode location, SyntaxNode? containerOpt,
string baseName, CancellationToken cancellationToken)
{
return GenerateUniqueName(
semanticModel, location, containerOpt, baseName, filter: null, usedNames: null, cancellationToken);
}

public SyntaxToken GenerateUniqueName(
SemanticModel semanticModel, SyntaxNode location, SyntaxNode containerOpt,
SemanticModel semanticModel, SyntaxNode location, SyntaxNode? containerOpt,
string baseName, IEnumerable<string> usedNames, CancellationToken cancellationToken)
{
return GenerateUniqueName(
semanticModel, location, containerOpt, baseName, filter: null, usedNames, cancellationToken);
}

public SyntaxToken GenerateUniqueLocalName(
SemanticModel semanticModel, SyntaxNode location, SyntaxNode containerOpt,
SemanticModel semanticModel, SyntaxNode location, SyntaxNode? containerOpt,
string baseName, CancellationToken cancellationToken)
{
return GenerateUniqueName(
semanticModel, location, containerOpt, baseName, s_LocalNameFilter, usedNames: [], cancellationToken);
}

public SyntaxToken GenerateUniqueLocalName(
SemanticModel semanticModel, SyntaxNode location, SyntaxNode containerOpt,
SemanticModel semanticModel, SyntaxNode location, SyntaxNode? containerOpt,
string baseName, IEnumerable<string> usedNames, CancellationToken cancellationToken)
{
return GenerateUniqueName(
Expand All @@ -71,10 +69,15 @@ public SyntaxToken GenerateUniqueLocalName(

public SyntaxToken GenerateUniqueName(
SemanticModel semanticModel,
SyntaxNode location, SyntaxNode containerOpt,
string baseName, Func<ISymbol, bool> filter,
IEnumerable<string> usedNames, CancellationToken cancellationToken)
SyntaxNode location,
SyntaxNode? containerOpt,
string baseName,
Func<ISymbol, bool>? filter,
IEnumerable<string>? usedNames,
CancellationToken cancellationToken)
{
usedNames ??= [];

var container = containerOpt ?? location.AncestorsAndSelf().FirstOrDefault(
a => BlockFacts.IsExecutableBlock(a) || SyntaxFacts.IsParameterList(a) || SyntaxFacts.IsMethodBody(a));

Expand All @@ -89,7 +92,7 @@ public SyntaxToken GenerateUniqueName(
/// A symbol can possibly collide with the location if it is available to that location and/or
/// could cause a compiler error if its name is re-used at that location.
/// </summary>
protected virtual IEnumerable<ISymbol> GetCollidableSymbols(SemanticModel semanticModel, SyntaxNode location, SyntaxNode container, CancellationToken cancellationToken)
protected virtual IEnumerable<ISymbol> GetCollidableSymbols(SemanticModel semanticModel, SyntaxNode location, SyntaxNode? container, CancellationToken cancellationToken)
=> semanticModel.LookupSymbols(location.SpanStart).Concat(semanticModel.GetAllDeclaredSymbols(container, cancellationToken));

public SyntaxToken GenerateUniqueName(string baseName, IEnumerable<string> usedNames)
Expand All @@ -99,8 +102,6 @@ public SyntaxToken GenerateUniqueName(string baseName, IEnumerable<string> usedN
baseName, usedNames, this.SyntaxFacts.IsCaseSensitive));
}

#nullable enable

protected static IMethodSymbol? FindDisposeMethod(Compilation compilation, ITypeSymbol? type, bool isAsync)
{
if (type is null)
Expand Down Expand Up @@ -167,8 +168,6 @@ public SyntaxToken GenerateUniqueName(string baseName, IEnumerable<string> usedN
}
}

#nullable disable

#region ISemanticFacts implementation

public bool SupportsImplicitInterfaceImplementation => SemanticFacts.SupportsImplicitInterfaceImplementation;
Expand All @@ -177,31 +176,31 @@ public SyntaxToken GenerateUniqueName(string baseName, IEnumerable<string> usedN

public bool ExposesAnonymousFunctionParameterNames => SemanticFacts.ExposesAnonymousFunctionParameterNames;

public bool IsWrittenTo(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken)
public bool IsWrittenTo(SemanticModel semanticModel, SyntaxNode? node, CancellationToken cancellationToken)
=> SemanticFacts.IsWrittenTo(semanticModel, node, cancellationToken);

public bool IsOnlyWrittenTo(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken)
public bool IsOnlyWrittenTo(SemanticModel semanticModel, SyntaxNode? node, CancellationToken cancellationToken)
=> SemanticFacts.IsOnlyWrittenTo(semanticModel, node, cancellationToken);

public bool IsInOutContext(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken)
public bool IsInOutContext(SemanticModel semanticModel, SyntaxNode? node, CancellationToken cancellationToken)
=> SemanticFacts.IsInOutContext(semanticModel, node, cancellationToken);

public bool IsInRefContext(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken)
public bool IsInRefContext(SemanticModel semanticModel, SyntaxNode? node, CancellationToken cancellationToken)
=> SemanticFacts.IsInRefContext(semanticModel, node, cancellationToken);

public bool IsInInContext(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken)
public bool IsInInContext(SemanticModel semanticModel, SyntaxNode? node, CancellationToken cancellationToken)
=> SemanticFacts.IsInInContext(semanticModel, node, cancellationToken);

public bool CanReplaceWithRValue(SemanticModel semanticModel, SyntaxNode expression, CancellationToken cancellationToken)
public bool CanReplaceWithRValue(SemanticModel semanticModel, SyntaxNode? expression, CancellationToken cancellationToken)
=> SemanticFacts.CanReplaceWithRValue(semanticModel, expression, cancellationToken);

public ISymbol GetDeclaredSymbol(SemanticModel semanticModel, SyntaxToken token, CancellationToken cancellationToken)
public ISymbol? GetDeclaredSymbol(SemanticModel semanticModel, SyntaxToken token, CancellationToken cancellationToken)
=> SemanticFacts.GetDeclaredSymbol(semanticModel, token, cancellationToken);

public bool LastEnumValueHasInitializer(INamedTypeSymbol namedTypeSymbol)
=> SemanticFacts.LastEnumValueHasInitializer(namedTypeSymbol);

public bool TryGetSpeculativeSemanticModel(SemanticModel oldSemanticModel, SyntaxNode oldNode, SyntaxNode newNode, out SemanticModel speculativeModel)
public bool TryGetSpeculativeSemanticModel(SemanticModel oldSemanticModel, SyntaxNode oldNode, SyntaxNode newNode, [NotNullWhen(true)] out SemanticModel? speculativeModel)
=> SemanticFacts.TryGetSpeculativeSemanticModel(oldSemanticModel, oldNode, newNode, out speculativeModel);

public ImmutableHashSet<string> GetAliasNameSet(SemanticModel model, CancellationToken cancellationToken)
Expand All @@ -213,7 +212,7 @@ public ForEachSymbols GetForEachSymbols(SemanticModel semanticModel, SyntaxNode
public SymbolInfo GetCollectionInitializerSymbolInfo(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken)
=> SemanticFacts.GetCollectionInitializerSymbolInfo(semanticModel, node, cancellationToken);

public IMethodSymbol GetGetAwaiterMethod(SemanticModel semanticModel, SyntaxNode node)
public IMethodSymbol? GetGetAwaiterMethod(SemanticModel semanticModel, SyntaxNode node)
=> SemanticFacts.GetGetAwaiterMethod(semanticModel, node);

public ImmutableArray<IMethodSymbol> GetDeconstructionAssignmentMethods(SemanticModel semanticModel, SyntaxNode node)
Expand All @@ -228,42 +227,42 @@ public bool IsPartial(INamedTypeSymbol typeSymbol, CancellationToken cancellatio
public IEnumerable<ISymbol> GetDeclaredSymbols(SemanticModel semanticModel, SyntaxNode memberDeclaration, CancellationToken cancellationToken)
=> SemanticFacts.GetDeclaredSymbols(semanticModel, memberDeclaration, cancellationToken);

public IParameterSymbol FindParameterForArgument(SemanticModel semanticModel, SyntaxNode argumentNode, bool allowUncertainCandidates, bool allowParams, CancellationToken cancellationToken)
public IParameterSymbol? FindParameterForArgument(SemanticModel semanticModel, SyntaxNode argumentNode, bool allowUncertainCandidates, bool allowParams, CancellationToken cancellationToken)
=> SemanticFacts.FindParameterForArgument(semanticModel, argumentNode, allowUncertainCandidates, allowParams, cancellationToken);

public IParameterSymbol FindParameterForAttributeArgument(SemanticModel semanticModel, SyntaxNode argumentNode, bool allowUncertainCandidates, bool allowParams, CancellationToken cancellationToken)
public IParameterSymbol? FindParameterForAttributeArgument(SemanticModel semanticModel, SyntaxNode argumentNode, bool allowUncertainCandidates, bool allowParams, CancellationToken cancellationToken)
=> SemanticFacts.FindParameterForAttributeArgument(semanticModel, argumentNode, allowUncertainCandidates, allowParams, cancellationToken);

public ISymbol FindFieldOrPropertyForArgument(SemanticModel semanticModel, SyntaxNode argumentNode, CancellationToken cancellationToken)
public ISymbol? FindFieldOrPropertyForArgument(SemanticModel semanticModel, SyntaxNode argumentNode, CancellationToken cancellationToken)
=> SemanticFacts.FindFieldOrPropertyForArgument(semanticModel, argumentNode, cancellationToken);

public ISymbol FindFieldOrPropertyForAttributeArgument(SemanticModel semanticModel, SyntaxNode argumentNode, CancellationToken cancellationToken)
public ISymbol? FindFieldOrPropertyForAttributeArgument(SemanticModel semanticModel, SyntaxNode argumentNode, CancellationToken cancellationToken)
=> SemanticFacts.FindFieldOrPropertyForAttributeArgument(semanticModel, argumentNode, cancellationToken);

public ImmutableArray<ISymbol> GetBestOrAllSymbols(SemanticModel semanticModel, SyntaxNode node, SyntaxToken token, CancellationToken cancellationToken)
public ImmutableArray<ISymbol> GetBestOrAllSymbols(SemanticModel semanticModel, SyntaxNode? node, SyntaxToken token, CancellationToken cancellationToken)
=> SemanticFacts.GetBestOrAllSymbols(semanticModel, node, token, cancellationToken);

public bool IsInsideNameOfExpression(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken)
public bool IsInsideNameOfExpression(SemanticModel semanticModel, SyntaxNode? node, CancellationToken cancellationToken)
=> SemanticFacts.IsInsideNameOfExpression(semanticModel, node, cancellationToken);

public ImmutableArray<IMethodSymbol> GetLocalFunctionSymbols(Compilation compilation, ISymbol symbol, CancellationToken cancellationToken)
=> SemanticFacts.GetLocalFunctionSymbols(compilation, symbol, cancellationToken);

public bool IsInExpressionTree(SemanticModel semanticModel, SyntaxNode node, INamedTypeSymbol expressionTypeOpt, CancellationToken cancellationToken)
public bool IsInExpressionTree(SemanticModel semanticModel, SyntaxNode node, INamedTypeSymbol? expressionTypeOpt, CancellationToken cancellationToken)
=> SemanticFacts.IsInExpressionTree(semanticModel, node, expressionTypeOpt, cancellationToken);

public string GenerateNameForExpression(SemanticModel semanticModel, SyntaxNode expression, bool capitalize, CancellationToken cancellationToken)
=> SemanticFacts.GenerateNameForExpression(semanticModel, expression, capitalize, cancellationToken);

public IPreprocessingSymbol GetPreprocessingSymbol(SemanticModel semanticModel, SyntaxNode node)
public IPreprocessingSymbol? GetPreprocessingSymbol(SemanticModel semanticModel, SyntaxNode node)
=> SemanticFacts.GetPreprocessingSymbol(semanticModel, node);

public bool TryGetPrimaryConstructor(INamedTypeSymbol typeSymbol, [NotNullWhen(true)] out IMethodSymbol primaryConstructor)
public bool TryGetPrimaryConstructor(INamedTypeSymbol typeSymbol, [NotNullWhen(true)] out IMethodSymbol? primaryConstructor)
=> SemanticFacts.TryGetPrimaryConstructor(typeSymbol, out primaryConstructor);

#if WORKSPACE

public Task<ISymbol> GetInterceptorSymbolAsync(Document document, int position, CancellationToken cancellationToken)
public Task<ISymbol?> GetInterceptorSymbolAsync(Document document, int position, CancellationToken cancellationToken)
=> SemanticFacts.GetInterceptorSymbolAsync(document, position, cancellationToken);

#endif
Expand Down
Loading