| skipped 26 lines |
27 | 27 | | import javax.swing.WindowConstants; |
28 | 28 | | |
29 | 29 | | import org.jetbrains.annotations.NotNull; |
| 30 | + | import org.jetbrains.annotations.Nullable; |
30 | 31 | | import org.slf4j.Logger; |
31 | 32 | | import org.slf4j.LoggerFactory; |
32 | 33 | | |
33 | | - | import jadx.api.JavaClass; |
34 | | - | import jadx.api.JavaMethod; |
35 | 34 | | import jadx.api.JavaNode; |
36 | | - | import jadx.api.JavaVariable; |
37 | 35 | | import jadx.api.data.ICodeRename; |
38 | 36 | | import jadx.api.data.impl.JadxCodeData; |
39 | | - | import jadx.api.data.impl.JadxCodeRef; |
40 | | - | import jadx.api.data.impl.JadxCodeRename; |
41 | | - | import jadx.api.data.impl.JadxNodeRef; |
42 | | - | import jadx.core.deobf.NameMapper; |
43 | 37 | | import jadx.core.utils.Utils; |
44 | | - | import jadx.core.utils.exceptions.JadxRuntimeException; |
45 | 38 | | import jadx.gui.jobs.TaskStatus; |
46 | 39 | | import jadx.gui.settings.JadxProject; |
47 | 40 | | import jadx.gui.treemodel.JClass; |
48 | | - | import jadx.gui.treemodel.JField; |
49 | | - | import jadx.gui.treemodel.JMethod; |
50 | 41 | | import jadx.gui.treemodel.JNode; |
51 | | - | import jadx.gui.treemodel.JPackage; |
52 | | - | import jadx.gui.treemodel.JVariable; |
| 42 | + | import jadx.gui.treemodel.JRenameNode; |
53 | 43 | | import jadx.gui.ui.MainWindow; |
54 | 44 | | import jadx.gui.ui.TabbedPane; |
55 | 45 | | import jadx.gui.ui.codearea.ClassCodeContentPanel; |
| skipped 14 lines |
70 | 60 | | |
71 | 61 | | private final transient MainWindow mainWindow; |
72 | 62 | | private final transient CacheObject cache; |
73 | | - | private final transient JNode source; |
74 | | - | private final transient JNode node; |
| 63 | + | private final transient @Nullable JNode source; |
| 64 | + | private final transient JRenameNode node; |
75 | 65 | | private transient JTextField renameField; |
76 | 66 | | private transient JButton renameBtn; |
77 | 67 | | |
78 | | - | public static boolean rename(MainWindow mainWindow, JNode node) { |
79 | | - | return rename(mainWindow, node, node); |
80 | | - | } |
81 | | - | |
82 | | - | public static boolean rename(MainWindow mainWindow, JNode source, JNode node) { |
| 68 | + | public static boolean rename(MainWindow mainWindow, JNode source, JRenameNode node) { |
83 | 69 | | RenameDialog renameDialog = new RenameDialog(mainWindow, source, node); |
84 | 70 | | UiUtils.uiRun(() -> renameDialog.setVisible(true)); |
85 | 71 | | UiUtils.uiRun(renameDialog::initRenameField); // wait for UI events to propagate |
86 | 72 | | return true; |
87 | 73 | | } |
88 | 74 | | |
89 | | - | public static JPopupMenu buildRenamePopup(MainWindow mainWindow, JNode node) { |
| 75 | + | public static JPopupMenu buildRenamePopup(MainWindow mainWindow, JRenameNode node) { |
90 | 76 | | JMenuItem jmi = new JMenuItem(NLS.str("popup.rename")); |
91 | | - | jmi.addActionListener(action -> RenameDialog.rename(mainWindow, node)); |
| 77 | + | jmi.addActionListener(action -> RenameDialog.rename(mainWindow, null, node)); |
92 | 78 | | JPopupMenu menu = new JPopupMenu(); |
93 | 79 | | menu.add(jmi); |
94 | 80 | | return menu; |
95 | 81 | | } |
96 | 82 | | |
97 | | - | private RenameDialog(MainWindow mainWindow, JNode source, JNode node) { |
| 83 | + | private RenameDialog(MainWindow mainWindow, JNode source, JRenameNode node) { |
98 | 84 | | super(mainWindow); |
99 | 85 | | this.mainWindow = mainWindow; |
100 | 86 | | this.cache = mainWindow.getCacheObject(); |
101 | 87 | | this.source = source; |
102 | | - | this.node = replaceNode(node); |
| 88 | + | this.node = node.replace(); |
103 | 89 | | initUI(); |
104 | 90 | | } |
105 | 91 | | |
| skipped 2 lines |
108 | 94 | | renameField.selectAll(); |
109 | 95 | | } |
110 | 96 | | |
111 | | - | private JNode replaceNode(JNode node) { |
112 | | - | if (node instanceof JMethod) { |
113 | | - | JavaMethod javaMethod = ((JMethod) node).getJavaMethod(); |
114 | | - | if (javaMethod.isClassInit()) { |
115 | | - | throw new JadxRuntimeException("Can't rename class init method: " + node); |
116 | | - | } |
117 | | - | if (javaMethod.isConstructor()) { |
118 | | - | // rename class instead constructor |
119 | | - | return node.getJParent(); |
120 | | - | } |
121 | | - | } |
122 | | - | return node; |
123 | | - | } |
124 | | - | |
125 | | - | private boolean checkNewName() { |
126 | | - | String newName = renameField.getText(); |
| 97 | + | private boolean checkNewName(String newName) { |
127 | 98 | | if (newName.isEmpty()) { |
128 | 99 | | // use empty name to reset rename (revert to original) |
129 | 100 | | return true; |
130 | 101 | | } |
131 | | - | boolean valid = NameMapper.isValidIdentifier(newName); |
| 102 | + | boolean valid = node.isValidName(newName); |
132 | 103 | | if (renameBtn.isEnabled() != valid) { |
133 | 104 | | renameBtn.setEnabled(valid); |
134 | 105 | | renameField.putClientProperty("JComponent.outline", valid ? "" : "error"); |
| skipped 2 lines |
137 | 108 | | } |
138 | 109 | | |
139 | 110 | | private void rename() { |
140 | | - | if (!checkNewName()) { |
| 111 | + | String newName = renameField.getText().trim(); |
| 112 | + | if (!checkNewName(newName)) { |
141 | 113 | | return; |
142 | 114 | | } |
143 | 115 | | try { |
144 | | - | updateCodeRenames(set -> processRename(node, renameField.getText(), set)); |
| 116 | + | updateCodeRenames(set -> processRename(newName, set)); |
145 | 117 | | refreshState(); |
146 | 118 | | } catch (Exception e) { |
147 | 119 | | LOG.error("Rename failed", e); |
| skipped 2 lines |
150 | 122 | | dispose(); |
151 | 123 | | } |
152 | 124 | | |
153 | | - | private void processRename(JNode node, String newName, Set<ICodeRename> renames) { |
154 | | - | JadxCodeRename rename = buildRename(node, newName, renames); |
| 125 | + | private void processRename(String newName, Set<ICodeRename> renames) { |
| 126 | + | ICodeRename rename = node.buildCodeRename(newName, renames); |
155 | 127 | | renames.remove(rename); |
156 | | - | JavaNode javaNode = node.getJavaNode(); |
157 | | - | if (javaNode != null) { |
158 | | - | javaNode.removeAlias(); |
159 | | - | } |
| 128 | + | node.removeAlias(); |
160 | 129 | | if (!newName.isEmpty()) { |
161 | 130 | | renames.add(rename); |
162 | 131 | | } |
163 | 132 | | } |
164 | 133 | | |
165 | | - | @NotNull |
166 | | - | private JadxCodeRename buildRename(JNode node, String newName, Set<ICodeRename> renames) { |
167 | | - | if (node instanceof JMethod) { |
168 | | - | JavaMethod javaMethod = ((JMethod) node).getJavaMethod(); |
169 | | - | List<JavaMethod> relatedMethods = javaMethod.getOverrideRelatedMethods(); |
170 | | - | if (!relatedMethods.isEmpty()) { |
171 | | - | for (JavaMethod relatedMethod : relatedMethods) { |
172 | | - | renames.remove(new JadxCodeRename(JadxNodeRef.forMth(relatedMethod), "")); |
173 | | - | } |
174 | | - | } |
175 | | - | return new JadxCodeRename(JadxNodeRef.forMth(javaMethod), newName); |
176 | | - | } |
177 | | - | if (node instanceof JField) { |
178 | | - | return new JadxCodeRename(JadxNodeRef.forFld(((JField) node).getJavaField()), newName); |
179 | | - | } |
180 | | - | if (node instanceof JClass) { |
181 | | - | return new JadxCodeRename(JadxNodeRef.forCls(((JClass) node).getCls()), newName); |
182 | | - | } |
183 | | - | if (node instanceof JPackage) { |
184 | | - | return new JadxCodeRename(JadxNodeRef.forPkg(((JPackage) node).getFullName()), newName); |
185 | | - | } |
186 | | - | if (node instanceof JVariable) { |
187 | | - | JavaVariable javaVar = ((JVariable) node).getJavaVarNode(); |
188 | | - | return new JadxCodeRename(JadxNodeRef.forMth(javaVar.getMth()), JadxCodeRef.forVar(javaVar), newName); |
189 | | - | } |
190 | | - | throw new JadxRuntimeException("Failed to build rename node for: " + node); |
191 | | - | } |
192 | | - | |
193 | 134 | | private void updateCodeRenames(Consumer<Set<ICodeRename>> updater) { |
194 | 135 | | JadxProject project = mainWindow.getProject(); |
195 | 136 | | JadxCodeData codeData = project.getCodeData(); |
| skipped 12 lines |
208 | 149 | | private void refreshState() { |
209 | 150 | | mainWindow.getWrapper().reInitRenameVisitor(); |
210 | 151 | | |
211 | | - | JNodeCache nodeCache = cache.getNodeCache(); |
212 | | - | JavaNode javaNode = node.getJavaNode(); |
213 | | - | |
214 | 152 | | List<JavaNode> toUpdate = new ArrayList<>(); |
215 | 153 | | if (source != null && source != node) { |
216 | 154 | | toUpdate.add(source.getJavaNode()); |
217 | 155 | | } |
218 | | - | if (javaNode != null) { |
219 | | - | toUpdate.add(javaNode); |
220 | | - | toUpdate.addAll(javaNode.getUseIn()); |
221 | | - | if (node instanceof JMethod) { |
222 | | - | toUpdate.addAll(((JMethod) node).getJavaMethod().getOverrideRelatedMethods()); |
223 | | - | } |
224 | | - | } else if (node instanceof JPackage) { |
225 | | - | processPackage(toUpdate); |
226 | | - | } else { |
227 | | - | throw new JadxRuntimeException("Unexpected node type: " + node); |
228 | | - | } |
| 156 | + | node.addUpdateNodes(toUpdate); |
| 157 | + | |
| 158 | + | JNodeCache nodeCache = cache.getNodeCache(); |
229 | 159 | | Set<JClass> updatedTopClasses = toUpdate |
230 | 160 | | .stream() |
231 | 161 | | .map(JavaNode::getTopParentClass) |
| skipped 13 lines |
245 | 175 | | mainWindow.showHeapUsageBar(); |
246 | 176 | | UiUtils.errorMessage(this, NLS.str("message.memoryLow")); |
247 | 177 | | } |
248 | | - | if (node instanceof JPackage) { |
249 | | - | mainWindow.getTreeRoot().update(); |
250 | | - | } |
251 | | - | mainWindow.reloadTree(); |
| 178 | + | node.reload(mainWindow); |
252 | 179 | | }); |
253 | | - | } |
254 | | - | } |
255 | | - | |
256 | | - | private void processPackage(List<JavaNode> toUpdate) { |
257 | | - | String rawFullPkg = ((JPackage) node).getFullName(); |
258 | | - | String rawFullPkgDot = rawFullPkg + "."; |
259 | | - | for (JavaClass cls : mainWindow.getWrapper().getClasses()) { |
260 | | - | String clsPkg = cls.getClassNode().getClassInfo().getPackage(); |
261 | | - | // search all classes in package |
262 | | - | if (clsPkg.equals(rawFullPkg) || clsPkg.startsWith(rawFullPkgDot)) { |
263 | | - | toUpdate.add(cls); |
264 | | - | // also include all usages (for import fix) |
265 | | - | toUpdate.addAll(cls.getUseIn()); |
266 | | - | } |
267 | 180 | | } |
268 | 181 | | } |
269 | 182 | | |
| skipped 53 lines |
323 | 236 | | |
324 | 237 | | private void initUI() { |
325 | 238 | | JLabel lbl = new JLabel(NLS.str("popup.rename")); |
326 | | - | JLabel nodeLabel = NodeLabel.longName(node); |
| 239 | + | NodeLabel nodeLabel = new NodeLabel(node.getTitle()); |
| 240 | + | nodeLabel.setIcon(node.getIcon()); |
| 241 | + | if (node instanceof JNode) { |
| 242 | + | nodeLabel.disableHtml(((JNode) node).disableHtml()); |
| 243 | + | } |
327 | 244 | | lbl.setLabelFor(nodeLabel); |
328 | 245 | | |
329 | 246 | | renameField = new JTextField(40); |
330 | | - | renameField.getDocument().addDocumentListener(new DocumentUpdateListener(ev -> checkNewName())); |
| 247 | + | renameField.getDocument().addDocumentListener(new DocumentUpdateListener(ev -> checkNewName(renameField.getText()))); |
331 | 248 | | renameField.addActionListener(e -> rename()); |
332 | 249 | | new TextStandardActions(renameField); |
333 | 250 | | |
| skipped 38 lines |