Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: backport xast package to v28 (partial backport #3770) #4108

Merged
merged 7 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Features

- [#4108](https://github.com/ignite/cli/pull/4108) Add `xast` package (cherry-picked from [#3770](https://github.com/ignite/cli/pull/3770))

### Changes

- [#3959](https://github.com/ignite/cli/pull/3959) Remove app name prefix from the `.gitignore` file
Expand Down
57 changes: 56 additions & 1 deletion ignite/pkg/goanalysis/goanalysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ func DiscoverMain(path string) (pkgPaths []string, err error) {

return nil
})

if err != nil {
return nil, err
}
Expand Down Expand Up @@ -338,3 +337,59 @@ func ReplaceCode(pkgPath, oldFunctionName, newFunction string) (err error) {
}
return nil
}

// HasAnyStructFieldsInPkg finds the struct within a package folder and checks
// if any of the fields are defined in the struct.
func HasAnyStructFieldsInPkg(pkgPath, structName string, fields []string) (bool, error) {
absPath, err := filepath.Abs(pkgPath)
if err != nil {
return false, err
}
fileSet := token.NewFileSet()
all, err := parser.ParseDir(fileSet, absPath, nil, parser.ParseComments)
if err != nil {
return false, err
}

fieldsNames := make(map[string]struct{})
for _, field := range fields {
fieldsNames[strings.ToLower(field)] = struct{}{}
}

exist := false
for _, pkg := range all {
for _, f := range pkg.Files {
ast.Inspect(f, func(x ast.Node) bool {
typeSpec, ok := x.(*ast.TypeSpec)
if !ok {
return true
}

if _, ok := typeSpec.Type.(*ast.StructType); !ok ||
typeSpec.Name.Name != structName ||
typeSpec.Type == nil {
return true
}

// Check if the struct has fields.
structType, ok := typeSpec.Type.(*ast.StructType)
if !ok {
return true
}

// Iterate through the fields of the struct.
for _, field := range structType.Fields.List {
for _, fieldName := range field.Names {
if _, ok := fieldsNames[strings.ToLower(fieldName.Name)]; !ok {
continue
}
exist = true
return false
}
}
return true
})
}
}
return exist, nil
}
118 changes: 105 additions & 13 deletions ignite/pkg/goanalysis/goanalysis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,92 +145,92 @@ func createMainFiles(tmpDir string, mainFiles []string) (pathsWithMain []string,
func TestFuncVarExists(t *testing.T) {
tests := []struct {
name string
testfile string
testFile string
goImport string
methodSignature string
want bool
}{
{
name: "test a declaration inside a method success",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "Background",
goImport: "context",
want: true,
},
{
name: "test global declaration success",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "Join",
goImport: "path/filepath",
want: true,
},
{
name: "test a declaration inside an if and inside a method success",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "SplitList",
goImport: "path/filepath",
want: true,
},
{
name: "test global variable success assign",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "New",
goImport: "errors",
want: true,
},
{
name: "test invalid import",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "Join",
goImport: "errors",
want: false,
},
{
name: "test invalid case sensitive assign",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "join",
goImport: "context",
want: false,
},
{
name: "test invalid struct assign",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "fooStruct",
goImport: "context",
want: false,
},
{
name: "test invalid method signature",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "fooMethod",
goImport: "context",
want: false,
},
{
name: "test not found name",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "Invalid",
goImport: "context",
want: false,
},
{
name: "test invalid assign with wrong",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "invalid.New",
goImport: "context",
want: false,
},
{
name: "test invalid assign with wrong",
testfile: "testdata/varexist",
testFile: "testdata/varexist",
methodSignature: "SplitList",
goImport: "path/filepath",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
appPkg, _, err := xast.ParseFile(tt.testfile)
appPkg, _, err := xast.ParseFile(tt.testFile)
require.NoError(t, err)

got := goanalysis.FuncVarExists(appPkg, tt.goImport, tt.methodSignature)
Expand Down Expand Up @@ -577,3 +577,95 @@ func NewMethod1() {
})
}
}

func TestHasStructFieldsInPkg(t *testing.T) {
tests := []struct {
name string
path string
structName string
fields []string
err error
want bool
}{
{
name: "test a value with an empty struct",
path: "testdata",
structName: "emptyStruct",
fields: []string{"name"},
want: false,
},
{
name: "test no value with an empty struct",
path: "testdata",
structName: "emptyStruct",
fields: []string{""},
want: false,
},
{
name: "test a valid field into single field struct",
path: "testdata",
structName: "fooStruct",
fields: []string{"name"},
want: true,
},
{
name: "test a not valid field into single field struct",
path: "testdata",
structName: "fooStruct",
fields: []string{"baz"},
want: false,
},
{
name: "test a not valid field into struct",
path: "testdata",
structName: "bazStruct",
fields: []string{"baz"},
want: false,
},
{
name: "test a valid field into struct",
path: "testdata",
structName: "bazStruct",
fields: []string{"name"},
want: true,
},
{
name: "test two valid fields into struct",
path: "testdata",
structName: "bazStruct",
fields: []string{"name", "title"},
want: true,
},
{
name: "test a valid and a not valid fields into struct",
path: "testdata",
structName: "bazStruct",
fields: []string{"foo", "title"},
want: true,
},
{
name: "test three not valid fields into struct",
path: "testdata",
structName: "bazStruct",
fields: []string{"foo", "baz", "bla"},
want: false,
},
{
name: "invalid path",
path: "invalid_path",
err: os.ErrNotExist,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := goanalysis.HasAnyStructFieldsInPkg(tt.path, tt.structName, tt.fields)
if tt.err != nil {
require.Error(t, err)
require.ErrorIs(t, err, tt.err)
return
}
require.NoError(t, err)
require.Equal(t, tt.want, got)
})
}
}
13 changes: 13 additions & 0 deletions ignite/pkg/goanalysis/testdata/fieldexist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package goanalysis

type (
emptyStruct struct{}
fooStruct struct {
name string
}
bazStruct struct {
name string
title string
description string
}
)
Loading
Loading