| /******************************************************************************* |
| * Copyright (c) 2000, 2006 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 |
| * N.Metchev@teamphone.com - contributed fixes for |
| * - convert anonymous to nested should sometimes declare class as static [refactoring] |
| * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=43360) |
| * - Convert anonymous to nested: should show error if field form outer anonymous type is references [refactoring] |
| * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=48282) |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.corext.refactoring.code; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.text.edits.MalformedTreeException; |
| import org.eclipse.text.edits.TextEdit; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| |
| import org.eclipse.core.filebuffers.ITextFileBuffer; |
| |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.IDocument; |
| |
| import org.eclipse.ltk.core.refactoring.Change; |
| import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments; |
| |
| import org.eclipse.jdt.core.Flags; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.NamingConventions; |
| import org.eclipse.jdt.core.dom.AST; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| 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.Expression; |
| import org.eclipse.jdt.core.dom.ExpressionStatement; |
| 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.Javadoc; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| import org.eclipse.jdt.core.dom.Modifier; |
| 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.SimpleName; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.SuperConstructorInvocation; |
| import org.eclipse.jdt.core.dom.SuperFieldAccess; |
| import org.eclipse.jdt.core.dom.Type; |
| import org.eclipse.jdt.core.dom.TypeDeclaration; |
| 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.ITrackedNodePosition; |
| |
| 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.NodeFinder; |
| import org.eclipse.jdt.internal.corext.refactoring.Checks; |
| import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments; |
| import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptor; |
| import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorComment; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitDescriptorChange; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility; |
| import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; |
| import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; |
| import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringFileBuffers; |
| import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil; |
| import org.eclipse.jdt.internal.corext.util.JdtFlags; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| 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.preferences.JavaPreferencesSettings; |
| import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; |
| |
| public class ConvertAnonymousToNestedRefactoring extends ScriptableRefactoring { |
| |
| private static final String ID_CONVERT_ANONYMOUS= "org.eclipse.jdt.ui.convert.anonymous"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_VISIBILITY= "visibility"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_FINAL= "final"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_STATIC= "static"; //$NON-NLS-1$ |
| |
| public static class TypeVariableFinder extends ASTVisitor { |
| |
| private final Map fBindings= new HashMap(); |
| private final List fFound= new ArrayList(); |
| |
| public final boolean visit(final SimpleName node) { |
| Assert.isNotNull(node); |
| final ITypeBinding binding= node.resolveTypeBinding(); |
| if (binding != null && binding.isTypeVariable() && !fBindings.containsKey(binding.getKey())) { |
| fBindings.put(binding.getKey(), binding); |
| fFound.add(binding); |
| } |
| return true; |
| } |
| |
| public final ITypeBinding[] getResult() { |
| final ITypeBinding[] result= new ITypeBinding[fFound.size()]; |
| fFound.toArray(result); |
| return result; |
| } |
| } |
| |
| private int fSelectionStart; |
| private int fSelectionLength; |
| private ICompilationUnit fCu; |
| |
| private int fVisibility; /* see Modifier */ |
| private boolean fDeclareFinal= true; |
| private boolean fDeclareStatic; |
| private String fClassName= ""; //$NON-NLS-1$ |
| private CodeGenerationSettings fSettings; |
| |
| private CompilationUnit fCompilationUnitNode; |
| private AnonymousClassDeclaration fAnonymousInnerClassNode; |
| private Set fClassNamesUsed; |
| private boolean fSelfInitializing= false; |
| |
| /** |
| * Creates a new convert anonymous to nested refactoring |
| * @param unit the compilation unit, or <code>null</code> if invoked by scripting |
| * @param settings the code generation settings |
| * @param selectionStart |
| * @param selectionLength |
| */ |
| public ConvertAnonymousToNestedRefactoring(ICompilationUnit unit, CodeGenerationSettings settings, int selectionStart, int selectionLength) { |
| Assert.isTrue(selectionStart >= 0); |
| Assert.isTrue(selectionLength >= 0); |
| Assert.isTrue(unit == null || unit.exists()); |
| fSelectionStart= selectionStart; |
| fSelectionLength= selectionLength; |
| fCu= unit; |
| if (unit != null) |
| fSettings= settings; |
| } |
| |
| public int[] getAvailableVisibilities() { |
| if (isLocalInnerType()) { |
| return new int[] { Modifier.NONE }; |
| } else { |
| return new int[] { Modifier.PUBLIC, Modifier.PROTECTED, Modifier.NONE, Modifier.PRIVATE }; |
| } |
| } |
| |
| public boolean isLocalInnerType() { |
| return ASTNodes.getParent(ASTNodes.getParent(fAnonymousInnerClassNode, AbstractTypeDeclaration.class), ASTNode.ANONYMOUS_CLASS_DECLARATION) != null; |
| } |
| |
| public int getVisibility() { |
| return fVisibility; |
| } |
| |
| public void setVisibility(int visibility) { |
| Assert.isTrue(visibility == Modifier.PRIVATE || visibility == Modifier.NONE || visibility == Modifier.PROTECTED || visibility == Modifier.PUBLIC); |
| fVisibility= visibility; |
| } |
| |
| public void setClassName(String className) { |
| Assert.isNotNull(className); |
| fClassName= className; |
| } |
| |
| public boolean canEnableSettingFinal() { |
| return true; |
| } |
| |
| public boolean getDeclareFinal() { |
| return fDeclareFinal; |
| } |
| |
| public boolean getDeclareStatic() { |
| return fDeclareStatic; |
| } |
| |
| public void setDeclareFinal(boolean declareFinal) { |
| fDeclareFinal= declareFinal; |
| } |
| |
| public void setDeclareStatic(boolean declareStatic) { |
| fDeclareStatic= declareStatic; |
| } |
| |
| public String getName() { |
| return RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_name; |
| } |
| |
| public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { |
| RefactoringStatus result= Checks.validateModifiesFiles( |
| ResourceUtil.getFiles(new ICompilationUnit[]{fCu}), |
| getValidationContext()); |
| if (result.hasFatalError()) |
| return result; |
| |
| initAST(pm); |
| |
| if (fAnonymousInnerClassNode == null) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_place_caret); |
| if (!fSelfInitializing) |
| initializeDefaults(); |
| if (getSuperConstructorBinding() == null) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_compile_errors); |
| if (getSuperTypeBinding().isLocal()) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_extends_local_class); |
| return new RefactoringStatus(); |
| } |
| |
| private void initializeDefaults() { |
| fVisibility= isLocalInnerType() ? Modifier.NONE : Modifier.PRIVATE; |
| fDeclareStatic = mustInnerClassBeStatic(); |
| } |
| |
| private void initAST(IProgressMonitor pm) { |
| fCompilationUnitNode= RefactoringASTParser.parseWithASTProvider(fCu, true, pm); |
| fAnonymousInnerClassNode= getAnonymousInnerClass(NodeFinder.perform(fCompilationUnitNode, fSelectionStart, fSelectionLength)); |
| if (fAnonymousInnerClassNode != null) { |
| final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) ASTNodes.getParent(fAnonymousInnerClassNode, AbstractTypeDeclaration.class); |
| if (declaration instanceof TypeDeclaration) { |
| final AbstractTypeDeclaration[] nested= ((TypeDeclaration) declaration).getTypes(); |
| fClassNamesUsed= new HashSet(nested.length); |
| for (int index= 0; index < nested.length; index++) |
| fClassNamesUsed.add(nested[index].getName().getIdentifier()); |
| } else |
| fClassNamesUsed= Collections.EMPTY_SET; |
| } |
| } |
| |
| private static AnonymousClassDeclaration getAnonymousInnerClass(ASTNode node) { |
| if (node == null) |
| return null; |
| if (node instanceof AnonymousClassDeclaration) |
| return (AnonymousClassDeclaration)node; |
| if (node instanceof ClassInstanceCreation) { |
| AnonymousClassDeclaration anon= ((ClassInstanceCreation)node).getAnonymousClassDeclaration(); |
| if (anon != null) |
| return anon; |
| } |
| node= ASTNodes.getNormalizedNode(node); |
| if (node.getLocationInParent() == ClassInstanceCreation.TYPE_PROPERTY) { |
| AnonymousClassDeclaration anon= ((ClassInstanceCreation)node.getParent()).getAnonymousClassDeclaration(); |
| if (anon != null) |
| return anon; |
| } |
| return (AnonymousClassDeclaration)ASTNodes.getParent(node, AnonymousClassDeclaration.class); |
| } |
| |
| public RefactoringStatus validateInput() { |
| RefactoringStatus result= Checks.checkTypeName(fClassName); |
| if (result.hasFatalError()) |
| return result; |
| |
| if (fClassNamesUsed.contains(fClassName)) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_type_exists); |
| IMethodBinding superConstructorBinding = getSuperConstructorBinding(); |
| if (superConstructorBinding == null) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_compile_errors); |
| if (fClassName.equals(superConstructorBinding.getDeclaringClass().getName())) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_another_name); |
| if (classNameHidesEnclosingType()) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_name_hides); |
| return result; |
| } |
| |
| private boolean accessesAnonymousFields() { |
| List anonymousInnerFieldTypes = getAllEnclosingAnonymousTypesField(); |
| List accessedField = getAllAccessedFields(); |
| final Iterator it = anonymousInnerFieldTypes.iterator(); |
| while(it.hasNext()) { |
| final IVariableBinding variableBinding = (IVariableBinding) it.next(); |
| final Iterator it2 = accessedField.iterator(); |
| while (it2.hasNext()) { |
| IVariableBinding variableBinding2 = (IVariableBinding) it2.next(); |
| if(Bindings.equals(variableBinding, variableBinding2)) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| private List getAllAccessedFields() { |
| final List accessedFields= new ArrayList(); |
| |
| ASTVisitor visitor= new ASTVisitor() { |
| |
| public boolean visit(FieldAccess node) { |
| final IVariableBinding binding= node.resolveFieldBinding(); |
| if (binding != null && !binding.isEnumConstant()) |
| accessedFields.add(binding); |
| return super.visit(node); |
| } |
| |
| public boolean visit(QualifiedName node) { |
| final IBinding binding= node.resolveBinding(); |
| if (binding != null && binding instanceof IVariableBinding) { |
| IVariableBinding variable= (IVariableBinding) binding; |
| if (!variable.isEnumConstant() && variable.isField()) |
| accessedFields.add(binding); |
| } |
| return super.visit(node); |
| } |
| |
| public boolean visit(SimpleName node) { |
| final IBinding binding= node.resolveBinding(); |
| if (binding != null && binding instanceof IVariableBinding) { |
| IVariableBinding variable= (IVariableBinding) binding; |
| if (!variable.isEnumConstant() && variable.isField()) |
| accessedFields.add(binding); |
| } |
| return super.visit(node); |
| } |
| |
| public boolean visit(SuperFieldAccess node) { |
| final IVariableBinding binding= node.resolveFieldBinding(); |
| if (binding != null && !binding.isEnumConstant()) |
| accessedFields.add(binding); |
| return super.visit(node); |
| } |
| }; |
| fAnonymousInnerClassNode.accept(visitor); |
| |
| return accessedFields; |
| } |
| |
| private List getAllEnclosingAnonymousTypesField() { |
| final List ans= new ArrayList(); |
| final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) ASTNodes.getParent(fAnonymousInnerClassNode, AbstractTypeDeclaration.class); |
| AnonymousClassDeclaration anonymous= (AnonymousClassDeclaration) ASTNodes.getParent(fAnonymousInnerClassNode, ASTNode.ANONYMOUS_CLASS_DECLARATION); |
| while (anonymous != null) { |
| if (ASTNodes.isParent(anonymous, declaration)) { |
| ITypeBinding binding= anonymous.resolveBinding(); |
| if (binding != null) { |
| ans.addAll(Arrays.asList(binding.getDeclaredFields())); |
| } |
| } else { |
| break; |
| } |
| anonymous= (AnonymousClassDeclaration) ASTNodes.getParent(anonymous, ASTNode.ANONYMOUS_CLASS_DECLARATION); |
| } |
| return ans; |
| } |
| |
| private boolean classNameHidesEnclosingType() { |
| ITypeBinding type= ((AbstractTypeDeclaration) ASTNodes.getParent(fAnonymousInnerClassNode, AbstractTypeDeclaration.class)).resolveBinding(); |
| while (type != null) { |
| if (fClassName.equals(type.getName())) |
| return true; |
| type= type.getDeclaringClass(); |
| } |
| return false; |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.corext.refactoring.base.Refactoring#checkInput(org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException { |
| try { |
| RefactoringStatus status= validateInput(); |
| if (accessesAnonymousFields()) |
| status.merge(RefactoringStatus.createErrorStatus(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_anonymous_field_access)); |
| return status; |
| } finally { |
| pm.done(); |
| } |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.corext.refactoring.base.IRefactoring#createChange(org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| public Change createChange(IProgressMonitor pm) throws CoreException { |
| pm.beginTask("", 1); //$NON-NLS-1$ |
| try { |
| final CompilationUnitRewrite rewrite= new CompilationUnitRewrite(fCu, fCompilationUnitNode); |
| final ITypeBinding[] parameters= getTypeParameters(); |
| addNestedClass(rewrite, parameters); |
| modifyConstructorCall(rewrite, parameters); |
| return createChange(rewrite); |
| } finally { |
| pm.done(); |
| } |
| } |
| |
| private ITypeBinding[] getTypeParameters() { |
| final List parameters= new ArrayList(4); |
| final ClassInstanceCreation creation= (ClassInstanceCreation) fAnonymousInnerClassNode.getParent(); |
| if (fDeclareStatic) { |
| final TypeVariableFinder finder= new TypeVariableFinder(); |
| creation.accept(finder); |
| return finder.getResult(); |
| } else { |
| final MethodDeclaration declaration= getEnclosingMethodDeclaration(creation); |
| if (declaration != null) { |
| ITypeBinding binding= null; |
| TypeParameter parameter= null; |
| for (final Iterator iterator= declaration.typeParameters().iterator(); iterator.hasNext();) { |
| parameter= (TypeParameter) iterator.next(); |
| binding= parameter.resolveBinding(); |
| if (binding != null) |
| parameters.add(binding); |
| } |
| } |
| } |
| final TypeVariableFinder finder= new TypeVariableFinder(); |
| creation.accept(finder); |
| final ITypeBinding[] variables= finder.getResult(); |
| final List remove= new ArrayList(4); |
| boolean match= false; |
| ITypeBinding binding= null; |
| ITypeBinding variable= null; |
| for (final Iterator iterator= parameters.iterator(); iterator.hasNext();) { |
| match= false; |
| binding= (ITypeBinding) iterator.next(); |
| for (int index= 0; index < variables.length; index++) { |
| variable= variables[index]; |
| if (variable.equals(binding)) |
| match= true; |
| } |
| if (!match) |
| remove.add(binding); |
| } |
| parameters.removeAll(remove); |
| final ITypeBinding[] result= new ITypeBinding[parameters.size()]; |
| parameters.toArray(result); |
| return result; |
| } |
| |
| private MethodDeclaration getEnclosingMethodDeclaration(ASTNode node) { |
| ASTNode parent= node.getParent(); |
| if (parent != null) { |
| if (parent instanceof AbstractTypeDeclaration) |
| return null; |
| else if (parent instanceof MethodDeclaration) |
| return (MethodDeclaration) parent; |
| return getEnclosingMethodDeclaration(parent); |
| } |
| return null; |
| } |
| |
| private Change createChange(CompilationUnitRewrite rewrite) throws CoreException { |
| final ITypeBinding binding= fAnonymousInnerClassNode.resolveBinding(); |
| final String[] labels= new String[] { BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED), BindingLabelProvider.getBindingLabel(binding.getDeclaringMethod(), JavaElementLabels.ALL_FULLY_QUALIFIED)}; |
| final Map arguments= new HashMap(); |
| String project= null; |
| IJavaProject javaProject= fCu.getJavaProject(); |
| if (javaProject != null) |
| project= javaProject.getElementName(); |
| final int flags= RefactoringDescriptor.STRUCTURAL_CHANGE | JavaRefactoringDescriptor.JAR_REFACTORABLE | JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT; |
| final String description= RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_descriptor_description_short; |
| final String header= Messages.format(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_descriptor_description, labels); |
| final JavaRefactoringDescriptorComment comment= new JavaRefactoringDescriptorComment(this, header); |
| comment.addSetting(Messages.format(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_original_pattern, BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED))); |
| comment.addSetting(Messages.format(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_class_name_pattern, fClassName)); |
| String visibility= JdtFlags.getVisibilityString(fVisibility); |
| if ("".equals(visibility)) //$NON-NLS-1$ |
| visibility= RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_default_visibility; |
| comment.addSetting(Messages.format(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_visibility_pattern, visibility)); |
| if (fDeclareFinal && fDeclareStatic) |
| comment.addSetting(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_declare_final_static); |
| else if (fDeclareFinal) |
| comment.addSetting(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_declare_final); |
| else if (fDeclareStatic) |
| comment.addSetting(RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_declare_static); |
| final JavaRefactoringDescriptor descriptor= new JavaRefactoringDescriptor(ID_CONVERT_ANONYMOUS, project, description, comment.asString(), arguments, flags); |
| arguments.put(JavaRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fCu)); |
| arguments.put(JavaRefactoringDescriptor.ATTRIBUTE_NAME, fClassName); |
| arguments.put(JavaRefactoringDescriptor.ATTRIBUTE_SELECTION, new Integer(fSelectionStart).toString() + " " + new Integer(fSelectionLength).toString()); //$NON-NLS-1$ |
| arguments.put(ATTRIBUTE_FINAL, Boolean.valueOf(fDeclareFinal).toString()); |
| arguments.put(ATTRIBUTE_STATIC, Boolean.valueOf(fDeclareStatic).toString()); |
| arguments.put(ATTRIBUTE_VISIBILITY, new Integer(fVisibility).toString()); |
| final CompilationUnitDescriptorChange result= new CompilationUnitDescriptorChange(descriptor, RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_name, fCu); |
| try { |
| ITextFileBuffer buffer= RefactoringFileBuffers.acquire(fCu); |
| TextEdit resultingEdits= rewrite.getASTRewrite().rewriteAST(buffer.getDocument(), fCu.getJavaProject().getOptions(true)); |
| TextChangeCompatibility.addTextEdit(result, RefactoringCoreMessages.ConvertAnonymousToNestedRefactoring_edit_name, resultingEdits); |
| } finally { |
| RefactoringFileBuffers.release(fCu); |
| } |
| return result; |
| } |
| |
| private void modifyConstructorCall(CompilationUnitRewrite rewrite, ITypeBinding[] parameters) { |
| rewrite.getASTRewrite().replace(fAnonymousInnerClassNode.getParent(), createNewClassInstanceCreation(rewrite, parameters), null); |
| } |
| |
| private ASTNode createNewClassInstanceCreation(CompilationUnitRewrite rewrite, ITypeBinding[] parameters) { |
| AST ast= fAnonymousInnerClassNode.getAST(); |
| ClassInstanceCreation newClassCreation= ast.newClassInstanceCreation(); |
| newClassCreation.setAnonymousClassDeclaration(null); |
| Type type= null; |
| if (parameters.length > 0) { |
| final ParameterizedType parameterized= ast.newParameterizedType(ast.newSimpleType(ast.newSimpleName(fClassName))); |
| for (int index= 0; index < parameters.length; index++) |
| parameterized.typeArguments().add(ast.newSimpleType(ast.newSimpleName(parameters[index].getName()))); |
| type= parameterized; |
| } else |
| type= ast.newSimpleType(ast.newSimpleName(fClassName)); |
| newClassCreation.setType(type); |
| copyArguments(rewrite, newClassCreation); |
| addArgumentsForLocalsUsedInInnerClass(rewrite, newClassCreation); |
| return newClassCreation; |
| } |
| |
| private void addArgumentsForLocalsUsedInInnerClass(CompilationUnitRewrite rewrite, ClassInstanceCreation newClassCreation) { |
| IVariableBinding[] usedLocals= getUsedLocalVariables(); |
| for (int i= 0; i < usedLocals.length; i++) { |
| final AST ast= fAnonymousInnerClassNode.getAST(); |
| final IVariableBinding binding= usedLocals[i]; |
| Name name= null; |
| if (binding.isEnumConstant()) |
| name= ast.newQualifiedName(ast.newSimpleName(binding.getDeclaringClass().getName()), ast.newSimpleName(binding.getName())); |
| else |
| name= ast.newSimpleName(binding.getName()); |
| newClassCreation.arguments().add(name); |
| } |
| } |
| |
| private void copyArguments(CompilationUnitRewrite rewrite, ClassInstanceCreation newClassCreation) { |
| for (Iterator iter= ((ClassInstanceCreation) fAnonymousInnerClassNode.getParent()).arguments().iterator(); iter.hasNext(); ) |
| newClassCreation.arguments().add(rewrite.getASTRewrite().createCopyTarget((Expression)iter.next())); |
| } |
| |
| private void addNestedClass(CompilationUnitRewrite rewrite, ITypeBinding[] parameters) throws CoreException { |
| final AbstractTypeDeclaration declarations= (AbstractTypeDeclaration) ASTNodes.getParent(fAnonymousInnerClassNode, AbstractTypeDeclaration.class); |
| int index= findIndexOfFistNestedClass(declarations.bodyDeclarations()); |
| if (index == -1) |
| index= 0; |
| rewrite.getASTRewrite().getListRewrite(declarations, declarations.getBodyDeclarationsProperty()).insertAt(createNewNestedClass(rewrite, parameters), index, null); |
| } |
| |
| private static int findIndexOfFistNestedClass(List bodyDeclarations) { |
| for (int i= 0, n= bodyDeclarations.size(); i < n; i++) { |
| BodyDeclaration each= (BodyDeclaration)bodyDeclarations.get(i); |
| if (isNestedType(each)) |
| return i; |
| } |
| return -1; |
| } |
| |
| private static boolean isNestedType(BodyDeclaration each) { |
| if (!(each instanceof AbstractTypeDeclaration)) |
| return false; |
| return (each.getParent() instanceof AbstractTypeDeclaration); |
| } |
| |
| private AbstractTypeDeclaration createNewNestedClass(CompilationUnitRewrite rewrite, ITypeBinding[] parameters) throws CoreException { |
| final AST ast= fAnonymousInnerClassNode.getAST(); |
| final TypeDeclaration declaration= ast.newTypeDeclaration(); |
| declaration.setInterface(false); |
| declaration.setJavadoc(null); |
| declaration.modifiers().addAll(ASTNodeFactory.newModifiers(ast, createModifiersForNestedClass())); |
| declaration.setName(ast.newSimpleName(fClassName)); |
| TypeParameter parameter= null; |
| for (int index= 0; index < parameters.length; index++) { |
| parameter= ast.newTypeParameter(); |
| parameter.setName(ast.newSimpleName(parameters[index].getName())); |
| declaration.typeParameters().add(parameter); |
| } |
| setSuperType(declaration); |
| removeInitializationFromDeclaredFields(rewrite); |
| final String delimiter= StubUtility.getLineDelimiterUsed(fCu); |
| ITextFileBuffer buffer= null; |
| try { |
| buffer= RefactoringFileBuffers.acquire(fCu); |
| final IDocument document= buffer.getDocument(); |
| IBinding[] bindings= getUsedLocalVariables(); |
| for (final Iterator iterator= fAnonymousInnerClassNode.bodyDeclarations().iterator(); iterator.hasNext();) { |
| final BodyDeclaration body= (BodyDeclaration) iterator.next(); |
| declaration.bodyDeclarations().add(createBodyDeclaration(rewrite, document, bindings, body, delimiter)); |
| } |
| } finally { |
| if (buffer != null) |
| RefactoringFileBuffers.release(fCu); |
| } |
| createFieldsForAccessedLocals(rewrite, declaration); |
| createNewConstructorIfNeeded(rewrite, declaration); |
| if (fSettings.createComments) { |
| String[] parameterNames= new String[parameters.length]; |
| for (int index= 0; index < parameterNames.length; index++) { |
| parameterNames[index]= parameters[index].getName(); |
| } |
| String string= CodeGeneration.getTypeComment(rewrite.getCu(), fClassName, parameterNames, StubUtility.getLineDelimiterUsed(rewrite.getCu())); |
| if (string != null) { |
| Javadoc javadoc= (Javadoc) rewrite.getASTRewrite().createStringPlaceholder(string, ASTNode.JAVADOC); |
| declaration.setJavadoc(javadoc); |
| } |
| } |
| return declaration; |
| } |
| |
| private ASTNode createBodyDeclaration(CompilationUnitRewrite rewriter, IDocument document, IBinding[] bindings, BodyDeclaration body, String delimiter) { |
| final ASTRewrite rewrite= ASTRewrite.create(rewriter.getAST()); |
| final ITrackedNodePosition position= rewrite.track(body); |
| final IBinding[] binding= { null}; |
| final ASTNode[] newNode= { null}; |
| List excludedFields= new ArrayList(); |
| final AST ast= fAnonymousInnerClassNode.getAST(); |
| final IJavaProject javaProject= fCu.getJavaProject(); |
| final IJavaProject project= javaProject; |
| for (int index= 0; index < bindings.length; index++) { |
| binding[0]= bindings[index]; |
| String name= binding[0].getName(); |
| String fieldName= name; |
| String oldName= name; |
| if (binding[0] instanceof IVariableBinding) { |
| IVariableBinding variable= (IVariableBinding) binding[0]; |
| if (!variable.isEnumConstant()) { |
| name= NamingConventions.removePrefixAndSuffixForLocalVariableName(project, name); |
| if (name.equals(oldName)) |
| name= NamingConventions.removePrefixAndSuffixForArgumentName(project, name); |
| fieldName= NamingConventions.suggestFieldNames(project, "", name, 0, Flags.AccPrivate, (String[]) excludedFields.toArray(new String[excludedFields.size()]))[0]; //$NON-NLS-1$ |
| excludedFields.add(fieldName); |
| if (fSettings.useKeywordThis) { |
| FieldAccess access= ast.newFieldAccess(); |
| access.setExpression(ast.newThisExpression()); |
| access.setName(ast.newSimpleName(fieldName)); |
| newNode[0]= access; |
| } else |
| newNode[0]= ast.newSimpleName(fieldName); |
| } else |
| newNode[0]= ast.newSimpleName(fieldName); |
| } |
| body.accept(new ASTVisitor() { |
| |
| public boolean visit(SimpleName node) { |
| IBinding resolved= node.resolveBinding(); |
| if (binding[0].equals(resolved)) |
| rewrite.replace(node, ASTNode.copySubtree(ast, newNode[0]), null); |
| return false; |
| } |
| |
| }); |
| } |
| final IDocument buffer= new Document(document.get()); |
| final Map options= javaProject.getOptions(true); |
| final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(javaProject); |
| final TextEdit edit= rewrite.rewriteAST(buffer, options); |
| try { |
| edit.apply(buffer, TextEdit.UPDATE_REGIONS); |
| final String trimmed= Strings.trimIndentation(buffer.get(position.getStartPosition(), position.getLength()), settings.tabWidth, settings.indentWidth, false); |
| return rewriter.getASTRewrite().createStringPlaceholder(trimmed, ASTNode.METHOD_DECLARATION); |
| } catch (MalformedTreeException exception) { |
| JavaPlugin.log(exception); |
| } catch (BadLocationException exception) { |
| JavaPlugin.log(exception); |
| } |
| return null; |
| } |
| |
| private void removeInitializationFromDeclaredFields(CompilationUnitRewrite rewrite) { |
| for (Iterator iter= getFieldsToInitializeInConstructor().iterator(); iter.hasNext();) { |
| VariableDeclarationFragment fragment= (VariableDeclarationFragment) iter.next(); |
| Assert.isNotNull(fragment.getInitializer()); |
| rewrite.getASTRewrite().remove(fragment.getInitializer(), null); |
| } |
| } |
| |
| private void createFieldsForAccessedLocals(CompilationUnitRewrite rewrite, AbstractTypeDeclaration declaration) { |
| final IVariableBinding[] bindings= getUsedLocalVariables(); |
| final IJavaProject project= rewrite.getCu().getJavaProject(); |
| List excluded= new ArrayList(); |
| final AST ast= fAnonymousInnerClassNode.getAST(); |
| for (int index= 0; index < bindings.length; index++) { |
| VariableDeclarationFragment fragment= ast.newVariableDeclarationFragment(); |
| fragment.setExtraDimensions(0); |
| fragment.setInitializer(null); |
| String name= bindings[index].getName(); |
| String oldName= name; |
| name= NamingConventions.removePrefixAndSuffixForLocalVariableName(project, name); |
| if (name.equals(oldName)) |
| name= NamingConventions.removePrefixAndSuffixForArgumentName(project, name); |
| name= NamingConventions.suggestFieldNames(project, "", name, 0, Flags.AccPrivate, (String[]) excluded.toArray(new String[excluded.size()]))[0]; //$NON-NLS-1$ |
| fragment.setName(ast.newSimpleName(name)); |
| excluded.add(name); |
| FieldDeclaration field= ast.newFieldDeclaration(fragment); |
| field.setType(rewrite.getImportRewrite().addImport(bindings[index].getType(), ast)); |
| field.modifiers().addAll(ASTNodeFactory.newModifiers(ast, Modifier.PRIVATE | Modifier.FINAL)); |
| declaration.bodyDeclarations().add(findIndexOfLastField(declaration.bodyDeclarations()) + 1, field); |
| if (fSettings.createComments) { |
| try { |
| String string= CodeGeneration.getFieldComment(rewrite.getCu(), bindings[index].getType().getName(), name, StubUtility.getLineDelimiterUsed(rewrite.getCu())); |
| if (string != null) { |
| Javadoc javadoc= (Javadoc) rewrite.getASTRewrite().createStringPlaceholder(string, ASTNode.JAVADOC); |
| field.setJavadoc(javadoc); |
| } |
| } catch (CoreException exception) { |
| JavaPlugin.log(exception); |
| } |
| } |
| } |
| } |
| |
| private IVariableBinding[] getUsedLocalVariables() { |
| final Set result= new HashSet(0); |
| fAnonymousInnerClassNode.accept(createTempUsageFinder(result)); |
| return (IVariableBinding[])result.toArray(new IVariableBinding[result.size()]); |
| } |
| |
| private ASTVisitor createTempUsageFinder(final Set result) { |
| return new ASTVisitor() { |
| public boolean visit(SimpleName node) { |
| IBinding binding= node.resolveBinding(); |
| if (ConvertAnonymousToNestedRefactoring.this.isBindingToTemp(binding)) |
| result.add(binding); |
| return true; |
| } |
| }; |
| } |
| |
| private boolean isBindingToTemp(IBinding binding) { |
| if (!(binding instanceof IVariableBinding)) |
| return false; |
| final IVariableBinding variable= (IVariableBinding) binding; |
| if (variable.isField()) |
| return false; |
| if (!Modifier.isFinal(binding.getModifiers())) |
| return false; |
| ASTNode declaringNode= fCompilationUnitNode.findDeclaringNode(binding); |
| if (declaringNode == null) |
| return false; |
| if (ASTNodes.isParent(declaringNode, fAnonymousInnerClassNode)) |
| return false; |
| return true; |
| } |
| |
| private void createNewConstructorIfNeeded(CompilationUnitRewrite rewrite, AbstractTypeDeclaration declaration) throws JavaModelException { |
| IVariableBinding[] bindings= getUsedLocalVariables(); |
| |
| if (((ClassInstanceCreation) fAnonymousInnerClassNode.getParent()).arguments().isEmpty() && bindings.length == 0) |
| return; |
| |
| final AST ast= fAnonymousInnerClassNode.getAST(); |
| MethodDeclaration newConstructor= ast.newMethodDeclaration(); |
| newConstructor.setConstructor(true); |
| newConstructor.setExtraDimensions(0); |
| newConstructor.setJavadoc(null); |
| newConstructor.modifiers().addAll(ASTNodeFactory.newModifiers(ast, fVisibility)); |
| newConstructor.setName(ast.newSimpleName(fClassName)); |
| List paramNames= new ArrayList(); |
| addParametersToNewConstructor(newConstructor, rewrite, paramNames); |
| int paramCount= newConstructor.parameters().size(); |
| |
| addParametersForLocalsUsedInInnerClass(rewrite, bindings, newConstructor, paramNames); |
| |
| Block body= ast.newBlock(); |
| if (paramCount > 0) { |
| SuperConstructorInvocation superConstructorInvocation= ast.newSuperConstructorInvocation(); |
| for (int i= 0; i < paramCount; i++) { |
| SingleVariableDeclaration param= (SingleVariableDeclaration) newConstructor.parameters().get(i); |
| superConstructorInvocation.arguments().add(ast.newSimpleName(param.getName().getIdentifier())); |
| } |
| body.statements().add(superConstructorInvocation); |
| } |
| final IJavaProject project= fCu.getJavaProject(); |
| List excludedFields= new ArrayList(); |
| List excludedParams= new ArrayList(); |
| for (int index= 0; index < bindings.length; index++) { |
| String name= bindings[index].getName(); |
| String fieldName= name; |
| String paramName= name; |
| String oldName= name; |
| name= NamingConventions.removePrefixAndSuffixForLocalVariableName(project, name); |
| if (name.equals(oldName)) |
| name= NamingConventions.removePrefixAndSuffixForArgumentName(project, name); |
| fieldName= NamingConventions.suggestFieldNames(project, "", name, 0, Flags.AccPrivate, (String[]) excludedFields.toArray(new String[excludedFields.size()]))[0]; //$NON-NLS-1$ |
| excludedFields.add(fieldName); |
| paramName= NamingConventions.suggestArgumentNames(project, "", name, 0, (String[]) excludedParams.toArray(new String[excludedParams.size()]))[0]; //$NON-NLS-1$ |
| excludedParams.add(paramName); |
| Assignment assignmentExpression= ast.newAssignment(); |
| assignmentExpression.setOperator(Assignment.Operator.ASSIGN); |
| if (fSettings.useKeywordThis || fieldName.equals(paramName)) { |
| FieldAccess access= ast.newFieldAccess(); |
| access.setExpression(ast.newThisExpression()); |
| access.setName(ast.newSimpleName(fieldName)); |
| assignmentExpression.setLeftHandSide(access); |
| } else |
| assignmentExpression.setLeftHandSide(ast.newSimpleName(fieldName)); |
| assignmentExpression.setRightHandSide(ast.newSimpleName(paramName)); |
| ExpressionStatement assignmentStatement= ast.newExpressionStatement(assignmentExpression); |
| body.statements().add(assignmentStatement); |
| } |
| |
| addFieldInitialization(rewrite, body); |
| |
| newConstructor.setBody(body); |
| |
| addExceptionsToNewConstructor(newConstructor); |
| declaration.bodyDeclarations().add(1 + bindings.length + findIndexOfLastField(fAnonymousInnerClassNode.bodyDeclarations()), newConstructor); |
| if (fSettings.createComments) { |
| try { |
| String string= CodeGeneration.getMethodComment(rewrite.getCu(), fClassName, fClassName, (String[]) paramNames.toArray(new String[paramNames.size()]), new String[0], null, new String[0], null, StubUtility.getLineDelimiterUsed(rewrite.getCu())); |
| if (string != null) { |
| Javadoc javadoc= (Javadoc) rewrite.getASTRewrite().createStringPlaceholder(string, ASTNode.JAVADOC); |
| newConstructor.setJavadoc(javadoc); |
| } |
| } catch (CoreException exception) { |
| JavaPlugin.log(exception); |
| } |
| } |
| } |
| |
| private void addFieldInitialization(CompilationUnitRewrite rewrite, Block constructorBody) { |
| final IJavaProject project= rewrite.getCu().getJavaProject(); |
| List excluded= new ArrayList(); |
| final AST ast= fAnonymousInnerClassNode.getAST(); |
| for (Iterator iter= getFieldsToInitializeInConstructor().iterator(); iter.hasNext();) { |
| VariableDeclarationFragment fragment= (VariableDeclarationFragment) iter.next(); |
| Assignment assignmentExpression= ast.newAssignment(); |
| assignmentExpression.setOperator(Assignment.Operator.ASSIGN); |
| String name= fragment.getName().getIdentifier(); |
| String oldName= name; |
| name= NamingConventions.removePrefixAndSuffixForLocalVariableName(project, name); |
| if (name.equals(oldName)) |
| name= NamingConventions.removePrefixAndSuffixForArgumentName(project, name); |
| name= NamingConventions.suggestFieldNames(project, "", name, 0, Flags.AccPrivate, (String[]) excluded.toArray(new String[excluded.size()]))[0]; //$NON-NLS-1$ |
| if (fSettings.useKeywordThis) { |
| FieldAccess access= ast.newFieldAccess(); |
| access.setExpression(ast.newThisExpression()); |
| access.setName(ast.newSimpleName(name)); |
| assignmentExpression.setLeftHandSide(access); |
| } else |
| assignmentExpression.setLeftHandSide(ast.newSimpleName(name)); |
| excluded.add(name); |
| Expression rhs= (Expression) rewrite.getASTRewrite().createCopyTarget(fragment.getInitializer()); |
| assignmentExpression.setRightHandSide(rhs); |
| ExpressionStatement assignmentStatement= ast.newExpressionStatement(assignmentExpression); |
| constructorBody.statements().add(assignmentStatement); |
| } |
| } |
| |
| // live List of VariableDeclarationFragments |
| private List getFieldsToInitializeInConstructor() { |
| List result= new ArrayList(0); |
| for (Iterator iter= fAnonymousInnerClassNode.bodyDeclarations().iterator(); iter.hasNext(); ) { |
| BodyDeclaration element= (BodyDeclaration)iter.next(); |
| if (!(element instanceof FieldDeclaration)) |
| continue; |
| FieldDeclaration field= (FieldDeclaration)element; |
| for (Iterator fragmentIter= field.fragments().iterator(); fragmentIter.hasNext(); ) { |
| VariableDeclarationFragment fragment= (VariableDeclarationFragment)fragmentIter.next(); |
| if (isToBeInitializerInConstructor(fragment)) |
| result.add(fragment); |
| } |
| } |
| return result; |
| } |
| |
| private boolean isToBeInitializerInConstructor(VariableDeclarationFragment fragment) { |
| if (fragment.getInitializer() == null) |
| return false; |
| return areLocalsUsedIn(fragment.getInitializer()); |
| } |
| |
| private boolean areLocalsUsedIn(Expression fieldInitializer) { |
| Set localsUsed= new HashSet(0); |
| fieldInitializer.accept(createTempUsageFinder(localsUsed)); |
| return !localsUsed.isEmpty(); |
| } |
| |
| private void addParametersForLocalsUsedInInnerClass(CompilationUnitRewrite rewrite, IVariableBinding[] usedLocals, MethodDeclaration newConstructor, List params) { |
| List excluded= new ArrayList(); |
| for (int index= 0; index < usedLocals.length; index++) { |
| SingleVariableDeclaration declaration= createNewParamDeclarationNode(usedLocals[index].getName(), usedLocals[index].getType(), rewrite, (String[]) excluded.toArray(new String[excluded.size()])); |
| newConstructor.parameters().add(declaration); |
| final String identifier= declaration.getName().getIdentifier(); |
| excluded.add(identifier); |
| params.add(identifier); |
| } |
| } |
| |
| private IMethodBinding getSuperConstructorBinding() { |
| //workaround for missing java core functionality - finding a |
| // super constructor for an anonymous class creation |
| IMethodBinding anonConstr= ((ClassInstanceCreation) fAnonymousInnerClassNode.getParent()).resolveConstructorBinding(); |
| if (anonConstr == null) |
| return null; |
| ITypeBinding superClass= anonConstr.getDeclaringClass().getSuperclass(); |
| IMethodBinding[] superMethods= superClass.getDeclaredMethods(); |
| for (int i= 0; i < superMethods.length; i++) { |
| IMethodBinding superMethod= superMethods[i]; |
| if (superMethod.isConstructor() && parameterTypesMatch(superMethod, anonConstr)) |
| return superMethod; |
| } |
| Assert.isTrue(false);//there's no way - it must be there |
| return null; |
| } |
| |
| private static boolean parameterTypesMatch(IMethodBinding m1, IMethodBinding m2) { |
| ITypeBinding[] m1Params= m1.getParameterTypes(); |
| ITypeBinding[] m2Params= m2.getParameterTypes(); |
| if (m1Params.length != m2Params.length) |
| return false; |
| for (int i= 0; i < m2Params.length; i++) { |
| if (!m1Params[i].equals(m2Params[i])) |
| return false; |
| } |
| return true; |
| } |
| |
| private void addExceptionsToNewConstructor(MethodDeclaration newConstructor) { |
| IMethodBinding constructorBinding= getSuperConstructorBinding(); |
| if (constructorBinding == null) |
| return; |
| ITypeBinding[] exceptions= constructorBinding.getExceptionTypes(); |
| for (int i= 0; i < exceptions.length; i++) { |
| Name exceptionTypeName= fAnonymousInnerClassNode.getAST().newName(Bindings.getNameComponents(exceptions[i])); |
| newConstructor.thrownExceptions().add(exceptionTypeName); |
| } |
| } |
| |
| private void addParametersToNewConstructor(MethodDeclaration newConstructor, CompilationUnitRewrite rewrite, List params) throws JavaModelException { |
| IMethodBinding constructorBinding= getSuperConstructorBinding(); |
| if (constructorBinding == null) |
| return; |
| ITypeBinding[] paramTypes= constructorBinding.getParameterTypes(); |
| IMethod method= (IMethod) constructorBinding.getJavaElement(); |
| if (method == null) |
| return; |
| String[] parameterNames= method.getParameterNames(); |
| final List excluded= new ArrayList(); |
| for (int index= 0; index < parameterNames.length; index++) { |
| SingleVariableDeclaration declaration= createNewParamDeclarationNode(parameterNames[index], paramTypes[index], rewrite, (String[]) excluded.toArray(new String[excluded.size()])); |
| newConstructor.parameters().add(declaration); |
| final String identifier= declaration.getName().getIdentifier(); |
| excluded.add(identifier); |
| params.add(identifier); |
| } |
| } |
| |
| private SingleVariableDeclaration createNewParamDeclarationNode(String paramName, ITypeBinding paramType, CompilationUnitRewrite rewrite, String[] excluded) { |
| SingleVariableDeclaration param= fAnonymousInnerClassNode.getAST().newSingleVariableDeclaration(); |
| param.setExtraDimensions(0); |
| param.setInitializer(null); |
| final IJavaProject project= rewrite.getCu().getJavaProject(); |
| String name= NamingConventions.removePrefixAndSuffixForLocalVariableName(project, paramName); |
| if (name.equals(paramName)) |
| name= NamingConventions.removePrefixAndSuffixForArgumentName(project, paramName); |
| name= NamingConventions.suggestArgumentNames(project, "", name, 0, excluded)[0]; //$NON-NLS-1$ |
| param.setName(fAnonymousInnerClassNode.getAST().newSimpleName(name)); |
| param.setType(rewrite.getImportRewrite().addImport(paramType, fAnonymousInnerClassNode.getAST())); |
| return param; |
| } |
| |
| private void setSuperType(TypeDeclaration declaration) throws JavaModelException { |
| ClassInstanceCreation classInstanceCreation= (ClassInstanceCreation) fAnonymousInnerClassNode.getParent(); |
| ITypeBinding binding= classInstanceCreation.resolveTypeBinding(); |
| if (binding == null) |
| return; |
| Type newType= (Type) ASTNode.copySubtree(fAnonymousInnerClassNode.getAST(), classInstanceCreation.getType()); |
| if (binding.getSuperclass().getQualifiedName().equals("java.lang.Object")) { //$NON-NLS-1$ |
| Assert.isTrue(binding.getInterfaces().length <= 1); |
| if (binding.getInterfaces().length == 0) |
| return; |
| declaration.superInterfaceTypes().add(0, newType); |
| } else { |
| declaration.setSuperclassType(newType); |
| } |
| } |
| |
| private ITypeBinding getSuperTypeBinding() { |
| ITypeBinding types= fAnonymousInnerClassNode.resolveBinding(); |
| ITypeBinding[] interfaces= types.getInterfaces(); |
| if (interfaces.length > 0) |
| return interfaces[0]; |
| else |
| return types.getSuperclass(); |
| } |
| |
| private int createModifiersForNestedClass() { |
| int flags= fVisibility; |
| if (fDeclareFinal) |
| flags|= Modifier.FINAL; |
| if (mustInnerClassBeStatic() || fDeclareStatic) |
| flags|= Modifier.STATIC; |
| return flags; |
| } |
| |
| public boolean mustInnerClassBeStatic() { |
| ITypeBinding typeBinding = ((AbstractTypeDeclaration) ASTNodes.getParent(fAnonymousInnerClassNode, AbstractTypeDeclaration.class)).resolveBinding(); |
| ASTNode current = fAnonymousInnerClassNode.getParent(); |
| boolean ans = false; |
| while(current != null) { |
| switch(current.getNodeType()) { |
| case ASTNode.ANONYMOUS_CLASS_DECLARATION: |
| { |
| AnonymousClassDeclaration enclosingAnonymousClassDeclaration= (AnonymousClassDeclaration)current; |
| ITypeBinding binding= enclosingAnonymousClassDeclaration.resolveBinding(); |
| if (binding != null && Bindings.isSuperType(typeBinding, binding.getSuperclass())) { |
| return false; |
| } |
| break; |
| } |
| case ASTNode.FIELD_DECLARATION: |
| { |
| FieldDeclaration enclosingFieldDeclaration= (FieldDeclaration)current; |
| if (Modifier.isStatic(enclosingFieldDeclaration.getModifiers())) { |
| ans = true; |
| } |
| break; |
| } |
| case ASTNode.METHOD_DECLARATION: |
| { |
| MethodDeclaration enclosingMethodDeclaration = (MethodDeclaration)current; |
| if (Modifier.isStatic(enclosingMethodDeclaration.getModifiers())) { |
| ans = true; |
| } |
| break; |
| } |
| case ASTNode.TYPE_DECLARATION: |
| { |
| return ans; |
| } |
| } |
| current = current.getParent(); |
| } |
| return ans; |
| } |
| |
| private static int findIndexOfLastField(List bodyDeclarations) { |
| for (int i= bodyDeclarations.size() - 1; i >= 0; i--) { |
| BodyDeclaration each= (BodyDeclaration)bodyDeclarations.get(i); |
| if (each instanceof FieldDeclaration) |
| return i; |
| } |
| return -1; |
| } |
| |
| public RefactoringStatus initialize(final RefactoringArguments arguments) { |
| fSelfInitializing= true; |
| if (arguments instanceof JavaRefactoringArguments) { |
| final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments; |
| final String handle= extended.getAttribute(JavaRefactoringDescriptor.ATTRIBUTE_INPUT); |
| if (handle != null) { |
| final IJavaElement element= JavaRefactoringDescriptor.handleToElement(extended.getProject(), handle, false); |
| if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT) |
| return createInputFatalStatus(element, ID_CONVERT_ANONYMOUS); |
| else { |
| fCu= (ICompilationUnit) element; |
| fSettings= JavaPreferencesSettings.getCodeGenerationSettings(fCu.getJavaProject()); |
| } |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptor.ATTRIBUTE_INPUT)); |
| final String name= extended.getAttribute(JavaRefactoringDescriptor.ATTRIBUTE_NAME); |
| if (name != null && !"".equals(name)) //$NON-NLS-1$ |
| fClassName= name; |
| else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptor.ATTRIBUTE_NAME)); |
| final String visibility= extended.getAttribute(ATTRIBUTE_VISIBILITY); |
| if (visibility != null && !"".equals(visibility)) {//$NON-NLS-1$ |
| int flag= 0; |
| try { |
| flag= Integer.parseInt(visibility); |
| } catch (NumberFormatException exception) { |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_VISIBILITY)); |
| } |
| fVisibility= flag; |
| } |
| final String selection= extended.getAttribute(JavaRefactoringDescriptor.ATTRIBUTE_SELECTION); |
| if (selection != null) { |
| int offset= -1; |
| int length= -1; |
| final StringTokenizer tokenizer= new StringTokenizer(selection); |
| if (tokenizer.hasMoreTokens()) |
| offset= Integer.valueOf(tokenizer.nextToken()).intValue(); |
| if (tokenizer.hasMoreTokens()) |
| length= Integer.valueOf(tokenizer.nextToken()).intValue(); |
| if (offset >= 0 && length >= 0) { |
| fSelectionStart= offset; |
| fSelectionLength= length; |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object[] { selection, JavaRefactoringDescriptor.ATTRIBUTE_SELECTION})); |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptor.ATTRIBUTE_SELECTION)); |
| final String declareStatic= extended.getAttribute(ATTRIBUTE_STATIC); |
| if (declareStatic != null) { |
| fDeclareStatic= Boolean.valueOf(declareStatic).booleanValue(); |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_STATIC)); |
| final String declareFinal= extended.getAttribute(ATTRIBUTE_FINAL); |
| if (declareFinal != null) { |
| fDeclareFinal= Boolean.valueOf(declareStatic).booleanValue(); |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_FINAL)); |
| } else |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments); |
| return new RefactoringStatus(); |
| } |
| } |