1 /******************************************************************************* 2 * Copyright (c) 2006, 2018 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.jdt.internal.corext.refactoring.structure; 15 16 import java.util.ArrayList; 17 import java.util.Arrays; 18 import java.util.HashMap; 19 import java.util.Iterator; 20 import java.util.List; 21 import java.util.Map; 22 23 import org.eclipse.core.runtime.Assert; 24 import org.eclipse.core.runtime.CoreException; 25 import org.eclipse.core.runtime.IProgressMonitor; 26 import org.eclipse.core.runtime.NullProgressMonitor; 27 import org.eclipse.core.runtime.SubProgressMonitor; 28 29 import org.eclipse.text.edits.MalformedTreeException; 30 import org.eclipse.text.edits.TextEdit; 31 32 import org.eclipse.jface.text.BadLocationException; 33 import org.eclipse.jface.text.Document; 34 import org.eclipse.jface.text.IDocument; 35 36 import org.eclipse.ltk.core.refactoring.GroupCategorySet; 37 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 38 import org.eclipse.ltk.core.refactoring.RefactoringStatusContext; 39 import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant; 40 import org.eclipse.ltk.core.refactoring.participants.SharableParticipants; 41 42 import org.eclipse.jdt.core.Flags; 43 import org.eclipse.jdt.core.ICompilationUnit; 44 import org.eclipse.jdt.core.IField; 45 import org.eclipse.jdt.core.IInitializer; 46 import org.eclipse.jdt.core.IJavaElement; 47 import org.eclipse.jdt.core.IMember; 48 import org.eclipse.jdt.core.IMethod; 49 import org.eclipse.jdt.core.ISourceRange; 50 import org.eclipse.jdt.core.IType; 51 import org.eclipse.jdt.core.ITypeHierarchy; 52 import org.eclipse.jdt.core.JavaModelException; 53 import org.eclipse.jdt.core.dom.AST; 54 import org.eclipse.jdt.core.dom.ASTNode; 55 import org.eclipse.jdt.core.dom.ASTVisitor; 56 import org.eclipse.jdt.core.dom.Annotation; 57 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; 58 import org.eclipse.jdt.core.dom.BodyDeclaration; 59 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 60 import org.eclipse.jdt.core.dom.CompilationUnit; 61 import org.eclipse.jdt.core.dom.Dimension; 62 import org.eclipse.jdt.core.dom.EnumDeclaration; 63 import org.eclipse.jdt.core.dom.Expression; 64 import org.eclipse.jdt.core.dom.FieldDeclaration; 65 import org.eclipse.jdt.core.dom.IExtendedModifier; 66 import org.eclipse.jdt.core.dom.IMethodBinding; 67 import org.eclipse.jdt.core.dom.ITypeBinding; 68 import org.eclipse.jdt.core.dom.Javadoc; 69 import org.eclipse.jdt.core.dom.MethodDeclaration; 70 import org.eclipse.jdt.core.dom.Modifier; 71 import org.eclipse.jdt.core.dom.SimpleName; 72 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 73 import org.eclipse.jdt.core.dom.Type; 74 import org.eclipse.jdt.core.dom.TypeDeclaration; 75 import org.eclipse.jdt.core.dom.TypeParameter; 76 import org.eclipse.jdt.core.dom.VariableDeclaration; 77 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 78 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 79 import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition; 80 import org.eclipse.jdt.core.search.IJavaSearchConstants; 81 import org.eclipse.jdt.core.search.SearchMatch; 82 import org.eclipse.jdt.core.search.SearchPattern; 83 84 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings; 85 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; 86 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 87 import org.eclipse.jdt.internal.corext.dom.ModifierRewrite; 88 import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester; 89 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 90 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory; 91 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2; 92 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; 93 import org.eclipse.jdt.internal.corext.refactoring.reorg.SourceReferenceUtil; 94 import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel; 95 import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsSolver; 96 import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor; 97 import org.eclipse.jdt.internal.corext.refactoring.util.JavaStatusContext; 98 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 99 import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager; 100 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 101 import org.eclipse.jdt.internal.corext.util.JdtFlags; 102 import org.eclipse.jdt.internal.corext.util.Messages; 103 import org.eclipse.jdt.internal.corext.util.SearchUtils; 104 import org.eclipse.jdt.internal.core.manipulation.StubUtility; 105 import org.eclipse.jdt.internal.core.manipulation.util.Strings; 106 107 import org.eclipse.jdt.ui.JavaElementLabels; 108 109 import org.eclipse.jdt.internal.ui.JavaPlugin; 110 111 /** 112 * Partial implementation of a hierarchy refactoring processor used in pull up, 113 * push down and extract supertype refactorings. 114 * <p> 115 * This processor provides common functionality to move members in a type 116 * hierarchy, and to perform a "Use Supertype" refactoring afterwards. 117 * </p> 118 * 119 * @since 3.2 120 */ 121 public abstract class HierarchyProcessor extends SuperTypeRefactoringProcessor { 122 123 /** 124 * AST node visitor which performs the actual mapping. 125 */ 126 public static class TypeVariableMapper extends ASTVisitor { 127 128 /** The type variable mapping to use */ 129 protected final TypeVariableMaplet[] fMapping; 130 131 /** The AST rewrite to use */ 132 protected final ASTRewrite fRewrite; 133 134 /** 135 * Creates a new type variable mapper. 136 * 137 * @param rewrite 138 * The AST rewrite to use 139 * @param mapping 140 * The type variable mapping to use 141 */ TypeVariableMapper(final ASTRewrite rewrite, final TypeVariableMaplet[] mapping)142 public TypeVariableMapper(final ASTRewrite rewrite, final TypeVariableMaplet[] mapping) { 143 Assert.isNotNull(rewrite); 144 Assert.isNotNull(mapping); 145 fRewrite= rewrite; 146 fMapping= mapping; 147 } 148 149 @Override visit(final SimpleName node)150 public final boolean visit(final SimpleName node) { 151 final ITypeBinding binding= node.resolveTypeBinding(); 152 if (binding != null && binding.isTypeVariable()) { 153 String name= null; 154 for (TypeVariableMaplet mapping : fMapping) { 155 name= binding.getName(); 156 if (mapping.getSourceName().equals(name) && node.getIdentifier().equals(name)) { 157 final MethodDeclaration declaration= ASTNodes.getParent(node, MethodDeclaration.class); 158 if (declaration != null) { 159 final IMethodBinding method= declaration.resolveBinding(); 160 if (method != null) { 161 for (ITypeBinding b : method.getTypeParameters()) { 162 if (b.isEqualTo(binding)) { 163 return true; 164 } 165 } 166 } 167 } 168 fRewrite.set(node, SimpleName.IDENTIFIER_PROPERTY, mapping.getTargetName(), null); 169 } 170 } 171 } 172 return true; 173 } 174 } 175 areAllFragmentsDeleted(final FieldDeclaration declaration, final List<ASTNode> declarationNodes)176 protected static boolean areAllFragmentsDeleted(final FieldDeclaration declaration, final List<ASTNode> declarationNodes) { 177 return declarationNodes.containsAll(declaration.fragments()); 178 } 179 checkProjectCompliance(CompilationUnitRewrite sourceRewriter, IType destination, IMember[] members)180 protected static RefactoringStatus checkProjectCompliance(CompilationUnitRewrite sourceRewriter, IType destination, IMember[] members) { 181 RefactoringStatus status= new RefactoringStatus(); 182 if (!JavaModelUtil.is50OrHigher(destination.getJavaProject())) { 183 for (IMember member : members) { 184 try { 185 BodyDeclaration decl= ASTNodeSearchUtil.getBodyDeclarationNode(member, sourceRewriter.getRoot()); 186 if (decl != null) { 187 for (final Iterator<IExtendedModifier> iterator= decl.modifiers().iterator(); iterator.hasNext();) { 188 boolean reported= false; 189 final IExtendedModifier modifier= iterator.next(); 190 if (!reported && modifier.isAnnotation()) { 191 status.merge(RefactoringStatus.createErrorStatus(Messages.format(RefactoringCoreMessages.PullUpRefactoring_incompatible_langauge_constructs, new String[]{JavaElementLabels.getTextLabel(member, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(destination, JavaElementLabels.ALL_DEFAULT)}), JavaStatusContext.create(member))); 192 reported= true; 193 } 194 } 195 } 196 } catch (JavaModelException exception) { 197 JavaPlugin.log(exception); 198 } 199 if (member instanceof IMethod) { 200 final IMethod method= (IMethod) member; 201 try { 202 if (Flags.isVarargs(method.getFlags())) { 203 status.merge(RefactoringStatus.createErrorStatus(Messages.format(RefactoringCoreMessages.PullUpRefactoring_incompatible_language_constructs1, new String[]{JavaElementLabels.getTextLabel(member, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(destination, JavaElementLabels.ALL_DEFAULT)}), JavaStatusContext.create(member))); 204 } 205 } catch (JavaModelException exception) { 206 JavaPlugin.log(exception); 207 } 208 } 209 } 210 } 211 return status; 212 } 213 copyExtraDimensions(final VariableDeclaration oldVarDeclaration, final VariableDeclaration newVarDeclaration)214 protected static void copyExtraDimensions(final VariableDeclaration oldVarDeclaration, final VariableDeclaration newVarDeclaration) { 215 final AST ast= newVarDeclaration.getAST(); 216 for (Object extraDimension : oldVarDeclaration.extraDimensions()) { 217 newVarDeclaration.extraDimensions().add(ASTNode.copySubtree(ast, (Dimension) extraDimension)); 218 } 219 } 220 copyExtraDimensions(final MethodDeclaration oldMethod, final MethodDeclaration newMethod)221 protected static void copyExtraDimensions(final MethodDeclaration oldMethod, final MethodDeclaration newMethod) { 222 final AST ast= newMethod.getAST(); 223 for (Object extraDimension : oldMethod.extraDimensions()) { 224 newMethod.extraDimensions().add(ASTNode.copySubtree(ast, (Dimension) extraDimension)); 225 } 226 } 227 copyAnnotations(final FieldDeclaration oldField, final FieldDeclaration newField)228 protected static void copyAnnotations(final FieldDeclaration oldField, final FieldDeclaration newField) { 229 final AST ast= newField.getAST(); 230 for (Object element : oldField.modifiers()) { 231 final IExtendedModifier modifier= (IExtendedModifier) element; 232 final List<IExtendedModifier> modifiers= newField.modifiers(); 233 if (modifier.isAnnotation() && !modifiers.contains(modifier)) 234 modifiers.add((IExtendedModifier) ASTNode.copySubtree(ast, (Annotation) modifier)); 235 } 236 } 237 copyAnnotations(final MethodDeclaration oldMethod, final MethodDeclaration newMethod)238 protected static void copyAnnotations(final MethodDeclaration oldMethod, final MethodDeclaration newMethod) { 239 final AST ast= newMethod.getAST(); 240 for (Object element : oldMethod.modifiers()) { 241 final IExtendedModifier modifier= (IExtendedModifier) element; 242 final List<IExtendedModifier> modifiers= newMethod.modifiers(); 243 if (modifier.isAnnotation() && !modifiers.contains(modifier)) 244 modifiers.add((IExtendedModifier) ASTNode.copySubtree(ast, (Annotation) modifier)); 245 } 246 } 247 copyJavadocNode(final ASTRewrite rewrite, final BodyDeclaration oldDeclaration, final BodyDeclaration newDeclaration)248 protected static void copyJavadocNode(final ASTRewrite rewrite, final BodyDeclaration oldDeclaration, final BodyDeclaration newDeclaration) { 249 final Javadoc predecessor= oldDeclaration.getJavadoc(); 250 if (predecessor != null) { 251 String newString= ASTNodes.getNodeSource(predecessor, false, true); 252 if (newString != null) { 253 newDeclaration.setJavadoc((Javadoc) rewrite.createStringPlaceholder(newString, ASTNode.JAVADOC)); 254 } 255 } 256 } 257 copyThrownExceptions(final MethodDeclaration oldMethod, final MethodDeclaration newMethod)258 protected static void copyThrownExceptions(final MethodDeclaration oldMethod, final MethodDeclaration newMethod) { 259 final AST ast= newMethod.getAST(); 260 for (Object thrownExceptionType : oldMethod.thrownExceptionTypes()) { 261 newMethod.thrownExceptionTypes().add(ASTNode.copySubtree(ast, (Type) thrownExceptionType)); 262 } 263 } 264 copyTypeParameters(final MethodDeclaration oldMethod, final MethodDeclaration newMethod)265 protected static void copyTypeParameters(final MethodDeclaration oldMethod, final MethodDeclaration newMethod) { 266 final AST ast= newMethod.getAST(); 267 for (Object typeParameter : oldMethod.typeParameters()) { 268 newMethod.typeParameters().add(ASTNode.copySubtree(ast, (TypeParameter) typeParameter)); 269 } 270 } 271 createLabel(final IMember member)272 protected static String createLabel(final IMember member) { 273 if (member instanceof IType) 274 return JavaElementLabels.getTextLabel(member, JavaElementLabels.ALL_FULLY_QUALIFIED); 275 else if (member instanceof IMethod) 276 return JavaElementLabels.getTextLabel(member, JavaElementLabels.ALL_FULLY_QUALIFIED); 277 else if (member instanceof IField) 278 return JavaElementLabels.getTextLabel(member, JavaElementLabels.ALL_FULLY_QUALIFIED); 279 else if (member instanceof IInitializer) 280 return RefactoringCoreMessages.HierarchyRefactoring_initializer; 281 Assert.isTrue(false); 282 return null; 283 } 284 createNewFieldDeclarationNode(final ASTRewrite rewrite, final CompilationUnit unit, final IField field, final VariableDeclarationFragment oldFieldFragment, final TypeVariableMaplet[] mapping, final IProgressMonitor monitor, final RefactoringStatus status, final int modifiers)285 protected static FieldDeclaration createNewFieldDeclarationNode(final ASTRewrite rewrite, final CompilationUnit unit, final IField field, final VariableDeclarationFragment oldFieldFragment, final TypeVariableMaplet[] mapping, final IProgressMonitor monitor, final RefactoringStatus status, final int modifiers) throws JavaModelException { 286 final VariableDeclarationFragment newFragment= rewrite.getAST().newVariableDeclarationFragment(); 287 copyExtraDimensions(oldFieldFragment, newFragment); 288 if (oldFieldFragment.getInitializer() != null) { 289 Expression newInitializer= null; 290 if (mapping.length > 0) 291 newInitializer= createPlaceholderForExpression(oldFieldFragment.getInitializer(), field.getCompilationUnit(), mapping, rewrite); 292 else 293 newInitializer= createPlaceholderForExpression(oldFieldFragment.getInitializer(), field.getCompilationUnit(), rewrite); 294 newFragment.setInitializer(newInitializer); 295 } 296 newFragment.setName(((SimpleName) ASTNode.copySubtree(rewrite.getAST(), oldFieldFragment.getName()))); 297 final FieldDeclaration newField= rewrite.getAST().newFieldDeclaration(newFragment); 298 final FieldDeclaration oldField= ASTNodeSearchUtil.getFieldDeclarationNode(field, unit); 299 copyJavadocNode(rewrite, oldField, newField); 300 copyAnnotations(oldField, newField); 301 newField.modifiers().addAll(ASTNodeFactory.newModifiers(rewrite.getAST(), modifiers)); 302 final Type oldType= oldField.getType(); 303 Type newType= null; 304 if (mapping.length > 0) { 305 newType= createPlaceholderForType(oldType, field.getCompilationUnit(), mapping, rewrite); 306 } else 307 newType= createPlaceholderForType(oldType, field.getCompilationUnit(), rewrite); 308 newField.setType(newType); 309 return newField; 310 } 311 createPlaceholderForExpression(final Expression expression, final ICompilationUnit declaringCu, final ASTRewrite rewrite)312 protected static Expression createPlaceholderForExpression(final Expression expression, final ICompilationUnit declaringCu, final ASTRewrite rewrite) throws JavaModelException { 313 return (Expression) rewrite.createStringPlaceholder(declaringCu.getBuffer().getText(expression.getStartPosition(), expression.getLength()), ASTNode.METHOD_INVOCATION); 314 } 315 createPlaceholderForExpression(final Expression expression, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite)316 protected static Expression createPlaceholderForExpression(final Expression expression, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite) throws JavaModelException { 317 Expression result= null; 318 try { 319 final IDocument document= new Document(declaringCu.getBuffer().getContents()); 320 final ASTRewrite rewriter= ASTRewrite.create(expression.getAST()); 321 final ITrackedNodePosition position= rewriter.track(expression); 322 expression.accept(new TypeVariableMapper(rewriter, mapping)); 323 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE); 324 result= (Expression) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.METHOD_INVOCATION); 325 } catch (MalformedTreeException exception) { 326 JavaPlugin.log(exception); 327 } catch (BadLocationException exception) { 328 JavaPlugin.log(exception); 329 } 330 return result; 331 } 332 createPlaceholderForProtectedTypeDeclaration(final BodyDeclaration bodyDeclaration, final CompilationUnit declaringCuNode, final ICompilationUnit declaringCu, final ASTRewrite rewrite, final boolean removeIndentation)333 protected static BodyDeclaration createPlaceholderForProtectedTypeDeclaration(final BodyDeclaration bodyDeclaration, final CompilationUnit declaringCuNode, final ICompilationUnit declaringCu, final ASTRewrite rewrite, final boolean removeIndentation) throws JavaModelException { 334 String text= null; 335 try { 336 final ASTRewrite rewriter= ASTRewrite.create(bodyDeclaration.getAST()); 337 ModifierRewrite.create(rewriter, bodyDeclaration).setVisibility(Modifier.PROTECTED, null); 338 final ITrackedNodePosition position= rewriter.track(bodyDeclaration); 339 final IDocument document= new Document(declaringCu.getBuffer().getText(declaringCuNode.getStartPosition(), declaringCuNode.getLength())); 340 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS); 341 text= document.get(position.getStartPosition(), position.getLength()); 342 } catch (BadLocationException exception) { 343 text= getNewText(bodyDeclaration, declaringCu, removeIndentation); 344 } 345 return (BodyDeclaration) rewrite.createStringPlaceholder(text, ASTNode.TYPE_DECLARATION); 346 } 347 createPlaceholderForProtectedTypeDeclaration(final BodyDeclaration bodyDeclaration, final CompilationUnit declaringCuNode, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite, final boolean removeIndentation)348 protected static BodyDeclaration createPlaceholderForProtectedTypeDeclaration(final BodyDeclaration bodyDeclaration, final CompilationUnit declaringCuNode, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite, final boolean removeIndentation) throws JavaModelException { 349 BodyDeclaration result= null; 350 try { 351 final IDocument document= new Document(declaringCu.getBuffer().getContents()); 352 final ASTRewrite rewriter= ASTRewrite.create(bodyDeclaration.getAST()); 353 final ITrackedNodePosition position= rewriter.track(bodyDeclaration); 354 bodyDeclaration.accept(new TypeVariableMapper(rewriter, mapping) { 355 356 @Override 357 public final boolean visit(final AnnotationTypeDeclaration node) { 358 ModifierRewrite.create(fRewrite, bodyDeclaration).setVisibility(Modifier.PROTECTED, null); 359 return true; 360 } 361 362 @Override 363 public final boolean visit(final EnumDeclaration node) { 364 ModifierRewrite.create(fRewrite, bodyDeclaration).setVisibility(Modifier.PROTECTED, null); 365 return true; 366 } 367 368 @Override 369 public final boolean visit(final TypeDeclaration node) { 370 ModifierRewrite.create(fRewrite, bodyDeclaration).setVisibility(Modifier.PROTECTED, null); 371 return true; 372 } 373 }); 374 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE); 375 result= (BodyDeclaration) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.TYPE_DECLARATION); 376 } catch (MalformedTreeException exception) { 377 JavaPlugin.log(exception); 378 } catch (BadLocationException exception) { 379 JavaPlugin.log(exception); 380 } 381 return result; 382 } 383 createPlaceholderForSingleVariableDeclaration(final SingleVariableDeclaration declaration, final ICompilationUnit declaringCu, final ASTRewrite rewrite)384 protected static SingleVariableDeclaration createPlaceholderForSingleVariableDeclaration(final SingleVariableDeclaration declaration, final ICompilationUnit declaringCu, final ASTRewrite rewrite) throws JavaModelException { 385 return (SingleVariableDeclaration) rewrite.createStringPlaceholder(declaringCu.getBuffer().getText(declaration.getStartPosition(), declaration.getLength()), ASTNode.SINGLE_VARIABLE_DECLARATION); 386 } 387 createPlaceholderForSingleVariableDeclaration(final SingleVariableDeclaration declaration, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite)388 protected static SingleVariableDeclaration createPlaceholderForSingleVariableDeclaration(final SingleVariableDeclaration declaration, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite) throws JavaModelException { 389 SingleVariableDeclaration result= null; 390 try { 391 final IDocument document= new Document(declaringCu.getBuffer().getContents()); 392 final ASTRewrite rewriter= ASTRewrite.create(declaration.getAST()); 393 final ITrackedNodePosition position= rewriter.track(declaration); 394 declaration.accept(new TypeVariableMapper(rewriter, mapping)); 395 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE); 396 result= (SingleVariableDeclaration) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.SINGLE_VARIABLE_DECLARATION); 397 } catch (MalformedTreeException exception) { 398 JavaPlugin.log(exception); 399 } catch (BadLocationException exception) { 400 JavaPlugin.log(exception); 401 } 402 return result; 403 } 404 createPlaceholderForType(final Type type, final ICompilationUnit declaringCu, final ASTRewrite rewrite)405 protected static Type createPlaceholderForType(final Type type, final ICompilationUnit declaringCu, final ASTRewrite rewrite) throws JavaModelException { 406 return (Type) rewrite.createStringPlaceholder(declaringCu.getBuffer().getText(type.getStartPosition(), type.getLength()), ASTNode.SIMPLE_TYPE); 407 } 408 createPlaceholderForType(final Type type, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite)409 protected static Type createPlaceholderForType(final Type type, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite) throws JavaModelException { 410 Type result= null; 411 try { 412 final IDocument document= new Document(declaringCu.getBuffer().getContents()); 413 final ASTRewrite rewriter= ASTRewrite.create(type.getAST()); 414 final ITrackedNodePosition position= rewriter.track(type); 415 type.accept(new TypeVariableMapper(rewriter, mapping)); 416 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE); 417 result= (Type) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.SIMPLE_TYPE); 418 } catch (MalformedTreeException exception) { 419 JavaPlugin.log(exception); 420 } catch (BadLocationException exception) { 421 JavaPlugin.log(exception); 422 } 423 return result; 424 } 425 createPlaceholderForTypeDeclaration(final BodyDeclaration bodyDeclaration, final ICompilationUnit declaringCu, final ASTRewrite rewrite, final boolean removeIndentation)426 protected static BodyDeclaration createPlaceholderForTypeDeclaration(final BodyDeclaration bodyDeclaration, final ICompilationUnit declaringCu, final ASTRewrite rewrite, final boolean removeIndentation) throws JavaModelException { 427 return (BodyDeclaration) rewrite.createStringPlaceholder(getNewText(bodyDeclaration, declaringCu, removeIndentation), ASTNode.TYPE_DECLARATION); 428 } 429 createPlaceholderForTypeDeclaration(final BodyDeclaration bodyDeclaration, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite, final boolean removeIndentation)430 protected static BodyDeclaration createPlaceholderForTypeDeclaration(final BodyDeclaration bodyDeclaration, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite, final boolean removeIndentation) throws JavaModelException { 431 BodyDeclaration result= null; 432 try { 433 final IDocument document= new Document(declaringCu.getBuffer().getContents()); 434 final ASTRewrite rewriter= ASTRewrite.create(bodyDeclaration.getAST()); 435 final ITrackedNodePosition position= rewriter.track(bodyDeclaration); 436 bodyDeclaration.accept(new TypeVariableMapper(rewriter, mapping)); 437 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE); 438 result= (BodyDeclaration) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.TYPE_DECLARATION); 439 } catch (MalformedTreeException exception) { 440 JavaPlugin.log(exception); 441 } catch (BadLocationException exception) { 442 JavaPlugin.log(exception); 443 } 444 return result; 445 } 446 deleteDeclarationNodes(final CompilationUnitRewrite sourceRewriter, final boolean sameCu, final CompilationUnitRewrite unitRewriter, final List<IMember> members, final GroupCategorySet set)447 protected static void deleteDeclarationNodes(final CompilationUnitRewrite sourceRewriter, final boolean sameCu, final CompilationUnitRewrite unitRewriter, final List<IMember> members, final GroupCategorySet set) throws JavaModelException { 448 final List<ASTNode> declarationNodes= getDeclarationNodes(unitRewriter.getRoot(), members); 449 for (ASTNode node : declarationNodes) { 450 final ASTRewrite rewriter= unitRewriter.getASTRewrite(); 451 final ImportRemover remover= unitRewriter.getImportRemover(); 452 if (node instanceof VariableDeclarationFragment) { 453 if (node.getParent() instanceof FieldDeclaration) { 454 final FieldDeclaration declaration= (FieldDeclaration) node.getParent(); 455 if (areAllFragmentsDeleted(declaration, declarationNodes)) { 456 rewriter.remove(declaration, unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_remove_member, set)); 457 if (!sameCu) 458 remover.registerRemovedNode(declaration); 459 } else { 460 rewriter.remove(node, unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_remove_member, set)); 461 if (!sameCu) 462 remover.registerRemovedNode(node); 463 } 464 } 465 } else { 466 rewriter.remove(node, unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_remove_member, set)); 467 if (!sameCu) 468 remover.registerRemovedNode(node); 469 } 470 } 471 } 472 getDeclarationNodes(final CompilationUnit cuNode, final List<IMember> members)473 protected static List<ASTNode> getDeclarationNodes(final CompilationUnit cuNode, final List<IMember> members) throws JavaModelException { 474 final List<ASTNode> result= new ArrayList<>(members.size()); 475 for (IMember member : members) { 476 ASTNode node= null; 477 if (member instanceof IField) { 478 if (Flags.isEnum(member.getFlags())) 479 node= ASTNodeSearchUtil.getEnumConstantDeclaration((IField) member, cuNode); 480 else 481 node= ASTNodeSearchUtil.getFieldDeclarationFragmentNode((IField) member, cuNode); 482 } else if (member instanceof IType) 483 node= ASTNodeSearchUtil.getAbstractTypeDeclarationNode((IType) member, cuNode); 484 else if (member instanceof IMethod) 485 node= ASTNodeSearchUtil.getMethodDeclarationNode((IMethod) member, cuNode); 486 if (node != null) 487 result.add(node); 488 } 489 return result; 490 } 491 getNewText(final ASTNode node, final ICompilationUnit declaringCu, final boolean removeIndentation)492 protected static String getNewText(final ASTNode node, final ICompilationUnit declaringCu, final boolean removeIndentation) throws JavaModelException { 493 final String result= declaringCu.getBuffer().getText(node.getStartPosition(), node.getLength()); 494 if (removeIndentation) 495 return getUnindentedText(result, declaringCu); 496 497 return result; 498 } 499 getUnindentedText(final String text, final ICompilationUnit declaringCu)500 protected static String getUnindentedText(final String text, final ICompilationUnit declaringCu) throws JavaModelException { 501 final String[] lines= Strings.convertIntoLines(text); 502 Strings.trimIndentation(lines, declaringCu.getJavaProject(), false); 503 return Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(declaringCu)); 504 } 505 506 /** The cached declaring type */ 507 protected IType fCachedDeclaringType; 508 509 /** The cached member references */ 510 protected final Map<IMember, Object[]> fCachedMembersReferences= new HashMap<>(2); 511 512 /** The cached type references */ 513 protected IType[] fCachedReferencedTypes; 514 515 /** The text edit based change manager */ 516 protected TextEditBasedChangeManager fChangeManager; 517 518 /** Does the refactoring use a working copy layer? */ 519 protected final boolean fLayer; 520 521 /** The members to move (may be in working copies) */ 522 protected IMember[] fMembersToMove; 523 524 /** 525 * Creates a new hierarchy processor. 526 * 527 * @param members 528 * the members, or <code>null</code> if invoked by scripting 529 * @param settings 530 * the code generation settings to use 531 * @param layer 532 * <code>true</code> to create a working copy layer, 533 * <code>false</code> otherwise 534 */ HierarchyProcessor(final IMember[] members, final CodeGenerationSettings settings, boolean layer)535 protected HierarchyProcessor(final IMember[] members, final CodeGenerationSettings settings, boolean layer) { 536 super(settings); 537 fLayer= layer; 538 if (members != null) { 539 fMembersToMove= (IMember[]) SourceReferenceUtil.sortByOffset(members); 540 if (layer && fMembersToMove.length > 0) { 541 final ICompilationUnit original= fMembersToMove[0].getCompilationUnit(); 542 if (original != null) { 543 try { 544 final ICompilationUnit copy= getSharedWorkingCopy(original.getPrimary(), new NullProgressMonitor()); 545 if (copy != null) { 546 for (int index= 0; index < fMembersToMove.length; index++) { 547 final IJavaElement[] elements= copy.findElements(fMembersToMove[index]); 548 if (elements != null && elements.length > 0 && elements[0] instanceof IMember) { 549 fMembersToMove[index]= (IMember) elements[0]; 550 } 551 } 552 } 553 } catch (JavaModelException exception) { 554 JavaPlugin.log(exception); 555 } 556 } 557 } 558 } 559 } 560 canBeAccessedFrom(final IMember member, final IType target, final ITypeHierarchy hierarchy)561 protected boolean canBeAccessedFrom(final IMember member, final IType target, final ITypeHierarchy hierarchy) throws JavaModelException { 562 Assert.isTrue(!(member instanceof IInitializer)); 563 return member.exists(); 564 } 565 checkConstructorCalls(final IType type, final IProgressMonitor monitor)566 protected RefactoringStatus checkConstructorCalls(final IType type, final IProgressMonitor monitor) throws JavaModelException { 567 try { 568 monitor.beginTask(RefactoringCoreMessages.PullUpRefactoring_checking, 2); 569 final RefactoringStatus result= new RefactoringStatus(); 570 final String message= Messages.format(RefactoringCoreMessages.HierarchyRefactoring_gets_instantiated, new Object[] { JavaElementLabels.getTextLabel(type, JavaElementLabels.ALL_FULLY_QUALIFIED)}); 571 572 for (SearchResultGroup group : ConstructorReferenceFinder.getConstructorReferences(type, fOwner, new SubProgressMonitor(monitor, 1), result)) { 573 ICompilationUnit unit= group.getCompilationUnit(); 574 if (unit != null) { 575 final CompilationUnit cuNode= RefactoringASTParser.parseWithASTProvider(unit, false, new SubProgressMonitor(monitor, 1)); 576 for (ASTNode node : ASTNodeSearchUtil.getAstNodes(group.getSearchResults(), cuNode)) { 577 if ((node instanceof ClassInstanceCreation) || ConstructorReferenceFinder.isImplicitConstructorReferenceNodeInClassCreations(node)) { 578 final RefactoringStatusContext context= JavaStatusContext.create(unit, node); 579 result.addError(message, context); 580 } 581 } 582 } 583 } 584 return result; 585 } finally { 586 monitor.done(); 587 } 588 } 589 checkDeclaringType(final IProgressMonitor monitor)590 protected RefactoringStatus checkDeclaringType(final IProgressMonitor monitor) throws JavaModelException { 591 try { 592 final IType type= getDeclaringType(); 593 if (type.isEnum()) 594 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_enum_members); 595 if (type.isAnnotation()) 596 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_annotation_members); 597 if (type.isInterface()) 598 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_interface_members); 599 if (type.isBinary()) 600 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_members_of_binary); 601 if (type.isReadOnly()) 602 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_members_of_read_only); 603 return new RefactoringStatus(); 604 } finally { 605 if (monitor != null) 606 monitor.done(); 607 } 608 } 609 checkIfMembersExist()610 protected RefactoringStatus checkIfMembersExist() { 611 final RefactoringStatus result= new RefactoringStatus(); 612 for (IMember member : fMembersToMove) { 613 if (member == null || !member.exists()) 614 result.addFatalError(RefactoringCoreMessages.HierarchyRefactoring_does_not_exist); 615 } 616 return result; 617 } 618 clearCaches()619 protected void clearCaches() { 620 fCachedReferencedTypes= null; 621 } 622 copyParameters(final ASTRewrite rewrite, final ICompilationUnit unit, final MethodDeclaration oldMethod, final MethodDeclaration newMethod, final TypeVariableMaplet[] mapping)623 protected void copyParameters(final ASTRewrite rewrite, final ICompilationUnit unit, final MethodDeclaration oldMethod, final MethodDeclaration newMethod, final TypeVariableMaplet[] mapping) throws JavaModelException { 624 SingleVariableDeclaration newDeclaration= null; 625 for (Object parameter : oldMethod.parameters()) { 626 final SingleVariableDeclaration oldDeclaration= (SingleVariableDeclaration) parameter; 627 if (mapping.length > 0) 628 newDeclaration= createPlaceholderForSingleVariableDeclaration(oldDeclaration, unit, mapping, rewrite); 629 else 630 newDeclaration= createPlaceholderForSingleVariableDeclaration(oldDeclaration, unit, rewrite); 631 newMethod.parameters().add(newDeclaration); 632 } 633 } 634 copyReturnType(final ASTRewrite rewrite, final ICompilationUnit unit, final MethodDeclaration oldMethod, final MethodDeclaration newMethod, final TypeVariableMaplet[] mapping)635 protected void copyReturnType(final ASTRewrite rewrite, final ICompilationUnit unit, final MethodDeclaration oldMethod, final MethodDeclaration newMethod, final TypeVariableMaplet[] mapping) throws JavaModelException { 636 Type newReturnType= null; 637 if (mapping.length > 0) 638 newReturnType= createPlaceholderForType(oldMethod.getReturnType2(), unit, mapping, rewrite); 639 else 640 newReturnType= createPlaceholderForType(oldMethod.getReturnType2(), unit, rewrite); 641 newMethod.setReturnType2(newReturnType); 642 } 643 644 @Override createContraintSolver(final SuperTypeConstraintsModel model)645 protected SuperTypeConstraintsSolver createContraintSolver(final SuperTypeConstraintsModel model) { 646 return new SuperTypeConstraintsSolver(model); 647 } 648 getDeclaringType()649 public IType getDeclaringType() { 650 if (fCachedDeclaringType != null) 651 return fCachedDeclaringType; 652 fCachedDeclaringType= RefactoringAvailabilityTester.getTopLevelType(fMembersToMove); 653 if (fCachedDeclaringType == null) 654 fCachedDeclaringType= fMembersToMove[0].getDeclaringType(); 655 return fCachedDeclaringType; 656 } 657 getMembersToMove()658 public IMember[] getMembersToMove() { 659 return fMembersToMove; 660 } 661 getTypesReferencedInMovedMembers(final IProgressMonitor monitor)662 protected IType[] getTypesReferencedInMovedMembers(final IProgressMonitor monitor) throws JavaModelException { 663 if (fCachedReferencedTypes == null) { 664 final IType[] types= ReferenceFinderUtil.getTypesReferencedIn(fMembersToMove, fOwner, monitor); 665 final List<IType> result= new ArrayList<>(types.length); 666 final List<IMember> members= Arrays.asList(fMembersToMove); 667 for (IType type : types) { 668 if (!members.contains(type) && !type.equals(getDeclaringType())) { 669 result.add(type); 670 } 671 } 672 fCachedReferencedTypes= new IType[result.size()]; 673 result.toArray(fCachedReferencedTypes); 674 } 675 return fCachedReferencedTypes; 676 } 677 hasNonMovedReferences(final IMember member, final IProgressMonitor monitor, final RefactoringStatus status)678 protected boolean hasNonMovedReferences(final IMember member, final IProgressMonitor monitor, final RefactoringStatus status) throws JavaModelException { 679 if (!fCachedMembersReferences.containsKey(member)) { 680 final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(member, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE)); 681 engine.setFiltering(true, true); 682 engine.setStatus(status); 683 engine.setOwner(fOwner); 684 engine.setScope(RefactoringScopeFactory.create(member)); 685 engine.searchPattern(new SubProgressMonitor(monitor, 1)); 686 fCachedMembersReferences.put(member, engine.getResults()); 687 } 688 final SearchResultGroup[] groups= (SearchResultGroup[]) fCachedMembersReferences.get(member); 689 if (groups.length == 0) 690 return false; 691 else if (groups.length > 1) 692 return true; 693 final ICompilationUnit unit= groups[0].getCompilationUnit(); 694 if (!getDeclaringType().getCompilationUnit().equals(unit)) 695 return true; 696 for (SearchMatch match : groups[0].getSearchResults()) { 697 if (!isMovedReference(match)) { 698 return true; 699 } 700 } 701 return false; 702 } 703 isMovedReference(final SearchMatch match)704 protected boolean isMovedReference(final SearchMatch match) throws JavaModelException { 705 for (IMember m : fMembersToMove) { 706 ISourceRange range= m.getSourceRange(); 707 if (range.getOffset() <= match.getOffset() && range.getOffset() + range.getLength() >= match.getOffset()) 708 return true; 709 } 710 return false; 711 } 712 713 @Override loadParticipants(final RefactoringStatus status, final SharableParticipants sharedParticipants)714 public RefactoringParticipant[] loadParticipants(final RefactoringStatus status, final SharableParticipants sharedParticipants) throws CoreException { 715 return new RefactoringParticipant[0]; 716 } 717 needsVisibilityAdjustment(final IMember member, final boolean references, final IProgressMonitor monitor, final RefactoringStatus status)718 protected boolean needsVisibilityAdjustment(final IMember member, final boolean references, final IProgressMonitor monitor, final RefactoringStatus status) throws JavaModelException { 719 if (JdtFlags.isPublic(member) || JdtFlags.isProtected(member)) 720 return false; 721 if (!references) 722 return true; 723 return hasNonMovedReferences(member, monitor, status); 724 } 725 } 726