Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
6ac9071a
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
6ac9071a
编写于
6月 23, 2020
作者:
G
Gen Lu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Address SymbolKey resolution issue when projects targeting different framework
Set ignoreAssemblyKey to true during SymbolKey resolution
上级
9a29e6af
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
117 addition
and
68 deletion
+117
-68
src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs
...Providers/ExtensionMethodImportCompletionProviderTests.cs
+0
-1
src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs
...mpletionProvider/ExtensionMethodImportCompletionHelper.cs
+112
-66
src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.cs
src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.cs
+5
-1
未找到文件。
src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs
浏览文件 @
6ac9071a
...
...
@@ -1623,7 +1623,6 @@ public void M({tupleType} x)
inlineDescription
:
"NS2"
);
}
[
InlineData
(
ReferenceType
.
Project
)]
[
InlineData
(
ReferenceType
.
Metadata
)]
[
Theory
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
...
...
src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs
浏览文件 @
6ac9071a
...
...
@@ -7,6 +7,7 @@
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Diagnostics
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
...
...
@@ -216,10 +217,18 @@ private static string GetReceiverTypeName(ITypeSymbol typeSymbol)
compilation
.
Assembly
,
filter
,
namespaceFilter
,
internalsVisible
,
counter
,
cancellationToken
);
var
isSymbolFromCurrentCompilation
=
project
==
currentProject
;
GetExtensionMethodItemsWorker
(
position
,
semanticModel
,
receiverTypeSymbol
,
matchingMethodSymbols
,
isSymbolFromCurrentCompilation
,
completionItemsbuilder
,
namespaceNameCache
,
checkedReceiverTypes
,
cancellationToken
);
if
(
project
==
currentProject
)
{
GetExtensionMethodItemsForSymbolsFromSameCompilation
(
position
,
semanticModel
,
receiverTypeSymbol
,
matchingMethodSymbols
,
completionItemsbuilder
,
namespaceNameCache
,
checkedReceiverTypes
,
cancellationToken
);
}
else
{
GetExtensionMethodItemsForSymbolsFromDifferentCompilation
(
position
,
semanticModel
,
receiverTypeSymbol
,
matchingMethodSymbols
,
completionItemsbuilder
,
namespaceNameCache
,
checkedReceiverTypes
,
cancellationToken
);
}
}
// Get extension method items from PE
...
...
@@ -234,9 +243,9 @@ private static string GetReceiverTypeName(ITypeSymbol typeSymbol)
assembly
,
filter
,
namespaceFilter
,
internalsVisible
,
counter
,
cancellationToken
);
GetExtensionMethodItems
Worker
(
GetExtensionMethodItems
ForSymbolsFromSameCompilation
(
position
,
semanticModel
,
receiverTypeSymbol
,
matchingMethodSymbols
,
isSymbolFromCurrentCompilation
:
true
,
completionItemsbuilder
,
namespaceNameCache
,
completionItemsbuilder
,
namespaceNameCache
,
checkedReceiverTypes
,
cancellationToken
);
}
}
...
...
@@ -256,83 +265,120 @@ static ImmutableArray<string> AttachComplexTypes(ImmutableArray<string> receiver
}
}
private
static
void
GetExtensionMethodItems
Worker
(
private
static
void
GetExtensionMethodItems
ForSymbolsFromDifferentCompilation
(
int
position
,
SemanticModel
semanticModel
,
ITypeSymbol
receiverTypeSymbol
,
MultiDictionary
<
ITypeSymbol
,
IMethodSymbol
>
matchingMethodSymbols
,
bool
isSymbolFromCurrentCompilation
,
ArrayBuilder
<
SerializableImportCompletionItem
>
builder
,
Dictionary
<
INamespaceSymbol
,
string
>
stringCache
,
Dictionary
<
ITypeSymbol
,
bool
>
checkedReceiverTypes
,
CancellationToken
cancellationToken
)
{
// Matching extension method symbols are grouped based on their receiver type.
foreach
(
var
(
r
eceiverType
,
methodSymbols
)
in
matchingMethodSymbols
)
foreach
(
var
(
declaredR
eceiverType
,
methodSymbols
)
in
matchingMethodSymbols
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
var
receiverTypeInCurrentCompilation
=
isSymbolFromCurrentCompilation
?
receiverType
:
SymbolFinder
.
FindSimilarSymbols
(
receiverType
,
semanticModel
.
Compilation
).
OfType
<
ITypeSymbol
>().
FirstOrDefault
();
var
declaredReceiverTypeInCurrentCompilation
=
SymbolFinder
.
FindSimilarSymbols
(
declaredReceiverType
,
semanticModel
.
Compilation
,
ignoreAssemblyKey
:
true
,
cancellationToken
).
FirstOrDefault
();
if
(
declaredReceiverTypeInCurrentCompilation
==
null
)
{
if
(!
Debugger
.
IsAttached
)
Debugger
.
Launch
();
continue
;
}
// If we already checked an extension method with same receiver type before, and we know it can't be applied
// to the receiverTypeSymbol, then no need to proceed further.
if
(
checkedReceiverTypes
.
TryGetValue
(
receiverTypeInCurrentCompilation
,
out
var
cachedResult
)
&&
!
cachedResult
)
if
(
checkedReceiverTypes
.
TryGetValue
(
declaredReceiverTypeInCurrentCompilation
,
out
var
cachedResult
)
&&
!
cachedResult
)
{
// If we already checked an extension method with same receiver type before, and we know it can't be applied
// to the receiverTypeSymbol, then no need to proceed methods from this group..
continue
;
}
if
(
isSymbolFromCurrentCompilation
)
var
methodsInCurrentCompilation
=
methodSymbols
.
Select
(
s
=>
SymbolFinder
.
FindSimilarSymbols
(
s
,
semanticModel
.
Compilation
,
ignoreAssemblyKey
:
false
,
cancellationToken
).
FirstOrDefault
()).
WhereNotNull
();
var
enumerator
=
methodsInCurrentCompilation
.
GetEnumerator
();
if
(!
enumerator
.
MoveNext
())
{
// We haven't seen this type yet. Try to check by reducing one extension method
// to the given receiver type and save the result.
if
(!
cachedResult
)
{
var
reducedMethodSymbol
=
methodSymbols
.
First
().
ReduceExtensionMethod
(
receiverTypeSymbol
);
cachedResult
=
reducedMethodSymbol
!=
null
;
checkedReceiverTypes
[
receiverType
]
=
cachedResult
;
}
continue
;
}
// Get the first method so we can check if the receiver type applies.
var
methodInCurrentCompilation
=
enumerator
.
Current
;
// We haven't seen this type yet. Try to check by reducing one extension method
// to the given receiver type and save the result.
if
(!
cachedResult
)
{
// If this is the first symbol we retrived from current compilation,
// try to check if we can apply it to given receiver type, and save result to our cache.
var
reducedMethodSymbol
=
methodInCurrentCompilation
.
ReduceExtensionMethod
(
receiverTypeSymbol
);
cachedResult
=
reducedMethodSymbol
!=
null
;
checkedReceiverTypes
[
declaredReceiverTypeInCurrentCompilation
]
=
cachedResult
;
}
// Now, cachedResult being false means the receiver type doesn't match,
// stop processing methods from this group.
if
(!
cachedResult
)
{
continue
;
}
// Add first method to the item list.
if
(
semanticModel
.
IsAccessible
(
position
,
methodInCurrentCompilation
))
{
CreateAndAddItem
(
methodInCurrentCompilation
,
builder
,
stringCache
);
}
// Receiver type matches the receiver type of the extension method declaration.
// We can add accessible ones to the item builder.
if
(
cachedResult
)
// Then add the rest to item list.
while
(
enumerator
.
MoveNext
())
{
methodInCurrentCompilation
=
enumerator
.
Current
;
if
(
semanticModel
.
IsAccessible
(
position
,
methodInCurrentCompilation
))
{
foreach
(
var
methodSymbol
in
methodSymbols
)
{
if
(
semanticModel
.
IsAccessible
(
position
,
methodSymbol
))
{
CreateAndAddItem
(
methodSymbol
,
builder
,
stringCache
);
}
}
CreateAndAddItem
(
methodInCurrentCompilation
,
builder
,
stringCache
);
}
}
else
}
}
private
static
void
GetExtensionMethodItemsForSymbolsFromSameCompilation
(
int
position
,
SemanticModel
semanticModel
,
ITypeSymbol
receiverTypeSymbol
,
MultiDictionary
<
ITypeSymbol
,
IMethodSymbol
>
matchingMethodSymbols
,
ArrayBuilder
<
SerializableImportCompletionItem
>
builder
,
Dictionary
<
INamespaceSymbol
,
string
>
stringCache
,
Dictionary
<
ITypeSymbol
,
bool
>
checkedReceiverTypes
,
CancellationToken
cancellationToken
)
{
// Matching extension method symbols are grouped based on their receiver type.
foreach
(
var
(
receiverType
,
methodSymbols
)
in
matchingMethodSymbols
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
// If we already checked an extension method with same receiver type before, and we know it can't be applied
// to the receiverTypeSymbol, then no need to proceed further.
if
(
checkedReceiverTypes
.
TryGetValue
(
receiverType
,
out
var
cachedResult
)
&&
!
cachedResult
)
{
// Symbols could be from a different compilation.
// Need to find the matching one in current compilation before any further checks is done.
foreach
(
var
methodSymbol
in
methodSymbols
.
Select
(
s
=>
SymbolFinder
.
FindSimilarSymbols
(
s
,
semanticModel
.
Compilation
).
FirstOrDefault
()).
WhereNotNull
())
{
// We haven't seen this type yet. Try to check by reducing one extension method
// to the given receiver type and save the result.
// Note we will only hit this condition at most once, which is the first time we find a non-null
// similar symbol from current compilation.
if
(!
cachedResult
)
{
// If this is the first symbol we retrived from current compilation,
// try to check if we can apply it to given receiver type, and save result to our cache.
var
reducedMethodSymbol
=
methodSymbol
.
ReduceExtensionMethod
(
receiverTypeSymbol
);
cachedResult
=
reducedMethodSymbol
!=
null
;
checkedReceiverTypes
[
receiverType
]
=
cachedResult
;
// Now, cachedResult being false means the receiver type doesn't match,
// stop processing any more methods.
if
(!
cachedResult
)
{
break
;
}
}
continue
;
}
// We haven't seen this type yet. Try to check by reducing one extension method
// to the given receiver type and save the result.
if
(!
cachedResult
)
{
var
reducedMethodSymbol
=
methodSymbols
.
First
().
ReduceExtensionMethod
(
receiverTypeSymbol
);
cachedResult
=
reducedMethodSymbol
!=
null
;
checkedReceiverTypes
[
receiverType
]
=
cachedResult
;
}
// Receiver type matches the receiver type of the extension method declaration.
// We can add accessible ones to the item builder.
if
(
cachedResult
)
{
foreach
(
var
methodSymbol
in
methodSymbols
)
{
if
(
semanticModel
.
IsAccessible
(
position
,
methodSymbol
))
{
CreateAndAddItem
(
methodSymbol
,
builder
,
stringCache
);
...
...
@@ -340,16 +386,16 @@ static ImmutableArray<string> AttachComplexTypes(ImmutableArray<string> receiver
}
}
}
static
void
CreateAndAddItem
(
IMethodSymbol
methodSymbol
,
ArrayBuilder
<
SerializableImportCompletionItem
>
builder
,
Dictionary
<
INamespaceSymbol
,
string
>
stringCache
)
=>
builder
.
Add
(
new
SerializableImportCompletionItem
(
SymbolKey
.
CreateString
(
methodSymbol
),
methodSymbol
.
Name
,
methodSymbol
.
Arity
,
methodSymbol
.
GetGlyph
(),
GetFullyQualifiedNamespaceName
(
methodSymbol
.
ContainingNamespace
,
stringCache
)));
}
private
static
void
CreateAndAddItem
(
IMethodSymbol
methodSymbol
,
ArrayBuilder
<
SerializableImportCompletionItem
>
builder
,
Dictionary
<
INamespaceSymbol
,
string
>
stringCache
)
=>
builder
.
Add
(
new
SerializableImportCompletionItem
(
SymbolKey
.
CreateString
(
methodSymbol
),
methodSymbol
.
Name
,
methodSymbol
.
Arity
,
methodSymbol
.
GetGlyph
(),
GetFullyQualifiedNamespaceName
(
methodSymbol
.
ContainingNamespace
,
stringCache
)));
private
static
string
GetFullyQualifiedNamespaceName
(
INamespaceSymbol
symbol
,
Dictionary
<
INamespaceSymbol
,
string
>
stringCache
)
{
if
(
symbol
.
ContainingNamespace
==
null
||
symbol
.
ContainingNamespace
.
IsGlobalNamespace
)
...
...
src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.cs
浏览文件 @
6ac9071a
...
...
@@ -198,6 +198,10 @@ private static bool InSource(ISymbol symbol)
/// <returns></returns>
public
static
IEnumerable
<
TSymbol
>
FindSimilarSymbols
<
TSymbol
>(
TSymbol
symbol
,
Compilation
compilation
,
CancellationToken
cancellationToken
=
default
)
where
TSymbol
:
ISymbol
=>
FindSimilarSymbols
(
symbol
,
compilation
,
ignoreAssemblyKey
:
false
,
cancellationToken
);
internal
static
IEnumerable
<
TSymbol
>
FindSimilarSymbols
<
TSymbol
>(
TSymbol
symbol
,
Compilation
compilation
,
bool
ignoreAssemblyKey
,
CancellationToken
cancellationToken
=
default
)
where
TSymbol
:
ISymbol
{
if
(
symbol
==
null
)
{
...
...
@@ -213,7 +217,7 @@ public static IEnumerable<TSymbol> FindSimilarSymbols<TSymbol>(TSymbol symbol, C
// We may be talking about different compilations. So do not try to resolve locations.
var
result
=
new
HashSet
<
TSymbol
>();
var
resolution
=
key
.
Resolve
(
compilation
,
cancellationToken
:
cancellationToken
);
var
resolution
=
key
.
Resolve
(
compilation
,
ignoreAssemblyKey
,
cancellationToken
);
foreach
(
var
current
in
resolution
.
OfType
<
TSymbol
>())
{
result
.
Add
(
current
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录