java builder completion: don't disprefer methods that can be called multiple times (IDEA-CR-47127,IDEA-211080)

GitOrigin-RevId: e3be838bca3755bdb935d46c8527ea01b0dfc495
This commit is contained in:
peter
2019-05-16 16:11:45 +03:00
committed by intellij-monorepo-bot
parent c62a77d3f2
commit 0e9086f681
3 changed files with 18 additions and 7 deletions
@@ -23,6 +23,7 @@ import com.intellij.util.ObjectUtils;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -89,19 +90,26 @@ public class JavaCompletionSorting {
@Nullable
private static LookupElementWeigher dispreferPreviousChainCalls(PsiElement position) {
Set<PsiMethod> previousChainCalls = new HashSet<>();
TObjectIntHashMap<PsiMethod> previousChainCalls = new TObjectIntHashMap<>();
if (position.getParent() instanceof PsiReferenceExpression) {
PsiMethodCallExpression qualifier = getCallQualifier((PsiReferenceExpression)position.getParent());
while (qualifier != null) {
ContainerUtil.addIfNotNull(previousChainCalls, qualifier.resolveMethod());
PsiMethod method = qualifier.resolveMethod();
if (method != null) {
String name = method.getName();
boolean seemsLikeExpectsMultipleCalls = name.startsWith("put") || name.startsWith("add");
if (!seemsLikeExpectsMultipleCalls) {
previousChainCalls.put(method, previousChainCalls.get(method) + 1);
}
}
qualifier = getCallQualifier(qualifier.getMethodExpression());
}
}
return previousChainCalls.isEmpty() ? null : new LookupElementWeigher("dispreferPreviousChainCalls") {
@Override
public Comparable weigh(@NotNull LookupElement element, @NotNull WeighingContext context) {
//noinspection SuspiciousMethodCalls
return previousChainCalls.contains(element.getPsiElement());
PsiElement psi = element.getPsiElement();
return psi instanceof PsiMethod && previousChainCalls.get((PsiMethod)psi) == 1;
}
};
}
@@ -1,13 +1,16 @@
class Test {
{
MyBuilder b;
b.a().b().<caret>
b.x().b().addInt(1).putLong(2).mayCallManyTimes().mayCallManyTimes().<caret>
}
}
interface MyBuilder {
MyBuilder a();
MyBuilder x();
MyBuilder b();
MyBuilder c();
MyBuilder d();
MyBuilder addInt(int a);
MyBuilder putLong(long a);
MyBuilder mayCallManyTimes();
}
@@ -872,7 +872,7 @@ class Foo {
}
void testDispreferAlreadyCalledBuilderMethods() {
checkPreferredItems 0, 'c', 'd'
checkPreferredItems 0, 'addInt', 'c', 'd', 'mayCallManyTimes', 'putLong'
}
void testPreferPrintln() {