diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/PromoteTempToFieldRefactoring.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/PromoteTempToFieldRefactoring.java index 774f96e..56687ce 100644 --- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/PromoteTempToFieldRefactoring.java +++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/PromoteTempToFieldRefactoring.java @@ -2,14 +2,15 @@ * Copyright (c) 2000, 2014 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: + * Timo Kinnunen - Contribution for bug 432147 - [refactoring] Extract Constant displays error message on name of local variable * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.corext.refactoring.code; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -52,14 +53,15 @@ import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IExtendedModifier; 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.Initializer; 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.SimpleName; import org.eclipse.jdt.core.dom.Statement; import org.eclipse.jdt.core.dom.SwitchStatement; import org.eclipse.jdt.core.dom.Type; @@ -122,14 +124,15 @@ //------ settings ---------// private String fFieldName; private int fVisibility; /*see Modifier*/ private boolean fDeclareStatic; private boolean fDeclareFinal; private int fInitializeIn; /*see INITIALIZE_IN_* constraints */ + private boolean fInitializeAsConstantIfPossible= false; //------ fields used for computations ---------// private CompilationUnit fCompilationUnitNode; private VariableDeclaration fTempDeclarationNode; //------ analysis ---------// private boolean fInitializerUsesLocalTypes; private boolean fTempTypeUsesClassTypeVariables; @@ -253,37 +256,50 @@ } public boolean canEnableSettingFinal(){ if (fInitializeIn == INITIALIZE_IN_CONSTRUCTOR) return canEnableSettingDeclareInConstructors() && ! tempHasAssignmentsOtherThanInitialization(); else if (fInitializeIn == INITIALIZE_IN_FIELD) return canEnableSettingDeclareInFieldDeclaration() && ! tempHasAssignmentsOtherThanInitialization(); - else if (getMethodDeclaration().isConstructor()) + else if (isDeclaredInConstructor() || isDeclaredInInitializer()) return !tempHasAssignmentsOtherThanInitialization(); else return false; } private boolean tempHasAssignmentsOtherThanInitialization() { TempAssignmentFinder assignmentFinder= new TempAssignmentFinder(fTempDeclarationNode); fCompilationUnitNode.accept(assignmentFinder); return assignmentFinder.hasAssignments(); } public boolean canEnableSettingDeclareInConstructors(){ return ! fDeclareStatic && ! fInitializerUsesLocalTypes && - ! getMethodDeclaration().isConstructor() && + ! isDeclaredInConstructor() && ! isDeclaredInAnonymousClass() && ! isTempDeclaredInStaticMethod() && tempHasInitializer(); } + private boolean isDeclaredInConstructor() { + BodyDeclaration methodDeclaration= getBodyDeclaration(); + if(methodDeclaration instanceof MethodDeclaration) { + return ((MethodDeclaration) methodDeclaration).isConstructor(); + } + return false; + } + + private boolean isDeclaredInInitializer() { + BodyDeclaration initializerDeclaration= getBodyDeclaration(); + return initializerDeclaration instanceof Initializer; + } + public boolean canEnableSettingDeclareInMethod(){ - return ! fDeclareFinal && + return (! fDeclareFinal || isDeclaredInInitializer()) && tempHasInitializer(); } private boolean tempHasInitializer() { return getTempInitializer() != null; } public boolean canEnableSettingDeclareInFieldDeclaration(){ @@ -291,19 +307,19 @@ } private Expression getTempInitializer() { return fTempDeclarationNode.getInitializer(); } private boolean isTempDeclaredInStaticMethod() { - return Modifier.isStatic(getMethodDeclaration().getModifiers()); + return Modifier.isStatic(getBodyDeclaration().getModifiers()); } - private MethodDeclaration getMethodDeclaration(){ - return (MethodDeclaration)ASTNodes.getParent(fTempDeclarationNode, MethodDeclaration.class); + private BodyDeclaration getBodyDeclaration(){ + return (BodyDeclaration)ASTNodes.getParent(fTempDeclarationNode, BodyDeclaration.class); } private boolean isDeclaredInAnonymousClass() { return null != ASTNodes.getParent(fTempDeclarationNode, AnonymousClassDeclaration.class); } /* @@ -318,15 +334,15 @@ return result; initAST(pm); if (fTempDeclarationNode == null) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.PromoteTempToFieldRefactoring_select_declaration); - if (! Checks.isDeclaredIn(fTempDeclarationNode, MethodDeclaration.class)) + if (! Checks.isDeclaredIn(fTempDeclarationNode, MethodDeclaration.class) && !Checks.isDeclaredIn(fTempDeclarationNode, Initializer.class) ) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.PromoteTempToFieldRefactoring_only_declared_in_methods); if (isMethodParameter()) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.PromoteTempToFieldRefactoring_method_parameters); if (isTempAnExceptionInCatchBlock()) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.PromoteTempToFieldRefactoring_exceptions); @@ -344,22 +360,31 @@ if (!fSelfInitializing) initializeDefaults(); return result; } private void initializeDefaults() { fVisibility= Modifier.PRIVATE; - fDeclareStatic= Modifier.isStatic(getMethodDeclaration().getModifiers()); - fDeclareFinal= false; - if (canEnableSettingDeclareInMethod()) - fInitializeIn= INITIALIZE_IN_METHOD; - else if (canEnableSettingDeclareInFieldDeclaration()) - fInitializeIn= INITIALIZE_IN_FIELD; - else if (canEnableSettingDeclareInConstructors()) - fInitializeIn= INITIALIZE_IN_CONSTRUCTOR; + fDeclareStatic= Modifier.isStatic(getBodyDeclaration().getModifiers()); + if (fInitializeAsConstantIfPossible) { + if(canEnableSettingDeclareInFieldDeclaration()) + fInitializeIn= INITIALIZE_IN_FIELD; + else if (canEnableSettingDeclareInMethod()) + fInitializeIn= INITIALIZE_IN_METHOD; + else if (canEnableSettingDeclareInConstructors()) + fInitializeIn= INITIALIZE_IN_CONSTRUCTOR; + } else { + if (canEnableSettingDeclareInMethod()) + fInitializeIn= INITIALIZE_IN_METHOD; + else if (canEnableSettingDeclareInFieldDeclaration()) + fInitializeIn= INITIALIZE_IN_FIELD; + else if (canEnableSettingDeclareInConstructors()) + fInitializeIn= INITIALIZE_IN_CONSTRUCTOR; + } + fDeclareFinal= fInitializeAsConstantIfPossible && canEnableSettingFinal(); } public String[] guessFieldNames() { String rawTempName= StubUtility.getBaseName(fTempDeclarationNode.resolveBinding(), fCu.getJavaProject()); String[] excludedNames= getNamesOfFieldsInDeclaringType(); int dim= ASTNodes.getDimensions(fTempDeclarationNode); return StubUtility.getFieldNameSuggestions(fCu.getJavaProject(), rawTempName, dim, getModifiers(), excludedNames); @@ -397,15 +422,15 @@ } private void checkTempInitializerForLocalTypeUsage() { Expression initializer= fTempDeclarationNode.getInitializer(); if (initializer == null) return; - IMethodBinding declaringMethodBinding= getMethodDeclaration().resolveBinding(); + IMethodBinding declaringMethodBinding= getMethodBinding(); ITypeBinding[] methodTypeParameters= declaringMethodBinding == null ? new ITypeBinding[0] : declaringMethodBinding.getTypeParameters(); LocalTypeAndVariableUsageAnalyzer localTypeAnalyer= new LocalTypeAndVariableUsageAnalyzer(methodTypeParameters); initializer.accept(localTypeAnalyer); fInitializerUsesLocalTypes= ! localTypeAnalyer.getUsageOfEnclosingNodes().isEmpty(); } private RefactoringStatus checkTempTypeForLocalTypeUsage(){ @@ -413,24 +438,29 @@ if (vds == null) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.PromoteTempToFieldRefactoring_cannot_promote); Type type= vds.getType(); ITypeBinding binding= type.resolveBinding(); if (binding == null) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.PromoteTempToFieldRefactoring_cannot_promote); - IMethodBinding declaringMethodBinding= getMethodDeclaration().resolveBinding(); + IMethodBinding declaringMethodBinding= getMethodBinding(); ITypeBinding[] methodTypeParameters= declaringMethodBinding == null ? new ITypeBinding[0] : declaringMethodBinding.getTypeParameters(); LocalTypeAndVariableUsageAnalyzer analyzer= new LocalTypeAndVariableUsageAnalyzer(methodTypeParameters); type.accept(analyzer); boolean usesLocalTypes= ! analyzer.getUsageOfEnclosingNodes().isEmpty(); fTempTypeUsesClassTypeVariables= analyzer.getClassTypeVariablesUsed(); if (usesLocalTypes) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.PromoteTempToFieldRefactoring_uses_type_declared_locally); return null; } + + private IMethodBinding getMethodBinding() { + BodyDeclaration methodDeclaration= getBodyDeclaration(); + return methodDeclaration != null && methodDeclaration instanceof MethodDeclaration ? ((MethodDeclaration) methodDeclaration).resolveBinding() : null; + } private VariableDeclarationStatement getTempDeclarationStatement() { return (VariableDeclarationStatement) ASTNodes.getParent(fTempDeclarationNode, VariableDeclarationStatement.class); } private boolean isTempAnExceptionInCatchBlock() { return (fTempDeclarationNode.getParent() instanceof CatchClause); @@ -466,15 +496,15 @@ pm.done(); } } private RefactoringStatus checkClashesInConstructors() { Assert.isTrue(fInitializeIn == INITIALIZE_IN_CONSTRUCTOR); Assert.isTrue(!isDeclaredInAnonymousClass()); - final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) getMethodDeclaration().getParent(); + final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) getBodyDeclaration().getParent(); if (declaration instanceof TypeDeclaration) { MethodDeclaration[] methods= ((TypeDeclaration) declaration).getMethods(); for (int i= 0; i < methods.length; i++) { MethodDeclaration method= methods[i]; if (!method.isConstructor()) continue; NameCollector nameCollector= new NameCollector(method) { @@ -509,15 +539,15 @@ } } } return null; } private FieldDeclaration[] getFieldDeclarations() { - List bodyDeclarations= ASTNodes.getBodyDeclarations(getMethodDeclaration().getParent()); + List bodyDeclarations= ASTNodes.getBodyDeclarations(getBodyDeclaration().getParent()); List fields= new ArrayList(1); for (Iterator iter= bodyDeclarations.iterator(); iter.hasNext();) { Object each= iter.next(); if (each instanceof FieldDeclaration) fields.add((FieldDeclaration) each); } return fields.toArray(new FieldDeclaration[fields.size()]); @@ -575,15 +605,15 @@ rewrite.replace(occurence, newName, null); } } } private void addInitializersToConstructors(ASTRewrite rewrite) throws CoreException { Assert.isTrue(! isDeclaredInAnonymousClass()); - final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration)getMethodDeclaration().getParent(); + final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration)getBodyDeclaration().getParent(); final MethodDeclaration[] constructors= getAllConstructors(declaration); if (constructors.length == 0) { AST ast= rewrite.getAST(); MethodDeclaration newConstructor= ast.newMethodDeclaration(); newConstructor.setConstructor(true); newConstructor.modifiers().addAll(ast.newModifiers(declaration.getModifiers() & ModifierRewrite.VISIBILITY_MODIFIERS)); newConstructor.setName(ast.newSimpleName(declaration.getName().getIdentifier())); @@ -817,15 +847,15 @@ rewrite.remove(fragment, null); if (fragments.size() == 1) rewrite.remove(tempDeclarationStatement, null); } private void addFieldDeclaration(ASTRewrite rewrite) { FieldDeclaration[] fields= getFieldDeclarations(); - ASTNode parent= getMethodDeclaration().getParent(); + ASTNode parent= getBodyDeclaration().getParent(); ChildListPropertyDescriptor descriptor= ASTNodes.getBodyDeclarationsProperty(parent); int insertIndex; if (fields.length == 0) insertIndex= 0; else insertIndex= ASTNodes.getBodyDeclarations(parent).indexOf(fields[fields.length - 1]) + 1; @@ -979,8 +1009,12 @@ return new RefactoringStatus(); } public void setLinkedProposalModel(LinkedProposalModel model) { fLinkedProposalModel= model; } + + public void setInitializeAsConstantIfPossible(boolean value) { + fInitializeAsConstantIfPossible = value; + } } diff --git a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/refactoringui.properties b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/refactoringui.properties index 0291a09..9d72a98 100644 --- a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/refactoringui.properties +++ b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/refactoringui.properties @@ -134,15 +134,15 @@ PullUpInputPage_pull_up1=Pull Up Methods PullUpInputPage_exception=An unexpected exception occurred. See the error log for more details ExtractTempAction_label=Extract &Local Variable... ExtractTempAction_extract_temp=Extract Local Variable ConvertLocalToField_label=Con&vert Local Variable to Field... -ConvertLocalToField_title=Convert Local Variable to Field +ConvertLocalToField_title=Convert Local Variable to Field or Constant ExtractConstantAction_label=Extr&act Constant... ExtractSuperTypeAction_label=Ex&tract Superclass... ExtractConstantAction_extract_constant=Extract Constant InlineTempAction_inline_temp=Inline Local Variable InlineTempAction_label=&Inline Local Variable... @@ -317,15 +317,15 @@ MoveInstanceMethodPage_Method_name=New &method name: MoveInstanceMethodPage_New_receiver=&New target for ''{0}'': MoveInstanceMethodPage_Receiver=Receiver MoveInstanceMethodPage_Type=Type MoveInstanceMethodPage_invalid_target=Target ''{0}'' is used in an assignment. PromoteTempInputPage_Field_declaration=Field decla&ration -PromoteTempInputPage_Current_method=&Current method +PromoteTempInputPage_Current_method=&Current block PromoteTempInputPage_constructors=C&lass constructors PromoteTempInputPage_Field_name=F&ield name: PromoteTempInputPage_Initialize=Initialize in PromoteTempInputPage_declare_static=&Declare field as \'static\' PromoteTempInputPage_declare_final=Decl&are field as \'final\' UseSupertypeInputPage_Select_supertype=Select the supertype to use diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/ExtractConstantAction.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/ExtractConstantAction.java index ff6a4c8..41fa011 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/ExtractConstantAction.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/ExtractConstantAction.java @@ -2,33 +2,49 @@ * 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: + * Timo Kinnunen - Contribution for bug 432147 - [refactoring] Extract Constant displays error message on name of local variable * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.ui.actions; import org.eclipse.jface.text.ITextSelection; import org.eclipse.ui.PlatformUI; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.SourceRange; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.VariableDeclaration; + +import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory; +import org.eclipse.jdt.internal.corext.dom.fragments.IASTFragment; import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester; import org.eclipse.jdt.internal.corext.refactoring.code.ExtractConstantRefactoring; +import org.eclipse.jdt.internal.corext.refactoring.code.PromoteTempToFieldRefactoring; +import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; +import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; import org.eclipse.jdt.ui.refactoring.RefactoringSaveHelper; import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; +import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jdt.internal.ui.actions.ActionUtil; import org.eclipse.jdt.internal.ui.actions.SelectionConverter; import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; import org.eclipse.jdt.internal.ui.javaeditor.JavaTextSelection; import org.eclipse.jdt.internal.ui.refactoring.ExtractConstantWizard; +import org.eclipse.jdt.internal.ui.refactoring.PromoteTempWizard; import org.eclipse.jdt.internal.ui.refactoring.RefactoringMessages; import org.eclipse.jdt.internal.ui.refactoring.actions.RefactoringStarter; /** * Extracts an expression into a constant field and replaces all occurrences of * the expression with the new constant. * @@ -80,11 +96,33 @@ /* (non-Javadoc) * Method declared on SelectionDispatchAction */ @Override public void run(ITextSelection selection) { if (!ActionUtil.isEditable(fEditor)) return; - ExtractConstantRefactoring refactoring= new ExtractConstantRefactoring(SelectionConverter.getInputAsCompilationUnit(fEditor), selection.getOffset(), selection.getLength()); + ICompilationUnit unit= SelectionConverter.getInputAsCompilationUnit(fEditor); + CompilationUnit cuNode= RefactoringASTParser.parseWithASTProvider(unit, true, null); + int selectionStart= selection.getOffset(); + int selectionLength= selection.getLength(); + ExtractConstantRefactoring refactoring= new ExtractConstantRefactoring(cuNode, selectionStart, selectionLength); + try { + CompilationUnitRewrite cuRewrite= new CompilationUnitRewrite(unit, cuNode); + SourceRange range= new SourceRange(selectionStart, selectionLength); + IASTFragment ast= ASTFragmentFactory.createFragmentForSourceRange(range, cuRewrite.getRoot(), unit); + ASTNode node= ast.getAssociatedNode(); + if (node instanceof SimpleName && node.getParent() instanceof VariableDeclaration) { + ICompilationUnit cunit= SelectionConverter.getInputAsCompilationUnit(fEditor); + PromoteTempToFieldRefactoring refactoring2= new PromoteTempToFieldRefactoring(cunit, selection.getOffset(), selection.getLength()); + refactoring2.setDeclareFinal(true); + refactoring2.setDeclareStatic(true); + refactoring2.setFieldName(refactoring.guessConstantName()); + refactoring2.setInitializeAsConstantIfPossible(true); + new RefactoringStarter().activate(new PromoteTempWizard(refactoring2), getShell(), RefactoringMessages.ConvertLocalToField_title, RefactoringSaveHelper.SAVE_NOTHING); + return; + } + } catch (JavaModelException e) { + JavaPlugin.log(e); + } new RefactoringStarter().activate(new ExtractConstantWizard(refactoring), getShell(), RefactoringMessages.ExtractConstantAction_extract_constant, RefactoringSaveHelper.SAVE_NOTHING); } }