replace all inheritors with static imports: minimize touched files count

This commit is contained in:
anna
2010-06-28 12:57:06 +04:00
parent d6b4e25b2b
commit 7dd54f8ace
13 changed files with 344 additions and 69 deletions

View File

@@ -280,7 +280,7 @@ public class ChangeContextUtil {
return refMemberClass;
}
private static boolean canRemoveQualifier(PsiReferenceExpression refExpr) {
public static boolean canRemoveQualifier(PsiReferenceExpression refExpr) {
try{
PsiExpression qualifier = refExpr.getQualifierExpression();
if (!(qualifier instanceof PsiReferenceExpression)) return false;

View File

@@ -27,9 +27,9 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
@@ -91,7 +91,7 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
}
});
((PsiReferenceExpressionImpl)refExpr).bindToElementViaStaticImport(((PsiMember)resolved).getContainingClass(), ((PsiNamedElement)resolved).getName(), ((PsiJavaFile)file).getImportList());
RefactoringUtil.bindToElementViaStaticImport(((PsiMember)resolved).getContainingClass(), ((PsiNamedElement)resolved).getName(), ((PsiJavaFile)file).getImportList());
file.accept(new JavaRecursiveElementVisitor() {
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
@@ -134,4 +134,4 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
}
});
}
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.intellij.codeInspection.actions;
import com.intellij.codeInsight.ChangeContextUtil;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
@@ -23,23 +24,26 @@ import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class ReplaceImplementsWithStaticImportAction extends PsiElementBaseIntentionAction {
private static final Logger LOG = Logger.getInstance("#" + ReplaceImplementsWithStaticImportAction.class.getName());
@NonNls private static final String FIND_CONSTANT_FIELD_USAGES = "Find constant field usages...";
@NotNull
public String getText() {
@@ -111,14 +115,27 @@ public class ReplaceImplementsWithStaticImportAction extends PsiElementBaseInten
LOG.assertTrue(target instanceof PsiClass);
final PsiClass targetClass = (PsiClass)target;
new WriteCommandAction(project, getText(), file) {
new WriteCommandAction(project, getText()) {
protected void run(Result result) throws Throwable {
for (PsiField constField : targetClass.getAllFields()) {
final String fieldName = constField.getName();
final PsiClass containingClass = constField.getContainingClass();
for (PsiReference ref : ReferencesSearch.search(constField)) {
((PsiReferenceExpressionImpl)ref)
.bindToElementViaStaticImport(containingClass, constField.getName(), ((PsiJavaFile)file).getImportList());
final PsiElement psiElement = ref.getElement();
if (ref instanceof PsiReferenceExpression) {
final PsiElement qualifier = ((PsiReferenceExpression)ref).getQualifier();
if (qualifier != null) {
if (qualifier instanceof PsiReferenceExpression) {
final PsiElement resolved = ((PsiReferenceExpression)qualifier).resolve();
if (resolved instanceof PsiClass && !InheritanceUtil.isInheritorOrSelf(psiClass, (PsiClass)resolved, true)) {
continue;
}
}
qualifier.putCopyableUserData(ChangeContextUtil.CAN_REMOVE_QUALIFIER_KEY,
ChangeContextUtil.canRemoveQualifier((PsiReferenceExpression)ref));
}
}
bindReference(psiElement.getContainingFile(), constField, containingClass, fieldName, ref, project);
}
}
element.delete();
@@ -135,33 +152,32 @@ public class ReplaceImplementsWithStaticImportAction extends PsiElementBaseInten
final Map<PsiFile, Map<PsiField, Set<PsiReference>>> refs = new HashMap<PsiFile, Map<PsiField, Set<PsiReference>>>();
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
for (PsiField field : targetClass.getAllFields()) {
final String fieldName = field.getName();
if (progressIndicator != null) {
progressIndicator.setText2(fieldName);
}
final PsiClass containingClass = field.getContainingClass();
for (PsiReference reference : ReferencesSearch.search(field)) {
if (reference == null) {
continue;
}
final PsiFile psiFile = reference.getElement().getContainingFile();
Map<PsiField, Set<PsiReference>> references = refs.get(psiFile);
if (references == null) {
references = new HashMap<PsiField, Set<PsiReference>>();
refs.put(psiFile, references);
final PsiElement refElement = reference.getElement();
if (encodeQualifier(containingClass, reference, targetClass)) continue;
final PsiFile psiFile = refElement.getContainingFile();
if (psiFile instanceof PsiJavaFile) {
Map<PsiField, Set<PsiReference>> references = refs.get(psiFile);
if (references == null) {
references = new HashMap<PsiField, Set<PsiReference>>();
refs.put(psiFile, references);
}
Set<PsiReference> fieldsRefs = references.get(field);
if (fieldsRefs == null) {
fieldsRefs = new HashSet<PsiReference>();
references.put(field, fieldsRefs);
}
fieldsRefs.add(reference);
}
Set<PsiReference> fieldsRefs = references.get(field);
if (fieldsRefs == null) {
fieldsRefs = new HashSet<PsiReference>();
references.put(field, fieldsRefs);
}
fieldsRefs.add(reference);
}
}
}
}, "Find constant field usages...", true, project)) {
}, FIND_CONSTANT_FIELD_USAGES, true, project)) {
return;
}
@@ -183,9 +199,6 @@ public class ReplaceImplementsWithStaticImportAction extends PsiElementBaseInten
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
for (PsiJavaCodeReferenceElement referenceElement : refs2Unimplement) {
referenceElement.delete();
}
for (PsiFile psiFile : refs.keySet()) {
final Map<PsiField, Set<PsiReference>> map = refs.get(psiFile);
@@ -193,19 +206,84 @@ public class ReplaceImplementsWithStaticImportAction extends PsiElementBaseInten
final PsiClass containingClass = psiField.getContainingClass();
final String fieldName = psiField.getName();
for (PsiReference reference : map.get(psiField)) {
if (reference instanceof PsiReferenceExpressionImpl && psiFile instanceof PsiJavaFile) {
((PsiReferenceExpressionImpl)reference).bindToElementViaStaticImport(containingClass, fieldName, ((PsiJavaFile)psiFile).getImportList());
} else {
reference.bindToElement(psiField);
}
bindReference(psiFile, psiField, containingClass, fieldName, reference, project);
}
}
}
for (PsiJavaCodeReferenceElement referenceElement : refs2Unimplement) {
referenceElement.delete();
}
}
});
final Set<SmartPsiElementPointer<PsiImportStatementBase>> redundant = new HashSet<SmartPsiElementPointer<PsiImportStatementBase>>();
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
final SmartPointerManager pointerManager = SmartPointerManager.getInstance(project);
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable(){
public void run() {
for (PsiFile psiFile : refs.keySet()) {
final Collection<PsiImportStatementBase> red = codeStyleManager.findRedundantImports((PsiJavaFile)psiFile);
if (red != null) {
for (PsiImportStatementBase statementBase : red) {
redundant.add(pointerManager.createSmartPsiElementPointer(statementBase));
}
}
}
}
}, "Collect redundant imports...", true, project)) return;
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
for (SmartPsiElementPointer<PsiImportStatementBase> pointer : redundant) {
final PsiImportStatementBase statementBase = pointer.getElement();
if (statementBase != null) statementBase.delete();
}
}
});
}
}
private static boolean encodeQualifier(PsiClass containingClass, PsiReference reference, PsiClass targetClass) {
if (reference instanceof PsiReferenceExpression) {
final PsiElement qualifier = ((PsiReferenceExpression)reference).getQualifier();
if (qualifier != null) {
if (qualifier instanceof PsiReferenceExpression) {
final PsiElement resolved = ((PsiReferenceExpression)qualifier).resolve();
if (resolved == containingClass || resolved instanceof PsiClass && InheritanceUtil.isInheritorOrSelf(targetClass, (PsiClass)resolved, true)) {
return true;
}
}
qualifier.putCopyableUserData(ChangeContextUtil.CAN_REMOVE_QUALIFIER_KEY,
ChangeContextUtil.canRemoveQualifier((PsiReferenceExpression)reference));
}
}
return false;
}
private static void bindReference(PsiFile psiFile,
PsiField psiField,
PsiClass containingClass,
String fieldName,
PsiReference reference,
Project project) {
if (reference instanceof PsiReferenceExpression) {
RefactoringUtil.bindToElementViaStaticImport(containingClass, fieldName, ((PsiJavaFile)psiFile).getImportList());
final PsiElement qualifier = ((PsiReferenceExpression)reference).getQualifier();
if (qualifier != null) {
final Boolean canRemoveQualifier = qualifier.getCopyableUserData(ChangeContextUtil.CAN_REMOVE_QUALIFIER_KEY);
if (canRemoveQualifier != null && canRemoveQualifier.booleanValue()) {
qualifier.delete();
} else {
final PsiJavaCodeReferenceElement classReferenceElement =
JavaPsiFacade.getElementFactory(project).createReferenceExpression(containingClass);
qualifier.replace(classReferenceElement);
}
}
} else if (reference.getElement() instanceof PsiDocMethodOrFieldRef){
reference.bindToElement(psiField); //todo refs through inheritors
}
}
private static boolean collectExtendsImplements(final PsiClass targetClass,
final PsiReferenceList referenceList,
final Set<PsiJavaCodeReferenceElement> refs) {

View File

@@ -17,7 +17,6 @@ package com.intellij.psi.impl.source.tree.java;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
@@ -47,9 +46,9 @@ import com.intellij.psi.scope.processor.MethodResolverProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.tree.ChildRoleBase;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.CharTable;
import com.intellij.util.Function;
@@ -59,8 +58,6 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements PsiReferenceExpression, SourceJavaCodeReference {
@@ -105,7 +102,7 @@ public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements
doImportStatic = false;
}
if (doImportStatic) {
bindToElementViaStaticImport(qualifierClass, staticName, importList);
RefactoringUtil.bindToElementViaStaticImport(qualifierClass, staticName, importList);
}
else {
PsiManagerEx manager = getManager();
@@ -118,34 +115,6 @@ public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements
return this;
}
public void bindToElementViaStaticImport(final PsiClass qualifierClass, final String staticName, final PsiImportList importList)
throws IncorrectOperationException {
final String qualifiedName = qualifierClass.getQualifiedName();
final List<PsiJavaCodeReferenceElement> refs = getImportsFromClass(importList, qualifiedName);
if (refs.size() < CodeStyleSettingsManager.getSettings(getProject()).NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND) {
importList.add(JavaPsiFacade.getInstance(getProject()).getElementFactory().createImportStaticStatement(qualifierClass, staticName));
} else {
for (PsiJavaCodeReferenceElement ref : refs) {
final PsiImportStaticStatement importStatement = PsiTreeUtil.getParentOfType(ref, PsiImportStaticStatement.class);
if (importStatement != null) {
importStatement.delete();
}
}
importList.add(JavaPsiFacade.getInstance(getProject()).getElementFactory().createImportStaticStatement(qualifierClass, "*"));
}
}
private static List<PsiJavaCodeReferenceElement> getImportsFromClass(@NotNull PsiImportList importList, String className){
final List<PsiJavaCodeReferenceElement> array = new ArrayList<PsiJavaCodeReferenceElement>();
for (PsiImportStaticStatement staticStatement : importList.getImportStaticStatements()) {
final PsiClass psiClass = staticStatement.resolveTargetClass();
if (psiClass != null && Comparing.strEqual(psiClass.getQualifiedName(), className)) {
array.add(staticStatement.getImportReference());
}
}
return array;
}
public void setQualifierExpression(@Nullable PsiExpression newQualifier) throws IncorrectOperationException {
final PsiExpression oldQualifier = getQualifierExpression();
if (newQualifier == null) {

View File

@@ -36,6 +36,7 @@ import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.controlFlow.ControlFlowUtil;
@@ -62,6 +63,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.psi.JavaTokenType.*;
public class RefactoringUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.util.RefactoringUtil");
public static final int EXPR_COPY_SAFE = 0;
@@ -882,6 +885,34 @@ public class RefactoringUtil {
}
}
public static void bindToElementViaStaticImport(final PsiClass qualifierClass, final String staticName, final PsiImportList importList)
throws IncorrectOperationException {
final String qualifiedName = qualifierClass.getQualifiedName();
final List<PsiJavaCodeReferenceElement> refs = getImportsFromClass(importList, qualifiedName);
if (refs.size() < CodeStyleSettingsManager.getSettings(qualifierClass.getProject()).NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND) {
importList.add(JavaPsiFacade.getInstance(qualifierClass.getProject()).getElementFactory().createImportStaticStatement(qualifierClass, staticName));
} else {
for (PsiJavaCodeReferenceElement ref : refs) {
final PsiImportStaticStatement importStatement = PsiTreeUtil.getParentOfType(ref, PsiImportStaticStatement.class);
if (importStatement != null) {
importStatement.delete();
}
}
importList.add(JavaPsiFacade.getInstance(qualifierClass.getProject()).getElementFactory().createImportStaticStatement(qualifierClass, "*"));
}
}
public static List<PsiJavaCodeReferenceElement> getImportsFromClass(@NotNull PsiImportList importList, String className){
final List<PsiJavaCodeReferenceElement> array = new ArrayList<PsiJavaCodeReferenceElement>();
for (PsiImportStaticStatement staticStatement : importList.getImportStaticStatements()) {
final PsiClass psiClass = staticStatement.resolveTargetClass();
if (psiClass != null && Comparing.strEqual(psiClass.getQualifiedName(), className)) {
array.add(staticStatement.getImportReference());
}
}
return array;
}
public static interface ImplicitConstructorUsageVisitor {
void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor);

View File

@@ -0,0 +1,26 @@
// "Replace Implements with Static Import" "true"
import static In.FOO;
interface In {
int FOO = 0;
}
class II {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class II1 {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + In.FOO);
}
}

View File

@@ -0,0 +1,29 @@
// "Replace Implements with Static Import" "true"
import static In.FOO;
interface In {
int FOO = 0;
}
class II {
public static void main(String[] args) {
System.out.println(FOO);
}
}
/**
* {@link In.FOO}
*/
class II1 {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + In.FOO);
}
}

View File

@@ -0,0 +1,29 @@
// "Replace Implements with Static Import" "true"
import static In.FOO;
interface In {
int FOO = 0;
}
class II {
public static void main(String[] args) {
System.out.println(FOO);
}
}
/**
* {@link I#FOO}
*/
class II1 {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + In.FOO);
}
}

View File

@@ -0,0 +1,20 @@
// "Replace Implements with Static Import" "true"
import static In.FOO;
interface In {
int FOO = 0;
}
class II {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class II1 {
int FOO = 9;
public static void main(String[] args) {
System.out.println(In.FOO);
}
}

View File

@@ -0,0 +1,23 @@
// "Replace Implements with Static Import" "true"
interface I<caret>n {
int FOO = 0;
}
class II implements In {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class II1 implements In {
public static void main(String[] args) {
System.out.println(II1.FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + II.FOO);
}
}

View File

@@ -0,0 +1,26 @@
// "Replace Implements with Static Import" "true"
interface I<caret>n {
int FOO = 0;
}
class II implements In {
public static void main(String[] args) {
System.out.println(FOO);
}
}
/**
* {@link In.FOO}
*/
class II1 implements In {
public static void main(String[] args) {
System.out.println(II1.FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + II.FOO);
}
}

View File

@@ -0,0 +1,27 @@
// "Replace Implements with Static Import" "true"
interface I<caret>n {
int FOO = 0;
}
class II implements In {
public static void main(String[] args) {
System.out.println(FOO);
}
}
/**
* {@link I#FOO}
*/
class II1 implements In {
public static void main(String[] args) {
System.out.println(II1.FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + II.FOO);
}
}

View File

@@ -0,0 +1,17 @@
// "Replace Implements with Static Import" "true"
interface I<caret>n {
int FOO = 0;
}
class II implements In {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class II1 implements In {
int FOO = 9;
public static void main(String[] args) {
System.out.println(In.FOO);
}
}