1 11 package org.eclipse.jdt.internal.corext.refactoring.code; 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.Iterator ; 18 import java.util.List ; 19 import java.util.Map ; 20 import java.util.StringTokenizer ; 21 22 import org.eclipse.text.edits.TextEditGroup; 23 24 import org.eclipse.core.runtime.Assert; 25 import org.eclipse.core.runtime.CoreException; 26 import org.eclipse.core.runtime.IProgressMonitor; 27 import org.eclipse.core.runtime.NullProgressMonitor; 28 import org.eclipse.core.runtime.SubProgressMonitor; 29 30 import org.eclipse.ltk.core.refactoring.Change; 31 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; 32 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 33 import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry; 34 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments; 35 36 import org.eclipse.jdt.core.ICompilationUnit; 37 import org.eclipse.jdt.core.IJavaElement; 38 import org.eclipse.jdt.core.IJavaProject; 39 import org.eclipse.jdt.core.JavaModelException; 40 import org.eclipse.jdt.core.compiler.IProblem; 41 import org.eclipse.jdt.core.dom.AST; 42 import org.eclipse.jdt.core.dom.ASTNode; 43 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 44 import org.eclipse.jdt.core.dom.BodyDeclaration; 45 import org.eclipse.jdt.core.dom.CompilationUnit; 46 import org.eclipse.jdt.core.dom.Expression; 47 import org.eclipse.jdt.core.dom.ExpressionStatement; 48 import org.eclipse.jdt.core.dom.FieldAccess; 49 import org.eclipse.jdt.core.dom.FieldDeclaration; 50 import org.eclipse.jdt.core.dom.ITypeBinding; 51 import org.eclipse.jdt.core.dom.Initializer; 52 import org.eclipse.jdt.core.dom.Javadoc; 53 import org.eclipse.jdt.core.dom.MethodDeclaration; 54 import org.eclipse.jdt.core.dom.Modifier; 55 import org.eclipse.jdt.core.dom.Name; 56 import org.eclipse.jdt.core.dom.NullLiteral; 57 import org.eclipse.jdt.core.dom.QualifiedName; 58 import org.eclipse.jdt.core.dom.SimpleName; 59 import org.eclipse.jdt.core.dom.SwitchCase; 60 import org.eclipse.jdt.core.dom.Type; 61 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 62 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 63 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 64 import org.eclipse.jdt.core.refactoring.IJavaRefactorings; 65 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor; 66 67 import org.eclipse.jdt.internal.corext.Corext; 68 import org.eclipse.jdt.internal.corext.SourceRange; 69 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 70 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 71 import org.eclipse.jdt.internal.corext.dom.Bindings; 72 import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer; 73 import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory; 74 import org.eclipse.jdt.internal.corext.dom.fragments.IASTFragment; 75 import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment; 76 import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel; 77 import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup; 78 import org.eclipse.jdt.internal.corext.refactoring.Checks; 79 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor; 80 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment; 81 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments; 82 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 83 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStringStatusContext; 84 import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes; 85 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange; 86 import org.eclipse.jdt.internal.corext.refactoring.changes.RefactoringDescriptorChange; 87 import org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringAnalyzeUtil; 88 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; 89 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 90 import org.eclipse.jdt.internal.corext.util.JdtFlags; 91 import org.eclipse.jdt.internal.corext.util.Messages; 92 93 import org.eclipse.jdt.ui.CodeGeneration; 94 import org.eclipse.jdt.ui.JavaElementLabels; 95 96 import org.eclipse.jdt.internal.ui.JavaPlugin; 97 import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings; 98 import org.eclipse.jdt.internal.ui.text.correction.ASTResolving; 99 import org.eclipse.jdt.internal.ui.text.correction.ModifierCorrectionSubProcessor; 100 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; 101 102 public class ExtractConstantRefactoring extends ScriptableRefactoring { 103 104 private static final String ATTRIBUTE_REPLACE= "replace"; private static final String ATTRIBUTE_QUALIFY= "qualify"; private static final String ATTRIBUTE_VISIBILITY= "visibility"; 108 private static final String MODIFIER= "static final"; 110 private static final String KEY_NAME= "name"; private static final String KEY_TYPE= "type"; 113 private CompilationUnitRewrite fCuRewrite; 114 private int fSelectionStart; 115 private int fSelectionLength; 116 private ICompilationUnit fCu; 117 118 private IExpressionFragment fSelectedExpression; 119 private Type fConstantTypeCache; 120 private boolean fReplaceAllOccurrences= true; private boolean fQualifyReferencesWithDeclaringClassName= false; 123 private String fVisibility= JdtFlags.VISIBILITY_STRING_PRIVATE; private boolean fTargetIsInterface= false; 125 private String fConstantName; 126 private String [] fExcludedVariableNames; 127 128 private boolean fSelectionAllStaticFinal; 129 private boolean fAllStaticFinalCheckPerformed= false; 130 131 private List fBodyDeclarations; 132 133 private BodyDeclaration fToInsertAfter; 135 private boolean fInsertFirst; 136 137 private CompilationUnitChange fChange; 138 private String [] fGuessedConstNames; 139 140 private LinkedProposalModel fLinkedProposalModel; 141 142 148 public ExtractConstantRefactoring(ICompilationUnit unit, int selectionStart, int selectionLength) { 149 Assert.isTrue(selectionStart >= 0); 150 Assert.isTrue(selectionLength >= 0); 151 fSelectionStart= selectionStart; 152 fSelectionLength= selectionLength; 153 fCu= unit; 154 fCuRewrite= null; 155 fLinkedProposalModel= null; 156 fConstantName= ""; } 158 159 public ExtractConstantRefactoring(CompilationUnit astRoot, int selectionStart, int selectionLength) { 160 Assert.isTrue(selectionStart >= 0); 161 Assert.isTrue(selectionLength >= 0); 162 Assert.isTrue(astRoot.getTypeRoot() instanceof ICompilationUnit); 163 164 fSelectionStart= selectionStart; 165 fSelectionLength= selectionLength; 166 fCu= (ICompilationUnit) astRoot.getTypeRoot(); 167 fCuRewrite= new CompilationUnitRewrite(fCu, astRoot); 168 fLinkedProposalModel= null; 169 fConstantName= ""; } 171 172 public void setLinkedProposalModel(LinkedProposalModel linkedProposalModel) { 173 fLinkedProposalModel= linkedProposalModel; 174 } 175 176 public String getName() { 177 return RefactoringCoreMessages.ExtractConstantRefactoring_name; 178 } 179 180 public boolean replaceAllOccurrences() { 181 return fReplaceAllOccurrences; 182 } 183 184 public void setReplaceAllOccurrences(boolean replaceAllOccurrences) { 185 fReplaceAllOccurrences= replaceAllOccurrences; 186 } 187 188 public void setVisibility(String am) { 189 Assert.isTrue( 190 am == JdtFlags.VISIBILITY_STRING_PRIVATE || am == JdtFlags.VISIBILITY_STRING_PROTECTED || am == JdtFlags.VISIBILITY_STRING_PACKAGE || am == JdtFlags.VISIBILITY_STRING_PUBLIC 191 ); 192 fVisibility= am; 193 } 194 195 public String getVisibility() { 196 return fVisibility; 197 } 198 199 public boolean getTargetIsInterface() { 200 return fTargetIsInterface; 201 } 202 203 public boolean qualifyReferencesWithDeclaringClassName() { 204 return fQualifyReferencesWithDeclaringClassName; 205 } 206 207 public void setQualifyReferencesWithDeclaringClassName(boolean qualify) { 208 fQualifyReferencesWithDeclaringClassName= qualify; 209 } 210 211 public String guessConstantName() throws JavaModelException { 212 String [] proposals= guessConstantNames(); 213 if (proposals.length > 0) 214 return proposals[0]; 215 else 216 return fConstantName; 217 } 218 219 223 public String [] guessConstantNames() { 224 if (fGuessedConstNames == null) { 225 try { 226 Expression expression= getSelectedExpression().getAssociatedExpression(); 227 if (expression != null) { 228 ITypeBinding binding= expression.resolveTypeBinding(); 229 fGuessedConstNames= StubUtility.getVariableNameSuggestions(StubUtility.CONSTANT_FIELD, fCu.getJavaProject(), binding, expression, Arrays.asList(getExcludedVariableNames())); 230 } 231 } catch (JavaModelException e) { 232 } 233 if (fGuessedConstNames == null) 234 fGuessedConstNames= new String [0]; 235 } 236 return fGuessedConstNames; 237 } 238 239 240 private String [] getExcludedVariableNames() { 241 if (fExcludedVariableNames == null) { 242 try { 243 IExpressionFragment expr= getSelectedExpression(); 244 Collection takenNames= new ScopeAnalyzer(fCuRewrite.getRoot()).getUsedVariableNames(expr.getStartPosition(), expr.getLength()); 245 fExcludedVariableNames= (String []) takenNames.toArray(new String [takenNames.size()]); 246 } catch (JavaModelException e) { 247 fExcludedVariableNames= new String [0]; 248 } 249 } 250 return fExcludedVariableNames; 251 } 252 253 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { 254 try { 255 pm.beginTask("", 7); 257 RefactoringStatus result= Checks.validateEdit(fCu, getValidationContext()); 258 if (result.hasFatalError()) 259 return result; 260 pm.worked(1); 261 262 if (fCuRewrite == null) { 263 CompilationUnit cuNode= RefactoringASTParser.parseWithASTProvider(fCu, true, new SubProgressMonitor(pm, 3)); 264 fCuRewrite= new CompilationUnitRewrite(fCu, cuNode); 265 } else { 266 pm.worked(3); 267 } 268 result.merge(checkSelection(new SubProgressMonitor(pm, 3))); 269 270 if (result.hasFatalError()) 271 return result; 272 273 if (isLiteralNodeSelected()) 274 fReplaceAllOccurrences= false; 275 276 ITypeBinding targetType= getContainingTypeBinding(); 277 if (targetType.isAnnotation() || targetType.isInterface()) { 278 fTargetIsInterface= true; 279 fVisibility= JdtFlags.VISIBILITY_STRING_PUBLIC; 280 } 281 282 return result; 283 } finally { 284 pm.done(); 285 } 286 } 287 288 public boolean selectionAllStaticFinal() { 289 Assert.isTrue(fAllStaticFinalCheckPerformed); 290 return fSelectionAllStaticFinal; 291 } 292 293 private void checkAllStaticFinal() throws JavaModelException { 294 fSelectionAllStaticFinal= ConstantChecks.isStaticFinalConstant(getSelectedExpression()); 295 fAllStaticFinalCheckPerformed= true; 296 } 297 298 private RefactoringStatus checkSelection(IProgressMonitor pm) throws JavaModelException { 299 try { 300 pm.beginTask("", 2); 302 IExpressionFragment selectedExpression= getSelectedExpression(); 303 304 if (selectedExpression == null) { 305 String message= RefactoringCoreMessages.ExtractConstantRefactoring_select_expression; 306 return CodeRefactoringUtil.checkMethodSyntaxErrors(fSelectionStart, fSelectionLength, fCuRewrite.getRoot(), message); 307 } 308 pm.worked(1); 309 310 RefactoringStatus result= new RefactoringStatus(); 311 result.merge(checkExpression()); 312 if (result.hasFatalError()) 313 return result; 314 pm.worked(1); 315 316 return result; 317 } finally { 318 pm.done(); 319 } 320 } 321 322 private RefactoringStatus checkExpressionBinding() throws JavaModelException { 323 return checkExpressionFragmentIsRValue(); 324 } 325 326 private RefactoringStatus checkExpressionFragmentIsRValue() throws JavaModelException { 327 329 switch(Checks.checkExpressionIsRValue(getSelectedExpression().getAssociatedExpression())) { 330 case Checks.NOT_RVALUE_MISC: 331 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.ExtractConstantRefactoring_select_expression, null, Corext.getPluginId(), RefactoringStatusCodes.EXPRESSION_NOT_RVALUE, null); 332 case Checks.NOT_RVALUE_VOID: 333 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.ExtractConstantRefactoring_no_void, null, Corext.getPluginId(), RefactoringStatusCodes.EXPRESSION_NOT_RVALUE_VOID, null); 334 case Checks.IS_RVALUE: 335 return new RefactoringStatus(); 336 default: 337 Assert.isTrue(false); return null; 338 } 339 } 340 341 private boolean isLiteralNodeSelected() throws JavaModelException { 343 IExpressionFragment fragment= getSelectedExpression(); 344 if (fragment == null) 345 return false; 346 Expression expression= fragment.getAssociatedExpression(); 347 if (expression == null) 348 return false; 349 switch (expression.getNodeType()) { 350 case ASTNode.BOOLEAN_LITERAL : 351 case ASTNode.CHARACTER_LITERAL : 352 case ASTNode.NULL_LITERAL : 353 case ASTNode.NUMBER_LITERAL : 354 return true; 355 356 default : 357 return false; 358 } 359 } 360 361 private RefactoringStatus checkExpression() throws JavaModelException { 362 RefactoringStatus result= new RefactoringStatus(); 363 result.merge(checkExpressionBinding()); 364 if(result.hasFatalError()) 365 return result; 366 checkAllStaticFinal(); 367 368 IExpressionFragment selectedExpression= getSelectedExpression(); 369 Expression associatedExpression= selectedExpression.getAssociatedExpression(); 370 if (associatedExpression instanceof NullLiteral) 371 result.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractConstantRefactoring_null_literals)); 372 else if (!ConstantChecks.isLoadTimeConstant(selectedExpression)) 373 result.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractConstantRefactoring_not_load_time_constant)); 374 else if (associatedExpression instanceof SimpleName) { 375 if (associatedExpression.getParent() instanceof QualifiedName && associatedExpression.getLocationInParent() == QualifiedName.NAME_PROPERTY 376 || associatedExpression.getParent() instanceof FieldAccess && associatedExpression.getLocationInParent() == FieldAccess.NAME_PROPERTY) 377 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractConstantRefactoring_select_expression); 378 } 379 380 return result; 381 } 382 383 public void setConstantName(String newName) { 384 Assert.isNotNull(newName); 385 fConstantName= newName; 386 } 387 388 public String getConstantName() { 389 return fConstantName; 390 } 391 392 400 public RefactoringStatus checkConstantNameOnChange() throws JavaModelException { 401 if (Arrays.asList(getExcludedVariableNames()).contains(fConstantName)) 402 return RefactoringStatus.createErrorStatus(Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_another_variable, getConstantName())); 403 return Checks.checkConstantName(getConstantName()); 404 } 405 406 public String getConstantSignaturePreview() throws JavaModelException { 408 String space= " "; return getVisibility() + space + MODIFIER + space + getConstantTypeName() + space + fConstantName; 410 } 411 412 public CompilationUnitChange createTextChange(IProgressMonitor pm) throws CoreException { 413 createConstantDeclaration(); 414 replaceExpressionsWithConstant(); 415 return fCuRewrite.createChange(RefactoringCoreMessages.ExtractConstantRefactoring_change_name, true, pm); 416 } 417 418 419 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException { 420 pm.beginTask(RefactoringCoreMessages.ExtractConstantRefactoring_checking_preconditions, 4); 421 422 425 426 429 try { 430 RefactoringStatus result= new RefactoringStatus(); 431 fChange= createTextChange(new SubProgressMonitor(pm, 2)); 432 433 String newCuSource= fChange.getPreviewContent(new NullProgressMonitor()); 434 CompilationUnit newCUNode= new RefactoringASTParser(AST.JLS3).parse(newCuSource, fCu, true, true, null); 435 436 IProblem[] newProblems= RefactoringAnalyzeUtil.getIntroducedCompileProblems(newCUNode, fCuRewrite.getRoot()); 437 for (int i= 0; i < newProblems.length; i++) { 438 IProblem problem= newProblems[i]; 439 if (problem.isError()) 440 result.addEntry(new RefactoringStatusEntry((problem.isError() ? RefactoringStatus.ERROR : RefactoringStatus.WARNING), problem.getMessage(), new JavaStringStatusContext(newCuSource, new SourceRange(problem)))); 441 } 442 443 fConstantTypeCache= null; 444 fCuRewrite.clearASTAndImportRewrites(); 445 446 return result; 447 } finally { 448 pm.done(); 449 } 450 } 451 452 private void createConstantDeclaration() throws CoreException { 453 Type type= getConstantType(); 454 455 IExpressionFragment fragment= getSelectedExpression(); 456 String initializerSource= fCu.getBuffer().getText(fragment.getStartPosition(), fragment.getLength()); 457 458 AST ast= fCuRewrite.getAST(); 459 VariableDeclarationFragment variableDeclarationFragment= ast.newVariableDeclarationFragment(); 460 variableDeclarationFragment.setName(ast.newSimpleName(fConstantName)); 461 variableDeclarationFragment.setInitializer((Expression) fCuRewrite.getASTRewrite().createStringPlaceholder(initializerSource, ASTNode.SIMPLE_NAME)); 462 463 FieldDeclaration fieldDeclaration= ast.newFieldDeclaration(variableDeclarationFragment); 464 fieldDeclaration.setType(type); 465 Modifier.ModifierKeyword accessModifier= Modifier.ModifierKeyword.toKeyword(fVisibility); 466 if (accessModifier != null) 467 fieldDeclaration.modifiers().add(ast.newModifier(accessModifier)); 468 fieldDeclaration.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD)); 469 fieldDeclaration.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.FINAL_KEYWORD)); 470 471 boolean createComments= JavaPreferencesSettings.getCodeGenerationSettings(fCu.getJavaProject()).createComments; 472 if (createComments) { 473 String comment= CodeGeneration.getFieldComment(fCu, getConstantTypeName(), fConstantName, StubUtility.getLineDelimiterUsed(fCu)); 474 if (comment != null && comment.length() > 0) { 475 Javadoc doc= (Javadoc) fCuRewrite.getASTRewrite().createStringPlaceholder(comment, ASTNode.JAVADOC); 476 fieldDeclaration.setJavadoc(doc); 477 } 478 } 479 480 AbstractTypeDeclaration parent= getContainingTypeDeclarationNode(); 481 ListRewrite listRewrite= fCuRewrite.getASTRewrite().getListRewrite(parent, parent.getBodyDeclarationsProperty()); 482 TextEditGroup msg= fCuRewrite.createGroupDescription(RefactoringCoreMessages.ExtractConstantRefactoring_declare_constant); 483 if (insertFirst()) { 484 listRewrite.insertFirst(fieldDeclaration, msg); 485 } else { 486 listRewrite.insertAfter(fieldDeclaration, getNodeToInsertConstantDeclarationAfter(), msg); 487 } 488 489 if (fLinkedProposalModel != null) { 490 ASTRewrite rewrite= fCuRewrite.getASTRewrite(); 491 LinkedProposalPositionGroup nameGroup= fLinkedProposalModel.getPositionGroup(KEY_NAME, true); 492 nameGroup.addPosition(rewrite.track(variableDeclarationFragment.getName()), true); 493 494 String [] nameSuggestions= guessConstantNames(); 495 if (nameSuggestions.length > 0 && !nameSuggestions[0].equals(fConstantName)) { 496 nameGroup.addProposal(fConstantName, null, nameSuggestions.length + 1); 497 } 498 for (int i= 0; i < nameSuggestions.length; i++) { 499 nameGroup.addProposal(nameSuggestions[i], null, nameSuggestions.length - i); 500 } 501 502 LinkedProposalPositionGroup typeGroup= fLinkedProposalModel.getPositionGroup(KEY_TYPE, true); 503 typeGroup.addPosition(rewrite.track(type), true); 504 505 ITypeBinding typeBinding= fragment.getAssociatedExpression().resolveTypeBinding(); 506 if (typeBinding != null) { 507 ITypeBinding[] relaxingTypes= ASTResolving.getNarrowingTypes(ast, typeBinding); 508 for (int i= 0; i < relaxingTypes.length; i++) { 509 typeGroup.addProposal(relaxingTypes[i], fCuRewrite.getCu(), relaxingTypes.length - i); 510 } 511 } 512 boolean isInterface= parent.resolveBinding() != null && parent.resolveBinding().isInterface(); 513 ModifierCorrectionSubProcessor.installLinkedVisibilityProposals(fLinkedProposalModel, rewrite, fieldDeclaration.modifiers(), isInterface); 514 } 515 } 516 517 private Type getConstantType() throws JavaModelException { 518 if (fConstantTypeCache == null) { 519 IExpressionFragment fragment= getSelectedExpression(); 520 ITypeBinding typeBinding= fragment.getAssociatedExpression().resolveTypeBinding(); 521 AST ast= fCuRewrite.getAST(); 522 typeBinding= Bindings.normalizeForDeclarationUse(typeBinding, ast); 523 fConstantTypeCache= fCuRewrite.getImportRewrite().addImport(typeBinding, ast); 524 } 525 return fConstantTypeCache; 526 } 527 528 public Change createChange(IProgressMonitor monitor) throws CoreException { 529 final Map arguments= new HashMap (); 530 String project= null; 531 IJavaProject javaProject= fCu.getJavaProject(); 532 if (javaProject != null) 533 project= javaProject.getElementName(); 534 int flags= JavaRefactoringDescriptor.JAR_REFACTORING | JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT; 535 if (JdtFlags.getVisibilityCode(fVisibility) != Modifier.PRIVATE) 536 flags|= RefactoringDescriptor.STRUCTURAL_CHANGE; 537 String pattern= ""; try { 539 pattern= BindingLabelProvider.getBindingLabel(getContainingTypeBinding(), JavaElementLabels.ALL_FULLY_QUALIFIED) + "."; } catch (JavaModelException exception) { 541 JavaPlugin.log(exception); 542 } 543 final String expression= ASTNodes.asString(fSelectedExpression.getAssociatedExpression()); 544 final String description= Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_descriptor_description_short, fConstantName); 545 final String header= Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_descriptor_description, new String [] { pattern + fConstantName, expression}); 546 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header); 547 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_constant_name_pattern, fConstantName)); 548 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_constant_expression_pattern, expression)); 549 String visibility= fVisibility; 550 if ("".equals(visibility)) visibility= RefactoringCoreMessages.ExtractConstantRefactoring_default_visibility; 552 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_visibility_pattern, visibility)); 553 if (fReplaceAllOccurrences) 554 comment.addSetting(RefactoringCoreMessages.ExtractConstantRefactoring_replace_occurrences); 555 if (fQualifyReferencesWithDeclaringClassName) 556 comment.addSetting(RefactoringCoreMessages.ExtractConstantRefactoring_qualify_references); 557 final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.EXTRACT_CONSTANT, project, description, comment.asString(), arguments, flags); 558 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fCu)); 559 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_NAME, fConstantName); 560 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION, new Integer (fSelectionStart).toString() + " " + new Integer (fSelectionLength).toString()); arguments.put(ATTRIBUTE_REPLACE, Boolean.valueOf(fReplaceAllOccurrences).toString()); 562 arguments.put(ATTRIBUTE_QUALIFY, Boolean.valueOf(fQualifyReferencesWithDeclaringClassName).toString()); 563 arguments.put(ATTRIBUTE_VISIBILITY, new Integer (JdtFlags.getVisibilityCode(fVisibility)).toString()); 564 return new RefactoringDescriptorChange(descriptor, RefactoringCoreMessages.ExtractConstantRefactoring_name, new Change[] { fChange}); 565 } 566 567 private void replaceExpressionsWithConstant() throws JavaModelException { 568 ASTRewrite astRewrite= fCuRewrite.getASTRewrite(); 569 AST ast= astRewrite.getAST(); 570 571 IASTFragment[] fragmentsToReplace= getFragmentsToReplace(); 572 for (int i= 0; i < fragmentsToReplace.length; i++) { 573 IASTFragment fragment= fragmentsToReplace[i]; 574 575 SimpleName ref= ast.newSimpleName(fConstantName); 576 Name replacement= ref; 577 if (qualifyReferencesWithDeclaringClassName()) { 578 replacement= ast.newQualifiedName(ast.newSimpleName(getContainingTypeBinding().getName()), ref); 579 } 580 TextEditGroup description= fCuRewrite.createGroupDescription(RefactoringCoreMessages.ExtractConstantRefactoring_replace); 581 582 fragment.replace(astRewrite, replacement, description); 583 if (fLinkedProposalModel != null) 584 fLinkedProposalModel.getPositionGroup(KEY_NAME, true).addPosition(astRewrite.track(ref), false); 585 } 586 } 587 588 private void computeConstantDeclarationLocation() throws JavaModelException { 589 if (isDeclarationLocationComputed()) 590 return; 591 592 BodyDeclaration lastStaticDependency= null; 593 Iterator decls= getBodyDeclarations(); 594 595 Assert.isTrue(decls.hasNext()); 599 600 while (decls.hasNext()) { 601 BodyDeclaration decl= (BodyDeclaration) decls.next(); 602 603 int modifiers; 604 if (decl instanceof FieldDeclaration) 605 modifiers= ((FieldDeclaration) decl).getModifiers(); 606 else if (decl instanceof Initializer) 607 modifiers= ((Initializer) decl).getModifiers(); 608 else { 609 continue; 612 } 613 614 if (Modifier.isStatic(modifiers) && depends(getSelectedExpression(), decl)) 615 lastStaticDependency= decl; 616 } 617 618 if(lastStaticDependency == null) 619 fInsertFirst= true; 620 else 621 fToInsertAfter= lastStaticDependency; 622 } 623 624 625 private static boolean depends(IExpressionFragment selected, BodyDeclaration bd) { 626 638 639 if(bd instanceof FieldDeclaration) { 640 FieldDeclaration fieldDecl = (FieldDeclaration) bd; 641 for(Iterator fragments = fieldDecl.fragments().iterator(); fragments.hasNext();) { 642 VariableDeclarationFragment fragment = (VariableDeclarationFragment) fragments.next(); 643 SimpleName staticFieldName = fragment.getName(); 644 if(selected.getSubFragmentsMatching(ASTFragmentFactory.createFragmentForFullSubtree(staticFieldName)).length != 0) 645 return true; 646 } 647 } 648 return false; 649 } 650 651 private boolean isDeclarationLocationComputed() { 652 return fInsertFirst == true || fToInsertAfter != null; 653 } 654 655 private boolean insertFirst() throws JavaModelException { 656 if(!isDeclarationLocationComputed()) 657 computeConstantDeclarationLocation(); 658 return fInsertFirst; 659 } 660 661 private BodyDeclaration getNodeToInsertConstantDeclarationAfter() throws JavaModelException { 662 if(!isDeclarationLocationComputed()) 663 computeConstantDeclarationLocation(); 664 return fToInsertAfter; 665 } 666 667 private Iterator getBodyDeclarations() throws JavaModelException { 668 if(fBodyDeclarations == null) 669 fBodyDeclarations= getContainingTypeDeclarationNode().bodyDeclarations(); 670 return fBodyDeclarations.iterator(); 671 } 672 673 private String getConstantTypeName() throws JavaModelException { 674 return ASTNodes.asString(getConstantType()); 675 } 676 677 private static boolean isStaticFieldOrStaticInitializer(BodyDeclaration node) { 678 if(node instanceof MethodDeclaration || node instanceof AbstractTypeDeclaration) 679 return false; 680 681 int modifiers; 682 if(node instanceof FieldDeclaration) { 683 modifiers = ((FieldDeclaration) node).getModifiers(); 684 } else if(node instanceof Initializer) { 685 modifiers = ((Initializer) node).getModifiers(); 686 } else { 687 Assert.isTrue(false); 688 return false; 689 } 690 691 if(!Modifier.isStatic(modifiers)) 692 return false; 693 694 return true; 695 } 696 697 701 private Iterator getReplacementScope() throws JavaModelException { 702 boolean declPredecessorReached= false; 703 704 Collection scope= new ArrayList (); 705 for(Iterator bodyDeclarations = getBodyDeclarations(); bodyDeclarations.hasNext();) { 706 BodyDeclaration bodyDeclaration= (BodyDeclaration) bodyDeclarations.next(); 707 708 if(bodyDeclaration == getNodeToInsertConstantDeclarationAfter()) 709 declPredecessorReached= true; 710 711 if(insertFirst() || declPredecessorReached || !isStaticFieldOrStaticInitializer(bodyDeclaration)) 712 scope.add(bodyDeclaration); 713 } 714 return scope.iterator(); 715 } 716 717 private IASTFragment[] getFragmentsToReplace() throws JavaModelException { 718 List toReplace = new ArrayList (); 719 if (fReplaceAllOccurrences) { 720 Iterator replacementScope = getReplacementScope(); 721 while(replacementScope.hasNext()) { 722 BodyDeclaration bodyDecl = (BodyDeclaration) replacementScope.next(); 723 IASTFragment[] allMatches= ASTFragmentFactory.createFragmentForFullSubtree(bodyDecl).getSubFragmentsMatching(getSelectedExpression()); 724 IASTFragment[] replaceableMatches = retainOnlyReplacableMatches(allMatches); 725 for(int i = 0; i < replaceableMatches.length; i++) 726 toReplace.add(replaceableMatches[i]); 727 } 728 } else if (canReplace(getSelectedExpression())) 729 toReplace.add(getSelectedExpression()); 730 return (IASTFragment[]) toReplace.toArray(new IASTFragment[toReplace.size()]); 731 } 732 733 private static IASTFragment[] retainOnlyReplacableMatches(IASTFragment[] allMatches) { 735 List result= new ArrayList (allMatches.length); 736 for (int i= 0; i < allMatches.length; i++) { 737 if (canReplace(allMatches[i])) 738 result.add(allMatches[i]); 739 } 740 return (IASTFragment[]) result.toArray(new IASTFragment[result.size()]); 741 } 742 743 private static boolean canReplace(IASTFragment fragment) { 745 ASTNode node= fragment.getAssociatedNode(); 746 ASTNode parent= node.getParent(); 747 if (parent instanceof VariableDeclarationFragment) { 748 VariableDeclarationFragment vdf= (VariableDeclarationFragment) parent; 749 if (node.equals(vdf.getName())) 750 return false; 751 } 752 if (parent instanceof ExpressionStatement) 753 return false; 754 if (parent instanceof SwitchCase) 755 return false; 756 return true; 757 } 758 759 private IExpressionFragment getSelectedExpression() throws JavaModelException { 760 if(fSelectedExpression != null) 761 return fSelectedExpression; 762 763 IASTFragment selectedFragment= ASTFragmentFactory.createFragmentForSourceRange(new SourceRange(fSelectionStart, fSelectionLength), fCuRewrite.getRoot(), fCu); 764 765 if (selectedFragment instanceof IExpressionFragment 766 && ! Checks.isInsideJavadoc(selectedFragment.getAssociatedNode())) { 767 fSelectedExpression= (IExpressionFragment) selectedFragment; 768 } 769 770 if (fSelectedExpression != null && Checks.isEnumCase(fSelectedExpression.getAssociatedExpression().getParent())) { 771 fSelectedExpression= null; 772 } 773 774 return fSelectedExpression; 775 } 776 777 private AbstractTypeDeclaration getContainingTypeDeclarationNode() throws JavaModelException { 778 AbstractTypeDeclaration result= (AbstractTypeDeclaration) ASTNodes.getParent(getSelectedExpression().getAssociatedNode(), AbstractTypeDeclaration.class); 779 Assert.isNotNull(result); 780 return result; 781 } 782 783 private ITypeBinding getContainingTypeBinding() throws JavaModelException { 784 ITypeBinding result= getContainingTypeDeclarationNode().resolveBinding(); 785 Assert.isNotNull(result); 786 return result; 787 } 788 789 public RefactoringStatus initialize(final RefactoringArguments arguments) { 790 if (arguments instanceof JavaRefactoringArguments) { 791 final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments; 792 final String selection= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION); 793 if (selection != null) { 794 int offset= -1; 795 int length= -1; 796 final StringTokenizer tokenizer= new StringTokenizer (selection); 797 if (tokenizer.hasMoreTokens()) 798 offset= Integer.valueOf(tokenizer.nextToken()).intValue(); 799 if (tokenizer.hasMoreTokens()) 800 length= Integer.valueOf(tokenizer.nextToken()).intValue(); 801 if (offset >= 0 && length >= 0) { 802 fSelectionStart= offset; 803 fSelectionLength= length; 804 } else 805 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object [] { selection, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION})); 806 } else 807 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION)); 808 final String handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT); 809 if (handle != null) { 810 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false); 811 if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT) 812 return createInputFatalStatus(element, IJavaRefactorings.EXTRACT_CONSTANT); 813 else 814 fCu= (ICompilationUnit) element; 815 } else 816 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT)); 817 final String visibility= extended.getAttribute(ATTRIBUTE_VISIBILITY); 818 if (visibility != null && !"".equals(visibility)) { int flag= 0; 820 try { 821 flag= Integer.parseInt(visibility); 822 } catch (NumberFormatException exception) { 823 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_VISIBILITY)); 824 } 825 fVisibility= JdtFlags.getVisibilityString(flag); 826 } 827 final String name= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_NAME); 828 if (name != null && !"".equals(name)) fConstantName= name; 830 else 831 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_NAME)); 832 final String replace= extended.getAttribute(ATTRIBUTE_REPLACE); 833 if (replace != null) { 834 fReplaceAllOccurrences= Boolean.valueOf(replace).booleanValue(); 835 } else 836 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REPLACE)); 837 final String declareFinal= extended.getAttribute(ATTRIBUTE_QUALIFY); 838 if (declareFinal != null) { 839 fQualifyReferencesWithDeclaringClassName= Boolean.valueOf(declareFinal).booleanValue(); 840 } else 841 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_QUALIFY)); 842 } else 843 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments); 844 return new RefactoringStatus(); 845 } 846 } 847 | Popular Tags |