102 lines
2.4 KiB
Go
102 lines
2.4 KiB
Go
package clangutils
|
|
|
|
import (
|
|
"errors"
|
|
"unsafe"
|
|
|
|
"github.com/goplus/llgo/c"
|
|
"github.com/goplus/llgo/c/clang"
|
|
)
|
|
|
|
type Config struct {
|
|
File string
|
|
Temp bool
|
|
Args []string
|
|
IsCpp bool
|
|
Index *clang.Index
|
|
}
|
|
|
|
type Visitor func(cursor, parent clang.Cursor) clang.ChildVisitResult
|
|
|
|
const TEMP_FILE = "temp.h"
|
|
|
|
func CreateTranslationUnit(config *Config) (*clang.Index, *clang.TranslationUnit, error) {
|
|
// default use the c/c++ standard of clang; c:gnu17 c++:gnu++17
|
|
// https://clang.llvm.org/docs/CommandGuide/clang.html
|
|
defaultArgs := []string{"-x", "c"}
|
|
if config.IsCpp {
|
|
defaultArgs = []string{"-x", "c++"}
|
|
}
|
|
allArgs := append(defaultArgs, config.Args...)
|
|
|
|
cArgs := make([]*c.Char, len(allArgs))
|
|
for i, arg := range allArgs {
|
|
cArgs[i] = c.AllocaCStr(arg)
|
|
}
|
|
|
|
var index *clang.Index
|
|
if config.Index != nil {
|
|
index = config.Index
|
|
} else {
|
|
index = clang.CreateIndex(0, 0)
|
|
}
|
|
|
|
var unit *clang.TranslationUnit
|
|
|
|
if config.Temp {
|
|
content := c.AllocaCStr(config.File)
|
|
tempFile := &clang.UnsavedFile{
|
|
Filename: c.Str(TEMP_FILE),
|
|
Contents: content,
|
|
Length: c.Ulong(c.Strlen(content)),
|
|
}
|
|
|
|
unit = index.ParseTranslationUnit(
|
|
tempFile.Filename,
|
|
unsafe.SliceData(cArgs), c.Int(len(cArgs)),
|
|
tempFile, 1,
|
|
clang.DetailedPreprocessingRecord,
|
|
)
|
|
|
|
} else {
|
|
cFile := c.AllocaCStr(config.File)
|
|
unit = index.ParseTranslationUnit(
|
|
cFile,
|
|
unsafe.SliceData(cArgs), c.Int(len(cArgs)),
|
|
nil, 0,
|
|
clang.DetailedPreprocessingRecord,
|
|
)
|
|
}
|
|
|
|
if unit == nil {
|
|
return nil, nil, errors.New("failed to parse translation unit")
|
|
}
|
|
|
|
return index, unit, nil
|
|
}
|
|
|
|
func GetLocation(loc clang.SourceLocation) (file clang.File, line c.Uint, column c.Uint, offset c.Uint) {
|
|
loc.SpellingLocation(&file, &line, &column, &offset)
|
|
return
|
|
}
|
|
|
|
// Traverse up the semantic parents
|
|
func BuildScopingParts(cursor clang.Cursor) []string {
|
|
var parts []string
|
|
for cursor.IsNull() != 1 && cursor.Kind != clang.CursorTranslationUnit {
|
|
name := cursor.String()
|
|
qualified := c.GoString(name.CStr())
|
|
parts = append([]string{qualified}, parts...)
|
|
cursor = cursor.SemanticParent()
|
|
name.Dispose()
|
|
}
|
|
return parts
|
|
}
|
|
|
|
func VisitChildren(cursor clang.Cursor, fn Visitor) c.Uint {
|
|
return clang.VisitChildren(cursor, func(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult {
|
|
cfn := *(*Visitor)(clientData)
|
|
return cfn(cursor, parent)
|
|
}, unsafe.Pointer(&fn))
|
|
}
|