From 5cf31bd3f39302654ce3de9f654cc57ef121fb88 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Sun, 4 Aug 2024 13:55:19 +0800 Subject: [PATCH] c/clang:marco info --- c/clang/_demo/symboldump/symboldump.go | 41 ++++++- c/clang/_wrap/cursor.cpp | 10 ++ c/clang/clang.go | 142 +++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 5 deletions(-) diff --git a/c/clang/_demo/symboldump/symboldump.go b/c/clang/_demo/symboldump/symboldump.go index a2eb0448c..e5a74a4b7 100644 --- a/c/clang/_demo/symboldump/symboldump.go +++ b/c/clang/_demo/symboldump/symboldump.go @@ -12,6 +12,7 @@ import ( type Context struct { namespaceName string className string + unit *clang.TranslationUnit } func newContext() *Context { @@ -26,23 +27,50 @@ func (c *Context) setClassName(name string) { c.className = name } +func (c *Context) setUnit(unit *clang.TranslationUnit) { + c.unit = unit +} + var context = newContext() -func print_cursor_info(cursor clang.Cursor) { +func printCursorLocation(cursor clang.Cursor) { loc := cursor.Location() var file clang.File var line, column c.Uint loc.SpellingLocation(&file, &line, &column, nil) filename := file.FileName() + defer filename.Dispose() c.Printf(c.Str("%s:%d:%d\n"), filename.CStr(), line, column) +} + +func printMarcoInfo(cursor clang.Cursor) { + printCursorLocation(cursor) + name := cursor.String() + c.Printf(c.Str("Marco Name: %s\n"), name.CStr()) + ran := cursor.Extent() + var numTokens c.Uint + var tokens *clang.Token + context.unit.Tokenize(ran, &tokens, &numTokens) + c.Printf(c.Str("Content: ")) + + tokensSlice := unsafe.Slice(tokens, int(numTokens)) + for _, tok := range tokensSlice { + tokStr := context.unit.Token(tok) + c.Printf(c.Str("%s "), tokStr.CStr()) + } + + c.Printf(c.Str("\n")) + println("--------------------------------") +} +func printFuncInfo(cursor clang.Cursor) { + printCursorLocation(cursor) cursorStr := cursor.String() symbol := cursor.Mangling() defer symbol.Dispose() defer cursorStr.Dispose() - defer filename.Dispose() if context.namespaceName != "" && context.className != "" { fmt.Printf("%s:%s:", context.namespaceName, context.className) @@ -78,7 +106,9 @@ func print_cursor_info(cursor clang.Cursor) { } func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult { - if cursor.Kind == clang.Namespace { + if cursor.Kind == clang.MacroDefinition { + printMarcoInfo(cursor) + } else if cursor.Kind == clang.Namespace { nameStr := cursor.String() context.setNamespaceName(c.GoString(nameStr.CStr())) clang.VisitChildren(cursor, visit, nil) @@ -89,7 +119,7 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe clang.VisitChildren(cursor, visit, nil) context.setClassName("") } else if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl { - print_cursor_info(cursor) + printFuncInfo(cursor) } return clang.ChildVisit_Continue @@ -105,7 +135,7 @@ func parse(filename *c.Char) { filename, unsafe.SliceData(args), 3, nil, 0, - clang.TranslationUnit_None, + clang.DetailedPreprocessingRecord, ) if unit == nil { @@ -113,6 +143,7 @@ func parse(filename *c.Char) { c.Exit(1) } + context.setUnit(unit) cursor := unit.Cursor() clang.VisitChildren(cursor, visit, nil) diff --git a/c/clang/_wrap/cursor.cpp b/c/clang/_wrap/cursor.cpp index 7b2df7762..949339dd7 100644 --- a/c/clang/_wrap/cursor.cpp +++ b/c/clang/_wrap/cursor.cpp @@ -35,6 +35,10 @@ void wrap_clang_getCursorResultType(CXCursor *cur, CXType *typ) { *typ = clang_g CXString wrap_clang_getTypeSpelling(CXType *typ) { return clang_getTypeSpelling(*typ); } +CXString wrap_clang_getTokenSpelling(CXTranslationUnit unit, CXToken *token) { + return clang_getTokenSpelling(unit, *token); +} + void wrap_clang_getCursorLocation(CXCursor *cur, CXSourceLocation *loc) { *loc = clang_getCursorLocation(*cur); } void wrap_clang_getSpellingLocation(CXSourceLocation *loc, CXFile *file, unsigned *line, unsigned *column, @@ -42,6 +46,12 @@ void wrap_clang_getSpellingLocation(CXSourceLocation *loc, CXFile *file, unsigne clang_getSpellingLocation(*loc, file, line, column, offset); } +void wrap_clang_getCursorExtent(CXCursor *cur, CXSourceRange *range) { *range = clang_getCursorExtent(*cur); } + +void wrap_clang_tokenize(CXTranslationUnit unit, CXSourceRange *Range, CXToken **Tokens, unsigned *NumTokens) { + clang_tokenize(unit, *Range, Tokens, NumTokens); +} + unsigned wrap_clang_visitChildren(CXCursor *parent, wrap_CXCursorVisitor visitor, CXClientData client_data) { wrap_data data = {client_data, visitor}; return clang_visitChildren(*parent, wrap_visitor, CXClientData(&data)); diff --git a/c/clang/clang.go b/c/clang/clang.go index 9bc123a51..dfbe6824b 100644 --- a/c/clang/clang.go +++ b/c/clang/clang.go @@ -1225,7 +1225,22 @@ func (*Index) Dispose() {} * constructing the translation unit. */ const ( + /** + * Used to indicate that no special translation-unit options are + * needed. + */ TranslationUnit_None = 0x0 + /** + * Used to indicate that the parser should construct a "detailed" + * preprocessing record, including all macro definitions and instantiations. + * + * Constructing a detailed preprocessing record requires more memory + * and time to parse, since the information contained in the record + * is usually not retained. However, it can be useful for + * applications that require more detailed information about the + * behavior of the preprocessor. + */ + DetailedPreprocessingRecord = 0x01 ) /** @@ -1330,6 +1345,53 @@ type SourceLocation struct { intData c.Uint } +/** + * Identifies a half-open character range in the source code. + * + * Use clang_getRangeStart() and clang_getRangeEnd() to retrieve the + * starting and end locations from a source range, respectively. + */ +type SourceRange struct { + ptrData [2]c.Pointer + beginIntData c.Uint + endIntData c.Uint +} + +/** + * Describes a kind of token. + */ + +type TokenKind c.Int + +const ( + /** + * A token that contains some kind of punctuation. + */ + Punctuation TokenKind = iota + /** + * A language keyword. + */ + Keyword + + /** + * An identifier (that is not a keyword). + */ + Identifier + /** + * A numeric, string, or character literal. + */ + Literal + /** + * A comment. + */ + Comment +) + +type Token struct { + intData [4]c.Uint + ptrData c.Pointer +} + /** * Retrieve a name for the entity referenced by this cursor. */ @@ -1417,6 +1479,86 @@ func (c Cursor) Location() (loc SourceLocation) { return } +/** + * Retrieve the physical extent of the source construct referenced by + * the given cursor. + * + * The extent of a cursor starts with the file/line/column pointing at the + * first character within the source construct that the cursor refers to and + * ends with the last character within that source construct. For a + * declaration, the extent covers the declaration itself. For a reference, + * the extent covers the location of the reference (e.g., where the referenced + * entity was actually used). + */ +// llgo:link (*Cursor).wrapExtent C.wrap_clang_getCursorExtent +func (c *Cursor) wrapExtent(loc *SourceRange) {} + +func (c Cursor) Extent() (loc SourceRange) { + c.wrapExtent(&loc) + return +} + +/** + * Tokenize the source code described by the given range into raw + * lexical tokens. + * + * \param TU the translation unit whose text is being tokenized. + * + * \param Range the source range in which text should be tokenized. All of the + * tokens produced by tokenization will fall within this source range, + * + * \param Tokens this pointer will be set to point to the array of tokens + * that occur within the given source range. The returned pointer must be + * freed with clang_disposeTokens() before the translation unit is destroyed. + * + * \param NumTokens will be set to the number of tokens in the \c *Tokens + * array. + * + */ +// llgo:link (*TranslationUnit).wrapTokenize C.wrap_clang_tokenize +func (t *TranslationUnit) wrapTokenize(ran *SourceRange, tokens **Token, numTokens *c.Uint) {} + +func (t TranslationUnit) Tokenize(ran SourceRange, tokens **Token, numTokens *c.Uint) { + t.wrapTokenize(&ran, tokens, numTokens) +} + +/** + * Determine the spelling of the given token. + * + * The spelling of a token is the textual representation of that token, e.g., + * the text of an identifier or keyword. + */ +// llgo:link (*TranslationUnit).wrapToken C.wrap_clang_getTokenSpelling +func (*TranslationUnit) wrapToken(token *Token) (ret String) { + return +} + +func (c TranslationUnit) Token(token Token) (ret String) { + return c.wrapToken(&token) +} + +/** + * Retrieve the file, line, column, and offset represented by + * the given source location. + * + * If the location refers into a macro instantiation, return where the + * location was originally spelled in the source file. + * + * \param location the location within a source file that will be decomposed + * into its parts. + * + * \param file [out] if non-NULL, will be set to the file to which the given + * source location points. + * + * \param line [out] if non-NULL, will be set to the line to which the given + * source location points. + * + * \param column [out] if non-NULL, will be set to the column to which the given + * source location points. + * + * \param offset [out] if non-NULL, will be set to the offset into the + * buffer to which the given source location points. + */ // llgo:link (*SourceLocation).wrapSpellingLocation C.wrap_clang_getSpellingLocation func (l *SourceLocation) wrapSpellingLocation(file *File, line, column, offset *c.Uint) {}