llcppsigfetch:-v
This commit is contained in:
@@ -19,6 +19,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -41,6 +42,10 @@ func main() {
|
||||
printUsage()
|
||||
return
|
||||
}
|
||||
if ags.Verbose {
|
||||
log.SetFlags(0)
|
||||
parse.SetDebug(parse.DbgFlagAll)
|
||||
}
|
||||
extract := false
|
||||
out := false
|
||||
|
||||
@@ -74,9 +79,21 @@ func main() {
|
||||
}
|
||||
|
||||
if extract {
|
||||
runExtract(extractFile, isTemp, isCpp, out, otherArgs)
|
||||
if ags.Verbose {
|
||||
log.Println("runExtract: extractFile:", extractFile)
|
||||
log.Println("isTemp:", isTemp)
|
||||
log.Println("isCpp:", isCpp)
|
||||
log.Println("out:", out)
|
||||
log.Println("otherArgs:", otherArgs)
|
||||
}
|
||||
runExtract(extractFile, isTemp, isCpp, out, otherArgs, ags.Verbose)
|
||||
} else {
|
||||
runFromConfig(ags.CfgFile, ags.UseStdin, out)
|
||||
if ags.Verbose {
|
||||
log.Println("runFromConfig: config file:", ags.CfgFile)
|
||||
log.Println("use stdin:", ags.UseStdin)
|
||||
log.Println("output to file:", out)
|
||||
}
|
||||
runFromConfig(ags.CfgFile, ags.UseStdin, out, ags.Verbose)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -109,7 +126,7 @@ func printUsage() {
|
||||
fmt.Println("Note: The two usage modes are mutually exclusive. Use either [<config_file>] OR --extract, not both.")
|
||||
}
|
||||
|
||||
func runFromConfig(cfgFile string, useStdin bool, outputToFile bool) {
|
||||
func runFromConfig(cfgFile string, useStdin bool, outputToFile bool, verbose bool) {
|
||||
var data []byte
|
||||
var err error
|
||||
if useStdin {
|
||||
@@ -117,6 +134,13 @@ func runFromConfig(cfgFile string, useStdin bool, outputToFile bool) {
|
||||
} else {
|
||||
data, err = os.ReadFile(cfgFile)
|
||||
}
|
||||
if verbose {
|
||||
if useStdin {
|
||||
log.Println("runFromConfig: read from stdin")
|
||||
} else {
|
||||
log.Println("runFromConfig: read from file", cfgFile)
|
||||
}
|
||||
}
|
||||
check(err)
|
||||
|
||||
conf, err := config.GetConf(data)
|
||||
@@ -124,10 +148,21 @@ func runFromConfig(cfgFile string, useStdin bool, outputToFile bool) {
|
||||
defer conf.Delete()
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile)
|
||||
log.Println("Failed to parse config file:", cfgFile)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
files := getHeaderFiles(conf.CFlags, conf.Include)
|
||||
//todo(zzy): reuse the llcppsymg's cflags parse
|
||||
cflag := ParseCFlags(conf.CFlags)
|
||||
files, notFounds, err := cflag.GenHeaderFilePaths(conf.Include)
|
||||
check(err)
|
||||
|
||||
if verbose {
|
||||
log.Println("runFromConfig: header file paths", files)
|
||||
if len(notFounds) > 0 {
|
||||
log.Println("runFromConfig: not found header files", notFounds)
|
||||
}
|
||||
}
|
||||
|
||||
context := parse.NewContext(conf.Cplusplus)
|
||||
err = context.ProcessFiles(files)
|
||||
@@ -136,7 +171,7 @@ func runFromConfig(cfgFile string, useStdin bool, outputToFile bool) {
|
||||
outputInfo(context, outputToFile)
|
||||
}
|
||||
|
||||
func runExtract(file string, isTemp bool, isCpp bool, outToFile bool, otherArgs []string) {
|
||||
func runExtract(file string, isTemp bool, isCpp bool, outToFile bool, otherArgs []string, verbose bool) {
|
||||
cfg := &clangutils.Config{
|
||||
File: file,
|
||||
Args: otherArgs,
|
||||
@@ -175,14 +210,46 @@ func outputResult(result *c.Char, outputToFile bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func getHeaderFiles(cflags string, files []string) []string {
|
||||
prefix := cflags
|
||||
prefix = strings.TrimPrefix(prefix, "-I")
|
||||
var paths []string
|
||||
for _, f := range files {
|
||||
paths = append(paths, filepath.Join(prefix, f))
|
||||
// todo(zzy): reuse the llcppsymg's cflags parse https://github.com/goplus/llgo/pull/788
|
||||
type CFlags struct {
|
||||
Paths []string // Include Path
|
||||
}
|
||||
|
||||
func ParseCFlags(cflags string) *CFlags {
|
||||
parts := strings.Fields(cflags)
|
||||
cf := &CFlags{}
|
||||
for _, part := range parts {
|
||||
if strings.HasPrefix(part, "-I") {
|
||||
cf.Paths = append(cf.Paths, part[2:])
|
||||
}
|
||||
}
|
||||
return paths
|
||||
return cf
|
||||
}
|
||||
|
||||
func (cf *CFlags) GenHeaderFilePaths(files []string) ([]string, []string, error) {
|
||||
var foundPaths []string
|
||||
var notFound []string
|
||||
|
||||
for _, file := range files {
|
||||
var found bool
|
||||
for _, path := range cf.Paths {
|
||||
fullPath := filepath.Join(path, file)
|
||||
if _, err := os.Stat(fullPath); err == nil {
|
||||
foundPaths = append(foundPaths, fullPath)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
notFound = append(notFound, file)
|
||||
}
|
||||
}
|
||||
|
||||
if len(foundPaths) == 0 {
|
||||
return nil, notFound, fmt.Errorf("failed to find any header files")
|
||||
}
|
||||
|
||||
return foundPaths, notFound, nil
|
||||
}
|
||||
|
||||
func outputInfo(context *parse.Context, outputToFile bool) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package parse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"unsafe"
|
||||
@@ -64,6 +65,13 @@ type Config struct {
|
||||
}
|
||||
|
||||
func NewConverter(config *clangutils.Config) (*Converter, error) {
|
||||
if debugParse {
|
||||
log.Println("NewConverter: config")
|
||||
log.Println("config.File", config.File)
|
||||
log.Println("config.Args", config.Args)
|
||||
log.Println("config.IsCpp", config.IsCpp)
|
||||
log.Println("config.Temp", config.Temp)
|
||||
}
|
||||
index, unit, err := clangutils.CreateTranslationUnit(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -79,7 +87,13 @@ func NewConverter(config *clangutils.Config) (*Converter, error) {
|
||||
}
|
||||
|
||||
func (ct *Converter) Dispose() {
|
||||
if debugParse {
|
||||
log.Println("Dispose: ct.index")
|
||||
}
|
||||
ct.index.Dispose()
|
||||
if debugParse {
|
||||
log.Println("Dispose: ct.unit")
|
||||
}
|
||||
ct.unit.Dispose()
|
||||
}
|
||||
|
||||
@@ -123,14 +137,23 @@ func (ct *Converter) UpdateLoc(cursor clang.Cursor) {
|
||||
|
||||
func (ct *Converter) GetCurFile() *ast.File {
|
||||
if ct.curLoc.File == "" {
|
||||
if debugParse {
|
||||
log.Println("GetCurFile: NO FILE")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// todo(zzy): more efficient
|
||||
for i, entry := range ct.Files {
|
||||
if entry.Path == ct.curLoc.File {
|
||||
if debugParse {
|
||||
log.Println("GetCurFile: found", ct.curLoc.File)
|
||||
}
|
||||
return ct.Files[i].Doc
|
||||
}
|
||||
}
|
||||
if debugParse {
|
||||
log.Println("GetCurFile: Create New ast.File", ct.curLoc.File)
|
||||
}
|
||||
newDoc := &ast.File{}
|
||||
ct.Files = append(ct.Files, &FileEntry{Path: ct.curLoc.File, Doc: newDoc})
|
||||
return newDoc
|
||||
@@ -219,6 +242,13 @@ func (ct *Converter) visitTop(cursor, parent clang.Cursor) clang.ChildVisitResul
|
||||
ct.UpdateLoc(cursor)
|
||||
|
||||
curFile := ct.GetCurFile()
|
||||
|
||||
if debugParse {
|
||||
name := cursor.String()
|
||||
defer name.Dispose()
|
||||
log.Println("visitTop: Cursor:", c.GoString(name.CStr()))
|
||||
}
|
||||
|
||||
if curFile == nil {
|
||||
return clang.ChildVisit_Continue
|
||||
}
|
||||
@@ -227,27 +257,69 @@ func (ct *Converter) visitTop(cursor, parent clang.Cursor) clang.ChildVisitResul
|
||||
case clang.CursorInclusionDirective:
|
||||
include := ct.ProcessInclude(cursor)
|
||||
curFile.Includes = append(curFile.Includes, include)
|
||||
if debugParse {
|
||||
log.Println("visitTop: ProcessInclude END ", include.Path)
|
||||
}
|
||||
case clang.CursorMacroDefinition:
|
||||
macro := ct.ProcessMacro(cursor)
|
||||
curFile.Macros = append(curFile.Macros, macro)
|
||||
if debugParse {
|
||||
log.Println("visitTop: ProcessMacro END ", macro.Name, "Tokens Length:", len(macro.Tokens))
|
||||
}
|
||||
case clang.CursorEnumDecl:
|
||||
enum := ct.ProcessEnumDecl(cursor)
|
||||
curFile.Decls = append(curFile.Decls, enum)
|
||||
if debugParse {
|
||||
name := "anonymous"
|
||||
if enum.Name != nil {
|
||||
name = enum.Name.Name
|
||||
}
|
||||
log.Println("visitTop: ProcessEnumDecl END", name)
|
||||
}
|
||||
case clang.CursorClassDecl:
|
||||
classDecl := ct.ProcessClassDecl(cursor)
|
||||
curFile.Decls = append(curFile.Decls, classDecl)
|
||||
if debugParse {
|
||||
name := "anonymous"
|
||||
if classDecl.Name != nil {
|
||||
name = classDecl.Name.Name
|
||||
}
|
||||
log.Println("visitTop: ProcessClassDecl END", name)
|
||||
}
|
||||
case clang.CursorStructDecl:
|
||||
structDecl := ct.ProcessStructDecl(cursor)
|
||||
curFile.Decls = append(curFile.Decls, structDecl)
|
||||
if debugParse {
|
||||
name := "anonymous"
|
||||
if structDecl.Name != nil {
|
||||
name = structDecl.Name.Name
|
||||
}
|
||||
log.Println("visitTop: ProcessStructDecl END", name)
|
||||
}
|
||||
case clang.CursorUnionDecl:
|
||||
unionDecl := ct.ProcessUnionDecl(cursor)
|
||||
curFile.Decls = append(curFile.Decls, unionDecl)
|
||||
if debugParse {
|
||||
name := "anonymous"
|
||||
if unionDecl.Name != nil {
|
||||
name = unionDecl.Name.Name
|
||||
}
|
||||
log.Println("visitTop: ProcessUnionDecl END", name)
|
||||
}
|
||||
case clang.CursorFunctionDecl, clang.CursorCXXMethod, clang.CursorConstructor, clang.CursorDestructor:
|
||||
// Handle functions and class methods (including out-of-class method)
|
||||
// Example: void MyClass::myMethod() { ... } out-of-class method
|
||||
curFile.Decls = append(curFile.Decls, ct.ProcessFuncDecl(cursor))
|
||||
funcDecl := ct.ProcessFuncDecl(cursor)
|
||||
curFile.Decls = append(curFile.Decls, funcDecl)
|
||||
if debugParse {
|
||||
log.Println("visitTop: ProcessFuncDecl END", funcDecl.Name.Name, funcDecl.MangledName, "isStatic:", funcDecl.IsStatic, "isInline:", funcDecl.IsInline)
|
||||
}
|
||||
case clang.CursorTypedefDecl:
|
||||
curFile.Decls = append(curFile.Decls, ct.ProcessTypeDefDecl(cursor))
|
||||
typedefDecl := ct.ProcessTypeDefDecl(cursor)
|
||||
curFile.Decls = append(curFile.Decls, typedefDecl)
|
||||
if debugParse {
|
||||
log.Println("visitTop: ProcessTypeDefDecl END", typedefDecl.Name.Name)
|
||||
}
|
||||
case clang.CursorNamespace:
|
||||
VisitChildren(cursor, ct.visitTop)
|
||||
}
|
||||
@@ -352,12 +424,17 @@ func (ct *Converter) ProcessTypeDefDecl(cursor clang.Cursor) *ast.TypedefDecl {
|
||||
}
|
||||
|
||||
ct.SetTypeDecl(cursor, decl)
|
||||
|
||||
return decl
|
||||
}
|
||||
|
||||
func (ct *Converter) ProcessUnderlyingType(cursor clang.Cursor) ast.Expr {
|
||||
underlyingTyp := cursor.TypedefDeclUnderlyingType()
|
||||
|
||||
if underlyingTyp.Kind != clang.TypeElaborated {
|
||||
if debugParse {
|
||||
log.Println("ProcessUnderlyingType: not elaborated")
|
||||
}
|
||||
return ct.ProcessType(underlyingTyp)
|
||||
}
|
||||
|
||||
@@ -370,6 +447,9 @@ func (ct *Converter) ProcessUnderlyingType(cursor clang.Cursor) ast.Expr {
|
||||
// In this case, libclang incorrectly reports an anonymous struct as a named struct
|
||||
sourceCode := ct.GetTokens(referTypeCursor)
|
||||
if isAnonymousStructure(sourceCode) {
|
||||
if debugParse {
|
||||
log.Println("ProcessUnderlyingType: is anonymous structure")
|
||||
}
|
||||
ct.SetAnonyType(referTypeCursor)
|
||||
typ, isValidType := ct.GetTypeDecl(referTypeCursor)
|
||||
if isValidType {
|
||||
@@ -377,9 +457,15 @@ func (ct *Converter) ProcessUnderlyingType(cursor clang.Cursor) ast.Expr {
|
||||
// according to a normal anonymous decl
|
||||
switch declType := typ.(type) {
|
||||
case *ast.EnumTypeDecl:
|
||||
if debugParse {
|
||||
log.Println("ProcessUnderlyingType: is actually anonymous enum,remove name")
|
||||
}
|
||||
declType.Name = nil
|
||||
case *ast.TypeDecl:
|
||||
if declType.Type.Tag != ast.Class {
|
||||
if debugParse {
|
||||
log.Println("ProcessUnderlyingType: is actually anonymous struct,remove name")
|
||||
}
|
||||
declType.Name = nil
|
||||
} else {
|
||||
// Unreachable: There should be no anonymous classes in this context
|
||||
@@ -405,11 +491,17 @@ func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl {
|
||||
|
||||
// function type will only collect return type
|
||||
// ProcessType can't get the field names,will collect in follows
|
||||
if debugParse {
|
||||
log.Println("ProcessFuncDecl: Get Base FuncType")
|
||||
}
|
||||
funcType, ok := ct.ProcessType(cursor.Type()).(*ast.FuncType)
|
||||
if !ok {
|
||||
fmt.Println("failed to process function type")
|
||||
return nil
|
||||
}
|
||||
if debugParse {
|
||||
log.Println("ProcessFuncDecl: ProcessFieldList")
|
||||
}
|
||||
params := ct.ProcessFieldList(cursor)
|
||||
funcType.Params = params
|
||||
|
||||
@@ -428,6 +520,9 @@ func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl {
|
||||
}
|
||||
|
||||
if isMethod(cursor) {
|
||||
if debugParse {
|
||||
log.Println("ProcessFuncDecl: is method, ProcessMethodAttributes")
|
||||
}
|
||||
ct.ProcessMethodAttributes(cursor, funcDecl)
|
||||
} else {
|
||||
if cursor.StorageClass() == clang.SCStatic {
|
||||
@@ -436,7 +531,6 @@ func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl {
|
||||
}
|
||||
|
||||
ct.SetTypeDecl(cursor, funcDecl)
|
||||
|
||||
return funcDecl
|
||||
}
|
||||
|
||||
@@ -675,7 +769,6 @@ func (ct *Converter) ProcessClassDecl(cursor clang.Cursor) *ast.TypeDecl {
|
||||
Type: typ,
|
||||
}
|
||||
ct.SetTypeDecl(cursor, decl)
|
||||
|
||||
return decl
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,27 @@ package parse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"github.com/goplus/llgo/c/cjson"
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/clangutils"
|
||||
)
|
||||
|
||||
type dbgFlags = int
|
||||
|
||||
const (
|
||||
DbgParse dbgFlags = 1 << iota
|
||||
DbgFlagAll = DbgParse
|
||||
)
|
||||
|
||||
var (
|
||||
debugParse bool
|
||||
)
|
||||
|
||||
func SetDebug(dbgFlags dbgFlags) {
|
||||
debugParse = (dbgFlags & DbgParse) != 0
|
||||
}
|
||||
|
||||
type Context struct {
|
||||
Files []*FileEntry
|
||||
IsCpp bool
|
||||
@@ -25,6 +41,9 @@ func (p *Context) Output() *cjson.JSON {
|
||||
|
||||
// ProcessFiles processes the given files and adds them to the context
|
||||
func (p *Context) ProcessFiles(files []string) error {
|
||||
if debugParse {
|
||||
log.Println("ProcessFiles: files", files, "isCpp", p.IsCpp)
|
||||
}
|
||||
for _, file := range files {
|
||||
if err := p.processFile(file); err != nil {
|
||||
return err
|
||||
@@ -35,8 +54,14 @@ func (p *Context) ProcessFiles(files []string) error {
|
||||
|
||||
// parse file and add it to the context,avoid duplicate parsing
|
||||
func (p *Context) processFile(path string) error {
|
||||
if debugParse {
|
||||
log.Println("processFile: path", path)
|
||||
}
|
||||
for _, entry := range p.Files {
|
||||
if entry.Path == path {
|
||||
if debugParse {
|
||||
log.Println("processFile: already parsed", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -50,6 +75,9 @@ func (p *Context) processFile(path string) error {
|
||||
}
|
||||
|
||||
func (p *Context) parseFile(path string) ([]*FileEntry, error) {
|
||||
if debugParse {
|
||||
log.Println("parseFile: path", path)
|
||||
}
|
||||
converter, err := NewConverter(&clangutils.Config{
|
||||
File: path,
|
||||
Temp: false,
|
||||
|
||||
Reference in New Issue
Block a user