Rob Pike | 1d8f822 | 2011-08-17 13:36:02 +1000 | [diff] [blame] | 1 | // Copyright 2011 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 | |
| 5 | package main |
| 6 | |
| 7 | import ( |
| 8 | "fmt" |
| 9 | "os" |
| 10 | "go/ast" |
| 11 | ) |
| 12 | |
| 13 | var _ fmt.Stringer |
| 14 | var _ os.Error |
| 15 | |
| 16 | var urlFix = fix{ |
| 17 | "url", |
| 18 | url, |
| 19 | `Move the URL pieces of package http into a new package, url. |
| 20 | |
| 21 | http://codereview.appspot.com/4893043 |
| 22 | `, |
| 23 | } |
| 24 | |
| 25 | func init() { |
| 26 | register(urlFix) |
| 27 | } |
| 28 | |
| 29 | var urlRenames = []struct{ in, out string }{ |
Rob Pike | 297a08e | 2011-08-25 10:16:11 +1000 | [diff] [blame] | 30 | {"URL", "URL"}, |
Rob Pike | 1d8f822 | 2011-08-17 13:36:02 +1000 | [diff] [blame] | 31 | {"ParseURL", "Parse"}, |
| 32 | {"ParseURLReference", "ParseWithReference"}, |
| 33 | {"ParseQuery", "ParseQuery"}, |
| 34 | {"Values", "Values"}, |
| 35 | {"URLEscape", "QueryEscape"}, |
| 36 | {"URLUnescape", "QueryUnescape"}, |
| 37 | {"URLError", "Error"}, |
| 38 | {"URLEscapeError", "EscapeError"}, |
| 39 | } |
| 40 | |
| 41 | func url(f *ast.File) bool { |
| 42 | if imports(f, "url") || !imports(f, "http") { |
| 43 | return false |
| 44 | } |
| 45 | |
| 46 | fixed := false |
| 47 | |
| 48 | // Update URL code. |
Gustavo Niemeyer | c5670f1 | 2011-09-03 16:01:54 -0300 | [diff] [blame] | 49 | var skip interface{} |
Rob Pike | 1d8f822 | 2011-08-17 13:36:02 +1000 | [diff] [blame] | 50 | urlWalk := func(n interface{}) { |
Gustavo Niemeyer | c5670f1 | 2011-09-03 16:01:54 -0300 | [diff] [blame] | 51 | if n == skip { |
| 52 | skip = nil |
| 53 | return |
| 54 | } |
Rob Pike | 1d8f822 | 2011-08-17 13:36:02 +1000 | [diff] [blame] | 55 | // Is it an identifier? |
| 56 | if ident, ok := n.(*ast.Ident); ok && ident.Name == "url" { |
| 57 | ident.Name = "url_" |
| 58 | return |
| 59 | } |
Rob Pike | 1d8f822 | 2011-08-17 13:36:02 +1000 | [diff] [blame] | 60 | // Parameter and result names. |
| 61 | if fn, ok := n.(*ast.FuncType); ok { |
| 62 | fixed = urlDoFields(fn.Params) || fixed |
| 63 | fixed = urlDoFields(fn.Results) || fixed |
| 64 | } |
Gustavo Niemeyer | c5670f1 | 2011-09-03 16:01:54 -0300 | [diff] [blame] | 65 | // U{url: ...} is likely a struct field. |
| 66 | if kv, ok := n.(*ast.KeyValueExpr); ok { |
| 67 | if ident, ok := kv.Key.(*ast.Ident); ok && ident.Name == "url" { |
| 68 | skip = ident |
| 69 | } |
| 70 | } |
Rob Pike | 1d8f822 | 2011-08-17 13:36:02 +1000 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | // Fix up URL code and add import, at most once. |
| 74 | fix := func() { |
| 75 | if fixed { |
| 76 | return |
| 77 | } |
Gustavo Niemeyer | c5670f1 | 2011-09-03 16:01:54 -0300 | [diff] [blame] | 78 | walkBeforeAfter(f, urlWalk, nop) |
Rob Pike | 1d8f822 | 2011-08-17 13:36:02 +1000 | [diff] [blame] | 79 | addImport(f, "url") |
| 80 | fixed = true |
| 81 | } |
| 82 | |
| 83 | walk(f, func(n interface{}) { |
| 84 | // Rename functions and methods. |
| 85 | if expr, ok := n.(ast.Expr); ok { |
| 86 | for _, s := range urlRenames { |
| 87 | if isPkgDot(expr, "http", s.in) { |
| 88 | fix() |
| 89 | expr.(*ast.SelectorExpr).X.(*ast.Ident).Name = "url" |
| 90 | expr.(*ast.SelectorExpr).Sel.Name = s.out |
| 91 | return |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | }) |
| 96 | |
| 97 | // Remove the http import if no longer needed. |
| 98 | if fixed && !usesImport(f, "http") { |
| 99 | deleteImport(f, "http") |
| 100 | } |
| 101 | |
| 102 | return fixed |
| 103 | } |
| 104 | |
| 105 | func urlDoFields(list *ast.FieldList) (fixed bool) { |
| 106 | if list == nil { |
| 107 | return |
| 108 | } |
| 109 | for _, field := range list.List { |
| 110 | for _, ident := range field.Names { |
| 111 | if ident.Name == "url" { |
| 112 | fixed = true |
| 113 | ident.Name = "url_" |
| 114 | } |
| 115 | } |
| 116 | } |
| 117 | return |
| 118 | } |