blob: f7f1fe824353dd5cd3e953b0ea49cd281deecbe5 [file] [log] [blame]
Russ Cox28e392d2009-11-20 15:09:54 -08001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package main
6
7import (
Robert Griesemer5a1d3322009-12-15 15:33:31 -08008 "fmt"
9 "go/ast"
10 "go/parser"
11 "go/token"
12 "os"
13 "reflect"
14 "strings"
15 "unicode"
16 "utf8"
Russ Cox28e392d2009-11-20 15:09:54 -080017)
18
19
20func initRewrite() {
21 if *rewriteRule == "" {
Robert Griesemerc78cddd2011-04-14 16:33:29 -070022 rewrite = nil // disable any previous rewrite
Russ Cox28e392d2009-11-20 15:09:54 -080023 return
24 }
Rob Pikeebb15662011-06-28 09:43:14 +100025 f := strings.Split(*rewriteRule, "->")
Russ Cox28e392d2009-11-20 15:09:54 -080026 if len(f) != 2 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080027 fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
28 os.Exit(2)
Russ Cox28e392d2009-11-20 15:09:54 -080029 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -080030 pattern := parseExpr(f[0], "pattern")
31 replace := parseExpr(f[1], "replacement")
32 rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
Russ Cox28e392d2009-11-20 15:09:54 -080033}
34
35
36// parseExpr parses s as an expression.
37// It might make sense to expand this to allow statement patterns,
38// but there are problems with preserving formatting and also
39// with what a wildcard for a statement looks like.
40func parseExpr(s string, what string) ast.Expr {
Robert Griesemer5a9ad8b2010-12-06 14:23:18 -080041 x, err := parser.ParseExpr(fset, "input", s)
Russ Cox28e392d2009-11-20 15:09:54 -080042 if err != nil {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080043 fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
44 os.Exit(2)
Russ Cox28e392d2009-11-20 15:09:54 -080045 }
Robert Griesemer59a3cae2009-12-16 16:53:56 -080046 return x
Russ Cox28e392d2009-11-20 15:09:54 -080047}
48
49
Robert Griesemera5ca6352011-04-13 09:38:13 -070050// Keep this function for debugging.
51/*
52func dump(msg string, val reflect.Value) {
53 fmt.Printf("%s:\n", msg)
54 ast.Print(fset, val.Interface())
55 fmt.Println()
56}
57*/
58
59
Robert Griesemerb32f22b2010-03-15 15:42:09 -070060// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
Russ Cox28e392d2009-11-20 15:09:54 -080061func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080062 m := make(map[string]reflect.Value)
Russ Cox07abf1c2011-04-25 13:39:36 -040063 pat := reflect.ValueOf(pattern)
64 repl := reflect.ValueOf(replace)
Robert Griesemer5a1d3322009-12-15 15:33:31 -080065 var f func(val reflect.Value) reflect.Value // f is recursive
Russ Cox28e392d2009-11-20 15:09:54 -080066 f = func(val reflect.Value) reflect.Value {
Robert Griesemera49e7f32011-04-14 14:25:25 -070067 // don't bother if val is invalid to start with
68 if !val.IsValid() {
69 return reflect.Value{}
70 }
Russ Cox28e392d2009-11-20 15:09:54 -080071 for k := range m {
Russ Coxdb5c5d62011-04-08 12:27:58 -040072 m[k] = reflect.Value{}, false
Russ Cox28e392d2009-11-20 15:09:54 -080073 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -080074 val = apply(f, val)
Russ Cox28e392d2009-11-20 15:09:54 -080075 if match(m, pat, val) {
Russ Cox07abf1c2011-04-25 13:39:36 -040076 val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
Russ Cox28e392d2009-11-20 15:09:54 -080077 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -080078 return val
79 }
Russ Cox07abf1c2011-04-25 13:39:36 -040080 return apply(f, reflect.ValueOf(p)).Interface().(*ast.File)
Russ Cox28e392d2009-11-20 15:09:54 -080081}
82
83
Robert Griesemera6820b62011-01-07 15:04:41 -080084// setValue is a wrapper for x.SetValue(y); it protects
85// the caller from panics if x cannot be changed to y.
86func setValue(x, y reflect.Value) {
Robert Griesemera49e7f32011-04-14 14:25:25 -070087 // don't bother if y is invalid to start with
88 if !y.IsValid() {
89 return
90 }
Robert Griesemera6820b62011-01-07 15:04:41 -080091 defer func() {
92 if x := recover(); x != nil {
93 if s, ok := x.(string); ok && strings.HasPrefix(s, "type mismatch") {
94 // x cannot be set to y - ignore this rewrite
95 return
96 }
97 panic(x)
98 }
99 }()
Russ Coxdb5c5d62011-04-08 12:27:58 -0400100 x.Set(y)
Russ Cox28e392d2009-11-20 15:09:54 -0800101}
102
103
Robert Griesemera5ca6352011-04-13 09:38:13 -0700104// Values/types for special cases.
105var (
Russ Cox07abf1c2011-04-25 13:39:36 -0400106 objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
107 scopePtrNil = reflect.ValueOf((*ast.Scope)(nil))
Robert Griesemera5ca6352011-04-13 09:38:13 -0700108
Russ Cox07abf1c2011-04-25 13:39:36 -0400109 identType = reflect.TypeOf((*ast.Ident)(nil))
110 objectPtrType = reflect.TypeOf((*ast.Object)(nil))
111 positionType = reflect.TypeOf(token.NoPos)
112 scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
Robert Griesemera5ca6352011-04-13 09:38:13 -0700113)
114
115
Russ Cox28e392d2009-11-20 15:09:54 -0800116// apply replaces each AST field x in val with f(x), returning val.
117// To avoid extra conversions, f operates on the reflect.Value form.
118func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
Russ Coxdb5c5d62011-04-08 12:27:58 -0400119 if !val.IsValid() {
120 return reflect.Value{}
Russ Cox28e392d2009-11-20 15:09:54 -0800121 }
Robert Griesemera5ca6352011-04-13 09:38:13 -0700122
123 // *ast.Objects introduce cycles and are likely incorrect after
124 // rewrite; don't follow them but replace with nil instead
125 if val.Type() == objectPtrType {
126 return objectPtrNil
127 }
128
Robert Griesemera49e7f32011-04-14 14:25:25 -0700129 // similarly for scopes: they are likely incorrect after a rewrite;
130 // replace them with nil
131 if val.Type() == scopePtrType {
132 return scopePtrNil
133 }
134
Russ Coxdb5c5d62011-04-08 12:27:58 -0400135 switch v := reflect.Indirect(val); v.Kind() {
136 case reflect.Slice:
Russ Cox28e392d2009-11-20 15:09:54 -0800137 for i := 0; i < v.Len(); i++ {
Russ Coxdb5c5d62011-04-08 12:27:58 -0400138 e := v.Index(i)
Robert Griesemera6820b62011-01-07 15:04:41 -0800139 setValue(e, f(e))
Russ Cox28e392d2009-11-20 15:09:54 -0800140 }
Russ Coxdb5c5d62011-04-08 12:27:58 -0400141 case reflect.Struct:
Russ Cox28e392d2009-11-20 15:09:54 -0800142 for i := 0; i < v.NumField(); i++ {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800143 e := v.Field(i)
Robert Griesemera6820b62011-01-07 15:04:41 -0800144 setValue(e, f(e))
Russ Cox28e392d2009-11-20 15:09:54 -0800145 }
Russ Coxdb5c5d62011-04-08 12:27:58 -0400146 case reflect.Interface:
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800147 e := v.Elem()
Robert Griesemera6820b62011-01-07 15:04:41 -0800148 setValue(v, f(e))
Russ Cox28e392d2009-11-20 15:09:54 -0800149 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800150 return val
Russ Cox28e392d2009-11-20 15:09:54 -0800151}
152
153
Robert Griesemera6820b62011-01-07 15:04:41 -0800154func isWildcard(s string) bool {
155 rune, size := utf8.DecodeRuneInString(s)
156 return size == len(s) && unicode.IsLower(rune)
157}
158
159
Russ Cox28e392d2009-11-20 15:09:54 -0800160// match returns true if pattern matches val,
161// recording wildcard submatches in m.
162// If m == nil, match checks whether pattern == val.
163func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
164 // Wildcard matches any expression. If it appears multiple
165 // times in the pattern, it must match the same expression
166 // each time.
Russ Coxdb5c5d62011-04-08 12:27:58 -0400167 if m != nil && pattern.IsValid() && pattern.Type() == identType {
Robert Griesemer1f9dfa22010-08-13 10:42:18 -0700168 name := pattern.Interface().(*ast.Ident).Name
Russ Coxdb5c5d62011-04-08 12:27:58 -0400169 if isWildcard(name) && val.IsValid() {
Robert Griesemer9d634e52011-01-07 13:33:29 -0800170 // wildcards only match expressions
171 if _, ok := val.Interface().(ast.Expr); ok {
172 if old, ok := m[name]; ok {
173 return match(nil, old, val)
174 }
175 m[name] = val
176 return true
Russ Cox28e392d2009-11-20 15:09:54 -0800177 }
Russ Cox28e392d2009-11-20 15:09:54 -0800178 }
179 }
180
Robert Griesemer9d634e52011-01-07 13:33:29 -0800181 // Otherwise, pattern and val must match recursively.
Russ Coxdb5c5d62011-04-08 12:27:58 -0400182 if !pattern.IsValid() || !val.IsValid() {
183 return !pattern.IsValid() && !val.IsValid()
Russ Cox28e392d2009-11-20 15:09:54 -0800184 }
185 if pattern.Type() != val.Type() {
186 return false
187 }
188
Robert Griesemerb32f22b2010-03-15 15:42:09 -0700189 // Special cases.
190 switch pattern.Type() {
Robert Griesemerb32f22b2010-03-15 15:42:09 -0700191 case identType:
192 // For identifiers, only the names need to match
193 // (and none of the other *ast.Object information).
194 // This is a common case, handle it all here instead
195 // of recursing down any further via reflection.
196 p := pattern.Interface().(*ast.Ident)
197 v := val.Interface().(*ast.Ident)
Robert Griesemer1f9dfa22010-08-13 10:42:18 -0700198 return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
Robert Griesemera5ca6352011-04-13 09:38:13 -0700199 case objectPtrType, positionType:
200 // object pointers and token positions don't need to match
201 return true
Russ Cox28e392d2009-11-20 15:09:54 -0800202 }
203
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800204 p := reflect.Indirect(pattern)
205 v := reflect.Indirect(val)
Russ Coxdb5c5d62011-04-08 12:27:58 -0400206 if !p.IsValid() || !v.IsValid() {
207 return !p.IsValid() && !v.IsValid()
Robert Griesemer4ddcb0e2009-12-17 15:23:19 -0800208 }
Russ Cox28e392d2009-11-20 15:09:54 -0800209
Russ Coxdb5c5d62011-04-08 12:27:58 -0400210 switch p.Kind() {
211 case reflect.Slice:
Robert Griesemer59a3cae2009-12-16 16:53:56 -0800212 if p.Len() != v.Len() {
213 return false
214 }
Russ Cox28e392d2009-11-20 15:09:54 -0800215 for i := 0; i < p.Len(); i++ {
Russ Coxdb5c5d62011-04-08 12:27:58 -0400216 if !match(m, p.Index(i), v.Index(i)) {
Russ Cox28e392d2009-11-20 15:09:54 -0800217 return false
218 }
219 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800220 return true
Russ Cox28e392d2009-11-20 15:09:54 -0800221
Russ Coxdb5c5d62011-04-08 12:27:58 -0400222 case reflect.Struct:
Robert Griesemer59a3cae2009-12-16 16:53:56 -0800223 if p.NumField() != v.NumField() {
224 return false
225 }
Russ Cox28e392d2009-11-20 15:09:54 -0800226 for i := 0; i < p.NumField(); i++ {
227 if !match(m, p.Field(i), v.Field(i)) {
228 return false
229 }
230 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800231 return true
Russ Cox28e392d2009-11-20 15:09:54 -0800232
Russ Coxdb5c5d62011-04-08 12:27:58 -0400233 case reflect.Interface:
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800234 return match(m, p.Elem(), v.Elem())
Russ Cox28e392d2009-11-20 15:09:54 -0800235 }
236
237 // Handle token integers, etc.
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800238 return p.Interface() == v.Interface()
Russ Cox28e392d2009-11-20 15:09:54 -0800239}
240
241
Russ Coxedf74852009-11-23 15:44:27 -0800242// subst returns a copy of pattern with values from m substituted in place
243// of wildcards and pos used as the position of tokens from the pattern.
244// if m == nil, subst returns a copy of pattern and doesn't change the line
245// number information.
246func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
Russ Coxdb5c5d62011-04-08 12:27:58 -0400247 if !pattern.IsValid() {
248 return reflect.Value{}
Russ Cox28e392d2009-11-20 15:09:54 -0800249 }
250
251 // Wildcard gets replaced with map value.
252 if m != nil && pattern.Type() == identType {
Robert Griesemer1f9dfa22010-08-13 10:42:18 -0700253 name := pattern.Interface().(*ast.Ident).Name
Russ Cox28e392d2009-11-20 15:09:54 -0800254 if isWildcard(name) {
255 if old, ok := m[name]; ok {
Russ Coxdb5c5d62011-04-08 12:27:58 -0400256 return subst(nil, old, reflect.Value{})
Russ Cox28e392d2009-11-20 15:09:54 -0800257 }
258 }
259 }
260
Russ Coxdb5c5d62011-04-08 12:27:58 -0400261 if pos.IsValid() && pattern.Type() == positionType {
Robert Griesemerdaf64bf2010-09-24 12:58:08 -0700262 // use new position only if old position was valid in the first place
Robert Griesemer9d634e52011-01-07 13:33:29 -0800263 if old := pattern.Interface().(token.Pos); !old.IsValid() {
Robert Griesemerdaf64bf2010-09-24 12:58:08 -0700264 return pattern
265 }
Russ Coxedf74852009-11-23 15:44:27 -0800266 return pos
Russ Cox28e392d2009-11-20 15:09:54 -0800267 }
268
269 // Otherwise copy.
Russ Coxdb5c5d62011-04-08 12:27:58 -0400270 switch p := pattern; p.Kind() {
271 case reflect.Slice:
272 v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
Russ Cox28e392d2009-11-20 15:09:54 -0800273 for i := 0; i < p.Len(); i++ {
Russ Coxdb5c5d62011-04-08 12:27:58 -0400274 v.Index(i).Set(subst(m, p.Index(i), pos))
Russ Cox28e392d2009-11-20 15:09:54 -0800275 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800276 return v
Russ Cox28e392d2009-11-20 15:09:54 -0800277
Russ Coxdb5c5d62011-04-08 12:27:58 -0400278 case reflect.Struct:
Russ Coxcded21a2011-04-18 14:36:22 -0400279 v := reflect.New(p.Type()).Elem()
Russ Cox28e392d2009-11-20 15:09:54 -0800280 for i := 0; i < p.NumField(); i++ {
Russ Coxdb5c5d62011-04-08 12:27:58 -0400281 v.Field(i).Set(subst(m, p.Field(i), pos))
Russ Cox28e392d2009-11-20 15:09:54 -0800282 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800283 return v
Russ Cox28e392d2009-11-20 15:09:54 -0800284
Russ Coxdb5c5d62011-04-08 12:27:58 -0400285 case reflect.Ptr:
Russ Coxcded21a2011-04-18 14:36:22 -0400286 v := reflect.New(p.Type()).Elem()
Robert Griesemera5ca6352011-04-13 09:38:13 -0700287 if elem := p.Elem(); elem.IsValid() {
288 v.Set(subst(m, elem, pos).Addr())
289 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800290 return v
Russ Cox28e392d2009-11-20 15:09:54 -0800291
Russ Coxdb5c5d62011-04-08 12:27:58 -0400292 case reflect.Interface:
Russ Coxcded21a2011-04-18 14:36:22 -0400293 v := reflect.New(p.Type()).Elem()
Robert Griesemera5ca6352011-04-13 09:38:13 -0700294 if elem := p.Elem(); elem.IsValid() {
295 v.Set(subst(m, elem, pos))
296 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800297 return v
Russ Cox28e392d2009-11-20 15:09:54 -0800298 }
299
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800300 return pattern
Russ Cox28e392d2009-11-20 15:09:54 -0800301}