From 6483a8cd44c0832cfdca1b96054073bcbf7cdfbe Mon Sep 17 00:00:00 2001 From: tcs Date: Sat, 21 Aug 2021 12:26:36 +0300 Subject: [PATCH 01/14] global constants and variables support --- .gitignore | 3 +- go.mod | 3 ++ parser.go | 110 +++++++++++++++++++++++++++++++++++++++++++++++------ types.go | 6 ++- 4 files changed, 107 insertions(+), 15 deletions(-) create mode 100644 go.mod diff --git a/.gitignore b/.gitignore index d51f406..f19078a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *~ -*exe \ No newline at end of file +*exe +.idea \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..05c4420 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/zpatrick/go-parser + +go 1.16 diff --git a/parser.go b/parser.go index b9a4ef2..177df9b 100644 --- a/parser.go +++ b/parser.go @@ -11,13 +11,16 @@ import ( ) // ParseFiles parses files at the same time -func ParseFiles(paths []string) ([]*GoFile, error) { +func ParseFiles(paths []string, withComments bool) ([]*GoFile, error) { files := make([]*ast.File, len(paths)) fsets := make([]*token.FileSet, len(paths)) for i, p := range paths { // File: A File node represents a Go source file: https://golang.org/pkg/go/ast/#File fset := token.NewFileSet() - file, err := parser.ParseFile(fset, p, nil, 0) + + var mode parser.Mode + if withComments { mode = parser.ParseComments } else { mode = 0 } + file, err := parser.ParseFile(fset, p, nil, mode) if err != nil { return nil, err } @@ -27,7 +30,7 @@ func ParseFiles(paths []string) ([]*GoFile, error) { goFiles := make([]*GoFile, len(paths)) for i, p := range paths { - goFile, err := parseFile(p, files[i], fsets[i], files) + goFile, err := parseFile(p, nil, files[i], fsets[i], files) if err != nil { return nil, err } @@ -37,20 +40,40 @@ func ParseFiles(paths []string) ([]*GoFile, error) { } // ParseSingleFile parses a single file at the same time -func ParseSingleFile(path string) (*GoFile, error) { +func ParseSingleFile(path string, withComments bool) (*GoFile, error) { fset := token.NewFileSet() - file, err := parser.ParseFile(fset, path, nil, 0) + + var mode parser.Mode + if withComments { mode = parser.ParseComments } else { mode = 0 } + file, err := parser.ParseFile(fset, path, nil, mode) if err != nil { return nil, err } - return parseFile(path, file, fset, []*ast.File{file}) + return parseFile(path, nil, file, fset, []*ast.File{file}) } -func parseFile(path string, file *ast.File, fset *token.FileSet, files []*ast.File) (*GoFile, error) { - source, err := ioutil.ReadFile(path) +func ParseSource(source string, withComments bool) (*GoFile, error) { + fset := token.NewFileSet() + path := "source" + var mode parser.Mode + if withComments { mode = parser.ParseComments } else { mode = 0 } + file, err := parser.ParseFile(fset, path, source, mode) + if err != nil { return nil, err } + return parseFile(path, []byte(source), file, fset, []*ast.File{file}) +} + +func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, files []*ast.File) (*GoFile, error) { + + var err error + if source == nil{ + source, err = ioutil.ReadFile(path) + if err != nil { + return nil, err + } + } // To import sources from vendor, we use "source" compile // https://github.com/golang/go/issues/11415#issuecomment-283445198 @@ -83,6 +106,20 @@ func parseFile(path string, file *ast.File, fset *token.FileSet, files []*ast.Fi for _, genSpec := range genDecl.Specs { switch genSpecType := genSpec.(type) { + // A ValueSpec node represents a constant or variable declaration: https://pkg.go.dev/go/ast#ValueSpec + case *ast.ValueSpec: + valueSpec := genSpecType + + switch genDecl.Tok { + case token.CONST: + goConst := buildGoConstant(source, goFile, info, valueSpec) + goFile.GlobalConstants = append(goFile.GlobalConstants, goConst) + + case token.VAR: + goVar := buildGoVariable(source, goFile, info, valueSpec) + goFile.GlobalVariables = append(goFile.GlobalVariables, goVar) + } + // TypeSpec: A TypeSpec node represents a type declaration: https://golang.org/pkg/go/ast/#TypeSpec case *ast.TypeSpec: typeSpec := genSpecType @@ -125,6 +162,33 @@ func parseFile(path string, file *ast.File, fset *token.FileSet, files []*ast.Fi return goFile, nil } +func buildGoVariable(source []byte, _ *GoFile, info *types.Info, spec *ast.ValueSpec) *GoType { + var t *GoType + if spec.Type == nil{ // untyped const + t = buildType(info, spec.Values[0], source) + } else { + t = buildType(info, spec.Type, source) + } + + t.Name = spec.Names[0].Name + + return t +} + +func buildGoConstant(source []byte, _ *GoFile, info *types.Info, spec *ast.ValueSpec) *GoType { + + var t *GoType + if spec.Type == nil{ // untyped const + t = buildType(info, spec.Values[0], source) + } else { + t = buildType(info, spec.Type, source) + } + + t.Name = spec.Names[0].Name + + return t +} + func buildGoImport(spec *ast.ImportSpec, file *GoFile) *GoImport { name := "" if spec.Name != nil { @@ -193,7 +257,7 @@ func buildReceiverList(info *types.Info, fieldList *ast.FieldList, source []byte if fieldList != nil { for _, t := range fieldList.List { - receivers = append(receivers, getTypeString(t.Type, source)) + receivers = append(receivers, getTypeString(info, t.Type, source)) } } @@ -231,8 +295,28 @@ func getNames(field *ast.Field) []string { return result } -func getTypeString(expr ast.Expr, source []byte) string { - return string(source[expr.Pos()-1 : expr.End()-1]) +func getTypeString(info *types.Info, expr ast.Expr, source []byte) string { + + if expr == nil{ + return "" + } + + switch expr.(type){ + case *ast.BasicLit: + if typeInfo := info.TypeOf(expr); typeInfo != nil { + return typeInfo.String() + } + + case *ast.BinaryExpr: + if typeInfo := info.TypeOf(expr); typeInfo != nil { + return typeInfo.String() + } + + default: + return string(source[expr.Pos()-1 : expr.End()-1]) + } + + return "" } func getUnderlyingTypeString(info *types.Info, expr ast.Expr) string { @@ -256,7 +340,7 @@ func copyType(goType *GoType) *GoType { func buildType(info *types.Info, expr ast.Expr, source []byte) *GoType { innerTypes := []*GoType{} - typeString := getTypeString(expr, source) + typeString := getTypeString(info, expr, source) underlyingString := getUnderlyingTypeString(info, expr) switch specType := expr.(type) { @@ -285,6 +369,8 @@ func buildType(info *types.Info, expr ast.Expr, source []byte) *GoType { case *ast.Ident: case *ast.SelectorExpr: + case *ast.BasicLit: + case *ast.BinaryExpr: default: fmt.Printf("Unexpected field type: `%s`,\n %#v\n", typeString, specType) } diff --git a/types.go b/types.go index 63fba43..e8f6e7d 100644 --- a/types.go +++ b/types.go @@ -9,8 +9,10 @@ import ( type GoFile struct { Package string - Path string - Structs []*GoStruct + Path string + GlobalConstants []*GoType + GlobalVariables []*GoType + Structs []*GoStruct Interfaces []*GoInterface Imports []*GoImport StructMethods []*GoStructMethod From 69a76356ec6d3dc7e748bb17153735f893c11dfb Mon Sep 17 00:00:00 2001 From: tcs Date: Sat, 21 Aug 2021 14:03:49 +0300 Subject: [PATCH 02/14] Comments support --- go.mod | 2 +- parser.go | 33 +++++++++++++++++++++++++++------ types.go | 3 +++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 05c4420..12efaff 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module github.com/zpatrick/go-parser +module github.com/GreenFuze/go-parser go 1.16 diff --git a/parser.go b/parser.go index 177df9b..f573f5f 100644 --- a/parser.go +++ b/parser.go @@ -8,6 +8,7 @@ import ( "go/token" "go/types" "io/ioutil" + "strings" ) // ParseFiles parses files at the same time @@ -130,12 +131,12 @@ func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, // StructType: A StructType node represents a struct type: https://golang.org/pkg/go/ast/#StructType case (*ast.StructType): structType := typeSpecType - goStruct := buildGoStruct(source, goFile, info, typeSpec, structType) + goStruct := buildGoStruct(source, goFile, info, typeSpec, structType, genDecl.Doc) goFile.Structs = append(goFile.Structs, goStruct) // InterfaceType: An InterfaceType node represents an interface type. https://golang.org/pkg/go/ast/#InterfaceType case (*ast.InterfaceType): interfaceType := typeSpecType - goInterface := buildGoInterface(source, goFile, info, typeSpec, interfaceType) + goInterface := buildGoInterface(source, goFile, info, typeSpec, interfaceType, genDecl.Doc) goFile.Interfaces = append(goFile.Interfaces, goInterface) default: // a not-implemented typeSpec.Type.(type), ignore @@ -151,7 +152,7 @@ func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, } case *ast.FuncDecl: funcDecl := declType - goStructMethod := buildStructMethod(info, funcDecl, source) + goStructMethod := buildStructMethod(info, funcDecl, source, declType.Doc) goFile.StructMethods = append(goFile.StructMethods, goStructMethod) default: @@ -207,11 +208,12 @@ func buildGoImport(spec *ast.ImportSpec, file *GoFile) *GoImport { } } -func buildGoInterface(source []byte, file *GoFile, info *types.Info, typeSpec *ast.TypeSpec, interfaceType *ast.InterfaceType) *GoInterface { +func buildGoInterface(source []byte, file *GoFile, info *types.Info, typeSpec *ast.TypeSpec, interfaceType *ast.InterfaceType, cg *ast.CommentGroup) *GoInterface { goInterface := &GoInterface{ File: file, Name: typeSpec.Name.Name, Methods: buildMethodList(info, interfaceType.Methods.List, source), + Comments: extractComment(cg), } return goInterface @@ -241,13 +243,14 @@ func buildMethodList(info *types.Info, fieldList []*ast.Field, source []byte) [] return methods } -func buildStructMethod(info *types.Info, funcDecl *ast.FuncDecl, source []byte) *GoStructMethod { +func buildStructMethod(info *types.Info, funcDecl *ast.FuncDecl, source []byte, cg *ast.CommentGroup) *GoStructMethod { return &GoStructMethod{ Receivers: buildReceiverList(info, funcDecl.Recv, source), GoMethod: GoMethod{ Name: funcDecl.Name.Name, Params: buildTypeList(info, funcDecl.Type.Params, source), Results: buildTypeList(info, funcDecl.Type.Results, source), + Comments: extractComment(cg), }, } } @@ -382,11 +385,12 @@ func buildType(info *types.Info, expr ast.Expr, source []byte) *GoType { } } -func buildGoStruct(source []byte, file *GoFile, info *types.Info, typeSpec *ast.TypeSpec, structType *ast.StructType) *GoStruct { +func buildGoStruct(source []byte, file *GoFile, info *types.Info, typeSpec *ast.TypeSpec, structType *ast.StructType, cg *ast.CommentGroup) *GoStruct { goStruct := &GoStruct{ File: file, Name: typeSpec.Name.Name, Fields: []*GoField{}, + Comments: extractComment(cg), } // Field: A Field declaration list in a struct type, a method list in an interface type, @@ -414,3 +418,20 @@ func buildGoStruct(source []byte, file *GoFile, info *types.Info, typeSpec *ast. return goStruct } + +func extractComment(cg *ast.CommentGroup) string { + if cg == nil || cg.List == nil{ + return "" + } + + var comment string + for _, c := range cg.List{ + comment += c.Text + comment = strings.ReplaceAll(comment, "//", "") + comment = strings.ReplaceAll(comment, "/*", "") + comment = strings.ReplaceAll(comment, "*/", "") + comment = strings.TrimSpace(comment) + } + + return comment +} \ No newline at end of file diff --git a/types.go b/types.go index e8f6e7d..7b2f8c3 100644 --- a/types.go +++ b/types.go @@ -45,12 +45,14 @@ type GoImport struct { type GoInterface struct { File *GoFile Name string + Comments string Methods []*GoMethod } type GoMethod struct { Name string Params []*GoType + Comments string Results []*GoType } @@ -69,6 +71,7 @@ type GoType struct { type GoStruct struct { File *GoFile Name string + Comments string Fields []*GoField } From 17e6125b325b8d411ae315d4692e74382724ae7d Mon Sep 17 00:00:00 2001 From: tcs Date: Sat, 21 Aug 2021 23:39:03 +0300 Subject: [PATCH 03/14] keep filepath when parsing source --- parser.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parser.go b/parser.go index f573f5f..067ffb6 100644 --- a/parser.go +++ b/parser.go @@ -53,9 +53,9 @@ func ParseSingleFile(path string, withComments bool) (*GoFile, error) { return parseFile(path, nil, file, fset, []*ast.File{file}) } -func ParseSource(source string, withComments bool) (*GoFile, error) { +func ParseSource(source string, filepath string, withComments bool) (*GoFile, error) { fset := token.NewFileSet() - path := "source" + path := filepath var mode parser.Mode if withComments { mode = parser.ParseComments } else { mode = 0 } file, err := parser.ParseFile(fset, path, source, mode) From f56f13091640b5040884d059f5da85d6306fc2c9 Mon Sep 17 00:00:00 2001 From: TCs Date: Mon, 27 Jun 2022 11:57:24 +0300 Subject: [PATCH 04/14] custom importer when parsing --- importer.go | 24 ++++++++++++++ parser.go | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 importer.go diff --git a/importer.go b/importer.go new file mode 100644 index 0000000..06f8685 --- /dev/null +++ b/importer.go @@ -0,0 +1,24 @@ +package parser + +import ( + "fmt" + "go/importer" + "go/token" + "go/types" +) + +type PackImporter struct { + Fset *token.FileSet +} + +func (this *PackImporter) Import(path string) (*types.Package, error){ + println("searching for "+path) + + pack, err := importer.ForCompiler(this.Fset, "source", nil).Import(path) + if err != nil{ + fmt.Printf("default importer: %v\n", err) + } + + return pack, nil +} +//-------------------------------------------------------------------- \ No newline at end of file diff --git a/parser.go b/parser.go index 067ffb6..13463b3 100644 --- a/parser.go +++ b/parser.go @@ -1,13 +1,15 @@ package parser import ( + "errors" "fmt" "go/ast" - "go/importer" "go/parser" "go/token" "go/types" "io/ioutil" + "os" + "os/exec" "strings" ) @@ -66,6 +68,60 @@ func ParseSource(source string, filepath string, withComments bool) (*GoFile, er return parseFile(path, []byte(source), file, fset, []*ast.File{file}) } +func execCommand(name string, args ...string) (out string, exitCode int, err error){ + stream := &strings.Builder{} + + cmd := exec.Command(name, args...) + cmd.Stderr = stream + cmd.Stdout = stream + + err = cmd.Run() + if err != nil{ + var terr *exec.ExitError + if errors.As(err, &terr){ + exitCode = terr.ExitCode() + out = stream.String() + } + } + + + fmt.Printf("Execution: %v\n", stream.String()) + + return +} + +func getLibrary(importUrl string) (err error, cleanup func()){ + + fmt.Printf("Importing %v\n", importUrl) + + cleanup = func() {} + + var out string + var exitCode int + + _, staterr := os.Stat("go.mod") + if os.IsNotExist(staterr){ + out, exitCode, err = execCommand("go", "mod", "init", "tempmod") + if err != nil{ + err = fmt.Errorf("failed to execute go mod init command to import Go library: %v.\nError: %v. Exit Code: %v\nOutput: %v\n", importUrl, err, exitCode, out) + return + } + + cleanup = func() { + _ = os.Remove("go.mod") + _ = os.Remove("go.sum") + } + } + + out, exitCode, err = execCommand("go", "get", "-v", importUrl) + if err != nil{ + err = fmt.Errorf("failed to execute go get command to import Go library: %v.\nError: %v. Exit Code: %v\nOutput: %v\n", importUrl, err, exitCode, out) + return + } + + return +} + func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, files []*ast.File) (*GoFile, error) { var err error @@ -75,19 +131,46 @@ func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, return nil, err } } - + + // To import sources from vendor, we use "source" compile // https://github.com/golang/go/issues/11415#issuecomment-283445198 - conf := types.Config{Importer: importer.For("source", nil)} + conf := types.Config{Importer: &PackImporter{fset}/*importer.ForCompiler(fset, "source", nil)*/} info := &types.Info{ Types: make(map[ast.Expr]types.TypeAndValue), Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), } - if _, err = conf.Check(file.Name.Name, fset, files, info); err != nil { - return nil, err + tries := 2 + for tries > 0{ + tries-- + if _, err = conf.Check(file.Name.Name, fset, files, info); err != nil { + + // Get package to import + startingPointString := "could not import " + + start := strings.Index(err.Error(), startingPointString) + if start > -1 && tries > 0{ + start += len(startingPointString) + end := strings.Index(err.Error()[start:], " ") + + if end > -1{ + toimport := err.Error()[start:start+end] + err, cleanup := getLibrary(toimport) + defer cleanup() + if err != nil{ + return nil, err + } + + continue + } + } + + return nil, fmt.Errorf("errors type checking source file. error: %v", err) + } } + goFile := &GoFile{ Path: path, From aee1377fc43f9839512175bf1d8638eac9b1209b Mon Sep 17 00:00:00 2001 From: TCs Date: Sun, 11 Dec 2022 09:30:18 +0200 Subject: [PATCH 05/14] ignore func bodies --- go.mod | 5 +++ go.sum | 20 +++++++++ importer.go | 47 +++++++++++++++++---- parser.go | 118 +++++++++++++++++++++++++++++----------------------- 4 files changed, 129 insertions(+), 61 deletions(-) create mode 100644 go.sum diff --git a/go.mod b/go.mod index 12efaff..d3cd836 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,8 @@ module github.com/GreenFuze/go-parser go 1.16 + +require ( + github.com/GreenFuze/go-mcache v0.0.0-20221207080506-8034db3d9647 // indirect + github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..12d66fd --- /dev/null +++ b/go.sum @@ -0,0 +1,20 @@ +github.com/GreenFuze/go-mcache v0.0.0-20221207080506-8034db3d9647 h1:d7QpF9rd5sCmQhN5BSbjf8ofbQbFMqmZoQDipahLPD4= +github.com/GreenFuze/go-mcache v0.0.0-20221207080506-8034db3d9647/go.mod h1:EQ0/870bGIuf4/tWri44NgO5bOKmGLYh9jXCPngtfTc= +github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a h1:Cf4CrDeyrIcuIiJZEZJAH5dapqQ6J3OmP/vHPbDjaFA= +github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a/go.mod h1:ig6eVXkYn/9dz0Vm8UdLf+E0u1bE6kBSn3n2hqk6jas= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/kevinma2010/astparser v0.0.0-20220911143635-3d191bfbebeb h1:bHLPc+r6JYGSC9tlVK8VKSMw01QBdAgF9ZMRHAwICPM= +github.com/kevinma2010/astparser v0.0.0-20220911143635-3d191bfbebeb/go.mod h1:PqWifNazpe+D7gKeTuPmDYXvRk+J0fr5pjB17t4Cr9s= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/wzshiming/gotype v0.7.3 h1:Wm4qSJ46BM7EeM1q1r65Vdt2OpSlKGZt3ZEkVPnLbpc= +github.com/wzshiming/gotype v0.7.3/go.mod h1:7YULvVsDObRVX2U6iUcF5hixYvHFavLsTSIW26c5GLM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/importer.go b/importer.go index 06f8685..2817d8e 100644 --- a/importer.go +++ b/importer.go @@ -5,20 +5,51 @@ import ( "go/importer" "go/token" "go/types" + "io" + "io/ioutil" + "os" ) type PackImporter struct { Fset *token.FileSet } -func (this *PackImporter) Import(path string) (*types.Package, error){ - println("searching for "+path) - - pack, err := importer.ForCompiler(this.Fset, "source", nil).Import(path) - if err != nil{ - fmt.Printf("default importer: %v\n", err) +func lookup(path string) (io.ReadCloser, error) { + fullpath := "C:\\Program Files\\go\\pkg\\windows_amd64\\" + path + ".a" + stat, err := os.Stat(fullpath) + if os.IsNotExist(err) { + fullpath = "c:\\src\\" + path + stat, err = os.Stat(fullpath) + if os.IsNotExist(err) { + return nil, fmt.Errorf("Did not find " + path) + } } - + + if stat.IsDir() { + files, err := ioutil.ReadDir(fullpath) + if err != nil { + return nil, err + } + fullpath = fullpath + string(os.PathSeparator) + files[0].Name() + + } + + return os.Open(fullpath) +} + +func (this *PackImporter) Import(path string) (*types.Package, error) { + println("searching for " + path) + + pack, err := importer.Default().Import(path) + + if err != nil { + pack, err = importer.ForCompiler(this.Fset, "source", nil).Import(path) + if err != nil { + fmt.Printf("default importer: %v\n", err) + } + } + return pack, nil } -//-------------------------------------------------------------------- \ No newline at end of file + +//-------------------------------------------------------------------- diff --git a/parser.go b/parser.go index 13463b3..dd0c970 100644 --- a/parser.go +++ b/parser.go @@ -22,7 +22,11 @@ func ParseFiles(paths []string, withComments bool) ([]*GoFile, error) { fset := token.NewFileSet() var mode parser.Mode - if withComments { mode = parser.ParseComments } else { mode = 0 } + if withComments { + mode = parser.ParseComments + } else { + mode = 0 + } file, err := parser.ParseFile(fset, p, nil, mode) if err != nil { return nil, err @@ -47,7 +51,11 @@ func ParseSingleFile(path string, withComments bool) (*GoFile, error) { fset := token.NewFileSet() var mode parser.Mode - if withComments { mode = parser.ParseComments } else { mode = 0 } + if withComments { + mode = parser.ParseComments + } else { + mode = 0 + } file, err := parser.ParseFile(fset, path, nil, mode) if err != nil { return nil, err @@ -59,7 +67,11 @@ func ParseSource(source string, filepath string, withComments bool) (*GoFile, er fset := token.NewFileSet() path := filepath var mode parser.Mode - if withComments { mode = parser.ParseComments } else { mode = 0 } + if withComments { + mode = parser.ParseComments + } else { + mode = 0 + } file, err := parser.ParseFile(fset, path, source, mode) if err != nil { @@ -68,109 +80,109 @@ func ParseSource(source string, filepath string, withComments bool) (*GoFile, er return parseFile(path, []byte(source), file, fset, []*ast.File{file}) } -func execCommand(name string, args ...string) (out string, exitCode int, err error){ +func execCommand(name string, args ...string) (out string, exitCode int, err error) { stream := &strings.Builder{} - + cmd := exec.Command(name, args...) cmd.Stderr = stream cmd.Stdout = stream - + fmt.Printf("%v\n", strings.Join(cmd.Args, " ")) + err = cmd.Run() - if err != nil{ + if err != nil { var terr *exec.ExitError - if errors.As(err, &terr){ + if errors.As(err, &terr) { exitCode = terr.ExitCode() out = stream.String() } } - - + fmt.Printf("Execution: %v\n", stream.String()) - + return } -func getLibrary(importUrl string) (err error, cleanup func()){ - +func getLibrary(importUrl string) (err error, cleanup func()) { + fmt.Printf("Importing %v\n", importUrl) - + cleanup = func() {} - + var out string var exitCode int - + _, staterr := os.Stat("go.mod") - if os.IsNotExist(staterr){ + if os.IsNotExist(staterr) { out, exitCode, err = execCommand("go", "mod", "init", "tempmod") - if err != nil{ + if err != nil { err = fmt.Errorf("failed to execute go mod init command to import Go library: %v.\nError: %v. Exit Code: %v\nOutput: %v\n", importUrl, err, exitCode, out) return } - + cleanup = func() { _ = os.Remove("go.mod") _ = os.Remove("go.sum") } } - + out, exitCode, err = execCommand("go", "get", "-v", importUrl) - if err != nil{ + if err != nil { err = fmt.Errorf("failed to execute go get command to import Go library: %v.\nError: %v. Exit Code: %v\nOutput: %v\n", importUrl, err, exitCode, out) return } - + return } func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, files []*ast.File) (*GoFile, error) { var err error - if source == nil{ + if source == nil { source, err = ioutil.ReadFile(path) if err != nil { return nil, err } } - - + // To import sources from vendor, we use "source" compile // https://github.com/golang/go/issues/11415#issuecomment-283445198 - conf := types.Config{Importer: &PackImporter{fset}/*importer.ForCompiler(fset, "source", nil)*/} + conf := types.Config{Importer: &PackImporter{fset} /*importer.ForCompiler(fset, "source", nil)*/} info := &types.Info{ Types: make(map[ast.Expr]types.TypeAndValue), Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), } + conf.IgnoreFuncBodies = true + tries := 2 - for tries > 0{ + for tries > 0 { tries-- if _, err = conf.Check(file.Name.Name, fset, files, info); err != nil { - + // Get package to import startingPointString := "could not import " - + start := strings.Index(err.Error(), startingPointString) - if start > -1 && tries > 0{ + if start > -1 && tries > 0 { start += len(startingPointString) end := strings.Index(err.Error()[start:], " ") - - if end > -1{ - toimport := err.Error()[start:start+end] + + if end > -1 { + toimport := err.Error()[start : start+end] err, cleanup := getLibrary(toimport) defer cleanup() - if err != nil{ + if err != nil { return nil, err } - + continue } } - + return nil, fmt.Errorf("errors type checking source file. error: %v", err) } } - goFile := &GoFile{ Path: path, @@ -248,7 +260,7 @@ func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, func buildGoVariable(source []byte, _ *GoFile, info *types.Info, spec *ast.ValueSpec) *GoType { var t *GoType - if spec.Type == nil{ // untyped const + if spec.Type == nil { // untyped const t = buildType(info, spec.Values[0], source) } else { t = buildType(info, spec.Type, source) @@ -262,7 +274,7 @@ func buildGoVariable(source []byte, _ *GoFile, info *types.Info, spec *ast.Value func buildGoConstant(source []byte, _ *GoFile, info *types.Info, spec *ast.ValueSpec) *GoType { var t *GoType - if spec.Type == nil{ // untyped const + if spec.Type == nil { // untyped const t = buildType(info, spec.Values[0], source) } else { t = buildType(info, spec.Type, source) @@ -293,9 +305,9 @@ func buildGoImport(spec *ast.ImportSpec, file *GoFile) *GoImport { func buildGoInterface(source []byte, file *GoFile, info *types.Info, typeSpec *ast.TypeSpec, interfaceType *ast.InterfaceType, cg *ast.CommentGroup) *GoInterface { goInterface := &GoInterface{ - File: file, - Name: typeSpec.Name.Name, - Methods: buildMethodList(info, interfaceType.Methods.List, source), + File: file, + Name: typeSpec.Name.Name, + Methods: buildMethodList(info, interfaceType.Methods.List, source), Comments: extractComment(cg), } @@ -330,9 +342,9 @@ func buildStructMethod(info *types.Info, funcDecl *ast.FuncDecl, source []byte, return &GoStructMethod{ Receivers: buildReceiverList(info, funcDecl.Recv, source), GoMethod: GoMethod{ - Name: funcDecl.Name.Name, - Params: buildTypeList(info, funcDecl.Type.Params, source), - Results: buildTypeList(info, funcDecl.Type.Results, source), + Name: funcDecl.Name.Name, + Params: buildTypeList(info, funcDecl.Type.Params, source), + Results: buildTypeList(info, funcDecl.Type.Results, source), Comments: extractComment(cg), }, } @@ -383,11 +395,11 @@ func getNames(field *ast.Field) []string { func getTypeString(info *types.Info, expr ast.Expr, source []byte) string { - if expr == nil{ + if expr == nil { return "" } - switch expr.(type){ + switch expr.(type) { case *ast.BasicLit: if typeInfo := info.TypeOf(expr); typeInfo != nil { return typeInfo.String() @@ -470,9 +482,9 @@ func buildType(info *types.Info, expr ast.Expr, source []byte) *GoType { func buildGoStruct(source []byte, file *GoFile, info *types.Info, typeSpec *ast.TypeSpec, structType *ast.StructType, cg *ast.CommentGroup) *GoStruct { goStruct := &GoStruct{ - File: file, - Name: typeSpec.Name.Name, - Fields: []*GoField{}, + File: file, + Name: typeSpec.Name.Name, + Fields: []*GoField{}, Comments: extractComment(cg), } @@ -503,12 +515,12 @@ func buildGoStruct(source []byte, file *GoFile, info *types.Info, typeSpec *ast. } func extractComment(cg *ast.CommentGroup) string { - if cg == nil || cg.List == nil{ + if cg == nil || cg.List == nil { return "" } var comment string - for _, c := range cg.List{ + for _, c := range cg.List { comment += c.Text comment = strings.ReplaceAll(comment, "//", "") comment = strings.ReplaceAll(comment, "/*", "") @@ -517,4 +529,4 @@ func extractComment(cg *ast.CommentGroup) string { } return comment -} \ No newline at end of file +} From 9b554f2f4641f997c4e504b9627f1a543511bff7 Mon Sep 17 00:00:00 2001 From: TCs Date: Sun, 11 Dec 2022 09:44:46 +0200 Subject: [PATCH 06/14] remove reuquired --- go.mod | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.mod b/go.mod index d3cd836..d58d7dd 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,4 @@ module github.com/GreenFuze/go-parser go 1.16 require ( - github.com/GreenFuze/go-mcache v0.0.0-20221207080506-8034db3d9647 // indirect - github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a // indirect ) From eb955a5b266439f372274fa2770d4cd84303f441 Mon Sep 17 00:00:00 2001 From: TCs Date: Mon, 12 Dec 2022 09:16:19 +0200 Subject: [PATCH 07/14] fixes --- go.mod | 3 +- parser_test.go | 13 +++++++ types.go | 103 ++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 99 insertions(+), 20 deletions(-) create mode 100644 parser_test.go diff --git a/go.mod b/go.mod index d58d7dd..ccd4bda 100644 --- a/go.mod +++ b/go.mod @@ -2,5 +2,4 @@ module github.com/GreenFuze/go-parser go 1.16 -require ( -) +require github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a // indirect diff --git a/parser_test.go b/parser_test.go new file mode 100644 index 0000000..1079cb4 --- /dev/null +++ b/parser_test.go @@ -0,0 +1,13 @@ +package parser + +import "testing" + +func TestParseFiles(t *testing.T) { + p, err := ParseSingleFile(`C:/Users/green/go/pkg/mod/github.com/!orlov!evgeny/go-mcache@v0.0.0-20200121124330-1a8195b34f3a/mcache.go`, true) + if err != nil { + t.Fatal(err) + } + + s, _ := p.ImportPath() + println(s) +} diff --git a/types.go b/types.go index 7b2f8c3..72cdff0 100644 --- a/types.go +++ b/types.go @@ -8,32 +8,99 @@ import ( ) type GoFile struct { - Package string + Package string Path string GlobalConstants []*GoType GlobalVariables []*GoType Structs []*GoStruct - Interfaces []*GoInterface - Imports []*GoImport - StructMethods []*GoStructMethod + Interfaces []*GoInterface + Imports []*GoImport + StructMethods []*GoStructMethod } -func (g *GoFile) ImportPath() (string, error) { - importPath, err := filepath.Abs(g.Path) +func isInGoPackages(path string) bool{ + goPath := strings.Replace(os.Getenv("GOPATH"), "\\", "/", -1) + return strings.Contains(path, goPath) +} + +func (g *GoFile) ImportPath() (importPath string, isExternalPackage bool, err error) { + isExternalPackage = false + + importPath, err = filepath.Abs(g.Path) + if err != nil { + return "", false, err + } + + if _, err = os.Stat(importPath); err != nil{ + return g.Path, false, err + } + + if !isInGoPackages(importPath){ + importPath = strings.TrimSuffix(importPath, filepath.Base(importPath)) + importPath = strings.TrimSuffix(importPath, "/") + return importPath, false, nil + } + + importPath, err = filepath.Abs(g.Path) if err != nil { - return "", err + return } importPath = strings.Replace(importPath, "\\", "/", -1) goPath := strings.Replace(os.Getenv("GOPATH"), "\\", "/", -1) + + isExternalPackage = true + importPath = strings.TrimPrefix(importPath, goPath) importPath = strings.TrimPrefix(importPath, "/src/") + importPath = strings.TrimPrefix(importPath, "/pkg/mod/") + + i := strings.Index(importPath, "@") + if i > 0 { + importPath = importPath[:i] + } + + if strings.HasSuffix(strings.ToLower(importPath), ".go") { + i := strings.LastIndex(importPath, "/") + if i > 0 { + importPath = importPath[:i] + } + } + + if strings.Contains(importPath, "!") { // replace "!c" to "C" + temp := "" + nextUppercase := false + for i := 0; i < len(importPath); i++ { + if importPath[i] == '!' { + nextUppercase = true + } else { + if nextUppercase { + temp += strings.ToUpper(string(importPath[i])) + nextUppercase = false + } else { + temp += string(importPath[i]) + } + } + } + importPath = temp + } - importPath = strings.TrimSuffix(importPath, filepath.Base(importPath)) importPath = strings.TrimSuffix(importPath, "/") - return importPath, nil + return + + // + //importPath = strings.Replace(importPath, "\\", "/", -1) + // + //goPath := strings.Replace(os.Getenv("GOPATH"), "\\", "/", -1) + //importPath = strings.TrimPrefix(importPath, goPath) + //importPath = strings.TrimPrefix(importPath, "/src/") + // + //importPath = strings.TrimSuffix(importPath, filepath.Base(importPath)) + //importPath = strings.TrimSuffix(importPath, "/") + // + //return importPath, false, nil } type GoImport struct { @@ -43,17 +110,17 @@ type GoImport struct { } type GoInterface struct { - File *GoFile - Name string + File *GoFile + Name string Comments string - Methods []*GoMethod + Methods []*GoMethod } type GoMethod struct { - Name string - Params []*GoType + Name string + Params []*GoType Comments string - Results []*GoType + Results []*GoType } type GoStructMethod struct { @@ -69,10 +136,10 @@ type GoType struct { } type GoStruct struct { - File *GoFile - Name string + File *GoFile + Name string Comments string - Fields []*GoField + Fields []*GoField } type GoField struct { From 8b32f99912ea6631e19f2490458a1ec7a8227e9b Mon Sep 17 00:00:00 2001 From: GreenFuze Date: Sun, 19 Mar 2023 16:36:59 +0200 Subject: [PATCH 08/14] Update types.go --- types.go | 1 + 1 file changed, 1 insertion(+) diff --git a/types.go b/types.go index 72cdff0..5e91c23 100644 --- a/types.go +++ b/types.go @@ -55,6 +55,7 @@ func (g *GoFile) ImportPath() (importPath string, isExternalPackage bool, err er importPath = strings.TrimPrefix(importPath, goPath) importPath = strings.TrimPrefix(importPath, "/src/") importPath = strings.TrimPrefix(importPath, "/pkg/mod/") + importPath = strings.TrimPrefix(importPath, "pkg/mod/") i := strings.Index(importPath, "@") if i > 0 { From 39975f58f232563cc3f0d6f15e41970ca93d7016 Mon Sep 17 00:00:00 2001 From: TCs Date: Thu, 20 Jul 2023 06:45:25 +0300 Subject: [PATCH 09/14] support parsing packages --- parser.go | 200 +++++++++++++++++++++++++++---------------------- parser_test.go | 13 ---- 2 files changed, 110 insertions(+), 103 deletions(-) delete mode 100644 parser_test.go diff --git a/parser.go b/parser.go index dd0c970..876945e 100644 --- a/parser.go +++ b/parser.go @@ -7,41 +7,47 @@ import ( "go/parser" "go/token" "go/types" - "io/ioutil" + "io/fs" "os" "os/exec" + "reflect" "strings" + "unicode" ) // ParseFiles parses files at the same time -func ParseFiles(paths []string, withComments bool) ([]*GoFile, error) { - files := make([]*ast.File, len(paths)) - fsets := make([]*token.FileSet, len(paths)) - for i, p := range paths { - // File: A File node represents a Go source file: https://golang.org/pkg/go/ast/#File - fset := token.NewFileSet() - - var mode parser.Mode - if withComments { - mode = parser.ParseComments - } else { - mode = 0 - } - file, err := parser.ParseFile(fset, p, nil, mode) - if err != nil { - return nil, err - } - files[i] = file - fsets[i] = fset +func ParseDir(path string, withComments bool, filterFiles func(fs.FileInfo) bool) ([]*GoFile, error) { + + // File: A File node represents a Go source file: https://golang.org/pkg/go/ast/#File + fset := token.NewFileSet() + + var mode parser.Mode + if withComments { + mode = parser.ParseComments + } else { + mode = 0 } - goFiles := make([]*GoFile, len(paths)) - for i, p := range paths { - goFile, err := parseFile(p, nil, files[i], fsets[i], files) - if err != nil { - return nil, err + pkgs, err := parser.ParseDir(fset, path, filterFiles, mode) + if err != nil { + return nil, err + } + + goFiles := make([]*GoFile, 0) + for _, astPackage := range pkgs { + + files := make([]*ast.File, 0) + for _, file := range astPackage.Files { + files = append(files, file) + } + + for name, file := range astPackage.Files { + goFile, err := parseFile(name, file, fset, files) + if err != nil { + return nil, err + } + goFiles = append(goFiles, goFile) } - goFiles[i] = goFile } return goFiles, nil } @@ -60,7 +66,7 @@ func ParseSingleFile(path string, withComments bool) (*GoFile, error) { if err != nil { return nil, err } - return parseFile(path, nil, file, fset, []*ast.File{file}) + return parseFile(path, file, fset, []*ast.File{file}) } func ParseSource(source string, filepath string, withComments bool) (*GoFile, error) { @@ -77,7 +83,7 @@ func ParseSource(source string, filepath string, withComments bool) (*GoFile, er if err != nil { return nil, err } - return parseFile(path, []byte(source), file, fset, []*ast.File{file}) + return parseFile(path, file, fset, []*ast.File{file}) } func execCommand(name string, args ...string) (out string, exitCode int, err error) { @@ -134,15 +140,18 @@ func getLibrary(importUrl string) (err error, cleanup func()) { return } -func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, files []*ast.File) (*GoFile, error) { +func isNamePublic(name string) bool { + if name == "" { + return false + } + + r := []rune(name)[0] + return unicode.IsLetter(r) && unicode.IsUpper(r) +} + +func parseFile(path string, file *ast.File, fset *token.FileSet, files []*ast.File) (*GoFile, error) { var err error - if source == nil { - source, err = ioutil.ReadFile(path) - if err != nil { - return nil, err - } - } // To import sources from vendor, we use "source" compile // https://github.com/golang/go/issues/11415#issuecomment-283445198 @@ -200,24 +209,34 @@ func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, // Specs: the Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec: https://golang.org/pkg/go/ast/#Spec for _, genSpec := range genDecl.Specs { - switch genSpecType := genSpec.(type) { + switch genSpecType := genSpec.(type) { // A ValueSpec node represents a constant or variable declaration: https://pkg.go.dev/go/ast#ValueSpec case *ast.ValueSpec: + + if !isNamePublic(genSpecType.Names[0].Name) { + continue + } + valueSpec := genSpecType switch genDecl.Tok { case token.CONST: - goConst := buildGoConstant(source, goFile, info, valueSpec) + goConst := buildGoConstant(goFile, info, valueSpec) goFile.GlobalConstants = append(goFile.GlobalConstants, goConst) case token.VAR: - goVar := buildGoVariable(source, goFile, info, valueSpec) + goVar := buildGoVariable(goFile, info, valueSpec) goFile.GlobalVariables = append(goFile.GlobalVariables, goVar) } // TypeSpec: A TypeSpec node represents a type declaration: https://golang.org/pkg/go/ast/#TypeSpec case *ast.TypeSpec: + + if !isNamePublic(genSpecType.Name.Name) { + continue + } + typeSpec := genSpecType // typeSpec.Type: an Expr (expression) node: https://golang.org/pkg/go/ast/#Expr @@ -226,12 +245,12 @@ func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, // StructType: A StructType node represents a struct type: https://golang.org/pkg/go/ast/#StructType case (*ast.StructType): structType := typeSpecType - goStruct := buildGoStruct(source, goFile, info, typeSpec, structType, genDecl.Doc) + goStruct := buildGoStruct(goFile, info, typeSpec, structType, genDecl.Doc) goFile.Structs = append(goFile.Structs, goStruct) // InterfaceType: An InterfaceType node represents an interface type. https://golang.org/pkg/go/ast/#InterfaceType case (*ast.InterfaceType): interfaceType := typeSpecType - goInterface := buildGoInterface(source, goFile, info, typeSpec, interfaceType, genDecl.Doc) + goInterface := buildGoInterface(goFile, info, typeSpec, interfaceType, genDecl.Doc) goFile.Interfaces = append(goFile.Interfaces, goInterface) default: // a not-implemented typeSpec.Type.(type), ignore @@ -246,8 +265,13 @@ func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, } } case *ast.FuncDecl: + + if !isNamePublic(declType.Name.Name) { + continue + } + funcDecl := declType - goStructMethod := buildStructMethod(info, funcDecl, source, declType.Doc) + goStructMethod := buildStructMethod(info, funcDecl, declType.Doc) goFile.StructMethods = append(goFile.StructMethods, goStructMethod) default: @@ -258,12 +282,12 @@ func parseFile(path string, source []byte, file *ast.File, fset *token.FileSet, return goFile, nil } -func buildGoVariable(source []byte, _ *GoFile, info *types.Info, spec *ast.ValueSpec) *GoType { +func buildGoVariable(_ *GoFile, info *types.Info, spec *ast.ValueSpec) *GoType { var t *GoType if spec.Type == nil { // untyped const - t = buildType(info, spec.Values[0], source) + t = buildType(info, spec.Values[0]) } else { - t = buildType(info, spec.Type, source) + t = buildType(info, spec.Type) } t.Name = spec.Names[0].Name @@ -271,13 +295,19 @@ func buildGoVariable(source []byte, _ *GoFile, info *types.Info, spec *ast.Value return t } -func buildGoConstant(source []byte, _ *GoFile, info *types.Info, spec *ast.ValueSpec) *GoType { +func goTypeStringFromInterface(data interface{}) string { + return reflect.TypeOf(data).Name() +} + +func buildGoConstant(_ *GoFile, info *types.Info, spec *ast.ValueSpec) *GoType { var t *GoType - if spec.Type == nil { // untyped const - t = buildType(info, spec.Values[0], source) + if spec.Type != nil { // untyped const + t = buildType(info, spec.Type) + } else if spec.Values != nil && len(spec.Values) > 0 { + t = buildType(info, spec.Values[0]) } else { - t = buildType(info, spec.Type, source) + t = &GoType{Type: goTypeStringFromInterface(spec.Names[0].Obj.Data)} } t.Name = spec.Names[0].Name @@ -303,18 +333,18 @@ func buildGoImport(spec *ast.ImportSpec, file *GoFile) *GoImport { } } -func buildGoInterface(source []byte, file *GoFile, info *types.Info, typeSpec *ast.TypeSpec, interfaceType *ast.InterfaceType, cg *ast.CommentGroup) *GoInterface { +func buildGoInterface(file *GoFile, info *types.Info, typeSpec *ast.TypeSpec, interfaceType *ast.InterfaceType, cg *ast.CommentGroup) *GoInterface { goInterface := &GoInterface{ File: file, Name: typeSpec.Name.Name, - Methods: buildMethodList(info, interfaceType.Methods.List, source), + Methods: buildMethodList(info, interfaceType.Methods.List), Comments: extractComment(cg), } return goInterface } -func buildMethodList(info *types.Info, fieldList []*ast.Field, source []byte) []*GoMethod { +func buildMethodList(info *types.Info, fieldList []*ast.Field) []*GoMethod { methods := []*GoMethod{} for _, field := range fieldList { @@ -328,8 +358,8 @@ func buildMethodList(info *types.Info, fieldList []*ast.Field, source []byte) [] goMethod := &GoMethod{ Name: name, - Params: buildTypeList(info, fType.Params, source), - Results: buildTypeList(info, fType.Results, source), + Params: buildTypeList(info, fType.Params), + Results: buildTypeList(info, fType.Results), } methods = append(methods, goMethod) @@ -338,36 +368,36 @@ func buildMethodList(info *types.Info, fieldList []*ast.Field, source []byte) [] return methods } -func buildStructMethod(info *types.Info, funcDecl *ast.FuncDecl, source []byte, cg *ast.CommentGroup) *GoStructMethod { +func buildStructMethod(info *types.Info, funcDecl *ast.FuncDecl, cg *ast.CommentGroup) *GoStructMethod { return &GoStructMethod{ - Receivers: buildReceiverList(info, funcDecl.Recv, source), + Receivers: buildReceiverList(info, funcDecl.Recv), GoMethod: GoMethod{ Name: funcDecl.Name.Name, - Params: buildTypeList(info, funcDecl.Type.Params, source), - Results: buildTypeList(info, funcDecl.Type.Results, source), + Params: buildTypeList(info, funcDecl.Type.Params), + Results: buildTypeList(info, funcDecl.Type.Results), Comments: extractComment(cg), }, } } -func buildReceiverList(info *types.Info, fieldList *ast.FieldList, source []byte) []string { +func buildReceiverList(info *types.Info, fieldList *ast.FieldList) []string { receivers := []string{} if fieldList != nil { for _, t := range fieldList.List { - receivers = append(receivers, getTypeString(info, t.Type, source)) + receivers = append(receivers, getTypeString(info, t.Type)) } } return receivers } -func buildTypeList(info *types.Info, fieldList *ast.FieldList, source []byte) []*GoType { +func buildTypeList(info *types.Info, fieldList *ast.FieldList) []*GoType { types := []*GoType{} if fieldList != nil { for _, t := range fieldList.List { - goType := buildType(info, t.Type, source) + goType := buildType(info, t.Type) for _, n := range getNames(t) { copyType := copyType(goType) @@ -393,28 +423,18 @@ func getNames(field *ast.Field) []string { return result } -func getTypeString(info *types.Info, expr ast.Expr, source []byte) string { +func getTypeString(info *types.Info, expr ast.Expr) string { if expr == nil { return "" } - switch expr.(type) { - case *ast.BasicLit: - if typeInfo := info.TypeOf(expr); typeInfo != nil { - return typeInfo.String() - } - - case *ast.BinaryExpr: - if typeInfo := info.TypeOf(expr); typeInfo != nil { - return typeInfo.String() - } - - default: - return string(source[expr.Pos()-1 : expr.End()-1]) + if typeInfo := info.TypeOf(expr); typeInfo != nil { + return typeInfo.String() } - return "" + panic("info.TypeOf failed to extract type from expression") + } func getUnderlyingTypeString(info *types.Info, expr ast.Expr) string { @@ -436,30 +456,30 @@ func copyType(goType *GoType) *GoType { } } -func buildType(info *types.Info, expr ast.Expr, source []byte) *GoType { +func buildType(info *types.Info, expr ast.Expr) *GoType { innerTypes := []*GoType{} - typeString := getTypeString(info, expr, source) + typeString := getTypeString(info, expr) underlyingString := getUnderlyingTypeString(info, expr) switch specType := expr.(type) { case *ast.FuncType: - innerTypes = append(innerTypes, buildTypeList(info, specType.Params, source)...) - innerTypes = append(innerTypes, buildTypeList(info, specType.Results, source)...) + innerTypes = append(innerTypes, buildTypeList(info, specType.Params)...) + innerTypes = append(innerTypes, buildTypeList(info, specType.Results)...) case *ast.ArrayType: - innerTypes = append(innerTypes, buildType(info, specType.Elt, source)) + innerTypes = append(innerTypes, buildType(info, specType.Elt)) case *ast.StructType: - innerTypes = append(innerTypes, buildTypeList(info, specType.Fields, source)...) + innerTypes = append(innerTypes, buildTypeList(info, specType.Fields)...) case *ast.MapType: - innerTypes = append(innerTypes, buildType(info, specType.Key, source)) - innerTypes = append(innerTypes, buildType(info, specType.Value, source)) + innerTypes = append(innerTypes, buildType(info, specType.Key)) + innerTypes = append(innerTypes, buildType(info, specType.Value)) case *ast.ChanType: - innerTypes = append(innerTypes, buildType(info, specType.Value, source)) + innerTypes = append(innerTypes, buildType(info, specType.Value)) case *ast.StarExpr: - innerTypes = append(innerTypes, buildType(info, specType.X, source)) + innerTypes = append(innerTypes, buildType(info, specType.X)) case *ast.Ellipsis: - innerTypes = append(innerTypes, buildType(info, specType.Elt, source)) + innerTypes = append(innerTypes, buildType(info, specType.Elt)) case *ast.InterfaceType: - methods := buildMethodList(info, specType.Methods.List, source) + methods := buildMethodList(info, specType.Methods.List) for _, m := range methods { innerTypes = append(innerTypes, m.Params...) innerTypes = append(innerTypes, m.Results...) @@ -480,7 +500,7 @@ func buildType(info *types.Info, expr ast.Expr, source []byte) *GoType { } } -func buildGoStruct(source []byte, file *GoFile, info *types.Info, typeSpec *ast.TypeSpec, structType *ast.StructType, cg *ast.CommentGroup) *GoStruct { +func buildGoStruct(file *GoFile, info *types.Info, typeSpec *ast.TypeSpec, structType *ast.StructType, cg *ast.CommentGroup) *GoStruct { goStruct := &GoStruct{ File: file, Name: typeSpec.Name.Name, @@ -495,7 +515,7 @@ func buildGoStruct(source []byte, file *GoFile, info *types.Info, typeSpec *ast. goField := &GoField{ Struct: goStruct, Name: name.String(), - Type: string(source[field.Type.Pos()-1 : field.Type.End()-1]), + Type: getTypeString(info, field.Type), } if field.Tag != nil { diff --git a/parser_test.go b/parser_test.go deleted file mode 100644 index 1079cb4..0000000 --- a/parser_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package parser - -import "testing" - -func TestParseFiles(t *testing.T) { - p, err := ParseSingleFile(`C:/Users/green/go/pkg/mod/github.com/!orlov!evgeny/go-mcache@v0.0.0-20200121124330-1a8195b34f3a/mcache.go`, true) - if err != nil { - t.Fatal(err) - } - - s, _ := p.ImportPath() - println(s) -} From 533fc4ebf13c115ae9113aa92abb39ef48187def Mon Sep 17 00:00:00 2001 From: TCs Date: Thu, 10 Aug 2023 08:40:43 +0300 Subject: [PATCH 10/14] . --- parser.go | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/parser.go b/parser.go index 876945e..7094d26 100644 --- a/parser.go +++ b/parser.go @@ -437,9 +437,89 @@ func getTypeString(info *types.Info, expr ast.Expr) string { } +func typesBasicToString(basic *types.Basic) string { + switch basic.Kind() { + case types.Bool: + return "bool" + case types.Int: + return "int" + case types.Int8: + return "int8" + case types.Int16: + return "int16" + case types.Int32: + return "int32" + case types.Int64: + return "int64" + case types.Uint: + return "uint" + case types.Uint8: + return "uint8" + case types.Uint16: + return "uint16" + case types.Uint32: + return "uint32" + case types.Uint64: + return "uint64" + case types.Uintptr: + return "uint64" + case types.Float32: + return "float32" + case types.Float64: + return "float64" + case types.Complex64: + return "complex64" + case types.Complex128: + return "complex128" + case types.String: + return "string" + case types.UnsafePointer: + return "uint64" + + // types for untyped values + case types.UntypedBool: + return "bool" + case types.UntypedInt: + return "int" + case types.UntypedRune: + return "int32" + case types.UntypedFloat: + return "float64" + case types.UntypedComplex: + return "complex128" + case types.UntypedString: + return "string" + case types.UntypedNil: + return "" + + default: + return "" + } +} + func getUnderlyingTypeString(info *types.Info, expr ast.Expr) string { if typeInfo := info.TypeOf(expr); typeInfo != nil { if underlying := typeInfo.Underlying(); underlying != nil { + if _, ok := underlying.(*types.Interface); ok { + return typeInfo.String() + } + + if _, ok := underlying.(*types.Slice); ok { + if e, ok := underlying.(*types.Slice).Elem().(*types.Basic); ok { + str := typesBasicToString(e) + if str != "" { + return "[]" + str + } + } + } + + if e, ok := underlying.(*types.Basic); ok { + str := typesBasicToString(e) + if str != "" { + return str + } + } + return underlying.String() } } From 7b0168006eb884df1f1b43109903cb700ae68857 Mon Sep 17 00:00:00 2001 From: TCs Date: Tue, 14 Nov 2023 09:00:54 +0200 Subject: [PATCH 11/14] ellipsis parameter --- parser.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/parser.go b/parser.go index 7094d26..4a6bc4e 100644 --- a/parser.go +++ b/parser.go @@ -557,6 +557,8 @@ func buildType(info *types.Info, expr ast.Expr) *GoType { case *ast.StarExpr: innerTypes = append(innerTypes, buildType(info, specType.X)) case *ast.Ellipsis: + typeString = strings.ReplaceAll(typeString, "[]", "...") + underlyingString = strings.ReplaceAll(underlyingString, "[]", "...") innerTypes = append(innerTypes, buildType(info, specType.Elt)) case *ast.InterfaceType: methods := buildMethodList(info, specType.Methods.List) From 0da3c119c9a7c0b2b8c9ba7ed9c499382d6644be Mon Sep 17 00:00:00 2001 From: TCs Date: Fri, 12 Jan 2024 18:37:38 +0200 Subject: [PATCH 12/14] build.Default.GOPATH --- types.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/types.go b/types.go index 5e91c23..6ee2e4a 100644 --- a/types.go +++ b/types.go @@ -1,6 +1,7 @@ package parser import ( + "go/build" "os" "path/filepath" "reflect" @@ -18,8 +19,8 @@ type GoFile struct { StructMethods []*GoStructMethod } -func isInGoPackages(path string) bool{ - goPath := strings.Replace(os.Getenv("GOPATH"), "\\", "/", -1) +func isInGoPackages(path string) bool { + goPath := strings.Replace(build.Default.GOPATH, "\\", "/", -1) return strings.Contains(path, goPath) } @@ -31,11 +32,11 @@ func (g *GoFile) ImportPath() (importPath string, isExternalPackage bool, err er return "", false, err } - if _, err = os.Stat(importPath); err != nil{ + if _, err = os.Stat(importPath); err != nil { return g.Path, false, err } - if !isInGoPackages(importPath){ + if !isInGoPackages(importPath) { importPath = strings.TrimSuffix(importPath, filepath.Base(importPath)) importPath = strings.TrimSuffix(importPath, "/") return importPath, false, nil @@ -48,7 +49,7 @@ func (g *GoFile) ImportPath() (importPath string, isExternalPackage bool, err er importPath = strings.Replace(importPath, "\\", "/", -1) - goPath := strings.Replace(os.Getenv("GOPATH"), "\\", "/", -1) + goPath := strings.Replace(build.Default.GOPATH, "\\", "/", -1) isExternalPackage = true @@ -162,8 +163,10 @@ func (g *GoTag) Get(key string) string { // For an import - guess what prefix will be used // in type declarations. For examples: -// "strings" -> "strings" -// "net/http/httptest" -> "httptest" +// +// "strings" -> "strings" +// "net/http/httptest" -> "httptest" +// // Libraries where the package name does not match // will be mis-identified. func (g *GoImport) Prefix() string { From 83cff8210dd03946fff4d0d9d79bc41290d72881 Mon Sep 17 00:00:00 2001 From: TCs Date: Sat, 13 Jan 2024 10:05:00 +0200 Subject: [PATCH 13/14] replace ForCompiler deprecated function with packages package --- go.mod | 5 +++- go.sum | 71 +++++++++++++++++++++++++++++++++++++++-------------- importer.go | 47 ++++++++++++++--------------------- 3 files changed, 76 insertions(+), 47 deletions(-) diff --git a/go.mod b/go.mod index ccd4bda..51a5f06 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/GreenFuze/go-parser go 1.16 -require github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a // indirect +require ( + github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a // indirect + golang.org/x/tools v0.17.0 +) diff --git a/go.sum b/go.sum index 12d66fd..e51ed54 100644 --- a/go.sum +++ b/go.sum @@ -1,20 +1,55 @@ -github.com/GreenFuze/go-mcache v0.0.0-20221207080506-8034db3d9647 h1:d7QpF9rd5sCmQhN5BSbjf8ofbQbFMqmZoQDipahLPD4= -github.com/GreenFuze/go-mcache v0.0.0-20221207080506-8034db3d9647/go.mod h1:EQ0/870bGIuf4/tWri44NgO5bOKmGLYh9jXCPngtfTc= github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a h1:Cf4CrDeyrIcuIiJZEZJAH5dapqQ6J3OmP/vHPbDjaFA= github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a/go.mod h1:ig6eVXkYn/9dz0Vm8UdLf+E0u1bE6kBSn3n2hqk6jas= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/kevinma2010/astparser v0.0.0-20220911143635-3d191bfbebeb h1:bHLPc+r6JYGSC9tlVK8VKSMw01QBdAgF9ZMRHAwICPM= -github.com/kevinma2010/astparser v0.0.0-20220911143635-3d191bfbebeb/go.mod h1:PqWifNazpe+D7gKeTuPmDYXvRk+J0fr5pjB17t4Cr9s= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/wzshiming/gotype v0.7.3 h1:Wm4qSJ46BM7EeM1q1r65Vdt2OpSlKGZt3ZEkVPnLbpc= -github.com/wzshiming/gotype v0.7.3/go.mod h1:7YULvVsDObRVX2U6iUcF5hixYvHFavLsTSIW26c5GLM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/importer.go b/importer.go index 2817d8e..fa1c66c 100644 --- a/importer.go +++ b/importer.go @@ -5,48 +5,39 @@ import ( "go/importer" "go/token" "go/types" - "io" - "io/ioutil" - "os" + "golang.org/x/tools/go/packages" ) type PackImporter struct { Fset *token.FileSet } -func lookup(path string) (io.ReadCloser, error) { - fullpath := "C:\\Program Files\\go\\pkg\\windows_amd64\\" + path + ".a" - stat, err := os.Stat(fullpath) - if os.IsNotExist(err) { - fullpath = "c:\\src\\" + path - stat, err = os.Stat(fullpath) - if os.IsNotExist(err) { - return nil, fmt.Errorf("Did not find " + path) - } - } - - if stat.IsDir() { - files, err := ioutil.ReadDir(fullpath) - if err != nil { - return nil, err - } - fullpath = fullpath + string(os.PathSeparator) + files[0].Name() - - } - - return os.Open(fullpath) -} - func (this *PackImporter) Import(path string) (*types.Package, error) { println("searching for " + path) pack, err := importer.Default().Import(path) if err != nil { - pack, err = importer.ForCompiler(this.Fset, "source", nil).Import(path) + cfg := &packages.Config{ + Fset: this.Fset, + Mode: packages.NeedTypes, + Tests: true, + } + + // Load the package by its import path + pkgs, err := packages.Load(cfg, path) if err != nil { - fmt.Printf("default importer: %v\n", err) + return nil, err } + + // Check for errors + if packages.PrintErrors(pkgs) > 0 { + return nil, fmt.Errorf("package %s has errors", path) + } + + // Return the first package object + return pkgs[0].Types, nil + } return pack, nil From f3897e769e4c866cf138ed818fa0049b623ffbcd Mon Sep 17 00:00:00 2001 From: GreenFuze <6296195+GreenFuze@users.noreply.github.com> Date: Sun, 14 Apr 2024 11:15:07 +0300 Subject: [PATCH 14/14] go get update --- go.mod | 2 +- go.sum | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 51a5f06..83e58ec 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,5 @@ go 1.16 require ( github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a // indirect - golang.org/x/tools v0.17.0 + golang.org/x/tools v0.20.0 ) diff --git a/go.sum b/go.sum index e51ed54..25679b9 100644 --- a/go.sum +++ b/go.sum @@ -5,11 +5,16 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -17,12 +22,16 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -32,12 +41,17 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -52,4 +66,6 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=