未验证 提交 5774395a 编写于 作者: D David 提交者: GitHub

Merge pull request #35914 from dibarbet/fix_completion_in_local_functions

Fix declaration name completion when local functions present.
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.Decompiler.CSharp;
using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit; using Xunit;
...@@ -4182,5 +4184,177 @@ IEnumerable<int> M(IEnumerable<int> nums) ...@@ -4182,5 +4184,177 @@ IEnumerable<int> M(IEnumerable<int> nums)
} }
#endregion #endregion
#region Name Generation
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertQueryToForEach)]
public async Task EnumerableFunctionDoesNotUseLocalFunctionName()
{
string source = @"
using System;
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>{ 1, 2, 3, 4, 5, 6, 7 };
var r = [|from i in c select i+1|];
void enumerable() { }
}
}";
string output = @"
using System;
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>{ 1, 2, 3, 4, 5, 6, 7 };
IEnumerable<int> enumerable1()
{
foreach (var i in c)
{
yield return i + 1;
}
}
var r = enumerable1();
void enumerable() { }
}
}";
await TestInRegularAndScriptAsync(source, output);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertQueryToForEach)]
public async Task EnumerableFunctionCanUseLocalFunctionParameterName()
{
string source = @"
using System;
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>{ 1, 2, 3, 4, 5, 6, 7 };
var r = [|from i in c select i+1|];
void M(IEnumerable<int> enumerable) { }
}
}";
string output = @"
using System;
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>{ 1, 2, 3, 4, 5, 6, 7 };
IEnumerable<int> enumerable()
{
foreach (var i in c)
{
yield return i + 1;
}
}
var r = enumerable();
void M(IEnumerable<int> enumerable) { }
}
}";
await TestInRegularAndScriptAsync(source, output);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertQueryToForEach)]
public async Task EnumerableFunctionDoesNotUseLambdaParameterNameWithCSharpLessThan8()
{
string source = @"
using System;
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>{ 1, 2, 3, 4, 5, 6, 7 };
var r = [|from i in c select i+1|];
Action<int> myLambda = enumerable => { };
}
}";
string output = @"
using System;
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>{ 1, 2, 3, 4, 5, 6, 7 };
IEnumerable<int> enumerable1()
{
foreach (var i in c)
{
yield return i + 1;
}
}
var r = enumerable1();
Action<int> myLambda = enumerable => { };
}
}";
await TestInRegularAndScriptAsync(source, output, parseOptions: new CSharpParseOptions(CodeAnalysis.CSharp.LanguageVersion.CSharp7_3));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertQueryToForEach)]
public async Task EnumerableFunctionCanUseLambdaParameterNameInCSharp8()
{
string source = @"
using System;
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>{ 1, 2, 3, 4, 5, 6, 7 };
var r = [|from i in c select i+1|];
Action<int> myLambda = enumerable => { };
}
}";
string output = @"
using System;
using System.Collections.Generic;
using System.Linq;
class Query
{
public static void Main(string[] args)
{
List<int> c = new List<int>{ 1, 2, 3, 4, 5, 6, 7 };
IEnumerable<int> enumerable()
{
foreach (var i in c)
{
yield return i + 1;
}
}
var r = enumerable();
Action<int> myLambda = enumerable => { };
}
}";
await TestInRegularAndScriptAsync(source, output, parseOptions: new CSharpParseOptions(CodeAnalysis.CSharp.LanguageVersion.CSharp8));
}
#endregion
} }
} }
...@@ -1718,6 +1718,180 @@ void M2() ...@@ -1718,6 +1718,180 @@ void M2()
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name); expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
} }
[WorkItem(35891, "https://github.com/dotnet/roslyn/issues/35891")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestCompletionDoesNotUseLocalAsLocalFunctionParameter()
{
var markup = @"
class ClassA
{
class ClassB { }
void M()
{
ClassB classB = new ClassB();
void LocalM1(ClassB $$) { }
}
}
";
await VerifyItemIsAbsentAsync(markup, "classB");
}
[WorkItem(35891, "https://github.com/dotnet/roslyn/issues/35891")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestCompletionDoesNotUseLocalAsLocalFunctionVariable()
{
var markup = @"
class ClassA
{
class ClassB { }
void M()
{
ClassB classB = new ClassB();
void LocalM1()
{
ClassB $$
}
}
}
";
await VerifyItemIsAbsentAsync(markup, "classB");
}
[WorkItem(35891, "https://github.com/dotnet/roslyn/issues/35891")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestCompletionDoesNotUseLocalInNestedLocalFunction()
{
var markup = @"
class ClassA
{
class ClassB { }
void M()
{
ClassB classB = new ClassB();
void LocalM1()
{
void LocalM2()
{
ClassB $$
}
}
}
}
";
await VerifyItemIsAbsentAsync(markup, "classB");
}
[WorkItem(35891, "https://github.com/dotnet/roslyn/issues/35891")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestCompletionDoesNotUseLocalFunctionParameterInNestedLocalFunction()
{
var markup = @"
class ClassA
{
class ClassB { }
void M()
{
void LocalM1(ClassB classB)
{
void LocalM2()
{
ClassB $$
}
}
}
}
";
await VerifyItemIsAbsentAsync(markup, "classB");
}
[WorkItem(35891, "https://github.com/dotnet/roslyn/issues/35891")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestCompletionCanUseLocalFunctionParameterAsParameter()
{
var markup = @"
class ClassA
{
class ClassB { }
void M()
{
void LocalM1(ClassB classB) { }
void LocalM2(ClassB $$) { }
}
}
";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Parameter,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[WorkItem(35891, "https://github.com/dotnet/roslyn/issues/35891")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestCompletionCanUseLocalFunctionVariableAsParameter()
{
var markup = @"
class ClassA
{
class ClassB { }
void M()
{
void LocalM1()
{
ClassB classB
}
void LocalM2(ClassB $$) { }
}
}
";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Parameter,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[WorkItem(35891, "https://github.com/dotnet/roslyn/issues/35891")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestCompletionCanUseLocalFunctionParameterAsVariable()
{
var markup = @"
class ClassA
{
class ClassB { }
void M()
{
void LocalM1(ClassB classB) { }
void LocalM2()
{
ClassB $$
}
}
}
";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[WorkItem(35891, "https://github.com/dotnet/roslyn/issues/35891")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestCompletionCanUseLocalFunctionVariableAsVariable()
{
var markup = @"
class ClassA
{
class ClassB { }
void M()
{
void LocalM1()
{
ClassB classB
}
void LocalM2()
{
ClassB $$
}
}
}
";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
private static NamingStylePreferences NamesEndWithSuffixPreferences() private static NamingStylePreferences NamesEndWithSuffixPreferences()
{ {
var specificationStyles = new[] var specificationStyles = new[]
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.ConvertForToForEach; using Microsoft.CodeAnalysis.CSharp.ConvertForToForEach;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
...@@ -1366,5 +1367,145 @@ void Test(string[][] array) ...@@ -1366,5 +1367,145 @@ void Test(string[][] array)
} }
}"); }");
} }
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertForToForEach)]
public async Task TestDoesNotUseLocalFunctionName()
{
await TestInRegularAndScript1Async(
@"using System;
class C
{
void Test(string[] array)
{
[||]for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
void v() { }
}
}",
@"using System;
class C
{
void Test(string[] array)
{
foreach (string {|Rename:v1|} in array)
{
Console.WriteLine(v1);
}
void v() { }
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertForToForEach)]
public async Task TestUsesLocalFunctionParameterName()
{
await TestInRegularAndScript1Async(
@"using System;
class C
{
void Test(string[] array)
{
[||]for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
void M(string v)
{
}
}
}",
@"using System;
class C
{
void Test(string[] array)
{
foreach (string {|Rename:v|} in array)
{
Console.WriteLine(v);
}
void M(string v)
{
}
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertForToForEach)]
public async Task TestDoesNotUseLambdaParameterWithCSharpLessThan8()
{
await TestInRegularAndScript1Async(
@"using System;
class C
{
void Test(string[] array)
{
[||]for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
Action<int> myLambda = v => { };
}
}",
@"using System;
class C
{
void Test(string[] array)
{
foreach (string {|Rename:v1|} in array)
{
Console.WriteLine(v1);
}
Action<int> myLambda = v => { };
}
}", parameters: new TestParameters(new CSharpParseOptions(LanguageVersion.CSharp7_3)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertForToForEach)]
public async Task TestUsesLambdaParameterNameInCSharp8()
{
await TestInRegularAndScript1Async(
@"using System;
class C
{
void Test(string[] array)
{
[||]for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
Action<int> myLambda = v => { };
}
}",
@"using System;
class C
{
void Test(string[] array)
{
foreach (string {|Rename:v|} in array)
{
Console.WriteLine(v);
}
Action<int> myLambda = v => { };
}
}", parameters: new TestParameters(new CSharpParseOptions(LanguageVersion.CSharp8)));
}
} }
} }
...@@ -6863,5 +6863,141 @@ public static void Test() ...@@ -6863,5 +6863,141 @@ public static void Test()
} }
}", optionName); }", optionName);
} }
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
public async Task DoesNotUseLocalFunctionName_PreferUnused()
{
await TestInRegularAndScriptAsync(
@"class C
{
int M()
{
int [|x|] = M2();
x = 2;
return x;
void unused() { }
}
int M2() => 0;
}",
@"class C
{
int M()
{
int unused1 = M2();
int x = 2;
return x;
void unused() { }
}
int M2() => 0;
}", options: PreferUnusedLocal);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
public async Task CanUseLocalFunctionParameterName_PreferUnused()
{
await TestInRegularAndScriptAsync(
@"class C
{
int M()
{
int [|x|] = M2();
x = 2;
return x;
void MLocal(int unused) { }
}
int M2() => 0;
}",
@"class C
{
int M()
{
int unused = M2();
int x = 2;
return x;
void MLocal(int unused) { }
}
int M2() => 0;
}", options: PreferUnusedLocal);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
public async Task DoesNotUseLambdaFunctionParameterNameWithCSharpLessThan8_PreferUnused()
{
await TestInRegularAndScriptAsync(
@"
using System;
class C
{
int M()
{
int [|x|] = M2();
x = 2;
Action<int> myLambda = unused => { };
return x;
}
int M2() => 0;
}",
@"
using System;
class C
{
int M()
{
int unused1 = M2();
int x = 2;
Action<int> myLambda = unused => { };
return x;
}
int M2() => 0;
}", options: PreferUnusedLocal, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7_3));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
public async Task CanUseLambdaFunctionParameterNameWithCSharp8_PreferUnused()
{
await TestInRegularAndScriptAsync(
@"
using System;
class C
{
int M()
{
int [|x|] = M2();
x = 2;
Action<int> myLambda = unused => { };
return x;
}
int M2() => 0;
}",
@"
using System;
class C
{
int M()
{
int unused = M2();
int x = 2;
Action<int> myLambda = unused => { };
return x;
}
int M2() => 0;
}", options: PreferUnusedLocal, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp8));
}
} }
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.LanguageServices;
......
...@@ -26,6 +26,30 @@ private CSharpSemanticFactsService() ...@@ -26,6 +26,30 @@ private CSharpSemanticFactsService()
{ {
} }
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);
// 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.GetExistingSymbols(container, cancellationToken,
descendInto: n => ShouldDescendInto(n));
return symbolsInBlock.Concat(visibleSymbols);
// Walk through the enclosing block symbols, but avoid exploring local functions
// a) Visible symbols from the local function would be returned by LookupSymbols
// (e.g. location is inside a local function, the local function method name).
// 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 ? !SyntaxFactsService.IsAnonymousOrLocalFunction(node) : !SyntaxFactsService.IsLocalFunctionStatement(node);
}
}
public bool SupportsImplicitInterfaceImplementation => true; public bool SupportsImplicitInterfaceImplementation => true;
public bool ExposesAnonymousFunctionParameterNames => false; public bool ExposesAnonymousFunctionParameterNames => false;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
...@@ -59,20 +60,25 @@ internal abstract class AbstractSemanticFactsService ...@@ -59,20 +60,25 @@ internal abstract class AbstractSemanticFactsService
var container = containerOpt ?? location.AncestorsAndSelf().FirstOrDefault( var container = containerOpt ?? location.AncestorsAndSelf().FirstOrDefault(
a => syntaxFacts.IsExecutableBlock(a) || syntaxFacts.IsMethodBody(a)); a => syntaxFacts.IsExecutableBlock(a) || syntaxFacts.IsMethodBody(a));
var candidates = semanticModel.LookupSymbols(location.SpanStart).Concat( var candidates = GetCollidableSymbols(semanticModel, location, container, cancellationToken);
semanticModel.GetExistingSymbols(container, cancellationToken)); var filteredCandidates = filter != null ? candidates.Where(filter) : candidates;
return GenerateUniqueName( return GenerateUniqueName(baseName, filteredCandidates.Select(s => s.Name).Concat(usedNames));
semanticModel, location, containerOpt, baseName, filter != null ? candidates.Where(filter) : candidates, usedNames, cancellationToken);
} }
private SyntaxToken GenerateUniqueName( /// <summary>
SemanticModel semanticModel, SyntaxNode location, SyntaxNode containerOpt, /// Retrieves all symbols that could collide with a symbol at the specified location.
string baseName, IEnumerable<ISymbol> candidates, IEnumerable<string> usedNames, CancellationToken cancellationToken) /// 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)
=> semanticModel.LookupSymbols(location.SpanStart).Concat(semanticModel.GetExistingSymbols(container, cancellationToken));
private SyntaxToken GenerateUniqueName(string baseName, IEnumerable<string> usedNames)
{ {
return this.SyntaxFactsService.ToIdentifierToken( return this.SyntaxFactsService.ToIdentifierToken(
NameGenerator.EnsureUniqueness( NameGenerator.EnsureUniqueness(
baseName, candidates.Select(s => s.Name).Concat(usedNames), this.SyntaxFactsService.IsCaseSensitive)); baseName, usedNames, this.SyntaxFactsService.IsCaseSensitive));
} }
} }
} }
...@@ -112,9 +112,8 @@ internal interface ISemanticFactsService : ILanguageService ...@@ -112,9 +112,8 @@ internal interface ISemanticFactsService : ILanguageService
SemanticModel semanticModel, SyntaxNode location, SemanticModel semanticModel, SyntaxNode location,
SyntaxNode containerOpt, string baseName, IEnumerable<string> usedNames, CancellationToken cancellationToken); SyntaxNode containerOpt, string baseName, IEnumerable<string> usedNames, CancellationToken cancellationToken);
SyntaxToken GenerateUniqueName( SyntaxToken GenerateUniqueName(SemanticModel semanticModel, SyntaxNode location, SyntaxNode containerOpt, string baseName,
SemanticModel semanticModel, SyntaxNode location, Func<ISymbol, bool> filter, IEnumerable<string> usedNames, CancellationToken cancellationToken);
SyntaxNode containerOpt, string baseName, Func<ISymbol, bool> filter, IEnumerable<string> usedNames, CancellationToken cancellationToken);
SyntaxToken GenerateUniqueLocalName( SyntaxToken GenerateUniqueLocalName(
SemanticModel semanticModel, SyntaxNode location, SemanticModel semanticModel, SyntaxNode location,
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
...@@ -221,29 +222,29 @@ public static SemanticModel GetOriginalSemanticModel(this SemanticModel semantic ...@@ -221,29 +222,29 @@ public static SemanticModel GetOriginalSemanticModel(this SemanticModel semantic
} }
public static HashSet<ISymbol> GetAllDeclaredSymbols( public static HashSet<ISymbol> GetAllDeclaredSymbols(
this SemanticModel semanticModel, SyntaxNode container, CancellationToken cancellationToken) this SemanticModel semanticModel, SyntaxNode container, CancellationToken cancellationToken, Func<SyntaxNode, bool> filter = null)
{ {
var symbols = new HashSet<ISymbol>(); var symbols = new HashSet<ISymbol>();
if (container != null) if (container != null)
{ {
GetAllDeclaredSymbols(semanticModel, container, symbols, cancellationToken); GetAllDeclaredSymbols(semanticModel, container, symbols, cancellationToken, filter);
} }
return symbols; return symbols;
} }
public static IEnumerable<ISymbol> GetExistingSymbols( public static IEnumerable<ISymbol> GetExistingSymbols(
this SemanticModel semanticModel, SyntaxNode container, CancellationToken cancellationToken) this SemanticModel semanticModel, SyntaxNode container, CancellationToken cancellationToken, Func<SyntaxNode, bool> descendInto = null)
{ {
// Ignore an anonymous type property or tuple field. It's ok if they have a name that // Ignore an anonymous type property or tuple field. It's ok if they have a name that
// matches the name of the local we're introducing. // matches the name of the local we're introducing.
return semanticModel.GetAllDeclaredSymbols(container, cancellationToken) return semanticModel.GetAllDeclaredSymbols(container, cancellationToken, descendInto)
.Where(s => !s.IsAnonymousTypeProperty() && !s.IsTupleField()); .Where(s => !s.IsAnonymousTypeProperty() && !s.IsTupleField());
} }
private static void GetAllDeclaredSymbols( private static void GetAllDeclaredSymbols(
SemanticModel semanticModel, SyntaxNode node, SemanticModel semanticModel, SyntaxNode node,
HashSet<ISymbol> symbols, CancellationToken cancellationToken) HashSet<ISymbol> symbols, CancellationToken cancellationToken, Func<SyntaxNode, bool> descendInto = null)
{ {
var symbol = semanticModel.GetDeclaredSymbol(node, cancellationToken); var symbol = semanticModel.GetDeclaredSymbol(node, cancellationToken);
...@@ -256,9 +257,16 @@ public static SemanticModel GetOriginalSemanticModel(this SemanticModel semantic ...@@ -256,9 +257,16 @@ public static SemanticModel GetOriginalSemanticModel(this SemanticModel semantic
{ {
if (child.IsNode) if (child.IsNode)
{ {
GetAllDeclaredSymbols(semanticModel, child.AsNode(), symbols, cancellationToken); var childNode = child.AsNode();
if (ShouldDescendInto(childNode, descendInto))
{
GetAllDeclaredSymbols(semanticModel, child.AsNode(), symbols, cancellationToken, descendInto);
}
} }
} }
static bool ShouldDescendInto(SyntaxNode node, Func<SyntaxNode, bool> filter)
=> filter != null ? filter(node) : true;
} }
} }
} }
...@@ -328,8 +328,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ...@@ -328,8 +328,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return node.FirstAncestorOrSelf(Of NameOfExpressionSyntax) IsNot Nothing Return node.FirstAncestorOrSelf(Of NameOfExpressionSyntax) IsNot Nothing
End Function End Function
Private Function ISemanticFactsService_GenerateUniqueName1( Private Function ISemanticFactsService_GenerateUniqueName(semanticModel As SemanticModel, location As SyntaxNode, containerOpt As SyntaxNode, baseName As String, filter As Func(Of ISymbol, Boolean), usedNames As IEnumerable(Of String), cancellationToken As CancellationToken) As SyntaxToken Implements ISemanticFactsService.GenerateUniqueName
semanticModel As SemanticModel, location As SyntaxNode, containerOpt As SyntaxNode, baseName As String, filter As Func(Of ISymbol, Boolean), usedNames As IEnumerable(Of String), cancellationToken As CancellationToken) As SyntaxToken Implements ISemanticFactsService.GenerateUniqueName
Return MyBase.GenerateUniqueName(semanticModel, location, containerOpt, baseName, filter, usedNames, cancellationToken) Return MyBase.GenerateUniqueName(semanticModel, location, containerOpt, baseName, filter, usedNames, cancellationToken)
End Function End Function
End Class End Class
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册