github.com/profzone/eden-framework@v1.0.10/internal/generator/scanner/status_err_scanner.go (about) 1 package scanner 2 3 import ( 4 "fmt" 5 "github.com/profzone/eden-framework/pkg/courier/status_error" 6 "github.com/profzone/eden-framework/pkg/packagex" 7 "go/ast" 8 "go/types" 9 "sort" 10 "strings" 11 ) 12 13 func NewStatusErrScanner(pkg *packagex.Package) *StatusErrScanner { 14 statusErrorScanner := &StatusErrScanner{ 15 pkg: pkg, 16 statusErrorTypes: map[*types.Named][]*status_error.StatusError{}, 17 errorsUsed: map[*types.Func][]*status_error.StatusError{}, 18 } 19 20 statusErrorScanner.init() 21 22 return statusErrorScanner 23 } 24 25 type StatusErrScanner struct { 26 StatusErrType *types.Named 27 pkg *packagex.Package 28 statusErrorTypes map[*types.Named][]*status_error.StatusError 29 errorsUsed map[*types.Func][]*status_error.StatusError 30 } 31 32 func (scanner *StatusErrScanner) StatusErrorsInFunc(typeFunc *types.Func) []*status_error.StatusError { 33 if typeFunc == nil { 34 return nil 35 } 36 37 if statusErrList, ok := scanner.errorsUsed[typeFunc]; ok { 38 return statusErrList 39 } 40 41 scanner.errorsUsed[typeFunc] = []*status_error.StatusError{} 42 43 pkg := packagex.NewPackage(scanner.pkg.Pkg(typeFunc.Pkg().Path())) 44 45 funcDecl := pkg.FuncDeclOf(typeFunc) 46 47 if funcDecl != nil { 48 ast.Inspect(funcDecl, func(node ast.Node) bool { 49 switch node.(type) { 50 case *ast.CallExpr: 51 identList := packagex.GetIdentChainOfCallFunc(node.(*ast.CallExpr).Fun) 52 if len(identList) > 0 { 53 callIdent := identList[len(identList)-1] 54 obj := pkg.TypesInfo.ObjectOf(callIdent) 55 56 if obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == scanner.StatusErrType.Obj().Pkg().Path() { 57 for i := range identList { 58 scanner.mayAddStateErrorByObject(typeFunc, pkg.TypesInfo.ObjectOf(identList[i])) 59 } 60 return false 61 } 62 if nextTypeFunc, ok := obj.(*types.Func); ok && nextTypeFunc != typeFunc && nextTypeFunc.Pkg() != nil { 63 scanner.appendStateErrs(typeFunc, scanner.StatusErrorsInFunc(nextTypeFunc)...) 64 } 65 } 66 case *ast.Ident: 67 scanner.mayAddStateErrorByObject(typeFunc, pkg.TypesInfo.ObjectOf(node.(*ast.Ident))) 68 } 69 return true 70 }) 71 72 doc := packagex.StringifyCommentGroup(funcDecl.Doc) 73 scanner.appendStateErrs(typeFunc, pickStatusErrorsFromDoc(doc)...) 74 } 75 76 return scanner.errorsUsed[typeFunc] 77 } 78 79 func (scanner *StatusErrScanner) mayAddStateErrorByObject(typeFunc *types.Func, obj types.Object) { 80 if obj == nil { 81 return 82 } 83 if typeConst, ok := obj.(*types.Const); ok { 84 if named, ok := typeConst.Type().(*types.Named); ok { 85 if errs, ok := scanner.statusErrorTypes[named]; ok { 86 for i := range errs { 87 if errs[i].Key == typeConst.Name() { 88 scanner.appendStateErrs(typeFunc, errs[i]) 89 } 90 } 91 } 92 } 93 } 94 } 95 96 func (scanner *StatusErrScanner) appendStateErrs(typeFunc *types.Func, statusErrs ...*status_error.StatusError) { 97 m := map[string]*status_error.StatusError{} 98 99 errs := append(scanner.errorsUsed[typeFunc], statusErrs...) 100 for i := range errs { 101 s := errs[i] 102 m[fmt.Sprintf("%s%d", s.Key, s.Code)] = s 103 } 104 105 next := make([]*status_error.StatusError, 0) 106 for k := range m { 107 next = append(next, m[k]) 108 } 109 110 sort.Slice(next, func(i, j int) bool { 111 return next[i].Code < next[j].Code 112 }) 113 114 scanner.errorsUsed[typeFunc] = next 115 } 116 117 func (scanner *StatusErrScanner) init() { 118 pkg := scanner.pkg.Pkg("github.com/profzone/eden-framework/pkg/courier/status_error") 119 if pkg == nil { 120 return 121 } 122 123 scanner.StatusErrType = packagex.NewPackage(pkg).TypeName("StatusError").Type().(*types.Named) 124 //ttypeStatusError := packagex.NewPackage(pkg).TypeName("StatusError").Type().Underlying().(*types.Interface) 125 // 126 //isStatusError := func(typ *types.TypeName) bool { 127 // return types.Implements(typ.Type(), ttypeStatusError) 128 //} 129 130 //s := NewStatusErrorScanner(scanner.pkg) 131 132 for _, pkgInfo := range scanner.pkg.AllPackages { 133 for _, obj := range pkgInfo.TypesInfo.Defs { 134 if _, ok := obj.(*types.TypeName); ok { 135 //if isStatusError(typName) { 136 // scanner.statusErrorTypes[typName.Type().(*types.Named)] = s.StatusError(typName) 137 //} 138 } 139 } 140 } 141 } 142 143 func pickStatusErrorsFromDoc(doc string) []*status_error.StatusError { 144 statusErrorList := make([]*status_error.StatusError, 0) 145 146 lines := strings.Split(doc, "\n") 147 148 for _, line := range lines { 149 if line != "" { 150 if statusErr := status_error.ParseString(line); statusErr != nil { 151 statusErrorList = append(statusErrorList, statusErr) 152 } 153 } 154 } 155 156 return statusErrorList 157 }