| /******************************************************************************* |
| * Copyright (c) 2000, 2005 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.code; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.text.edits.MalformedTreeException; |
| import org.eclipse.text.edits.RangeMarker; |
| import org.eclipse.text.edits.TextEdit; |
| import org.eclipse.text.edits.TextEditGroup; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.TextUtilities; |
| |
| import org.eclipse.ltk.core.refactoring.Change; |
| import org.eclipse.ltk.core.refactoring.Refactoring; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IField; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| 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.BodyDeclaration; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.EnumConstantDeclaration; |
| 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.MethodInvocation; |
| import org.eclipse.jdt.core.dom.Modifier; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.ParenthesizedExpression; |
| import org.eclipse.jdt.core.dom.QualifiedName; |
| import org.eclipse.jdt.core.dom.SimpleName; |
| import org.eclipse.jdt.core.dom.Type; |
| import org.eclipse.jdt.core.dom.TypeDeclarationStatement; |
| import org.eclipse.jdt.core.dom.VariableDeclaration; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; |
| 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.corext.Assert; |
| import org.eclipse.jdt.internal.corext.Corext; |
| import org.eclipse.jdt.internal.corext.codemanipulation.ImportReferencesCollector; |
| 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.HierarchicalASTVisitor; |
| import org.eclipse.jdt.internal.corext.dom.NodeFinder; |
| import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory; |
| import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment; |
| import org.eclipse.jdt.internal.corext.refactoring.Checks; |
| import org.eclipse.jdt.internal.corext.refactoring.IRefactoringSearchRequestor; |
| 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.RefactoringStatusCodes; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationStateChange; |
| import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; |
| import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; |
| import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil; |
| import org.eclipse.jdt.internal.corext.refactoring.util.TightSourceRangeComputer; |
| import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
| import org.eclipse.jdt.internal.corext.util.Strings; |
| |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| |
| public class InlineConstantRefactoring extends Refactoring { |
| |
| private static class InlineTargetCompilationUnit { |
| |
| private static class InitializerTraversal extends HierarchicalASTVisitor { |
| |
| private static boolean areInSameType(ASTNode one, ASTNode other) { |
| ASTNode onesContainer= getContainingTypeDeclaration(one); |
| ASTNode othersContainer= getContainingTypeDeclaration(other); |
| |
| if (onesContainer == null || othersContainer == null) |
| return false; |
| |
| ITypeBinding onesContainerBinding= getTypeBindingForTypeDeclaration(onesContainer); |
| ITypeBinding othersContainerBinding= getTypeBindingForTypeDeclaration(othersContainer); |
| |
| Assert.isNotNull(onesContainerBinding); |
| Assert.isNotNull(othersContainerBinding); |
| |
| String onesKey= onesContainerBinding.getKey(); |
| String othersKey= othersContainerBinding.getKey(); |
| |
| if (onesKey == null || othersKey == null) |
| return false; |
| |
| return onesKey.equals(othersKey); |
| } |
| |
| private static boolean isStaticAccess(SimpleName memberName) { |
| IBinding binding= memberName.resolveBinding(); |
| Assert.isTrue(binding instanceof IVariableBinding || binding instanceof IMethodBinding || binding instanceof ITypeBinding); |
| |
| if (binding instanceof ITypeBinding) |
| return true; |
| |
| if (binding instanceof IVariableBinding) |
| return ((IVariableBinding) binding).isField(); |
| |
| int modifiers= binding.getModifiers(); |
| return Modifier.isStatic(modifiers); |
| } |
| |
| private static ASTNode getContainingTypeDeclaration(ASTNode node) { |
| while (node != null && !(node instanceof AbstractTypeDeclaration) && !(node instanceof AnonymousClassDeclaration)) { |
| node= node.getParent(); |
| } |
| return node; |
| } |
| |
| private static ITypeBinding getTypeBindingForTypeDeclaration(ASTNode declaration) { |
| if (declaration instanceof AnonymousClassDeclaration) |
| return ((AnonymousClassDeclaration) declaration).resolveBinding(); |
| |
| if (declaration instanceof AbstractTypeDeclaration) |
| return ((AbstractTypeDeclaration) declaration).resolveBinding(); |
| |
| Assert.isTrue(false); |
| return null; |
| } |
| |
| private final Expression fInitializer; |
| private ASTRewrite fInitializerRewrite; |
| private final HashSet fStaticImportsInInitializer2; |
| |
| // cache: |
| private Set fNamesDeclaredLocallyAtNewLocation; |
| |
| private final Expression fNewLocation; |
| private final HashSet fStaticImportsInReference; |
| private final CompilationUnitRewrite fNewLocationCuRewrite; |
| |
| public InitializerTraversal(Expression initializer, HashSet staticImportsInInitializer, Expression newLocation, HashSet staticImportsInReference, CompilationUnitRewrite newLocationCuRewrite) { |
| fInitializer= initializer; |
| fInitializerRewrite= ASTRewrite.create(initializer.getAST()); |
| fStaticImportsInInitializer2= staticImportsInInitializer; |
| |
| fNewLocation= newLocation; |
| fStaticImportsInReference= staticImportsInReference; |
| fNewLocationCuRewrite= newLocationCuRewrite; |
| |
| perform(initializer); |
| } |
| |
| /** |
| * @param scope not a TypeDeclaration |
| * @return Set containing Strings representing simple names |
| */ |
| private Set getLocallyDeclaredNames(BodyDeclaration scope) { |
| Assert.isTrue(!(scope instanceof AbstractTypeDeclaration)); |
| |
| final Set result= new HashSet(); |
| |
| if (scope instanceof FieldDeclaration) |
| return result; |
| |
| scope.accept(new HierarchicalASTVisitor() { |
| |
| public boolean visit(AbstractTypeDeclaration node) { |
| Assert.isTrue(node.getParent() instanceof TypeDeclarationStatement); |
| |
| result.add(node.getName().getIdentifier()); |
| return false; |
| } |
| |
| public boolean visit(AnonymousClassDeclaration anonDecl) { |
| return false; |
| } |
| |
| public boolean visit(VariableDeclaration varDecl) { |
| result.add(varDecl.getName().getIdentifier()); |
| return false; |
| } |
| }); |
| return result; |
| } |
| |
| public ASTRewrite getInitializerRewrite() { |
| return fInitializerRewrite; |
| } |
| |
| private void perform(Expression initializer) { |
| initializer.accept(this); |
| } |
| |
| public boolean visit(FieldAccess fieldAccess) { |
| fieldAccess.getExpression().accept(this); |
| return false; |
| } |
| |
| public boolean visit(MethodInvocation invocation) { |
| if (invocation.getExpression() == null) |
| qualifyUnqualifiedMemberNameIfNecessary(invocation.getName()); |
| else |
| invocation.getExpression().accept(this); |
| |
| for (Iterator it= invocation.arguments().iterator(); it.hasNext();) |
| ((Expression) it.next()).accept(this); |
| |
| return false; |
| } |
| |
| public boolean visit(Name name) { |
| SimpleName leftmost= getLeftmost(name); |
| |
| IBinding leftmostBinding= leftmost.resolveBinding(); |
| if (leftmostBinding instanceof IVariableBinding || leftmostBinding instanceof IMethodBinding || leftmostBinding instanceof ITypeBinding) { |
| if (shouldUnqualify(leftmost)) |
| unqualifyMemberName(leftmost); |
| else |
| qualifyUnqualifiedMemberNameIfNecessary(leftmost); |
| } |
| |
| if (leftmostBinding instanceof ITypeBinding) { |
| String addedImport= fNewLocationCuRewrite.getImportRewrite().addImport((ITypeBinding) leftmostBinding); |
| fNewLocationCuRewrite.getImportRemover().registerAddedImport(addedImport); |
| } |
| |
| return false; |
| } |
| |
| private void qualifyUnqualifiedMemberNameIfNecessary(SimpleName memberName) { |
| if (shouldQualify(memberName)) |
| qualifyMemberName(memberName); |
| } |
| |
| private boolean shouldUnqualify(SimpleName memberName) { |
| if (areInSameType(memberName, fNewLocation)) |
| return ! mayBeShadowedByLocalDeclaration(memberName); |
| |
| return false; |
| } |
| |
| private void unqualifyMemberName(SimpleName memberName) { |
| if (doesParentQualify(memberName)) |
| fInitializerRewrite.replace(memberName.getParent(), memberName, null); |
| } |
| |
| private boolean shouldQualify(SimpleName memberName) { |
| if (! areInSameType(fInitializer, fNewLocation)) |
| return true; |
| |
| return mayBeShadowedByLocalDeclaration(memberName); |
| } |
| |
| private boolean mayBeShadowedByLocalDeclaration(SimpleName memberName) { |
| return getNamesDeclaredLocallyAtNewLocation().contains(memberName.getIdentifier()); |
| } |
| |
| private Set getNamesDeclaredLocallyAtNewLocation() { |
| if (fNamesDeclaredLocallyAtNewLocation != null) |
| return fNamesDeclaredLocallyAtNewLocation; |
| |
| BodyDeclaration enclosingBodyDecl= (BodyDeclaration) ASTNodes.getParent(fNewLocation, BodyDeclaration.class); |
| Assert.isTrue(!(enclosingBodyDecl instanceof AbstractTypeDeclaration)); |
| |
| return fNamesDeclaredLocallyAtNewLocation= getLocallyDeclaredNames(enclosingBodyDecl); |
| } |
| |
| private void qualifyMemberName(SimpleName memberName) { |
| if (isStaticAccess(memberName)) { |
| IBinding memberBinding= memberName.resolveBinding(); |
| |
| if (memberBinding instanceof IVariableBinding || memberBinding instanceof IMethodBinding) { |
| if (fStaticImportsInReference.contains(fNewLocation)) { // use static import if reference location used static import |
| importStatically(memberName, memberBinding); |
| return; |
| } else if (fStaticImportsInInitializer2.contains(memberName)) { // use static import if already imported statically in initializer |
| importStatically(memberName, memberBinding); |
| return; |
| } |
| } |
| qualifyToTopLevelClass(memberName); //otherwise: qualify and import non-static |
| } |
| } |
| |
| private void importStatically(SimpleName toImport, IBinding binding) { |
| String newName= fNewLocationCuRewrite.getImportRewrite().addStaticImport(binding); |
| fNewLocationCuRewrite.getImportRemover().registerAddedStaticImport(binding); |
| |
| Name newReference= ASTNodeFactory.newName(fInitializerRewrite.getAST(), newName); |
| fInitializerRewrite.replace(toImport, newReference, null); |
| } |
| |
| private void qualifyToTopLevelClass(SimpleName toQualify) { |
| ITypeBinding declaringClass= getDeclaringClassBinding(toQualify); |
| if (declaringClass == null) |
| return; |
| |
| Type newQualification= fNewLocationCuRewrite.getImportRewrite().addImport(declaringClass, fInitializerRewrite.getAST()); |
| fNewLocationCuRewrite.getImportRemover().registerAddedImports(newQualification); |
| |
| SimpleName newToQualify= (SimpleName) fInitializerRewrite.createMoveTarget(toQualify); |
| Type newType= fInitializerRewrite.getAST().newQualifiedType(newQualification, newToQualify); |
| fInitializerRewrite.replace(toQualify, newType, null); |
| } |
| |
| private static ITypeBinding getDeclaringClassBinding(SimpleName memberName) { |
| |
| IBinding binding= memberName.resolveBinding(); |
| if (binding instanceof IMethodBinding) |
| return ((IMethodBinding) binding).getDeclaringClass(); |
| |
| if (binding instanceof IVariableBinding) |
| return ((IVariableBinding) binding).getDeclaringClass(); |
| |
| if (binding instanceof ITypeBinding) |
| return ((ITypeBinding) binding).getDeclaringClass(); |
| |
| Assert.isTrue(false); |
| return null; |
| |
| } |
| |
| } |
| |
| private final Expression fInitializer; |
| private final ICompilationUnit fInitializerUnit; |
| |
| /** The references in this compilation unit, represented as AST Nodes in the parsed representation of the compilation unit */ |
| private final Expression[] fReferences; |
| private final VariableDeclarationFragment fDeclarationToRemove; |
| private final CompilationUnitRewrite fCuRewrite; |
| private final TightSourceRangeComputer fSourceRangeComputer; |
| private final HashSet fStaticImportsInInitializer; |
| private final boolean fIs15; |
| |
| private InlineTargetCompilationUnit(CompilationUnitRewrite cuRewrite, Name[] references, InlineConstantRefactoring refactoring, HashSet staticImportsInInitializer) throws JavaModelException { |
| fInitializer= refactoring.getInitializer(); |
| fInitializerUnit= refactoring.getDeclaringCompilationUnit(); |
| |
| fCuRewrite= cuRewrite; |
| fSourceRangeComputer= new TightSourceRangeComputer(); |
| fCuRewrite.getASTRewrite().setTargetSourceRangeComputer(fSourceRangeComputer); |
| if (refactoring.getRemoveDeclaration() && refactoring.getReplaceAllReferences() && cuRewrite.getCu().equals(fInitializerUnit)) |
| fDeclarationToRemove= refactoring.getDeclaration(); |
| else |
| fDeclarationToRemove= null; |
| |
| fReferences= new Expression[references.length]; |
| for (int i= 0; i < references.length; i++) |
| fReferences[i]= getQualifiedReference(references[i]); |
| |
| fIs15= JavaModelUtil.is50OrHigher(cuRewrite.getCu().getJavaProject()); |
| fStaticImportsInInitializer= fIs15 ? staticImportsInInitializer : new HashSet(0); |
| } |
| |
| private static Expression getQualifiedReference(Name fieldName) { |
| if (doesParentQualify(fieldName)) |
| return (Expression) fieldName.getParent(); |
| |
| return fieldName; |
| } |
| |
| private static boolean doesParentQualify(Name fieldName) { |
| ASTNode parent= fieldName.getParent(); |
| Assert.isNotNull(parent); |
| |
| if (parent instanceof FieldAccess && ((FieldAccess) parent).getName() == fieldName) |
| return true; |
| |
| if (parent instanceof QualifiedName && ((QualifiedName) parent).getName() == fieldName) |
| return true; |
| |
| if (parent instanceof MethodInvocation && ((MethodInvocation) parent).getName() == fieldName) |
| return true; |
| |
| return false; |
| } |
| |
| public CompilationUnitChange getChange() throws CoreException { |
| for (int i= 0; i < fReferences.length; i++) |
| inlineReference(fReferences[i]); |
| |
| removeConstantDeclarationIfNecessary(); |
| |
| return fCuRewrite.createChange(); |
| } |
| |
| private void inlineReference(Expression reference) throws CoreException { |
| ASTNode importDecl= ASTNodes.getParent(reference, ImportDeclaration.class); |
| if (importDecl != null) |
| return; // don't inline into static imports |
| |
| String modifiedInitializer= prepareInitializerForLocation(reference); |
| if (modifiedInitializer == null) |
| return; |
| |
| TextEditGroup msg= fCuRewrite.createGroupDescription(RefactoringCoreMessages.InlineConstantRefactoring_Inline); |
| Expression newReference= (Expression) fCuRewrite.getASTRewrite().createStringPlaceholder(modifiedInitializer, reference.getNodeType()); |
| if (shouldParenthesizeSubstitute(fInitializer, reference)) { |
| ParenthesizedExpression parenthesized= fCuRewrite.getAST().newParenthesizedExpression(); |
| parenthesized.setExpression(newReference); |
| newReference= parenthesized; |
| } |
| fCuRewrite.getASTRewrite().replace(reference, newReference, msg); |
| fSourceRangeComputer.addTightSourceNode(reference); |
| fCuRewrite.getImportRemover().registerRemovedNode(reference); |
| } |
| |
| private String prepareInitializerForLocation(Expression location) throws CoreException { |
| HashSet staticImportsInReference= new HashSet(); |
| final IJavaProject project= fCuRewrite.getCu().getJavaProject(); |
| if (fIs15) |
| location.accept(new ImportReferencesCollector(project, null, new ArrayList(), staticImportsInReference)); |
| InitializerTraversal traversal= new InitializerTraversal(fInitializer, fStaticImportsInInitializer, location, staticImportsInReference, fCuRewrite); |
| ASTRewrite initializerRewrite= traversal.getInitializerRewrite(); |
| IDocument document= new Document(fInitializerUnit.getBuffer().getContents()); // could reuse document when generating and applying undo edits |
| |
| final RangeMarker marker= new RangeMarker(fInitializer.getStartPosition(), fInitializer.getLength()); |
| TextEdit[] rewriteEdits= initializerRewrite.rewriteAST(document, fInitializerUnit.getJavaProject().getOptions(true)).removeChildren(); |
| marker.addChildren(rewriteEdits); |
| try { |
| marker.apply(document, TextEdit.UPDATE_REGIONS); |
| String rewrittenInitializer= document.get(marker.getOffset(), marker.getLength()); |
| IRegion region= document.getLineInformation(document.getLineOfOffset(marker.getOffset())); |
| int oldIndent= Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), project); |
| return Strings.changeIndent(rewrittenInitializer, oldIndent, project, "", TextUtilities.getDefaultLineDelimiter(document)); //$NON-NLS-1$ |
| } catch (MalformedTreeException e) { |
| JavaPlugin.log(e); |
| } catch (BadLocationException e) { |
| JavaPlugin.log(e); |
| } |
| return fInitializerUnit.getBuffer().getText(fInitializer.getStartPosition(), fInitializer.getLength()); |
| } |
| |
| private static boolean shouldParenthesizeSubstitute(Expression substitute, Expression location) { |
| if (substitute instanceof Assignment) // for esthetic reasons |
| return true; |
| else |
| return ASTNodes.substituteMustBeParenthesized(substitute, location); |
| } |
| |
| private void removeConstantDeclarationIfNecessary() throws CoreException { |
| if (fDeclarationToRemove == null) |
| return; |
| |
| FieldDeclaration parentDeclaration= (FieldDeclaration) fDeclarationToRemove.getParent(); |
| ASTNode toRemove; |
| if (parentDeclaration.fragments().size() == 1) |
| toRemove= parentDeclaration; |
| else |
| toRemove= fDeclarationToRemove; |
| |
| TextEditGroup msg= fCuRewrite.createGroupDescription(RefactoringCoreMessages.InlineConstantRefactoring_remove_declaration); |
| fCuRewrite.getASTRewrite().remove(toRemove, msg); |
| fCuRewrite.getImportRemover().registerRemovedNode(toRemove); |
| } |
| } |
| |
| // ---- End InlineTargetCompilationUnit ---------------------------------------------------------------------------------------------- |
| |
| private static SimpleName getLeftmost(Name name) { |
| if (name instanceof SimpleName) |
| return (SimpleName) name; |
| |
| return getLeftmost(((QualifiedName) name).getQualifier()); |
| } |
| |
| private final int fSelectionStart; |
| private final int fSelectionLength; |
| |
| private final ICompilationUnit fSelectionCu; |
| private CompilationUnitRewrite fSelectionCuRewrite; |
| private Name fSelectedConstantName; |
| |
| IField fField; |
| private CompilationUnitRewrite fDeclarationCuRewrite; |
| private VariableDeclarationFragment fDeclaration; |
| private boolean fDeclarationSelected; |
| private boolean fDeclarationSelectedChecked= false; |
| private boolean fInitializerAllStaticFinal; |
| private boolean fInitializerChecked= false; |
| |
| private boolean fRemoveDeclaration= false; |
| private boolean fReplaceAllReferences= true; |
| |
| private CompilationUnitChange[] fChanges; |
| |
| private InlineConstantRefactoring(ICompilationUnit cu, CompilationUnit node, int selectionStart, int selectionLength) { |
| Assert.isTrue(selectionStart >= 0); |
| Assert.isTrue(selectionLength >= 0); |
| Assert.isTrue(cu.exists()); |
| fSelectionCu= cu; |
| fSelectionStart= selectionStart; |
| fSelectionLength= selectionLength; |
| fSelectionCuRewrite= new CompilationUnitRewrite(cu, node); |
| fSelectedConstantName= findConstantNameNode(); |
| } |
| |
| private Name findConstantNameNode() { |
| ASTNode node= NodeFinder.perform(fSelectionCuRewrite.getRoot(), fSelectionStart, fSelectionLength); |
| if (node == null) |
| return null; |
| if (node instanceof FieldAccess) |
| node= ((FieldAccess) node).getName(); |
| if (node.getParent() instanceof EnumConstantDeclaration) |
| return null; |
| if (!(node instanceof Name)) |
| return null; |
| Name name= (Name) node; |
| IBinding binding= name.resolveBinding(); |
| if (!(binding instanceof IVariableBinding)) |
| return null; |
| IVariableBinding variableBinding= (IVariableBinding) binding; |
| if (!variableBinding.isField() || variableBinding.isEnumConstant()) |
| return null; |
| int modifiers= binding.getModifiers(); |
| if (! (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers))) |
| return null; |
| |
| return name; |
| } |
| |
| public static InlineConstantRefactoring create(ICompilationUnit cu, CompilationUnit node, int selectionStart, int selectionLength) { |
| InlineConstantRefactoring ref= new InlineConstantRefactoring(cu, node, selectionStart, selectionLength); |
| if (ref.checkStaticFinalConstantNameSelected().hasFatalError()) |
| return null; |
| return ref; |
| } |
| |
| private RefactoringStatus checkStaticFinalConstantNameSelected() { |
| if (fSelectedConstantName == null) |
| return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.InlineConstantRefactoring_static_final_field, null, Corext.getPluginId(), RefactoringStatusCodes.NOT_STATIC_FINAL_SELECTED, null); |
| |
| return new RefactoringStatus(); |
| } |
| |
| public String getName() { |
| return RefactoringCoreMessages.InlineConstantRefactoring_name; |
| } |
| |
| public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { |
| try { |
| pm.beginTask("", 3); //$NON-NLS-1$ |
| |
| if (!fSelectionCu.isStructureKnown()) |
| return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.InlineConstantRefactoring_syntax_errors, null, Corext.getPluginId(), RefactoringStatusCodes.SYNTAX_ERRORS, null); |
| |
| RefactoringStatus result= checkStaticFinalConstantNameSelected(); |
| if (result.hasFatalError()) |
| return result; |
| |
| result.merge(findField()); |
| if (result.hasFatalError()) |
| return result; |
| pm.worked(1); |
| |
| result.merge(findDeclaration()); |
| if (result.hasFatalError()) |
| return result; |
| pm.worked(1); |
| |
| result.merge(checkInitializer()); |
| if (result.hasFatalError()) |
| return result; |
| pm.worked(1); |
| |
| return result; |
| |
| } finally { |
| pm.done(); |
| } |
| } |
| |
| private RefactoringStatus findField() throws JavaModelException { |
| fField= Bindings.findField((IVariableBinding) fSelectedConstantName.resolveBinding(), fSelectionCu.getJavaProject()); |
| if (fField != null && ! fField.exists()) |
| return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.InlineConstantRefactoring_local_anonymous_unsupported, null, Corext.getPluginId(), RefactoringStatusCodes.LOCAL_AND_ANONYMOUS_NOT_SUPPORTED, null); |
| |
| return null; |
| } |
| |
| private RefactoringStatus findDeclaration() throws JavaModelException { |
| fDeclarationSelectedChecked= true; |
| fDeclarationSelected= false; |
| ASTNode parent= fSelectedConstantName.getParent(); |
| if (parent instanceof VariableDeclarationFragment) { |
| VariableDeclarationFragment parentDeclaration= (VariableDeclarationFragment) parent; |
| if (parentDeclaration.getName() == fSelectedConstantName) { |
| fDeclarationSelected= true; |
| fDeclarationCuRewrite= fSelectionCuRewrite; |
| fDeclaration= (VariableDeclarationFragment) fSelectedConstantName.getParent(); |
| return null; |
| } |
| } |
| |
| VariableDeclarationFragment declaration= (VariableDeclarationFragment) fSelectionCuRewrite.getRoot().findDeclaringNode(fSelectedConstantName.resolveBinding()); |
| if (declaration != null) { |
| fDeclarationCuRewrite= fSelectionCuRewrite; |
| fDeclaration= declaration; |
| return null; |
| } |
| |
| if (fField.getCompilationUnit() == null) |
| return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.InlineConstantRefactoring_binary_file, null, Corext.getPluginId(), RefactoringStatusCodes.DECLARED_IN_CLASSFILE, null); |
| |
| fDeclarationCuRewrite= new CompilationUnitRewrite(fField.getCompilationUnit()); |
| fDeclaration= ASTNodeSearchUtil.getFieldDeclarationFragmentNode(fField, fDeclarationCuRewrite.getRoot()); |
| return null; |
| } |
| |
| private RefactoringStatus checkInitializer() { |
| Expression initializer= getInitializer(); |
| if (initializer == null) |
| return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.InlineConstantRefactoring_blank_finals, null, Corext.getPluginId(), RefactoringStatusCodes.CANNOT_INLINE_BLANK_FINAL, null); |
| |
| fInitializerAllStaticFinal= ConstantChecks.isStaticFinalConstant((IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(initializer)); |
| fInitializerChecked= true; |
| return new RefactoringStatus(); |
| } |
| |
| private VariableDeclarationFragment getDeclaration() throws JavaModelException { |
| return fDeclaration; |
| } |
| |
| private Expression getInitializer() { |
| return fDeclaration.getInitializer(); |
| } |
| |
| private ICompilationUnit getDeclaringCompilationUnit() throws JavaModelException { |
| return fField.getCompilationUnit(); |
| } |
| |
| public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException { |
| RefactoringStatus result= new RefactoringStatus(); |
| pm.beginTask("", 3); //$NON-NLS-1$ |
| |
| try { |
| List/*<CompilationUnitChange>*/changes= new ArrayList(); |
| HashSet staticImportsInInitializer= new HashSet(); |
| ImportReferencesCollector importReferencesCollector= new ImportReferencesCollector(fField.getJavaProject(), null, new ArrayList(), staticImportsInInitializer); |
| getInitializer().accept(importReferencesCollector); |
| |
| if (getReplaceAllReferences()) { |
| SearchResultGroup[] searchResultGroups= findReferences(pm, result); |
| for (int i= 0; i < searchResultGroups.length; i++) { |
| if (pm.isCanceled()) |
| throw new OperationCanceledException(); |
| SearchResultGroup group= searchResultGroups[i]; |
| ICompilationUnit cu= group.getCompilationUnit(); |
| |
| CompilationUnitRewrite cuRewrite= getCuRewrite(cu); |
| Name[] references= extractReferenceNodes(group.getSearchResults(), cuRewrite.getRoot()); |
| InlineTargetCompilationUnit targetCompilationUnit= new InlineTargetCompilationUnit( |
| cuRewrite, references, this, staticImportsInInitializer); |
| changes.add(targetCompilationUnit.getChange()); |
| } |
| |
| } else { |
| Assert.isTrue(! isDeclarationSelected()); |
| InlineTargetCompilationUnit targetForOnlySelectedReference= new InlineTargetCompilationUnit( |
| fSelectionCuRewrite, new Name[] { fSelectedConstantName }, this, staticImportsInInitializer); |
| changes.add(targetForOnlySelectedReference.getChange()); |
| } |
| |
| if (result.hasFatalError()) |
| return result; |
| |
| if (getRemoveDeclaration() && getReplaceAllReferences()) { |
| boolean declarationRemoved= false; |
| for (Iterator iter= changes.iterator(); iter.hasNext();) { |
| CompilationUnitChange change= (CompilationUnitChange) iter.next(); |
| if (change.getCompilationUnit().equals(fDeclarationCuRewrite.getCu())) { |
| declarationRemoved= true; |
| break; |
| } |
| } |
| if (! declarationRemoved) { |
| InlineTargetCompilationUnit targetForDeclaration= new InlineTargetCompilationUnit(fDeclarationCuRewrite, new Name[0], this, staticImportsInInitializer); |
| CompilationUnitChange change= targetForDeclaration.getChange(); |
| if (change != null) |
| changes.add(change); |
| } |
| } |
| |
| ICompilationUnit[] cus= new ICompilationUnit[changes.size()]; |
| for (int i= 0; i < changes.size(); i++) { |
| CompilationUnitChange change= (CompilationUnitChange) changes.get(i); |
| cus[i]= change.getCompilationUnit(); |
| } |
| result.merge(Checks.validateModifiesFiles(ResourceUtil.getFiles(cus), getValidationContext())); |
| |
| pm.worked(1); |
| |
| fChanges= (CompilationUnitChange[]) changes.toArray(new CompilationUnitChange[changes.size()]); |
| |
| return result; |
| |
| } finally { |
| fSelectionCuRewrite= null; |
| fSelectedConstantName= null; |
| fDeclarationCuRewrite= null; |
| fDeclaration= null; |
| pm.done(); |
| } |
| } |
| |
| private Name[] extractReferenceNodes(SearchMatch[] searchResults, CompilationUnit cuNode) { |
| Name[] references= new Name[searchResults.length]; |
| for (int i= 0; i < searchResults.length; i++) |
| references[i]= (Name) NodeFinder.perform(cuNode, searchResults[i].getOffset(), searchResults[i].getLength()); |
| return references; |
| } |
| |
| private CompilationUnitRewrite getCuRewrite(ICompilationUnit cu) { |
| CompilationUnitRewrite cuRewrite; |
| if (cu.equals(fSelectionCu)) { |
| cuRewrite= fSelectionCuRewrite; |
| } else if (cu.equals(fField.getCompilationUnit())) { |
| cuRewrite= fDeclarationCuRewrite; |
| } else { |
| cuRewrite= new CompilationUnitRewrite(cu); |
| } |
| return cuRewrite; |
| } |
| |
| private SearchResultGroup[] findReferences(IProgressMonitor pm, RefactoringStatus status) throws JavaModelException { |
| final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(fField, IJavaSearchConstants.REFERENCES)); |
| engine.setFiltering(true, true); |
| engine.setScope(RefactoringScopeFactory.create(fField)); |
| engine.setStatus(status); |
| engine.setRequestor(new IRefactoringSearchRequestor() { |
| public SearchMatch acceptSearchMatch(SearchMatch match) { |
| return match.isInsideDocComment() ? null : match; |
| } |
| }); |
| engine.searchPattern(new SubProgressMonitor(pm, 1)); |
| return (SearchResultGroup[]) engine.getResults(); |
| } |
| |
| public Change createChange(IProgressMonitor pm) throws CoreException { |
| try { |
| pm.beginTask(RefactoringCoreMessages.InlineConstantRefactoring_preview, 2); |
| final DynamicValidationStateChange result= new DynamicValidationStateChange(RefactoringCoreMessages.InlineConstantRefactoring_inline); |
| result.addAll(fChanges); |
| return result; |
| } finally { |
| pm.done(); |
| fChanges= null; |
| } |
| } |
| |
| |
| private void checkInvariant() { |
| if (isDeclarationSelected()) |
| Assert.isTrue(fReplaceAllReferences); |
| } |
| |
| public boolean getRemoveDeclaration() { |
| return fRemoveDeclaration; |
| } |
| |
| public boolean getReplaceAllReferences() { |
| checkInvariant(); |
| return fReplaceAllReferences; |
| } |
| |
| public boolean isDeclarationSelected() { |
| Assert.isTrue(fDeclarationSelectedChecked); |
| return fDeclarationSelected; |
| } |
| |
| public boolean isInitializerAllStaticFinal() { |
| Assert.isTrue(fInitializerChecked); |
| return fInitializerAllStaticFinal; |
| } |
| |
| public void setRemoveDeclaration(boolean removeDeclaration) { |
| fRemoveDeclaration= removeDeclaration; |
| } |
| |
| public void setReplaceAllReferences(boolean replaceAllReferences) { |
| fReplaceAllReferences= replaceAllReferences; |
| checkInvariant(); |
| } |
| } |