llcppsigfetch:distinguish collect doc&comment

This commit is contained in:
luoliwoshang
2024-09-09 18:33:13 +08:00
parent 140352b637
commit ee5cd06077
3 changed files with 371 additions and 29 deletions

View File

@@ -212,23 +212,42 @@ func (ct *Converter) GetTypeDecl(cursor clang.Cursor) (ast.Decl, bool) {
} }
func (ct *Converter) CreateDeclBase(cursor clang.Cursor) ast.DeclBase { func (ct *Converter) CreateDeclBase(cursor clang.Cursor) ast.DeclBase {
rawComment := cursor.RawCommentText() base := ast.DeclBase{
defer rawComment.Dispose()
res := ast.DeclBase{
Loc: &ct.curLoc, Loc: &ct.curLoc,
Parent: ct.BuildScopingExpr(cursor.SemanticParent()), Parent: ct.BuildScopingExpr(cursor.SemanticParent()),
} }
commentGroup, isDoc := ct.ParseCommentGroup(cursor)
if isDoc {
base.Doc = commentGroup
}
return base
}
// extracts and parses comments associated with a given Clang cursor,
// distinguishing between documentation comments and line comments.
// It uses libclang to parse only Doxygen-style comments.
// Reference for Doxygen documentation blocks: https://www.doxygen.nl/manual/docblocks.html
// The function determines whether a comment is a documentation comment or a line comment by
// comparing the range of the comment node with the range of the declaration node in the AST.
// Note: In cases where both documentation comments and line comments conceptually exist,
// only the line comment will be preserved.
func (ct *Converter) ParseCommentGroup(cursor clang.Cursor) (comentGroup *ast.CommentGroup, isDoc bool) {
rawComment := cursor.RawCommentText()
defer rawComment.Dispose()
commentGroup := &ast.CommentGroup{} commentGroup := &ast.CommentGroup{}
if rawComment.CStr() != nil { if rawComment.CStr() != nil {
commentRange := cursor.CommentRange()
cursorRange := cursor.Extent()
isDoc := getOffset(commentRange.RangeStart()) < getOffset(cursorRange.RangeStart())
commentGroup = ct.ParseComment(c.GoString(rawComment.CStr())) commentGroup = ct.ParseComment(c.GoString(rawComment.CStr()))
if len(commentGroup.List) > 0 { if len(commentGroup.List) > 0 {
res.Doc = commentGroup return commentGroup, isDoc
} }
} }
return nil, false
return res
} }
func (ct *Converter) ParseComment(rawComment string) *ast.CommentGroup { func (ct *Converter) ParseComment(rawComment string) *ast.CommentGroup {
@@ -560,13 +579,31 @@ type visitFieldContext struct {
converter *Converter converter *Converter
} }
func (p *visitFieldContext) createBaseField(cursor clang.Cursor) *ast.Field {
field := &ast.Field{
Type: p.converter.ProcessType(cursor.Type()),
}
fieldName := cursor.String()
defer fieldName.Dispose()
commentGroup, isDoc := p.converter.ParseCommentGroup(cursor)
if commentGroup != nil {
if isDoc {
field.Doc = commentGroup
} else {
field.Comment = commentGroup
}
}
if name := fieldName.CStr(); name != nil {
field.Names = []*ast.Ident{{Name: c.GoString(name)}}
}
return field
}
func visitFieldList(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult { func visitFieldList(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult {
ctx := (*visitFieldContext)(clientData) ctx := (*visitFieldContext)(clientData)
switch cursor.Kind { switch cursor.Kind {
case clang.CursorParmDecl, clang.CursorFieldDecl: case clang.CursorParmDecl, clang.CursorFieldDecl:
paramName := cursor.String()
defer paramName.Dispose()
// In C language, parameter lists do not have similar parameter grouping in Go. // In C language, parameter lists do not have similar parameter grouping in Go.
// func foo(a, b int) // func foo(a, b int)
@@ -574,15 +611,7 @@ func visitFieldList(cursor, parent clang.Cursor, clientData unsafe.Pointer) clan
// struct A { // struct A {
// int a, b; // int a, b;
// }; // };
field := &ast.Field{ field := ctx.createBaseField(cursor)
// todo(zzy):comment & doc
Type: ctx.converter.ProcessType(cursor.Type()),
}
if paramName.CStr() != nil {
field.Names = []*ast.Ident{{Name: c.GoString(paramName.CStr())}}
}
if cursor.Kind == clang.CursorFieldDecl { if cursor.Kind == clang.CursorFieldDecl {
field.Access = ast.AccessSpecifier(cursor.CXXAccessSpecifier()) field.Access = ast.AccessSpecifier(cursor.CXXAccessSpecifier())
} }
@@ -592,17 +621,9 @@ func visitFieldList(cursor, parent clang.Cursor, clientData unsafe.Pointer) clan
case clang.CursorVarDecl: case clang.CursorVarDecl:
if cursor.StorageClass() == clang.SCStatic { if cursor.StorageClass() == clang.SCStatic {
// static member variable // static member variable
fieldname := cursor.String() field := ctx.createBaseField(cursor)
defer fieldname.Dispose() field.Access = ast.AccessSpecifier(cursor.CXXAccessSpecifier())
//todo(zzy): comment & doc field.IsStatic = true
field := &ast.Field{
Type: ctx.converter.ProcessType(cursor.Type()),
Access: ast.AccessSpecifier(cursor.CXXAccessSpecifier()),
IsStatic: true,
}
if fieldname.CStr() != nil && c.GoString(fieldname.CStr()) != "" {
field.Names = []*ast.Ident{{Name: c.GoString(fieldname.CStr())}}
}
ctx.params.List = append(ctx.params.List, field) ctx.params.List = append(ctx.params.List, field)
} }
} }

View File

@@ -41,6 +41,38 @@ void foo();`,
* doc 2 * doc 2
*/ */
void foo();`, void foo();`,
`
struct Foo {
/// doc
int x;
int y; ///< comment
/**
* field doc (parse ignore with comment in same cursor)
*/
int z; /*!< comment */
};
`,
`
class Doc
{
public:
/**
* static field doc
*/
static int x;
static int y; /*!< static field comment */
/**
* field doc
*/
int a;
int b; ///< field comment
/**
* method doc
*/
void Foo();
protected:
int value; /*!< protected field comment */
};`,
} }
test.RunTest("TestDoc", testCases) test.RunTest("TestDoc", testCases)
} }

View File

@@ -437,6 +437,295 @@ TestDoc Case 9:
} }
} }
TestDoc Case 10:
{
"temp.h": {
"_Type": "File",
"decls": [{
"_Type": "TypeDecl",
"Loc": {
"_Type": "Location",
"File": "temp.h"
},
"Doc": null,
"Parent": null,
"Name": {
"_Type": "Ident",
"Name": "Foo"
},
"Type": {
"_Type": "RecordType",
"Tag": 0,
"Fields": {
"_Type": "FieldList",
"List": [{
"_Type": "Field",
"Type": {
"_Type": "BuiltinType",
"Kind": 6,
"Flags": 0
},
"Doc": {
"_Type": "CommentGroup",
"List": [{
"_Type": "Comment",
"Text": "/// doc"
}]
},
"Comment": null,
"IsStatic": false,
"Access": 1,
"Names": [{
"_Type": "Ident",
"Name": "x"
}]
}, {
"_Type": "Field",
"Type": {
"_Type": "BuiltinType",
"Kind": 6,
"Flags": 0
},
"Doc": null,
"Comment": {
"_Type": "CommentGroup",
"List": [{
"_Type": "Comment",
"Text": "///< comment"
}]
},
"IsStatic": false,
"Access": 1,
"Names": [{
"_Type": "Ident",
"Name": "y"
}]
}, {
"_Type": "Field",
"Type": {
"_Type": "BuiltinType",
"Kind": 6,
"Flags": 0
},
"Doc": null,
"Comment": {
"_Type": "CommentGroup",
"List": [{
"_Type": "Comment",
"Text": "/*!< comment */"
}]
},
"IsStatic": false,
"Access": 1,
"Names": [{
"_Type": "Ident",
"Name": "z"
}]
}]
},
"Methods": []
}
}],
"includes": [],
"macros": []
}
}
TestDoc Case 11:
{
"temp.h": {
"_Type": "File",
"decls": [{
"_Type": "TypeDecl",
"Loc": {
"_Type": "Location",
"File": "temp.h"
},
"Doc": null,
"Parent": null,
"Name": {
"_Type": "Ident",
"Name": "Doc"
},
"Type": {
"_Type": "RecordType",
"Tag": 3,
"Fields": {
"_Type": "FieldList",
"List": [{
"_Type": "Field",
"Type": {
"_Type": "BuiltinType",
"Kind": 6,
"Flags": 0
},
"Doc": {
"_Type": "CommentGroup",
"List": [{
"_Type": "Comment",
"Text": "/** "
}, {
"_Type": "Comment",
"Text": " * static field doc"
}, {
"_Type": "Comment",
"Text": " */"
}]
},
"Comment": null,
"IsStatic": true,
"Access": 1,
"Names": [{
"_Type": "Ident",
"Name": "x"
}]
}, {
"_Type": "Field",
"Type": {
"_Type": "BuiltinType",
"Kind": 6,
"Flags": 0
},
"Doc": null,
"Comment": {
"_Type": "CommentGroup",
"List": [{
"_Type": "Comment",
"Text": "/*!< static field comment */"
}]
},
"IsStatic": true,
"Access": 1,
"Names": [{
"_Type": "Ident",
"Name": "y"
}]
}, {
"_Type": "Field",
"Type": {
"_Type": "BuiltinType",
"Kind": 6,
"Flags": 0
},
"Doc": {
"_Type": "CommentGroup",
"List": [{
"_Type": "Comment",
"Text": "/** "
}, {
"_Type": "Comment",
"Text": " * field doc"
}, {
"_Type": "Comment",
"Text": " */"
}]
},
"Comment": null,
"IsStatic": false,
"Access": 1,
"Names": [{
"_Type": "Ident",
"Name": "a"
}]
}, {
"_Type": "Field",
"Type": {
"_Type": "BuiltinType",
"Kind": 6,
"Flags": 0
},
"Doc": null,
"Comment": {
"_Type": "CommentGroup",
"List": [{
"_Type": "Comment",
"Text": "///< field comment"
}]
},
"IsStatic": false,
"Access": 1,
"Names": [{
"_Type": "Ident",
"Name": "b"
}]
}, {
"_Type": "Field",
"Type": {
"_Type": "BuiltinType",
"Kind": 6,
"Flags": 0
},
"Doc": null,
"Comment": {
"_Type": "CommentGroup",
"List": [{
"_Type": "Comment",
"Text": "/*!< protected field comment */"
}]
},
"IsStatic": false,
"Access": 2,
"Names": [{
"_Type": "Ident",
"Name": "value"
}]
}]
},
"Methods": [{
"_Type": "FuncDecl",
"Loc": {
"_Type": "Location",
"File": "temp.h"
},
"Doc": {
"_Type": "CommentGroup",
"List": [{
"_Type": "Comment",
"Text": "/** "
}, {
"_Type": "Comment",
"Text": " * method doc"
}, {
"_Type": "Comment",
"Text": " */"
}]
},
"Parent": {
"_Type": "Ident",
"Name": "Doc"
},
"Name": {
"_Type": "Ident",
"Name": "Foo"
},
"Type": {
"_Type": "FuncType",
"Params": {
"_Type": "FieldList",
"List": null
},
"Ret": {
"_Type": "BuiltinType",
"Kind": 0,
"Flags": 0
}
},
"IsInline": false,
"IsStatic": false,
"IsConst": false,
"IsExplicit": false,
"IsConstructor": false,
"IsDestructor": false,
"IsVirtual": false,
"IsOverride": false
}]
}
}],
"includes": [],
"macros": []
}
}
#stderr #stderr