| /******************************************************************************* |
| * Copyright (c) 2000, 2011 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.corext.refactoring.structure; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| |
| import org.eclipse.text.edits.TextEdit; |
| import org.eclipse.text.edits.TextEditGroup; |
| |
| import org.eclipse.ltk.core.refactoring.Change; |
| import org.eclipse.ltk.core.refactoring.IRefactoringStatusEntryComparator; |
| import org.eclipse.ltk.core.refactoring.Refactoring; |
| import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry; |
| import org.eclipse.ltk.core.refactoring.TextChange; |
| |
| import org.eclipse.jdt.core.Flags; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IField; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.ITypeParameter; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.dom.AST; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.ASTParser; |
| import org.eclipse.jdt.core.dom.ASTVisitor; |
| import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; |
| import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; |
| import org.eclipse.jdt.core.dom.Assignment; |
| import org.eclipse.jdt.core.dom.Block; |
| import org.eclipse.jdt.core.dom.BodyDeclaration; |
| import org.eclipse.jdt.core.dom.ClassInstanceCreation; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.ConstructorInvocation; |
| import org.eclipse.jdt.core.dom.EnumDeclaration; |
| import org.eclipse.jdt.core.dom.Expression; |
| import org.eclipse.jdt.core.dom.FieldAccess; |
| import org.eclipse.jdt.core.dom.FieldDeclaration; |
| import org.eclipse.jdt.core.dom.IBinding; |
| import org.eclipse.jdt.core.dom.IMethodBinding; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jdt.core.dom.IVariableBinding; |
| import org.eclipse.jdt.core.dom.ImportDeclaration; |
| import org.eclipse.jdt.core.dom.Javadoc; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| import org.eclipse.jdt.core.dom.MethodInvocation; |
| import org.eclipse.jdt.core.dom.Modifier; |
| import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.ParameterizedType; |
| import org.eclipse.jdt.core.dom.QualifiedName; |
| import org.eclipse.jdt.core.dom.QualifiedType; |
| import org.eclipse.jdt.core.dom.SimpleName; |
| import org.eclipse.jdt.core.dom.SimpleType; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.Statement; |
| import org.eclipse.jdt.core.dom.SuperConstructorInvocation; |
| import org.eclipse.jdt.core.dom.ThisExpression; |
| import org.eclipse.jdt.core.dom.Type; |
| import org.eclipse.jdt.core.dom.TypeDeclaration; |
| import org.eclipse.jdt.core.dom.TypeDeclarationStatement; |
| import org.eclipse.jdt.core.dom.TypeParameter; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; |
| import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; |
| import org.eclipse.jdt.core.dom.rewrite.ListRewrite; |
| import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer; |
| import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer.SourceRange; |
| import org.eclipse.jdt.core.refactoring.CompilationUnitChange; |
| import org.eclipse.jdt.core.refactoring.IJavaRefactorings; |
| import org.eclipse.jdt.core.refactoring.descriptors.ConvertMemberTypeDescriptor; |
| import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor; |
| import org.eclipse.jdt.core.search.IJavaSearchConstants; |
| import org.eclipse.jdt.core.search.SearchMatch; |
| import org.eclipse.jdt.core.search.SearchPattern; |
| |
| import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory; |
| import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings; |
| import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; |
| import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; |
| import org.eclipse.jdt.internal.corext.dom.ASTNodes; |
| import org.eclipse.jdt.internal.corext.dom.Bindings; |
| import org.eclipse.jdt.internal.corext.dom.ModifierRewrite; |
| import org.eclipse.jdt.internal.corext.refactoring.Checks; |
| import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment; |
| import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments; |
| import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2; |
| import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; |
| import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.CreateCompilationUnitChange; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange; |
| import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.OutgoingMemberVisibilityAdjustment; |
| import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil; |
| import org.eclipse.jdt.internal.corext.refactoring.util.JavadocUtil; |
| import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; |
| import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil; |
| import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager; |
| import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
| import org.eclipse.jdt.internal.corext.util.JdtFlags; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| import org.eclipse.jdt.internal.corext.util.SearchUtils; |
| import org.eclipse.jdt.internal.corext.util.Strings; |
| |
| import org.eclipse.jdt.ui.CodeGeneration; |
| import org.eclipse.jdt.ui.JavaElementLabels; |
| |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider; |
| import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings; |
| import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels; |
| import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; |
| |
| |
| public final class MoveInnerToTopRefactoring extends Refactoring { |
| |
| private static final String ATTRIBUTE_FIELD= "field"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_MANDATORY= "mandatory"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_POSSIBLE= "possible"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_FINAL= "final"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_FIELD_NAME= "fieldName"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_PARAMETER_NAME= "parameterName"; //$NON-NLS-1$ |
| |
| private static class MemberAccessNodeCollector extends ASTVisitor { |
| |
| private final ITypeBinding fCurrentType; |
| |
| private final List<MethodInvocation> fMethodAccesses= new ArrayList<MethodInvocation>(0); |
| |
| private final List<Name> fSimpleNames= new ArrayList<Name>(0); |
| |
| MemberAccessNodeCollector(ITypeBinding currType) { |
| Assert.isNotNull(currType); |
| fCurrentType= currType; |
| } |
| |
| MethodInvocation[] getMethodInvocations() { |
| return fMethodAccesses.toArray(new MethodInvocation[fMethodAccesses.size()]); |
| } |
| |
| SimpleName[] getSimpleFieldNames() { |
| return fSimpleNames.toArray(new SimpleName[fSimpleNames.size()]); |
| } |
| |
| @Override |
| public boolean visit(FieldAccess node) { |
| // field accesses always have an expression: look at the expression to find out if we do an outer instance access. |
| node.getExpression().accept(this); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(MethodInvocation node) { |
| Expression expression= node.getExpression(); |
| if (expression == null) { |
| IMethodBinding binding= node.resolveMethodBinding(); |
| if (binding != null) { |
| if (isAccessToOuter(binding.getDeclaringClass())) { |
| fMethodAccesses.add(node); |
| } |
| } |
| } else { |
| expression.accept(this); |
| } |
| List<Expression> arguments= node.arguments(); |
| for (int i= 0; i < arguments.size(); i++) { |
| arguments.get(i).accept(this); |
| } |
| return false; |
| } |
| @Override |
| public boolean visit(QualifiedName node) { |
| node.getQualifier().accept(this); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SimpleName node) { |
| IBinding binding= node.resolveBinding(); |
| if (binding instanceof IVariableBinding) { |
| IVariableBinding variableBinding= (IVariableBinding) binding; |
| if (variableBinding.isField()) { |
| if (isAccessToOuter(variableBinding.getDeclaringClass())) { |
| fSimpleNames.add(node); |
| } |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ThisExpression node) { |
| final Name qualifier= node.getQualifier(); |
| if (qualifier != null) { |
| final ITypeBinding binding= qualifier.resolveTypeBinding(); |
| if (binding != null && binding != fCurrentType.getTypeDeclaration()) { |
| fSimpleNames.add(qualifier); |
| } |
| } |
| return super.visit(node); |
| } |
| |
| private boolean isAccessToOuter(ITypeBinding binding) { |
| binding= binding.getTypeDeclaration(); |
| if (Bindings.isSuperType(binding, fCurrentType, false)) { |
| return false; |
| } |
| ITypeBinding outer= fCurrentType.getDeclaringClass(); |
| while (outer != null) { |
| if (Bindings.isSuperType(binding, outer, false)) { |
| return true; |
| } |
| outer= outer.getDeclaringClass(); |
| } |
| return false; |
| } |
| |
| |
| } |
| |
| private class TypeReferenceQualifier extends ASTVisitor { |
| |
| private final TextEditGroup fGroup; |
| |
| private final ITypeBinding fTypeBinding; |
| |
| public TypeReferenceQualifier(final ITypeBinding type, final TextEditGroup group) { |
| Assert.isNotNull(type); |
| Assert.isNotNull(type.getDeclaringClass()); |
| fTypeBinding= type; |
| fGroup= group; |
| } |
| |
| @Override |
| public boolean visit(final ClassInstanceCreation node) { |
| Assert.isNotNull(node); |
| if (fCreateInstanceField) { |
| final AST ast= node.getAST(); |
| final Type type= node.getType(); |
| final ITypeBinding binding= type.resolveBinding(); |
| if (binding != null && binding.getDeclaringClass() != null && !Bindings.equals(binding, fTypeBinding) && fSourceRewrite.getRoot().findDeclaringNode(binding) != null) { |
| if (!Modifier.isStatic(binding.getModifiers())) { |
| Expression expression= null; |
| if (fCodeGenerationSettings.useKeywordThis || fEnclosingInstanceFieldName.equals(fNameForEnclosingInstanceConstructorParameter)) { |
| final FieldAccess access= ast.newFieldAccess(); |
| access.setExpression(ast.newThisExpression()); |
| access.setName(ast.newSimpleName(fEnclosingInstanceFieldName)); |
| expression= access; |
| } else |
| expression= ast.newSimpleName(fEnclosingInstanceFieldName); |
| if (node.getExpression() != null) |
| fSourceRewrite.getImportRemover().registerRemovedNode(node.getExpression()); |
| fSourceRewrite.getASTRewrite().set(node, ClassInstanceCreation.EXPRESSION_PROPERTY, expression, fGroup); |
| } else |
| addTypeQualification(type, fSourceRewrite, fGroup); |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(final QualifiedType node) { |
| Assert.isNotNull(node); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(final SimpleType node) { |
| Assert.isNotNull(node); |
| if (!(node.getParent() instanceof ClassInstanceCreation)) { |
| final ITypeBinding binding= node.resolveBinding(); |
| if (binding != null) { |
| final ITypeBinding declaring= binding.getDeclaringClass(); |
| if (declaring != null && !Bindings.equals(declaring, fTypeBinding.getDeclaringClass()) && !Bindings.equals(binding, fTypeBinding) && fSourceRewrite.getRoot().findDeclaringNode(binding) != null && Modifier.isStatic(binding.getModifiers())) |
| addTypeQualification(node, fSourceRewrite, fGroup); |
| } |
| } |
| return super.visit(node); |
| } |
| |
| @Override |
| public boolean visit(final ThisExpression node) { |
| Assert.isNotNull(node); |
| final Name name= node.getQualifier(); |
| if (name != null && name.isSimpleName()) { |
| final AST ast= node.getAST(); |
| Expression expression= null; |
| if (fCodeGenerationSettings.useKeywordThis || fEnclosingInstanceFieldName.equals(fNameForEnclosingInstanceConstructorParameter)) { |
| final FieldAccess access= ast.newFieldAccess(); |
| access.setExpression(ast.newThisExpression()); |
| access.setName(ast.newSimpleName(fEnclosingInstanceFieldName)); |
| expression= access; |
| } else |
| expression= ast.newSimpleName(fEnclosingInstanceFieldName); |
| fSourceRewrite.getASTRewrite().replace(node, expression, null); |
| } |
| return super.visit(node); |
| } |
| } |
| |
| private static void addTypeParameters(final CompilationUnit unit, final IType type, final Map<String, ITypeBinding> map) throws JavaModelException { |
| Assert.isNotNull(unit); |
| Assert.isNotNull(type); |
| Assert.isNotNull(map); |
| final AbstractTypeDeclaration declaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(type, unit); |
| if (declaration instanceof TypeDeclaration) { |
| ITypeBinding binding= null; |
| TypeParameter parameter= null; |
| for (final Iterator<TypeParameter> iterator= ((TypeDeclaration) declaration).typeParameters().iterator(); iterator.hasNext();) { |
| parameter= iterator.next(); |
| binding= parameter.resolveBinding(); |
| if (binding != null && !map.containsKey(binding.getKey())) |
| map.put(binding.getKey(), binding); |
| } |
| final IType declaring= type.getDeclaringType(); |
| if (declaring != null && !Flags.isStatic(type.getFlags())) |
| addTypeParameters(unit, declaring, map); |
| } |
| } |
| |
| private static boolean containsNonStatic(MethodInvocation[] invocations) { |
| for (int i= 0; i < invocations.length; i++) { |
| if (!isStatic(invocations[i])) |
| return true; |
| } |
| return false; |
| } |
| |
| private static boolean containsNonStatic(SimpleName[] fieldNames) { |
| for (int i= 0; i < fieldNames.length; i++) { |
| if (!isStaticFieldName(fieldNames[i])) |
| return true; |
| } |
| return false; |
| } |
| |
| private static boolean containsStatusEntry(final RefactoringStatus status, final RefactoringStatusEntry other) { |
| return status.getEntries(new IRefactoringStatusEntryComparator() { |
| |
| public final int compare(final RefactoringStatusEntry entry1, final RefactoringStatusEntry entry2) { |
| return entry1.getMessage().compareTo(entry2.getMessage()); |
| } |
| }, other).length > 0; |
| } |
| |
| private static AbstractTypeDeclaration findTypeDeclaration(IType enclosing, AbstractTypeDeclaration[] declarations) { |
| String typeName= enclosing.getElementName(); |
| for (int i= 0; i < declarations.length; i++) { |
| AbstractTypeDeclaration declaration= declarations[i]; |
| if (declaration.getName().getIdentifier().equals(typeName)) |
| return declaration; |
| } |
| return null; |
| } |
| |
| private static AbstractTypeDeclaration findTypeDeclaration(IType type, CompilationUnit unit) { |
| final List<IType> types= getDeclaringTypes(type); |
| types.add(type); |
| AbstractTypeDeclaration[] declarations= (AbstractTypeDeclaration[]) unit.types().toArray(new AbstractTypeDeclaration[unit.types().size()]); |
| AbstractTypeDeclaration declaration= null; |
| for (final Iterator<IType> iterator= types.iterator(); iterator.hasNext();) { |
| IType enclosing= iterator.next(); |
| declaration= findTypeDeclaration(enclosing, declarations); |
| Assert.isNotNull(declaration); |
| declarations= getAbstractTypeDeclarations(declaration); |
| } |
| Assert.isNotNull(declaration); |
| return declaration; |
| } |
| |
| public static AbstractTypeDeclaration[] getAbstractTypeDeclarations(final AbstractTypeDeclaration declaration) { |
| int typeCount= 0; |
| for (Iterator<BodyDeclaration> iterator= declaration.bodyDeclarations().listIterator(); iterator.hasNext();) { |
| if (iterator.next() instanceof AbstractTypeDeclaration) { |
| typeCount++; |
| } |
| } |
| AbstractTypeDeclaration[] declarations= new AbstractTypeDeclaration[typeCount]; |
| int next= 0; |
| for (final Iterator<BodyDeclaration> iterator= declaration.bodyDeclarations().listIterator(); iterator.hasNext();) { |
| BodyDeclaration object= iterator.next(); |
| if (object instanceof AbstractTypeDeclaration) { |
| declarations[next++]= (AbstractTypeDeclaration) object; |
| } |
| } |
| return declarations; |
| } |
| |
| private static List<IType> getDeclaringTypes(IType type) { |
| IType declaringType= type.getDeclaringType(); |
| if (declaringType == null) |
| return new ArrayList<IType>(0); |
| List<IType> result= getDeclaringTypes(declaringType); |
| result.add(declaringType); |
| return result; |
| } |
| |
| private static String[] getFieldNames(IType type) { |
| try { |
| IField[] fields= type.getFields(); |
| List<String> result= new ArrayList<String>(fields.length); |
| for (int i= 0; i < fields.length; i++) { |
| result.add(fields[i].getElementName()); |
| } |
| return result.toArray(new String[result.size()]); |
| } catch (JavaModelException e) { |
| return null; |
| } |
| } |
| |
| private static Set<ICompilationUnit> getMergedSet(Set<ICompilationUnit> s1, Set<ICompilationUnit> s2) { |
| Set<ICompilationUnit> result= new HashSet<ICompilationUnit>(); |
| result.addAll(s1); |
| result.addAll(s2); |
| return result; |
| } |
| |
| private static String[] getParameterNamesOfAllConstructors(IType type) throws JavaModelException { |
| IMethod[] constructors= JavaElementUtil.getAllConstructors(type); |
| Set<String> result= new HashSet<String>(); |
| for (int i= 0; i < constructors.length; i++) { |
| result.addAll(Arrays.asList(constructors[i].getParameterNames())); |
| } |
| return result.toArray(new String[result.size()]); |
| } |
| |
| private static ASTNode[] getReferenceNodesIn(CompilationUnit cuNode, Map<ICompilationUnit, SearchMatch[]> references, ICompilationUnit cu) { |
| SearchMatch[] results= references.get(cu); |
| if (results == null) |
| return new ASTNode[0]; |
| return ASTNodeSearchUtil.getAstNodes(results, cuNode); |
| } |
| |
| private static boolean isCorrespondingTypeBinding(ITypeBinding binding, IType type) { |
| if (binding == null) |
| return false; |
| return Bindings.getFullyQualifiedName(binding).equals(JavaElementUtil.createSignature(type)); |
| } |
| |
| private static boolean isStatic(MethodInvocation invocation) { |
| IMethodBinding methodBinding= invocation.resolveMethodBinding(); |
| if (methodBinding == null) |
| return false; |
| return JdtFlags.isStatic(methodBinding); |
| } |
| |
| private static boolean isStaticFieldName(SimpleName name) { |
| IBinding binding= name.resolveBinding(); |
| if (!(binding instanceof IVariableBinding)) |
| return false; |
| IVariableBinding variableBinding= (IVariableBinding) binding; |
| if (!variableBinding.isField()) |
| return false; |
| return JdtFlags.isStatic(variableBinding); |
| } |
| |
| private TextChangeManager fChangeManager; |
| |
| private CodeGenerationSettings fCodeGenerationSettings; |
| |
| private boolean fCreateInstanceField; |
| |
| private String fEnclosingInstanceFieldName; |
| |
| private boolean fIsInstanceFieldCreationMandatory; |
| |
| private boolean fIsInstanceFieldCreationPossible; |
| |
| private boolean fMarkInstanceFieldAsFinal; |
| |
| private String fNameForEnclosingInstanceConstructorParameter; |
| |
| private String fNewSourceOfInputType; |
| |
| private CompilationUnitRewrite fSourceRewrite; |
| |
| private Collection<IBinding> fStaticImports; |
| |
| private IType fType; |
| |
| private String fQualifiedTypeName; |
| |
| private Collection<ITypeBinding> fTypeImports; |
| |
| /** |
| * Creates a new move inner to top refactoring. |
| * @param type the type, or <code>null</code> if invoked by scripting |
| * @param settings the code generation settings, or <code>null</code> if invoked by scripting |
| * @throws JavaModelException if initialization failed |
| */ |
| public MoveInnerToTopRefactoring(IType type, CodeGenerationSettings settings) throws JavaModelException { |
| fType= type; |
| fCodeGenerationSettings= settings; |
| fMarkInstanceFieldAsFinal= true; // default |
| if (fType != null) |
| initialize(); |
| } |
| |
| public MoveInnerToTopRefactoring(JavaRefactoringArguments arguments, RefactoringStatus status) { |
| fType= null; |
| fCodeGenerationSettings= null; |
| fMarkInstanceFieldAsFinal= true; // default |
| RefactoringStatus initializeStatus= initialize(arguments); |
| status.merge(initializeStatus); |
| } |
| |
| private void initialize() throws JavaModelException { |
| fQualifiedTypeName= JavaModelUtil.concatenateName(fType.getPackageFragment().getElementName(), fType.getElementName()); |
| fEnclosingInstanceFieldName= getInitialNameForEnclosingInstanceField(); |
| fSourceRewrite= new CompilationUnitRewrite(fType.getCompilationUnit()); |
| fIsInstanceFieldCreationPossible= !(JdtFlags.isStatic(fType) || fType.isAnnotation() || fType.isEnum() || (fType.getDeclaringType() == null && !JavaElementUtil.isMainType(fType))); |
| fIsInstanceFieldCreationMandatory= fIsInstanceFieldCreationPossible && isInstanceFieldCreationMandatory(); |
| fCreateInstanceField= fIsInstanceFieldCreationMandatory; |
| } |
| |
| private void addEnclosingInstanceDeclaration(final AbstractTypeDeclaration declaration, final ASTRewrite rewrite) throws CoreException { |
| Assert.isNotNull(declaration); |
| Assert.isNotNull(rewrite); |
| final AST ast= declaration.getAST(); |
| final VariableDeclarationFragment fragment= ast.newVariableDeclarationFragment(); |
| fragment.setName(ast.newSimpleName(fEnclosingInstanceFieldName)); |
| final FieldDeclaration newField= ast.newFieldDeclaration(fragment); |
| newField.modifiers().addAll(ASTNodeFactory.newModifiers(ast, getEnclosingInstanceAccessModifiers())); |
| newField.setType(createEnclosingType(ast)); |
| final String comment= CodeGeneration.getFieldComment(fType.getCompilationUnit(), declaration.getName().getIdentifier(), fEnclosingInstanceFieldName, StubUtility.getLineDelimiterUsed(fType.getJavaProject())); |
| if (comment != null && comment.length() > 0) { |
| final Javadoc doc= (Javadoc) rewrite.createStringPlaceholder(comment, ASTNode.JAVADOC); |
| newField.setJavadoc(doc); |
| } |
| rewrite.getListRewrite(declaration, declaration.getBodyDeclarationsProperty()).insertFirst(newField, null); |
| } |
| |
| private void addEnclosingInstanceTypeParameters(final ITypeBinding[] parameters, final AbstractTypeDeclaration declaration, final ASTRewrite rewrite) { |
| Assert.isNotNull(parameters); |
| Assert.isNotNull(declaration); |
| Assert.isNotNull(rewrite); |
| if (declaration instanceof TypeDeclaration) { |
| final TypeDeclaration type= (TypeDeclaration) declaration; |
| final List<TypeParameter> existing= type.typeParameters(); |
| final Set<String> names= new HashSet<String>(); |
| TypeParameter parameter= null; |
| for (final Iterator<TypeParameter> iterator= existing.iterator(); iterator.hasNext();) { |
| parameter= iterator.next(); |
| names.add(parameter.getName().getIdentifier()); |
| } |
| final ListRewrite rewriter= rewrite.getListRewrite(type, TypeDeclaration.TYPE_PARAMETERS_PROPERTY); |
| String name= null; |
| for (int index= 0; index < parameters.length; index++) { |
| name= parameters[index].getName(); |
| if (!names.contains(name)) { |
| parameter= type.getAST().newTypeParameter(); |
| parameter.setName(type.getAST().newSimpleName(name)); |
| rewriter.insertLast(parameter, null); |
| } |
| } |
| } |
| } |
| |
| private void addImportsToTargetUnit(final ICompilationUnit targetUnit, final IProgressMonitor monitor) throws CoreException, JavaModelException { |
| monitor.beginTask("", 2); //$NON-NLS-1$ |
| try { |
| ImportRewrite rewrite= StubUtility.createImportRewrite(targetUnit, true); |
| if (fTypeImports != null) { |
| ITypeBinding type= null; |
| for (final Iterator<ITypeBinding> iterator= fTypeImports.iterator(); iterator.hasNext();) { |
| type= iterator.next(); |
| rewrite.addImport(type); |
| } |
| } |
| if (fStaticImports != null) { |
| IBinding binding= null; |
| for (final Iterator<IBinding> iterator= fStaticImports.iterator(); iterator.hasNext();) { |
| binding= iterator.next(); |
| rewrite.addStaticImport(binding); |
| } |
| } |
| fTypeImports= null; |
| fStaticImports= null; |
| TextEdit edits= rewrite.rewriteImports(new SubProgressMonitor(monitor, 1)); |
| JavaModelUtil.applyEdit(targetUnit, edits, false, new SubProgressMonitor(monitor, 1)); |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| private void addInheritedTypeQualifications(final AbstractTypeDeclaration declaration, final CompilationUnitRewrite targetRewrite, final TextEditGroup group) { |
| Assert.isNotNull(declaration); |
| Assert.isNotNull(targetRewrite); |
| final CompilationUnit unit= (CompilationUnit) declaration.getRoot(); |
| final ITypeBinding binding= declaration.resolveBinding(); |
| if (binding != null) { |
| Type type= null; |
| if (declaration instanceof TypeDeclaration) { |
| type= ((TypeDeclaration) declaration).getSuperclassType(); |
| if (type != null && unit.findDeclaringNode(binding) != null) |
| addTypeQualification(type, targetRewrite, group); |
| } |
| List<Type> types= null; |
| if (declaration instanceof TypeDeclaration) |
| types= ((TypeDeclaration) declaration).superInterfaceTypes(); |
| else if (declaration instanceof EnumDeclaration) |
| types= ((EnumDeclaration) declaration).superInterfaceTypes(); |
| if (types != null) { |
| for (final Iterator<Type> iterator= types.iterator(); iterator.hasNext();) { |
| type= iterator.next(); |
| if (unit.findDeclaringNode(type.resolveBinding()) != null) |
| addTypeQualification(type, targetRewrite, group); |
| } |
| } |
| } |
| } |
| |
| private void addParameterToConstructor(final ASTRewrite rewrite, final MethodDeclaration declaration) throws JavaModelException { |
| Assert.isNotNull(rewrite); |
| Assert.isNotNull(declaration); |
| final AST ast= declaration.getAST(); |
| final String name= getNameForEnclosingInstanceConstructorParameter(); |
| final SingleVariableDeclaration variable= ast.newSingleVariableDeclaration(); |
| variable.setType(createEnclosingType(ast)); |
| variable.setName(ast.newSimpleName(name)); |
| rewrite.getListRewrite(declaration, MethodDeclaration.PARAMETERS_PROPERTY).insertFirst(variable, null); |
| JavadocUtil.addParamJavadoc(name, declaration, rewrite, fType.getJavaProject(), null); |
| } |
| |
| private void addSimpleTypeQualification(final CompilationUnitRewrite targetRewrite, final ITypeBinding declaring, final SimpleType simpleType, final TextEditGroup group) { |
| Assert.isNotNull(targetRewrite); |
| Assert.isNotNull(declaring); |
| Assert.isNotNull(simpleType); |
| final AST ast= targetRewrite.getRoot().getAST(); |
| if (!(simpleType.getName() instanceof QualifiedName)) { |
| targetRewrite.getASTRewrite().replace(simpleType, ast.newQualifiedType(targetRewrite.getImportRewrite().addImport(declaring, ast), ast.newSimpleName(simpleType.getName().getFullyQualifiedName())), group); |
| targetRewrite.getImportRemover().registerRemovedNode(simpleType); |
| } |
| } |
| |
| private void addTypeQualification(final Type type, final CompilationUnitRewrite targetRewrite, final TextEditGroup group) { |
| Assert.isNotNull(type); |
| Assert.isNotNull(targetRewrite); |
| final ITypeBinding binding= type.resolveBinding(); |
| if (binding != null) { |
| final ITypeBinding declaring= binding.getDeclaringClass(); |
| if (declaring != null) { |
| if (type instanceof SimpleType) { |
| final SimpleType simpleType= (SimpleType) type; |
| addSimpleTypeQualification(targetRewrite, declaring, simpleType, group); |
| } else if (type instanceof ParameterizedType) { |
| final ParameterizedType parameterizedType= (ParameterizedType) type; |
| final Type rawType= parameterizedType.getType(); |
| if (rawType instanceof SimpleType) |
| addSimpleTypeQualification(targetRewrite, declaring, (SimpleType) rawType, group); |
| } |
| } |
| } |
| } |
| |
| private RefactoringStatus checkConstructorParameterNames() { |
| RefactoringStatus result= new RefactoringStatus(); |
| CompilationUnit cuNode= new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL).parse(fType.getCompilationUnit(), false); |
| MethodDeclaration[] nodes= getConstructorDeclarationNodes(findTypeDeclaration(fType, cuNode)); |
| for (int i= 0; i < nodes.length; i++) { |
| MethodDeclaration constructor= nodes[i]; |
| for (Iterator<SingleVariableDeclaration> iter= constructor.parameters().iterator(); iter.hasNext();) { |
| SingleVariableDeclaration param= iter.next(); |
| if (fEnclosingInstanceFieldName.equals(param.getName().getIdentifier())) { |
| String[] keys= new String[] { BasicElementLabels.getJavaElementName(param.getName().getIdentifier()), BasicElementLabels.getJavaElementName(fType.getElementName())}; |
| String msg= Messages.format(RefactoringCoreMessages.MoveInnerToTopRefactoring_name_used, keys); |
| result.addError(msg, JavaStatusContext.create(fType.getCompilationUnit(), param)); |
| } |
| } |
| } |
| return result; |
| } |
| |
| public RefactoringStatus checkEnclosingInstanceName(String name) { |
| if (!fCreateInstanceField) |
| return new RefactoringStatus(); |
| RefactoringStatus result= Checks.checkFieldName(name, fType); |
| if (!Checks.startsWithLowerCase(name)) |
| result.addWarning(RefactoringCoreMessages.MoveInnerToTopRefactoring_names_start_lowercase); |
| |
| if (fType.getField(name).exists()) { |
| Object[] keys= new String[] { BasicElementLabels.getJavaElementName(name), BasicElementLabels.getJavaElementName(fType.getElementName())}; |
| String msg= Messages.format(RefactoringCoreMessages.MoveInnerToTopRefactoring_already_declared, keys); |
| result.addError(msg, JavaStatusContext.create(fType.getField(name))); |
| } |
| return result; |
| } |
| |
| @Override |
| public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException { |
| pm.beginTask("", 2);//$NON-NLS-1$ |
| try { |
| RefactoringStatus result= new RefactoringStatus(); |
| |
| if (JdtFlags.isStatic(fType)) |
| result.merge(checkEnclosingInstanceName(fEnclosingInstanceFieldName)); |
| |
| String newCUName= JavaModelUtil.getRenamedCUName(fType.getCompilationUnit(), fType.getElementName()); |
| if (fType.getPackageFragment().getCompilationUnit(newCUName).exists()) { |
| String message= Messages.format(RefactoringCoreMessages.MoveInnerToTopRefactoring_compilation_Unit_exists, new String[] { BasicElementLabels.getResourceName(newCUName), JavaElementLabels.getElementLabel(fType.getPackageFragment(), JavaElementLabels.ALL_DEFAULT)}); |
| result.addFatalError(message); |
| } |
| result.merge(checkEnclosingInstanceName(fEnclosingInstanceFieldName)); |
| result.merge(Checks.checkCompilationUnitName(newCUName, fType)); |
| result.merge(checkConstructorParameterNames()); |
| result.merge(checkTypeNameInPackage()); |
| fChangeManager= createChangeManager(new SubProgressMonitor(pm, 1), result); |
| result.merge(Checks.validateModifiesFiles(ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits()), getValidationContext())); |
| return result; |
| } finally { |
| pm.done(); |
| } |
| } |
| |
| @Override |
| public RefactoringStatus checkInitialConditions(IProgressMonitor monitor) throws CoreException { |
| return Checks.checkIfCuBroken(fType); |
| } |
| |
| private RefactoringStatus checkTypeNameInPackage() throws JavaModelException { |
| IType type= Checks.findTypeInPackage(fType.getPackageFragment(), fType.getElementName()); |
| if (type == null || !type.exists() || fType.equals(type)) { |
| return null; |
| } |
| String message= Messages.format(RefactoringCoreMessages.MoveInnerToTopRefactoring_type_exists, new String[] { BasicElementLabels.getJavaElementName(fType.getElementName()), JavaElementLabels.getElementLabel(fType.getPackageFragment(), JavaElementLabels.ALL_DEFAULT)}); |
| return RefactoringStatus.createErrorStatus(message); |
| } |
| |
| private Expression createAccessExpressionToEnclosingInstanceFieldText(ASTNode node, IBinding binding, AbstractTypeDeclaration declaration) { |
| if (Modifier.isStatic(binding.getModifiers())) |
| return node.getAST().newName(fType.getDeclaringType().getTypeQualifiedName('.')); |
| else if ((isInAnonymousTypeInsideInputType(node, declaration) || isInLocalTypeInsideInputType(node, declaration) || isInNonStaticMemberTypeInsideInputType(node, declaration))) |
| return createQualifiedReadAccessExpressionForEnclosingInstance(node.getAST()); |
| else |
| return createReadAccessExpressionForEnclosingInstance(node.getAST()); |
| } |
| |
| @Override |
| public Change createChange(final IProgressMonitor monitor) throws CoreException { |
| monitor.beginTask(RefactoringCoreMessages.MoveInnerToTopRefactoring_creating_change, 1); |
| final Map<String, String> arguments= new HashMap<String, String>(); |
| String project= null; |
| IJavaProject javaProject= fType.getJavaProject(); |
| if (javaProject != null) |
| project= javaProject.getElementName(); |
| final String description= Messages.format(RefactoringCoreMessages.MoveInnerToTopRefactoring_descriptor_description_short, BasicElementLabels.getJavaElementName(fType.getElementName())); |
| final String header= Messages.format(RefactoringCoreMessages.MoveInnerToTopRefactoring_descriptor_description, new String[] { JavaElementLabels.getElementLabel(fType, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getElementLabel(fType.getParent(), JavaElementLabels.ALL_FULLY_QUALIFIED)}); |
| final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header); |
| comment.addSetting(Messages.format(RefactoringCoreMessages.MoveInnerToTopRefactoring_original_pattern, JavaElementLabels.getElementLabel(fType, JavaElementLabels.ALL_FULLY_QUALIFIED))); |
| final boolean enclosing= fEnclosingInstanceFieldName != null && !"".equals(fEnclosingInstanceFieldName); //$NON-NLS-1$ |
| if (enclosing) |
| comment.addSetting(Messages.format(RefactoringCoreMessages.MoveInnerToTopRefactoring_field_pattern, BasicElementLabels.getJavaElementName(fEnclosingInstanceFieldName))); |
| if (fNameForEnclosingInstanceConstructorParameter != null && !"".equals(fNameForEnclosingInstanceConstructorParameter)) //$NON-NLS-1$ |
| comment.addSetting(Messages.format(RefactoringCoreMessages.MoveInnerToTopRefactoring_parameter_pattern, BasicElementLabels.getJavaElementName(fNameForEnclosingInstanceConstructorParameter))); |
| if (enclosing && fMarkInstanceFieldAsFinal) |
| comment.addSetting(RefactoringCoreMessages.MoveInnerToTopRefactoring_declare_final); |
| final ConvertMemberTypeDescriptor descriptor= RefactoringSignatureDescriptorFactory.createConvertMemberTypeDescriptor(project, description, comment.asString(), arguments, RefactoringDescriptor.MULTI_CHANGE | RefactoringDescriptor.STRUCTURAL_CHANGE | JavaRefactoringDescriptor.JAR_REFACTORING | JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT); |
| arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT, JavaRefactoringDescriptorUtil.elementToHandle(project, fType)); |
| if (enclosing) |
| arguments.put(ATTRIBUTE_FIELD_NAME, fEnclosingInstanceFieldName); |
| if (fNameForEnclosingInstanceConstructorParameter != null && !"".equals(fNameForEnclosingInstanceConstructorParameter)) //$NON-NLS-1$ |
| arguments.put(ATTRIBUTE_PARAMETER_NAME, fNameForEnclosingInstanceConstructorParameter); |
| arguments.put(ATTRIBUTE_FIELD, Boolean.valueOf(fCreateInstanceField).toString()); |
| arguments.put(ATTRIBUTE_FINAL, Boolean.valueOf(fMarkInstanceFieldAsFinal).toString()); |
| arguments.put(ATTRIBUTE_POSSIBLE, Boolean.valueOf(fIsInstanceFieldCreationPossible).toString()); |
| arguments.put(ATTRIBUTE_MANDATORY, Boolean.valueOf(fIsInstanceFieldCreationMandatory).toString()); |
| final DynamicValidationRefactoringChange result= new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.MoveInnerToTopRefactoring_move_to_Top); |
| result.addAll(fChangeManager.getAllChanges()); |
| result.add(createCompilationUnitForMovedType(new SubProgressMonitor(monitor, 1))); |
| return result; |
| } |
| |
| private TextChangeManager createChangeManager(final IProgressMonitor monitor, final RefactoringStatus status) throws CoreException { |
| Assert.isNotNull(monitor); |
| Assert.isNotNull(status); |
| final TextChangeManager manager= new TextChangeManager(); |
| try { |
| monitor.beginTask(RefactoringCoreMessages.MoveInnerToTopRefactoring_creating_preview, 4); |
| final Map<ICompilationUnit, CompilationUnitRewrite> rewrites= new HashMap<ICompilationUnit, CompilationUnitRewrite>(2); |
| fSourceRewrite.clearASTAndImportRewrites(); |
| rewrites.put(fSourceRewrite.getCu(), fSourceRewrite); |
| final MemberVisibilityAdjustor adjustor= new MemberVisibilityAdjustor(fType.getPackageFragment(), fType); |
| adjustor.setRewrites(rewrites); |
| adjustor.setVisibilitySeverity(RefactoringStatus.WARNING); |
| adjustor.setFailureSeverity(RefactoringStatus.WARNING); |
| adjustor.setStatus(status); |
| adjustor.adjustVisibility(new SubProgressMonitor(monitor, 1)); |
| final Map<String, ITypeBinding> parameters= new LinkedHashMap<String, ITypeBinding>(); |
| addTypeParameters(fSourceRewrite.getRoot(), fType, parameters); |
| final ITypeBinding[] bindings= new ITypeBinding[parameters.values().size()]; |
| parameters.values().toArray(bindings); |
| final Map<ICompilationUnit, SearchMatch[]> typeReferences= createTypeReferencesMapping(new SubProgressMonitor(monitor, 1), status); |
| Map<ICompilationUnit, SearchMatch[]> constructorReferences= null; |
| if (JdtFlags.isStatic(fType)) |
| constructorReferences= new HashMap<ICompilationUnit, SearchMatch[]>(0); |
| else |
| constructorReferences= createConstructorReferencesMapping(new SubProgressMonitor(monitor, 1), status); |
| if (fCreateInstanceField) { |
| // must increase visibility of all member types up |
| // to the top level type to allow this |
| IType type= fType; |
| ModifierKeyword keyword= null; |
| while ( (type= type.getDeclaringType()) != null) { |
| if ((!adjustor.getAdjustments().containsKey(type)) && (Modifier.isPrivate(type.getFlags()))) |
| adjustor.getAdjustments().put(type, new OutgoingMemberVisibilityAdjustment(type, keyword, RefactoringStatus.createWarningStatus(Messages.format(RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_type_warning, new String[] { MemberVisibilityAdjustor.getLabel(type), MemberVisibilityAdjustor.getLabel(keyword) }), JavaStatusContext.create(type.getCompilationUnit(), type.getSourceRange())))); |
| } |
| } |
| monitor.worked(1); |
| ICompilationUnit inputCU= fType.getCompilationUnit(); |
| for (final Iterator<ICompilationUnit> iterator= getMergedSet(typeReferences.keySet(), constructorReferences.keySet()).iterator(); iterator.hasNext();) { |
| final ICompilationUnit unit= iterator.next(); |
| final CompilationUnitRewrite targetRewrite= getCompilationUnitRewrite(unit); |
| createCompilationUnitRewrite(bindings, targetRewrite, typeReferences, constructorReferences, adjustor.getAdjustments().containsKey(fType), inputCU, unit, false, status, monitor); |
| if (unit.equals(inputCU)) { |
| try { |
| adjustor.setStatus(new RefactoringStatus()); |
| adjustor.rewriteVisibility(targetRewrite.getCu(), new SubProgressMonitor(monitor, 1)); |
| } finally { |
| adjustor.setStatus(status); |
| } |
| fNewSourceOfInputType= createNewSource(targetRewrite, unit); |
| targetRewrite.clearASTAndImportRewrites(); |
| createCompilationUnitRewrite(bindings, targetRewrite, typeReferences, constructorReferences, adjustor.getAdjustments().containsKey(fType), inputCU, unit, true, status, monitor); |
| } |
| adjustor.rewriteVisibility(targetRewrite.getCu(), new SubProgressMonitor(monitor, 1)); |
| manager.manage(unit, targetRewrite.createChange(true)); |
| } |
| if (fNewSourceOfInputType == null) { |
| fNewSourceOfInputType= createNewSource(fSourceRewrite, inputCU); |
| } |
| } finally { |
| monitor.done(); |
| } |
| return manager; |
| } |
| |
| private Change createCompilationUnitForMovedType(IProgressMonitor pm) throws CoreException { |
| ICompilationUnit newCuWC= null; |
| try { |
| newCuWC= fType.getPackageFragment().getCompilationUnit(JavaModelUtil.getRenamedCUName(fType.getCompilationUnit(), fType.getElementName())).getWorkingCopy(null); |
| String source= createSourceForNewCu(newCuWC, pm); |
| return new CreateCompilationUnitChange(fType.getPackageFragment().getCompilationUnit(JavaModelUtil.getRenamedCUName(fType.getCompilationUnit(), fType.getElementName())), source, null); |
| } finally { |
| if (newCuWC != null) |
| newCuWC.discardWorkingCopy(); |
| } |
| } |
| |
| private void createCompilationUnitRewrite(final ITypeBinding[] parameters, final CompilationUnitRewrite targetRewrite, final Map<ICompilationUnit, SearchMatch[]> typeReferences, final Map<ICompilationUnit, SearchMatch[]> constructorReferences, boolean visibilityWasAdjusted, final ICompilationUnit sourceUnit, final ICompilationUnit targetUnit, final boolean remove, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException { |
| Assert.isNotNull(parameters); |
| Assert.isNotNull(targetRewrite); |
| Assert.isNotNull(typeReferences); |
| Assert.isNotNull(constructorReferences); |
| Assert.isNotNull(sourceUnit); |
| Assert.isNotNull(targetUnit); |
| final CompilationUnit root= targetRewrite.getRoot(); |
| final ASTRewrite rewrite= targetRewrite.getASTRewrite(); |
| if (targetUnit.equals(sourceUnit)) { |
| final AbstractTypeDeclaration declaration= findTypeDeclaration(fType, root); |
| final TextEditGroup qualifierGroup= fSourceRewrite.createGroupDescription(RefactoringCoreMessages.MoveInnerToTopRefactoring_change_qualifier); |
| ITypeBinding binding= declaration.resolveBinding(); |
| if (!remove) { |
| if (!JdtFlags.isStatic(fType) && fCreateInstanceField) { |
| if (JavaElementUtil.getAllConstructors(fType).length == 0) |
| createConstructor(declaration, rewrite); |
| else |
| modifyConstructors(declaration, rewrite); |
| addInheritedTypeQualifications(declaration, targetRewrite, qualifierGroup); |
| addEnclosingInstanceDeclaration(declaration, rewrite); |
| } |
| fTypeImports= new HashSet<ITypeBinding>(); |
| fStaticImports= new HashSet<IBinding>(); |
| ImportRewriteUtil.collectImports(fType.getJavaProject(), declaration, fTypeImports, fStaticImports, false); |
| if (binding != null) |
| fTypeImports.remove(binding); |
| } |
| addEnclosingInstanceTypeParameters(parameters, declaration, rewrite); |
| modifyAccessToEnclosingInstance(targetRewrite, declaration, monitor); |
| if (binding != null) { |
| modifyInterfaceMemberModifiers(binding); |
| final ITypeBinding declaring= binding.getDeclaringClass(); |
| if (declaring != null) |
| declaration.accept(new TypeReferenceQualifier(binding, null)); |
| } |
| final TextEditGroup groupMove= targetRewrite.createGroupDescription(RefactoringCoreMessages.MoveInnerToTopRefactoring_change_label); |
| if (remove) { |
| rewrite.remove(declaration, groupMove); |
| targetRewrite.getImportRemover().registerRemovedNode(declaration); |
| } else { |
| // Bug 101017/96308: Rewrite the visibility of the element to be |
| // moved and add a warning. |
| |
| // Note that this cannot be done in the MemberVisibilityAdjustor, as the private and |
| // static flags must always be cleared when moving to new type. |
| int newFlags= JdtFlags.clearFlag(Modifier.STATIC, declaration.getModifiers()); |
| |
| if (!visibilityWasAdjusted) { |
| if (Modifier.isPrivate(declaration.getModifiers()) || Modifier.isProtected(declaration.getModifiers())) { |
| newFlags= JdtFlags.clearFlag(Modifier.PROTECTED | Modifier.PRIVATE, newFlags); |
| final RefactoringStatusEntry entry= new RefactoringStatusEntry(RefactoringStatus.WARNING, Messages.format(RefactoringCoreMessages.MoveInnerToTopRefactoring_change_visibility_type_warning, new String[] { BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED)}), JavaStatusContext.create(fSourceRewrite.getCu())); |
| if (!containsStatusEntry(status, entry)) |
| status.addEntry(entry); |
| } |
| } |
| |
| ModifierRewrite.create(rewrite, declaration).setModifiers(newFlags, groupMove); |
| } |
| } |
| ASTNode[] references= getReferenceNodesIn(root, typeReferences, targetUnit); |
| for (int index= 0; index < references.length; index++) |
| updateTypeReference(parameters, references[index], targetRewrite, targetUnit); |
| references= getReferenceNodesIn(root, constructorReferences, targetUnit); |
| for (int index= 0; index < references.length; index++) |
| updateConstructorReference(parameters, references[index], targetRewrite, targetUnit); |
| } |
| |
| private void createConstructor(final AbstractTypeDeclaration declaration, final ASTRewrite rewrite) throws CoreException { |
| Assert.isNotNull(declaration); |
| Assert.isNotNull(rewrite); |
| final AST ast= declaration.getAST(); |
| final MethodDeclaration constructor= ast.newMethodDeclaration(); |
| constructor.setConstructor(true); |
| constructor.setName(ast.newSimpleName(declaration.getName().getIdentifier())); |
| final String comment= CodeGeneration.getMethodComment(fType.getCompilationUnit(), fType.getElementName(), fType.getElementName(), getNewConstructorParameterNames(), new String[0], null, null, StubUtility.getLineDelimiterUsed(fType.getJavaProject())); |
| if (comment != null && comment.length() > 0) { |
| final Javadoc doc= (Javadoc) rewrite.createStringPlaceholder(comment, ASTNode.JAVADOC); |
| constructor.setJavadoc(doc); |
| } |
| if (fCreateInstanceField) { |
| final SingleVariableDeclaration variable= ast.newSingleVariableDeclaration(); |
| final String name= getNameForEnclosingInstanceConstructorParameter(); |
| variable.setName(ast.newSimpleName(name)); |
| variable.setType(createEnclosingType(ast)); |
| constructor.parameters().add(variable); |
| final Block body= ast.newBlock(); |
| final Assignment assignment= ast.newAssignment(); |
| if (fCodeGenerationSettings.useKeywordThis || fEnclosingInstanceFieldName.equals(fNameForEnclosingInstanceConstructorParameter)) { |
| final FieldAccess access= ast.newFieldAccess(); |
| access.setExpression(ast.newThisExpression()); |
| access.setName(ast.newSimpleName(fEnclosingInstanceFieldName)); |
| assignment.setLeftHandSide(access); |
| } else |
| assignment.setLeftHandSide(ast.newSimpleName(fEnclosingInstanceFieldName)); |
| assignment.setRightHandSide(ast.newSimpleName(name)); |
| final Statement statement= ast.newExpressionStatement(assignment); |
| body.statements().add(statement); |
| constructor.setBody(body); |
| } else |
| constructor.setBody(ast.newBlock()); |
| rewrite.getListRewrite(declaration, declaration.getBodyDeclarationsProperty()).insertFirst(constructor, null); |
| } |
| |
| // Map<ICompilationUnit, SearchMatch[]> |
| private Map<ICompilationUnit, SearchMatch[]> createConstructorReferencesMapping(IProgressMonitor pm, RefactoringStatus status) throws JavaModelException { |
| SearchResultGroup[] groups= ConstructorReferenceFinder.getConstructorReferences(fType, pm, status); |
| Map<ICompilationUnit, SearchMatch[]> result= new HashMap<ICompilationUnit, SearchMatch[]>(); |
| for (int i= 0; i < groups.length; i++) { |
| SearchResultGroup group= groups[i]; |
| ICompilationUnit cu= group.getCompilationUnit(); |
| if (cu == null) |
| continue; |
| result.put(cu, group.getSearchResults()); |
| } |
| return result; |
| } |
| |
| private Expression createEnclosingInstanceCreationString(final ASTNode node, final ICompilationUnit cu) throws JavaModelException { |
| Assert.isTrue((node instanceof ClassInstanceCreation) || (node instanceof SuperConstructorInvocation)); |
| Assert.isNotNull(cu); |
| Expression expression= null; |
| if (node instanceof ClassInstanceCreation) |
| expression= ((ClassInstanceCreation) node).getExpression(); |
| else |
| expression= ((SuperConstructorInvocation) node).getExpression(); |
| final AST ast= node.getAST(); |
| if (expression != null) |
| return expression; |
| else if (JdtFlags.isStatic(fType)) |
| return null; |
| else if (isInsideSubclassOfDeclaringType(node)) |
| return ast.newThisExpression(); |
| else if ((node.getStartPosition() >= fType.getSourceRange().getOffset() && ASTNodes.getExclusiveEnd(node) <= fType.getSourceRange().getOffset() + fType.getSourceRange().getLength())) { |
| if (fCodeGenerationSettings.useKeywordThis || fEnclosingInstanceFieldName.equals(fNameForEnclosingInstanceConstructorParameter)) { |
| final FieldAccess access= ast.newFieldAccess(); |
| access.setExpression(ast.newThisExpression()); |
| access.setName(ast.newSimpleName(fEnclosingInstanceFieldName)); |
| return access; |
| } else |
| return ast.newSimpleName(fEnclosingInstanceFieldName); |
| } else if (isInsideTypeNestedInDeclaringType(node)) { |
| final ThisExpression qualified= ast.newThisExpression(); |
| qualified.setQualifier(ast.newSimpleName(fType.getDeclaringType().getElementName())); |
| return qualified; |
| } |
| return null; |
| } |
| |
| private Type createEnclosingType(final AST ast) throws JavaModelException { |
| Assert.isNotNull(ast); |
| final ITypeParameter[] parameters= fType.getDeclaringType().getTypeParameters(); |
| final Type type= ASTNodeFactory.newType(ast, fType.getDeclaringType().getTypeQualifiedName('.')); |
| if (parameters.length > 0) { |
| final ParameterizedType parameterized= ast.newParameterizedType(type); |
| for (int index= 0; index < parameters.length; index++) |
| parameterized.typeArguments().add(ast.newSimpleType(ast.newSimpleName(parameters[index].getElementName()))); |
| return parameterized; |
| } |
| return type; |
| } |
| |
| private String createNewSource(final CompilationUnitRewrite targetRewrite, final ICompilationUnit unit) throws CoreException, JavaModelException { |
| Assert.isNotNull(targetRewrite); |
| Assert.isNotNull(unit); |
| TextChange change= targetRewrite.createChange(true); |
| if (change == null) |
| change= new CompilationUnitChange("", unit); //$NON-NLS-1$ |
| final String source= change.getPreviewContent(new NullProgressMonitor()); |
| final ASTParser parser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL); |
| parser.setProject(fType.getJavaProject()); |
| parser.setResolveBindings(false); |
| parser.setSource(source.toCharArray()); |
| final AbstractTypeDeclaration declaration= findTypeDeclaration(fType, (CompilationUnit) parser.createAST(null)); |
| SourceRange sourceRange= new TargetSourceRangeComputer().computeSourceRange(declaration); |
| return source.substring(sourceRange.getStartPosition(), sourceRange.getStartPosition() + sourceRange.getLength()); |
| } |
| |
| private Expression createQualifiedReadAccessExpressionForEnclosingInstance(AST ast) { |
| ThisExpression expression= ast.newThisExpression(); |
| expression.setQualifier(ast.newName(new String[] { fType.getElementName()})); |
| FieldAccess access= ast.newFieldAccess(); |
| access.setExpression(expression); |
| access.setName(ast.newSimpleName(fEnclosingInstanceFieldName)); |
| return access; |
| } |
| |
| private Expression createReadAccessExpressionForEnclosingInstance(AST ast) { |
| if (fCodeGenerationSettings.useKeywordThis || fEnclosingInstanceFieldName.equals(fNameForEnclosingInstanceConstructorParameter)) { |
| final FieldAccess access= ast.newFieldAccess(); |
| access.setExpression(ast.newThisExpression()); |
| access.setName(ast.newSimpleName(fEnclosingInstanceFieldName)); |
| return access; |
| } |
| return ast.newSimpleName(fEnclosingInstanceFieldName); |
| } |
| |
| private String createSourceForNewCu(final ICompilationUnit unit, final IProgressMonitor monitor) throws CoreException { |
| Assert.isNotNull(unit); |
| Assert.isNotNull(monitor); |
| try { |
| monitor.beginTask("", 2); //$NON-NLS-1$ |
| final String separator= StubUtility.getLineDelimiterUsed(fType.getJavaProject()); |
| final String block= getAlignedSourceBlock(unit, fNewSourceOfInputType); |
| String fileComment= null; |
| if (StubUtility.doAddComments(unit.getJavaProject())) |
| fileComment= CodeGeneration.getFileComment(unit, separator); |
| String content= CodeGeneration.getCompilationUnitContent(unit, fileComment, null, block, separator); |
| if (content == null) { |
| final StringBuffer buffer= new StringBuffer(); |
| if (!fType.getPackageFragment().isDefaultPackage()) { |
| buffer.append("package ").append(fType.getPackageFragment().getElementName()).append(';'); //$NON-NLS-1$ |
| } |
| buffer.append(separator).append(separator); |
| buffer.append(block); |
| content= buffer.toString(); |
| } |
| unit.getBuffer().setContents(content); |
| addImportsToTargetUnit(unit, new SubProgressMonitor(monitor, 1)); |
| } finally { |
| monitor.done(); |
| } |
| return unit.getSource(); |
| } |
| |
| private Map<ICompilationUnit, SearchMatch[]> createTypeReferencesMapping(IProgressMonitor pm, RefactoringStatus status) throws JavaModelException { |
| final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(fType, IJavaSearchConstants.ALL_OCCURRENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE)); |
| engine.setFiltering(true, true); |
| engine.setScope(RefactoringScopeFactory.create(fType)); |
| engine.setStatus(status); |
| engine.searchPattern(new SubProgressMonitor(pm, 1)); |
| final SearchResultGroup[] groups= (SearchResultGroup[]) engine.getResults(); |
| Map<ICompilationUnit, SearchMatch[]> result= new HashMap<ICompilationUnit, SearchMatch[]>(); |
| for (int i= 0; i < groups.length; i++) { |
| SearchResultGroup group= groups[i]; |
| ICompilationUnit cu= group.getCompilationUnit(); |
| if (cu == null) |
| continue; |
| result.put(cu, group.getSearchResults()); |
| } |
| return result; |
| } |
| |
| private String getAlignedSourceBlock(final ICompilationUnit unit, final String block) { |
| Assert.isNotNull(block); |
| final String[] lines= Strings.convertIntoLines(block); |
| Strings.trimIndentation(lines, unit.getJavaProject(), false); |
| return Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(fType.getJavaProject())); |
| } |
| |
| private CompilationUnitRewrite getCompilationUnitRewrite(final ICompilationUnit unit) { |
| Assert.isNotNull(unit); |
| if (unit.equals(fType.getCompilationUnit())) |
| return fSourceRewrite; |
| return new CompilationUnitRewrite(unit); |
| } |
| |
| private MethodDeclaration[] getConstructorDeclarationNodes(final AbstractTypeDeclaration declaration) { |
| if (declaration instanceof TypeDeclaration) { |
| final MethodDeclaration[] declarations= ((TypeDeclaration) declaration).getMethods(); |
| final List<MethodDeclaration> result= new ArrayList<MethodDeclaration>(2); |
| for (int index= 0; index < declarations.length; index++) { |
| if (declarations[index].isConstructor()) |
| result.add(declarations[index]); |
| } |
| return result.toArray(new MethodDeclaration[result.size()]); |
| } |
| return new MethodDeclaration[] {}; |
| } |
| |
| public boolean getCreateInstanceField() { |
| return fCreateInstanceField; |
| } |
| |
| private int getEnclosingInstanceAccessModifiers() { |
| if (fMarkInstanceFieldAsFinal) |
| return Modifier.PRIVATE | Modifier.FINAL; |
| else |
| return Modifier.PRIVATE; |
| } |
| |
| public String getEnclosingInstanceName() { |
| return fEnclosingInstanceFieldName; |
| } |
| |
| private String getInitialNameForEnclosingInstanceField() { |
| IType enclosingType= fType.getDeclaringType(); |
| if (enclosingType == null) |
| return ""; //$NON-NLS-1$ |
| String[] suggestedNames= StubUtility.getFieldNameSuggestions(fType.getDeclaringType(), getEnclosingInstanceAccessModifiers(), getFieldNames(fType)); |
| if (suggestedNames.length > 0) |
| return suggestedNames[0]; |
| String name= enclosingType.getElementName(); |
| if (name.equals("")) //$NON-NLS-1$ |
| return ""; //$NON-NLS-1$ |
| return Character.toLowerCase(name.charAt(0)) + name.substring(1); |
| } |
| |
| public IType getInputType() { |
| return fType; |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.corext.refactoring.base.IRefactoring#getName() |
| */ |
| @Override |
| public String getName() { |
| return RefactoringCoreMessages.MoveInnerToTopRefactoring_name; |
| } |
| |
| private String getNameForEnclosingInstanceConstructorParameter() throws JavaModelException { |
| if (fNameForEnclosingInstanceConstructorParameter != null) |
| return fNameForEnclosingInstanceConstructorParameter; |
| |
| String[] suggestedNames= StubUtility.getArgumentNameSuggestions(fType.getDeclaringType(), getParameterNamesOfAllConstructors(fType)); |
| if (suggestedNames.length > 0) |
| fNameForEnclosingInstanceConstructorParameter= suggestedNames[0]; |
| else |
| fNameForEnclosingInstanceConstructorParameter= fEnclosingInstanceFieldName; |
| return fNameForEnclosingInstanceConstructorParameter; |
| } |
| |
| private String[] getNewConstructorParameterNames() throws JavaModelException { |
| if (!fCreateInstanceField) |
| return new String[0]; |
| return new String[] { getNameForEnclosingInstanceConstructorParameter()}; |
| } |
| |
| private ASTNode getNewQualifiedNameNode(ITypeBinding[] parameters, Name name) { |
| final AST ast= name.getAST(); |
| boolean raw= false; |
| final ITypeBinding binding= name.resolveTypeBinding(); |
| if (binding != null && binding.isRawType()) |
| raw= true; |
| if (parameters != null && parameters.length > 0 && !raw) { |
| final ParameterizedType type= ast.newParameterizedType(ast.newSimpleType(ast.newName(fQualifiedTypeName))); |
| for (int index= 0; index < parameters.length; index++) |
| type.typeArguments().add(ast.newSimpleType(ast.newSimpleName(parameters[index].getName()))); |
| return type; |
| } |
| return ast.newName(fQualifiedTypeName); |
| } |
| |
| private ASTNode getNewUnqualifiedTypeNode(ITypeBinding[] parameters, Name name) { |
| final AST ast= name.getAST(); |
| boolean raw= false; |
| final ITypeBinding binding= name.resolveTypeBinding(); |
| if (binding != null && binding.isRawType()) |
| raw= true; |
| if (parameters != null && parameters.length > 0 && !raw) { |
| final ParameterizedType type= ast.newParameterizedType(ast.newSimpleType(ast.newSimpleName(fType.getElementName()))); |
| for (int index= 0; index < parameters.length; index++) |
| type.typeArguments().add(ast.newSimpleType(ast.newSimpleName(parameters[index].getName()))); |
| return type; |
| } |
| return ast.newSimpleType(ast.newSimpleName(fType.getElementName())); |
| } |
| |
| private boolean insertExpressionAsParameter(ClassInstanceCreation cic, ASTRewrite rewrite, ICompilationUnit cu, TextEditGroup group) throws JavaModelException { |
| final Expression expression= createEnclosingInstanceCreationString(cic, cu); |
| if (expression == null) |
| return false; |
| rewrite.getListRewrite(cic, ClassInstanceCreation.ARGUMENTS_PROPERTY).insertFirst(expression, group); |
| return true; |
| } |
| |
| private boolean insertExpressionAsParameter(SuperConstructorInvocation sci, ASTRewrite rewrite, ICompilationUnit cu, TextEditGroup group) throws JavaModelException { |
| final Expression expression= createEnclosingInstanceCreationString(sci, cu); |
| if (expression == null) |
| return false; |
| rewrite.getListRewrite(sci, SuperConstructorInvocation.ARGUMENTS_PROPERTY).insertFirst(expression, group); |
| return true; |
| } |
| |
| public boolean isCreatingInstanceFieldMandatory() { |
| return fIsInstanceFieldCreationMandatory; |
| } |
| |
| public boolean isCreatingInstanceFieldPossible() { |
| return fIsInstanceFieldCreationPossible; |
| } |
| |
| private boolean isInAnonymousTypeInsideInputType(ASTNode node, AbstractTypeDeclaration declaration) { |
| final AnonymousClassDeclaration anonymous= (AnonymousClassDeclaration) ASTNodes.getParent(node, AnonymousClassDeclaration.class); |
| return anonymous != null && ASTNodes.isParent(anonymous, declaration); |
| } |
| |
| private boolean isInLocalTypeInsideInputType(ASTNode node, AbstractTypeDeclaration declaration) { |
| final TypeDeclarationStatement statement= (TypeDeclarationStatement) ASTNodes.getParent(node, TypeDeclarationStatement.class); |
| return statement != null && ASTNodes.isParent(statement, declaration); |
| } |
| |
| private boolean isInNonStaticMemberTypeInsideInputType(ASTNode node, AbstractTypeDeclaration declaration) { |
| final AbstractTypeDeclaration nested= (AbstractTypeDeclaration) ASTNodes.getParent(node, AbstractTypeDeclaration.class); |
| return nested != null && !declaration.equals(nested) && !Modifier.isStatic(nested.getFlags()) && ASTNodes.isParent(nested, declaration); |
| } |
| |
| private boolean isInsideSubclassOfDeclaringType(ASTNode node) { |
| Assert.isTrue((node instanceof ClassInstanceCreation) || (node instanceof SuperConstructorInvocation)); |
| final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) ASTNodes.getParent(node, AbstractTypeDeclaration.class); |
| Assert.isNotNull(declaration); |
| |
| final AnonymousClassDeclaration anonymous= (AnonymousClassDeclaration) ASTNodes.getParent(node, AnonymousClassDeclaration.class); |
| boolean isAnonymous= anonymous != null && ASTNodes.isParent(anonymous, declaration); |
| if (isAnonymous) |
| return anonymous != null && isSubclassBindingOfEnclosingType(anonymous.resolveBinding()); |
| return isSubclassBindingOfEnclosingType(declaration.resolveBinding()); |
| } |
| |
| private boolean isInsideTypeNestedInDeclaringType(ASTNode node) { |
| Assert.isTrue((node instanceof ClassInstanceCreation) || (node instanceof SuperConstructorInvocation)); |
| final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) ASTNodes.getParent(node, AbstractTypeDeclaration.class); |
| Assert.isNotNull(declaration); |
| ITypeBinding enclosing= declaration.resolveBinding(); |
| while (enclosing != null) { |
| if (isCorrespondingTypeBinding(enclosing, fType.getDeclaringType())) |
| return true; |
| enclosing= enclosing.getDeclaringClass(); |
| } |
| return false; |
| } |
| |
| private boolean isInstanceFieldCreationMandatory() { |
| AbstractTypeDeclaration typeDeclaration= findTypeDeclaration(fType, fSourceRewrite.getRoot()); |
| ITypeBinding typeBinding= typeDeclaration.resolveBinding(); |
| if (typeBinding == null || Modifier.isStatic(typeBinding.getModifiers())) { |
| return false; |
| } |
| final MemberAccessNodeCollector collector= new MemberAccessNodeCollector(typeBinding); |
| typeDeclaration.accept(collector); |
| return containsNonStatic(collector.getMethodInvocations()) || containsNonStatic(collector.getSimpleFieldNames()); |
| } |
| |
| public boolean isInstanceFieldMarkedFinal() { |
| return fMarkInstanceFieldAsFinal; |
| } |
| |
| private boolean isSubclassBindingOfEnclosingType(ITypeBinding binding) { |
| while (binding != null) { |
| if (isCorrespondingTypeBinding(binding, fType.getDeclaringType())) |
| return true; |
| binding= binding.getSuperclass(); |
| } |
| return false; |
| } |
| |
| /* |
| * This method qualifies accesses from within the moved type to the (now former) enclosed |
| * type of the moved type. Note that all visibility changes have already been scheduled |
| * in the visibility adjustor. |
| */ |
| private void modifyAccessToEnclosingInstance(final CompilationUnitRewrite targetRewrite, final AbstractTypeDeclaration declaration, final IProgressMonitor monitor) { |
| Assert.isNotNull(targetRewrite); |
| Assert.isNotNull(declaration); |
| Assert.isNotNull(monitor); |
| ITypeBinding typeBinding= declaration.resolveBinding(); |
| if (typeBinding == null) { |
| return; |
| } |
| final MemberAccessNodeCollector collector= new MemberAccessNodeCollector(typeBinding); |
| declaration.accept(collector); |
| modifyAccessToMethodsFromEnclosingInstance(targetRewrite, collector.getMethodInvocations(), declaration); |
| modifyAccessToFieldsFromEnclosingInstance(targetRewrite, collector.getSimpleFieldNames(), declaration); |
| } |
| |
| private void modifyAccessToFieldsFromEnclosingInstance(CompilationUnitRewrite targetRewrite, SimpleName[] simpleNames, AbstractTypeDeclaration declaration) { |
| IBinding binding= null; |
| SimpleName simpleName= null; |
| IVariableBinding variable= null; |
| for (int index= 0; index < simpleNames.length; index++) { |
| simpleName= simpleNames[index]; |
| binding= simpleName.resolveBinding(); |
| if (binding != null && binding instanceof IVariableBinding && !(simpleName.getParent() instanceof FieldAccess)) { |
| variable= (IVariableBinding) binding; |
| final FieldAccess access= simpleName.getAST().newFieldAccess(); |
| access.setExpression(createAccessExpressionToEnclosingInstanceFieldText(simpleName, variable, declaration)); |
| access.setName(simpleName.getAST().newSimpleName(simpleName.getIdentifier())); |
| targetRewrite.getASTRewrite().replace(simpleName, access, null); |
| targetRewrite.getImportRemover().registerRemovedNode(simpleName); |
| } |
| } |
| } |
| |
| private void modifyAccessToMethodsFromEnclosingInstance(CompilationUnitRewrite targetRewrite, MethodInvocation[] methodInvocations, AbstractTypeDeclaration declaration) { |
| IMethodBinding binding= null; |
| MethodInvocation invocation= null; |
| for (int index= 0; index < methodInvocations.length; index++) { |
| invocation= methodInvocations[index]; |
| binding= invocation.resolveMethodBinding(); |
| if (binding != null) { |
| final Expression target= invocation.getExpression(); |
| if (target == null) { |
| final Expression expression= createAccessExpressionToEnclosingInstanceFieldText(invocation, binding, declaration); |
| targetRewrite.getASTRewrite().set(invocation, MethodInvocation.EXPRESSION_PROPERTY, expression, null); |
| } else { |
| if (!(invocation.getExpression() instanceof ThisExpression) || !(((ThisExpression) invocation.getExpression()).getQualifier() != null)) |
| continue; |
| targetRewrite.getASTRewrite().replace(target, createAccessExpressionToEnclosingInstanceFieldText(invocation, binding, declaration), null); |
| targetRewrite.getImportRemover().registerRemovedNode(target); |
| } |
| } |
| } |
| } |
| |
| private void modifyConstructors(AbstractTypeDeclaration declaration, ASTRewrite rewrite) throws CoreException { |
| final MethodDeclaration[] declarations= getConstructorDeclarationNodes(declaration); |
| for (int index= 0; index < declarations.length; index++) { |
| Assert.isTrue(declarations[index].isConstructor()); |
| addParameterToConstructor(rewrite, declarations[index]); |
| setEnclosingInstanceFieldInConstructor(rewrite, declarations[index]); |
| } |
| } |
| |
| private void modifyInterfaceMemberModifiers(final ITypeBinding binding) { |
| Assert.isNotNull(binding); |
| ITypeBinding declaring= binding.getDeclaringClass(); |
| while (declaring != null && !declaring.isInterface()) { |
| declaring= declaring.getDeclaringClass(); |
| } |
| if (declaring != null) { |
| final ASTNode node= ASTNodes.findDeclaration(binding, fSourceRewrite.getRoot()); |
| if (node instanceof AbstractTypeDeclaration) { |
| ModifierRewrite.create(fSourceRewrite.getASTRewrite(), node).setVisibility(Modifier.PUBLIC, null); |
| } |
| } |
| } |
| |
| public void setCreateInstanceField(boolean create) { |
| Assert.isTrue(fIsInstanceFieldCreationPossible); |
| Assert.isTrue(!fIsInstanceFieldCreationMandatory); |
| fCreateInstanceField= create; |
| } |
| |
| private void setEnclosingInstanceFieldInConstructor(ASTRewrite rewrite, MethodDeclaration decl) throws JavaModelException { |
| final AST ast= decl.getAST(); |
| final Block body= decl.getBody(); |
| final List<Statement> statements= body.statements(); |
| if (statements.isEmpty()) { |
| final Assignment assignment= ast.newAssignment(); |
| assignment.setLeftHandSide(createReadAccessExpressionForEnclosingInstance(ast)); |
| assignment.setRightHandSide(ast.newSimpleName(getNameForEnclosingInstanceConstructorParameter())); |
| rewrite.getListRewrite(body, Block.STATEMENTS_PROPERTY).insertFirst(ast.newExpressionStatement(assignment), null); |
| } else { |
| final Statement first= statements.get(0); |
| if (first instanceof ConstructorInvocation) { |
| rewrite.getListRewrite(first, ConstructorInvocation.ARGUMENTS_PROPERTY).insertFirst(ast.newSimpleName(fEnclosingInstanceFieldName), null); |
| } else { |
| int index= 0; |
| if (first instanceof SuperConstructorInvocation) |
| index++; |
| final Assignment assignment= ast.newAssignment(); |
| assignment.setLeftHandSide(createReadAccessExpressionForEnclosingInstance(ast)); |
| assignment.setRightHandSide(ast.newSimpleName(getNameForEnclosingInstanceConstructorParameter())); |
| rewrite.getListRewrite(body, Block.STATEMENTS_PROPERTY).insertAt(ast.newExpressionStatement(assignment), index, null); |
| } |
| } |
| } |
| |
| public void setEnclosingInstanceName(String name) { |
| Assert.isNotNull(name); |
| fEnclosingInstanceFieldName= name; |
| } |
| |
| public void setMarkInstanceFieldAsFinal(boolean mark) { |
| fMarkInstanceFieldAsFinal= mark; |
| } |
| |
| private void updateConstructorReference(final ClassInstanceCreation creation, final CompilationUnitRewrite targetRewrite, final ICompilationUnit unit, TextEditGroup group) throws JavaModelException { |
| Assert.isNotNull(creation); |
| Assert.isNotNull(targetRewrite); |
| Assert.isNotNull(unit); |
| final ASTRewrite rewrite= targetRewrite.getASTRewrite(); |
| if (fCreateInstanceField) |
| insertExpressionAsParameter(creation, rewrite, unit, group); |
| final Expression expression= creation.getExpression(); |
| if (expression != null) { |
| rewrite.remove(expression, null); |
| targetRewrite.getImportRemover().registerRemovedNode(expression); |
| } |
| } |
| |
| private void updateConstructorReference(ITypeBinding[] parameters, ASTNode reference, CompilationUnitRewrite targetRewrite, ICompilationUnit cu) throws CoreException { |
| final TextEditGroup group= targetRewrite.createGroupDescription(RefactoringCoreMessages.MoveInnerToTopRefactoring_update_constructor_reference); |
| if (reference instanceof SuperConstructorInvocation) |
| updateConstructorReference((SuperConstructorInvocation) reference, targetRewrite, cu, group); |
| else if (reference instanceof ClassInstanceCreation) |
| updateConstructorReference((ClassInstanceCreation) reference, targetRewrite, cu, group); |
| else if (reference.getParent() instanceof ClassInstanceCreation) |
| updateConstructorReference((ClassInstanceCreation) reference.getParent(), targetRewrite, cu, group); |
| else if (reference.getParent() instanceof ParameterizedType && reference.getParent().getParent() instanceof ClassInstanceCreation) |
| updateConstructorReference(parameters, (ParameterizedType) reference.getParent(), targetRewrite, cu, group); |
| } |
| |
| private void updateConstructorReference(ITypeBinding[] parameters, ParameterizedType type, CompilationUnitRewrite targetRewrite, ICompilationUnit cu, TextEditGroup group) throws CoreException { |
| final ListRewrite rewrite= targetRewrite.getASTRewrite().getListRewrite(type, ParameterizedType.TYPE_ARGUMENTS_PROPERTY); |
| TypeParameter parameter= null; |
| for (int index= type.typeArguments().size(); index < parameters.length; index++) { |
| parameter= targetRewrite.getRoot().getAST().newTypeParameter(); |
| parameter.setName(targetRewrite.getRoot().getAST().newSimpleName(parameters[index].getName())); |
| rewrite.insertLast(parameter, group); |
| } |
| if (type.getParent() instanceof ClassInstanceCreation) |
| updateConstructorReference((ClassInstanceCreation) type.getParent(), targetRewrite, cu, group); |
| } |
| |
| private void updateConstructorReference(final SuperConstructorInvocation invocation, final CompilationUnitRewrite targetRewrite, final ICompilationUnit unit, TextEditGroup group) throws CoreException { |
| Assert.isNotNull(invocation); |
| Assert.isNotNull(targetRewrite); |
| Assert.isNotNull(unit); |
| final ASTRewrite rewrite= targetRewrite.getASTRewrite(); |
| if (fCreateInstanceField) |
| insertExpressionAsParameter(invocation, rewrite, unit, group); |
| final Expression expression= invocation.getExpression(); |
| if (expression != null) { |
| rewrite.remove(expression, null); |
| targetRewrite.getImportRemover().registerRemovedNode(expression); |
| } |
| } |
| |
| private boolean updateNameReference(ITypeBinding[] parameters, Name name, CompilationUnitRewrite targetRewrite, TextEditGroup group) { |
| if (ASTNodes.asString(name).equals(fType.getFullyQualifiedName('.'))) { |
| targetRewrite.getASTRewrite().replace(name, getNewQualifiedNameNode(parameters, name), group); |
| targetRewrite.getImportRemover().registerRemovedNode(name); |
| return true; |
| } |
| targetRewrite.getASTRewrite().replace(name, getNewUnqualifiedTypeNode(parameters, name), group); |
| targetRewrite.getImportRemover().registerRemovedNode(name); |
| return true; |
| } |
| |
| private boolean updateParameterizedTypeReference(ITypeBinding[] parameters, ParameterizedType type, CompilationUnitRewrite targetRewrite, TextEditGroup group) { |
| if (!(type.getParent() instanceof ClassInstanceCreation)) { |
| final ListRewrite rewrite= targetRewrite.getASTRewrite().getListRewrite(type, ParameterizedType.TYPE_ARGUMENTS_PROPERTY); |
| final AST ast= targetRewrite.getRoot().getAST(); |
| Type simpleType= null; |
| for (int index= type.typeArguments().size(); index < parameters.length; index++) { |
| simpleType= ast.newSimpleType(ast.newSimpleName(parameters[index].getName())); |
| rewrite.insertLast(simpleType, group); |
| } |
| } |
| return true; |
| } |
| |
| private boolean updateReference(ITypeBinding[] parameters, ASTNode node, CompilationUnitRewrite rewrite, TextEditGroup group) { |
| if (node.getLocationInParent() == ParameterizedType.TYPE_PROPERTY) { |
| updateParameterizedTypeReference(parameters, (ParameterizedType) node.getParent(), rewrite, group); |
| return updateNameReference(new ITypeBinding[] {}, ((SimpleType) node).getName(), rewrite, group); |
| } else if (node instanceof QualifiedName) |
| return updateNameReference(parameters, (QualifiedName) node, rewrite, group); |
| else if (node instanceof SimpleType) |
| return updateNameReference(parameters, ((SimpleType) node).getName(), rewrite, group); |
| else |
| return false; |
| } |
| |
| private void updateReferenceInImport(ImportDeclaration enclosingImport, ASTNode node, CompilationUnitRewrite rewrite) { |
| final IBinding binding= enclosingImport.resolveBinding(); |
| if (binding instanceof ITypeBinding) { |
| final ITypeBinding type= (ITypeBinding) binding; |
| final ImportRewrite rewriter= rewrite.getImportRewrite(); |
| if (enclosingImport.isStatic()) { |
| final String oldImport= ASTNodes.asString(node); |
| final StringBuffer buffer= new StringBuffer(oldImport); |
| final String typeName= fType.getDeclaringType().getElementName(); |
| final int index= buffer.indexOf(typeName); |
| if (index >= 0) { |
| buffer.delete(index, index + typeName.length() + 1); |
| final String newImport= buffer.toString(); |
| if (enclosingImport.isOnDemand()) { |
| rewriter.removeStaticImport(oldImport + ".*"); //$NON-NLS-1$ |
| rewriter.addStaticImport(newImport, "*", false); //$NON-NLS-1$ |
| } else { |
| rewriter.removeStaticImport(oldImport); |
| final int offset= newImport.lastIndexOf('.'); |
| if (offset >= 0 && offset < newImport.length() - 1) { |
| rewriter.addStaticImport(newImport.substring(0, offset), newImport.substring(offset + 1), false); |
| } |
| } |
| } |
| } else |
| rewriter.removeImport(type.getQualifiedName()); |
| } |
| } |
| |
| private void updateTypeReference(ITypeBinding[] parameters, ASTNode node, CompilationUnitRewrite rewrite, ICompilationUnit cu) { |
| ImportDeclaration enclosingImport= (ImportDeclaration) ASTNodes.getParent(node, ImportDeclaration.class); |
| if (enclosingImport != null) |
| updateReferenceInImport(enclosingImport, node, rewrite); |
| else { |
| final TextEditGroup group= rewrite.createGroupDescription(RefactoringCoreMessages.MoveInnerToTopRefactoring_update_type_reference); |
| updateReference(parameters, node, rewrite, group); |
| if (!fType.getPackageFragment().equals(cu.getParent())) { |
| final String name= fType.getPackageFragment().getElementName() + '.' + fType.getElementName(); |
| rewrite.getImportRemover().registerAddedImport(name); |
| rewrite.getImportRewrite().addImport(name); |
| } |
| } |
| } |
| |
| private RefactoringStatus initialize(JavaRefactoringArguments arguments) { |
| final String handle= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT); |
| if (handle != null) { |
| final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(arguments.getProject(), handle, false); |
| if (element == null || !element.exists() || element.getElementType() != IJavaElement.TYPE) |
| return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getName(), IJavaRefactorings.CONVERT_MEMBER_TYPE); |
| else { |
| fType= (IType) element; |
| fCodeGenerationSettings= JavaPreferencesSettings.getCodeGenerationSettings(fType.getJavaProject()); |
| try { |
| initialize(); |
| } catch (JavaModelException exception) { |
| JavaPlugin.log(exception); |
| } |
| } |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT)); |
| final String fieldName= arguments.getAttribute(ATTRIBUTE_FIELD_NAME); |
| if (fieldName != null && !"".equals(fieldName)) //$NON-NLS-1$ |
| fEnclosingInstanceFieldName= fieldName; |
| final String parameterName= arguments.getAttribute(ATTRIBUTE_PARAMETER_NAME); |
| if (parameterName != null && !"".equals(parameterName)) //$NON-NLS-1$ |
| fNameForEnclosingInstanceConstructorParameter= parameterName; |
| final String createField= arguments.getAttribute(ATTRIBUTE_FIELD); |
| if (createField != null) { |
| fCreateInstanceField= Boolean.valueOf(createField).booleanValue(); |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_FIELD)); |
| final String markFinal= arguments.getAttribute(ATTRIBUTE_FINAL); |
| if (markFinal != null) { |
| fMarkInstanceFieldAsFinal= Boolean.valueOf(markFinal).booleanValue(); |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_FINAL)); |
| final String possible= arguments.getAttribute(ATTRIBUTE_POSSIBLE); |
| if (possible != null) { |
| fIsInstanceFieldCreationPossible= Boolean.valueOf(possible).booleanValue(); |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_POSSIBLE)); |
| final String mandatory= arguments.getAttribute(ATTRIBUTE_MANDATORY); |
| if (mandatory != null) |
| fIsInstanceFieldCreationMandatory= Boolean.valueOf(mandatory).booleanValue(); |
| else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_MANDATORY)); |
| return new RefactoringStatus(); |
| } |
| } |