inline to anonymous: allow to inline from library (IDEA-162893)

This commit is contained in:
Anna.Kozlova
2016-10-20 19:04:25 +02:00
parent 6d286a5ec7
commit 94105ecee4
9 changed files with 88 additions and 26 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,6 +81,11 @@ public class InlineToAnonymousClassDialog extends InlineOptionsWithSearchSetting
protected void saveSearchInCommentsAndStrings(boolean searchInComments) {
JavaRefactoringSettings.getInstance().INLINE_CLASS_SEARCH_IN_COMMENTS = searchInComments;
}
@Override
protected boolean allowInlineAll() {
return true;
}
@Override
protected void saveSearchInTextOccurrences(boolean searchInTextOccurrences) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.FunctionalExpressionSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
@@ -115,7 +116,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
}
final Ref<String> errorMessage = new Ref<>();
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> ApplicationManager.getApplication().runReadAction(() -> errorMessage.set(getCannotInlineMessage(psiClass))), "Check if inline is possible...", true, project)) return;
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> ApplicationManager.getApplication().runReadAction(() -> errorMessage.set(getCannotInlineMessage((PsiClass)psiClass.getNavigationElement()))), "Check if inline is possible...", true, project)) return;
if (errorMessage.get() != null) {
CommonRefactoringUtil.showErrorHint(project, editor, errorMessage.get(), RefactoringBundle.message("inline.to.anonymous.refactoring"), null);
return;
@@ -201,7 +202,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
if (psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
return RefactoringBundle.message("inline.to.anonymous.no.abstract");
}
if (!psiClass.getManager().isInProject(psiClass)) {
if (psiClass instanceof PsiCompiledElement) {
return "Library classes cannot be inlined";
}
@@ -230,6 +231,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
}
}
final GlobalSearchScope searchScope = GlobalSearchScope.projectScope(psiClass.getProject());
final PsiMethod[] methods = psiClass.getMethods();
for(PsiMethod method: methods) {
if (method.isConstructor()) {
@@ -238,7 +240,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
}
}
else if (method.findSuperMethods().length == 0) {
if (!ReferencesSearch.search(method).forEach(new AllowedUsagesProcessor(psiClass))) {
if (!ReferencesSearch.search(method, searchScope).forEach(new AllowedUsagesProcessor(psiClass))) {
return "Class cannot be inlined because there are usages of its methods not inherited from its superclass or interface";
}
}
@@ -253,7 +255,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
if (classModifiers.hasModifierProperty(PsiModifier.STATIC)) {
return "Class cannot be inlined because it has static inner classes";
}
if (!ReferencesSearch.search(innerClass).forEach(new AllowedUsagesProcessor(psiClass))) {
if (!ReferencesSearch.search(innerClass, searchScope).forEach(new AllowedUsagesProcessor(psiClass))) {
return "Class cannot be inlined because it has usages of its inner classes";
}
}
@@ -274,7 +276,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
return "Class cannot be inlined because it has static fields with non-constant initializers";
}
}
if (!ReferencesSearch.search(field).forEach(new AllowedUsagesProcessor(psiClass))) {
if (!ReferencesSearch.search(field, searchScope).forEach(new AllowedUsagesProcessor(psiClass))) {
return "Class cannot be inlined because it has usages of fields not inherited from its superclass";
}
}
@@ -305,7 +307,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
@Nullable
private static String getCannotInlineDueToUsagesMessage(final PsiClass aClass) {
boolean hasUsages = false;
for(PsiReference reference : ReferencesSearch.search(aClass)) {
for(PsiReference reference : ReferencesSearch.search(aClass, GlobalSearchScope.projectScope(aClass.getProject()))) {
final PsiElement element = reference.getElement();
if (element == null) continue;
if (!PsiTreeUtil.isAncestor(aClass, element, false)) {
@@ -359,10 +361,10 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
@Override
public boolean process(final PsiReference psiReference) {
if (PsiTreeUtil.isAncestor(myPsiElement, psiReference.getElement(), false)) {
PsiElement element = psiReference.getElement();
if (element != null && PsiTreeUtil.isAncestor(myPsiElement, element.getNavigationElement(), false)) {
return true;
}
PsiElement element = psiReference.getElement();
if (element instanceof PsiReferenceExpression) {
PsiExpression qualifier = ((PsiReferenceExpression)element).getQualifierExpression();
while (qualifier instanceof PsiParenthesizedExpression) {
@@ -371,7 +373,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
if (qualifier instanceof PsiNewExpression) {
PsiNewExpression newExpr = (PsiNewExpression) qualifier;
PsiJavaCodeReferenceElement classRef = newExpr.getClassReference();
if (classRef != null && myPsiElement.equals(classRef.resolve())) {
if (classRef != null && myPsiElement.isEquivalentTo(classRef.resolve())) {
return true;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -76,7 +76,8 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
return new UsageInfo[] { new UsageInfo(myCallToInline) };
}
Set<UsageInfo> usages = new HashSet<>();
for (PsiReference reference : ReferencesSearch.search(myClass)) {
final GlobalSearchScope searchScope = GlobalSearchScope.projectScope(myProject);
for (PsiReference reference : ReferencesSearch.search(myClass, searchScope)) {
usages.add(new UsageInfo(reference.getElement()));
}
@@ -89,9 +90,8 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
}
if (mySearchInNonJavaFiles) {
GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myClass.getProject());
TextOccurrencesUtil.addTextOccurences(myClass, qName, projectScope, nonCodeUsages,
new NonCodeUsageInfoFactory(myClass, qName));
TextOccurrencesUtil.addTextOccurences(myClass, qName, searchScope, nonCodeUsages,
new NonCodeUsageInfoFactory(myClass, qName));
}
usages.addAll(nonCodeUsages);
}
@@ -99,6 +99,15 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
return usages.toArray(new UsageInfo[usages.size()]);
}
@NotNull
@Override
protected Collection<? extends PsiElement> getElementsToWrite(@NotNull UsageViewDescriptor descriptor) {
if (!myInlineThisOnly && !myClass.isWritable()) {
return Collections.emptyList();
}
return super.getElementsToWrite(descriptor);
}
protected void refreshElements(@NotNull PsiElement[] elements) {
assert elements.length == 1;
myClass = (PsiClass) elements [0];
@@ -156,7 +165,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
@Override
public void visitParameter(PsiParameter parameter) {
super.visitParameter(parameter);
if (PsiUtil.resolveClassInType(parameter.getType()) != myClass) return;
if (!myClass.isEquivalentTo(PsiUtil.resolveClassInType(parameter.getType()))) return;
for (PsiReference psiReference : ReferencesSearch.search(parameter)) {
final PsiElement refElement = psiReference.getElement();
@@ -180,7 +189,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
@Override
public void visitNewExpression(PsiNewExpression expression) {
super.visitNewExpression(expression);
if (PsiUtil.resolveClassInType(expression.getType()) != myClass) return;
if (!myClass.isEquivalentTo(PsiUtil.resolveClassInType(expression.getType()))) return;
result.putValue(expression, "Class cannot be inlined because a call to its constructor inside body");
}
@@ -189,7 +198,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
super.visitMethodCallExpression(expression);
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
if (qualifierExpression != null && PsiUtil.resolveClassInType(qualifierExpression.getType()) != myClass) return;
if (qualifierExpression != null && !myClass.isEquivalentTo(PsiUtil.resolveClassInType(qualifierExpression.getType()))) return;
final PsiElement resolved = methodExpression.resolve();
if (resolved instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)resolved;
@@ -244,7 +253,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
LOG.error(e);
}
}
if (!myInlineThisOnly) {
if (!myInlineThisOnly && myClass.getOriginalElement().isWritable()) {
try {
myClass.delete();
}
@@ -262,7 +271,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
else {
PsiClass target = superType.resolve();
assert target != null : superType;
PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory();
PsiJavaCodeReferenceElement element = factory.createClassReferenceElement(target);
PsiJavaCodeReferenceElement reference = psiNewExpression.getClassReference();
assert reference != null : psiNewExpression;
@@ -275,11 +284,11 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
}
private void replaceWithSuperType(final PsiTypeElement typeElement, final PsiClassType superType) {
PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory();
PsiClassType psiType = (PsiClassType) typeElement.getType();
PsiClassType.ClassResolveResult classResolveResult = psiType.resolveGenerics();
PsiType substType = classResolveResult.getSubstitutor().substitute(superType);
assert classResolveResult.getElement() == myClass;
assert myClass.isEquivalentTo(classResolveResult.getElement());
try {
PsiElement replaced = typeElement.replace(factory.createTypeElement(substType));
JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(replaced);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -82,7 +82,8 @@ class InlineToAnonymousConstructorProcessor {
checkInlineChainingConstructor();
JavaResolveResult classResolveResult = myNewExpression.getClassReference().advancedResolve(false);
JavaResolveResult methodResolveResult = myNewExpression.resolveMethodGenerics();
myConstructor = (PsiMethod) methodResolveResult.getElement();
final PsiElement element = methodResolveResult.getElement();
myConstructor = element != null ? (PsiMethod) element.getNavigationElement() : null;
myConstructorArguments = myNewExpression.getArgumentList();
PsiSubstitutor classResolveSubstitutor = classResolveResult.getSubstitutor();