1 11 package org.eclipse.jdt.internal.corext.refactoring.rename; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.Collection ; 16 import java.util.HashSet ; 17 18 import org.eclipse.text.edits.MultiTextEdit; 19 import org.eclipse.text.edits.ReplaceEdit; 20 import org.eclipse.text.edits.TextEdit; 21 import org.eclipse.text.edits.TextEditGroup; 22 23 import org.eclipse.core.runtime.CoreException; 24 import org.eclipse.core.runtime.IProgressMonitor; 25 import org.eclipse.core.runtime.NullProgressMonitor; 26 27 import org.eclipse.jdt.core.ICompilationUnit; 28 import org.eclipse.jdt.core.IJavaElement; 29 import org.eclipse.jdt.core.JavaModelException; 30 import org.eclipse.jdt.core.compiler.IProblem; 31 import org.eclipse.jdt.core.dom.AST; 32 import org.eclipse.jdt.core.dom.ASTNode; 33 import org.eclipse.jdt.core.dom.ASTParser; 34 import org.eclipse.jdt.core.dom.ASTVisitor; 35 import org.eclipse.jdt.core.dom.CompilationUnit; 36 import org.eclipse.jdt.core.dom.IBinding; 37 import org.eclipse.jdt.core.dom.IVariableBinding; 38 import org.eclipse.jdt.core.dom.Initializer; 39 import org.eclipse.jdt.core.dom.MethodDeclaration; 40 import org.eclipse.jdt.core.dom.Name; 41 import org.eclipse.jdt.core.dom.SimpleName; 42 import org.eclipse.jdt.core.dom.VariableDeclaration; 43 44 import org.eclipse.jface.text.Region; 45 46 import org.eclipse.jdt.internal.corext.Assert; 47 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 48 import org.eclipse.jdt.internal.corext.refactoring.Checks; 49 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 50 import org.eclipse.jdt.internal.corext.refactoring.base.JavaRefactorings; 51 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange; 52 import org.eclipse.jdt.internal.corext.refactoring.tagging.INameUpdating; 53 import org.eclipse.jdt.internal.corext.refactoring.tagging.IReferenceUpdating; 54 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 55 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil; 56 57 import org.eclipse.ltk.core.refactoring.Change; 58 import org.eclipse.ltk.core.refactoring.Refactoring; 59 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 60 import org.eclipse.ltk.core.refactoring.TextChange; 61 62 public class RenameTempRefactoring extends Refactoring implements INameUpdating, IReferenceUpdating { 63 private static class ProblemNodeFinder { 64 65 private ProblemNodeFinder() { 66 } 68 69 public static SimpleName[] getProblemNodes(ASTNode methodNode, TextEdit[] edits, TextChange change, String key) { 70 NameNodeVisitor visitor= new NameNodeVisitor(edits, change, key); 71 methodNode.accept(visitor); 72 return visitor.getProblemNodes(); 73 } 74 75 private static class NameNodeVisitor extends ASTVisitor { 76 77 private Collection fRanges; 78 private Collection fProblemNodes; 79 private String fKey; 80 81 public NameNodeVisitor(TextEdit[] edits, TextChange change, String key) { 82 Assert.isNotNull(edits); 83 Assert.isNotNull(key); 84 fRanges= new HashSet (Arrays.asList(RefactoringAnalyzeUtil.getNewRanges(edits, change))); 85 fProblemNodes= new ArrayList (0); 86 fKey= key; 87 } 88 89 public SimpleName[] getProblemNodes() { 90 return (SimpleName[]) fProblemNodes.toArray(new SimpleName[fProblemNodes.size()]); 91 } 92 93 private static VariableDeclaration getVariableDeclaration(Name node) { 94 IBinding binding= node.resolveBinding(); 95 if (binding == null && node.getParent() instanceof VariableDeclaration) 96 return (VariableDeclaration) node.getParent(); 97 98 if (binding != null && binding.getKind() == IBinding.VARIABLE) { 99 CompilationUnit cu= (CompilationUnit) ASTNodes.getParent(node, CompilationUnit.class); 100 return ASTNodes.findVariableDeclaration(((IVariableBinding) binding), cu); 101 } 102 return null; 103 } 104 105 107 public boolean visit(SimpleName node) { 108 VariableDeclaration decl= getVariableDeclaration(node); 109 if (decl == null) 110 return super.visit(node); 111 boolean keysEqual= fKey.equals(RefactoringAnalyzeUtil.getFullBindingKey(decl)); 112 boolean rangeInSet= fRanges.contains(new Region(node.getStartPosition(), node.getLength())); 113 114 if (keysEqual && !rangeInSet) 115 fProblemNodes.add(node); 116 117 if (!keysEqual && rangeInSet) 118 fProblemNodes.add(node); 119 120 return super.visit(node); 121 } 122 } 123 } 124 125 private final int fSelectionStart; 126 private final int fSelectionLength; 127 private final ICompilationUnit fCu; 128 129 private boolean fUpdateReferences; 131 private String fCurrentName; 132 private String fNewName; 133 private CompilationUnit fCompilationUnitNode; 134 private VariableDeclaration fTempDeclarationNode; 135 private TextChange fChange; 136 137 private RenameTempRefactoring(ICompilationUnit cu, int selectionStart, int selectionLength) { 138 Assert.isTrue(selectionStart >= 0); 139 Assert.isTrue(selectionLength >= 0); 140 Assert.isTrue(cu.exists()); 141 fUpdateReferences= true; 142 fSelectionStart= selectionStart; 143 fSelectionLength= selectionLength; 144 fCu= cu; 145 fNewName= ""; } 147 148 public static boolean isAvailable(IJavaElement element) { 149 return element != null && element.getElementType() == IJavaElement.LOCAL_VARIABLE; 150 } 151 152 public static RenameTempRefactoring create(ICompilationUnit cu, int selectionStart, int selectionLength) { 153 return new RenameTempRefactoring(cu, selectionStart, selectionLength); 154 } 155 156 public Object getNewElement(){ 157 return null; } 159 160 163 public String getName() { 164 return RefactoringCoreMessages.getString("RenameTempRefactoring.rename"); } 166 167 170 public boolean canEnableUpdateReferences() { 171 return true; 172 } 173 174 177 public boolean getUpdateReferences() { 178 return fUpdateReferences; 179 } 180 181 184 public void setUpdateReferences(boolean updateReferences) { 185 fUpdateReferences= updateReferences; 186 } 187 188 191 public void setNewElementName(String newName) { 192 Assert.isNotNull(newName); 193 fNewName= newName; 194 } 195 196 199 public String getNewElementName() { 200 return fNewName; 201 } 202 203 206 public String getCurrentElementName() { 207 return fCurrentName; 208 } 209 210 212 215 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { 216 initAST(); 217 if (fTempDeclarationNode == null || fTempDeclarationNode.resolveBinding() == null) 218 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getString("RenameTempRefactoring.must_select_local")); if (! Checks.isDeclaredIn(fTempDeclarationNode, MethodDeclaration.class) 220 && ! Checks.isDeclaredIn(fTempDeclarationNode, Initializer.class)) 221 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getString("RenameTempRefactoring.only_in_methods_and_initializers")); 223 initNames(); 224 return new RefactoringStatus(); 225 } 226 227 private void initAST(){ 228 fCompilationUnitNode= new RefactoringASTParser(AST.JLS2).parse(fCu, true); 229 fTempDeclarationNode= TempDeclarationFinder.findTempDeclaration(fCompilationUnitNode, fSelectionStart, fSelectionLength); 230 } 231 232 private void initNames(){ 233 fCurrentName= fTempDeclarationNode.getName().getIdentifier(); 234 } 235 236 239 public RefactoringStatus checkNewElementName(String newName) throws JavaModelException { 240 RefactoringStatus result= Checks.checkFieldName(newName); 241 if (! Checks.startsWithLowerCase(newName)) 242 result.addWarning(RefactoringCoreMessages.getString("RenameTempRefactoring.lowercase")); return result; 244 } 245 246 249 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException { 250 try { 251 pm.beginTask("", 1); RefactoringStatus result= new RefactoringStatus(); 253 result.merge(Checks.validateModifiesFiles( 254 ResourceUtil.getFiles(new ICompilationUnit[]{fCu}), 255 getValidationContext())); 256 if (result.hasFatalError()) 257 return result; 258 259 result.merge(checkNewElementName(fNewName)); 260 if (result.hasFatalError()) 261 return result; 262 result.merge(analyzeAST()); 263 return result; 264 } finally { 265 pm.done(); 266 } 267 } 268 269 private RefactoringStatus analyzeAST() throws CoreException{ 270 TextEdit declarationEdit= createRenameEdit(fTempDeclarationNode.getName().getStartPosition()); 271 TextEdit[] allRenameEdits= getAllRenameEdits(declarationEdit); 272 fChange= new CompilationUnitChange(RefactoringCoreMessages.getString("RenameTempRefactoring.rename"), fCu); MultiTextEdit rootEdit= new MultiTextEdit(); 274 fChange.setEdit(rootEdit); 275 fChange.setKeepPreviewEdits(true); 276 277 String changeName= RefactoringCoreMessages.getFormattedString("RenameTempRefactoring.changeName", new String []{fCurrentName, fNewName}); for (int i= 0; i < allRenameEdits.length; i++) { 279 rootEdit.addChild(allRenameEdits[i]); 280 fChange.addTextEditGroup(new TextEditGroup(changeName, allRenameEdits[i])); 281 } 282 String newCuSource= fChange.getPreviewContent(new NullProgressMonitor()); 283 ASTParser p= ASTParser.newParser(AST.JLS2); 284 p.setSource(newCuSource.toCharArray()); 285 p.setUnitName(fCu.getElementName()); 286 p.setProject(fCu.getJavaProject()); 287 p.setCompilerOptions(RefactoringASTParser.getCompilerOptions(fCu)); 288 CompilationUnit newCUNode= (CompilationUnit) p.createAST(null); 289 290 RefactoringStatus result= new RefactoringStatus(); 291 result.merge(analyzeCompileErrors(newCuSource, newCUNode)); 292 if (result.hasError()) 293 return result; 294 295 String fullKey= RefactoringAnalyzeUtil.getFullBindingKey(fTempDeclarationNode); 296 ASTNode enclosing= getEnclosingBlockOrMethod(declarationEdit, fChange, newCUNode); 297 SimpleName[] problemNodes= ProblemNodeFinder.getProblemNodes(enclosing, allRenameEdits, fChange, fullKey); 298 result.merge(RefactoringAnalyzeUtil.reportProblemNodes(newCuSource, problemNodes)); 299 return result; 300 } 301 302 private TextEdit[] getAllRenameEdits(TextEdit declarationEdit) { 303 if (! fUpdateReferences) 304 return new TextEdit[] { declarationEdit }; 305 306 TempOccurrenceAnalyzer fTempAnalyzer= new TempOccurrenceAnalyzer(fTempDeclarationNode, true); 307 fTempAnalyzer.perform(); 308 int[] referenceOffsets= fTempAnalyzer.getReferenceAndJavadocOffsets(); 309 310 TextEdit[] allRenameEdits= new TextEdit[referenceOffsets.length + 1]; 311 for (int i= 0; i < referenceOffsets.length; i++) 312 allRenameEdits[i]= createRenameEdit(referenceOffsets[i]); 313 allRenameEdits[referenceOffsets.length]= declarationEdit; 314 return allRenameEdits; 315 } 316 317 private TextEdit createRenameEdit(int offset) { 318 return new ReplaceEdit(offset, fCurrentName.length(), fNewName); 319 } 320 321 private ASTNode getEnclosingBlockOrMethod(TextEdit declarationEdit, TextChange change, CompilationUnit newCUNode) { 322 ASTNode enclosing= RefactoringAnalyzeUtil.getBlock(declarationEdit, change, newCUNode); 323 if (enclosing == null) 324 enclosing= RefactoringAnalyzeUtil.getMethodDeclaration(declarationEdit, change, newCUNode); 325 return enclosing; 326 } 327 328 private RefactoringStatus analyzeCompileErrors(String newCuSource, CompilationUnit newCUNode) { 329 RefactoringStatus result= new RefactoringStatus(); 330 IProblem[] newProblems= RefactoringAnalyzeUtil.getIntroducedCompileProblems(newCUNode, fCompilationUnitNode); 331 for (int i= 0; i < newProblems.length; i++) { 332 IProblem problem= newProblems[i]; 333 if (problem.isError()) 334 result.addEntry(JavaRefactorings.createStatusEntry(problem, newCuSource)); 335 } 336 return result; 337 } 338 339 341 344 public Change createChange(IProgressMonitor pm) throws CoreException { 345 pm.done(); 346 return fChange; 347 } 348 } 349 | Popular Tags |