Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
4f1a0cf0
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,发现更多精彩内容 >>
提交
4f1a0cf0
编写于
3月 16, 2020
作者:
C
Cyrus Najmabadi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Initial TODO work
上级
289aae87
变更
18
显示空白变更内容
内联
并排
Showing
18 changed file
with
761 addition
and
128 deletion
+761
-128
src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentTokens.cs
...ures/Core/Implementation/TodoComment/TodoCommentTokens.cs
+0
-35
src/Features/CSharp/Portable/TodoComments/CSharpTodoCommentIncrementalAnalyzerProvider.cs
...oComments/CSharpTodoCommentIncrementalAnalyzerProvider.cs
+12
-20
src/Features/Core/Portable/SolutionCrawler/IncrementalAnalyzerBase.cs
.../Core/Portable/SolutionCrawler/IncrementalAnalyzerBase.cs
+1
-1
src/Features/Core/Portable/TodoComments/AbstractTodoCommentService.cs
.../Core/Portable/TodoComments/AbstractTodoCommentService.cs
+23
-59
src/Features/Core/Portable/TodoComments/ITodoCommentService.cs
...eatures/Core/Portable/TodoComments/ITodoCommentService.cs
+31
-2
src/Features/VisualBasic/Portable/TodoComments/BasicTodoCommentIncrementalAnalyzerProvider.vb
...doComments/BasicTodoCommentIncrementalAnalyzerProvider.vb
+8
-7
src/VisualStudio/Core/Def/Implementation/TodoComments/ITodoCommentsService.cs
...e/Def/Implementation/TodoComments/ITodoCommentsService.cs
+23
-0
src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs
...mentation/TodoComments/VisualStudioTodoCommentsService.cs
+180
-0
src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsServiceFactory.cs
...on/TodoComments/VisualStudioTodoCommentsServiceFactory.cs
+34
-0
src/VisualStudio/Core/Def/RoslynPackage.cs
src/VisualStudio/Core/Def/RoslynPackage.cs
+5
-0
src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs
.../Core/Portable/TodoComments/IRemoteTodoCommentsService.cs
+20
-0
src/Workspaces/Core/Portable/TodoComments/ITodoCommentsServiceCallback.cs
...ore/Portable/TodoComments/ITodoCommentsServiceCallback.cs
+6
-4
src/Workspaces/Core/Portable/TodoComments/TodoCommentInfo.cs
src/Workspaces/Core/Portable/TodoComments/TodoCommentInfo.cs
+81
-0
src/Workspaces/Remote/ServiceHub/Services/TodoComments/DescriptorsInfo.cs
...emote/ServiceHub/Services/TodoComments/DescriptorsInfo.cs
+21
-0
src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs
...ces/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs
+152
-0
src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs
...Comments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs
+28
-0
src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer_Serialization.cs
...ts/RemoteTodoCommentsIncrementalAnalyzer_Serialization.cs
+91
-0
src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsService.cs
...iceHub/Services/TodoComments/RemoteTodoCommentsService.cs
+45
-0
未找到文件。
src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentTokens.cs
浏览文件 @
4f1a0cf0
...
...
@@ -24,41 +24,6 @@ public TodoCommentTokens()
{
}
private
ImmutableArray
<
TodoCommentDescriptor
>
Parse
(
string
data
)
{
if
(
string
.
IsNullOrWhiteSpace
(
data
))
{
return
ImmutableArray
<
TodoCommentDescriptor
>.
Empty
;
}
var
tuples
=
data
.
Split
(
'|'
);
var
result
=
new
List
<
TodoCommentDescriptor
>(
tuples
.
Length
);
foreach
(
var
tuple
in
tuples
)
{
if
(
string
.
IsNullOrWhiteSpace
(
tuple
))
{
continue
;
}
var
pair
=
tuple
.
Split
(
':'
);
if
(
pair
.
Length
!=
2
||
string
.
IsNullOrWhiteSpace
(
pair
[
0
]))
{
continue
;
}
if
(!
int
.
TryParse
(
pair
[
1
],
NumberStyles
.
None
,
CultureInfo
.
InvariantCulture
,
out
var
priority
))
{
continue
;
}
result
.
Add
(
new
TodoCommentDescriptor
(
pair
[
0
].
Trim
(),
priority
));
}
return
result
.
ToImmutableArray
();
}
private
class
TokenInfo
{
internal
readonly
string
OptionText
;
...
...
src/Features/CSharp/Portable/TodoComments/CSharpTodoCommentIncrementalAnalyzerProvider.cs
浏览文件 @
4f1a0cf0
...
...
@@ -3,11 +3,12 @@
// See the LICENSE file in the project root for more information.
using
System
;
using
System.Collections.
Generic
;
using
System.Collections.
Immutable
;
using
System.Composition
;
using
Microsoft.CodeAnalysis.CSharp.Extensions
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.CodeAnalysis.TodoComments
;
using
Roslyn.Utilities
;
...
...
@@ -22,7 +23,7 @@ public CSharpTodoCommentServiceFactory()
}
public
ILanguageService
CreateLanguageService
(
HostLanguageServices
languageServices
)
=>
new
CSharpTodoCommentService
(
languageServices
.
WorkspaceServices
.
Workspace
);
=>
new
CSharpTodoCommentService
();
}
internal
class
CSharpTodoCommentService
:
AbstractTodoCommentService
...
...
@@ -30,11 +31,10 @@ internal class CSharpTodoCommentService : AbstractTodoCommentService
private
static
readonly
int
s_multilineCommentPostfixLength
=
"*/"
.
Length
;
private
const
string
SingleLineCommentPrefix
=
"//"
;
public
CSharpTodoCommentService
(
Workspace
workspace
)
:
base
(
workspace
)
{
}
protected
override
void
AppendTodoComments
(
IList
<
TodoCommentDescriptor
>
commentDescriptors
,
SyntacticDocument
document
,
SyntaxTrivia
trivia
,
List
<
TodoComment
>
todoList
)
protected
override
void
AppendTodoComments
(
ImmutableArray
<
TodoCommentDescriptor
>
commentDescriptors
,
SyntacticDocument
document
,
SyntaxTrivia
trivia
,
ArrayBuilder
<
TodoComment
>
todoList
)
{
if
(
PreprocessorHasComment
(
trivia
))
{
...
...
@@ -43,7 +43,7 @@ protected override void AppendTodoComments(IList<TodoCommentDescriptor> commentD
var
index
=
message
.
IndexOf
(
SingleLineCommentPrefix
,
StringComparison
.
Ordinal
);
var
start
=
trivia
.
FullSpan
.
Start
+
index
;
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
document
,
message
.
Substring
(
index
),
start
,
todoList
);
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
message
.
Substring
(
index
),
start
,
todoList
);
return
;
}
...
...
@@ -63,14 +63,10 @@ protected override void AppendTodoComments(IList<TodoCommentDescriptor> commentD
}
protected
override
string
GetNormalizedText
(
string
message
)
{
return
message
;
}
=>
message
;
protected
override
bool
IsIdentifierCharacter
(
char
ch
)
{
return
SyntaxFacts
.
IsIdentifierPartCharacter
(
ch
);
}
=>
SyntaxFacts
.
IsIdentifierPartCharacter
(
ch
);
protected
override
int
GetCommentStartingIndex
(
string
message
)
{
...
...
@@ -94,13 +90,9 @@ protected override bool PreprocessorHasComment(SyntaxTrivia trivia)
}
protected
override
bool
IsSingleLineComment
(
SyntaxTrivia
trivia
)
{
return
trivia
.
IsSingleLineComment
()
||
trivia
.
IsSingleLineDocComment
();
}
=>
trivia
.
IsSingleLineComment
()
||
trivia
.
IsSingleLineDocComment
();
protected
override
bool
IsMultilineComment
(
SyntaxTrivia
trivia
)
{
return
trivia
.
IsMultiLineComment
()
||
trivia
.
IsMultiLineDocComment
();
}
=>
trivia
.
IsMultiLineComment
()
||
trivia
.
IsMultiLineDocComment
();
}
}
src/Features/Core/Portable/SolutionCrawler/IncrementalAnalyzerBase.cs
浏览文件 @
4f1a0cf0
...
...
@@ -34,7 +34,7 @@ public virtual Task DocumentResetAsync(Document document, CancellationToken canc
return
Task
.
CompletedTask
;
}
public
bool
NeedsReanalysisOnOptionChanged
(
object
sender
,
OptionChangedEventArgs
e
)
public
virtual
bool
NeedsReanalysisOnOptionChanged
(
object
sender
,
OptionChangedEventArgs
e
)
{
return
false
;
}
...
...
src/Features/Core/Portable/TodoComments/AbstractTodoCommentService.cs
浏览文件 @
4f1a0cf0
...
...
@@ -4,8 +4,10 @@
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.CodeAnalysis.Remote
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.Text
;
...
...
@@ -15,17 +17,6 @@ namespace Microsoft.CodeAnalysis.TodoComments
{
internal
abstract
class
AbstractTodoCommentService
:
ITodoCommentService
{
// we hold onto workspace to make sure given input (Document) belong to right workspace.
// since remote host is from workspace service, different workspace can have different expectation
// on remote host, so we need to make sure given input always belong to right workspace where
// the session belong to.
private
readonly
Workspace
_workspace
;
protected
AbstractTodoCommentService
(
Workspace
workspace
)
{
_workspace
=
workspace
;
}
protected
abstract
bool
PreprocessorHasComment
(
SyntaxTrivia
trivia
);
protected
abstract
bool
IsSingleLineComment
(
SyntaxTrivia
trivia
);
protected
abstract
bool
IsMultilineComment
(
SyntaxTrivia
trivia
);
...
...
@@ -33,42 +24,12 @@ protected AbstractTodoCommentService(Workspace workspace)
protected
abstract
string
GetNormalizedText
(
string
message
);
protected
abstract
int
GetCommentStartingIndex
(
string
message
);
protected
abstract
void
AppendTodoComments
(
IList
<
TodoCommentDescriptor
>
commentDescriptors
,
SyntacticDocument
document
,
SyntaxTrivia
trivia
,
List
<
TodoComment
>
todoList
);
public
async
Task
<
IList
<
TodoComment
>>
GetTodoCommentsAsync
(
Document
document
,
IList
<
TodoCommentDescriptor
>
commentDescriptors
,
CancellationToken
cancellationToken
)
{
// make sure given input is right one
Contract
.
ThrowIfFalse
(
_workspace
==
document
.
Project
.
Solution
.
Workspace
);
// run todo scanner on remote host.
// we only run closed files to make open document to have better responsiveness.
// also we cache everything related to open files anyway, no saving by running
// them in remote host
if
(!
document
.
IsOpen
())
{
var
client
=
await
RemoteHostClient
.
TryGetClientAsync
(
document
.
Project
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
client
!=
null
)
{
var
result
=
await
client
.
TryRunRemoteAsync
<
IList
<
TodoComment
>>(
WellKnownServiceHubServices
.
CodeAnalysisService
,
nameof
(
IRemoteTodoCommentService
.
GetTodoCommentsAsync
),
document
.
Project
.
Solution
,
new
object
[]
{
document
.
Id
,
commentDescriptors
},
callbackTarget
:
null
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
result
.
HasValue
)
{
return
result
.
Value
;
}
}
}
return
await
GetTodoCommentsInCurrentProcessAsync
(
document
,
commentDescriptors
,
cancellationToken
).
ConfigureAwait
(
false
);
}
protected
abstract
void
AppendTodoComments
(
ImmutableArray
<
TodoCommentDescriptor
>
commentDescriptors
,
SyntacticDocument
document
,
SyntaxTrivia
trivia
,
ArrayBuilder
<
TodoComment
>
todoList
);
private
async
Task
<
IList
<
TodoComment
>>
GetTodoCommentsInCurrentProcessAsync
(
Document
document
,
IList
<
TodoCommentDescriptor
>
commentDescriptors
,
CancellationToken
cancellationToken
)
public
async
Task
<
ImmutableArray
<
TodoComment
>>
GetTodoCommentsAsync
(
Document
document
,
ImmutableArray
<
TodoCommentDescriptor
>
commentDescriptors
,
CancellationToken
cancellationToken
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
...
...
@@ -76,29 +37,28 @@ public async Task<IList<TodoComment>> GetTodoCommentsAsync(Document document, IL
var
syntaxDoc
=
await
SyntacticDocument
.
CreateAsync
(
document
,
cancellationToken
).
ConfigureAwait
(
false
);
// reuse list
var
todoList
=
new
List
<
TodoComment
>(
);
using
var
_
=
ArrayBuilder
<
TodoComment
>.
GetInstance
(
out
var
todoList
);
foreach
(
var
trivia
in
syntaxDoc
.
Root
.
DescendantTrivia
())
{
cancellationToken
.
ThrowIfCancellationRequested
();
if
(!
ContainsComments
(
trivia
))
{
continue
;
}
AppendTodoComments
(
commentDescriptors
,
syntaxDoc
,
trivia
,
todoList
);
}
return
todoList
;
return
todoList
.
ToImmutable
()
;
}
private
bool
ContainsComments
(
SyntaxTrivia
trivia
)
{
return
PreprocessorHasComment
(
trivia
)
||
IsSingleLineComment
(
trivia
)
||
IsMultilineComment
(
trivia
);
}
=>
PreprocessorHasComment
(
trivia
)
||
IsSingleLineComment
(
trivia
)
||
IsMultilineComment
(
trivia
);
protected
void
AppendTodoCommentInfoFromSingleLine
(
IList
<
TodoCommentDescriptor
>
commentDescriptors
,
SyntacticDocument
document
,
string
message
,
int
start
,
List
<
TodoComment
>
todoList
)
protected
void
AppendTodoCommentInfoFromSingleLine
(
ImmutableArray
<
TodoCommentDescriptor
>
commentDescriptors
,
string
message
,
int
start
,
ArrayBuilder
<
TodoComment
>
todoList
)
{
var
index
=
GetCommentStartingIndex
(
message
);
if
(
index
>=
message
.
Length
)
...
...
@@ -130,7 +90,11 @@ protected void AppendTodoCommentInfoFromSingleLine(IList<TodoCommentDescriptor>
}
}
protected
void
ProcessMultilineComment
(
IList
<
TodoCommentDescriptor
>
commentDescriptors
,
SyntacticDocument
document
,
SyntaxTrivia
trivia
,
int
postfixLength
,
List
<
TodoComment
>
todoList
)
protected
void
ProcessMultilineComment
(
ImmutableArray
<
TodoCommentDescriptor
>
commentDescriptors
,
SyntacticDocument
document
,
SyntaxTrivia
trivia
,
int
postfixLength
,
ArrayBuilder
<
TodoComment
>
todoList
)
{
// this is okay since we know it is already alive
var
text
=
document
.
Text
;
...
...
@@ -145,20 +109,20 @@ protected void ProcessMultilineComment(IList<TodoCommentDescriptor> commentDescr
if
(
startLine
.
LineNumber
==
endLine
.
LineNumber
)
{
var
message
=
postfixLength
==
0
?
fullString
:
fullString
.
Substring
(
0
,
fullSpan
.
Length
-
postfixLength
);
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
document
,
message
,
fullSpan
.
Start
,
todoList
);
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
message
,
fullSpan
.
Start
,
todoList
);
return
;
}
// multiline
var
startMessage
=
text
.
ToString
(
TextSpan
.
FromBounds
(
fullSpan
.
Start
,
startLine
.
End
));
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
document
,
startMessage
,
fullSpan
.
Start
,
todoList
);
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
startMessage
,
fullSpan
.
Start
,
todoList
);
for
(
var
lineNumber
=
startLine
.
LineNumber
+
1
;
lineNumber
<
endLine
.
LineNumber
;
lineNumber
++)
{
var
line
=
text
.
Lines
[
lineNumber
];
var
message
=
line
.
ToString
();
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
document
,
message
,
line
.
Start
,
todoList
);
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
message
,
line
.
Start
,
todoList
);
}
var
length
=
fullSpan
.
End
-
endLine
.
Start
;
...
...
@@ -168,7 +132,7 @@ protected void ProcessMultilineComment(IList<TodoCommentDescriptor> commentDescr
}
var
endMessage
=
text
.
ToString
(
new
TextSpan
(
endLine
.
Start
,
length
));
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
document
,
endMessage
,
endLine
.
Start
,
todoList
);
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
endMessage
,
endLine
.
Start
,
todoList
);
}
}
}
src/Features/Core/Portable/TodoComments/ITodoCommentService.cs
浏览文件 @
4f1a0cf0
...
...
@@ -2,10 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Globalization
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.PooledObjects
;
namespace
Microsoft.CodeAnalysis.TodoComments
{
...
...
@@ -22,6 +24,33 @@ public TodoCommentDescriptor(string text, int priority) : this()
Text
=
text
;
Priority
=
priority
;
}
public
static
ImmutableArray
<
TodoCommentDescriptor
>
Parse
(
string
data
)
{
if
(
string
.
IsNullOrWhiteSpace
(
data
))
return
ImmutableArray
<
TodoCommentDescriptor
>.
Empty
;
var
tuples
=
data
.
Split
(
'|'
);
var
result
=
ArrayBuilder
<
TodoCommentDescriptor
>.
GetInstance
();
foreach
(
var
tuple
in
tuples
)
{
if
(
string
.
IsNullOrWhiteSpace
(
tuple
))
continue
;
var
pair
=
tuple
.
Split
(
':'
);
if
(
pair
.
Length
!=
2
||
string
.
IsNullOrWhiteSpace
(
pair
[
0
]))
continue
;
if
(!
int
.
TryParse
(
pair
[
1
],
NumberStyles
.
None
,
CultureInfo
.
InvariantCulture
,
out
var
priority
))
continue
;
result
.
Add
(
new
TodoCommentDescriptor
(
pair
[
0
].
Trim
(),
priority
));
}
return
result
.
ToImmutableAndFree
();
}
}
/// <summary>
...
...
@@ -43,6 +72,6 @@ public TodoComment(TodoCommentDescriptor descriptor, string message, int positio
internal
interface
ITodoCommentService
:
ILanguageService
{
Task
<
I
List
<
TodoComment
>>
GetTodoCommentsAsync
(
Document
document
,
IList
<
TodoCommentDescriptor
>
commentDescriptors
,
CancellationToken
cancellationToken
);
Task
<
I
mmutableArray
<
TodoComment
>>
GetTodoCommentsAsync
(
Document
document
,
ImmutableArray
<
TodoCommentDescriptor
>
commentDescriptors
,
CancellationToken
cancellationToken
);
}
}
src/Features/VisualBasic/Portable/TodoComments/BasicTodoCommentIncrementalAnalyzerProvider.vb
浏览文件 @
4f1a0cf0
...
...
@@ -7,6 +7,7 @@ Imports System.Composition
Imports
Microsoft.CodeAnalysis
Imports
Microsoft.CodeAnalysis.Host
Imports
Microsoft.CodeAnalysis.Host.Mef
Imports
Microsoft.CodeAnalysis.PooledObjects
Imports
Microsoft.CodeAnalysis.TodoComments
Namespace
Microsoft.CodeAnalysis.VisualBasic.TodoComments
...
...
@@ -19,7 +20,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.TodoComments
End
Sub
Public
Function
CreateLanguageService
(
languageServices
As
HostLanguageServices
)
As
ILanguageService
Implements
ILanguageServiceFactory
.
CreateLanguageService
Return
New
VisualBasicTodoCommentService
(
languageServices
.
WorkspaceServices
.
Workspace
)
Return
New
VisualBasicTodoCommentService
()
End
Function
End
Class
...
...
@@ -27,15 +28,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.TodoComments
Friend
Class
VisualBasicTodoCommentService
Inherits
AbstractTodoCommentService
P
ublic
Sub
New
(
workspace
As
Workspace
)
MyBase
.
New
(
workspace
)
End
Sub
Protected
Overrides
Sub
AppendTodoComments
(
commentDescriptors
As
IList
(
Of
TodoCommentDescriptor
),
document
As
SyntacticDocument
,
trivia
As
SyntaxTrivia
,
todoList
As
List
(
Of
TodoComment
))
P
rotected
Overrides
Sub
AppendTodoComments
(
commentDescriptors
As
ImmutableArray
(
Of
TodoCommentDescriptor
),
document
As
SyntacticDocument
,
trivia
As
SyntaxTrivia
,
todoList
As
ArrayBuilder
(
Of
TodoComment
))
If
PreprocessorHasComment
(
trivia
)
Then
Dim
commentTrivia
=
trivia
.
GetStructure
().
DescendantTrivia
().
First
(
Function
(
t
)
t
.
RawKind
=
SyntaxKind
.
CommentTrivia
)
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
document
,
commentTrivia
.
ToFullString
(),
commentTrivia
.
FullSpan
.
Start
,
todoList
)
AppendTodoCommentInfoFromSingleLine
(
commentDescriptors
,
commentTrivia
.
ToFullString
(),
commentTrivia
.
FullSpan
.
Start
,
todoList
)
Return
End
If
...
...
src/VisualStudio/Core/Def/Implementation/TodoComments/ITodoCommentsService.cs
0 → 100644
浏览文件 @
4f1a0cf0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System.Threading
;
using
Microsoft.CodeAnalysis.Host
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.TodoComments
{
/// <summary>
/// In process service responsible for listening to OOP todo comment notifications.
/// </summary>
internal
interface
ITodoCommentsService
:
IWorkspaceService
{
/// <summary>
/// Called by a host to let this service know that it should start background
/// analysis of the workspace to find todo comments
/// </summary>
void
Start
(
CancellationToken
cancellationToken
);
}
}
src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs
0 → 100644
浏览文件 @
4f1a0cf0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System
;
using
System.Collections.Immutable
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.Editor.Shared.Utilities
;
using
Microsoft.CodeAnalysis.ErrorReporting
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.CodeAnalysis.ProjectTelemetry
;
using
Microsoft.CodeAnalysis.Remote
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.Internal.VisualStudio.Shell
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
using
Roslyn.Utilities
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.TodoComments
{
internal
class
VisualStudioTodoCommentsService
:
ForegroundThreadAffinitizedObject
,
ITodoCommentsService
,
IProjectTelemetryServiceCallback
{
private
const
string
EventPrefix
=
"VS/Compilers/Compilation/"
;
private
const
string
PropertyPrefix
=
"VS.Compilers.Compilation.Inputs."
;
private
const
string
TelemetryEventPath
=
EventPrefix
+
"Inputs"
;
private
const
string
TelemetryExceptionEventPath
=
EventPrefix
+
"TelemetryUnhandledException"
;
private
const
string
TelemetryProjectIdName
=
PropertyPrefix
+
"ProjectId"
;
private
const
string
TelemetryProjectGuidName
=
PropertyPrefix
+
"ProjectGuid"
;
private
const
string
TelemetryLanguageName
=
PropertyPrefix
+
"Language"
;
private
const
string
TelemetryAnalyzerReferencesCountName
=
PropertyPrefix
+
"AnalyzerReferences.Count"
;
private
const
string
TelemetryProjectReferencesCountName
=
PropertyPrefix
+
"ProjectReferences.Count"
;
private
const
string
TelemetryMetadataReferencesCountName
=
PropertyPrefix
+
"MetadataReferences.Count"
;
private
const
string
TelemetryDocumentsCountName
=
PropertyPrefix
+
"Documents.Count"
;
private
const
string
TelemetryAdditionalDocumentsCountName
=
PropertyPrefix
+
"AdditionalDocuments.Count"
;
private
readonly
VisualStudioWorkspaceImpl
_workspace
;
/// <summary>
/// Our connections to the remote OOP server. Created on demand when we startup and then
/// kept around for the lifetime of this service.
/// </summary>
private
KeepAliveSession
?
_keepAliveSession
;
/// <summary>
/// Queue where we enqueue the information we get from OOP to process in batch in the future.
/// </summary>
private
AsyncBatchingWorkQueue
<
ProjectTelemetryInfo
>
_workQueue
=
null
!;
public
VisualStudioTodoCommentsService
(
VisualStudioWorkspaceImpl
workspace
,
IThreadingContext
threadingContext
)
:
base
(
threadingContext
)
=>
_workspace
=
workspace
;
void
ITodoCommentsService
.
Start
(
CancellationToken
cancellationToken
)
=>
_
=
StartAsync
(
cancellationToken
);
private
async
Task
StartAsync
(
CancellationToken
cancellationToken
)
{
// Have to catch all exceptions coming through here as this is called from a
// fire-and-forget method and we want to make sure nothing leaks out.
try
{
await
StartWorkerAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
}
catch
(
OperationCanceledException
)
{
// Cancellation is normal (during VS closing). Just ignore.
}
catch
(
Exception
e
)
when
(
FatalError
.
ReportWithoutCrash
(
e
))
{
// Otherwise report a watson for any other exception. Don't bring down VS. This is
// a BG service we don't want impacting the user experience.
}
}
private
async
Task
StartWorkerAsync
(
CancellationToken
cancellationToken
)
{
_workQueue
=
new
AsyncBatchingWorkQueue
<
ProjectTelemetryInfo
>(
TimeSpan
.
FromSeconds
(
1
),
NotifyTelemetryServiceAsync
,
cancellationToken
);
var
client
=
await
RemoteHostClient
.
TryGetClientAsync
(
_workspace
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
client
==
null
)
return
;
// Pass ourselves in as the callback target for the OOP service. As it discovers
// designer attributes it will call back into us to notify VS about it.
_keepAliveSession
=
await
client
.
TryCreateKeepAliveSessionAsync
(
WellKnownServiceHubServices
.
RemoteTodoCommentsService
,
callbackTarget
:
this
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
_keepAliveSession
==
null
)
return
;
// Now kick off scanning in the OOP process.
var
success
=
await
_keepAliveSession
.
TryInvokeAsync
(
nameof
(
IRemoteTodoCommentsService
.
ComputeTodoCommentsAsync
),
solution
:
null
,
arguments
:
Array
.
Empty
<
object
>(),
cancellationToken
).
ConfigureAwait
(
false
);
}
/// <summary>
/// Callback from the OOP service back into us.
/// </summary>
public
Task
RegisterProjectTelemetryInfoAsync
(
ProjectTelemetryInfo
info
,
CancellationToken
cancellationToken
)
{
_workQueue
.
AddWork
(
info
);
return
Task
.
CompletedTask
;
}
private
async
Task
NotifyTelemetryServiceAsync
(
ImmutableArray
<
ProjectTelemetryInfo
>
infos
,
CancellationToken
cancellationToken
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
using
var
_1
=
ArrayBuilder
<
ProjectTelemetryInfo
>.
GetInstance
(
out
var
filteredInfos
);
AddFilteredInfos
(
infos
,
filteredInfos
);
using
var
_2
=
ArrayBuilder
<
Task
>.
GetInstance
(
out
var
tasks
);
foreach
(
var
info
in
filteredInfos
)
tasks
.
Add
(
Task
.
Run
(()
=>
NotifyTelemetryService
(
info
),
cancellationToken
));
await
Task
.
WhenAll
(
tasks
).
ConfigureAwait
(
false
);
}
private
void
AddFilteredInfos
(
ImmutableArray
<
ProjectTelemetryInfo
>
infos
,
ArrayBuilder
<
ProjectTelemetryInfo
>
filteredInfos
)
{
using
var
_
=
PooledHashSet
<
ProjectId
>.
GetInstance
(
out
var
seenProjectIds
);
// Walk the list of telemetry items in reverse, and skip any items for a project once
// we've already seen it once. That way, we're only reporting the most up to date
// information for a project, and we're skipping the stale information.
for
(
var
i
=
infos
.
Length
-
1
;
i
>=
0
;
i
--)
{
var
info
=
infos
[
i
];
if
(
seenProjectIds
.
Add
(
info
.
ProjectId
))
filteredInfos
.
Add
(
info
);
}
}
private
void
NotifyTelemetryService
(
ProjectTelemetryInfo
info
)
{
try
{
var
telemetryEvent
=
TelemetryHelper
.
TelemetryService
.
CreateEvent
(
TelemetryEventPath
);
telemetryEvent
.
SetStringProperty
(
TelemetryProjectIdName
,
info
.
ProjectId
.
Id
.
ToString
());
telemetryEvent
.
SetStringProperty
(
TelemetryProjectGuidName
,
Guid
.
Empty
.
ToString
());
telemetryEvent
.
SetStringProperty
(
TelemetryLanguageName
,
info
.
Language
);
telemetryEvent
.
SetIntProperty
(
TelemetryAnalyzerReferencesCountName
,
info
.
AnalyzerReferencesCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryProjectReferencesCountName
,
info
.
ProjectReferencesCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryMetadataReferencesCountName
,
info
.
MetadataReferencesCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryDocumentsCountName
,
info
.
DocumentsCount
);
telemetryEvent
.
SetIntProperty
(
TelemetryAdditionalDocumentsCountName
,
info
.
AdditionalDocumentsCount
);
TelemetryHelper
.
DefaultTelemetrySession
.
PostEvent
(
telemetryEvent
);
}
catch
(
Exception
e
)
{
// The telemetry service itself can throw.
// So, to be very careful, put this in a try/catch too.
try
{
var
exceptionEvent
=
TelemetryHelper
.
TelemetryService
.
CreateEvent
(
TelemetryExceptionEventPath
);
exceptionEvent
.
SetStringProperty
(
"Type"
,
e
.
GetTypeDisplayName
());
exceptionEvent
.
SetStringProperty
(
"Message"
,
e
.
Message
);
exceptionEvent
.
SetStringProperty
(
"StackTrace"
,
e
.
StackTrace
);
TelemetryHelper
.
DefaultTelemetrySession
.
PostEvent
(
exceptionEvent
);
}
catch
{
}
}
}
}
}
src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsServiceFactory.cs
0 → 100644
浏览文件 @
4f1a0cf0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System
;
using
System.Composition
;
using
Microsoft.CodeAnalysis.Editor.Shared.Utilities
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.TodoComments
{
[
ExportWorkspaceServiceFactory
(
typeof
(
ITodoCommentsService
),
ServiceLayer
.
Host
),
Shared
]
internal
class
VisualStudioTodoCommentsServiceFactory
:
IWorkspaceServiceFactory
{
private
readonly
IThreadingContext
_threadingContext
;
[
ImportingConstructor
]
[
Obsolete
(
MefConstruction
.
ImportingConstructorMessage
,
error
:
true
)]
public
VisualStudioTodoCommentsServiceFactory
(
IThreadingContext
threadingContext
)
=>
_threadingContext
=
threadingContext
;
public
IWorkspaceService
?
CreateService
(
HostWorkspaceServices
workspaceServices
)
{
if
(!(
workspaceServices
.
Workspace
is
VisualStudioWorkspaceImpl
workspace
))
return
null
;
return
new
VisualStudioTodoCommentsService
(
workspace
,
_threadingContext
);
}
}
}
src/VisualStudio/Core/Def/RoslynPackage.cs
浏览文件 @
4f1a0cf0
...
...
@@ -29,6 +29,7 @@
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.RuleSets
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectTelemetry
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.TodoComments
;
using
Microsoft.VisualStudio.LanguageServices.Telemetry
;
using
Microsoft.VisualStudio.PlatformUI
;
using
Microsoft.VisualStudio.Shell
;
...
...
@@ -164,6 +165,10 @@ private async Task LoadComponentsBackgroundAsync(CancellationToken cancellationT
// Load the telemetry service and tell it to start watching the solution for project info.
var
projectTelemetryService
=
_workspace
.
Services
.
GetRequiredService
<
IProjectTelemetryService
>();
projectTelemetryService
.
Start
(
this
.
DisposalToken
);
// Load the todo comments service and tell it to start watching the solution for new comments
var
todoCommentsService
=
_workspace
.
Services
.
GetRequiredService
<
ITodoCommentsService
>();
todoCommentsService
.
Start
(
this
.
DisposalToken
);
}
private
async
Task
LoadInteractiveMenusAsync
(
CancellationToken
cancellationToken
)
...
...
src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs
0 → 100644
浏览文件 @
4f1a0cf0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System.Threading
;
using
System.Threading.Tasks
;
namespace
Microsoft.CodeAnalysis.ProjectTelemetry
{
/// <summary>
/// Interface to allow host (VS) to inform the OOP service to start incrementally analyzing and
/// reporting results back to the host.
/// </summary>
internal
interface
IRemoteTodoCommentsService
{
Task
ComputeTodoCommentsAsync
(
CancellationToken
cancellation
);
}
}
src/
Features/Core/Portable/TodoComments/IRemoteTodoCommentService
.cs
→
src/
Workspaces/Core/Portable/TodoComments/ITodoCommentsServiceCallback
.cs
浏览文件 @
4f1a0cf0
...
...
@@ -2,18 +2,20 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System.Collections.Generic
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Remote
;
namespace
Microsoft.CodeAnalysis.TodoComments
{
/// <summary>
/// interface exist to strongly type todo comment remote service
/// Callback the host (VS) passes to the OOP service to allow it to send batch notifications
/// about todo comments.
/// </summary>
internal
interface
I
RemoteTodoCommentService
internal
interface
I
TodoCommentsServiceCallback
{
Task
<
IList
<
TodoComment
>>
GetTodoCommentsAsync
(
PinnedSolutionInfo
solutionInfo
,
DocumentId
documentId
,
IList
<
TodoCommentDescriptor
>
commentDescriptor
s
,
CancellationToken
cancellationToken
);
Task
ReportTodoCommentsAsync
(
List
<
TodoCommentInfo
>
info
s
,
CancellationToken
cancellationToken
);
}
}
src/Workspaces/Core/Portable/TodoComments/TodoCommentInfo.cs
0 → 100644
浏览文件 @
4f1a0cf0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.TodoComments
{
/// <summary>
/// Serialization typed used to pass information to/from OOP and VS.
/// </summary>
internal
struct
TodoCommentInfo
{
public
int
Priority
;
public
string
Message
;
public
DocumentId
DocumentId
;
public
string
?
MappedFilePath
;
public
string
?
OriginalFilePath
;
public
int
MappedLine
;
public
int
MappedColumn
;
public
int
OriginalLine
;
public
int
OriginalColumn
;
public
override
bool
Equals
(
object
?
obj
)
=>
obj
is
TodoCommentInfo
other
&&
Equals
(
other
);
public
override
int
GetHashCode
()
=>
GetHashCode
(
this
);
public
override
string
ToString
()
=>
$"
{
Priority
}
{
Message
}
{
MappedFilePath
??
""
}
(
{
MappedLine
.
ToString
()}
,
{
MappedColumn
.
ToString
()}
) [original:
{
OriginalFilePath
??
""
}
(
{
OriginalLine
.
ToString
()}
,
{
OriginalColumn
.
ToString
()}
)"
;
public
bool
Equals
(
TodoCommentInfo
right
)
{
return
DocumentId
==
right
.
DocumentId
&&
Priority
==
right
.
Priority
&&
Message
==
right
.
Message
&&
OriginalLine
==
right
.
OriginalLine
&&
OriginalColumn
==
right
.
OriginalColumn
;
}
public
static
int
GetHashCode
(
TodoCommentInfo
item
)
=>
Hash
.
Combine
(
item
.
DocumentId
,
Hash
.
Combine
(
item
.
Priority
,
Hash
.
Combine
(
item
.
Message
,
Hash
.
Combine
(
item
.
OriginalLine
,
Hash
.
Combine
(
item
.
OriginalColumn
,
0
)))));
internal
void
WriteTo
(
ObjectWriter
writer
)
{
writer
.
WriteInt32
(
Priority
);
writer
.
WriteString
(
Message
);
DocumentId
.
WriteTo
(
writer
);
writer
.
WriteString
(
MappedFilePath
);
writer
.
WriteString
(
OriginalFilePath
);
writer
.
WriteInt32
(
MappedLine
);
writer
.
WriteInt32
(
MappedColumn
);
writer
.
WriteInt32
(
OriginalLine
);
writer
.
WriteInt32
(
OriginalColumn
);
}
internal
static
TodoCommentInfo
ReadFrom
(
ObjectReader
reader
)
{
return
new
TodoCommentInfo
{
Priority
=
reader
.
ReadInt32
(),
Message
=
reader
.
ReadString
(),
DocumentId
=
DocumentId
.
ReadFrom
(
reader
),
MappedFilePath
=
reader
.
ReadString
(),
OriginalFilePath
=
reader
.
ReadString
(),
MappedLine
=
reader
.
ReadInt32
(),
MappedColumn
=
reader
.
ReadInt32
(),
OriginalLine
=
reader
.
ReadInt32
(),
OriginalColumn
=
reader
.
ReadInt32
(),
};
}
}
}
src/Workspaces/Remote/ServiceHub/Services/TodoComments/DescriptorsInfo.cs
0 → 100644
浏览文件 @
4f1a0cf0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using
System.Collections.Immutable
;
using
Microsoft.CodeAnalysis.TodoComments
;
namespace
Microsoft.CodeAnalysis.Remote.Services.TodoComments
{
internal
class
DescriptorInfo
{
public
readonly
string
OptionText
;
public
readonly
ImmutableArray
<
TodoCommentDescriptor
>
Descriptors
;
public
DescriptorInfo
(
string
optionText
,
ImmutableArray
<
TodoCommentDescriptor
>
descriptors
)
{
this
.
OptionText
=
optionText
;
this
.
Descriptors
=
descriptors
;
}
}
}
src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs
0 → 100644
浏览文件 @
4f1a0cf0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.IO
;
using
System.Security.Cryptography
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Windows.Media.TextFormatting
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.Editor.Implementation.TodoComments
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.Options
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.CodeAnalysis.ProjectTelemetry
;
using
Microsoft.CodeAnalysis.Remote.Services.TodoComments
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
using
Microsoft.CodeAnalysis.Text
;
using
Microsoft.CodeAnalysis.TodoComments
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.Remote
{
internal
partial
class
RemoteTodoCommentsIncrementalAnalyzer
:
IncrementalAnalyzerBase
{
private
const
string
DataKey
=
"TodoComments"
;
/// <summary>
/// Channel back to VS to inform it of the designer attributes we discover.
/// </summary>
private
readonly
RemoteEndPoint
_endPoint
;
private
readonly
IPersistentStorageService
_storageService
;
private
readonly
object
_gate
=
new
object
();
private
DescriptorInfo
?
_lastDescriptorInfo
;
public
RemoteTodoCommentsIncrementalAnalyzer
(
Workspace
workspace
,
RemoteEndPoint
endPoint
)
{
_endPoint
=
endPoint
;
_storageService
=
workspace
.
Services
.
GetRequiredService
<
IPersistentStorageService
>();
}
public
override
bool
NeedsReanalysisOnOptionChanged
(
object
sender
,
OptionChangedEventArgs
e
)
=>
e
.
Option
==
TodoCommentOptions
.
TokenList
;
private
DescriptorInfo
GetDescriptorInfo
(
Document
document
)
{
var
optionText
=
document
.
Project
.
Solution
.
Options
.
GetOption
(
TodoCommentOptions
.
TokenList
);
lock
(
_gate
)
{
if
(
_lastDescriptorInfo
==
null
||
_lastDescriptorInfo
.
OptionText
!=
optionText
)
_lastDescriptorInfo
=
new
DescriptorInfo
(
optionText
,
TodoCommentDescriptor
.
Parse
(
optionText
));
return
_lastDescriptorInfo
;
}
}
public
override
async
Task
AnalyzeSyntaxAsync
(
Document
document
,
InvocationReasons
reasons
,
CancellationToken
cancellationToken
)
{
var
todoCommentService
=
document
.
GetLanguageService
<
ITodoCommentService
>();
if
(
todoCommentService
==
null
)
return
;
using
var
storage
=
_storageService
.
GetStorage
(
document
.
Project
.
Solution
);
var
version
=
await
document
.
GetSyntaxVersionAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
descriptorInfo
=
GetDescriptorInfo
(
document
);
var
persistedInfo
=
await
TryReadExistingCommentInfoAsync
(
storage
,
document
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
persistedInfo
!=
null
&&
persistedInfo
.
Version
==
version
&&
persistedInfo
.
OptionText
==
descriptorInfo
.
OptionText
)
{
// Our info for this file is up to date.
return
;
}
// We're out of date. Recompute this info.
var
todoComments
=
await
todoCommentService
.
GetTodoCommentsAsync
(
document
,
descriptorInfo
.
Descriptors
,
cancellationToken
).
ConfigureAwait
(
false
);
// Convert the roslyn-level results to the more VS oriented line/col data.
using
var
_
=
ArrayBuilder
<
TodoCommentInfo
>.
GetInstance
(
out
var
converted
);
await
ConvertAsync
(
document
,
todoComments
,
converted
,
cancellationToken
).
ConfigureAwait
(
false
);
// Now inform VS about this new information
await
_endPoint
.
InvokeAsync
(
nameof
(
ITodoCommentsServiceCallback
.
ReportTodoCommentsAsync
),
new
object
[]
{
converted
},
cancellationToken
).
ConfigureAwait
(
false
);
persistedInfo
=
new
PersistedTodoCommentInfo
{
Version
=
version
,
OptionText
=
descriptorInfo
.
OptionText
,
TodoComments
=
converted
.
ToImmutable
(),
};
// now that we've informed VS, save this information for the future.
await
PersistTodoCommentsAsync
(
storage
,
document
,
persistedInfo
,
cancellationToken
).
ConfigureAwait
(
false
);
}
private
async
Task
ConvertAsync
(
Document
document
,
ImmutableArray
<
TodoComment
>
todoComments
,
ArrayBuilder
<
TodoCommentInfo
>
converted
,
CancellationToken
cancellationToken
)
{
var
sourceText
=
await
document
.
GetTextAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
syntaxTree
=
await
document
.
GetRequiredSyntaxTreeAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
foreach
(
var
comment
in
todoComments
)
converted
.
Add
(
Convert
(
document
,
sourceText
,
syntaxTree
,
comment
));
}
private
TodoCommentInfo
Convert
(
Document
document
,
SourceText
text
,
SyntaxTree
tree
,
TodoComment
comment
)
{
// make sure given position is within valid text range.
var
textSpan
=
new
TextSpan
(
Math
.
Min
(
text
.
Length
,
Math
.
Max
(
0
,
comment
.
Position
)),
0
);
var
location
=
tree
.
GetLocation
(
textSpan
);
// var location = tree == null ? Location.Create(document.FilePath, textSpan, text.Lines.GetLinePositionSpan(textSpan)) : tree.GetLocation(textSpan);
var
originalLineInfo
=
location
.
GetLineSpan
();
var
mappedLineInfo
=
location
.
GetMappedLineSpan
();
return
new
TodoCommentInfo
{
Priority
=
comment
.
Descriptor
.
Priority
,
Message
=
comment
.
Message
,
DocumentId
=
document
.
Id
,
OriginalLine
=
originalLineInfo
.
StartLinePosition
.
Line
,
OriginalColumn
=
originalLineInfo
.
StartLinePosition
.
Character
,
OriginalFilePath
=
document
.
FilePath
,
MappedLine
=
mappedLineInfo
.
StartLinePosition
.
Line
,
MappedColumn
=
mappedLineInfo
.
StartLinePosition
.
Character
,
MappedFilePath
=
mappedLineInfo
.
GetMappedFilePathIfExist
(),
};
}
}
}
src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs
0 → 100644
浏览文件 @
4f1a0cf0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
Microsoft.CodeAnalysis.SolutionCrawler
;
namespace
Microsoft.CodeAnalysis.Remote
{
/// <remarks>Note: this is explicitly <b>not</b> exported. We don't want the <see
/// cref="RemoteWorkspace"/> to automatically load this. Instead, VS waits until it is ready
/// and then calls into OOP to tell it to start analyzing the solution. At that point we'll get
/// created and added to the solution crawler.
/// </remarks>
internal
class
RemoteTodoCommentsIncrementalAnalyzerProvider
:
IIncrementalAnalyzerProvider
{
private
readonly
RemoteEndPoint
_endPoint
;
public
RemoteTodoCommentsIncrementalAnalyzerProvider
(
RemoteEndPoint
endPoint
)
{
_endPoint
=
endPoint
;
}
public
IIncrementalAnalyzer
CreateIncrementalAnalyzer
(
Workspace
workspace
)
=>
new
RemoteTodoCommentsIncrementalAnalyzer
(
_endPoint
);
}
}
src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer_Serialization.cs
0 → 100644
浏览文件 @
4f1a0cf0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System.Collections.Immutable
;
using
System.IO
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.CodeAnalysis.TodoComments
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.Remote
{
internal
partial
class
RemoteTodoCommentsIncrementalAnalyzer
{
private
const
string
SerializationFormat
=
"1"
;
private
async
Task
<
PersistedTodoCommentInfo
?>
TryReadExistingCommentInfoAsync
(
IPersistentStorage
storage
,
Document
document
,
CancellationToken
cancellationToken
)
{
using
var
stream
=
await
storage
.
ReadStreamAsync
(
document
,
DataKey
,
cancellationToken
).
ConfigureAwait
(
false
);
using
var
reader
=
ObjectReader
.
TryGetReader
(
stream
,
cancellationToken
:
cancellationToken
);
return
TryReadPersistedInfo
(
reader
);
}
private
async
Task
PersistTodoCommentsAsync
(
IPersistentStorage
storage
,
Document
document
,
PersistedTodoCommentInfo
info
,
CancellationToken
cancellationToken
)
{
using
var
memoryStream
=
new
MemoryStream
();
using
var
writer
=
new
ObjectWriter
(
memoryStream
);
writer
.
WriteString
(
SerializationFormat
);
info
.
Version
.
WriteTo
(
writer
);
writer
.
WriteString
(
info
.
OptionText
);
writer
.
WriteInt32
(
info
.
TodoComments
.
Length
);
foreach
(
var
comment
in
info
.
TodoComments
)
comment
.
WriteTo
(
writer
);
memoryStream
.
Position
=
0
;
await
storage
.
WriteStreamAsync
(
document
,
DataKey
,
memoryStream
,
cancellationToken
).
ConfigureAwait
(
false
);
}
private
static
PersistedTodoCommentInfo
?
TryReadPersistedInfo
(
ObjectReader
reader
)
{
if
(
reader
==
null
)
return
null
;
try
{
var
serializationFormat
=
reader
.
ReadString
();
if
(
serializationFormat
!=
SerializationFormat
)
return
null
;
var
version
=
VersionStamp
.
ReadFrom
(
reader
);
var
optionText
=
reader
.
ReadString
();
var
count
=
reader
.
ReadInt32
();
using
var
_
=
ArrayBuilder
<
TodoCommentInfo
>.
GetInstance
(
out
var
comments
);
for
(
int
i
=
0
;
i
<
count
;
i
++)
comments
.
Add
(
TodoCommentInfo
.
ReadFrom
(
reader
));
return
new
PersistedTodoCommentInfo
{
Version
=
version
,
OptionText
=
optionText
,
TodoComments
=
comments
.
ToImmutable
(),
};
}
catch
{
}
return
null
;
}
private
class
PersistedTodoCommentInfo
{
public
VersionStamp
Version
;
public
string
?
OptionText
;
public
ImmutableArray
<
TodoCommentInfo
>
TodoComments
;
}
}
}
src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsService.cs
0 → 100644
浏览文件 @
4f1a0cf0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#
nullable
enable
using
System
;
using
System.IO
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.ProjectTelemetry
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
namespace
Microsoft.CodeAnalysis.Remote
{
internal
partial
class
RemoteTodoCommentsService
:
ServiceBase
,
IRemoteTodoCommentsService
{
public
RemoteTodoCommentsService
(
Stream
stream
,
IServiceProvider
serviceProvider
)
:
base
(
serviceProvider
,
stream
)
{
StartService
();
}
public
Task
ComputeTodoCommentsAsync
(
CancellationToken
cancellation
)
{
return
RunServiceAsync
(()
=>
{
var
workspace
=
SolutionService
.
PrimaryWorkspace
;
var
endpoint
=
this
.
EndPoint
;
var
registrationService
=
workspace
.
Services
.
GetRequiredService
<
ISolutionCrawlerRegistrationService
>();
var
analyzerProvider
=
new
RemoteTodoCommentsIncrementalAnalyzerProvider
(
endpoint
);
registrationService
.
AddAnalyzerProvider
(
analyzerProvider
,
new
IncrementalAnalyzerProviderMetadata
(
nameof
(
RemoteTodoCommentsIncrementalAnalyzerProvider
),
highPriorityForActiveFile
:
false
,
workspaceKinds
:
WorkspaceKind
.
RemoteWorkspace
));
return
Task
.
CompletedTask
;
},
cancellation
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录