Files
llgo/_xtool/castdump/castdump.go

222 lines
5.3 KiB
Go
Raw Normal View History

2024-08-06 18:31:54 +08:00
package main
import (
"fmt"
"os"
"strings"
2024-08-06 18:31:54 +08:00
"unsafe"
2025-04-03 15:52:18 +08:00
"github.com/goplus/lib/c"
"github.com/goplus/lib/c/clang"
2024-08-06 18:31:54 +08:00
)
type Data struct {
Depth c.Uint
Unit *clang.TranslationUnit
}
2024-08-07 10:59:27 +08:00
var accessMap = map[clang.CXXAccessSpecifier]string{
clang.CXXInvalidAccessSpecifier: "invalid",
clang.CXXPublic: "public",
clang.CXXProtected: "protected",
clang.CXXPrivate: "private",
}
func printIndent(depth c.Uint) {
2024-08-07 20:07:27 +08:00
fmt.Print(strings.Repeat(" ", int(depth)))
}
2024-08-06 18:31:54 +08:00
func accessToString(spec clang.CXXAccessSpecifier) string {
2024-08-07 10:59:27 +08:00
if str, ok := accessMap[spec]; ok {
return str
2024-08-06 18:31:54 +08:00
}
2024-08-07 10:59:27 +08:00
return "unknown"
2024-08-06 18:31:54 +08:00
}
func visit(cursor, parent clang.Cursor, ClientData c.Pointer) clang.ChildVisitResult {
data := (*Data)(ClientData)
printAST(cursor, data)
return clang.ChildVisit_Continue
}
func printType(t clang.Type, data *Data) {
printIndent(data.Depth)
typeSpell := t.String()
typeKind := t.Kind.String()
2024-08-07 20:07:27 +08:00
if t.Kind == clang.TypeInvalid {
} else if t.Kind == clang.TypeUnexposed {
c.Printf(c.Str("<UnexposedType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
} else if t.Kind >= clang.TypeFirstBuiltin && t.Kind <= clang.TypeLastBuiltin {
c.Printf(c.Str("<BuiltinType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
} else if t.Kind > clang.TypeComplex {
c.Printf(c.Str("<ComplexType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
}
data.Depth++
switch t.Kind {
case clang.TypePointer:
printType(t.PointeeType(), data)
case clang.TypeIncompleteArray, clang.TypeVariableArray, clang.TypeDependentSizedArray, clang.TypeConstantArray:
printType(t.ArrayElementType(), data)
case clang.TypeTypedef:
printType(t.TypeDeclaration().TypedefDeclUnderlyingType(), data)
case clang.TypeElaborated:
printType(t.NamedType(), data)
2024-08-07 20:07:27 +08:00
case clang.TypeFunctionProto:
printType(t.ResultType(), data)
for i := 0; i < int(t.NumArgTypes()); i++ {
printType(t.ArgType(c.Uint(i)), data)
}
}
data.Depth--
typeKind.Dispose()
typeSpell.Dispose()
}
2024-08-06 18:31:54 +08:00
func printLocation(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("(Loc:%s:%d:%d)\n"), filename.CStr(), line, column)
}
func printAccess(cursor clang.Cursor) {
kind := cursor.Kind.String()
spell := cursor.String()
defer kind.Dispose()
defer spell.Dispose()
2024-08-07 20:07:27 +08:00
c.Printf(c.Str("%s: %s %s"), kind.CStr(), spell.CStr(), c.AllocaCStr(accessToString(cursor.CXXAccessSpecifier())))
printLocation(cursor)
2024-08-06 18:31:54 +08:00
}
func printMacro(cursor clang.Cursor, unit *clang.TranslationUnit) {
kind := cursor.Kind.String()
defer kind.Dispose()
c.Printf(c.Str("%s: "), kind.CStr())
ran := cursor.Extent()
var numTokens c.Uint
var tokens *clang.Token
unit.Tokenize(ran, &tokens, &numTokens)
2024-08-20 11:10:29 +08:00
defer unit.DisposeTokens(tokens, numTokens)
2024-08-06 18:31:54 +08:00
tokensSlice := unsafe.Slice(tokens, int(numTokens))
for _, tok := range tokensSlice {
tokStr := unit.Token(tok)
c.Printf(c.Str("%s "), tokStr.CStr())
tokStr.Dispose()
}
2024-08-07 20:07:27 +08:00
printLocation(cursor)
2024-08-06 18:31:54 +08:00
}
2024-08-07 20:07:27 +08:00
func printFunc(cursor clang.Cursor, data *Data) {
2024-08-06 18:31:54 +08:00
kind := cursor.Kind.String()
spell := cursor.String()
symbol := cursor.Mangling()
defer symbol.Dispose()
defer kind.Dispose()
defer spell.Dispose()
2024-08-07 20:07:27 +08:00
c.Printf(c.Str("%s: %s (Symbol: %s)"), kind.CStr(), spell.CStr(), symbol.CStr())
printLocation(cursor)
printType(cursor.Type(), data)
}
func printEnumConstant(cursor clang.Cursor) {
kind := cursor.Kind.String()
spell := cursor.String()
defer kind.Dispose()
defer spell.Dispose()
c.Printf(c.Str("%s: %s:%lld"), kind.CStr(), spell.CStr(), cursor.EnumConstantDeclValue())
printLocation(cursor)
2024-08-06 18:31:54 +08:00
}
func printDefault(cursor clang.Cursor, data *Data) {
2024-08-06 18:31:54 +08:00
kind := cursor.Kind.String()
spell := cursor.String()
defer kind.Dispose()
defer spell.Dispose()
// node which has type
2024-08-06 18:31:54 +08:00
if cursor.Type().Kind != clang.TypeInvalid {
c.Printf(c.Str("%s: %s"), kind.CStr(), spell.CStr())
printLocation(cursor)
printType(cursor.Type(), data)
} else {
c.Printf(c.Str("%s: %s\n"), kind.CStr(), spell.CStr())
2024-08-06 18:31:54 +08:00
}
}
func printAST(cursor clang.Cursor, data *Data) {
kind := cursor.Kind.String()
spell := cursor.String()
printIndent(data.Depth)
2024-08-06 18:31:54 +08:00
switch cursor.Kind {
case clang.CursorCXXAccessSpecifier:
printAccess(cursor)
case clang.CursorMacroDefinition:
printMacro(cursor, data.Unit)
case clang.CursorFunctionDecl, clang.CursorCXXMethod, clang.CursorConstructor, clang.CursorDestructor:
2024-08-07 20:07:27 +08:00
printFunc(cursor, data)
case clang.CursorEnumConstantDecl:
printEnumConstant(cursor)
2024-08-06 18:31:54 +08:00
default:
printDefault(cursor, data)
2024-08-06 18:31:54 +08:00
}
data.Depth++
clang.VisitChildren(cursor, visit, c.Pointer(data))
data.Depth--
kind.Dispose()
spell.Dispose()
}
func main() {
if c.Argc != 2 {
fmt.Fprintln(os.Stderr, "Usage: castdump <headerFile>")
return
}
args := make([]*c.Char, 3)
args[0] = c.Str("-x")
args[1] = c.Str("c++")
args[2] = c.Str("-std=c++11")
sourceFile := *c.Advance(c.Argv, 1)
index := clang.CreateIndex(0, 0)
unit := index.ParseTranslationUnit(
sourceFile,
unsafe.SliceData(args), 3,
nil, 0,
clang.DetailedPreprocessingRecord,
)
defer index.Dispose()
defer unit.Dispose()
if unit == nil {
println("Unable to parse translation unit. Quitting.")
c.Exit(1)
}
cursor := unit.Cursor()
Data := &Data{
Depth: 0,
Unit: unit,
}
printAST(cursor, Data)
}