1 11 package org.eclipse.jdt.internal.corext.refactoring.code; 12 13 import java.util.HashMap ; 14 import java.util.Map ; 15 import java.util.StringTokenizer ; 16 17 import org.eclipse.text.edits.MalformedTreeException; 18 import org.eclipse.text.edits.RangeMarker; 19 import org.eclipse.text.edits.TextEdit; 20 import org.eclipse.text.edits.TextEditGroup; 21 22 import org.eclipse.core.runtime.Assert; 23 import org.eclipse.core.runtime.CoreException; 24 import org.eclipse.core.runtime.IProgressMonitor; 25 import org.eclipse.core.runtime.SubProgressMonitor; 26 27 import org.eclipse.jface.text.BadLocationException; 28 import org.eclipse.jface.text.Document; 29 import org.eclipse.jface.text.IDocument; 30 import org.eclipse.jface.text.IRegion; 31 import org.eclipse.jface.text.TextUtilities; 32 33 import org.eclipse.ltk.core.refactoring.Change; 34 import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor; 35 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; 36 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 37 import org.eclipse.ltk.core.refactoring.RefactoringStatusContext; 38 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments; 39 40 import org.eclipse.jdt.core.ICompilationUnit; 41 import org.eclipse.jdt.core.IJavaElement; 42 import org.eclipse.jdt.core.IJavaProject; 43 import org.eclipse.jdt.core.ISourceRange; 44 import org.eclipse.jdt.core.JavaModelException; 45 import org.eclipse.jdt.core.dom.ASTNode; 46 import org.eclipse.jdt.core.dom.ArrayCreation; 47 import org.eclipse.jdt.core.dom.ArrayInitializer; 48 import org.eclipse.jdt.core.dom.ArrayType; 49 import org.eclipse.jdt.core.dom.Assignment; 50 import org.eclipse.jdt.core.dom.CatchClause; 51 import org.eclipse.jdt.core.dom.CompilationUnit; 52 import org.eclipse.jdt.core.dom.Expression; 53 import org.eclipse.jdt.core.dom.FieldDeclaration; 54 import org.eclipse.jdt.core.dom.ForStatement; 55 import org.eclipse.jdt.core.dom.IMethodBinding; 56 import org.eclipse.jdt.core.dom.ITypeBinding; 57 import org.eclipse.jdt.core.dom.IVariableBinding; 58 import org.eclipse.jdt.core.dom.MethodDeclaration; 59 import org.eclipse.jdt.core.dom.MethodInvocation; 60 import org.eclipse.jdt.core.dom.ParenthesizedExpression; 61 import org.eclipse.jdt.core.dom.SimpleName; 62 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 63 import org.eclipse.jdt.core.dom.SuperMethodInvocation; 64 import org.eclipse.jdt.core.dom.Type; 65 import org.eclipse.jdt.core.dom.VariableDeclaration; 66 import org.eclipse.jdt.core.dom.VariableDeclarationExpression; 67 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 68 import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 69 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 70 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 71 import org.eclipse.jdt.core.refactoring.IJavaRefactorings; 72 73 import org.eclipse.jdt.internal.corext.SourceRange; 74 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; 75 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 76 import org.eclipse.jdt.internal.corext.refactoring.Checks; 77 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor; 78 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment; 79 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments; 80 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 81 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; 82 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange; 83 import org.eclipse.jdt.internal.corext.refactoring.rename.TempDeclarationFinder; 84 import org.eclipse.jdt.internal.corext.refactoring.rename.TempOccurrenceAnalyzer; 85 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; 86 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 87 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil; 88 import org.eclipse.jdt.internal.corext.util.Messages; 89 import org.eclipse.jdt.internal.corext.util.Strings; 90 91 import org.eclipse.jdt.ui.JavaElementLabels; 92 93 import org.eclipse.jdt.internal.ui.JavaPlugin; 94 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; 95 96 public class InlineTempRefactoring extends ScriptableRefactoring { 97 98 private int fSelectionStart; 99 private int fSelectionLength; 100 private ICompilationUnit fCu; 101 102 private VariableDeclaration fVariableDeclaration; 104 private SimpleName[] fReferences; 105 private CompilationUnit fASTRoot; 106 107 114 public InlineTempRefactoring(ICompilationUnit unit, CompilationUnit node, int selectionStart, int selectionLength) { 115 Assert.isTrue(selectionStart >= 0); 116 Assert.isTrue(selectionLength >= 0); 117 fSelectionStart= selectionStart; 118 fSelectionLength= selectionLength; 119 fCu= unit; 120 121 fASTRoot= node; 122 fVariableDeclaration= null; 123 } 124 125 131 public InlineTempRefactoring(ICompilationUnit unit, int selectionStart, int selectionLength) { 132 this(unit, null, selectionStart, selectionLength); 133 } 134 135 public InlineTempRefactoring(VariableDeclaration decl) { 136 fVariableDeclaration= decl; 137 ASTNode astRoot= decl.getRoot(); 138 Assert.isTrue(astRoot instanceof CompilationUnit); 139 fASTRoot= (CompilationUnit) astRoot; 140 Assert.isTrue(fASTRoot.getJavaElement() instanceof ICompilationUnit); 141 142 fSelectionStart= decl.getStartPosition(); 143 fSelectionLength= decl.getLength(); 144 fCu= (ICompilationUnit) fASTRoot.getJavaElement(); 145 } 146 147 public RefactoringStatus checkIfTempSelected() { 148 VariableDeclaration decl= getVariableDeclaration(); 149 if (decl == null) { 150 return CodeRefactoringUtil.checkMethodSyntaxErrors(fSelectionStart, fSelectionLength, getASTRoot(), RefactoringCoreMessages.InlineTempRefactoring_select_temp); 151 } 152 if (decl.getParent() instanceof FieldDeclaration) { 153 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineTemRefactoring_error_message_fieldsCannotBeInlined); 154 } 155 return new RefactoringStatus(); 156 } 157 158 private CompilationUnit getASTRoot() { 159 if (fASTRoot == null) { 160 fASTRoot= RefactoringASTParser.parseWithASTProvider(fCu, true, null); 161 } 162 return fASTRoot; 163 } 164 165 public VariableDeclaration getVariableDeclaration() { 166 if (fVariableDeclaration == null) { 167 fVariableDeclaration= TempDeclarationFinder.findTempDeclaration(getASTRoot(), fSelectionStart, fSelectionLength); 168 } 169 return fVariableDeclaration; 170 } 171 172 175 public String getName() { 176 return RefactoringCoreMessages.InlineTempRefactoring_name; 177 } 178 179 182 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { 183 try { 184 pm.beginTask("", 1); 186 RefactoringStatus result= Checks.validateModifiesFiles(ResourceUtil.getFiles(new ICompilationUnit[]{fCu}), getValidationContext()); 187 if (result.hasFatalError()) 188 return result; 189 190 VariableDeclaration declaration= getVariableDeclaration(); 191 192 result.merge(checkSelection(declaration)); 193 if (result.hasFatalError()) 194 return result; 195 196 result.merge(checkInitializer(declaration)); 197 return result; 198 } finally { 199 pm.done(); 200 } 201 } 202 203 private RefactoringStatus checkInitializer(VariableDeclaration decl) { 204 if (decl.getInitializer().getNodeType() == ASTNode.NULL_LITERAL) 205 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineTemRefactoring_error_message_nulLiteralsCannotBeInlined); 206 return null; 207 } 208 209 private RefactoringStatus checkSelection(VariableDeclaration decl) { 210 ASTNode parent= decl.getParent(); 211 if (parent instanceof MethodDeclaration) { 212 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineTempRefactoring_method_parameter); 213 } 214 215 if (parent instanceof CatchClause) { 216 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineTempRefactoring_exceptions_declared); 217 } 218 219 if (parent instanceof VariableDeclarationExpression && parent.getLocationInParent() == ForStatement.INITIALIZERS_PROPERTY) { 220 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineTempRefactoring_for_initializers); 221 } 222 223 if (decl.getInitializer() == null) { 224 String message= Messages.format(RefactoringCoreMessages.InlineTempRefactoring_not_initialized, decl.getName().getIdentifier()); 225 return RefactoringStatus.createFatalErrorStatus(message); 226 } 227 228 return checkAssignments(decl); 229 } 230 231 private RefactoringStatus checkAssignments(VariableDeclaration decl) { 232 TempAssignmentFinder assignmentFinder= new TempAssignmentFinder(decl); 233 getASTRoot().accept(assignmentFinder); 234 if (!assignmentFinder.hasAssignments()) 235 return new RefactoringStatus(); 236 ASTNode firstAssignment= assignmentFinder.getFirstAssignment(); 237 int start= firstAssignment.getStartPosition(); 238 int length= firstAssignment.getLength(); 239 ISourceRange range= new SourceRange(start, length); 240 RefactoringStatusContext context= JavaStatusContext.create(fCu, range); 241 String message= Messages.format(RefactoringCoreMessages.InlineTempRefactoring_assigned_more_once, decl.getName().getIdentifier()); 242 return RefactoringStatus.createFatalErrorStatus(message, context); 243 } 244 245 248 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException { 249 try { 250 pm.beginTask("", 1); return new RefactoringStatus(); 252 } finally { 253 pm.done(); 254 } 255 } 256 257 259 public Change createChange(IProgressMonitor pm) throws CoreException { 260 try { 261 pm.beginTask(RefactoringCoreMessages.InlineTempRefactoring_preview, 2); 262 final Map arguments= new HashMap (); 263 String project= null; 264 IJavaProject javaProject= fCu.getJavaProject(); 265 if (javaProject != null) 266 project= javaProject.getElementName(); 267 268 final IVariableBinding binding= getVariableDeclaration().resolveBinding(); 269 String text= null; 270 final IMethodBinding method= binding.getDeclaringMethod(); 271 if (method != null) 272 text= BindingLabelProvider.getBindingLabel(method, JavaElementLabels.ALL_FULLY_QUALIFIED); 273 else 274 text= '{' + JavaElementLabels.ELLIPSIS_STRING + '}'; 275 final String description= Messages.format(RefactoringCoreMessages.InlineTempRefactoring_descriptor_description_short, binding.getName()); 276 final String header= Messages.format(RefactoringCoreMessages.InlineTempRefactoring_descriptor_description, new String [] { BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED), text}); 277 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header); 278 comment.addSetting(Messages.format(RefactoringCoreMessages.InlineTempRefactoring_original_pattern, BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED))); 279 final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.INLINE_LOCAL_VARIABLE, project, description, comment.asString(), arguments, RefactoringDescriptor.NONE); 280 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fCu)); 281 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION, String.valueOf(fSelectionStart) + ' ' + String.valueOf(fSelectionLength)); 282 283 CompilationUnitRewrite cuRewrite= new CompilationUnitRewrite(fCu, fASTRoot); 284 285 inlineTemp(cuRewrite); 286 removeTemp(cuRewrite); 287 288 final CompilationUnitChange result= cuRewrite.createChange(RefactoringCoreMessages.InlineTempRefactoring_inline, false, new SubProgressMonitor(pm, 1)); 289 result.setDescriptor(new RefactoringChangeDescriptor(descriptor)); 290 return result; 291 } finally { 292 pm.done(); 293 } 294 } 295 296 private void inlineTemp(CompilationUnitRewrite cuRewrite) throws JavaModelException { 297 SimpleName[] references= getReferences(); 298 299 TextEditGroup groupDesc= cuRewrite.createGroupDescription(RefactoringCoreMessages.InlineTempRefactoring_inline_edit_name); 300 ASTRewrite rewrite= cuRewrite.getASTRewrite(); 301 302 for (int i= 0; i < references.length; i++){ 303 SimpleName curr= references[i]; 304 ASTNode initializerCopy= getInitializerSource(cuRewrite, curr); 305 rewrite.replace(curr, initializerCopy, groupDesc); 306 } 307 } 308 309 private boolean needsBrackets(SimpleName name, VariableDeclaration variableDeclaration) { 310 Expression initializer= variableDeclaration.getInitializer(); 311 if (initializer instanceof Assignment) return true; 313 314 return ASTNodes.substituteMustBeParenthesized(initializer, name); 315 } 316 317 318 private void removeTemp(CompilationUnitRewrite cuRewrite) throws JavaModelException { 319 VariableDeclaration variableDeclaration= getVariableDeclaration(); 320 TextEditGroup groupDesc= cuRewrite.createGroupDescription(RefactoringCoreMessages.InlineTempRefactoring_remove_edit_name); 321 ASTNode parent= variableDeclaration.getParent(); 322 ASTRewrite rewrite= cuRewrite.getASTRewrite(); 323 if (parent instanceof VariableDeclarationStatement && ((VariableDeclarationStatement) parent).fragments().size() == 1) { 324 rewrite.remove(parent, groupDesc); 325 } else { 326 rewrite.remove(variableDeclaration, groupDesc); 327 } 328 } 329 330 private Expression getInitializerSource(CompilationUnitRewrite rewrite, SimpleName reference) throws JavaModelException { 331 Expression copy= getModifiedInitializerSource(rewrite, reference); 332 boolean brackets= needsBrackets(reference, getVariableDeclaration()); 333 if (brackets) { 334 ParenthesizedExpression parentExpr= rewrite.getAST().newParenthesizedExpression(); 335 parentExpr.setExpression(copy); 336 return parentExpr; 337 } 338 return copy; 339 } 340 341 private Expression getModifiedInitializerSource(CompilationUnitRewrite rewrite, SimpleName reference) throws JavaModelException { 342 VariableDeclaration varDecl= getVariableDeclaration(); 343 Expression initializer= varDecl.getInitializer(); 344 345 ASTNode referenceContext= reference.getParent(); 346 if (isInvocation(initializer)) { 347 if (Invocations.isResolvedTypeInferredFromExpectedType(initializer)) { 348 if (! (referenceContext instanceof VariableDeclarationFragment 349 || referenceContext instanceof SingleVariableDeclaration 350 || referenceContext instanceof Assignment)) { 351 IMethodBinding methodBinding= Invocations.resolveBinding(initializer); 352 ITypeBinding[] typeArguments= methodBinding.getTypeArguments(); 353 Type[] typeArgumentNodes= new Type[typeArguments.length]; 354 for (int i= 0; i < typeArguments.length; i++) { 355 typeArgumentNodes[i]= rewrite.getImportRewrite().addImport(typeArguments[i], rewrite.getAST()); 356 } 357 String newSource= createParameterizedInvocation(initializer, typeArgumentNodes); 358 return (Expression) rewrite.getASTRewrite().createStringPlaceholder(newSource, initializer.getNodeType()); 359 } 360 } 361 } 362 363 Expression copy= (Expression) rewrite.getASTRewrite().createCopyTarget(initializer); 364 if (initializer instanceof ArrayInitializer && ASTNodes.getDimensions(varDecl) > 0) { 365 ArrayType newType= (ArrayType) ASTNodeFactory.newType(rewrite.getAST(), varDecl); 366 367 ArrayCreation newArrayCreation= rewrite.getAST().newArrayCreation(); 368 newArrayCreation.setType(newType); 369 newArrayCreation.setInitializer((ArrayInitializer) copy); 370 return newArrayCreation; 371 } 372 return copy; 373 } 374 375 private String createParameterizedInvocation(Expression invocation, Type[] typeArgumentNodes) throws JavaModelException { 376 ASTRewrite rewrite= ASTRewrite.create(invocation.getAST()); 377 ListRewrite typeArgsRewrite= rewrite.getListRewrite(invocation, Invocations.getTypeArgumentsProperty(invocation)); 378 for (int i= 0; i < typeArgumentNodes.length; i++) { 379 typeArgsRewrite.insertLast(typeArgumentNodes[i], null); 380 } 381 382 IDocument document= new Document(fCu.getBuffer().getContents()); 383 final RangeMarker marker= new RangeMarker(invocation.getStartPosition(), invocation.getLength()); 384 IJavaProject project= fCu.getJavaProject(); 385 TextEdit[] rewriteEdits= rewrite.rewriteAST(document, project.getOptions(true)).removeChildren(); 386 marker.addChildren(rewriteEdits); 387 try { 388 marker.apply(document, TextEdit.UPDATE_REGIONS); 389 String rewrittenInitializer= document.get(marker.getOffset(), marker.getLength()); 390 IRegion region= document.getLineInformation(document.getLineOfOffset(marker.getOffset())); 391 int oldIndent= Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), project); 392 return Strings.changeIndent(rewrittenInitializer, oldIndent, project, "", TextUtilities.getDefaultLineDelimiter(document)); } catch (MalformedTreeException e) { 394 JavaPlugin.log(e); 395 } catch (BadLocationException e) { 396 JavaPlugin.log(e); 397 } 398 return fCu.getBuffer().getText(invocation.getStartPosition(), invocation.getLength()); 400 } 401 402 private static boolean isInvocation(Expression node) { 403 return node instanceof MethodInvocation || node instanceof SuperMethodInvocation; 404 } 405 406 public SimpleName[] getReferences() { 407 if (fReferences != null) 408 return fReferences; 409 TempOccurrenceAnalyzer analyzer= new TempOccurrenceAnalyzer(getVariableDeclaration(), false); 410 analyzer.perform(); 411 fReferences= analyzer.getReferenceNodes(); 412 return fReferences; 413 } 414 415 public RefactoringStatus initialize(final RefactoringArguments arguments) { 416 if (arguments instanceof JavaRefactoringArguments) { 417 final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments; 418 final String selection= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION); 419 if (selection != null) { 420 int offset= -1; 421 int length= -1; 422 final StringTokenizer tokenizer= new StringTokenizer (selection); 423 if (tokenizer.hasMoreTokens()) 424 offset= Integer.valueOf(tokenizer.nextToken()).intValue(); 425 if (tokenizer.hasMoreTokens()) 426 length= Integer.valueOf(tokenizer.nextToken()).intValue(); 427 if (offset >= 0 && length >= 0) { 428 fSelectionStart= offset; 429 fSelectionLength= length; 430 } else 431 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object [] { selection, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION})); 432 } else 433 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION)); 434 final String handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT); 435 if (handle != null) { 436 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false); 437 if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT) 438 return createInputFatalStatus(element, IJavaRefactorings.INLINE_LOCAL_VARIABLE); 439 else { 440 fCu= (ICompilationUnit) element; 441 if (checkIfTempSelected().hasFatalError()) 442 return createInputFatalStatus(element, IJavaRefactorings.INLINE_LOCAL_VARIABLE); 443 } 444 } else 445 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT)); 446 } else 447 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments); 448 return new RefactoringStatus(); 449 } 450 } 451 | Popular Tags |