Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Phodal
Chapi
提交
7c37d131
C
Chapi
项目概览
Phodal
/
Chapi
通知
5
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
Chapi
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
7c37d131
编写于
3月 04, 2020
作者:
P
Phodal Huang
提交者:
GitHub
3月 04, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #4 from cuijinyu/master
test: <c> add function parameters test
上级
3549ec21
a53f2bba
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
101 addition
and
67 deletion
+101
-67
chapi-ast-c/src/main/java/chapi/ast/antlr/CBaseListener.java
chapi-ast-c/src/main/java/chapi/ast/antlr/CBaseListener.java
+12
-12
chapi-ast-c/src/main/java/chapi/ast/antlr/CBaseVisitor.java
chapi-ast-c/src/main/java/chapi/ast/antlr/CBaseVisitor.java
+6
-6
chapi-ast-c/src/main/java/chapi/ast/antlr/CListener.java
chapi-ast-c/src/main/java/chapi/ast/antlr/CListener.java
+12
-12
chapi-ast-c/src/main/java/chapi/ast/antlr/CParser.java
chapi-ast-c/src/main/java/chapi/ast/antlr/CParser.java
+25
-25
chapi-ast-c/src/main/java/chapi/ast/antlr/CVisitor.java
chapi-ast-c/src/main/java/chapi/ast/antlr/CVisitor.java
+7
-7
chapi-ast-c/src/main/kotlin/chapi/ast/cast/CFullIdentListener.kt
...st-c/src/main/kotlin/chapi/ast/cast/CFullIdentListener.kt
+4
-4
chapi-ast-c/src/test/kotlin/chapi/ast/cast/CFullIdentListenerTest.kt
.../src/test/kotlin/chapi/ast/cast/CFullIdentListenerTest.kt
+34
-0
grammars/c/C.g4
grammars/c/C.g4
+1
-1
未找到文件。
chapi-ast-c/src/main/java/chapi/ast/antlr/CBaseListener.java
浏览文件 @
7c37d131
...
...
@@ -628,73 +628,73 @@ public class CBaseListener implements CListener {
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
enterP
ostStaticAssignmentExpressionDirectDeclarator
(
CParser
.
PostStaticAssignmentExpression
DirectDeclaratorContext
ctx
)
{
}
@Override
public
void
enterP
arameterDirectDeclarator
(
CParser
.
Parameter
DirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
exitP
ostStaticAssignmentExpressionDirectDeclarator
(
CParser
.
PostStaticAssignmentExpression
DirectDeclaratorContext
ctx
)
{
}
@Override
public
void
exitP
arameterDirectDeclarator
(
CParser
.
Parameter
DirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
enter
TypeQualifierListPointerDirectDeclarator
(
CParser
.
TypeQualifierListPointer
DirectDeclaratorContext
ctx
)
{
}
@Override
public
void
enter
PostStaticAssignmentExpressionDirectDeclarator
(
CParser
.
PostStaticAssignmentExpression
DirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
exit
TypeQualifierListPointerDirectDeclarator
(
CParser
.
TypeQualifierListPointer
DirectDeclaratorContext
ctx
)
{
}
@Override
public
void
exit
PostStaticAssignmentExpressionDirectDeclarator
(
CParser
.
PostStaticAssignmentExpression
DirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
enter
DeclaratorDirectDeclarator
(
CParser
.
Declarato
rDirectDeclaratorContext
ctx
)
{
}
@Override
public
void
enter
TypeQualifierListPointerDirectDeclarator
(
CParser
.
TypeQualifierListPointe
rDirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
exit
DeclaratorDirectDeclarator
(
CParser
.
Declarato
rDirectDeclaratorContext
ctx
)
{
}
@Override
public
void
exit
TypeQualifierListPointerDirectDeclarator
(
CParser
.
TypeQualifierListPointe
rDirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
enter
FunctionPointerDirectDeclarator
(
CParser
.
FunctionPointe
rDirectDeclaratorContext
ctx
)
{
}
@Override
public
void
enter
DeclaratorDirectDeclarator
(
CParser
.
Declarato
rDirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
exit
FunctionPointerDirectDeclarator
(
CParser
.
FunctionPointe
rDirectDeclaratorContext
ctx
)
{
}
@Override
public
void
exit
DeclaratorDirectDeclarator
(
CParser
.
Declarato
rDirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
enter
IdentifierListDirectDeclarator
(
CParser
.
IdentifierList
DirectDeclaratorContext
ctx
)
{
}
@Override
public
void
enter
FunctionPointerDirectDeclarator
(
CParser
.
FunctionPointer
DirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
exit
IdentifierListDirectDeclarator
(
CParser
.
IdentifierList
DirectDeclaratorContext
ctx
)
{
}
@Override
public
void
exit
FunctionPointerDirectDeclarator
(
CParser
.
FunctionPointer
DirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
enter
ParammeterDirectDeclarator
(
CParser
.
Parammeter
DirectDeclaratorContext
ctx
)
{
}
@Override
public
void
enter
IdentifierListDirectDeclarator
(
CParser
.
IdentifierList
DirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override
public
void
exit
ParammeterDirectDeclarator
(
CParser
.
Parammeter
DirectDeclaratorContext
ctx
)
{
}
@Override
public
void
exit
IdentifierListDirectDeclarator
(
CParser
.
IdentifierList
DirectDeclaratorContext
ctx
)
{
}
/**
* {@inheritDoc}
*
...
...
chapi-ast-c/src/main/java/chapi/ast/antlr/CBaseVisitor.java
浏览文件 @
7c37d131
...
...
@@ -374,42 +374,42 @@ public class CBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements CVis
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public
T
visitP
ostStaticAssignmentExpressionDirectDeclarator
(
CParser
.
PostStaticAssignmentExpression
DirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
@Override
public
T
visitP
arameterDirectDeclarator
(
CParser
.
Parameter
DirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public
T
visit
TypeQualifierListPointerDirectDeclarator
(
CParser
.
TypeQualifierListPointer
DirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
@Override
public
T
visit
PostStaticAssignmentExpressionDirectDeclarator
(
CParser
.
PostStaticAssignmentExpression
DirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public
T
visit
DeclaratorDirectDeclarator
(
CParser
.
Declarato
rDirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
@Override
public
T
visit
TypeQualifierListPointerDirectDeclarator
(
CParser
.
TypeQualifierListPointe
rDirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public
T
visit
FunctionPointerDirectDeclarator
(
CParser
.
FunctionPointe
rDirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
@Override
public
T
visit
DeclaratorDirectDeclarator
(
CParser
.
Declarato
rDirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public
T
visit
IdentifierListDirectDeclarator
(
CParser
.
IdentifierList
DirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
@Override
public
T
visit
FunctionPointerDirectDeclarator
(
CParser
.
FunctionPointer
DirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override
public
T
visit
ParammeterDirectDeclarator
(
CParser
.
Parammeter
DirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
@Override
public
T
visit
IdentifierListDirectDeclarator
(
CParser
.
IdentifierList
DirectDeclaratorContext
ctx
)
{
return
visitChildren
(
ctx
);
}
/**
* {@inheritDoc}
*
...
...
chapi-ast-c/src/main/java/chapi/ast/antlr/CListener.java
浏览文件 @
7c37d131
...
...
@@ -523,6 +523,18 @@ public interface CListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void
exitPreStaticAssignmentExpressionDirectDeclarator
(
CParser
.
PreStaticAssignmentExpressionDirectDeclaratorContext
ctx
);
/**
* Enter a parse tree produced by the {@code parameterDirectDeclarator}
* labeled alternative in {@link CParser#directDeclarator}.
* @param ctx the parse tree
*/
void
enterParameterDirectDeclarator
(
CParser
.
ParameterDirectDeclaratorContext
ctx
);
/**
* Exit a parse tree produced by the {@code parameterDirectDeclarator}
* labeled alternative in {@link CParser#directDeclarator}.
* @param ctx the parse tree
*/
void
exitParameterDirectDeclarator
(
CParser
.
ParameterDirectDeclaratorContext
ctx
);
/**
* Enter a parse tree produced by the {@code postStaticAssignmentExpressionDirectDeclarator}
* labeled alternative in {@link CParser#directDeclarator}.
...
...
@@ -583,18 +595,6 @@ public interface CListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void
exitIdentifierListDirectDeclarator
(
CParser
.
IdentifierListDirectDeclaratorContext
ctx
);
/**
* Enter a parse tree produced by the {@code parammeterDirectDeclarator}
* labeled alternative in {@link CParser#directDeclarator}.
* @param ctx the parse tree
*/
void
enterParammeterDirectDeclarator
(
CParser
.
ParammeterDirectDeclaratorContext
ctx
);
/**
* Exit a parse tree produced by the {@code parammeterDirectDeclarator}
* labeled alternative in {@link CParser#directDeclarator}.
* @param ctx the parse tree
*/
void
exitParammeterDirectDeclarator
(
CParser
.
ParammeterDirectDeclaratorContext
ctx
);
/**
* Enter a parse tree produced by the {@code identifierDirectDeclarator}
* labeled alternative in {@link CParser#directDeclarator}.
...
...
chapi-ast-c/src/main/java/chapi/ast/antlr/CParser.java
浏览文件 @
7c37d131
...
...
@@ -4545,6 +4545,30 @@ public class CParser extends Parser {
else
return
visitor
.
visitChildren
(
this
);
}
}
public
static
class
ParameterDirectDeclaratorContext
extends
DirectDeclaratorContext
{
public
DirectDeclaratorContext
directDeclarator
()
{
return
getRuleContext
(
DirectDeclaratorContext
.
class
,
0
);
}
public
TerminalNode
LeftParen
()
{
return
getToken
(
CParser
.
LeftParen
,
0
);
}
public
ParameterTypeListContext
parameterTypeList
()
{
return
getRuleContext
(
ParameterTypeListContext
.
class
,
0
);
}
public
TerminalNode
RightParen
()
{
return
getToken
(
CParser
.
RightParen
,
0
);
}
public
ParameterDirectDeclaratorContext
(
DirectDeclaratorContext
ctx
)
{
copyFrom
(
ctx
);
}
@Override
public
void
enterRule
(
ParseTreeListener
listener
)
{
if
(
listener
instanceof
CListener
)
((
CListener
)
listener
).
enterParameterDirectDeclarator
(
this
);
}
@Override
public
void
exitRule
(
ParseTreeListener
listener
)
{
if
(
listener
instanceof
CListener
)
((
CListener
)
listener
).
exitParameterDirectDeclarator
(
this
);
}
@Override
public
<
T
>
T
accept
(
ParseTreeVisitor
<?
extends
T
>
visitor
)
{
if
(
visitor
instanceof
CVisitor
)
return
((
CVisitor
<?
extends
T
>)
visitor
).
visitParameterDirectDeclarator
(
this
);
else
return
visitor
.
visitChildren
(
this
);
}
}
public
static
class
PostStaticAssignmentExpressionDirectDeclaratorContext
extends
DirectDeclaratorContext
{
public
DirectDeclaratorContext
directDeclarator
()
{
return
getRuleContext
(
DirectDeclaratorContext
.
class
,
0
);
...
...
@@ -4670,30 +4694,6 @@ public class CParser extends Parser {
else
return
visitor
.
visitChildren
(
this
);
}
}
public
static
class
ParammeterDirectDeclaratorContext
extends
DirectDeclaratorContext
{
public
DirectDeclaratorContext
directDeclarator
()
{
return
getRuleContext
(
DirectDeclaratorContext
.
class
,
0
);
}
public
TerminalNode
LeftParen
()
{
return
getToken
(
CParser
.
LeftParen
,
0
);
}
public
ParameterTypeListContext
parameterTypeList
()
{
return
getRuleContext
(
ParameterTypeListContext
.
class
,
0
);
}
public
TerminalNode
RightParen
()
{
return
getToken
(
CParser
.
RightParen
,
0
);
}
public
ParammeterDirectDeclaratorContext
(
DirectDeclaratorContext
ctx
)
{
copyFrom
(
ctx
);
}
@Override
public
void
enterRule
(
ParseTreeListener
listener
)
{
if
(
listener
instanceof
CListener
)
((
CListener
)
listener
).
enterParammeterDirectDeclarator
(
this
);
}
@Override
public
void
exitRule
(
ParseTreeListener
listener
)
{
if
(
listener
instanceof
CListener
)
((
CListener
)
listener
).
exitParammeterDirectDeclarator
(
this
);
}
@Override
public
<
T
>
T
accept
(
ParseTreeVisitor
<?
extends
T
>
visitor
)
{
if
(
visitor
instanceof
CVisitor
)
return
((
CVisitor
<?
extends
T
>)
visitor
).
visitParammeterDirectDeclarator
(
this
);
else
return
visitor
.
visitChildren
(
this
);
}
}
public
static
class
IdentifierDirectDeclaratorContext
extends
DirectDeclaratorContext
{
public
TerminalNode
Identifier
()
{
return
getToken
(
CParser
.
Identifier
,
0
);
}
public
IdentifierDirectDeclaratorContext
(
DirectDeclaratorContext
ctx
)
{
copyFrom
(
ctx
);
}
...
...
@@ -4907,7 +4907,7 @@ public class CParser extends Parser {
break
;
case
5
:
{
_localctx
=
new
Param
m
eterDirectDeclaratorContext
(
new
DirectDeclaratorContext
(
_parentctx
,
_parentState
));
_localctx
=
new
ParameterDirectDeclaratorContext
(
new
DirectDeclaratorContext
(
_parentctx
,
_parentState
));
pushNewRecursionContext
(
_localctx
,
_startState
,
RULE_directDeclarator
);
setState
(
782
);
if
(!(
precpred
(
_ctx
,
4
)))
throw
new
FailedPredicateException
(
this
,
"precpred(_ctx, 4)"
);
...
...
chapi-ast-c/src/main/java/chapi/ast/antlr/CVisitor.java
浏览文件 @
7c37d131
...
...
@@ -319,6 +319,13 @@ public interface CVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T
visitPreStaticAssignmentExpressionDirectDeclarator
(
CParser
.
PreStaticAssignmentExpressionDirectDeclaratorContext
ctx
);
/**
* Visit a parse tree produced by the {@code parameterDirectDeclarator}
* labeled alternative in {@link CParser#directDeclarator}.
* @param ctx the parse tree
* @return the visitor result
*/
T
visitParameterDirectDeclarator
(
CParser
.
ParameterDirectDeclaratorContext
ctx
);
/**
* Visit a parse tree produced by the {@code postStaticAssignmentExpressionDirectDeclarator}
* labeled alternative in {@link CParser#directDeclarator}.
...
...
@@ -354,13 +361,6 @@ public interface CVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T
visitIdentifierListDirectDeclarator
(
CParser
.
IdentifierListDirectDeclaratorContext
ctx
);
/**
* Visit a parse tree produced by the {@code parammeterDirectDeclarator}
* labeled alternative in {@link CParser#directDeclarator}.
* @param ctx the parse tree
* @return the visitor result
*/
T
visitParammeterDirectDeclarator
(
CParser
.
ParammeterDirectDeclaratorContext
ctx
);
/**
* Visit a parse tree produced by the {@code identifierDirectDeclarator}
* labeled alternative in {@link CParser#directDeclarator}.
...
...
chapi-ast-c/src/main/kotlin/chapi/ast/cast/CFullIdentListener.kt
浏览文件 @
7c37d131
...
...
@@ -57,9 +57,9 @@ open class CFullIdentListener(fileName: String) : CAstBaseListener() {
fun
parseDirectDeclarator
(
ctx
:
CParser
.
DirectDeclaratorContext
)
{
val
directDeclaratorType
=
ctx
::
class
.
java
.
simpleName
when
(
directDeclaratorType
)
{
"Param
m
eterDirectDeclaratorContext"
->
{
"ParameterDirectDeclaratorContext"
->
{
currentFunction
.
Parameters
=
arrayOf
<
CodeProperty
>()
val
directDeclarator
=
ctx
as
CParser
.
Param
m
eterDirectDeclaratorContext
val
directDeclarator
=
ctx
as
CParser
.
ParameterDirectDeclaratorContext
parseDirectDeclarator
(
ctx
.
directDeclarator
())
val
parameterTypeList
=
directDeclarator
.
parameterTypeList
().
parameterList
()
var
parameters
:
MutableList
<
CParser
.
ParameterDeclarationContext
>
=
ArrayList
()
...
...
@@ -108,12 +108,12 @@ open class CFullIdentListener(fileName: String) : CAstBaseListener() {
}
val
directDeclaratorType
=
directDeclarator
.
directDeclarator
()
::
class
.
java
.
simpleName
if
(
directDeclaratorType
==
"IdentifierDirectDeclaratorContext"
)
{
name
=
(
directDeclarator
.
directDeclarator
()
as
CParser
.
IdentifierDirectDeclaratorContext
).
Identifier
().
text
+
'*'
name
=
(
directDeclarator
.
directDeclarator
()
as
CParser
.
IdentifierDirectDeclaratorContext
).
Identifier
().
text
}
if
(
name
!=
null
&&
type
!=
null
)
{
currentFunction
.
Parameters
+=
CodeProperty
(
TypeValue
=
name
,
TypeType
=
type
TypeType
=
"$type*"
)
}
}
...
...
chapi-ast-c/src/test/kotlin/chapi/ast/cast/CFullIdentListenerTest.kt
浏览文件 @
7c37d131
...
...
@@ -121,6 +121,40 @@ int is_old(Person* p) {
assertEquals
(
codeFile
.
DataStructures
[
0
].
Functions
[
0
].
Name
,
"is_old"
)
}
@Test
internal
fun
shouldIdentifyFunctionSingleParameter
()
{
val
code
=
"""
int is_old(Person* p) {
return p->age > 60;
}
"""
val
codeFile
=
CAnalyser
().
analysis
(
code
,
"helloworld.c"
)
val
parameters
=
codeFile
.
DataStructures
[
0
].
Functions
[
0
].
Parameters
assertEquals
(
parameters
.
size
,
1
)
assertEquals
(
parameters
[
0
].
TypeType
,
"Person*"
)
assertEquals
(
parameters
[
0
].
TypeValue
,
"p"
)
}
@Test
internal
fun
shouldIdentifyFunctionMultiParameters
()
{
val
code
=
"""
int is_old(Person* p, int a, double b) {
return p->age > 60;
}
"""
val
codeFile
=
CAnalyser
().
analysis
(
code
,
"helloworld.c"
)
val
parameters
=
codeFile
.
DataStructures
[
0
].
Functions
[
0
].
Parameters
assertEquals
(
parameters
.
size
,
3
)
assertEquals
(
parameters
[
0
].
TypeType
,
"Person*"
)
assertEquals
(
parameters
[
0
].
TypeValue
,
"p"
)
assertEquals
(
parameters
[
1
].
TypeType
,
"int"
)
assertEquals
(
parameters
[
1
].
TypeValue
,
"a"
)
assertEquals
(
parameters
[
2
].
TypeType
,
"double"
)
assertEquals
(
parameters
[
2
].
TypeValue
,
"b"
)
}
@Test
internal
fun
shouldIdentifyForwardDeclaration
()
{
val
code
=
"""
...
...
grammars/c/C.g4
浏览文件 @
7c37d131
...
...
@@ -333,7 +333,7 @@ directDeclarator
| directDeclarator '[' 'static' typeQualifierList? assignmentExpression ']' #preStaticAssignmentExpressionDirectDeclarator
| directDeclarator '[' typeQualifierList 'static' assignmentExpression ']' #postStaticAssignmentExpressionDirectDeclarator
| directDeclarator '[' typeQualifierList? '*' ']' #typeQualifierListPointerDirectDeclarator
| directDeclarator '(' parameterTypeList ')' #param
m
eterDirectDeclarator
| directDeclarator '(' parameterTypeList ')' #parameterDirectDeclarator
| directDeclarator '(' identifierList? ')' #identifierListDirectDeclarator
| Identifier ':' DigitSequence #bitFieldDirectDeclarator // bit field
| '(' typeSpecifier? pointer directDeclarator ')' #functionPointerDirectDeclarator // function pointer like: (__cdecl *f)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录