blob: 41a88c992ab68832fcf97590616cae639bc34d37 [file] [log] [blame]
/*
* Licensed Materials - Property of IBM,
* WebSphere Studio Workbench
* (c) Copyright IBM Corp 1999, 2000
*/
package org.eclipse.jdt.core.refactoring.fields;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.refactoring.IChange;
import org.eclipse.jdt.core.refactoring.RefactoringStatus;
import org.eclipse.jdt.core.refactoring.tagging.IRenameRefactoring;
import org.eclipse.jdt.core.refactoring.text.ITextBuffer;
import org.eclipse.jdt.core.refactoring.text.ITextBufferChange;
import org.eclipse.jdt.core.refactoring.text.ITextBufferChangeCreator;
import org.eclipse.jdt.core.refactoring.text.SimpleReplaceTextChange;
import org.eclipse.jdt.core.refactoring.text.SimpleTextChange;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.ISearchPattern;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.internal.core.CompilationUnit;
import org.eclipse.jdt.internal.core.refactoring.Assert;
import org.eclipse.jdt.internal.core.refactoring.Checks;
import org.eclipse.jdt.internal.core.refactoring.CompositeChange;
import org.eclipse.jdt.internal.core.refactoring.RefactoringSearchEngine;
import org.eclipse.jdt.internal.core.refactoring.SearchResult;
import org.eclipse.jdt.internal.core.util.HackFinder;
/*
* non java-doc
* not API
*/
abstract class RenameFieldRefactoring extends FieldRefactoring implements IRenameRefactoring{
private String fNewName;
private List fOccurrences;
private ITextBufferChangeCreator fTextBufferChangeCreator;
public RenameFieldRefactoring(ITextBufferChangeCreator changeCreator, IField field){
super(field);
Assert.isNotNull(changeCreator, "change creator");
fTextBufferChangeCreator= changeCreator;
}
public RenameFieldRefactoring(ITextBufferChangeCreator changeCreator, IJavaSearchScope scope, IField field, String newName){
super(scope, field);
Assert.isNotNull(changeCreator, "change creator");
Assert.isNotNull(newName, "new name");
fTextBufferChangeCreator= changeCreator;
fNewName= newName;
}
/**
* @see IRenameRefactoring#setNewName
*/
public final void setNewName(String newName){
Assert.isNotNull(newName);
fNewName= newName;
}
public final String getNewName(){
return fNewName;
}
protected final ITextBufferChangeCreator getChangeCreator(){
return fTextBufferChangeCreator;
}
/**
* @see IRefactoring#getName
*/
public String getName(){
return "Rename Field " + getField().getElementName() + "(declared in " + getField().getDeclaringType().getFullyQualifiedName()+ ")" +" to " + getNewName();
}
// -------------- Preconditions -----------------------
/**
* @see IRenameRefactoring#checkNewName
*/
public RefactoringStatus checkNewName() {
RefactoringStatus result= new RefactoringStatus();
result.merge(Checks.checkFieldName(getNewName()));
if (Checks.isAlreadyNamed(getField(), getNewName()))
result.addFatalError("Choose another name.");
if (getField().getDeclaringType().getField(getNewName()).exists())
result.addError("Field with this name already defined");
return result;
}
/**
* @see Refactoring#checkInput
*/
public RefactoringStatus checkInput(IProgressMonitor pm) throws JavaModelException {
pm.beginTask("", 8);
pm.subTask("checking preconditions");
RefactoringStatus result= new RefactoringStatus();
result.merge(checkNewName());
pm.worked(1);
result.merge(checkEnclosingHierarchy());
pm.worked(1);
result.merge(checkNestedHierarchy(getField().getDeclaringType()));
pm.worked(1);
result.merge(Checks.checkAffectedResourcesAvailability(getOccurrences(pm)));
pm.worked(3);
result.merge(analyzeAffectedCompilationUnits());
pm.worked(2);
pm.done();
return result;
}
private RefactoringStatus checkNestedHierarchy(IType type) throws JavaModelException {
IType[] nestedTypes= type.getTypes();
if (nestedTypes == null)
return null;
RefactoringStatus result= new RefactoringStatus();
for (int i= 0; i < nestedTypes.length; i++){
IField otherField= nestedTypes[i].getField(getNewName());
if (otherField.exists())
result.addWarning("After renaming, the field " + getField().getElementName() + " will be hidden in the scope of the field "+ getNewName() + " declared in type " + nestedTypes[i].getFullyQualifiedName());
result.merge(checkNestedHierarchy(nestedTypes[i]));
}
return result;
}
private RefactoringStatus checkEnclosingHierarchy() throws JavaModelException {
IType current= getField().getDeclaringType();
if (Checks.isTopLevel(current))
return null;
RefactoringStatus result= new RefactoringStatus();
while (current != null){
IField otherField= current.getField(getNewName());
if (otherField.exists())
result.addWarning("After renaming, the field named " + getNewName() + " declared in type " + current.getFullyQualifiedName() + " will be hidden in the scope of the field " + getField().getElementName());
current= current.getDeclaringType();
}
return result;
}
//-------------- AST visitor-based analysis
/*
* (non java-doc)
* Analyzes all compilation units in which type is referenced
*/
private RefactoringStatus analyzeAffectedCompilationUnits() throws JavaModelException{
RefactoringStatus result= new RefactoringStatus();
Iterator iter= getOccurrences(null).iterator();
RenameFieldASTAnalyzer analyzer= new RenameFieldASTAnalyzer(fNewName, getField());
while (iter.hasNext()){
analyzeCompilationUnit(analyzer, (List)iter.next(), result);
}
return result;
}
private void analyzeCompilationUnit(RenameFieldASTAnalyzer analyzer, List searchResults, RefactoringStatus result) throws JavaModelException {
SearchResult searchResult= (SearchResult)searchResults.get(0);
CompilationUnit cu= (CompilationUnit) (JavaCore.create(searchResult.getResource()));
if ((! cu.exists()) || (cu.isReadOnly()) || (!cu.isStructureKnown()))
return;
result.merge(analyzer.analyze(searchResults, cu));
}
// ---------- Changes -----------------
/**
* @see IRefactoring#createChange
*/
public IChange createChange(IProgressMonitor pm) throws JavaModelException {
pm.beginTask("creating rename package change", 7);
CompositeChange builder= new CompositeChange();
getOccurrences(new SubProgressMonitor(pm, 6, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
addOccurrences(pm, builder);
pm.worked(1);
pm.done();
return builder;
}
private SimpleReplaceTextChange createTextChange(SearchResult searchResult) {
return new SimpleReplaceTextChange("Field Reference Update", searchResult.getStart(), searchResult.getEnd() - searchResult.getStart(), getNewName()){
protected SimpleTextChange[] adjust(ITextBuffer buffer) {
String oldText= buffer.getContent(getOffset(), getLength());
if (oldText.startsWith("this.")){
setText("this." + getText());
setLength(getLength());
}
return null;
}
};
}
private void addOccurrences(IProgressMonitor pm, CompositeChange builder) throws JavaModelException{
List grouped= getOccurrences(null);
for (Iterator iter= grouped.iterator(); iter.hasNext();){
List l= (List)iter.next();
ITextBufferChange change= getChangeCreator().create("Rename Field", (ICompilationUnit)JavaCore.create(((SearchResult)l.get(0)).getResource()));
for (Iterator subIter= l.iterator(); subIter.hasNext();){
change.addSimpleTextChange(createTextChange((SearchResult)subIter.next()));
}
builder.addChange(change);
pm.worked(1);
}
HackFinder.fixMeSoon("maybe add dispose() method?");
setOccurrences(null); //to prevent memory leak
}
//--------------------------------------
protected ISearchPattern createSearchPattern(){
return SearchEngine.createSearchPattern(getField(), IJavaSearchConstants.ALL_OCCURRENCES);
}
protected List getOccurrences(IProgressMonitor pm) throws JavaModelException{
if (fOccurrences == null){
if (pm == null)
pm= new NullProgressMonitor();
fOccurrences= RefactoringSearchEngine.search(new SubProgressMonitor(pm, 6, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK), getScope(), createSearchPattern());
}
return fOccurrences;
}
/*package*/ final void setOccurrences(List Occurrences){
fOccurrences= Occurrences;
}
}