reporter.mx raw
1 package main
2
3 import (
4 "fmt"
5 "io"
6 )
7
8 func report(w io.Writer, path string, f *File) {
9 for _, d := range f.DeclList {
10 reportDecl(w, path, d)
11 }
12 }
13
14 func reportDecl(w io.Writer, path string, d Decl) {
15 switch d := d.(type) {
16 case *ImportDecl:
17 if d.Path == nil {
18 return
19 }
20 v := unquote(d.Path.Value)
21 switch v {
22 case "reflect":
23 flag(w, path, d.Pos(), "reflect", "reflect import - requires manual elimination")
24 case "sync":
25 flag(w, path, d.Pos(), "sync", "sync import - no shared memory in moxie")
26 case "context":
27 flag(w, path, d.Pos(), "context", "context import - restructure to channels")
28 case "unsafe":
29 flag(w, path, d.Pos(), "unsafe", "unsafe import - review for necessity")
30 }
31
32 case *VarDecl:
33 flag(w, path, d.Pos(), "pkg-var", "package-level var: " | d.NameList[0].Value)
34
35 case *FuncDecl:
36 if d.Body != nil {
37 reportBlock(w, path, d.Body)
38 }
39 }
40 }
41
42 func reportBlock(w io.Writer, path string, b *BlockStmt) {
43 for _, s := range b.List {
44 reportStmt(w, path, s)
45 }
46 }
47
48 func reportStmt(w io.Writer, path string, s Stmt) {
49 if s == nil {
50 return
51 }
52 switch s := s.(type) {
53 case *CallStmt:
54 if s.Tok == Go {
55 flag(w, path, s.Pos(), "goroutine", "go statement - restructure to spawn/channels")
56 }
57 reportExpr(w, path, s.Call)
58
59 case *ExprStmt:
60 reportExpr(w, path, s.X)
61
62 case *SendStmt:
63 reportExpr(w, path, s.Chan)
64 reportExpr(w, path, s.Value)
65
66 case *AssignStmt:
67 reportExpr(w, path, s.Lhs)
68 reportExpr(w, path, s.Rhs)
69
70 case *ReturnStmt:
71 reportExpr(w, path, s.Results)
72
73 case *IfStmt:
74 reportSimpleStmt(w, path, s.Init)
75 reportExpr(w, path, s.Cond)
76 reportBlock(w, path, s.Then)
77 if s.Else != nil {
78 reportStmt(w, path, s.Else)
79 }
80
81 case *ForStmt:
82 reportSimpleStmt(w, path, s.Init)
83 reportExpr(w, path, s.Cond)
84 reportSimpleStmt(w, path, s.Post)
85 reportBlock(w, path, s.Body)
86
87 case *SwitchStmt:
88 reportSimpleStmt(w, path, s.Init)
89 reportExpr(w, path, s.Tag)
90 for _, cc := range s.Body {
91 reportExpr(w, path, cc.Cases)
92 for _, st := range cc.Body {
93 reportStmt(w, path, st)
94 }
95 }
96
97 case *SelectStmt:
98 for _, cc := range s.Body {
99 reportSimpleStmt(w, path, cc.Comm)
100 for _, st := range cc.Body {
101 reportStmt(w, path, st)
102 }
103 }
104
105 case *BlockStmt:
106 reportBlock(w, path, s)
107
108 case *DeclStmt:
109 for _, d := range s.DeclList {
110 reportDecl(w, path, d)
111 }
112
113 case *LabeledStmt:
114 reportStmt(w, path, s.Stmt)
115
116 case *BranchStmt:
117 if s.Tok == Fallthrough {
118 flag(w, path, s.Pos(), "fallthrough", "fallthrough with preceding code - needs manual restructure")
119 }
120 }
121 }
122
123 func reportSimpleStmt(w io.Writer, path string, s SimpleStmt) {
124 if s == nil {
125 return
126 }
127 switch s := s.(type) {
128 case *ExprStmt:
129 reportExpr(w, path, s.X)
130 case *SendStmt:
131 reportExpr(w, path, s.Chan)
132 reportExpr(w, path, s.Value)
133 case *AssignStmt:
134 reportExpr(w, path, s.Lhs)
135 reportExpr(w, path, s.Rhs)
136 case *RangeClause:
137 reportExpr(w, path, s.Lhs)
138 reportExpr(w, path, s.X)
139 }
140 }
141
142 func reportExpr(w io.Writer, path string, e Expr) {
143 if e == nil {
144 return
145 }
146 switch e := e.(type) {
147 case *Name:
148 switch e.Value {
149 case "any":
150 flag(w, path, e.Pos(), "any", "any type - needs concrete type or interface")
151 case "uintptr":
152 flag(w, path, e.Pos(), "uintptr", "uintptr - removed in moxie")
153 case "complex64":
154 flag(w, path, e.Pos(), "complex", "complex64 - removed in moxie")
155 case "complex128":
156 flag(w, path, e.Pos(), "complex", "complex128 - removed in moxie")
157 }
158
159 case *InterfaceType:
160 if int32(len(e.MethodList)) == 0 {
161 flag(w, path, e.Pos(), "empty-iface", "interface{} - needs concrete type")
162 }
163
164 case *Operation:
165 if e.Op == Add && e.Y != nil && !isStringLit(e.X) && !isStringLit(e.Y) {
166 flag(w, path, e.Pos(), "maybe-string+", "+ operator on non-literal - check if string concat")
167 }
168 reportExpr(w, path, e.X)
169 reportExpr(w, path, e.Y)
170
171 case *CallExpr:
172 reportExpr(w, path, e.Fun)
173 for _, arg := range e.ArgList {
174 reportExpr(w, path, arg)
175 }
176
177 case *CompositeLit:
178 reportExpr(w, path, e.Type)
179 for _, elem := range e.ElemList {
180 reportExpr(w, path, elem)
181 }
182
183 case *KeyValueExpr:
184 reportExpr(w, path, e.Key)
185 reportExpr(w, path, e.Value)
186
187 case *FuncLit:
188 if e.Body != nil {
189 reportBlock(w, path, e.Body)
190 }
191
192 case *ParenExpr:
193 reportExpr(w, path, e.X)
194
195 case *SelectorExpr:
196 reportExpr(w, path, e.X)
197
198 case *IndexExpr:
199 reportExpr(w, path, e.X)
200 reportExpr(w, path, e.Index)
201
202 case *SliceExpr:
203 reportExpr(w, path, e.X)
204 for i := 0; i < 3; i++ {
205 reportExpr(w, path, e.Index[i])
206 }
207
208 case *AssertExpr:
209 reportExpr(w, path, e.X)
210 reportExpr(w, path, e.Type)
211
212 case *TypeSwitchGuard:
213 reportExpr(w, path, e.X)
214
215 case *ListExpr:
216 for _, elem := range e.ElemList {
217 reportExpr(w, path, elem)
218 }
219 }
220 }
221
222 func flag(w io.Writer, path string, pos Pos, kind string, msg string) {
223 if pos.IsKnown() {
224 fmt.Fprintf(w, "%s:%d:%d: [%s] %s\n", path, pos.Line(), pos.Col(), kind, msg)
225 } else {
226 fmt.Fprintf(w, "%s: [%s] %s\n", path, kind, msg)
227 }
228 }
229
230 func unquote(s string) string {
231 if int32(len(s)) >= 2 && s[0] == '"' && s[int32(len(s))-1] == '"' {
232 return s[1 : int32(len(s))-1]
233 }
234 return s
235 }
236