Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
f42de27b
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,发现更多精彩内容 >>
提交
f42de27b
编写于
8月 09, 2019
作者:
P
Paul Chen
提交者:
Jason Malinowski
8月 08, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add ref, qualified generic name detection, and tuple handling for SpeculativeT completion. (#37323)
Fixes #37224 Fixes #37268 Fixes #37361
上级
d2296ee0
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
660 addition
and
30 deletion
+660
-30
src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SpeculativeTCompletionProviderTests.cs
...ompletionProviders/SpeculativeTCompletionProviderTests.cs
+585
-3
src/Features/CSharp/Portable/Completion/CompletionProviders/SpeculativeTCompletionProvider.cs
...ion/CompletionProviders/SpeculativeTCompletionProvider.cs
+74
-26
src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs
.../Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs
+1
-1
未找到文件。
src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SpeculativeTCompletionProviderTests.cs
浏览文件 @
f42de27b
...
...
@@ -162,6 +162,588 @@ class C
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
public
async
Task
InRef0
()
{
var
markup
=
@"
using System;
class C
{
ref $$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
public
async
Task
InRef1
()
{
var
markup
=
@"
using System;
class C
{
ref T$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
public
async
Task
InRefGeneric0
()
{
var
markup
=
@"
using System;
class C
{
ref Func<$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
public
async
Task
InRefGeneric1
()
{
var
markup
=
@"
using System;
class C
{
ref Func<$$>
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
public
async
Task
InRefGeneric2
()
{
var
markup
=
@"
using System;
class C
{
ref Func<T$$>
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
public
async
Task
InRefGeneric3
()
{
var
markup
=
@"
using System;
class C
{
ref Func<int, $$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
public
async
Task
InRefReadonlyGeneric
()
{
var
markup
=
@"
using System;
class C
{
ref readonly Func<$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37268
,
"https://github.com/dotnet/roslyn/issues/37268"
)]
public
async
Task
InQualifiedGeneric0
()
{
var
markup
=
@"
using System;
class C
{
System.Func<$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37268
,
"https://github.com/dotnet/roslyn/issues/37268"
)]
public
async
Task
InQualifiedGeneric1
()
{
var
markup
=
@"
using System;
class C
{
System.Collections.Generic.List<$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
[
WorkItem
(
37268
,
"https://github.com/dotnet/roslyn/issues/37268"
)]
public
async
Task
InRefAndQualifiedGeneric0
()
{
var
markup
=
@"
using System;
class C
{
ref System.Func<$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
[
WorkItem
(
37268
,
"https://github.com/dotnet/roslyn/issues/37268"
)]
public
async
Task
InRefAndQualifiedGeneric1
()
{
var
markup
=
@"
using System;
class C
{
internal ref System.Func<int,$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
[
WorkItem
(
37268
,
"https://github.com/dotnet/roslyn/issues/37268"
)]
public
async
Task
InRefAndQualifiedNestedGeneric0
()
{
var
markup
=
@"
using System;
class C
{
partial ref System.Func<Func<$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
[
WorkItem
(
37268
,
"https://github.com/dotnet/roslyn/issues/37268"
)]
public
async
Task
InRefAndQualifiedNestedGeneric1
()
{
var
markup
=
@"
using System;
class C
{
private ref Func<System.Func<int,$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
[
WorkItem
(
37268
,
"https://github.com/dotnet/roslyn/issues/37268"
)]
public
async
Task
InRefAndQualifiedNestedGeneric2
()
{
var
markup
=
@"
using System;
class C
{
public ref Func<int, System.Func<int,$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37224
,
"https://github.com/dotnet/roslyn/issues/37224"
)]
[
WorkItem
(
37268
,
"https://github.com/dotnet/roslyn/issues/37268"
)]
public
async
Task
InRefAndQualifiedNestedGeneric3
()
{
var
markup
=
@"
using System;
class C
{
private protected ref Func<int, System.Func<$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InTuple0
()
{
var
markup
=
@"
using System;
class C
{
protected ($$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
TupleInMethod0
()
{
var
markup
=
@"
using System;
class C
{
void M()
{
($$
}
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
TupleInMethod1
()
{
var
markup
=
@"
using System;
class C
{
void M()
{
var a = 0;
($$
}
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
TupleInMethod2
()
{
var
markup
=
@"
using System;
class C
{
void M()
{
($$)
}
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
TupleInMethod3
()
{
var
markup
=
@"
using System;
class C
{
void M()
{
var a = 0;
(T$$)
a = 1;
}
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InTupleNot0
()
{
var
markup
=
@"
using System;
class C
{
protected sealed (int $$
}"
;
await
VerifyItemIsAbsentAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InTuple1
()
{
var
markup
=
@"
using System;
class C
{
sealed (int, $$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InTupleNot1
()
{
var
markup
=
@"
using System;
class C
{
virtual (int x, C $$
}"
;
await
VerifyItemIsAbsentAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InTupleGeneric0
()
{
var
markup
=
@"
using System;
class C
{
(Func<$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InTupleGeneric1
()
{
var
markup
=
@"
using System;
class C
{
(int, Func<$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InTupleGeneric2
()
{
var
markup
=
@"
using System;
class C
{
(int, Func<int, $$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InGenericTuple0
()
{
var
markup
=
@"
using System;
class C
{
Func<($$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InGenericTuple1
()
{
var
markup
=
@"
using System;
class C
{
Func<int, ($$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InGenericTuple1Not
()
{
var
markup
=
@"
using System;
class C
{
Func<int, (T $$
}"
;
await
VerifyItemIsAbsentAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InGenericTuple2
()
{
var
markup
=
@"
using System;
class C
{
Func<(int, $$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InGenericTuple2Not
()
{
var
markup
=
@"
using System;
class C
{
Func<(C c, int $$
}"
;
await
VerifyItemIsAbsentAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InGenericTuple3
()
{
var
markup
=
@"
using System;
class C
{
Func<int, (int,$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InGenericTuple3Not
()
{
var
markup
=
@"
using System;
class C
{
Func<C, (int, C $$
}"
;
await
VerifyItemIsAbsentAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InRefTupleQualifiedNestedGeneric0
()
{
var
markup
=
@"
using System;
class C
{
ref (Func<System.Func<int,$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InRefTupleQualifiedNestedGeneric1
()
{
var
markup
=
@"
using System;
class C
{
ref (C c, Func<System.Func<int,$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InRefTupleQualifiedNestedGeneric2
()
{
var
markup
=
@"
using System;
class C
{
ref (C c, Func<int, System.Func<(int,T$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InRefTupleQualifiedNestedGeneric3
()
{
var
markup
=
@"
using System;
class C
{
ref (C c, System.Func<Func<int,(T$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InRefTupleQualifiedNestedGeneric4
()
{
var
markup
=
@"
using System;
class C
{
ref (System.Func<(int,C), (Func<int,T$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InRefTupleQualifiedNestedGeneric5
()
{
var
markup
=
@"
using System;
class C
{
ref readonly (System.Func<(int, (C, (Func<int,T$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
[
WorkItem
(
37361
,
"https://github.com/dotnet/roslyn/issues/37361"
)]
public
async
Task
InRefTupleQualifiedNestedGeneric6
()
{
var
markup
=
@"
using System;
class C
{
ref readonly (System.Collections.Generic.List<(int, (C, (Func<int,T$$
}"
;
await
VerifyItemExistsAsync
(
markup
,
"T"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
public
async
Task
InNestedGeneric1
()
{
...
...
@@ -286,7 +868,7 @@ class Program
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
Completion
)]
public
async
Task
Not
AfterAsync
()
public
async
Task
Ok
AfterAsync
()
{
var
markup
=
@"
using System.Threading.Tasks;
...
...
@@ -295,7 +877,7 @@ class Program
async $$
}"
;
await
VerifyItem
IsAbsent
Async
(
markup
,
"T"
);
await
VerifyItem
Exists
Async
(
markup
,
"T"
);
}
[
WorkItem
(
968256
,
"http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/968256"
)]
...
...
@@ -384,7 +966,7 @@ public void M()
async $$
}
}"
;
await
VerifyItem
IsAbsent
Async
(
markup
,
"T"
);
await
VerifyItem
Exists
Async
(
markup
,
"T"
);
}
}
}
src/Features/CSharp/Portable/Completion/CompletionProviders/SpeculativeTCompletionProvider.cs
浏览文件 @
f42de27b
...
...
@@ -56,46 +56,94 @@ private async Task<bool> ShouldShowSpeculativeTCompletionItemAsync(Document docu
return
false
;
}
// If we're in a generic type argument context, use the start of the generic type name
// as the position for the rest of the context checks.
var
testPosition
=
position
;
var
leftToken
=
syntaxTree
.
FindTokenOnLeftOfPosition
(
position
,
cancellationToken
);
// We could be in the middle of a ref/generic/tuple type, instead of a simple T case.
// If we managed to walk out and get a different SpanStart, we treat it as a simple $$T case.
var
semanticModel
=
await
document
.
GetSemanticModelForNodeAsync
(
leftToken
.
Parent
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
syntaxTree
.
IsGenericTypeArgumentContext
(
position
,
leftToken
,
cancellationToken
,
semanticModel
))
var
token
=
syntaxTree
.
FindTokenOnLeftOfPosition
(
position
,
cancellationToken
);
var
semanticModel
=
await
document
.
GetSemanticModelForNodeAsync
(
token
.
Parent
,
cancellationToken
).
ConfigureAwait
(
false
);
var
spanStart
=
position
;
while
(
true
)
{
var
oldSpanStart
=
spanStart
;
spanStart
=
WalkOutOfGenericType
(
syntaxTree
,
spanStart
,
semanticModel
,
cancellationToken
);
spanStart
=
WalkOutOfTupleType
(
syntaxTree
,
spanStart
,
cancellationToken
);
spanStart
=
WalkOutOfRefType
(
syntaxTree
,
spanStart
,
cancellationToken
);
if
(
spanStart
==
oldSpanStart
)
{
break
;
}
}
return
IsStartOfSpeculativeTContext
(
syntaxTree
,
spanStart
,
cancellationToken
);
}
private
static
bool
IsStartOfSpeculativeTContext
(
SyntaxTree
syntaxTree
,
int
position
,
CancellationToken
cancellationToken
)
{
var
token
=
syntaxTree
.
FindTokenOnLeftOfPosition
(
position
,
cancellationToken
);
return
syntaxTree
.
IsMemberDeclarationContext
(
position
,
contextOpt
:
null
,
SyntaxKindSet
.
AllMemberModifiers
,
SyntaxKindSet
.
ClassInterfaceStructTypeDeclarations
,
canBePartial
:
true
,
cancellationToken
)
||
syntaxTree
.
IsStatementContext
(
position
,
token
,
cancellationToken
)
||
syntaxTree
.
IsGlobalMemberDeclarationContext
(
position
,
SyntaxKindSet
.
AllGlobalMemberModifiers
,
cancellationToken
)
||
syntaxTree
.
IsGlobalStatementContext
(
position
,
cancellationToken
)
||
syntaxTree
.
IsDelegateReturnTypeContext
(
position
,
token
,
cancellationToken
);
}
private
static
int
WalkOutOfGenericType
(
SyntaxTree
syntaxTree
,
int
position
,
SemanticModel
semanticModel
,
CancellationToken
cancellationToken
)
{
var
spanStart
=
position
;
var
token
=
syntaxTree
.
FindTokenOnLeftOfPosition
(
position
,
cancellationToken
);
if
(
syntaxTree
.
IsGenericTypeArgumentContext
(
position
,
token
,
cancellationToken
,
semanticModel
))
{
// Walk out until we find the start of the partial written generic
while
(
syntaxTree
.
IsInPartiallyWrittenGeneric
(
testPosition
,
cancellationToken
,
out
var
nameToken
))
if
(
syntaxTree
.
IsInPartiallyWrittenGeneric
(
spanStart
,
cancellationToken
,
out
var
nameToken
))
{
testPosition
=
nameToken
.
SpanStart
;
spanStart
=
nameToken
.
SpanStart
;
}
// If the user types Goo<T, automatic brace completion will insert the close brace
// and the generic won't be "partially written".
if
(
testPosition
==
position
)
if
(
spanStart
==
position
)
{
spanStart
=
token
.
GetAncestor
<
GenericNameSyntax
>()?.
SpanStart
??
spanStart
;
}
var
tokenLeftOfGenericName
=
syntaxTree
.
FindTokenOnLeftOfPosition
(
spanStart
,
cancellationToken
);
if
(
tokenLeftOfGenericName
.
IsKind
(
SyntaxKind
.
DotToken
)
&&
tokenLeftOfGenericName
.
Parent
.
IsKind
(
SyntaxKind
.
QualifiedName
))
{
var
typeArgumentList
=
leftToken
.
GetAncestor
<
TypeArgumentListSyntax
>();
if
(
typeArgumentList
!=
null
)
{
if
(
typeArgumentList
.
LessThanToken
!=
default
&&
typeArgumentList
.
GreaterThanToken
!=
default
)
{
testPosition
=
typeArgumentList
.
LessThanToken
.
SpanStart
;
}
}
spanStart
=
tokenLeftOfGenericName
.
Parent
.
SpanStart
;
}
}
if
((!
leftToken
.
GetPreviousTokenIfTouchingWord
(
position
).
IsKindOrHasMatchingText
(
SyntaxKind
.
AsyncKeyword
)
&&
syntaxTree
.
IsMemberDeclarationContext
(
testPosition
,
contextOpt
:
null
,
validModifiers
:
SyntaxKindSet
.
AllMemberModifiers
,
validTypeDeclarations
:
SyntaxKindSet
.
ClassInterfaceStructTypeDeclarations
,
canBePartial
:
false
,
cancellationToken
:
cancellationToken
))
||
syntaxTree
.
IsStatementContext
(
testPosition
,
leftToken
,
cancellationToken
)
||
syntaxTree
.
IsGlobalMemberDeclarationContext
(
testPosition
,
SyntaxKindSet
.
AllGlobalMemberModifiers
,
cancellationToken
)
||
syntaxTree
.
IsGlobalStatementContext
(
testPosition
,
cancellationToken
)
||
syntaxTree
.
IsDelegateReturnTypeContext
(
testPosition
,
syntaxTree
.
FindTokenOnLeftOfPosition
(
testPosition
,
cancellationToken
),
cancellationToken
))
return
spanStart
;
}
private
static
int
WalkOutOfRefType
(
SyntaxTree
syntaxTree
,
int
position
,
CancellationToken
cancellationToken
)
{
var
prevToken
=
syntaxTree
.
FindTokenOnLeftOfPosition
(
position
,
cancellationToken
)
.
GetPreviousTokenIfTouchingWord
(
position
);
if
(
prevToken
.
IsKind
(
SyntaxKind
.
RefKeyword
,
SyntaxKind
.
ReadOnlyKeyword
)
&&
prevToken
.
Parent
.
IsKind
(
SyntaxKind
.
RefType
))
{
return
prevToken
.
SpanStart
;
}
return
position
;
}
private
static
int
WalkOutOfTupleType
(
SyntaxTree
syntaxTree
,
int
position
,
CancellationToken
cancellationToken
)
{
var
prevToken
=
syntaxTree
.
FindTokenOnLeftOfPosition
(
position
,
cancellationToken
)
.
GetPreviousTokenIfTouchingWord
(
position
);
if
(
prevToken
.
IsPossibleTupleOpenParenOrComma
())
{
return
true
;
return
prevToken
.
Parent
.
SpanStart
;
}
return
false
;
return
position
;
}
}
}
src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs
浏览文件 @
f42de27b
...
...
@@ -1304,7 +1304,7 @@ private static SyntaxToken FindTokenOnLeftOfNode(SyntaxNode node)
}
public
static
bool
IsPossibleTupleOpenParenOrComma
(
SyntaxToken
possibleCommaOrParen
)
public
static
bool
IsPossibleTupleOpenParenOrComma
(
this
SyntaxToken
possibleCommaOrParen
)
{
if
(!
possibleCommaOrParen
.
IsKind
(
SyntaxKind
.
OpenParenToken
,
SyntaxKind
.
CommaToken
))
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录