blob: 7135d8edf11ebfe6cfd016257dd503c3f02dc88f [file] [log] [blame]
Rob Pike1d8f8222011-08-17 13:36:02 +10001// 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
5package main
6
7import (
8 "fmt"
9 "os"
10 "go/ast"
11)
12
13var _ fmt.Stringer
14var _ os.Error
15
16var urlFix = fix{
17 "url",
18 url,
19 `Move the URL pieces of package http into a new package, url.
20
21http://codereview.appspot.com/4893043
22`,
23}
24
25func init() {
26 register(urlFix)
27}
28
29var urlRenames = []struct{ in, out string }{
Rob Pike297a08e2011-08-25 10:16:11 +100030 {"URL", "URL"},
Rob Pike1d8f8222011-08-17 13:36:02 +100031 {"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
41func 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 Niemeyerc5670f12011-09-03 16:01:54 -030049 var skip interface{}
Rob Pike1d8f8222011-08-17 13:36:02 +100050 urlWalk := func(n interface{}) {
Gustavo Niemeyerc5670f12011-09-03 16:01:54 -030051 if n == skip {
52 skip = nil
53 return
54 }
Rob Pike1d8f8222011-08-17 13:36:02 +100055 // Is it an identifier?
56 if ident, ok := n.(*ast.Ident); ok && ident.Name == "url" {
57 ident.Name = "url_"
58 return
59 }
Rob Pike1d8f8222011-08-17 13:36:02 +100060 // 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 Niemeyerc5670f12011-09-03 16:01:54 -030065 // 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 Pike1d8f8222011-08-17 13:36:02 +100071 }
72
73 // Fix up URL code and add import, at most once.
74 fix := func() {
75 if fixed {
76 return
77 }
Gustavo Niemeyerc5670f12011-09-03 16:01:54 -030078 walkBeforeAfter(f, urlWalk, nop)
Rob Pike1d8f8222011-08-17 13:36:02 +100079 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
105func 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}