-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathast.go
142 lines (137 loc) · 3.86 KB
/
ast.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package fake
import (
"fmt"
"go/ast"
"strings"
"github.com/sonalys/fake/internal/imports"
"github.com/sonalys/fake/internal/packages"
)
func (file *ParsedFile) importConflictResolution() string {
if file.importResolved {
return file.importAlias
}
var alias string = file.PkgName
info, ok := file.Imports[file.PkgName]
// Conflict detected for a package with different path.
if ok && info.Path != file.PkgPath {
alias = fmt.Sprintf("%s1", alias)
}
info = &imports.ImportEntry{
PackageInfo: &packages.PackageInfo{
Path: file.PkgPath,
Name: file.PkgName,
},
Alias: alias,
}
file.Imports[alias] = info
file.ImportsPathMap[file.PkgPath] = info
file.UsedImports[alias] = struct{}{}
file.importAlias = alias
file.importResolved = true
return alias
}
func (f *ParsedInterface) printAstExpr(expr ast.Expr) string {
file := f.ParsedFile
gen := file.Generator
// Extract package and type name
switch fieldType := expr.(type) {
case *ast.Ident:
// If the type name starts with a lowercase letter, it's an internal type.
if strings.ToLower(fieldType.Name[:1]) == fieldType.Name[:1] {
return fieldType.Name
}
// If it's a generic type, we don't need to print package name with it.
for idx, name := range f.GenericsNames {
if name == fieldType.Name {
if len(f.TranslateGenericNames) > 0 {
return f.TranslateGenericNames[idx]
}
return fieldType.Name
}
}
return fmt.Sprintf("%s.%s", file.importConflictResolution(), fieldType.Name)
case *ast.SelectorExpr:
// Type from another package.
pkgName := fmt.Sprint(fieldType.X)
if file.OriginalImports != nil {
pkgInfo, ok := file.OriginalImports[pkgName]
newPkgInfo := file.ImportsPathMap[pkgInfo.Path]
var pkgAlias = newPkgInfo.Name
if newPkgInfo.Alias != "" {
pkgAlias = newPkgInfo.Alias
}
if ok {
file.UsedImports[pkgAlias] = struct{}{}
return fmt.Sprintf("%s.%s", pkgAlias, fieldType.Sel)
}
}
file.UsedImports[pkgName] = struct{}{}
return fmt.Sprintf("%s.%s", pkgName, fieldType.Sel)
case *ast.StarExpr:
return fmt.Sprintf("*%s", f.printAstExpr(fieldType.X))
case *ast.ArrayType:
return fmt.Sprintf("[]%s", f.printAstExpr(fieldType.Elt))
case *ast.Ellipsis:
return fmt.Sprintf("...%s", f.printAstExpr(fieldType.Elt))
case *ast.ChanType:
switch fieldType.Dir {
case ast.RECV:
return fmt.Sprintf("<-chan %s", f.printAstExpr(fieldType.Value))
case ast.SEND:
return fmt.Sprintf("chan<-%s", f.printAstExpr(fieldType.Value))
case ast.SEND | ast.RECV:
return fmt.Sprintf("chan %s", f.printAstExpr(fieldType.Value))
}
case *ast.MapType:
return fmt.Sprintf("map[%s]%s", f.printAstExpr(fieldType.Key), f.printAstExpr(fieldType.Value))
case *ast.FuncType:
b := &strings.Builder{}
f.PrintMethodHeader(b, "func", &ParsedField{
Interface: f,
Ref: &ast.Field{
Type: expr,
},
Name: "func",
})
return b.String()
case *ast.InterfaceType:
if fieldType.Methods.NumFields() == 0 {
return "interface{}"
}
methods := gen.listInterfaceFields(&ParsedInterface{
Ref: fieldType,
}, file.Imports)
b := &strings.Builder{}
for _, method := range methods {
for _, methodName := range method.Ref.Names {
b.WriteString("\t\t")
f.PrintMethodHeader(b, methodName.Name, &ParsedField{
Interface: f,
Ref: &ast.Field{
Type: method.Ref.Type.(*ast.FuncType),
},
Name: methodName.Name,
})
}
}
return fmt.Sprintf("interface{\n%s\n}", b.String())
}
return ""
}
func getAstTypeName(expr ast.Expr) string {
switch fieldType := expr.(type) {
case *ast.Ident:
return fieldType.Name
case *ast.SelectorExpr:
return fmt.Sprintf("%s", fieldType.X)
case *ast.StarExpr:
return getAstTypeName(fieldType.X)
case *ast.ArrayType:
return getAstTypeName(fieldType.Elt)
case *ast.Ellipsis:
return getAstTypeName(fieldType.Elt)
case *ast.ChanType:
return getAstTypeName(fieldType.Value)
}
return ""
}