@@ -22,20 +22,27 @@ function renamerefactor(
22
22
)
23
23
mod = getmodule (mod)
24
24
25
- # catch field renaming
25
+ # check on dot accessor
26
26
modnote = if (obj = first (split (full, ' .' ))) != old
27
- if (parentmod = getfield′ (mod, obj)) isa Module && parentmod != mod
28
- modulenote (old, parentmod)
27
+ if (parent = getfield′ (mod, obj)) isa Module
28
+ if parent != mod
29
+ modulenote (old, parent)
30
+ else
31
+ " "
32
+ end
29
33
else
34
+ # catch field renaming
30
35
return Dict (:warning => " Rename refactoring on a field isn't available: `$obj .$old `" )
31
36
end
32
37
else
33
38
" "
34
39
end
35
40
36
- # local refactor only if `old` is really a local binding
37
- bind = CSTParser. bindingof (CSTParser. parse (context))
38
- if bind === nothing || old != bind. name
41
+ expr = CSTParser. parse (context)
42
+ bind = CSTParser. bindingof (expr)
43
+
44
+ # local rename refactor if `old` isn't a toplevel binding
45
+ if bind === nothing || old ≠ bind. name
39
46
try
40
47
refactored = localrefactor (old, new, path, column, row, startrow, context)
41
48
isempty (refactored) || return Dict (
@@ -47,31 +54,52 @@ function renamerefactor(
47
54
end
48
55
end
49
56
57
+ # global rename refactor if the local rename refactor didn't happen
50
58
try
51
59
val = getfield′ (mod, full)
60
+
52
61
# catch keyword renaming
53
62
if val isa Undefined && Symbol (old) in keys (Docs. keywords)
54
63
return Dict (:warning => " Keywords can't be renamed: `$old `" )
55
64
end
56
- # update modnote
57
- if isempty (modnote) && applicable (parentmodule, val) && (parentmod = parentmodule (val)) != mod
58
- modnote = modulenote (old, parentmod)
65
+
66
+ # catch global refactoring not on definition, e.g.: on a call site
67
+ if bind === nothing || old ≠ bind. name
68
+ # TODO : `goto` uri
69
+ return Dict (:info => contextnote (old, mod, context))
59
70
end
60
- kind, desc = globalrefactor (old, new, mod)
61
- return Dict (
62
- kind => kind === :success ?
63
- join ((" _Global_ rename refactoring `$old ` ⟹ `$new ` succeeded." , modnote, desc), " \n\n " ) :
64
- desc
65
- )
71
+
72
+ kind, desc = globalrefactor (old, new, mod, expr)
73
+
74
+ # make description
75
+ if kind === :success
76
+ # update modnote
77
+ if isempty (modnote) && applicable (parentmodule, val) && (parent = parentmodule (val)) ≠ mod
78
+ modnote = modulenote (old, parent)
79
+ end
80
+
81
+ desc = join ((" _Global_ rename refactoring `$old ` ⟹ `$new ` succeeded." , modnote, desc), " \n\n " )
82
+ end
83
+
84
+ return Dict (kind => desc)
66
85
catch err
67
86
@error err
68
87
end
69
88
70
89
return Dict (:error => " Rename refactoring `$old ` ⟹ `$new ` failed" )
71
90
end
72
91
73
- modulenote (old, parentmod) =
74
- " **NOTE**: `$old ` is defined in `$parentmod ` -- you may need the same rename refactorings in that module as well."
92
+ modulenote (old, parentmod) = """
93
+ **NOTE**: `$old ` is defined in `$parentmod `
94
+ -- you may need the same rename refactorings in that module as well.
95
+ """
96
+
97
+ contextnote (old, mod, context) = """
98
+ `$old ` isn't found in local bindings in the current context:
99
+ <details><summary>Context</summary><pre><code>$(strip (context)) </code></p></details>
100
+
101
+ If you want a global rename refactoring on `$mod .$old `, you need to call from its definition.
102
+ """
75
103
76
104
# local refactor
77
105
# --------------
91
119
# global refactor
92
120
# ---------------
93
121
94
- function globalrefactor (old, new, mod)
122
+ function globalrefactor (old, new, mod, expr )
95
123
entrypath, line = moduledefinition (mod)
96
124
files = modulefiles (entrypath)
97
125
98
126
with_logger (JunoProgressLogger ()) do
99
- refactorfiles (old, new, mod, files)
127
+ refactorfiles (old, new, mod, files, expr )
100
128
end
101
129
end
102
130
103
- function refactorfiles (old, new, mod, files)
104
- id = " global_rename_refactor_progress"
105
- @info " Start global rename refactoring" progress= 0 _id= id
131
+ function refactorfiles (old, new, mod, files, expr)
132
+ ismacro = CSTParser. defines_macro (expr)
133
+ oldsym = ismacro ? Symbol (" @" * old) : Symbol (old)
134
+ newsym = ismacro ? Symbol (" @" * new) : Symbol (new)
106
135
107
- oldsym = Symbol (old)
108
- newsym = Symbol (new)
109
136
total = length (files)
110
-
111
137
# TODO : enable line location information (the upstream needs to be enhanced)
112
138
refactoredfiles = Set {String} ()
113
139
140
+ id = " global_rename_refactor_progress"
141
+ @info " Start global rename refactoring" progress= 0 _id= id
142
+
114
143
for (i, file) ∈ enumerate (files)
115
144
@info " Refactoring: $file ($i / $total )" progress= i/ total _id= id
145
+
116
146
MacroTools. sourcewalk (file) do ex
117
- return if ex === oldsym
147
+ if ex === oldsym
118
148
push! (refactoredfiles, fullpath (file))
119
149
newsym
150
+ # handle dot (module) accessor
120
151
elseif @capture (ex, m_.$ oldsym) && getfield′ (mod, Symbol (m)) isa Module
121
152
push! (refactoredfiles, fullpath (file))
122
153
Expr (:., m, newsym)
154
+ # macro case
155
+ elseif ismacro && @capture (ex, macro $ (Symbol (old))(args__) body_ end )
156
+ push! (refactoredfiles, fullpath (file))
157
+ Expr (:macro , :($ (Symbol (new))($ (args... ))), :($ body))
123
158
else
124
159
ex
125
160
end
0 commit comments