IDEA-171205 Create local variable from usage: honor most suitable overload by parameter count

This commit is contained in:
Tagir Valeev
2017-04-10 11:25:31 +07:00
parent e5ddd95495
commit f4c6d909ab
3 changed files with 97 additions and 91 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -67,6 +67,7 @@ import com.intellij.psi.util.proximity.PsiProximityComparator;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -388,71 +389,68 @@ public class CreateFromUsageUtils {
final PsiElementFactory factory = facade.getElementFactory();
return ApplicationManager.getApplication().runWriteAction(
new Computable<PsiClass>() {
@Override
public PsiClass compute() {
try {
PsiClass targetClass;
if (directory != null) {
try {
if (classKind == CreateClassKind.INTERFACE) {
targetClass = JavaDirectoryService.getInstance().createInterface(directory, name);
}
else if (classKind == CreateClassKind.CLASS) {
targetClass = JavaDirectoryService.getInstance().createClass(directory, name);
}
else if (classKind == CreateClassKind.ENUM) {
targetClass = JavaDirectoryService.getInstance().createEnum(directory, name);
}
else if (classKind == CreateClassKind.ANNOTATION) {
targetClass = JavaDirectoryService.getInstance().createAnnotationType(directory, name);
}
else {
LOG.error("Unknown kind of a class to create");
return null;
}
}
catch (final IncorrectOperationException e) {
scheduleFileOrPackageCreationFailedMessageBox(e, name, directory, false);
return null;
}
if (!facade.getResolveHelper().isAccessible(targetClass, contextElement, null)) {
PsiUtil.setModifierProperty(targetClass, PsiModifier.PUBLIC, true);
}
}
else { //tests
PsiClass aClass;
(Computable<PsiClass>)() -> {
try {
PsiClass targetClass;
if (directory != null) {
try {
if (classKind == CreateClassKind.INTERFACE) {
aClass = factory.createInterface(name);
targetClass = JavaDirectoryService.getInstance().createInterface(directory, name);
}
else if (classKind == CreateClassKind.CLASS) {
aClass = factory.createClass(name);
targetClass = JavaDirectoryService.getInstance().createClass(directory, name);
}
else if (classKind == CreateClassKind.ENUM) {
aClass = factory.createEnum(name);
targetClass = JavaDirectoryService.getInstance().createEnum(directory, name);
}
else if (classKind == CreateClassKind.ANNOTATION) {
aClass = factory.createAnnotationType(name);
targetClass = JavaDirectoryService.getInstance().createAnnotationType(directory, name);
}
else {
LOG.error("Unknown kind of a class to create");
return null;
}
targetClass = (PsiClass) sourceFile.add(aClass);
}
catch (final IncorrectOperationException e) {
scheduleFileOrPackageCreationFailedMessageBox(e, name, directory, false);
return null;
}
if (!facade.getResolveHelper().isAccessible(targetClass, contextElement, null)) {
PsiUtil.setModifierProperty(targetClass, PsiModifier.PUBLIC, true);
}
}
else { //tests
PsiClass aClass;
if (classKind == CreateClassKind.INTERFACE) {
aClass = factory.createInterface(name);
}
else if (classKind == CreateClassKind.CLASS) {
aClass = factory.createClass(name);
}
else if (classKind == CreateClassKind.ENUM) {
aClass = factory.createEnum(name);
}
else if (classKind == CreateClassKind.ANNOTATION) {
aClass = factory.createAnnotationType(name);
}
else {
LOG.error("Unknown kind of a class to create");
return null;
}
targetClass = (PsiClass)sourceFile.add(aClass);
}
if (superClassName != null && (classKind != CreateClassKind.ENUM || !superClassName.equals(CommonClassNames.JAVA_LANG_ENUM))) {
setupSuperClassReference(targetClass, superClassName);
}
if (contextElement instanceof PsiJavaCodeReferenceElement) {
CreateFromUsageBaseFix.setupGenericParameters(targetClass, (PsiJavaCodeReferenceElement)contextElement);
}
return targetClass;
if (superClassName != null && (classKind != CreateClassKind.ENUM || !superClassName.equals(CommonClassNames.JAVA_LANG_ENUM))) {
setupSuperClassReference(targetClass, superClassName);
}
catch (IncorrectOperationException e) {
LOG.error(e);
return null;
if (contextElement instanceof PsiJavaCodeReferenceElement) {
CreateFromUsageBaseFix.setupGenericParameters(targetClass, (PsiJavaCodeReferenceElement)contextElement);
}
return targetClass;
}
catch (IncorrectOperationException e) {
LOG.error(e);
return null;
}
});
}
@@ -571,16 +569,27 @@ public class CreateFromUsageUtils {
List<ExpectedTypeInfo[]> types,
List<String> expectedMethodNames,
List<String> expectedFieldNames) {
Comparator<ExpectedTypeInfo> expectedTypesComparator = (o1, o2) -> compareExpectedTypes(o1, o2, expression);
for (PsiExpression expr : collectExpressions(expression, PsiMember.class, PsiFile.class)) {
PsiElement parent = expr.getParent();
if (!(parent instanceof PsiReferenceExpression)) {
boolean isAssignmentToFunctionalExpression = PsiUtil.isOnAssignmentLeftHand(expr) &&
((PsiAssignmentExpression)PsiUtil.skipParenthesizedExprUp(parent)).getRExpression() instanceof PsiFunctionalExpression;
boolean forCompletion = PsiUtil.skipParenthesizedExprUp(isAssignmentToFunctionalExpression ? parent.getParent() : parent) instanceof PsiExpressionList;
PsiExpressionList expressionList = ObjectUtils
.tryCast(PsiUtil.skipParenthesizedExprUp(isAssignmentToFunctionalExpression ? parent.getParent() : parent),
PsiExpressionList.class);
boolean forCompletion = expressionList != null;
ExpectedTypeInfo[] someExpectedTypes = ExpectedTypesProvider.getExpectedTypes(expr, forCompletion);
if (someExpectedTypes.length > 0) {
Arrays.sort(someExpectedTypes, (o1, o2) -> compareExpectedTypes(o1, o2, expression));
Comparator<ExpectedTypeInfo> comparator = expectedTypesComparator;
if (expressionList != null) {
int argCount = expressionList.getExpressions().length;
Comparator<ExpectedTypeInfo> mostSuitableMethodComparator = Comparator
.comparingInt((ExpectedTypeInfo eti) -> eti.getCalledMethod().getParameterList().getParametersCount() == argCount ? 0 : 1);
comparator = mostSuitableMethodComparator.thenComparing(comparator);
}
Arrays.sort(someExpectedTypes, comparator);
types.add(someExpectedTypes);
}
continue;
@@ -597,7 +606,7 @@ public class CreateFromUsageUtils {
if (refName.equals("equals")) {
ExpectedTypeInfo[] someExpectedTypes = equalsExpectedTypes((PsiMethodCallExpression)pparent);
if (someExpectedTypes.length > 0) {
Arrays.sort(someExpectedTypes, (o1, o2) -> compareExpectedTypes(o1, o2, expression));
Arrays.sort(someExpectedTypes, expectedTypesComparator);
types.add(someExpectedTypes);
}
}
@@ -689,7 +698,7 @@ public class CreateFromUsageUtils {
}
@Nullable
@NotNull
static PsiType[] guessType(PsiExpression expression, final boolean allowVoidType) {
final PsiManager manager = expression.getManager();
final GlobalSearchScope resolveScope = expression.getResolveScope();
@@ -876,12 +885,8 @@ public class CreateFromUsageUtils {
final Module moduleForFile = ModuleUtilCore.findModuleForPsiElement(file);
if (moduleForFile == null) return;
final GlobalSearchScope searchScope = ApplicationManager.getApplication().runReadAction(new Computable<GlobalSearchScope>() {
@Override
public GlobalSearchScope compute() {
return file.getResolveScope();
}
});
final GlobalSearchScope searchScope =
ApplicationManager.getApplication().runReadAction((Computable<GlobalSearchScope>)file::getResolveScope);
GlobalSearchScope descendantsSearchScope = GlobalSearchScope.moduleWithDependenciesScope(moduleForFile);
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
@@ -890,12 +895,10 @@ public class CreateFromUsageUtils {
return;
}
final PsiMember[] members = ApplicationManager.getApplication().runReadAction(new Computable<PsiMember[]>() {
@Override
public PsiMember[] compute() {
return method ? cache.getMethodsByName(memberName, searchScope) : cache.getFieldsByName(memberName, searchScope);
}
});
final PsiMember[] members = ApplicationManager.getApplication().runReadAction(
(Computable<PsiMember[]>)() -> method
? cache.getMethodsByName(memberName, searchScope)
: cache.getFieldsByName(memberName, searchScope));
for (int i = 0; i < members.length; ++i) {
final PsiMember member = members[i];
@@ -942,19 +945,10 @@ public class CreateFromUsageUtils {
return true;
}
final String[] strings = ApplicationManager.getApplication().runReadAction(new Computable<String[]>() {
@Override
public String[] compute() {
return cache.getAllClassNames();
}
});
final String[] strings = ApplicationManager.getApplication().runReadAction((Computable<String[]>)cache::getAllClassNames);
for (final String className : strings) {
final PsiClass[] classes = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass[]>() {
@Override
public PsiClass[] compute() {
return cache.getClassesByName(className, searchScope);
}
});
final PsiClass[] classes = ApplicationManager.getApplication().runReadAction(
(Computable<PsiClass[]>)() -> cache.getClassesByName(className, searchScope));
for (final PsiClass aClass : classes) {
final String qname = getQualifiedName(aClass);
ContainerUtil.addIfNotNull(possibleClassNames, qname);
@@ -967,13 +961,7 @@ public class CreateFromUsageUtils {
@Nullable
private static String getQualifiedName(final PsiClass aClass) {
return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Nullable
@Override
public String compute() {
return aClass.getQualifiedName();
}
});
return ApplicationManager.getApplication().runReadAction((Computable<String>)aClass::getQualifiedName);
}
private static boolean hasCorrectModifiers(@Nullable final PsiMember member, final boolean staticAccess) {
@@ -981,12 +969,9 @@ public class CreateFromUsageUtils {
return false;
}
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return !member.hasModifierProperty(PsiModifier.PRIVATE) && member.hasModifierProperty(PsiModifier.STATIC) == staticAccess;
}
}).booleanValue();
return ApplicationManager.getApplication().runReadAction(
(Computable<Boolean>)() -> !member.hasModifierProperty(PsiModifier.PRIVATE) &&
member.hasModifierProperty(PsiModifier.STATIC) == staticAccess).booleanValue();
}
private static class ParameterNameExpression extends Expression {

View File

@@ -0,0 +1,11 @@
// "Create local variable 'xyz'" "true"
interface Other<T> {
void add(int x, T y);
void add(T y);
}
class A {
public void foo(Other<String> other) {
String xyz;
other.add(xyz);
}
}

View File

@@ -0,0 +1,10 @@
// "Create local variable 'xyz'" "true"
interface Other<T> {
void add(int x, T y);
void add(T y);
}
class A {
public void foo(Other<String> other) {
other.add(x<caret>yz);
}
}