Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
6895112f
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,发现更多精彩内容 >>
未验证
提交
6895112f
编写于
3月 14, 2020
作者:
C
CyrusNajmabadi
提交者:
GitHub
3月 14, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #42346 from CyrusNajmabadi/designerOOP
Move designer attribute scanning out-of-process
上级
c0a1d1ec
5c7f25b1
变更
31
隐藏空白更改
内联
并排
Showing
31 changed file
with
1078 addition
and
844 deletion
+1078
-844
eng/targets/GenerateServiceHubConfigurationFiles.targets
eng/targets/GenerateServiceHubConfigurationFiles.targets
+1
-0
src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs
...orFeatures/TestUtilities/Remote/InProcRemostHostClient.cs
+1
-0
src/Features/CSharp/Portable/DesignerAttributes/CSharpDesignerAttributeService.cs
...able/DesignerAttributes/CSharpDesignerAttributeService.cs
+0
-74
src/Features/Core/Portable/DesignerAttributes/AbstractDesignerAttributeService.cs
...le/DesignerAttributes/AbstractDesignerAttributeService.cs
+0
-149
src/Features/VisualBasic/Portable/DesignerAttributes/BasicDesignerAttributeService.vb
...table/DesignerAttributes/BasicDesignerAttributeService.vb
+0
-74
src/VisualStudio/CSharp/Test/DesignerAttribute/DesignerAttributeServiceTests.cs
...p/Test/DesignerAttribute/DesignerAttributeServiceTests.cs
+52
-16
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/DesignerAttributeIncrementalAnalyzer.cs
...DesignerAttribute/DesignerAttributeIncrementalAnalyzer.cs
+0
-339
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/DesignerAttributeState.cs
...mplementation/DesignerAttribute/DesignerAttributeState.cs
+0
-92
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/IDesignerAttributeService.cs
...ementation/DesignerAttribute/IDesignerAttributeService.cs
+22
-0
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs
...DesignerAttribute/VisualStudioDesignerAttributeService.cs
+377
-0
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeServiceFactory.cs
...rAttribute/VisualStudioDesignerAttributeServiceFactory.cs
+39
-0
src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs
...Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs
+4
-1
src/VisualStudio/Core/Def/RoslynPackage.cs
src/VisualStudio/Core/Def/RoslynPackage.cs
+6
-0
src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs
...Studio/Core/Test.Next/Services/ServiceHubServicesTests.cs
+66
-15
src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs
...ualStudio/Core/Test.Next/Services/SolutionServiceTests.cs
+0
-2
src/VisualStudio/Setup/source.extension.vsixmanifest
src/VisualStudio/Setup/source.extension.vsixmanifest
+2
-0
src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeHelpers.cs
...re/Portable/DesignerAttribute/DesignerAttributeHelpers.cs
+96
-0
src/Workspaces/Core/Portable/DesignerAttribute/DesignerInfo.cs
...orkspaces/Core/Portable/DesignerAttribute/DesignerInfo.cs
+29
-0
src/Workspaces/Core/Portable/DesignerAttribute/IDesignerAttributeListener.cs
.../Portable/DesignerAttribute/IDesignerAttributeListener.cs
+23
-0
src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeService.cs
...able/DesignerAttribute/IRemoteDesignerAttributeService.cs
+24
-0
src/Workspaces/Core/Portable/Remote/WellKnownServiceHubServices.cs
...paces/Core/Portable/Remote/WellKnownServiceHubServices.cs
+2
-0
src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute_Names.cs
.../Core/Portable/Shared/TestHooks/FeatureAttribute_Names.cs
+0
-1
src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_DesignerAttributes.cs
...iceHub/Services/CodeAnalysisService_DesignerAttributes.cs
+0
-45
src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer.cs
...erAttribute/RemoteDesignerAttributeIncrementalAnalyzer.cs
+191
-0
src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzerProvider.cs
...ute/RemoteDesignerAttributeIncrementalAnalyzerProvider.cs
+28
-0
src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer_Serialization.cs
...moteDesignerAttributeIncrementalAnalyzer_Serialization.cs
+56
-0
src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeService.cs
...vices/DesignerAttribute/RemoteDesignerAttributeService.cs
+43
-0
src/Workspaces/Remote/ServiceHub/Shared/RoslynJsonConverter.RoslynOnly.cs
...emote/ServiceHub/Shared/RoslynJsonConverter.RoslynOnly.cs
+0
-36
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs
...Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs
+6
-0
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs
...nsions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs
+2
-0
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb
...isualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb
+8
-0
未找到文件。
eng/targets/GenerateServiceHubConfigurationFiles.targets
浏览文件 @
6895112f
...
...
@@ -9,6 +9,7 @@
<ServiceHubService
Include=
"roslynCodeAnalysis"
ClassName=
"Microsoft.CodeAnalysis.Remote.CodeAnalysisService"
/>
<ServiceHubService
Include=
"roslynRemoteHost"
ClassName=
"Microsoft.CodeAnalysis.Remote.RemoteHostService"
/>
<ServiceHubService
Include=
"roslynSnapshot"
ClassName=
"Microsoft.CodeAnalysis.Remote.SnapshotService"
/>
<ServiceHubService
Include=
"roslynRemoteDesignerAttributeService"
ClassName=
"Microsoft.CodeAnalysis.Remote.RemoteDesignerAttributeService"
/>
<ServiceHubService
Include=
"roslynRemoteSymbolSearchUpdateEngine"
ClassName=
"Microsoft.CodeAnalysis.Remote.RemoteSymbolSearchUpdateEngine"
/>
<ServiceHubService
Include=
"roslynLanguageServer"
ClassName=
"Microsoft.CodeAnalysis.Remote.LanguageServer"
/>
</ItemGroup>
...
...
src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs
浏览文件 @
6895112f
...
...
@@ -167,6 +167,7 @@ public InProcRemoteServices(bool runCacheCleanup)
RegisterService
(
WellKnownServiceHubServices
.
CodeAnalysisService
,
(
s
,
p
)
=>
new
CodeAnalysisService
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
SnapshotService
,
(
s
,
p
)
=>
new
SnapshotService
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
RemoteSymbolSearchUpdateEngine
,
(
s
,
p
)
=>
new
RemoteSymbolSearchUpdateEngine
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
RemoteDesignerAttributeService
,
(
s
,
p
)
=>
new
RemoteDesignerAttributeService
(
s
,
p
));
RegisterService
(
WellKnownServiceHubServices
.
LanguageServer
,
(
s
,
p
)
=>
new
LanguageServer
(
s
,
p
));
}
...
...
src/Features/CSharp/Portable/DesignerAttributes/CSharpDesignerAttributeService.cs
已删除
100644 → 0
浏览文件 @
c0a1d1ec
// 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.Generic
;
using
System.Composition
;
using
System.Linq
;
using
Microsoft.CodeAnalysis.CSharp.Syntax
;
using
Microsoft.CodeAnalysis.DesignerAttributes
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.CSharp.DesignerAttributes
{
[
ExportLanguageServiceFactory
(
typeof
(
IDesignerAttributeService
),
LanguageNames
.
CSharp
),
Shared
]
internal
class
CSharpDesignerAttributeServiceFactory
:
ILanguageServiceFactory
{
[
ImportingConstructor
]
public
CSharpDesignerAttributeServiceFactory
()
{
}
public
ILanguageService
CreateLanguageService
(
HostLanguageServices
languageServices
)
=>
new
CSharpDesignerAttributeService
(
languageServices
.
WorkspaceServices
.
Workspace
);
}
internal
class
CSharpDesignerAttributeService
:
AbstractDesignerAttributeService
{
public
CSharpDesignerAttributeService
(
Workspace
workspace
)
:
base
(
workspace
)
{
}
protected
override
IEnumerable
<
SyntaxNode
>
GetAllTopLevelTypeDefined
(
SyntaxNode
node
)
{
if
(!(
node
is
CompilationUnitSyntax
compilationUnit
))
{
return
SpecializedCollections
.
EmptyEnumerable
<
SyntaxNode
>();
}
return
compilationUnit
.
Members
.
SelectMany
(
GetAllTopLevelTypeDefined
);
}
private
IEnumerable
<
SyntaxNode
>
GetAllTopLevelTypeDefined
(
MemberDeclarationSyntax
member
)
{
switch
(
member
)
{
case
NamespaceDeclarationSyntax
namespaceMember
:
return
namespaceMember
.
Members
.
SelectMany
(
GetAllTopLevelTypeDefined
);
case
ClassDeclarationSyntax
type
:
return
SpecializedCollections
.
SingletonEnumerable
<
SyntaxNode
>(
type
);
}
return
SpecializedCollections
.
EmptyEnumerable
<
SyntaxNode
>();
}
protected
override
bool
ProcessOnlyFirstTypeDefined
()
{
return
true
;
}
protected
override
bool
HasAttributesOrBaseTypeOrIsPartial
(
SyntaxNode
typeNode
)
{
if
(
typeNode
is
ClassDeclarationSyntax
classNode
)
{
return
classNode
.
AttributeLists
.
Count
>
0
||
classNode
.
BaseList
!=
null
||
classNode
.
Modifiers
.
Any
(
SyntaxKind
.
PartialKeyword
);
}
return
false
;
}
}
}
src/Features/Core/Portable/DesignerAttributes/AbstractDesignerAttributeService.cs
已删除
100644 → 0
浏览文件 @
c0a1d1ec
// 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.Generic
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Remote
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.DesignerAttributes
{
internal
abstract
class
AbstractDesignerAttributeService
:
IDesignerAttributeService
{
// 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
AbstractDesignerAttributeService
(
Workspace
workspace
)
{
_workspace
=
workspace
;
}
protected
abstract
bool
ProcessOnlyFirstTypeDefined
();
protected
abstract
IEnumerable
<
SyntaxNode
>
GetAllTopLevelTypeDefined
(
SyntaxNode
root
);
protected
abstract
bool
HasAttributesOrBaseTypeOrIsPartial
(
SyntaxNode
typeNode
);
public
async
Task
<
DesignerAttributeResult
>
ScanDesignerAttributesAsync
(
Document
document
,
CancellationToken
cancellationToken
)
{
// make sure given input is right one
Contract
.
ThrowIfFalse
(
_workspace
==
document
.
Project
.
Solution
.
Workspace
);
// run designer attributes 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
<
DesignerAttributeResult
>(
WellKnownServiceHubServices
.
CodeAnalysisService
,
nameof
(
IRemoteDesignerAttributeService
.
ScanDesignerAttributesAsync
),
document
.
Project
.
Solution
,
new
[]
{
document
.
Id
},
callbackTarget
:
null
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
result
.
HasValue
)
{
return
result
.
Value
;
}
}
}
return
await
ScanDesignerAttributesInCurrentProcessAsync
(
document
,
cancellationToken
).
ConfigureAwait
(
false
);
}
private
async
Task
<
DesignerAttributeResult
>
ScanDesignerAttributesInCurrentProcessAsync
(
Document
document
,
CancellationToken
cancellationToken
)
{
var
root
=
await
document
.
GetSyntaxRootAsync
(
cancellationToken
).
ConfigureAwait
(
continueOnCapturedContext
:
false
);
// Delay getting any of these until we need them, but hold on to them once we have them.
Compilation
compilation
=
null
;
INamedTypeSymbol
designerAttribute
=
null
;
SemanticModel
model
=
null
;
string
designerAttributeArgument
=
null
;
var
documentHasError
=
false
;
// get type defined in current tree
foreach
(
var
typeNode
in
GetAllTopLevelTypeDefined
(
root
))
{
cancellationToken
.
ThrowIfCancellationRequested
();
if
(
HasAttributesOrBaseTypeOrIsPartial
(
typeNode
))
{
if
(
designerAttribute
==
null
)
{
compilation
??=
await
document
.
Project
.
GetCompilationAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
designerAttribute
=
compilation
.
DesignerCategoryAttributeType
();
if
(
designerAttribute
==
null
)
{
// The DesignerCategoryAttribute doesn't exist. either not applicable or
// no idea on design attribute status, just leave things as it is.
return
new
DesignerAttributeResult
(
designerAttributeArgument
,
documentHasError
,
applicable
:
false
);
}
}
if
(
model
==
null
)
{
model
=
await
document
.
GetSemanticModelAsync
(
cancellationToken
).
ConfigureAwait
(
continueOnCapturedContext
:
false
);
}
if
(!(
model
.
GetDeclaredSymbol
(
typeNode
,
cancellationToken
)
is
INamedTypeSymbol
definedType
))
{
continue
;
}
// walk up type chain
foreach
(
var
type
in
definedType
.
GetBaseTypesAndThis
())
{
if
(
type
.
IsErrorType
())
{
documentHasError
=
true
;
continue
;
}
cancellationToken
.
ThrowIfCancellationRequested
();
// if it has designer attribute, set it
var
attribute
=
type
.
GetAttributes
().
Where
(
d
=>
designerAttribute
.
Equals
(
d
.
AttributeClass
)).
FirstOrDefault
();
if
(
attribute
!=
null
&&
attribute
.
ConstructorArguments
.
Length
==
1
)
{
designerAttributeArgument
=
GetArgumentString
(
attribute
.
ConstructorArguments
[
0
]);
return
new
DesignerAttributeResult
(
designerAttributeArgument
,
documentHasError
,
applicable
:
true
);
}
}
}
// check only first type
if
(
ProcessOnlyFirstTypeDefined
())
{
break
;
}
}
return
new
DesignerAttributeResult
(
designerAttributeArgument
,
documentHasError
,
applicable
:
true
);
}
private
static
string
GetArgumentString
(
TypedConstant
argument
)
{
if
(
argument
.
Type
==
null
||
argument
.
Type
.
SpecialType
!=
SpecialType
.
System_String
||
argument
.
IsNull
)
{
return
null
;
}
return
((
string
)
argument
.
Value
).
Trim
();
}
}
}
src/Features/VisualBasic/Portable/DesignerAttributes/BasicDesignerAttributeService.vb
已删除
100644 → 0
浏览文件 @
c0a1d1ec
' 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.
Imports
System.Composition
Imports
Microsoft.CodeAnalysis.DesignerAttributes
Imports
Microsoft.CodeAnalysis.Host
Imports
Microsoft.CodeAnalysis.Host.Mef
Imports
Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace
Microsoft.CodeAnalysis.VisualBasic.DesignerAttributes
<
ExportLanguageServiceFactory
(
GetType
(
IDesignerAttributeService
),
LanguageNames
.
VisualBasic
),
[
Shared
]
>
Friend
Class
VisualBasicDesignerAttributeServiceFactory
Implements
ILanguageServiceFactory
<
ImportingConstructor
>
Public
Sub
New
()
End
Sub
Public
Function
CreateLanguageService
(
languageServices
As
HostLanguageServices
)
As
ILanguageService
Implements
ILanguageServiceFactory
.
CreateLanguageService
Return
New
BasicDesignerAttributeService
(
languageServices
.
WorkspaceServices
.
Workspace
)
End
Function
End
Class
Friend
Class
BasicDesignerAttributeService
Inherits
AbstractDesignerAttributeService
Public
Sub
New
(
workspace
As
Workspace
)
MyBase
.
New
(
workspace
)
End
Sub
Protected
Overrides
Function
GetAllTopLevelTypeDefined
(
node
As
SyntaxNode
)
As
IEnumerable
(
Of
SyntaxNode
)
Dim
compilationUnit
=
TryCast
(
node
,
CompilationUnitSyntax
)
If
compilationUnit
Is
Nothing
Then
Return
SpecializedCollections
.
EmptyEnumerable
(
Of
SyntaxNode
)()
End
If
Return
compilationUnit
.
Members
.
SelectMany
(
AddressOf
GetAllTopLevelTypeDefined
)
End
Function
Private
Overloads
Function
GetAllTopLevelTypeDefined
(
member
As
StatementSyntax
)
As
IEnumerable
(
Of
SyntaxNode
)
Dim
namespaceMember
=
TryCast
(
member
,
NamespaceBlockSyntax
)
If
namespaceMember
IsNot
Nothing
Then
Return
namespaceMember
.
Members
.
SelectMany
(
AddressOf
GetAllTopLevelTypeDefined
)
End
If
Dim
type
=
TryCast
(
member
,
ClassBlockSyntax
)
If
type
IsNot
Nothing
Then
Return
SpecializedCollections
.
SingletonEnumerable
(
Of
SyntaxNode
)(
type
)
End
If
Return
SpecializedCollections
.
EmptyEnumerable
(
Of
SyntaxNode
)()
End
Function
Protected
Overrides
Function
ProcessOnlyFirstTypeDefined
()
As
Boolean
Return
True
End
Function
Protected
Overrides
Function
HasAttributesOrBaseTypeOrIsPartial
(
typeNode
As
SyntaxNode
)
As
Boolean
Dim
type
=
TryCast
(
typeNode
,
ClassBlockSyntax
)
If
type
IsNot
Nothing
Then
' VB can't actually use any syntactic tricks to limit the types we need to look at.
' VB allows up to one partial declaration omit the 'Partial' keyword; so the presence
' or absence of attributes, base types, or the 'Partial' keyword doesn't mean anything.
' If this is a ClassBlockSyntax node, we're going to have to bind.
Return
True
End
If
Return
False
End
Function
End
Class
End
Namespace
src/VisualStudio/CSharp/Test/DesignerAttribute/DesignerAttributeServiceTests.cs
浏览文件 @
6895112f
...
...
@@ -5,7 +5,7 @@
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.DesignerAttribute
s
;
using
Microsoft.CodeAnalysis.DesignerAttribute
;
using
Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.Test.Utilities
;
...
...
@@ -19,43 +19,79 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.DesignerAttri
public
class
DesignerAttributeServiceTests
{
[
Fact
]
public
async
Task
NoDesignerTest
()
public
async
Task
NoDesignerTest
1
()
{
var
code
=
@"class Test { }"
;
await
TestAsync
(
code
,
designer
:
false
);
await
TestAsync
(
code
,
category
:
null
);
}
[
Fact
]
public
async
Task
NoDesignerOnSecondClass
()
{
await
TestAsync
(
@"class Test1 { }
[System.ComponentModel.DesignerCategory(""Form"")]
class Test2 { }"
,
category
:
null
);
}
[
Fact
]
public
async
Task
NoDesignerOnStruct
()
{
await
TestAsync
(
@"
[System.ComponentModel.DesignerCategory(""Form"")]
struct Test1 { }"
,
category
:
null
);
}
[
Fact
]
public
async
Task
NoDesignerOnNestedClass
()
{
await
TestAsync
(
@"class Test1
{
[System.ComponentModel.DesignerCategory(""Form"")]
class Test2 { }
}"
,
category
:
null
);
}
[
Fact
]
public
async
Task
SimpleDesignerTest
()
{
var
code
=
@"[System.ComponentModel.DesignerCategory(""Form"")]
class Test { }"
;
await
TestAsync
(
code
,
designer
:
true
);
await
TestAsync
(
@"[System.ComponentModel.DesignerCategory(""Form"")]
class Test { }"
,
"Form"
);
}
private
static
async
Task
TestAsync
(
string
codeWithMarker
,
bool
designer
)
[
Fact
]
public
async
Task
SimpleDesignerTest2
()
{
await
TestAsync
(
codeWithMarker
,
designer
,
remote
:
false
);
await
TestAsync
(
codeWithMarker
,
designer
,
remote
:
true
);
await
TestAsync
(
@"using System.ComponentModel;
[DesignerCategory(""Form"")]
class Test { }"
,
"Form"
);
}
private
static
async
Task
TestAsync
(
string
codeWithMarker
,
bool
designer
,
bool
remote
)
private
static
async
Task
TestAsync
(
string
codeWithMarker
,
string
category
)
{
using
var
workspace
=
TestWorkspace
.
CreateCSharp
(
codeWithMarker
,
openDocuments
:
false
);
workspace
.
TryApplyChanges
(
workspace
.
CurrentSolution
.
WithOptions
(
workspace
.
Options
.
WithChangedOption
(
RemoteHostOptions
.
RemoteHostTest
,
remote
)));
var
hostDocument
=
workspace
.
Documents
.
First
();
var
documentId
=
hostDocument
.
Id
;
var
document
=
workspace
.
CurrentSolution
.
GetDocument
(
documentId
);
var
service
=
document
.
GetLanguageService
<
IDesignerAttributeService
>();
var
result
=
await
service
.
ScanDesignerAttributesAsync
(
document
,
CancellationToken
.
None
);
var
compilation
=
await
document
.
Project
.
GetCompilationAsync
();
var
actual
=
await
DesignerAttributeHelpers
.
ComputeDesignerAttributeCategoryAsync
(
compilation
.
DesignerCategoryAttributeType
(),
document
,
CancellationToken
.
None
);
var
argumentIsNull
=
result
.
DesignerAttributeArgument
==
null
;
Assert
.
Equal
(
designer
,
!
argumentIsNull
);
Assert
.
Equal
(
category
,
actual
);
}
}
}
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/DesignerAttributeIncrementalAnalyzer.cs
已删除
100644 → 0
浏览文件 @
c0a1d1ec
// 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
;
using
System.Collections.Concurrent
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.DesignerAttributes
;
using
Microsoft.CodeAnalysis.Editor
;
using
Microsoft.CodeAnalysis.Editor.Shared.Options
;
using
Microsoft.CodeAnalysis.Editor.Shared.Utilities
;
using
Microsoft.CodeAnalysis.Options
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.Shared.TestHooks
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
using
Microsoft.CodeAnalysis.Versions
;
using
Microsoft.VisualStudio.Designer.Interfaces
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
using
Microsoft.VisualStudio.Shell.Interop
;
using
Microsoft.VisualStudio.Shell.Services
;
using
Microsoft.VisualStudio.Threading
;
using
Roslyn.Utilities
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute
{
internal
partial
class
DesignerAttributeIncrementalAnalyzer
:
ForegroundThreadAffinitizedObject
,
IIncrementalAnalyzer
{
private
readonly
IForegroundNotificationService
_notificationService
;
private
readonly
IServiceProvider
_serviceProvider
;
private
readonly
DesignerAttributeState
_state
;
private
readonly
IAsynchronousOperationListener
_listener
;
// cache whether a project is cps project or not
private
readonly
ConcurrentDictionary
<
ProjectId
,
IProjectItemDesignerTypeUpdateService
>
_cpsProjects
;
/// <summary>
/// cache designer from UI thread
///
/// access this field through <see cref="GetDesignerFromForegroundThread"/>
/// </summary>
private
IVSMDDesignerService
_dotNotAccessDirectlyDesigner
;
public
DesignerAttributeIncrementalAnalyzer
(
IThreadingContext
threadingContext
,
IServiceProvider
serviceProvider
,
IForegroundNotificationService
notificationService
,
IAsynchronousOperationListenerProvider
listenerProvider
)
:
base
(
threadingContext
)
{
_serviceProvider
=
serviceProvider
;
Contract
.
ThrowIfNull
(
_serviceProvider
);
_notificationService
=
notificationService
;
_cpsProjects
=
new
ConcurrentDictionary
<
ProjectId
,
IProjectItemDesignerTypeUpdateService
>(
concurrencyLevel
:
2
,
capacity
:
10
);
_listener
=
listenerProvider
.
GetListener
(
FeatureAttribute
.
DesignerAttribute
);
_state
=
new
DesignerAttributeState
();
}
public
Task
DocumentResetAsync
(
Document
document
,
CancellationToken
cancellationToken
)
{
_state
.
Remove
(
document
.
Id
);
return
_state
.
PersistAsync
(
document
,
new
Data
(
VersionStamp
.
Default
,
VersionStamp
.
Default
,
designerAttributeArgument
:
null
),
cancellationToken
);
}
public
bool
NeedsReanalysisOnOptionChanged
(
object
sender
,
OptionChangedEventArgs
e
)
{
return
false
;
}
public
async
Task
AnalyzeDocumentAsync
(
Document
document
,
SyntaxNode
bodyOpt
,
InvocationReasons
reasons
,
CancellationToken
cancellationToken
)
{
Contract
.
ThrowIfFalse
(
document
.
IsFromPrimaryBranch
());
cancellationToken
.
ThrowIfCancellationRequested
();
if
(!
document
.
Project
.
Solution
.
Workspace
.
Options
.
GetOption
(
InternalFeatureOnOffOptions
.
DesignerAttributes
))
{
return
;
}
// use text and project dependent versions so that we can detect changes on this file and its dependent files
// in current project or projects this depends on transitively
var
textVersion
=
await
document
.
GetTextVersionAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
projectVersion
=
await
document
.
Project
.
GetDependentVersionAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
existingData
=
await
_state
.
TryGetExistingDataAsync
(
document
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
existingData
!=
null
)
{
// check whether we can use the data as it is (can happen when re-using persisted data from previous VS session)
if
(
CheckVersions
(
document
,
textVersion
,
projectVersion
,
existingData
))
{
await
RegisterDesignerAttributeAsync
(
document
,
existingData
.
DesignerAttributeArgument
,
cancellationToken
).
ConfigureAwait
(
false
);
return
;
}
}
var
result
=
await
ScanDesignerAttributesOnRemoteHostIfPossibleAsync
(
document
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(!
result
.
Applicable
)
{
_state
.
Remove
(
document
.
Id
);
return
;
}
// we checked all types in the document, but couldn't find designer attribute, but we can't say this document doesn't have designer attribute
// if the document also contains some errors.
var
designerAttributeArgumentOpt
=
result
.
ContainsErrors
?
new
Optional
<
string
>()
:
new
Optional
<
string
>(
result
.
DesignerAttributeArgument
);
await
RegisterDesignerAttributeAndSaveStateAsync
(
document
,
textVersion
,
projectVersion
,
designerAttributeArgumentOpt
,
cancellationToken
).
ConfigureAwait
(
false
);
}
public
void
RemoveDocument
(
DocumentId
documentId
)
{
_state
.
Remove
(
documentId
);
}
public
void
RemoveProject
(
ProjectId
projectId
)
{
_cpsProjects
.
TryRemove
(
projectId
,
out
_
);
}
private
async
Task
<
DesignerAttributeResult
>
ScanDesignerAttributesOnRemoteHostIfPossibleAsync
(
Document
document
,
CancellationToken
cancellationToken
)
{
// No remote host support, use inproc service
var
service
=
document
.
GetLanguageService
<
IDesignerAttributeService
>();
if
(
service
==
null
)
{
return
new
DesignerAttributeResult
(
designerAttributeArgument
:
null
,
containsErrors
:
true
,
applicable
:
false
);
}
return
await
service
.
ScanDesignerAttributesAsync
(
document
,
cancellationToken
).
ConfigureAwait
(
false
);
}
private
async
Task
<
IProjectItemDesignerTypeUpdateService
>
GetUpdateServiceIfCpsProjectAsync
(
Project
project
,
CancellationToken
cancellationToken
)
{
if
(
_cpsProjects
.
TryGetValue
(
project
.
Id
,
out
var
value
))
{
return
value
;
}
var
vsWorkspace
=
project
.
Solution
.
Workspace
as
VisualStudioWorkspaceImpl
;
await
ThreadingContext
.
JoinableTaskFactory
.
SwitchToMainThreadAsync
(
alwaysYield
:
true
,
cancellationToken
);
cancellationToken
.
ThrowIfCancellationRequested
();
if
(!
vsWorkspace
.
IsCPSProject
(
project
))
{
_cpsProjects
.
TryAdd
(
project
.
Id
,
null
);
return
null
;
}
var
vsProject
=
(
IVsProject
)
vsWorkspace
.
GetHierarchy
(
project
.
Id
);
if
(
ErrorHandler
.
Failed
(
vsProject
.
GetItemContext
((
uint
)
VSConstants
.
VSITEMID
.
Root
,
out
var
projectServiceProvider
)))
{
_cpsProjects
.
TryAdd
(
project
.
Id
,
null
);
return
null
;
}
var
serviceProvider
=
new
Shell
.
ServiceProvider
(
projectServiceProvider
);
var
updateService
=
serviceProvider
.
GetService
(
typeof
(
IProjectItemDesignerTypeUpdateService
))
as
IProjectItemDesignerTypeUpdateService
;
if
(
updateService
==
null
)
{
_cpsProjects
.
TryAdd
(
project
.
Id
,
null
);
return
null
;
}
_cpsProjects
[
project
.
Id
]
=
updateService
;
return
updateService
;
}
private
bool
CheckVersions
(
Document
document
,
VersionStamp
textVersion
,
VersionStamp
semanticVersion
,
Data
existingData
)
{
// first check full version to see whether we can reuse data in same session, if we can't, check timestamp only version to see whether
// we can use it cross-session.
return
document
.
CanReusePersistedTextVersion
(
textVersion
,
existingData
.
TextVersion
)
&&
document
.
Project
.
CanReusePersistedDependentProjectVersion
(
semanticVersion
,
existingData
.
SemanticVersion
);
}
private
async
Task
RegisterDesignerAttributeAndSaveStateAsync
(
Document
document
,
VersionStamp
textVersion
,
VersionStamp
semanticVersion
,
Optional
<
string
>
designerAttributeArgumentOpt
,
CancellationToken
cancellationToken
)
{
if
(!
designerAttributeArgumentOpt
.
HasValue
)
{
// no value means it couldn't determine whether this document has designer attribute or not.
// one of such case is when base type is error type.
return
;
}
var
data
=
new
Data
(
textVersion
,
semanticVersion
,
designerAttributeArgumentOpt
.
Value
);
await
_state
.
PersistAsync
(
document
,
data
,
cancellationToken
).
ConfigureAwait
(
false
);
await
RegisterDesignerAttributeAsync
(
document
,
designerAttributeArgumentOpt
.
Value
,
cancellationToken
).
ConfigureAwait
(
false
);
}
private
async
Task
RegisterDesignerAttributeAsync
(
Document
document
,
string
designerAttributeArgument
,
CancellationToken
cancellationToken
)
{
if
(!
_state
.
Update
(
document
.
Id
,
designerAttributeArgument
))
{
// value is not updated, meaning we are trying to report same value as before.
// we don't need to do anything.
//
// I kept this since existing code had this, but since we check what platform has before
// reporting it, this might be redundant.
return
;
}
if
(!(
document
.
Project
.
Solution
.
Workspace
is
VisualStudioWorkspaceImpl
workspace
))
{
return
;
}
var
updateService
=
await
GetUpdateServiceIfCpsProjectAsync
(
document
.
Project
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
updateService
!=
null
)
{
// fire and forget designer attribute notification to CPS
_
=
NotifyCpsDesignerAttributeAsync
(
document
,
designerAttributeArgument
,
updateService
).
ReportNonFatalErrorAsync
();
}
else
{
var
documentId
=
document
.
Id
;
_notificationService
.
RegisterNotification
(()
=>
{
var
hierarchy
=
workspace
.
GetHierarchy
(
documentId
.
ProjectId
);
if
(
hierarchy
==
null
)
{
return
;
}
var
itemId
=
hierarchy
.
TryGetItemId
(
document
.
FilePath
);
if
(
itemId
==
VSConstants
.
VSITEMID_NIL
)
{
return
;
}
if
(
ErrorHandler
.
Succeeded
(
hierarchy
.
GetProperty
(
itemId
,
(
int
)
__VSHPROPID
.
VSHPROPID_ItemSubType
,
out
var
currentValue
)))
{
var
currentStringValue
=
string
.
IsNullOrEmpty
(
currentValue
as
string
)
?
null
:
(
string
)
currentValue
;
if
(
string
.
Equals
(
currentStringValue
,
designerAttributeArgument
,
StringComparison
.
OrdinalIgnoreCase
))
{
// PERF: Avoid sending the message if the project system already has the current value.
return
;
}
}
try
{
var
designer
=
GetDesignerFromForegroundThread
();
if
(
designer
!=
null
)
{
designer
.
RegisterDesignViewAttribute
(
hierarchy
,
(
int
)
itemId
,
dwClass
:
0
,
pwszAttributeValue
:
designerAttributeArgument
);
}
}
catch
{
// DevDiv # 933717
// turns out RegisterDesignViewAttribute can throw in certain cases such as a file failed to be checked out by source control
// or IVSHierarchy failed to set a property for this project
//
// just swallow it. don't crash VS.
}
},
_listener
.
BeginAsyncOperation
(
"RegisterDesignerAttribute"
));
}
}
private
async
Task
NotifyCpsDesignerAttributeAsync
(
Document
document
,
string
designerAttributeArgument
,
IProjectItemDesignerTypeUpdateService
updateService
)
{
using
(
_listener
.
BeginAsyncOperation
(
"RegisterDesignerAttribute"
))
{
try
{
await
updateService
.
SetProjectItemDesignerTypeAsync
(
document
.
FilePath
,
designerAttributeArgument
).
ConfigureAwait
(
false
);
}
catch
(
ObjectDisposedException
)
{
// we might call update service after project is already removed and get object disposed exception.
// we will catch the exception and ignore.
// see this PR for more detail - https://github.com/dotnet/roslyn/pull/35383
}
}
}
private
IVSMDDesignerService
GetDesignerFromForegroundThread
()
{
if
(
_dotNotAccessDirectlyDesigner
!=
null
)
{
return
_dotNotAccessDirectlyDesigner
;
}
AssertIsForeground
();
_dotNotAccessDirectlyDesigner
=
_serviceProvider
.
GetService
(
typeof
(
SVSMDDesignerService
))
as
IVSMDDesignerService
;
return
_dotNotAccessDirectlyDesigner
;
}
private
class
Data
{
public
readonly
VersionStamp
TextVersion
;
public
readonly
VersionStamp
SemanticVersion
;
public
readonly
string
DesignerAttributeArgument
;
public
Data
(
VersionStamp
textVersion
,
VersionStamp
semanticVersion
,
string
designerAttributeArgument
)
{
this
.
TextVersion
=
textVersion
;
this
.
SemanticVersion
=
semanticVersion
;
this
.
DesignerAttributeArgument
=
designerAttributeArgument
;
}
}
#
region
unused
public
Task
NewSolutionSnapshotAsync
(
Solution
solution
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
public
Task
DocumentOpenAsync
(
Document
document
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
public
Task
DocumentCloseAsync
(
Document
document
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
public
Task
AnalyzeSyntaxAsync
(
Document
document
,
InvocationReasons
reasons
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
public
Task
AnalyzeProjectAsync
(
Project
project
,
bool
semanticsChanged
,
InvocationReasons
reasons
,
CancellationToken
cancellationToken
)
{
return
Task
.
CompletedTask
;
}
#
endregion
}
}
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/DesignerAttributeState.cs
已删除
100644 → 0
浏览文件 @
c0a1d1ec
// 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
;
using
System.Collections.Concurrent
;
using
System.IO
;
using
System.Threading
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
using
Microsoft.CodeAnalysis.SolutionCrawler.State
;
using
Roslyn.Utilities
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute
{
internal
partial
class
DesignerAttributeIncrementalAnalyzer
:
IIncrementalAnalyzer
{
private
class
DesignerAttributeState
:
AbstractDocumentAnalyzerState
<
Data
>
{
private
const
string
FormatVersion
=
"2"
;
/// <summary>
/// remember last time what we reported
/// </summary>
private
readonly
ConcurrentDictionary
<
DocumentId
,
string
>
_lastReported
=
new
ConcurrentDictionary
<
DocumentId
,
string
>(
concurrencyLevel
:
2
,
capacity
:
10
);
public
bool
Update
(
DocumentId
id
,
string
designerAttributeArgument
)
{
if
(
_lastReported
.
TryGetValue
(
id
,
out
var
lastReported
)
&&
lastReported
==
designerAttributeArgument
)
{
// nothing is actually updated
return
false
;
}
// value updated
_lastReported
[
id
]
=
designerAttributeArgument
;
return
true
;
}
protected
override
string
StateName
{
get
{
return
"<DesignerAttribute>"
;
}
}
protected
override
int
GetCount
(
Data
data
)
{
return
1
;
}
protected
override
Data
TryGetExistingData
(
Stream
stream
,
Document
value
,
CancellationToken
cancellationToken
)
{
using
var
reader
=
ObjectReader
.
TryGetReader
(
stream
,
leaveOpen
:
true
,
cancellationToken
);
if
(
reader
!=
null
)
{
var
format
=
reader
.
ReadString
();
if
(
string
.
Equals
(
format
,
FormatVersion
,
StringComparison
.
InvariantCulture
))
{
var
textVersion
=
VersionStamp
.
ReadFrom
(
reader
);
var
dataVersion
=
VersionStamp
.
ReadFrom
(
reader
);
var
designerAttributeArgument
=
reader
.
ReadString
();
return
new
Data
(
textVersion
,
dataVersion
,
designerAttributeArgument
);
}
}
return
null
;
}
protected
override
void
WriteTo
(
Stream
stream
,
Data
data
,
CancellationToken
cancellationToken
)
{
using
var
writer
=
new
ObjectWriter
(
stream
,
leaveOpen
:
true
,
cancellationToken
);
writer
.
WriteString
(
FormatVersion
);
data
.
TextVersion
.
WriteTo
(
writer
);
data
.
SemanticVersion
.
WriteTo
(
writer
);
writer
.
WriteString
(
data
.
DesignerAttributeArgument
);
}
public
override
bool
Remove
(
DocumentId
id
)
{
// forget what I have reported
_lastReported
.
TryRemove
(
id
,
out
_
);
return
base
.
Remove
(
id
);
}
}
}
}
src/
Features/Core/Portable/DesignerAttributes
/IDesignerAttributeService.cs
→
src/
VisualStudio/Core/Def/Implementation/DesignerAttribute
/IDesignerAttributeService.cs
浏览文件 @
6895112f
...
...
@@ -3,13 +3,20 @@
// See the LICENSE file in the project root for more information.
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Host
;
namespace
Microsoft.
CodeAnalysis.DesignerAttributes
namespace
Microsoft.
VisualStudio.LanguageServices.Implementation.DesignerAttribute
{
internal
interface
IDesignerAttributeService
:
ILanguageService
/// <summary>
/// In process service responsible for listening to OOP notifications whether or not a file is
/// designable and then notifying the respective project systems about that information.
/// </summary>
internal
interface
IDesignerAttributeService
:
IWorkspaceService
{
Task
<
DesignerAttributeResult
>
ScanDesignerAttributesAsync
(
Document
document
,
CancellationToken
cancellationToken
);
/// <summary>
/// Called by a host to let this service know that it should start background
/// analysis of the workspace to determine which classes are designable.
/// </summary>
void
Start
(
CancellationToken
cancellationToken
);
}
}
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs
0 → 100644
浏览文件 @
6895112f
// 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.Concurrent
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.DesignerAttribute
;
using
Microsoft.CodeAnalysis.Editor
;
using
Microsoft.CodeAnalysis.Editor.Shared.Utilities
;
using
Microsoft.CodeAnalysis.ErrorReporting
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.CodeAnalysis.Remote
;
using
Microsoft.CodeAnalysis.Shared.TestHooks
;
using
Microsoft.VisualStudio.Designer.Interfaces
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
using
Microsoft.VisualStudio.Shell.Interop
;
using
Microsoft.VisualStudio.Shell.Services
;
using
Roslyn.Utilities
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute
{
internal
class
VisualStudioDesignerAttributeService
:
ForegroundThreadAffinitizedObject
,
IDesignerAttributeService
,
IDesignerAttributeListener
{
private
readonly
VisualStudioWorkspaceImpl
_workspace
;
/// <summary>
/// Used so we can switch over to the UI thread for communicating with legacy projects that
/// require that.
/// </summary>
private
readonly
IThreadingContext
_threadingContext
;
/// <summary>
/// Used to acquire the legacy project designer service.
/// </summary>
private
readonly
IServiceProvider
_serviceProvider
;
/// <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>
/// Cache from project to the CPS designer service for it. Computed on demand (which
/// requires using the UI thread), but then cached for all subsequent notifications about
/// that project.
/// </summary>
private
readonly
ConcurrentDictionary
<
ProjectId
,
IProjectItemDesignerTypeUpdateService
?>
_cpsProjects
=
new
ConcurrentDictionary
<
ProjectId
,
IProjectItemDesignerTypeUpdateService
?>();
/// <summary>
/// Cached designer service for notifying legacy projects about designer atttributes.
/// </summary>
private
IVSMDDesignerService
?
_legacyDesignerService
;
// We'll get notifications from the OOP server about new attribute arguments. Batch those
// notifications up and deliver them to VS every second.
#
region
protected
by
lock
/// <summary>
/// Lock we will use to ensure the remainder of these fields can be accessed in a threadsafe
/// manner. When OOP calls back into us, we'll place the data it produced into
/// <see cref="_updatedInfos"/>. We'll then kick of a task to process this in the future if
/// we don't already have an existing task in flight for that.
/// </summary>
private
readonly
object
_gate
=
new
object
();
/// <summary>
/// Data produced by OOP that we want to process in our next update task.
/// </summary>
private
readonly
List
<
DesignerInfo
>
_updatedInfos
=
new
List
<
DesignerInfo
>();
/// <summary>
/// Task kicked off to do the next batch of processing of <see cref="_updatedInfos"/>. These
/// tasks form a chain so that the next task only processes when the previous one completes.
/// </summary>
private
Task
_updateTask
=
Task
.
CompletedTask
;
/// <summary>
/// Whether or not there is an existing task in flight that will process the current batch
/// of <see cref="_updatedInfos"/>. If there is an existing in flight task, we don't need
/// to kick off a new one if we receive more notifications before it runs.
/// </summary>
private
bool
_taskInFlight
=
false
;
#
endregion
public
VisualStudioDesignerAttributeService
(
VisualStudioWorkspaceImpl
workspace
,
IThreadingContext
threadingContext
,
IServiceProvider
serviceProvider
)
:
base
(
threadingContext
)
{
_workspace
=
workspace
;
_threadingContext
=
threadingContext
;
_serviceProvider
=
serviceProvider
;
_workspace
.
WorkspaceChanged
+=
OnWorkspaceChanged
;
}
private
void
OnWorkspaceChanged
(
object
sender
,
WorkspaceChangeEventArgs
e
)
{
if
(
e
.
Kind
==
WorkspaceChangeKind
.
ProjectRemoved
)
_cpsProjects
.
TryRemove
(
e
.
ProjectId
,
out
_
);
}
void
IDesignerAttributeService
.
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
)
{
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
.
RemoteDesignerAttributeService
,
callbackTarget
:
this
,
cancellationToken
).
ConfigureAwait
(
false
);
if
(
_keepAliveSession
==
null
)
return
;
// Now kick off scanning in the OOP process.
var
success
=
await
_keepAliveSession
.
TryInvokeAsync
(
nameof
(
IRemoteDesignerAttributeService
.
StartScanningForDesignerAttributesAsync
),
solution
:
null
,
arguments
:
Array
.
Empty
<
object
>(),
cancellationToken
).
ConfigureAwait
(
false
);
}
/// <summary>
/// Callback from the OOP service back into us.
/// </summary>
public
Task
RegisterDesignerAttributesAsync
(
IList
<
DesignerInfo
>
attributeInfos
,
CancellationToken
cancellationToken
)
{
lock
(
_gate
)
{
// add our work to the set we'll process in the next batch.
_updatedInfos
.
AddRange
(
attributeInfos
);
if
(!
_taskInFlight
)
{
// No in-flight task. Kick one off to process these messages a second from now.
// We always attach the task to the previous one so that notifications to the ui
// follow the same order as the notification the OOP server sent to us.
_updateTask
=
_updateTask
.
ContinueWithAfterDelayFromAsync
(
_
=>
NotifyProjectSystemAsync
(
cancellationToken
),
cancellationToken
,
1000
/*ms*/
,
TaskContinuationOptions
.
RunContinuationsAsynchronously
,
TaskScheduler
.
Default
);
_taskInFlight
=
true
;
}
}
return
Task
.
CompletedTask
;
}
private
async
Task
NotifyProjectSystemAsync
(
CancellationToken
cancellationToken
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
using
var
_1
=
ArrayBuilder
<
DesignerInfo
>.
GetInstance
(
out
var
attributeInfos
);
AddInfosAndResetQueue
(
attributeInfos
);
// Now, group all the notifications by project and update all the projects in parallel.
using
var
_2
=
ArrayBuilder
<
Task
>.
GetInstance
(
out
var
tasks
);
foreach
(
var
group
in
attributeInfos
.
GroupBy
(
a
=>
a
.
DocumentId
.
ProjectId
))
{
cancellationToken
.
ThrowIfCancellationRequested
();
tasks
.
Add
(
NotifyProjectSystemAsync
(
group
.
Key
,
group
,
cancellationToken
));
}
// Wait until all project updates have happened before processing the next batch.
await
Task
.
WhenAll
(
tasks
).
ConfigureAwait
(
false
);
}
private
void
AddInfosAndResetQueue
(
ArrayBuilder
<
DesignerInfo
>
attributeInfos
)
{
using
var
_
=
PooledHashSet
<
DocumentId
>.
GetInstance
(
out
var
seenDocumentIds
);
lock
(
_gate
)
{
// walk the set of updates in reverse, and ignore documents if we see them a second
// time. This ensures that if we're batching up multiple notifications for the same
// document, that we only bother processing the last one since it should beat out
// all the prior ones.
for
(
var
i
=
_updatedInfos
.
Count
-
1
;
i
>=
0
;
i
--)
{
var
designerArg
=
_updatedInfos
[
i
];
if
(
seenDocumentIds
.
Add
(
designerArg
.
DocumentId
))
attributeInfos
.
Add
(
designerArg
);
}
// mark there being no existing update task so that the next OOP notification will
// kick one off.
_updatedInfos
.
Clear
();
_taskInFlight
=
false
;
}
}
private
async
Task
NotifyProjectSystemAsync
(
ProjectId
projectId
,
IEnumerable
<
DesignerInfo
>
attributeInfos
,
CancellationToken
cancellationToken
)
{
// Delegate to the CPS or legacy notification services as necessary.
var
cpsUpdateService
=
await
GetUpdateServiceIfCpsProjectAsync
(
projectId
,
cancellationToken
).
ConfigureAwait
(
false
);
var
task
=
cpsUpdateService
==
null
?
NotifyLegacyProjectSystemAsync
(
projectId
,
attributeInfos
,
cancellationToken
)
:
NotifyCpsProjectSystemAsync
(
cpsUpdateService
,
attributeInfos
,
cancellationToken
);
await
task
.
ConfigureAwait
(
false
);
}
private
async
Task
NotifyLegacyProjectSystemAsync
(
ProjectId
projectId
,
IEnumerable
<
DesignerInfo
>
attributeInfos
,
CancellationToken
cancellationToken
)
{
// legacy project system can only be talked to on the UI thread.
await
_threadingContext
.
JoinableTaskFactory
.
SwitchToMainThreadAsync
(
alwaysYield
:
true
,
cancellationToken
);
cancellationToken
.
ThrowIfCancellationRequested
();
AssertIsForeground
();
var
designerService
=
_legacyDesignerService
??=
(
IVSMDDesignerService
)
_serviceProvider
.
GetService
(
typeof
(
SVSMDDesignerService
));
if
(
designerService
==
null
)
return
;
var
hierarchy
=
_workspace
.
GetHierarchy
(
projectId
);
if
(
hierarchy
==
null
)
return
;
foreach
(
var
info
in
attributeInfos
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
NotifyLegacyProjectSystemOnUIThread
(
designerService
,
hierarchy
,
info
);
}
}
private
void
NotifyLegacyProjectSystemOnUIThread
(
IVSMDDesignerService
designerService
,
IVsHierarchy
hierarchy
,
DesignerInfo
info
)
{
this
.
AssertIsForeground
();
var
itemId
=
hierarchy
.
TryGetItemId
(
info
.
FilePath
);
if
(
itemId
==
VSConstants
.
VSITEMID_NIL
)
return
;
// PERF: Avoid sending the message if the project system already has the current value.
if
(
ErrorHandler
.
Succeeded
(
hierarchy
.
GetProperty
(
itemId
,
(
int
)
__VSHPROPID
.
VSHPROPID_ItemSubType
,
out
var
currentValue
)))
{
var
currentStringValue
=
string
.
IsNullOrEmpty
(
currentValue
as
string
)
?
null
:
(
string
)
currentValue
;
if
(
string
.
Equals
(
currentStringValue
,
info
.
Category
,
StringComparison
.
OrdinalIgnoreCase
))
return
;
}
try
{
designerService
.
RegisterDesignViewAttribute
(
hierarchy
,
(
int
)
itemId
,
dwClass
:
0
,
pwszAttributeValue
:
info
.
Category
);
}
catch
{
// DevDiv # 933717
// turns out RegisterDesignViewAttribute can throw in certain cases such as a file failed to be checked out by source control
// or IVSHierarchy failed to set a property for this project
//
// just swallow it. don't crash VS.
}
}
private
async
Task
NotifyCpsProjectSystemAsync
(
IProjectItemDesignerTypeUpdateService
updateService
,
IEnumerable
<
DesignerInfo
>
attributeInfos
,
CancellationToken
cancellationToken
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
// Broadcast all the information about all the documents in parallel to CPS.
using
var
_
=
ArrayBuilder
<
Task
>.
GetInstance
(
out
var
tasks
);
foreach
(
var
info
in
attributeInfos
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
tasks
.
Add
(
NotifyCpsProjectSystemAsync
(
updateService
,
info
,
cancellationToken
));
}
await
Task
.
WhenAll
(
tasks
).
ConfigureAwait
(
false
);
}
private
async
Task
NotifyCpsProjectSystemAsync
(
IProjectItemDesignerTypeUpdateService
updateService
,
DesignerInfo
info
,
CancellationToken
cancellationToken
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
try
{
await
updateService
.
SetProjectItemDesignerTypeAsync
(
info
.
FilePath
,
info
.
Category
).
ConfigureAwait
(
false
);
}
catch
(
ObjectDisposedException
)
{
// we might call update service after project is already removed and get object disposed exception.
// we will catch the exception and ignore.
// see this PR for more detail - https://github.com/dotnet/roslyn/pull/35383
}
}
private
async
Task
<
IProjectItemDesignerTypeUpdateService
?>
GetUpdateServiceIfCpsProjectAsync
(
ProjectId
projectId
,
CancellationToken
cancellationToken
)
{
if
(!
_cpsProjects
.
TryGetValue
(
projectId
,
out
var
updateService
))
{
await
_threadingContext
.
JoinableTaskFactory
.
SwitchToMainThreadAsync
(
alwaysYield
:
true
,
cancellationToken
);
cancellationToken
.
ThrowIfCancellationRequested
();
this
.
AssertIsForeground
();
updateService
=
ComputeUpdateService
();
_cpsProjects
.
TryAdd
(
projectId
,
updateService
);
}
return
updateService
;
IProjectItemDesignerTypeUpdateService
?
ComputeUpdateService
()
{
if
(!
_workspace
.
IsCPSProject
(
projectId
))
return
null
;
var
vsProject
=
(
IVsProject
?)
_workspace
.
GetHierarchy
(
projectId
);
if
(
vsProject
==
null
)
return
null
;
if
(
ErrorHandler
.
Failed
(
vsProject
.
GetItemContext
((
uint
)
VSConstants
.
VSITEMID
.
Root
,
out
var
projectServiceProvider
)))
return
null
;
var
serviceProvider
=
new
Shell
.
ServiceProvider
(
projectServiceProvider
);
return
serviceProvider
.
GetService
(
typeof
(
IProjectItemDesignerTypeUpdateService
))
as
IProjectItemDesignerTypeUpdateService
;
}
}
}
}
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/
DesignerAttributeIncrementalAnalyzerProvider
.cs
→
src/VisualStudio/Core/Def/Implementation/DesignerAttribute/
VisualStudioDesignerAttributeServiceFactory
.cs
浏览文件 @
6895112f
...
...
@@ -4,44 +4,36 @@
using
System
;
using
System.Composition
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.Editor
;
using
Microsoft.CodeAnalysis.Editor.Shared.Utilities
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.Host.Mef
;
using
Microsoft.CodeAnalysis.Shared.TestHooks
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
using
Microsoft.VisualStudio.Shell
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute
{
[
Export
IncrementalAnalyzerProvider
(
Name
,
new
[]
{
WorkspaceKind
.
Host
}
),
Shared
]
internal
class
DesignerAttributeIncrementalAnalyzerProvider
:
IIncrementalAnalyzerProvider
[
Export
WorkspaceServiceFactory
(
typeof
(
IDesignerAttributeService
),
ServiceLayer
.
Host
),
Shared
]
internal
class
VisualStudioDesignerAttributeServiceFactory
:
IWorkspaceServiceFactory
{
public
const
string
Name
=
nameof
(
DesignerAttributeIncrementalAnalyzerProvider
);
private
readonly
IThreadingContext
_threadingContext
;
private
readonly
IServiceProvider
_serviceProvider
;
private
readonly
IForegroundNotificationService
_notificationService
;
private
readonly
IAsynchronousOperationListenerProvider
_listenerProvider
;
[
ImportingConstructor
]
[
Obsolete
(
MefConstruction
.
ImportingConstructorMessage
,
error
:
true
)]
public
DesignerAttributeIncrementalAnalyzerProvider
(
public
VisualStudioDesignerAttributeServiceFactory
(
IThreadingContext
threadingContext
,
SVsServiceProvider
serviceProvider
,
IForegroundNotificationService
notificationService
,
IAsynchronousOperationListenerProvider
listenerProvider
)
Shell
.
SVsServiceProvider
serviceProvider
)
{
_threadingContext
=
threadingContext
;
_serviceProvider
=
serviceProvider
;
_notificationService
=
notificationService
;
_listenerProvider
=
listenerProvider
;
}
public
I
IncrementalAnalyzer
CreateIncrementalAnalyzer
(
CodeAnalysis
.
Workspace
workspace
)
public
I
WorkspaceService
CreateService
(
HostWorkspaceServices
workspaceServices
)
{
return
new
DesignerAttributeIncrementalAnalyzer
(
_threadingContext
,
_serviceProvider
,
_notificationService
,
_listenerProvider
);
if
(!(
workspaceServices
.
Workspace
is
VisualStudioWorkspaceImpl
workspace
))
return
null
;
return
new
VisualStudioDesignerAttributeService
(
workspace
,
_threadingContext
,
_serviceProvider
);
}
}
}
src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs
浏览文件 @
6895112f
...
...
@@ -423,10 +423,13 @@ internal override bool CanRenameFilesDuringCodeActions(CodeAnalysis.Project proj
=>
!
IsCPSProject
(
project
);
internal
bool
IsCPSProject
(
CodeAnalysis
.
Project
project
)
=>
IsCPSProject
(
project
.
Id
);
internal
bool
IsCPSProject
(
ProjectId
projectId
)
{
_foregroundObject
.
AssertIsForeground
();
if
(
this
.
TryGetHierarchy
(
project
.
Id
,
out
var
hierarchy
))
if
(
this
.
TryGetHierarchy
(
projectId
,
out
var
hierarchy
))
{
// Currently renaming files in CPS projects (i.e. .NET Core) doesn't work proprey.
// This is because the remove/add of the documents in CPS is not synchronous
...
...
src/VisualStudio/Core/Def/RoslynPackage.cs
浏览文件 @
6895112f
...
...
@@ -22,6 +22,7 @@
using
Microsoft.VisualStudio.LanguageServices.ColorSchemes
;
using
Microsoft.VisualStudio.LanguageServices.Experimentation
;
using
Microsoft.VisualStudio.LanguageServices.Implementation
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.Interactive
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
;
...
...
@@ -154,6 +155,11 @@ private async Task LoadComponentsBackgroundAsync(CancellationToken cancellationT
{
await
experiment
.
InitializeAsync
().
ConfigureAwait
(
true
);
}
// Load the designer attribute service and tell it to start watching the solution for
// designable files.
var
designerAttributeService
=
_workspace
.
Services
.
GetService
<
IDesignerAttributeService
>();
designerAttributeService
.
Start
(
this
.
DisposalToken
);
}
private
async
Task
LoadInteractiveMenusAsync
(
CancellationToken
cancellationToken
)
...
...
src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs
浏览文件 @
6895112f
...
...
@@ -9,7 +9,7 @@
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.DesignerAttribute
s
;
using
Microsoft.CodeAnalysis.DesignerAttribute
;
using
Microsoft.CodeAnalysis.Diagnostics
;
using
Microsoft.CodeAnalysis.Editor.UnitTests.Extensions
;
using
Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
;
...
...
@@ -17,10 +17,14 @@
using
Microsoft.CodeAnalysis.Options
;
using
Microsoft.CodeAnalysis.Remote
;
using
Microsoft.CodeAnalysis.Remote.DebugUtil
;
using
Microsoft.CodeAnalysis.Remote.Shared
;
using
Microsoft.CodeAnalysis.Serialization
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
using
Microsoft.CodeAnalysis.Test.Utilities
;
using
Microsoft.CodeAnalysis.Text
;
using
Microsoft.CodeAnalysis.TodoComments
;
using
Microsoft.CodeAnalysis.UnitTests
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute
;
using
Nerdbank
;
using
Roslyn.Test.Utilities.Remote
;
using
Roslyn.Utilities
;
...
...
@@ -152,27 +156,74 @@ public async Task TestTodoComments()
}
}
private
static
async
Task
<
SolutionService
>
GetSolutionServiceAsync
(
Solution
solution
,
Dictionary
<
Checksum
,
object
>
map
=
null
)
{
// make sure checksum is calculated
await
solution
.
State
.
GetChecksumAsync
(
CancellationToken
.
None
);
map
??=
new
Dictionary
<
Checksum
,
object
>();
await
solution
.
AppendAssetMapAsync
(
map
,
CancellationToken
.
None
);
var
sessionId
=
0
;
var
storage
=
new
AssetStorage
();
_
=
new
SimpleAssetSource
(
storage
,
map
);
var
remoteWorkspace
=
new
RemoteWorkspace
(
applyStartupOptions
:
false
);
return
new
SolutionService
(
new
AssetProvider
(
sessionId
,
storage
,
remoteWorkspace
.
Services
.
GetService
<
ISerializerService
>()));
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
RemoteHost
)]
public
async
Task
TestDesignerAttributes
()
{
var
code
=
@"[System.ComponentModel.DesignerCategory(""Form"")]
class Test { }"
;
using
(
var
workspace
=
TestWorkspace
.
CreateCSharp
(
code
))
{
var
client
=
(
InProcRemoteHostClient
)
await
InProcRemoteHostClient
.
CreateAsync
(
workspace
,
runCacheCleanup
:
false
);
using
var
workspace
=
TestWorkspace
.
CreateCSharp
(
@"[System.ComponentModel.DesignerCategory(""Form"")]
class Test { }"
);
var
solution
=
workspace
.
CurrentSolution
;
var
cancellationTokenSource
=
new
CancellationTokenSource
()
;
var
result
=
await
client
.
TryRunRemoteAsync
<
DesignerAttributeResult
>(
WellKnownServiceHubServices
.
CodeAnalysisService
,
nameof
(
IRemoteDesignerAttributeService
.
ScanDesignerAttributesAsync
),
solution
,
new
[]
{
solution
.
Projects
.
First
().
DocumentIds
.
First
()
},
callbackTarget
:
null
,
CancellationToken
.
None
);
var
solution
=
workspace
.
CurrentSolution
;
Assert
.
Equal
(
"Form"
,
result
.
Value
.
DesignerAttributeArgument
);
// Ensure remote workspace is in sync with normal workspace.
var
solutionService
=
await
GetSolutionServiceAsync
(
solution
);
var
solutionChecksum
=
await
solution
.
State
.
GetChecksumAsync
(
CancellationToken
.
None
);
await
solutionService
.
UpdatePrimaryWorkspaceAsync
(
solutionChecksum
,
solution
.
WorkspaceVersion
,
CancellationToken
.
None
);
var
callback
=
new
DesignerListener
();
using
var
client
=
await
InProcRemoteHostClient
.
CreateAsync
(
workspace
,
runCacheCleanup
:
false
);
var
session
=
await
client
.
TryCreateKeepAliveSessionAsync
(
WellKnownServiceHubServices
.
RemoteDesignerAttributeService
,
callback
,
cancellationTokenSource
.
Token
);
var
invokeTask
=
session
.
TryInvokeAsync
(
nameof
(
IRemoteDesignerAttributeService
.
StartScanningForDesignerAttributesAsync
),
solution
:
null
,
arguments
:
Array
.
Empty
<
object
>(),
cancellationTokenSource
.
Token
);
var
infos
=
await
callback
.
Infos
;
Assert
.
Equal
(
1
,
infos
.
Count
);
var
info
=
infos
[
0
];
Assert
.
Equal
(
"Form"
,
info
.
Category
);
Assert
.
Equal
(
solution
.
Projects
.
Single
().
Documents
.
Single
().
Id
,
info
.
DocumentId
);
cancellationTokenSource
.
Cancel
();
await
invokeTask
;
}
private
class
DesignerListener
:
IDesignerAttributeListener
{
private
readonly
TaskCompletionSource
<
IList
<
DesignerInfo
>>
_infosSource
=
new
TaskCompletionSource
<
IList
<
DesignerInfo
>>();
public
Task
<
IList
<
DesignerInfo
>>
Infos
=>
_infosSource
.
Task
;
public
Task
RegisterDesignerAttributesAsync
(
IList
<
DesignerInfo
>
infos
,
CancellationToken
cancellationToken
)
{
_infosSource
.
SetResult
(
infos
);
return
Task
.
CompletedTask
;
}
}
...
...
src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs
浏览文件 @
6895112f
...
...
@@ -10,7 +10,6 @@
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
;
using
Microsoft.CodeAnalysis.Execution
;
using
Microsoft.CodeAnalysis.Remote
;
using
Microsoft.CodeAnalysis.Remote.DebugUtil
;
using
Microsoft.CodeAnalysis.Remote.Shared
;
...
...
@@ -19,7 +18,6 @@
using
Microsoft.CodeAnalysis.Test.Utilities
;
using
Microsoft.CodeAnalysis.Text
;
using
Roslyn.Utilities
;
using
Roslyn.VisualStudio.Next.UnitTests.Mocks
;
using
Xunit
;
namespace
Roslyn.VisualStudio.Next.UnitTests.Remote
...
...
src/VisualStudio/Setup/source.extension.vsixmanifest
浏览文件 @
6895112f
...
...
@@ -34,11 +34,13 @@
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteHost.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynSnapshot.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynCodeAnalysis.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteDesignerAttributeService.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteSymbolSearchUpdateEngine.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynLanguageServer.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteHost64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynSnapshot64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynCodeAnalysis64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteDesignerAttributeService64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynRemoteSymbolSearchUpdateEngine64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.ServiceHub.Service"
d:Source=
"File"
Path=
"roslynLanguageServer64.servicehub.service.json"
/>
<Asset
Type=
"Microsoft.VisualStudio.MefComponent"
d:Source=
"Project"
d:ProjectName=
"BasicVisualStudio"
Path=
"|BasicVisualStudio|"
/>
...
...
src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeHelpers.cs
0 → 100644
浏览文件 @
6895112f
// 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.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.LanguageServices
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
namespace
Microsoft.CodeAnalysis.DesignerAttribute
{
internal
static
class
DesignerAttributeHelpers
{
public
static
async
Task
<
string
?>
ComputeDesignerAttributeCategoryAsync
(
INamedTypeSymbol
?
designerCategoryType
,
Document
document
,
CancellationToken
cancellationToken
)
{
// simple case. If there's no DesignerCategory type in this compilation, then there's
// definitely no designable types. Just immediately bail out.
if
(
designerCategoryType
==
null
)
return
null
;
var
root
=
await
document
.
GetRequiredSyntaxRootAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
syntaxFacts
=
document
.
GetRequiredLanguageService
<
ISyntaxFactsService
>();
// Legacy behavior. We only register the designer info for the first non-nested class
// in the file.
var
firstClass
=
FindFirstNonNestedClass
(
syntaxFacts
,
syntaxFacts
.
GetMembersOfCompilationUnit
(
root
),
cancellationToken
);
if
(
firstClass
==
null
)
return
null
;
var
semanticModel
=
await
document
.
GetRequiredSemanticModelAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
firstClassType
=
(
INamedTypeSymbol
)
semanticModel
.
GetDeclaredSymbol
(
firstClass
,
cancellationToken
);
return
TryGetDesignerCategory
(
firstClassType
,
designerCategoryType
,
cancellationToken
);
}
private
static
string
?
TryGetDesignerCategory
(
INamedTypeSymbol
classType
,
INamedTypeSymbol
designerCategoryType
,
CancellationToken
cancellationToken
)
{
foreach
(
var
type
in
classType
.
GetBaseTypesAndThis
())
{
cancellationToken
.
ThrowIfCancellationRequested
();
// if it has designer attribute, set it
var
attribute
=
type
.
GetAttributes
().
FirstOrDefault
(
d
=>
designerCategoryType
.
Equals
(
d
.
AttributeClass
));
if
(
attribute
?.
ConstructorArguments
.
Length
==
1
)
return
GetArgumentString
(
attribute
.
ConstructorArguments
[
0
]);
}
return
null
;
}
private
static
SyntaxNode
?
FindFirstNonNestedClass
(
ISyntaxFactsService
syntaxFacts
,
SyntaxList
<
SyntaxNode
>
members
,
CancellationToken
cancellationToken
)
{
foreach
(
var
member
in
members
)
{
cancellationToken
.
ThrowIfCancellationRequested
();
if
(
syntaxFacts
.
IsNamespaceDeclaration
(
member
))
{
var
firstClass
=
FindFirstNonNestedClass
(
syntaxFacts
,
syntaxFacts
.
GetMembersOfNamespaceDeclaration
(
member
),
cancellationToken
);
if
(
firstClass
!=
null
)
return
firstClass
;
}
else
if
(
syntaxFacts
.
IsClassDeclaration
(
member
))
{
return
member
;
}
}
return
null
;
}
private
static
string
?
GetArgumentString
(
TypedConstant
argument
)
{
if
(
argument
.
Type
==
null
||
argument
.
Type
.
SpecialType
!=
SpecialType
.
System_String
||
argument
.
IsNull
||
!(
argument
.
Value
is
string
stringValue
))
{
return
null
;
}
return
stringValue
.
Trim
();
}
}
}
src/
Features/Core/Portable/DesignerAttributes/DesignerAttributeResult
.cs
→
src/
Workspaces/Core/Portable/DesignerAttribute/DesignerInfo
.cs
浏览文件 @
6895112f
...
...
@@ -2,30 +2,28 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace
Microsoft.CodeAnalysis.DesignerAttributes
#
nullable
enable
namespace
Microsoft.CodeAnalysis.DesignerAttribute
{
internal
readonly
struct
DesignerAttributeResult
/// <summary>
/// Serialization typed used to pass information to/from OOP and VS.
/// </summary>
internal
struct
DesignerInfo
{
/// <summary>
///
Designer attribute string
///
The category specified in a <c>[DesignerCategory("...")]</c> attribute.
/// </summary>
public
string
DesignerAttributeArgument
{
get
;
}
public
string
?
Category
;
/// <summary>
///
No designer attribute due to errors in the document
///
The document this <see cref="Category"/> applies to.
/// </summary>
public
bool
ContainsErrors
{
get
;
}
public
DocumentId
DocumentId
;
/// <summary>
///
The document asked is applicable for the designer attribute
///
Path for this <see cref="DocumentId"/>.
/// </summary>
public
bool
Applicable
{
get
;
}
public
DesignerAttributeResult
(
string
designerAttributeArgument
,
bool
containsErrors
,
bool
applicable
)
{
DesignerAttributeArgument
=
designerAttributeArgument
;
ContainsErrors
=
containsErrors
;
Applicable
=
applicable
;
}
public
string
FilePath
;
}
}
src/Workspaces/Core/Portable/DesignerAttribute/IDesignerAttributeListener.cs
0 → 100644
浏览文件 @
6895112f
// 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.Generic
;
using
System.Threading
;
using
System.Threading.Tasks
;
namespace
Microsoft.CodeAnalysis.DesignerAttribute
{
/// <summary>
/// Callback the host (VS) passes to the OOP service to allow it to send batch notifications
/// about designer attribute info. There is no guarantee that the host will have done anything
/// with this data when the callback returns, only that it will try to inform the project system
/// about the designer attribute info in the future.
/// </summary>
internal
interface
IDesignerAttributeListener
{
Task
RegisterDesignerAttributesAsync
(
IList
<
DesignerInfo
>
infos
,
CancellationToken
cancellationToken
);
}
}
src/
Features/Core/Portable/DesignerAttributes
/IRemoteDesignerAttributeService.cs
→
src/
Workspaces/Core/Portable/DesignerAttribute
/IRemoteDesignerAttributeService.cs
浏览文件 @
6895112f
...
...
@@ -2,14 +2,23 @@
// 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.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.Remote
;
using
Microsoft.CodeAnalysis.ErrorReporting
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.DesignerAttribute
s
namespace
Microsoft.CodeAnalysis.DesignerAttribute
{
/// <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
IRemoteDesignerAttributeService
{
Task
<
DesignerAttributeResult
>
ScanDesignerAttributesAsync
(
PinnedSolutionInfo
solutionInfo
,
DocumentId
documentId
,
CancellationToken
cancellationToke
n
);
Task
StartScanningForDesignerAttributesAsync
(
CancellationToken
cancellatio
n
);
}
}
src/Workspaces/Core/Portable/Remote/WellKnownServiceHubServices.cs
浏览文件 @
6895112f
...
...
@@ -12,6 +12,7 @@ public static void Set64bit(bool x64)
SnapshotService
=
"roslynSnapshot"
+
bit
;
CodeAnalysisService
=
"roslynCodeAnalysis"
+
bit
;
RemoteDesignerAttributeService
=
"roslynRemoteDesignerAttributeService"
+
bit
;
RemoteSymbolSearchUpdateEngine
=
"roslynRemoteSymbolSearchUpdateEngine"
+
bit
;
LanguageServer
=
"roslynLanguageServer"
+
bit
;
}
...
...
@@ -19,6 +20,7 @@ public static void Set64bit(bool x64)
public
static
string
SnapshotService
{
get
;
private
set
;
}
=
"roslynSnapshot"
;
public
static
string
CodeAnalysisService
{
get
;
private
set
;
}
=
"roslynCodeAnalysis"
;
public
static
string
RemoteSymbolSearchUpdateEngine
{
get
;
private
set
;
}
=
"roslynRemoteSymbolSearchUpdateEngine"
;
public
static
string
RemoteDesignerAttributeService
{
get
;
private
set
;
}
=
"roslynRemoteDesignerAttributeService"
;
public
static
string
LanguageServer
{
get
;
private
set
;
}
=
"roslynLanguageServer"
;
// these are OOP implementation itself should care. not features that consume OOP care
...
...
src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute_Names.cs
浏览文件 @
6895112f
...
...
@@ -13,7 +13,6 @@ internal partial class FeatureAttribute
public
const
string
Classification
=
nameof
(
Classification
);
public
const
string
CodeModel
=
nameof
(
CodeModel
);
public
const
string
CompletionSet
=
nameof
(
CompletionSet
);
public
const
string
DesignerAttribute
=
nameof
(
DesignerAttribute
);
public
const
string
DiagnosticService
=
nameof
(
DiagnosticService
);
public
const
string
EncapsulateField
=
nameof
(
EncapsulateField
);
public
const
string
ErrorList
=
nameof
(
ErrorList
);
...
...
src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_DesignerAttributes.cs
已删除
100644 → 0
浏览文件 @
c0a1d1ec
// 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.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.DesignerAttributes
;
using
Microsoft.CodeAnalysis.Execution
;
using
Microsoft.CodeAnalysis.Internal.Log
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Roslyn.Utilities
;
using
RoslynLogger
=
Microsoft
.
CodeAnalysis
.
Internal
.
Log
.
Logger
;
namespace
Microsoft.CodeAnalysis.Remote
{
// root level service for all Roslyn services
internal
partial
class
CodeAnalysisService
:
IRemoteDesignerAttributeService
{
/// <summary>
/// This is top level entry point for DesignerAttribute service from client (VS).
///
/// This will be called by ServiceHub/JsonRpc framework
/// </summary>
public
Task
<
DesignerAttributeResult
>
ScanDesignerAttributesAsync
(
PinnedSolutionInfo
solutionInfo
,
DocumentId
documentId
,
CancellationToken
cancellationToken
)
{
return
RunServiceAsync
(
async
()
=>
{
using
(
RoslynLogger
.
LogBlock
(
FunctionId
.
CodeAnalysisService_GetDesignerAttributesAsync
,
documentId
.
DebugName
,
cancellationToken
))
{
var
solution
=
await
GetSolutionAsync
(
solutionInfo
,
cancellationToken
).
ConfigureAwait
(
false
);
var
document
=
solution
.
GetDocument
(
documentId
);
var
service
=
document
.
GetLanguageService
<
IDesignerAttributeService
>();
if
(
service
!=
null
)
{
// todo comment service supported
return
await
service
.
ScanDesignerAttributesAsync
(
document
,
cancellationToken
).
ConfigureAwait
(
false
);
}
return
new
DesignerAttributeResult
(
designerAttributeArgument
:
null
,
containsErrors
:
true
,
applicable
:
false
);
}
},
cancellationToken
);
}
}
}
src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer.cs
0 → 100644
浏览文件 @
6895112f
// 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.Linq
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
Microsoft.CodeAnalysis.DesignerAttribute
;
using
Microsoft.CodeAnalysis.ErrorReporting
;
using
Microsoft.CodeAnalysis.Host
;
using
Microsoft.CodeAnalysis.PooledObjects
;
using
Microsoft.CodeAnalysis.Shared.Extensions
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.Remote
{
internal
sealed
partial
class
RemoteDesignerAttributeIncrementalAnalyzer
:
IncrementalAnalyzerBase
{
private
const
string
DataKey
=
"DesignerAttributeData"
;
/// <summary>
/// Channel back to VS to inform it of the designer attributes we discover.
/// </summary>
private
readonly
RemoteEndPoint
_endPoint
;
private
readonly
IPersistentStorageService
_storageService
;
public
RemoteDesignerAttributeIncrementalAnalyzer
(
Workspace
workspace
,
RemoteEndPoint
endPoint
)
{
_endPoint
=
endPoint
;
_storageService
=
workspace
.
Services
.
GetRequiredService
<
IPersistentStorageService
>();
}
public
override
Task
AnalyzeProjectAsync
(
Project
project
,
bool
semanticsChanged
,
InvocationReasons
reasons
,
CancellationToken
cancellationToken
)
=>
AnalyzeProjectAsync
(
project
,
specificDocument
:
null
,
cancellationToken
);
public
override
Task
AnalyzeDocumentAsync
(
Document
document
,
SyntaxNode
?
body
,
InvocationReasons
reasons
,
CancellationToken
cancellationToken
)
{
// don't need to reanalyze file if just a method body was edited. That can't
// affect designer attributes.
if
(
body
!=
null
)
return
Task
.
CompletedTask
;
// When we register our analyzer we will get called into for every document to
// 'reanalyze' them all. Ignore those as we would prefer to analyze the project
// en-mass.
if
(
reasons
.
Contains
(
PredefinedInvocationReasons
.
Reanalyze
))
return
Task
.
CompletedTask
;
return
AnalyzeProjectAsync
(
document
.
Project
,
document
,
cancellationToken
);
}
private
async
Task
AnalyzeProjectAsync
(
Project
project
,
Document
?
specificDocument
,
CancellationToken
cancellationToken
)
{
if
(!
project
.
SupportsCompilation
)
return
;
// We need to reanalyze the project whenever it (or any of its dependencies) have
// changed. We need to know about dependencies since if a downstream project adds the
// DesignerCategory attribute to a class, that can affect us when we examine the classes
// in this project.
var
projectVersion
=
await
project
.
GetDependentSemanticVersionAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
latestInfos
=
await
ComputeLatestInfosAsync
(
project
,
projectVersion
,
specificDocument
,
cancellationToken
).
ConfigureAwait
(
false
);
// Now get all the values that actually changed and notify VS about them. We don't need
// to tell it about the ones that didn't change since that will have no effect on the
// user experience.
//
// ! is safe here as `i.changed` implies `i.info` is non-null.
var
changedInfos
=
latestInfos
.
Where
(
i
=>
i
.
changed
).
Select
(
i
=>
i
.
info
!.
Value
).
ToList
();
if
(
changedInfos
.
Count
>
0
)
{
await
_endPoint
.
InvokeAsync
(
nameof
(
IDesignerAttributeListener
.
RegisterDesignerAttributesAsync
),
new
object
[]
{
changedInfos
},
cancellationToken
).
ConfigureAwait
(
false
);
}
// now that we've notified VS, persist all the infos we have (changed or otherwise) back
// to disk. We want to do this even when the data is unchanged so that our version
// stamps will be correct for the next time we come around to analyze this project.
//
// Note: we have a potential race condition here. Specifically, for simplicity, the VS
// side will return immediately, without actually notifying the project system. That
// means that we could persist the data to local storage that isn't in sync with what
// the project system knows about. i.e. if VS is closed or crashes before that
// information is persisted, then these two systems will be in disagreement. this is
// believed to not be a big issue given how small a time window this would be and how
// easy it would be to get out of that state (just edit the file).
await
PersistLatestInfosAsync
(
project
.
Solution
,
projectVersion
,
latestInfos
,
cancellationToken
).
ConfigureAwait
(
false
);
}
private
async
Task
PersistLatestInfosAsync
(
Solution
solution
,
VersionStamp
projectVersion
,
(
Document
,
DesignerInfo
?
info
,
bool
changed
)[]
latestInfos
,
CancellationToken
cancellationToken
)
{
using
var
storage
=
_storageService
.
GetStorage
(
solution
);
foreach
(
var
(
doc
,
info
,
_
)
in
latestInfos
)
{
// Skip documents that didn't change contents/version at all. No point in writing
// back out the exact same data as before.
if
(
info
==
null
)
continue
;
using
var
memoryStream
=
new
MemoryStream
();
using
var
writer
=
new
ObjectWriter
(
memoryStream
);
PersistInfoTo
(
writer
,
info
.
Value
,
projectVersion
);
memoryStream
.
Position
=
0
;
await
storage
.
WriteStreamAsync
(
doc
,
DataKey
,
memoryStream
,
cancellationToken
).
ConfigureAwait
(
false
);
}
}
private
async
Task
<(
Document
,
DesignerInfo
?
info
,
bool
changed
)[
]>
ComputeLatestInfosAsync
(
Project
project
,
VersionStamp
projectVersion
,
Document
?
specificDocument
,
CancellationToken
cancellationToken
)
{
using
var
storage
=
_storageService
.
GetStorage
(
project
.
Solution
);
var
compilation
=
await
project
.
GetRequiredCompilationAsync
(
cancellationToken
).
ConfigureAwait
(
false
);
var
designerCategoryType
=
compilation
.
DesignerCategoryAttributeType
();
using
var
_
=
ArrayBuilder
<
Task
<(
Document
,
DesignerInfo
?,
bool
changed
)>>.
GetInstance
(
out
var
tasks
);
foreach
(
var
document
in
project
.
Documents
)
{
// If we're only analyzing a specific document, then skip the rest.
if
(
specificDocument
!=
null
&&
document
!=
specificDocument
)
continue
;
tasks
.
Add
(
ComputeDesignerAttributeInfoAsync
(
storage
,
projectVersion
,
designerCategoryType
,
document
,
cancellationToken
));
}
return
await
Task
.
WhenAll
(
tasks
).
ConfigureAwait
(
false
);
}
private
async
Task
<(
Document
,
DesignerInfo
?,
bool
changed
)>
ComputeDesignerAttributeInfoAsync
(
IPersistentStorage
storage
,
VersionStamp
projectVersion
,
INamedTypeSymbol
?
designerCategoryType
,
Document
document
,
CancellationToken
cancellationToken
)
{
try
{
// If we don't have a path for this document, we cant proceed with it.
// We need that path to inform the project system which file we're referring to.
if
(
document
.
FilePath
==
null
)
return
default
;
// First check and see if we have stored information for this doc and if that
// information is up to date.
using
var
stream
=
await
storage
.
ReadStreamAsync
(
document
,
DataKey
,
cancellationToken
).
ConfigureAwait
(
false
);
using
var
reader
=
ObjectReader
.
TryGetReader
(
stream
,
cancellationToken
:
cancellationToken
);
var
persisted
=
TryReadPersistedInfo
(
reader
);
if
(
persisted
.
category
!=
null
&&
persisted
.
projectVersion
==
projectVersion
)
{
// We were able to read out the old data, and it matches our current project
// version. Just return back that nothing changed here. We won't tell VS about
// this, and we won't re-persist this later.
return
default
;
}
// We either haven't computed the designer info, or our data was out of date. We need
// So recompute here. Figure out what the current category is, and if that's different
// from what we previously stored.
var
category
=
await
DesignerAttributeHelpers
.
ComputeDesignerAttributeCategoryAsync
(
designerCategoryType
,
document
,
cancellationToken
).
ConfigureAwait
(
false
);
var
info
=
new
DesignerInfo
{
Category
=
category
,
DocumentId
=
document
.
Id
,
FilePath
=
document
.
FilePath
,
};
return
(
document
,
info
,
changed
:
category
!=
persisted
.
category
);
}
catch
(
Exception
e
)
when
(
FatalError
.
ReportWithoutCrashUnlessCanceled
(
e
))
{
return
default
;
}
}
}
}
src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzerProvider.cs
0 → 100644
浏览文件 @
6895112f
// 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
sealed
class
RemoteDesignerAttributeIncrementalAnalyzerProvider
:
IIncrementalAnalyzerProvider
{
private
readonly
RemoteEndPoint
_endPoint
;
public
RemoteDesignerAttributeIncrementalAnalyzerProvider
(
RemoteEndPoint
endPoint
)
{
_endPoint
=
endPoint
;
}
public
IIncrementalAnalyzer
CreateIncrementalAnalyzer
(
Workspace
workspace
)
=>
new
RemoteDesignerAttributeIncrementalAnalyzer
(
workspace
,
_endPoint
);
}
}
src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer_Serialization.cs
0 → 100644
浏览文件 @
6895112f
// 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
Microsoft.CodeAnalysis.DesignerAttribute
;
using
Microsoft.CodeAnalysis.ErrorReporting
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.Remote
{
internal
partial
class
RemoteDesignerAttributeIncrementalAnalyzer
{
/// <summary>
/// Our current serialization format. Increment whenever it changes so that we don't read
/// bogus data when reading older persisted data.
/// </summary>
private
const
string
SerializationFormat
=
"1"
;
private
static
(
string
?
category
,
VersionStamp
projectVersion
)
TryReadPersistedInfo
(
ObjectReader
reader
)
{
try
{
// if we couldn't get a reader then we have no persisted category/version to read out.
if
(
reader
==
null
)
return
default
;
// check to make sure whatever we persisted matches our current format for this info
// type. If not, then we can't read this out.
var
format
=
reader
.
ReadString
();
if
(
format
!=
SerializationFormat
)
return
default
;
// Looks good, pull out the stored data.
var
category
=
reader
.
ReadString
();
var
projectVersion
=
VersionStamp
.
ReadFrom
(
reader
);
return
(
category
,
projectVersion
);
}
catch
(
Exception
e
)
when
(
FatalError
.
ReportWithoutCrash
(
e
))
{
// can happen if the DB got edited outside of our control.
return
default
;
}
}
private
static
void
PersistInfoTo
(
ObjectWriter
writer
,
DesignerInfo
info
,
VersionStamp
projectVersion
)
{
writer
.
WriteString
(
SerializationFormat
);
writer
.
WriteString
(
info
.
Category
);
projectVersion
.
WriteTo
(
writer
);
}
}
}
src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeService.cs
0 → 100644
浏览文件 @
6895112f
// 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.DesignerAttribute
;
using
Microsoft.CodeAnalysis.SolutionCrawler
;
namespace
Microsoft.CodeAnalysis.Remote
{
internal
sealed
class
RemoteDesignerAttributeService
:
ServiceBase
,
IRemoteDesignerAttributeService
{
public
RemoteDesignerAttributeService
(
Stream
stream
,
IServiceProvider
serviceProvider
)
:
base
(
serviceProvider
,
stream
)
{
StartService
();
}
public
Task
StartScanningForDesignerAttributesAsync
(
CancellationToken
cancellation
)
{
return
RunServiceAsync
(()
=>
{
var
registrationService
=
SolutionService
.
PrimaryWorkspace
.
Services
.
GetRequiredService
<
ISolutionCrawlerRegistrationService
>();
var
analyzerProvider
=
new
RemoteDesignerAttributeIncrementalAnalyzerProvider
(
this
.
EndPoint
);
registrationService
.
AddAnalyzerProvider
(
analyzerProvider
,
new
IncrementalAnalyzerProviderMetadata
(
nameof
(
RemoteDesignerAttributeIncrementalAnalyzerProvider
),
highPriorityForActiveFile
:
false
,
workspaceKinds
:
WorkspaceKind
.
RemoteWorkspace
));
return
Task
.
CompletedTask
;
},
cancellation
);
}
}
}
src/Workspaces/Remote/ServiceHub/Shared/RoslynJsonConverter.RoslynOnly.cs
浏览文件 @
6895112f
...
...
@@ -5,10 +5,8 @@
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Immutable
;
using
System.Linq
;
using
Microsoft.CodeAnalysis.AddImport
;
using
Microsoft.CodeAnalysis.CodeActions
;
using
Microsoft.CodeAnalysis.DesignerAttributes
;
using
Microsoft.CodeAnalysis.Diagnostics
;
using
Microsoft.CodeAnalysis.DocumentHighlighting
;
using
Microsoft.CodeAnalysis.Packaging
;
...
...
@@ -29,7 +27,6 @@ internal partial class AggregateJsonConverter : JsonConverter
Add
(
builder
,
new
TodoCommentDescriptorJsonConverter
());
Add
(
builder
,
new
TodoCommentJsonConverter
());
Add
(
builder
,
new
DesignerAttributeResultJsonConverter
());
Add
(
builder
,
new
PackageSourceJsonConverter
());
Add
(
builder
,
new
PackageWithTypeResultJsonConverter
());
...
...
@@ -105,39 +102,6 @@ protected override void WriteValue(JsonWriter writer, TodoComment todoComment, J
}
}
private
class
DesignerAttributeResultJsonConverter
:
BaseJsonConverter
<
DesignerAttributeResult
>
{
protected
override
DesignerAttributeResult
ReadValue
(
JsonReader
reader
,
JsonSerializer
serializer
)
{
Contract
.
ThrowIfFalse
(
reader
.
TokenType
==
JsonToken
.
StartObject
);
var
designerAttributeArgument
=
ReadProperty
<
string
>(
reader
);
var
containsErrors
=
ReadProperty
<
bool
>(
reader
);
var
applicable
=
ReadProperty
<
bool
>(
reader
);
Contract
.
ThrowIfFalse
(
reader
.
Read
());
Contract
.
ThrowIfFalse
(
reader
.
TokenType
==
JsonToken
.
EndObject
);
return
new
DesignerAttributeResult
(
designerAttributeArgument
,
containsErrors
,
applicable
);
}
protected
override
void
WriteValue
(
JsonWriter
writer
,
DesignerAttributeResult
result
,
JsonSerializer
serializer
)
{
writer
.
WriteStartObject
();
writer
.
WritePropertyName
(
nameof
(
DesignerAttributeResult
.
DesignerAttributeArgument
));
writer
.
WriteValue
(
result
.
DesignerAttributeArgument
);
writer
.
WritePropertyName
(
nameof
(
DesignerAttributeResult
.
ContainsErrors
));
writer
.
WriteValue
(
result
.
ContainsErrors
);
writer
.
WritePropertyName
(
nameof
(
DesignerAttributeResult
.
Applicable
));
writer
.
WriteValue
(
result
.
Applicable
);
writer
.
WriteEndObject
();
}
}
private
class
PackageSourceJsonConverter
:
BaseJsonConverter
<
PackageSource
>
{
protected
override
PackageSource
ReadValue
(
JsonReader
reader
,
JsonSerializer
serializer
)
...
...
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs
浏览文件 @
6895112f
...
...
@@ -870,6 +870,12 @@ public List<SyntaxNode> GetMethodLevelMembers(SyntaxNode root)
return
list
;
}
public
bool
IsClassDeclaration
(
SyntaxNode
node
)
=>
node
?.
Kind
()
==
SyntaxKind
.
ClassDeclaration
;
public
bool
IsNamespaceDeclaration
(
SyntaxNode
node
)
=>
node
?.
Kind
()
==
SyntaxKind
.
NamespaceDeclaration
;
public
SyntaxList
<
SyntaxNode
>
GetMembersOfTypeDeclaration
(
SyntaxNode
typeDeclaration
)
=>
((
TypeDeclarationSyntax
)
typeDeclaration
).
Members
;
...
...
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs
浏览文件 @
6895112f
...
...
@@ -347,6 +347,8 @@ internal partial interface ISyntaxFacts
SyntaxNode
ConvertToSingleLine
(
SyntaxNode
node
,
bool
useElasticTrivia
=
false
);
bool
IsClassDeclaration
(
SyntaxNode
node
);
bool
IsNamespaceDeclaration
(
SyntaxNode
node
);
List
<
SyntaxNode
>
GetMethodLevelMembers
(
SyntaxNode
root
);
SyntaxList
<
SyntaxNode
>
GetMembersOfTypeDeclaration
(
SyntaxNode
typeDeclaration
);
SyntaxList
<
SyntaxNode
>
GetMembersOfNamespaceDeclaration
(
SyntaxNode
namespaceDeclaration
);
...
...
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb
浏览文件 @
6895112f
...
...
@@ -868,6 +868,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageServices
Return
list
End
Function
Public
Function
IsClassDeclaration
(
node
As
SyntaxNode
)
As
Boolean
Implements
ISyntaxFacts
.
IsClassDeclaration
Return
node
.
IsKind
(
SyntaxKind
.
ClassBlock
)
End
Function
Public
Function
IsNamespaceDeclaration
(
node
As
SyntaxNode
)
As
Boolean
Implements
ISyntaxFacts
.
IsNamespaceDeclaration
Return
node
.
IsKind
(
SyntaxKind
.
NamespaceBlock
)
End
Function
Public
Function
GetMembersOfTypeDeclaration
(
typeDeclaration
As
SyntaxNode
)
As
SyntaxList
(
Of
SyntaxNode
)
Implements
ISyntaxFacts
.
GetMembersOfTypeDeclaration
Return
DirectCast
(
typeDeclaration
,
TypeBlockSyntax
).
Members
End
Function
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录