Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
a1cff112
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,发现更多精彩内容 >>
提交
a1cff112
编写于
5月 02, 2015
作者:
P
Pilchie
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add support for IVsLanguageBlock.GetCurrentBlock
Fixes internal TFS bug 1043580.
上级
e4f6411d
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
381 addition
and
21 deletion
+381
-21
src/EditorFeatures/TestUtilities/Traits.cs
src/EditorFeatures/TestUtilities/Traits.cs
+1
-0
src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractLanguageService`2.IVsLanguageBlock.cs
...uageService/AbstractLanguageService`2.IVsLanguageBlock.cs
+86
-0
src/VisualStudio/Core/Def/ServicesVSResources.Designer.cs
src/VisualStudio/Core/Def/ServicesVSResources.Designer.cs
+18
-0
src/VisualStudio/Core/Def/ServicesVSResources.resx
src/VisualStudio/Core/Def/ServicesVSResources.resx
+6
-0
src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
+1
-0
src/VisualStudio/Core/Test/LanguageBlockTests.vb
src/VisualStudio/Core/Test/LanguageBlockTests.vb
+241
-0
src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj
src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj
+1
-0
src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
...arp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
+6
-3
src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs
...anguageServices/SyntaxFactsService/ISyntaxFactsService.cs
+1
-1
src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
...ortable/LanguageServices/VisualBasicSyntaxFactsService.vb
+20
-17
未找到文件。
src/EditorFeatures/TestUtilities/Traits.cs
浏览文件 @
a1cff112
...
...
@@ -122,6 +122,7 @@ public static class Features
public
const
string
TodoComments
=
"TodoComments"
;
public
const
string
TypeInferenceService
=
"TypeInferenceService"
;
public
const
string
Venus
=
"Venus"
;
public
const
string
VsLanguageBlock
=
"VsLanguageBlock"
;
public
const
string
XmlTagCompletion
=
"XmlTagCompletion"
;
}
}
...
...
src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractLanguageService`2.IVsLanguageBlock.cs
0 → 100644
浏览文件 @
a1cff112
using
System.Threading
;
using
Microsoft.CodeAnalysis
;
using
Microsoft.CodeAnalysis.Editor.Host
;
using
Microsoft.CodeAnalysis.LanguageServices
;
using
Microsoft.CodeAnalysis.Text
;
using
Microsoft.CodeAnalysis.Text.Shared.Extensions
;
using
Microsoft.VisualStudio.LanguageServices.Implementation.Extensions
;
using
Microsoft.VisualStudio.Text
;
using
Roslyn.Utilities
;
using
IVsLanguageBlock
=
Microsoft
.
VisualStudio
.
TextManager
.
Interop
.
IVsLanguageBlock
;
using
IVsTextLines
=
Microsoft
.
VisualStudio
.
TextManager
.
Interop
.
IVsTextLines
;
using
VsTextSpan
=
Microsoft
.
VisualStudio
.
TextManager
.
Interop
.
TextSpan
;
namespace
Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
{
internal
abstract
partial
class
AbstractLanguageService
<
TPackage
,
TLanguageService
>
:
IVsLanguageBlock
{
public
int
GetCurrentBlock
(
IVsTextLines
pTextLines
,
int
iCurrentLine
,
int
iCurrentChar
,
VsTextSpan
[]
ptsBlockSpan
,
out
string
pbstrDescription
,
out
int
pfBlockAvailable
)
{
var
foundBlock
=
false
;
string
description
=
null
;
var
span
=
default
(
TextSpan
);
var
snapshot
=
this
.
EditorAdaptersFactoryService
.
GetDataBuffer
(
pTextLines
).
CurrentSnapshot
;
var
position
=
snapshot
.
GetPosition
(
iCurrentLine
,
iCurrentChar
);
var
waitIndicator
=
this
.
Package
.
ComponentModel
.
GetService
<
IWaitIndicator
>();
waitIndicator
.
Wait
(
ServicesVSResources
.
CurrentBlock
,
ServicesVSResources
.
DeterminingCurrentBlock
,
allowCancel
:
true
,
action
:
context
=>
{
foundBlock
=
VsLanguageBlock
.
GetCurrentBlock
(
snapshot
,
position
,
context
.
CancellationToken
,
ref
description
,
ref
span
);
});
pfBlockAvailable
=
foundBlock
?
1
:
0
;
pbstrDescription
=
description
;
if
(
ptsBlockSpan
!=
null
&&
ptsBlockSpan
.
Length
>=
1
)
{
ptsBlockSpan
[
0
]
=
span
.
ToSnapshotSpan
(
snapshot
).
ToVsTextSpan
();
}
return
VSConstants
.
S_OK
;
}
}
internal
static
class
VsLanguageBlock
{
public
static
bool
GetCurrentBlock
(
ITextSnapshot
snapshot
,
int
position
,
CancellationToken
cancellationToken
,
ref
string
description
,
ref
TextSpan
span
)
{
var
document
=
snapshot
.
GetOpenDocumentInCurrentContextWithChanges
();
var
syntaxFactsService
=
document
.
Project
.
LanguageServices
.
GetService
<
ISyntaxFactsService
>();
var
syntaxRoot
=
document
.
GetSyntaxRootAsync
(
cancellationToken
).
WaitAndGetResult
(
cancellationToken
);
var
node
=
syntaxFactsService
.
GetContainingMemberDeclaration
(
syntaxRoot
,
position
,
useFullSpan
:
false
);
if
(
node
==
null
)
{
return
false
;
}
var
semanticModel
=
document
.
GetSemanticModelAsync
(
cancellationToken
).
WaitAndGetResult
(
cancellationToken
);
var
symbol
=
semanticModel
.
GetDeclaredSymbol
(
node
,
cancellationToken
);
if
(
symbol
==
null
)
{
return
false
;
}
description
=
symbol
.
ToMinimalDisplayString
(
semanticModel
,
position
);
span
=
node
.
Span
;
return
true
;
}
}
}
src/VisualStudio/Core/Def/ServicesVSResources.Designer.cs
浏览文件 @
a1cff112
...
...
@@ -159,6 +159,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Current block.
/// </summary>
internal
static
string
CurrentBlock
{
get
{
return
ResourceManager
.
GetString
(
"CurrentBlock"
,
resourceCulture
);
}
}
/// <summary>
/// Looks up a localized string similar to Debugger.
/// </summary>
...
...
@@ -204,6 +213,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Determining current block..
/// </summary>
internal
static
string
DeterminingCurrentBlock
{
get
{
return
ResourceManager
.
GetString
(
"DeterminingCurrentBlock"
,
resourceCulture
);
}
}
/// <summary>
/// Looks up a localized string similar to Get help for '{0}'{1}{2}{3}.
/// </summary>
...
...
src/VisualStudio/Core/Def/ServicesVSResources.resx
浏览文件 @
a1cff112
...
...
@@ -471,4 +471,10 @@ Use the dropdown to view and switch to other projects this file may belong to.</
<data
name=
"FromBing"
xml:space=
"preserve"
>
<value>
from Bing
</value>
</data>
<data
name=
"CurrentBlock"
xml:space=
"preserve"
>
<value>
Current block
</value>
</data>
<data
name=
"DeterminingCurrentBlock"
xml:space=
"preserve"
>
<value>
Determining current block.
</value>
</data>
</root>
\ No newline at end of file
src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
浏览文件 @
a1cff112
...
...
@@ -29,6 +29,7 @@
<Compile
Include=
"Implementation\Diagnostics\VisualStudioVenusSpanMappingService.cs"
/>
<Compile
Include=
"Implementation\EditAndContinue\Interop\NativeMethods.cs"
/>
<Compile
Include=
"Implementation\Interop\IComWrapperFactory.cs"
/>
<Compile
Include=
"Implementation\LanguageService\AbstractLanguageService`2.IVsLanguageBlock.cs"
/>
<Compile
Include=
"Implementation\Library\FindResults\TreeItems\AbstractSourceTreeItem.cs"
/>
<Compile
Include=
"Implementation\Library\FindResults\TreeItems\MetadataDefinitionTreeItem.cs"
/>
<Compile
Include=
"Implementation\Library\FindResults\TreeItems\SourceDefinitionTreeItem.cs"
/>
...
...
src/VisualStudio/Core/Test/LanguageBlockTests.vb
0 → 100644
浏览文件 @
a1cff112
Imports
System.Threading
Imports
Microsoft.CodeAnalysis
Imports
Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports
Microsoft.CodeAnalysis.Text
Imports
Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
Imports
Roslyn.Test.Utilities
Public
Class
LanguageBlockTests
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_NotInImports_VB
()
VerifyNoBlock
(
"
I$$mports System
Module Program
Sub M()
End Sub
End Module
"
,
LanguageNames
.
VisualBasic
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_NotLeadingTriviaOfRootClass_VB
()
VerifyNoBlock
(
"
Imports System
$$
Module Program
Sub M()
End Sub
End Module
"
,
LanguageNames
.
VisualBasic
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_InNamespace_VB
()
VerifyBlock
(
"
[|Namespace N
$$
Module Program
Sub M()
End Sub
End Module
End Namespace|]
"
,
LanguageNames
.
VisualBasic
,
"N"
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_InModule_VB
()
VerifyBlock
(
"
Namespace N
[|Module Program
$$
Sub M()
End Sub
End Module|]
End Namespace
"
,
LanguageNames
.
VisualBasic
,
"Program"
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_InSub
()
VerifyBlock
(
"
Namespace N
Module Program
[|Sub M()
$$
End Sub|]
End Module
End Namespace
"
,
LanguageNames
.
VisualBasic
,
"Sub Program.M()"
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_InFunction
()
VerifyBlock
(
"
Namespace N
Module Program
[|Function F() As Integer
$$
End Function|]
End Module
End Namespace
"
,
LanguageNames
.
VisualBasic
,
"Function Program.F() As Integer"
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_InProperty_VB
()
VerifyBlock
(
"
Namespace N
Module Program
[|ReadOnly Property P() As Integer
Get
$$
End Get
End Property|]
End Module
End Namespace
"
,
LanguageNames
.
VisualBasic
,
"Property Program.P As Integer"
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_NotInUsings_CS
()
VerifyNoBlock
(
"
u$$sing System;
class Program
{
void M() { }
}
"
,
LanguageNames
.
CSharp
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_NotLeadingTriviaOfRootClass_CS
()
VerifyNoBlock
(
"
using System;
$$
class Program
{
void M() { }
}
"
,
LanguageNames
.
CSharp
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_InNamespace_CS
()
VerifyBlock
(
"
[|namespace N
{
$$
class Program
{
void M() { }
}
}|]
"
,
LanguageNames
.
CSharp
,
"N"
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_InClass_CS
()
VerifyBlock
(
"
namespace N
{
[|class Program
{
$$
void M() { }
}|]
}
"
,
LanguageNames
.
CSharp
,
"Program"
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_InMethod
()
VerifyBlock
(
"
namespace N
{
class Program
{
[|void M()
{
$$
}|]
}
}
"
,
LanguageNames
.
CSharp
,
"void Program.M()"
)
End
Sub
<
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
VsLanguageBlock
),
WorkItem
(
1043580
)
>
Public
Sub
GetCurrentBlock_InProperty_CS
()
VerifyBlock
(
"
namespace N
{
class Program
{
[|public int P
{
get
{
$$
}
}|]
}
}
"
,
LanguageNames
.
CSharp
,
"int Program.P"
)
End
Sub
Private
Sub
VerifyNoBlock
(
markup
As
String
,
languageName
As
String
)
Dim
xml
=
<
Workspace
>
<
Project
Language
=<
%
=
languageName
%
>
CommonReferences
=
"True"
>
<
Document
>
<
%
=
markup
%
>
</
Document
>
</
Project
>
</
Workspace
>
Using
workspace
=
TestWorkspaceFactory
.
CreateWorkspace
(
xml
)
Dim
hostDocument
=
workspace
.
Documents
.
Single
()
Dim
description
As
String
=
Nothing
Dim
span
As
TextSpan
Assert
.
False
(
VsLanguageBlock
.
GetCurrentBlock
(
hostDocument
.
TextBuffer
.
CurrentSnapshot
,
hostDocument
.
CursorPosition
.
Value
,
CancellationToken
.
None
,
description
,
span
))
End
Using
End
Sub
Private
Sub
VerifyBlock
(
markup
As
String
,
languageName
As
String
,
expectedDescription
As
String
)
Dim
xml
=
<
Workspace
>
<
Project
Language
=<
%
=
languageName
%
>
CommonReferences
=
"True"
>
<
Document
>
<
%
=
markup
%
>
</
Document
>
</
Project
>
</
Workspace
>
Using
workspace
=
TestWorkspaceFactory
.
CreateWorkspace
(
xml
)
Dim
hostDocument
=
workspace
.
Documents
.
Single
()
Dim
description
As
String
=
Nothing
Dim
span
As
TextSpan
Assert
.
True
(
VsLanguageBlock
.
GetCurrentBlock
(
hostDocument
.
TextBuffer
.
CurrentSnapshot
,
hostDocument
.
CursorPosition
.
Value
,
CancellationToken
.
None
,
description
,
span
))
Assert
.
Equal
(
expectedDescription
,
description
)
Assert
.
Equal
(
hostDocument
.
SelectedSpans
.
Single
(),
span
)
End
Using
End
Sub
End
Class
src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj
浏览文件 @
a1cff112
...
...
@@ -334,6 +334,7 @@
<Compile
Include=
"GoToDefinition\GoToDefinitionApiTests.vb"
/>
<Compile
Include=
"GoToDefinition\MockNavigableItemsPresenter.vb"
/>
<Compile
Include=
"Help\HelpTests.vb"
/>
<Compile
Include=
"LanguageBlockTests.vb"
/>
<Compile
Include=
"MockComponentModel.vb"
/>
<Compile
Include=
"ObjectBrowser\AbstractObjectBrowserTests.vb"
/>
<Compile
Include=
"ObjectBrowser\CSharp\ObjectBrowerTests.vb"
/>
...
...
src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
浏览文件 @
a1cff112
...
...
@@ -703,7 +703,7 @@ public bool IsIndexerMemberCRef(SyntaxNode node)
return
node
.
Kind
()
==
SyntaxKind
.
IndexerMemberCref
;
}
public
SyntaxNode
GetContainingMemberDeclaration
(
SyntaxNode
root
,
int
position
)
public
SyntaxNode
GetContainingMemberDeclaration
(
SyntaxNode
root
,
int
position
,
bool
useFullSpan
=
true
)
{
Contract
.
ThrowIfNull
(
root
,
"root"
);
Contract
.
ThrowIfTrue
(
position
<
0
||
position
>
root
.
FullSpan
.
End
,
"position"
);
...
...
@@ -721,9 +721,12 @@ public SyntaxNode GetContainingMemberDeclaration(SyntaxNode root, int position)
var
node
=
root
.
FindToken
(
position
).
Parent
;
while
(
node
!=
null
)
{
if
(
node
is
MemberDeclarationSyntax
)
if
(
useFullSpan
||
node
.
Span
.
Contains
(
position
)
)
{
return
node
;
if
(
node
is
MemberDeclarationSyntax
)
{
return
node
;
}
}
node
=
node
.
Parent
;
...
...
src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs
浏览文件 @
a1cff112
...
...
@@ -114,7 +114,7 @@ internal interface ISyntaxFactsService : ILanguageService
bool
TryGetDeclaredSymbolInfo
(
SyntaxNode
node
,
out
DeclaredSymbolInfo
declaredSymbolInfo
);
SyntaxNode
GetContainingTypeDeclaration
(
SyntaxNode
root
,
int
position
);
SyntaxNode
GetContainingMemberDeclaration
(
SyntaxNode
root
,
int
position
);
SyntaxNode
GetContainingMemberDeclaration
(
SyntaxNode
root
,
int
position
,
bool
useFullSpan
=
true
);
SyntaxNode
GetContainingVariableDeclaratorOfFieldDeclaration
(
SyntaxNode
node
);
SyntaxToken
FindTokenOnLeftOfPosition
(
SyntaxNode
node
,
int
position
,
bool
includeSkipped
=
true
,
bool
includeDirectives
=
false
,
bool
includeDocumentationComments
=
false
);
...
...
src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
浏览文件 @
a1cff112
...
...
@@ -578,7 +578,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return
False
End
Function
Public
Function
GetContainingMemberDeclaration
(
root
As
SyntaxNode
,
position
As
Integer
)
As
SyntaxNode
Implements
ISyntaxFactsService
.
GetContainingMemberDeclaration
Public
Function
GetContainingMemberDeclaration
(
root
As
SyntaxNode
,
position
As
Integer
,
Optional
useFullSpan
As
Boolean
=
True
)
As
SyntaxNode
Implements
ISyntaxFactsService
.
GetContainingMemberDeclaration
Contract
.
ThrowIfNull
(
root
,
NameOf
(
root
))
Contract
.
ThrowIfTrue
(
position
<
0
OrElse
position
>
root
.
FullSpan
.
End
,
NameOf
(
position
))
...
...
@@ -593,25 +593,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim
node
=
root
.
FindToken
(
position
).
Parent
While
node
IsNot
Nothing
If
TypeOf
node
Is
MethodBlockBaseSyntax
AndAlso
Not
TypeOf
node
.
Parent
Is
PropertyBlockSyntax
Then
Return
node
End
If
If
useFullSpan
OrElse
node
.
Span
.
Contains
(
position
)
Then
If
TypeOf
node
Is
PropertyStatement
Syntax
AndAlso
Not
TypeOf
node
.
Parent
Is
PropertyBlockSyntax
Then
Return
node
End
If
If
TypeOf
node
Is
MethodBlockBase
Syntax
AndAlso
Not
TypeOf
node
.
Parent
Is
PropertyBlockSyntax
Then
Return
node
End
If
If
TypeOf
node
Is
EventStatementSyntax
AndAlso
Not
TypeOf
node
.
Parent
Is
Event
BlockSyntax
Then
Return
node
End
If
If
TypeOf
node
Is
PropertyStatementSyntax
AndAlso
Not
TypeOf
node
.
Parent
Is
Property
BlockSyntax
Then
Return
node
End
If
If
TypeOf
node
Is
PropertyBlockSyntax
OrElse
TypeOf
node
Is
TypeBlockSyntax
OrElse
TypeOf
node
Is
EnumBlockSyntax
OrElse
TypeOf
node
Is
NamespaceBlockSyntax
OrElse
TypeOf
node
Is
EventBlockSyntax
OrElse
TypeOf
node
Is
FieldDeclarationSyntax
Then
Return
node
If
TypeOf
node
Is
EventStatementSyntax
AndAlso
Not
TypeOf
node
.
Parent
Is
EventBlockSyntax
Then
Return
node
End
If
If
TypeOf
node
Is
PropertyBlockSyntax
OrElse
TypeOf
node
Is
TypeBlockSyntax
OrElse
TypeOf
node
Is
EnumBlockSyntax
OrElse
TypeOf
node
Is
NamespaceBlockSyntax
OrElse
TypeOf
node
Is
EventBlockSyntax
OrElse
TypeOf
node
Is
FieldDeclarationSyntax
Then
Return
node
End
If
End
If
node
=
node
.
Parent
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录