66 "go/parser"
77 "go/token"
88 "os"
9- "path/filepath"
109 "strings"
1110
1211 tt "github.com/gnoswap-labs/lint/internal/types"
@@ -17,38 +16,22 @@ const (
1716 GNO_STD_PACKAGE = "std"
1817)
1918
20- // Dependency represents an imported package and its usage status.
2119type Dependency struct {
2220 ImportPath string
2321 IsGno bool
2422 IsUsed bool
25- IsIgnored bool // alias with `_` should be ignored
23+ IsIgnored bool // aliased as `_`
2624}
2725
28- type (
29- // Dependencies is a map of import paths to their Dependency information.
30- Dependencies map [string ]* Dependency
26+ type Dependencies map [string ]* Dependency
3127
32- // FileMap is a map of filenames to their parsed AST representation.
33- FileMap map [string ]* ast.File
34- )
35-
36- // Package represents a Go/Gno package with its name and files.
37- type Package struct {
38- Name string
39- Files FileMap
40- }
41-
42- // DetectGnoPackageImports analyzes the given file for Gno package imports and returns any issues found.
4328func DetectGnoPackageImports (filename string ) ([]tt.Issue , error ) {
44- dir := filepath .Dir (filename )
45-
46- pkg , deps , err := analyzePackage (dir )
29+ file , deps , err := analyzeFile (filename )
4730 if err != nil {
48- return nil , fmt .Errorf ("error analyzing package : %w" , err )
31+ return nil , fmt .Errorf ("error analyzing file : %w" , err )
4932 }
5033
51- issues := runGnoPackageLinter (pkg , deps )
34+ issues := runGnoPackageLinter (file , deps )
5235
5336 for i := range issues {
5437 issues [i ].Filename = filename
@@ -57,83 +40,52 @@ func DetectGnoPackageImports(filename string) ([]tt.Issue, error) {
5740 return issues , nil
5841}
5942
60- // parses all gno files and collect their imports and usage.
61- func analyzePackage ( dir string ) ( * Package , Dependencies , error ) {
62- pkg := & Package {
63- Files : make ( FileMap ),
43+ func analyzeFile ( filename string ) ( * ast. File , Dependencies , error ) {
44+ content , err := os . ReadFile ( filename )
45+ if err != nil {
46+ return nil , nil , err
6447 }
65- deps := make (Dependencies )
6648
67- files , err := filepath .Glob (filepath .Join (dir , "*.gno" ))
49+ fset := token .NewFileSet ()
50+ file , err := parser .ParseFile (fset , filename , content , parser .ParseComments )
6851 if err != nil {
6952 return nil , nil , err
7053 }
7154
72- // 1. Parse all file contents and collect dependencies
73- for _ , file := range files {
74- f , err := parseFile (file )
75- if err != nil {
76- return nil , nil , err
77- }
78-
79- pkg .Files [file ] = f
80- if pkg .Name == "" {
81- pkg .Name = f .Name .Name
82- }
83-
84- for _ , imp := range f .Imports {
85- impPath := strings .Trim (imp .Path .Value , `"` )
86- if _ , exists := deps [impPath ]; ! exists {
87- deps [impPath ] = & Dependency {
88- ImportPath : impPath ,
89- IsGno : isGnoPackage (impPath ),
90- IsUsed : false ,
91- IsIgnored : imp .Name != nil && imp .Name .Name == "_" ,
92- }
93- }
55+ deps := make (Dependencies )
56+ for _ , imp := range file .Imports {
57+ impPath := strings .Trim (imp .Path .Value , `"` )
58+ deps [impPath ] = & Dependency {
59+ ImportPath : impPath ,
60+ IsGno : isGnoPackage (impPath ),
61+ IsUsed : false ,
62+ IsIgnored : imp .Name != nil && imp .Name .Name == "_" ,
9463 }
9564 }
9665
97- // 2. Determine which dependencies are used
98- for _ , file := range pkg .Files {
99- ast .Inspect (file , func (n ast.Node ) bool {
100- switch x := n .(type ) {
101- case * ast.SelectorExpr :
102- if ident , ok := x .X .(* ast.Ident ); ok {
103- for _ , imp := range file .Imports {
104- if imp .Name != nil && imp .Name .Name == ident .Name {
105- deps [strings .Trim (imp .Path .Value , `"` )].IsUsed = true
106- } else if lastPart := getLastPart (strings .Trim (imp .Path .Value , `"` )); lastPart == ident .Name {
107- deps [strings .Trim (imp .Path .Value , `"` )].IsUsed = true
108- }
66+ // Determine which dependencies are used in this file
67+ ast .Inspect (file , func (n ast.Node ) bool {
68+ switch x := n .(type ) {
69+ case * ast.SelectorExpr :
70+ if ident , ok := x .X .(* ast.Ident ); ok {
71+ for _ , imp := range file .Imports {
72+ if imp .Name != nil && imp .Name .Name == ident .Name {
73+ deps [strings .Trim (imp .Path .Value , `"` )].IsUsed = true
74+ } else if lastPart := getLastPart (strings .Trim (imp .Path .Value , `"` )); lastPart == ident .Name {
75+ deps [strings .Trim (imp .Path .Value , `"` )].IsUsed = true
10976 }
11077 }
11178 }
112- return true
113- })
114- }
79+ }
80+ return true
81+ })
11582
116- return pkg , deps , nil
83+ return file , deps , nil
11784}
11885
119- func runGnoPackageLinter (pkg * Package , deps Dependencies ) []tt.Issue {
86+ func runGnoPackageLinter (_ * ast. File , deps Dependencies ) []tt.Issue {
12087 var issues []tt.Issue
12188
122- for _ , file := range pkg .Files {
123- ast .Inspect (file , func (n ast.Node ) bool {
124- switch x := n .(type ) {
125- case * ast.SelectorExpr :
126- // check unused imports
127- if ident , ok := x .X .(* ast.Ident ); ok {
128- if dep , exists := deps [ident .Name ]; exists {
129- dep .IsUsed = true
130- }
131- }
132- }
133- return true
134- })
135- }
136-
13789 for impPath , dep := range deps {
13890 if ! dep .IsUsed && ! dep .IsIgnored {
13991 issue := tt.Issue {
@@ -151,16 +103,6 @@ func isGnoPackage(importPath string) bool {
151103 return strings .HasPrefix (importPath , GNO_PKG_PREFIX ) || importPath == GNO_STD_PACKAGE
152104}
153105
154- func parseFile (filename string ) (* ast.File , error ) {
155- content , err := os .ReadFile (filename )
156- if err != nil {
157- return nil , err
158- }
159-
160- fset := token .NewFileSet ()
161- return parser .ParseFile (fset , filename , content , parser .ParseComments )
162- }
163-
164106func getLastPart (path string ) string {
165107 parts := strings .Split (path , "/" )
166108 return parts [len (parts )- 1 ]
0 commit comments