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.HashMap ; 17 import java.util.HashSet ; 18 import java.util.Iterator ; 19 import java.util.Map ; 20 import java.util.Map.Entry; 21 22 import org.eclipse.text.edits.TextEdit; 23 24 import org.eclipse.core.runtime.Assert; 25 import org.eclipse.core.runtime.CoreException; 26 import org.eclipse.core.runtime.NullProgressMonitor; 27 import org.eclipse.core.runtime.SubProgressMonitor; 28 29 import org.eclipse.core.resources.IResource; 30 31 import org.eclipse.jface.text.IRegion; 32 import org.eclipse.jface.text.Region; 33 34 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 35 import org.eclipse.ltk.core.refactoring.RefactoringStatusContext; 36 import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry; 37 import org.eclipse.ltk.core.refactoring.TextChange; 38 import org.eclipse.ltk.core.refactoring.TextEditChangeGroup; 39 40 import org.eclipse.jdt.core.ICompilationUnit; 41 import org.eclipse.jdt.core.IJavaElement; 42 import org.eclipse.jdt.core.ISourceRange; 43 import org.eclipse.jdt.core.ISourceReference; 44 import org.eclipse.jdt.core.JavaModelException; 45 import org.eclipse.jdt.core.WorkingCopyOwner; 46 import org.eclipse.jdt.core.compiler.IProblem; 47 import org.eclipse.jdt.core.dom.AST; 48 import org.eclipse.jdt.core.dom.ASTNode; 49 import org.eclipse.jdt.core.dom.ASTVisitor; 50 import org.eclipse.jdt.core.dom.CompilationUnit; 51 import org.eclipse.jdt.core.dom.IBinding; 52 import org.eclipse.jdt.core.dom.IVariableBinding; 53 import org.eclipse.jdt.core.dom.Name; 54 import org.eclipse.jdt.core.dom.SimpleName; 55 import org.eclipse.jdt.core.dom.VariableDeclaration; 56 import org.eclipse.jdt.core.search.FieldDeclarationMatch; 57 import org.eclipse.jdt.core.search.MethodDeclarationMatch; 58 import org.eclipse.jdt.core.search.SearchMatch; 59 60 import org.eclipse.jdt.internal.corext.SourceRange; 61 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 62 import org.eclipse.jdt.internal.corext.dom.NodeFinder; 63 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 64 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; 65 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; 66 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStringStatusContext; 67 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 68 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager; 69 import org.eclipse.jdt.internal.corext.util.Messages; 70 import org.eclipse.jdt.internal.corext.util.SearchUtils; 71 72 class RenameAnalyzeUtil { 73 74 private static class ProblemNodeFinder { 75 76 private ProblemNodeFinder() { 77 } 79 80 public static SimpleName[] getProblemNodes(ASTNode methodNode, VariableDeclaration variableNode, TextEdit[] edits, TextChange change) { 81 String key= variableNode.resolveBinding().getKey(); 82 NameNodeVisitor visitor= new NameNodeVisitor(edits, change, key); 83 methodNode.accept(visitor); 84 return visitor.getProblemNodes(); 85 } 86 87 private static class NameNodeVisitor extends ASTVisitor { 88 89 private Collection fRanges; 90 private Collection fProblemNodes; 91 private String fKey; 92 93 public NameNodeVisitor(TextEdit[] edits, TextChange change, String key) { 94 Assert.isNotNull(edits); 95 Assert.isNotNull(key); 96 97 fRanges= new HashSet (Arrays.asList(RefactoringAnalyzeUtil.getNewRanges(edits, change))); 98 fProblemNodes= new ArrayList (0); 99 fKey= key; 100 } 101 102 public SimpleName[] getProblemNodes() { 103 return (SimpleName[]) fProblemNodes.toArray(new SimpleName[fProblemNodes.size()]); 104 } 105 106 108 public boolean visit(SimpleName node) { 109 VariableDeclaration decl= getVariableDeclaration(node); 110 if (decl == null) 111 return super.visit(node); 112 113 IVariableBinding binding= decl.resolveBinding(); 114 if (binding == null) 115 return super.visit(node); 116 117 boolean keysEqual= fKey.equals(binding.getKey()); 118 boolean rangeInSet= fRanges.contains(new Region(node.getStartPosition(), node.getLength())); 119 120 if (keysEqual && !rangeInSet) 121 fProblemNodes.add(node); 122 123 if (!keysEqual && rangeInSet) 124 fProblemNodes.add(node); 125 126 133 134 return super.visit(node); 135 } 136 } 137 } 138 139 static class LocalAnalyzePackage { 140 public final TextEdit fDeclarationEdit; 141 public final TextEdit[] fOccurenceEdits; 142 143 public LocalAnalyzePackage(final TextEdit declarationEdit, final TextEdit[] occurenceEdits) { 144 fDeclarationEdit = declarationEdit; 145 fOccurenceEdits = occurenceEdits; 146 } 147 } 148 149 private RenameAnalyzeUtil() { 150 } 152 153 static RefactoringStatus analyzeRenameChanges(TextChangeManager manager, SearchResultGroup[] oldOccurrences, SearchResultGroup[] newOccurrences) { 154 RefactoringStatus result= new RefactoringStatus(); 155 for (int i= 0; i < oldOccurrences.length; i++) { 156 SearchResultGroup oldGroup= oldOccurrences[i]; 157 SearchMatch[] oldSearchResults= oldGroup.getSearchResults(); 158 ICompilationUnit cunit= oldGroup.getCompilationUnit(); 159 if (cunit == null) 160 continue; 161 for (int j= 0; j < oldSearchResults.length; j++) { 162 SearchMatch oldSearchResult= oldSearchResults[j]; 163 if (! RenameAnalyzeUtil.existsInNewOccurrences(oldSearchResult, newOccurrences, manager)){ 164 addShadowsError(cunit, oldSearchResult, result); 165 } 166 } 167 } 168 return result; 169 } 170 171 static ICompilationUnit findWorkingCopyForCu(ICompilationUnit[] newWorkingCopies, ICompilationUnit cu){ 172 ICompilationUnit original= cu == null ? null : cu.getPrimary(); 173 for (int i= 0; i < newWorkingCopies.length; i++) { 174 if (newWorkingCopies[i].getPrimary().equals(original)) 175 return newWorkingCopies[i]; 176 } 177 return null; 178 } 179 180 static ICompilationUnit[] createNewWorkingCopies(ICompilationUnit[] compilationUnitsToModify, TextChangeManager manager, WorkingCopyOwner owner, SubProgressMonitor pm) throws CoreException { 181 pm.beginTask("", compilationUnitsToModify.length); ICompilationUnit[] newWorkingCopies= new ICompilationUnit[compilationUnitsToModify.length]; 183 for (int i= 0; i < compilationUnitsToModify.length; i++) { 184 ICompilationUnit cu= compilationUnitsToModify[i]; 185 newWorkingCopies[i]= createNewWorkingCopy(cu, manager, owner, new SubProgressMonitor(pm, 1)); 186 } 187 pm.done(); 188 return newWorkingCopies; 189 } 190 191 static ICompilationUnit createNewWorkingCopy(ICompilationUnit cu, TextChangeManager manager, 192 WorkingCopyOwner owner, SubProgressMonitor pm) throws CoreException { 193 ICompilationUnit newWc= cu.getWorkingCopy(owner, null, null); 194 String previewContent= manager.get(cu).getPreviewContent(new NullProgressMonitor()); 195 newWc.getBuffer().setContents(previewContent); 196 newWc.reconcile(ICompilationUnit.NO_AST, false, owner, pm); 197 return newWc; 198 } 199 200 private static boolean existsInNewOccurrences(SearchMatch searchResult, SearchResultGroup[] newOccurrences, TextChangeManager manager) { 201 SearchResultGroup newGroup= findOccurrenceGroup(searchResult.getResource(), newOccurrences); 202 if (newGroup == null) 203 return false; 204 205 IRegion oldEditRange= getCorrespondingEditChangeRange(searchResult, manager); 206 if (oldEditRange == null) 207 return false; 208 209 SearchMatch[] newSearchResults= newGroup.getSearchResults(); 210 int oldRangeOffset = oldEditRange.getOffset(); 211 for (int i= 0; i < newSearchResults.length; i++) { 212 if (newSearchResults[i].getOffset() == oldRangeOffset) 213 return true; 214 } 215 return false; 216 } 217 218 private static IRegion getCorrespondingEditChangeRange(SearchMatch searchResult, TextChangeManager manager) { 219 TextChange change= getTextChange(searchResult, manager); 220 if (change == null) 221 return null; 222 223 IRegion oldMatchRange= createTextRange(searchResult); 224 TextEditChangeGroup[] editChanges= change.getTextEditChangeGroups(); 225 for (int i= 0; i < editChanges.length; i++) { 226 if (oldMatchRange.equals(editChanges[i].getRegion())) 227 return TextEdit.getCoverage(change.getPreviewEdits(editChanges[i].getTextEdits())); 228 } 229 return null; 230 } 231 232 private static TextChange getTextChange(SearchMatch searchResult, TextChangeManager manager) { 233 ICompilationUnit cu= SearchUtils.getCompilationUnit(searchResult); 234 if (cu == null) 235 return null; 236 return manager.get(cu); 237 } 238 239 private static IRegion createTextRange(SearchMatch searchResult) { 240 return new Region(searchResult.getOffset(), searchResult.getLength()); 241 } 242 243 private static SearchResultGroup findOccurrenceGroup(IResource resource, SearchResultGroup[] newOccurrences) { 244 for (int i= 0; i < newOccurrences.length; i++) { 245 if (newOccurrences[i].getResource().equals(resource)) 246 return newOccurrences[i]; 247 } 248 return null; 249 } 250 251 253 static RefactoringStatus analyzeRenameChanges2(TextChangeManager manager, 256 SearchResultGroup[] oldReferences, SearchResultGroup[] newReferences, String newElementName) { 257 RefactoringStatus result= new RefactoringStatus(); 258 259 HashMap cuToNewResults= new HashMap (newReferences.length); 260 for (int i1= 0; i1 < newReferences.length; i1++) { 261 ICompilationUnit cu= newReferences[i1].getCompilationUnit(); 262 if (cu != null) 263 cuToNewResults.put(cu.getPrimary(), newReferences[i1].getSearchResults()); 264 } 265 266 for (int i= 0; i < oldReferences.length; i++) { 267 SearchResultGroup oldGroup= oldReferences[i]; 268 SearchMatch[] oldMatches= oldGroup.getSearchResults(); 269 ICompilationUnit cu= oldGroup.getCompilationUnit(); 270 if (cu == null) 271 continue; 272 273 SearchMatch[] newSearchMatches= (SearchMatch[]) cuToNewResults.remove(cu); 274 if (newSearchMatches == null) { 275 for (int j = 0; j < oldMatches.length; j++) { 276 SearchMatch oldMatch = oldMatches[j]; 277 addShadowsError(cu, oldMatch, result); 278 } 279 } else { 280 analyzeChanges(cu, manager.get(cu), oldMatches, newSearchMatches, newElementName, result); 281 } 282 } 283 284 for (Iterator iter= cuToNewResults.entrySet().iterator(); iter.hasNext();) { 285 Map.Entry entry= (Entry) iter.next(); 286 ICompilationUnit cu= (ICompilationUnit) entry.getKey(); 287 SearchMatch[] newSearchMatches= (SearchMatch[]) entry.getValue(); 288 for (int i= 0; i < newSearchMatches.length; i++) { 289 SearchMatch newMatch= newSearchMatches[i]; 290 addReferenceShadowedError(cu, newMatch, newElementName, result); 291 } 292 } 293 return result; 294 } 295 296 private static void analyzeChanges(ICompilationUnit cu, TextChange change, 297 SearchMatch[] oldMatches, SearchMatch[] newMatches, String newElementName, RefactoringStatus result) { 298 Map updatedOldOffsets= getUpdatedChangeOffsets(change, oldMatches); 299 for (int i= 0; i < newMatches.length; i++) { 300 SearchMatch newMatch= newMatches[i]; 301 Integer offsetInNew= new Integer (newMatch.getOffset()); 302 SearchMatch oldMatch= (SearchMatch) updatedOldOffsets.remove(offsetInNew); 303 if (oldMatch == null) { 304 addReferenceShadowedError(cu, newMatch, newElementName, result); 305 } 306 } 307 for (Iterator iter= updatedOldOffsets.values().iterator(); iter.hasNext();) { 308 SearchMatch oldMatch= (SearchMatch) iter.next(); 310 addShadowsError(cu, oldMatch, result); 311 } 312 } 313 314 315 private static Map getUpdatedChangeOffsets(TextChange change, SearchMatch[] oldMatches) { 316 Map updatedOffsets= new HashMap (); 317 Map oldToUpdatedOffsets= getEditChangeOffsetUpdates(change); 318 for (int i= 0; i < oldMatches.length; i++) { 319 SearchMatch oldMatch= oldMatches[i]; 320 Integer updatedOffset= (Integer ) oldToUpdatedOffsets.get(new Integer (oldMatch.getOffset())); 321 if (updatedOffset == null) 322 updatedOffset= new Integer (-1); updatedOffsets.put(updatedOffset, oldMatch); 324 } 325 return updatedOffsets; 326 } 327 328 329 private static Map getEditChangeOffsetUpdates(TextChange change) { 330 TextEditChangeGroup[] editChanges= change.getTextEditChangeGroups(); 331 Map offsetUpdates= new HashMap (editChanges.length); 332 for (int i= 0; i < editChanges.length; i++) { 333 TextEditChangeGroup editChange= editChanges[i]; 334 IRegion oldRegion= editChange.getRegion(); 335 if (oldRegion == null) 336 continue; 337 IRegion updatedRegion= TextEdit.getCoverage(change.getPreviewEdits(editChange.getTextEdits())); 338 if (updatedRegion == null) 339 continue; 340 341 offsetUpdates.put(new Integer (oldRegion.getOffset()), new Integer (updatedRegion.getOffset())); 342 } 343 return offsetUpdates; 344 } 345 346 private static void addReferenceShadowedError(ICompilationUnit cu, SearchMatch newMatch, String newElementName, RefactoringStatus result) { 347 351 if (newMatch instanceof MethodDeclarationMatch || newMatch instanceof FieldDeclarationMatch) 353 return; 354 ISourceRange range= getOldSourceRange(newMatch); 355 RefactoringStatusContext context= JavaStatusContext.create(cu, range); 356 String message= Messages.format( 357 RefactoringCoreMessages.RenameAnalyzeUtil_reference_shadowed, 358 new String [] {cu.getElementName(), newElementName}); 359 result.addError(message, context); 360 } 361 362 private static ISourceRange getOldSourceRange(SearchMatch newMatch) { 363 IJavaElement newMatchElement= (IJavaElement) newMatch.getElement(); 365 IJavaElement primaryElement= newMatchElement.getPrimaryElement(); 366 ISourceRange range= null; 367 if (primaryElement.exists() && primaryElement instanceof ISourceReference) { 368 try { 369 range= ((ISourceReference) primaryElement).getSourceRange(); 370 } catch (JavaModelException e) { 371 } 373 } 374 return range; 375 } 376 377 private static void addShadowsError(ICompilationUnit cu, SearchMatch oldMatch, RefactoringStatus result) { 378 380 if (oldMatch instanceof MethodDeclarationMatch || oldMatch instanceof FieldDeclarationMatch) 382 return; 383 ISourceRange range= new SourceRange(oldMatch.getOffset(), oldMatch.getLength()); 384 RefactoringStatusContext context= JavaStatusContext.create(cu, range); 385 String message= Messages.format(RefactoringCoreMessages.RenameAnalyzeUtil_shadows, cu.getElementName()); 386 result.addError(message, context); 387 } 388 389 401 public static RefactoringStatus analyzeLocalRenames(LocalAnalyzePackage[] analyzePackages, TextChange cuChange, CompilationUnit oldCUNode, boolean statementsRecovery) throws CoreException { 402 403 RefactoringStatus result= new RefactoringStatus(); 404 ICompilationUnit compilationUnit= (ICompilationUnit) oldCUNode.getJavaElement(); 405 406 String newCuSource= cuChange.getPreviewContent(new NullProgressMonitor()); 407 CompilationUnit newCUNode= new RefactoringASTParser(AST.JLS3).parse(newCuSource, compilationUnit, true, statementsRecovery, null); 408 409 result.merge(analyzeCompileErrors(newCuSource, newCUNode, oldCUNode)); 410 if (result.hasError()) 411 return result; 412 413 for (int i= 0; i < analyzePackages.length; i++) { 414 ASTNode enclosing= getEnclosingBlockOrMethod(analyzePackages[i].fDeclarationEdit, cuChange, newCUNode); 415 416 IRegion newRegion= RefactoringAnalyzeUtil.getNewTextRange(analyzePackages[i].fDeclarationEdit, cuChange); 418 ASTNode newDeclaration= NodeFinder.perform(newCUNode, newRegion.getOffset(), newRegion.getLength()); 419 Assert.isTrue(newDeclaration instanceof Name); 420 421 VariableDeclaration declaration= getVariableDeclaration((Name) newDeclaration); 422 Assert.isNotNull(declaration); 423 424 SimpleName[] problemNodes= ProblemNodeFinder.getProblemNodes(enclosing, declaration, analyzePackages[i].fOccurenceEdits, cuChange); 425 result.merge(RefactoringAnalyzeUtil.reportProblemNodes(newCuSource, problemNodes)); 426 } 427 return result; 428 } 429 430 private static VariableDeclaration getVariableDeclaration(Name node) { 431 IBinding binding= node.resolveBinding(); 432 if (binding == null && node.getParent() instanceof VariableDeclaration) 433 return (VariableDeclaration) node.getParent(); 434 435 if (binding != null && binding.getKind() == IBinding.VARIABLE) { 436 CompilationUnit cu= (CompilationUnit) ASTNodes.getParent(node, CompilationUnit.class); 437 return ASTNodes.findVariableDeclaration( ((IVariableBinding) binding), cu); 438 } 439 return null; 440 } 441 442 private static ASTNode getEnclosingBlockOrMethod(TextEdit declarationEdit, TextChange change, CompilationUnit newCUNode) { 443 ASTNode enclosing= RefactoringAnalyzeUtil.getBlock(declarationEdit, change, newCUNode); 444 if (enclosing == null) 445 enclosing= RefactoringAnalyzeUtil.getMethodDeclaration(declarationEdit, change, newCUNode); 446 return enclosing; 447 } 448 449 private static RefactoringStatus analyzeCompileErrors(String newCuSource, CompilationUnit newCUNode, CompilationUnit oldCUNode) { 450 RefactoringStatus result= new RefactoringStatus(); 451 IProblem[] newProblems= RefactoringAnalyzeUtil.getIntroducedCompileProblems(newCUNode, oldCUNode); 452 for (int i= 0; i < newProblems.length; i++) { 453 IProblem problem= newProblems[i]; 454 if (problem.isError()) 455 result.addEntry(new RefactoringStatusEntry((problem.isError() ? RefactoringStatus.ERROR : RefactoringStatus.WARNING), problem.getMessage(), new JavaStringStatusContext(newCuSource, new SourceRange(problem)))); 456 } 457 return result; 458 } 459 } 460 | Popular Tags |