Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
3d0c9cd1
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,发现更多精彩内容 >>
提交
3d0c9cd1
编写于
7月 29, 2020
作者:
M
Manish Vasani
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Address feedback
上级
dd1d514c
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
127 addition
and
126 deletion
+127
-126
src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs
.../Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs
+1
-1
src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs
...res/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs
+2
-2
src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs
...icIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs
+10
-15
src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs
...ble/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs
+2
-1
src/Workspaces/Core/Portable/Diagnostics/Extensions.cs
src/Workspaces/Core/Portable/Diagnostics/Extensions.cs
+17
-17
src/Workspaces/Remote/Core/Diagnostics/DiagnosticComputer.cs
src/Workspaces/Remote/Core/Diagnostics/DiagnosticComputer.cs
+95
-90
未找到文件。
src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs
浏览文件 @
3d0c9cd1
...
...
@@ -147,7 +147,7 @@ private async Task AnalyzeForKindAsync(TextDocument document, AnalysisKind kind,
///
/// The intended audience for this API is for ones that pefer simplicity over performance such as document that belong to misc project.
/// this doesn't cache nor use cache for anything. it will re-caculate new diagnostics every time for the given document.
/// it will not persist any data on disk nor use OOP to calcuate the data.
/// it will not persist any data on disk nor use OOP to calcu
l
ate the data.
///
/// This should never be used when performance is a big concern. for such context, use much complex API from IDiagnosticAnalyzerService
/// that provide all kinds of knobs/cache/persistency/OOP to get better perf over simplicity.
...
...
src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs
浏览文件 @
3d0c9cd1
...
...
@@ -121,7 +121,7 @@ public async Task<IEnumerable<DiagnosticData>> ComputeDiagnosticsAsync(Diagnosti
}
}
if
(
document
==
null
&&
!(
textDocument
is
AdditionalDocument
)
)
if
(
document
==
null
&&
textDocument
is
not
AdditionalDocument
)
{
// We currently support document analysis only for source documents and additional documents.
return
SpecializedCollections
.
EmptyEnumerable
<
DiagnosticData
>();
...
...
@@ -182,7 +182,7 @@ private async Task<ImmutableArray<DiagnosticData>> GetSyntaxDiagnosticsAsync(Dia
if
(
isCompilerAnalyzer
)
{
if
(
!(
AnalysisScope
.
TextDocument
is
Document
)
)
if
(
AnalysisScope
.
TextDocument
is
not
Document
)
{
return
ImmutableArray
<
DiagnosticData
>.
Empty
;
}
...
...
src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs
浏览文件 @
3d0c9cd1
...
...
@@ -74,19 +74,15 @@ internal class InProcOrRemoteHostAnalyzerRunner
{
Contract
.
ThrowIfFalse
(!
compilationWithAnalyzers
.
Analyzers
.
IsEmpty
);
var
workspace
=
project
.
Solution
.
Workspace
;
if
(
workspace
.
Services
.
GetService
<
IRemoteHostClientProvider
>()
is
{
}
service
&&
await
service
.
TryGetRemoteHostClientAsync
(
cancellationToken
).
ConfigureAwait
(
false
)
is
{
}
remoteHostClient
)
var
remoteHostClient
=
await
RemoteHostClient
.
TryGetClientAsync
(
project
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
remoteHostClient
!=
null
)
{
return
await
AnalyzeOutOfProcAsync
(
documentAnalysisScope
,
project
,
compilationWithAnalyzers
,
remoteHostClient
,
forceExecuteAllAnalyzers
,
logPerformanceInfo
,
getTelemetryInfo
,
cancellationToken
).
ConfigureAwait
(
false
);
}
// We need to execute InProc due to one of the following reasons:
// 1. The host doesn't support RemoteHostService (such as under unit test) OR
// 2. Remote host is not running (this can happen if remote host is disabled).
return
await
AnalyzeInProcAsync
(
documentAnalysisScope
,
project
,
compilationWithAnalyzers
,
client
:
null
,
logPerformanceInfo
,
getTelemetryInfo
,
cancellationToken
).
ConfigureAwait
(
false
);
client
:
null
,
logPerformanceInfo
,
getTelemetryInfo
,
cancellationToken
).
ConfigureAwait
(
false
);
}
}
...
...
@@ -115,9 +111,10 @@ await service.TryGetRemoteHostClientAsync(cancellationToken).ConfigureAwait(fals
var
skippedAnalyzersInfo
=
project
.
GetSkippedAnalyzersInfo
(
AnalyzerInfoCache
);
// get compiler result builder map
var
builderMap
=
a
nalysisResult
.
ToResultBuilderMap
(
var
builderMap
=
a
wait
analysisResult
.
ToResultBuilderMapAsync
(
additionalPragmaSuppressionDiagnostics
,
documentAnalysisScope
,
project
,
version
,
compilationWithAnalyzers
.
Compilation
,
analyzers
,
skippedAnalyzersInfo
,
compilationWithAnalyzers
.
AnalysisOptions
.
ReportSuppressedDiagnostics
,
cancellationToken
);
compilationWithAnalyzers
.
Compilation
,
analyzers
,
skippedAnalyzersInfo
,
compilationWithAnalyzers
.
AnalysisOptions
.
ReportSuppressedDiagnostics
,
cancellationToken
).
ConfigureAwait
(
false
);
var
result
=
builderMap
.
ToImmutableDictionary
(
kv
=>
kv
.
Key
,
kv
=>
DiagnosticAnalysisResult
.
CreateFromBuilder
(
kv
.
Value
));
var
telemetry
=
getTelemetryInfo
...
...
@@ -140,16 +137,14 @@ await service.TryGetRemoteHostClientAsync(cancellationToken).ConfigureAwait(fals
try
{
// +1 for project itself
var
count
=
documentAnalysisScope
!=
null
?
1
:
project
.
DocumentIds
.
Count
+
1
;
await
client
.
RunRemoteAsync
(
WellKnownServiceHubService
.
CodeAnalysis
,
nameof
(
IRemoteDiagnosticAnalyzerService
.
ReportAnalyzerPerformance
),
solution
:
null
,
new
object
[]
{
analysisResult
.
AnalyzerTelemetryInfo
.
ToAnalyzerPerformanceInfo
(
AnalyzerInfoCache
),
// +1 for project itself
documentAnalysisScope
!=
null
?
1
:
project
.
DocumentIds
.
Count
+
1
},
new
object
[]
{
analysisResult
.
AnalyzerTelemetryInfo
.
ToAnalyzerPerformanceInfo
(
AnalyzerInfoCache
),
count
},
callbackTarget
:
null
,
cancellationToken
).
ConfigureAwait
(
false
);
}
...
...
src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs
浏览文件 @
3d0c9cd1
...
...
@@ -40,7 +40,6 @@ internal partial class DiagnosticIncrementalAnalyzer : IIncrementalAnalyzer2
internal
DiagnosticAnalyzerService
AnalyzerService
{
get
;
}
internal
Workspace
Workspace
{
get
;
}
internal
IPersistentStorageService
PersistentStorageService
{
get
;
}
internal
DiagnosticAnalyzerInfoCache
DiagnosticAnalyzerInfoCache
=>
_diagnosticAnalyzerRunner
.
AnalyzerInfoCache
;
public
DiagnosticIncrementalAnalyzer
(
DiagnosticAnalyzerService
analyzerService
,
...
...
@@ -64,6 +63,8 @@ internal partial class DiagnosticIncrementalAnalyzer : IIncrementalAnalyzer2
_projectCompilationsWithAnalyzers
=
new
ConditionalWeakTable
<
Project
,
CompilationWithAnalyzers
?>();
}
internal
DiagnosticAnalyzerInfoCache
DiagnosticAnalyzerInfoCache
=>
_diagnosticAnalyzerRunner
.
AnalyzerInfoCache
;
public
bool
IsCompilationEndAnalyzer
(
DiagnosticAnalyzer
diagnosticAnalyzer
,
Project
project
,
Compilation
compilation
)
=>
DiagnosticAnalyzerInfoCache
.
IsCompilationEndAnalyzer
(
diagnosticAnalyzer
,
project
,
compilation
)
==
true
;
...
...
src/Workspaces/Core/Portable/Diagnostics/Extensions.cs
浏览文件 @
3d0c9cd1
...
...
@@ -132,7 +132,7 @@ private static string GetAssemblyQualifiedName(Type type)
return
type
.
AssemblyQualifiedName
??
throw
ExceptionUtilities
.
UnexpectedValue
(
type
);
}
public
static
ImmutableDictionary
<
DiagnosticAnalyzer
,
DiagnosticAnalysisResultBuilder
>
ToResultBuilderMap
(
public
static
async
Task
<
ImmutableDictionary
<
DiagnosticAnalyzer
,
DiagnosticAnalysisResultBuilder
>>
ToResultBuilderMapAsync
(
this
AnalysisResult
analysisResult
,
ImmutableArray
<
Diagnostic
>
additionalPragmaSuppressionDiagnostics
,
DocumentAnalysisScope
?
documentAnalysisScope
,
...
...
@@ -144,17 +144,17 @@ private static string GetAssemblyQualifiedName(Type type)
bool
includeSuppressedDiagnostics
,
CancellationToken
cancellationToken
)
{
SyntaxTree
?
filterTre
e
=
null
;
AdditionalText
?
filterAdditionalFil
e
=
null
;
SyntaxTree
?
treeToAnalyz
e
=
null
;
AdditionalText
?
additionalFileToAnalyz
e
=
null
;
if
(
documentAnalysisScope
!=
null
)
{
if
(
documentAnalysisScope
.
TextDocument
is
Document
document
)
{
filterTree
=
document
.
GetSyntaxTreeSynchronously
(
cancellationToken
);
treeToAnalyze
=
await
document
.
GetSyntaxTreeAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
}
else
{
filterAdditionalFil
e
=
documentAnalysisScope
.
AdditionalFile
;
additionalFileToAnalyz
e
=
documentAnalysisScope
.
AdditionalFile
;
}
}
...
...
@@ -175,35 +175,35 @@ private static string GetAssemblyQualifiedName(Type type)
if
(
documentAnalysisScope
!=
null
)
{
RoslynDebug
.
Assert
(
filterTree
!=
null
||
filterAdditionalFil
e
!=
null
);
var
filterSpan
=
documentAnalysisScope
.
Span
;
RoslynDebug
.
Assert
(
treeToAnalyze
!=
null
||
additionalFileToAnalyz
e
!=
null
);
var
spanToAnalyze
=
documentAnalysisScope
.
Span
;
var
kind
=
documentAnalysisScope
.
Kind
;
ImmutableDictionary
<
DiagnosticAnalyzer
,
ImmutableArray
<
Diagnostic
>>?
diagnosticsByAnalyzerMap
;
switch
(
kind
)
{
case
AnalysisKind
.
Syntax
:
if
(
filterTre
e
!=
null
)
if
(
treeToAnalyz
e
!=
null
)
{
if
(
analysisResult
.
SyntaxDiagnostics
.
TryGetValue
(
filterTre
e
,
out
diagnosticsByAnalyzerMap
))
if
(
analysisResult
.
SyntaxDiagnostics
.
TryGetValue
(
treeToAnalyz
e
,
out
diagnosticsByAnalyzerMap
))
{
AddAnalyzerDiagnosticsToResult
(
analyzer
,
diagnosticsByAnalyzerMap
,
ref
result
,
compilation
,
filterTree
,
additionalDocumentId
:
null
,
filterSpan
,
AnalysisKind
.
Syntax
,
diagnosticIdsToFilter
,
includeSuppressedDiagnostics
);
treeToAnalyze
,
additionalDocumentId
:
null
,
spanToAnalyze
,
AnalysisKind
.
Syntax
,
diagnosticIdsToFilter
,
includeSuppressedDiagnostics
);
}
}
else
if
(
analysisResult
.
AdditionalFileDiagnostics
.
TryGetValue
(
filterAdditionalFil
e
!,
out
diagnosticsByAnalyzerMap
))
else
if
(
analysisResult
.
AdditionalFileDiagnostics
.
TryGetValue
(
additionalFileToAnalyz
e
!,
out
diagnosticsByAnalyzerMap
))
{
AddAnalyzerDiagnosticsToResult
(
analyzer
,
diagnosticsByAnalyzerMap
,
ref
result
,
compilation
,
tree
:
null
,
documentAnalysisScope
.
TextDocument
.
Id
,
filterSpan
,
AnalysisKind
.
Syntax
,
diagnosticIdsToFilter
,
includeSuppressedDiagnostics
);
tree
:
null
,
documentAnalysisScope
.
TextDocument
.
Id
,
spanToAnalyze
,
AnalysisKind
.
Syntax
,
diagnosticIdsToFilter
,
includeSuppressedDiagnostics
);
}
break
;
case
AnalysisKind
.
Semantic
:
if
(
analysisResult
.
SemanticDiagnostics
.
TryGetValue
(
filterTre
e
!,
out
diagnosticsByAnalyzerMap
))
if
(
analysisResult
.
SemanticDiagnostics
.
TryGetValue
(
treeToAnalyz
e
!,
out
diagnosticsByAnalyzerMap
))
{
AddAnalyzerDiagnosticsToResult
(
analyzer
,
diagnosticsByAnalyzerMap
,
ref
result
,
compilation
,
filterTree
,
additionalDocumentId
:
null
,
filterSpan
,
AnalysisKind
.
Semantic
,
diagnosticIdsToFilter
,
includeSuppressedDiagnostics
);
treeToAnalyze
,
additionalDocumentId
:
null
,
spanToAnalyze
,
AnalysisKind
.
Semantic
,
diagnosticIdsToFilter
,
includeSuppressedDiagnostics
);
}
break
;
...
...
@@ -244,10 +244,10 @@ private static string GetAssemblyQualifiedName(Type type)
{
if
(
documentAnalysisScope
!=
null
)
{
if
(
filterTre
e
!=
null
)
if
(
treeToAnalyz
e
!=
null
)
{
var
diagnostics
=
additionalPragmaSuppressionDiagnostics
.
WhereAsArray
(
d
=>
d
.
Location
.
SourceTree
==
filterTre
e
);
AddDiagnosticsToResult
(
diagnostics
,
ref
result
,
compilation
,
filterTre
e
,
additionalDocumentId
:
null
,
var
diagnostics
=
additionalPragmaSuppressionDiagnostics
.
WhereAsArray
(
d
=>
d
.
Location
.
SourceTree
==
treeToAnalyz
e
);
AddDiagnosticsToResult
(
diagnostics
,
ref
result
,
compilation
,
treeToAnalyz
e
,
additionalDocumentId
:
null
,
documentAnalysisScope
!.
Span
,
AnalysisKind
.
Semantic
,
diagnosticIdsToFilter
,
includeSuppressedDiagnostics
);
}
}
...
...
src/Workspaces/Remote/Core/Diagnostics/DiagnosticComputer.cs
浏览文件 @
3d0c9cd1
...
...
@@ -24,6 +24,19 @@ namespace Microsoft.CodeAnalysis.Remote.Diagnostics
{
internal
class
DiagnosticComputer
{
/// <summary>
/// Cache of <see cref="CompilationWithAnalyzers"/> and a map from analyzer IDs to <see cref="DiagnosticAnalyzer"/>s
/// for all analyzers for each project.
/// The <see cref="CompilationWithAnalyzers"/> instance is shared between all the following document analyses modes for the project:
/// 1. Span-based analysis for active document (lightbulb)
/// 2. Background analysis for active and open documents.
///
/// NOTE: We do not re-use this cache for project analysis as it leads to significant memory increase in the OOP process,
/// and CWT does not seem to drop entries until ForceGC happens.
/// </summary>
private
static
readonly
ConditionalWeakTable
<
Project
,
CompilationWithAnalyzersCacheEntry
>
s_compilationWithAnalyzersCache
=
new
ConditionalWeakTable
<
Project
,
CompilationWithAnalyzersCacheEntry
>();
private
readonly
TextDocument
?
_document
;
private
readonly
Project
_project
;
private
readonly
TextSpan
?
_span
;
...
...
@@ -55,10 +68,10 @@ internal class DiagnosticComputer
bool
getTelemetryInfo
,
CancellationToken
cancellationToken
)
{
var
compilationWithAnalyzersData
=
await
CompilationWithAnalyzersData
.
GetOrCreate
Async
(
var
(
compilationWithAnalyzers
,
analyzerToIdMap
)
=
await
GetOrCreateCompilationWithAnalyzers
Async
(
_project
,
isDocumentAnalysis
:
_document
!=
null
,
cancellationToken
).
ConfigureAwait
(
false
);
var
analyzers
=
GetAnalyzers
(
compilationWithAnalyzersData
.
A
nalyzerToIdMap
,
analyzerIds
);
var
analyzers
=
GetAnalyzers
(
a
nalyzerToIdMap
,
analyzerIds
);
if
(
analyzers
.
IsEmpty
)
{
return
DiagnosticAnalysisResultMap
<
string
,
DiagnosticAnalysisResultBuilder
>.
Empty
;
...
...
@@ -67,12 +80,13 @@ internal class DiagnosticComputer
var
cacheService
=
_project
.
Solution
.
Workspace
.
Services
.
GetRequiredService
<
IProjectCacheService
>();
using
var
cache
=
cacheService
.
EnableCaching
(
_project
.
Id
);
var
skippedAnalyzersInfo
=
_project
.
GetSkippedAnalyzersInfo
(
_analyzerInfoCache
);
return
await
AnalyzeAsync
(
compilationWithAnalyzers
Data
,
analyzers
,
skippedAnalyzersInfo
,
return
await
AnalyzeAsync
(
compilationWithAnalyzers
,
analyzerToIdMap
,
analyzers
,
skippedAnalyzersInfo
,
reportSuppressedDiagnostics
,
logPerformanceInfo
,
getTelemetryInfo
,
cancellationToken
).
ConfigureAwait
(
false
);
}
private
async
Task
<
DiagnosticAnalysisResultMap
<
string
,
DiagnosticAnalysisResultBuilder
>>
AnalyzeAsync
(
CompilationWithAnalyzersData
compilationWithAnalyzersData
,
CompilationWithAnalyzers
compilationWithAnalyzers
,
BidirectionalMap
<
string
,
DiagnosticAnalyzer
>
analyzerToIdMap
,
ImmutableArray
<
DiagnosticAnalyzer
>
analyzers
,
SkippedHostAnalyzersInfo
skippedAnalyzersInfo
,
bool
reportSuppressedDiagnostics
,
...
...
@@ -80,7 +94,6 @@ internal class DiagnosticComputer
bool
getTelemetryInfo
,
CancellationToken
cancellationToken
)
{
var
compilationWithAnalyzers
=
compilationWithAnalyzersData
.
CompilationWithAnalyzers
;
var
documentAnalysisScope
=
_document
!=
null
?
new
DocumentAnalysisScope
(
_document
,
_span
,
analyzers
,
_analysisKind
!.
Value
)
:
null
;
...
...
@@ -96,12 +109,11 @@ internal class DiagnosticComputer
_performanceTracker
.
AddSnapshot
(
analysisResult
.
AnalyzerTelemetryInfo
.
ToAnalyzerPerformanceInfo
(
_analyzerInfoCache
),
unitCount
);
}
var
builderMap
=
a
nalysisResult
.
ToResultBuilderMap
(
var
builderMap
=
a
wait
analysisResult
.
ToResultBuilderMapAsync
(
additionalPragmaSuppressionDiagnostics
,
documentAnalysisScope
,
_project
,
VersionStamp
.
Default
,
compilationWithAnalyzers
.
Compilation
,
analyzers
,
skippedAnalyzersInfo
,
reportSuppressedDiagnostics
,
cancellationToken
);
analyzers
,
skippedAnalyzersInfo
,
reportSuppressedDiagnostics
,
cancellationToken
)
.
ConfigureAwait
(
false
)
;
var
analyzerToIdMap
=
compilationWithAnalyzersData
.
AnalyzerToIdMap
;
var
result
=
builderMap
.
ToImmutableDictionary
(
kv
=>
GetAnalyzerId
(
analyzerToIdMap
,
kv
.
Key
),
kv
=>
kv
.
Value
);
var
telemetry
=
getTelemetryInfo
?
GetTelemetryInfo
(
analysisResult
,
analyzers
,
analyzerToIdMap
)
...
...
@@ -165,108 +177,101 @@ private static ImmutableArray<DiagnosticAnalyzer> GetAnalyzers(BidirectionalMap<
return
builder
.
ToImmutable
();
}
private
sealed
class
CompilationWithAnalyzersData
private
static
async
Task
<(
CompilationWithAnalyzers
compilationWithAnalyzers
,
BidirectionalMap
<
string
,
DiagnosticAnalyzer
>
analyzerToIdMap
)>
GetOrCreateCompilationWithAnalyzersAsync
(
Project
project
,
bool
isDocumentAnalysis
,
CancellationToken
cancellationToken
)
{
/// <summary>
/// Cache of <see cref="CompilationWithAnalyzers"/> and a map from analyzer IDs to <see cref="DiagnosticAnalyzer"/>s
/// for all analyzers for each project.
/// The <see cref="CompilationWithAnalyzers"/> instance is shared between all the following document analyses modes for the project:
/// 1. Span-based analysis for active document (lightbulb)
/// 2. Background analysis for active and open documents.
///
/// NOTE: We do not re-use this cache for project analysis as it leads to significant memory increase in the OOP process,
/// and CWT does not seem to drop entries until ForceGC happens.
/// </summary>
private
static
readonly
ConditionalWeakTable
<
Project
,
CompilationWithAnalyzersData
>
s_cache
=
new
ConditionalWeakTable
<
Project
,
CompilationWithAnalyzersData
>();
private
CompilationWithAnalyzersData
(
CompilationWithAnalyzers
compilationWithAnalyzers
,
BidirectionalMap
<
string
,
DiagnosticAnalyzer
>
analyzerToIdMap
)
{
CompilationWithAnalyzers
=
compilationWithAnalyzers
;
AnalyzerToIdMap
=
analyzerToIdMap
;
}
public
BidirectionalMap
<
string
,
DiagnosticAnalyzer
>
AnalyzerToIdMap
{
get
;
}
public
CompilationWithAnalyzers
CompilationWithAnalyzers
{
get
;
}
var
cacheEntry
=
await
GetOrCreateCacheEntryAsync
().
ConfigureAwait
(
false
);
return
(
cacheEntry
.
CompilationWithAnalyzers
,
cacheEntry
.
AnalyzerToIdMap
);
public
static
async
Task
<
CompilationWithAnalyzersData
>
GetOrCreateAsync
(
Project
project
,
bool
isDocumentAnalysis
,
CancellationToken
cancellationToken
)
async
Task
<
CompilationWithAnalyzersCacheEntry
>
GetOrCreateCacheEntryAsync
()
{
if
(!
isDocumentAnalysis
)
{
// Only use cache for document analysis.
return
await
CreateAsync
(
project
,
cancellationToken
).
ConfigureAwait
(
false
);
return
await
Create
CompilationWithAnalyzersCacheEntry
Async
(
project
,
cancellationToken
).
ConfigureAwait
(
false
);
}
if
(
s_cache
.
TryGetValue
(
project
,
out
var
data
))
if
(
s_c
ompilationWithAnalyzersC
ache
.
TryGetValue
(
project
,
out
var
data
))
{
return
data
;
}
data
=
await
CreateAsync
(
project
,
cancellationToken
).
ConfigureAwait
(
false
);
return
s_cache
.
GetValue
(
project
,
_
=>
data
);
data
=
await
Create
CompilationWithAnalyzersCacheEntry
Async
(
project
,
cancellationToken
).
ConfigureAwait
(
false
);
return
s_c
ompilationWithAnalyzersC
ache
.
GetValue
(
project
,
_
=>
data
);
}
}
private
static
async
Task
<
CompilationWithAnalyzersData
>
CreateAsync
(
Project
project
,
CancellationToken
cancellationToken
)
private
static
async
Task
<
CompilationWithAnalyzersCacheEntry
>
CreateCompilationWithAnalyzersCacheEntryAsync
(
Project
project
,
CancellationToken
cancellationToken
)
{
// We could consider creating a service so that we don't do this repeatedly if this shows up as perf cost
using
var
pooledObject
=
SharedPools
.
Default
<
HashSet
<
object
>>().
GetPooledObject
();
using
var
pooledMap
=
SharedPools
.
Default
<
Dictionary
<
string
,
DiagnosticAnalyzer
>>().
GetPooledObject
();
var
referenceSet
=
pooledObject
.
Object
;
var
analyzerMapBuilder
=
pooledMap
.
Object
;
// This follows what we do in DiagnosticAnalyzerInfoCache.CheckAnalyzerReferenceIdentity
using
var
_
=
ArrayBuilder
<
DiagnosticAnalyzer
>.
GetInstance
(
out
var
analyzerBuilder
);
foreach
(
var
reference
in
project
.
Solution
.
AnalyzerReferences
.
Concat
(
project
.
AnalyzerReferences
))
{
// We could consider creating a service so that we don't do this repeatedly if this shows up as perf cost
using
var
pooledObject
=
SharedPools
.
Default
<
HashSet
<
object
>>().
GetPooledObject
();
using
var
pooledMap
=
SharedPools
.
Default
<
Dictionary
<
string
,
DiagnosticAnalyzer
>>().
GetPooledObject
();
var
referenceSet
=
pooledObject
.
Object
;
var
analyzerMapBuilder
=
pooledMap
.
Object
;
// This follows what we do in DiagnosticAnalyzerInfoCache.CheckAnalyzerReferenceIdentity
using
var
_
=
ArrayBuilder
<
DiagnosticAnalyzer
>.
GetInstance
(
out
var
analyzerBuilder
);
foreach
(
var
reference
in
project
.
Solution
.
AnalyzerReferences
.
Concat
(
project
.
AnalyzerReferences
))
if
(!
referenceSet
.
Add
(
reference
.
Id
))
{
if
(!
referenceSet
.
Add
(
reference
.
Id
))
{
continue
;
}
var
analyzers
=
reference
.
GetAnalyzers
(
project
.
Language
);
analyzerBuilder
.
AddRange
(
analyzers
);
analyzerMapBuilder
.
AppendAnalyzerMap
(
analyzers
);
continue
;
}
var
compilationWithAnalyzers
=
await
CreateCompilationWithAnalyzerAsync
(
project
,
analyzerBuilder
.
ToImmutable
(),
cancellationToken
).
ConfigureAwait
(
false
);
var
analyzerToIdMap
=
new
BidirectionalMap
<
string
,
DiagnosticAnalyzer
>(
analyzerMapBuilder
);
var
analyzers
=
reference
.
GetAnalyzers
(
project
.
Language
);
analyzerBuilder
.
AddRange
(
analyzers
);
analyzerMapBuilder
.
AppendAnalyzerMap
(
analyzers
);
}
return
new
CompilationWithAnalyzersData
(
compilationWithAnalyzers
,
analyzerToIdMap
);
var
compilationWithAnalyzers
=
await
CreateCompilationWithAnalyzerAsync
(
project
,
analyzerBuilder
.
ToImmutable
(),
cancellationToken
).
ConfigureAwait
(
false
);
var
analyzerToIdMap
=
new
BidirectionalMap
<
string
,
DiagnosticAnalyzer
>(
analyzerMapBuilder
);
static
async
Task
<
CompilationWithAnalyzers
>
CreateCompilationWithAnalyzerAsync
(
Project
project
,
ImmutableArray
<
DiagnosticAnalyzer
>
analyzers
,
CancellationToken
cancellationToken
)
{
// Always run analyzers concurrently in OOP
const
bool
concurrentAnalysis
=
true
;
// Get original compilation
var
compilation
=
await
project
.
GetRequiredCompilationAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
// Fork compilation with concurrent build. this is okay since WithAnalyzers will fork compilation
// anyway to attach event queue. This should make compiling compilation concurrent and make things
// faster
compilation
=
compilation
.
WithOptions
(
compilation
.
Options
.
WithConcurrentBuild
(
concurrentAnalysis
));
// Run analyzers concurrently, with performance logging and reporting suppressed diagnostics.
// This allows all client requests with or without performance data and/or suppressed diagnostics to be satisfied.
// TODO: can we support analyzerExceptionFilter in remote host?
// right now, host doesn't support watson, we might try to use new NonFatal watson API?
var
analyzerOptions
=
new
CompilationWithAnalyzersOptions
(
options
:
new
WorkspaceAnalyzerOptions
(
project
.
AnalyzerOptions
,
project
.
Solution
),
onAnalyzerException
:
null
,
analyzerExceptionFilter
:
null
,
concurrentAnalysis
:
concurrentAnalysis
,
logAnalyzerExecutionTime
:
true
,
reportSuppressedDiagnostics
:
true
);
return
compilation
.
WithAnalyzers
(
analyzers
,
analyzerOptions
);
}
return
new
CompilationWithAnalyzersCacheEntry
(
compilationWithAnalyzers
,
analyzerToIdMap
);
static
async
Task
<
CompilationWithAnalyzers
>
CreateCompilationWithAnalyzerAsync
(
Project
project
,
ImmutableArray
<
DiagnosticAnalyzer
>
analyzers
,
CancellationToken
cancellationToken
)
{
// Always run analyzers concurrently in OOP
const
bool
concurrentAnalysis
=
true
;
// Get original compilation
var
compilation
=
await
project
.
GetRequiredCompilationAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
// Fork compilation with concurrent build. this is okay since WithAnalyzers will fork compilation
// anyway to attach event queue. This should make compiling compilation concurrent and make things
// faster
compilation
=
compilation
.
WithOptions
(
compilation
.
Options
.
WithConcurrentBuild
(
concurrentAnalysis
));
// Run analyzers concurrently, with performance logging and reporting suppressed diagnostics.
// This allows all client requests with or without performance data and/or suppressed diagnostics to be satisfied.
// TODO: can we support analyzerExceptionFilter in remote host?
// right now, host doesn't support watson, we might try to use new NonFatal watson API?
var
analyzerOptions
=
new
CompilationWithAnalyzersOptions
(
options
:
new
WorkspaceAnalyzerOptions
(
project
.
AnalyzerOptions
,
project
.
Solution
),
onAnalyzerException
:
null
,
analyzerExceptionFilter
:
null
,
concurrentAnalysis
:
concurrentAnalysis
,
logAnalyzerExecutionTime
:
true
,
reportSuppressedDiagnostics
:
true
);
return
compilation
.
WithAnalyzers
(
analyzers
,
analyzerOptions
);
}
}
private
sealed
class
CompilationWithAnalyzersCacheEntry
{
public
CompilationWithAnalyzers
CompilationWithAnalyzers
{
get
;
}
public
BidirectionalMap
<
string
,
DiagnosticAnalyzer
>
AnalyzerToIdMap
{
get
;
}
public
CompilationWithAnalyzersCacheEntry
(
CompilationWithAnalyzers
compilationWithAnalyzers
,
BidirectionalMap
<
string
,
DiagnosticAnalyzer
>
analyzerToIdMap
)
{
CompilationWithAnalyzers
=
compilationWithAnalyzers
;
AnalyzerToIdMap
=
analyzerToIdMap
;
}
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录