summaryrefslogtreecommitdiff
path: root/java/java-impl/src/com/intellij/codeInsight/completion/methodChains
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-impl/src/com/intellij/codeInsight/completion/methodChains')
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsCompletionContributor.java38
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionNewVariableLookupElement.java80
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/WeightableChainLookupElement.java1
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/CachedNotDeprecatedMethodsResolver.java36
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainRelevance.java17
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainsSearcher.java331
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MaxSizeTreeSet.java209
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchService.java54
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChain.java121
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChainLookupRangingHelper.java85
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ParametersMatcher.java82
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/SearchInitializer.java64
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/WeightAware.java6
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/OverridenMethodsService.java65
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/SingletonService.java89
15 files changed, 721 insertions, 557 deletions
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsCompletionContributor.java
index 27c63a0c2a50..8781e46630bf 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsCompletionContributor.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/MethodsChainsCompletionContributor.java
@@ -9,7 +9,7 @@ import com.intellij.codeInsight.completion.methodChains.search.MethodChainsSearc
import com.intellij.codeInsight.completion.methodChains.search.MethodsChain;
import com.intellij.codeInsight.completion.methodChains.search.MethodsChainLookupRangingHelper;
import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer;
+import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexFeature;
import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.text.StringUtil;
@@ -35,13 +35,13 @@ import static com.intellij.patterns.PsiJavaPatterns.or;
public class MethodsChainsCompletionContributor extends CompletionContributor {
public static final int INVOCATIONS_THRESHOLD = 3;
- private final static int MAX_SEARCH_RESULT_SIZE = 20;
+ private final static int MAX_SEARCH_RESULT_SIZE = 5;
private final static int MAX_CHAIN_SIZE = 4;
private final static int FILTER_RATIO = 10;
@Override
public void fillCompletionVariants(final CompletionParameters parameters, final CompletionResultSet result) {
- if (parameters.getInvocationCount() >= INVOCATIONS_THRESHOLD && CompilerOutputIndexer.getInstance(parameters.getPosition().getProject()).isEnabled()) {
+ if (parameters.getInvocationCount() >= INVOCATIONS_THRESHOLD && CompilerOutputIndexFeature.METHOD_CHAINS_COMPLETION.isEnabled()) {
super.fillCompletionVariants(parameters, result);
if (ApplicationManager.getApplication().isUnitTestMode()) {
result.stopHere();
@@ -73,16 +73,19 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
}
contextRelevantTypes.remove(targetClassQName);
- final List<LookupElement> foundedElements = searchForLookups(targetClassQName, contextRelevantTypes, completionContext);
- result.addAllElements(foundedElements);
+ //final boolean useBigrams = ApplicationManager.getApplication().isUnitTestMode() || parameters.getInvocationCount() == 3;
+ final boolean useBigrams = true;
+ final List<LookupElement> foundElements = searchForLookups(targetClassQName, contextRelevantTypes, completionContext, useBigrams);
+ result.addAllElements(foundElements);
}
});
}
private static List<LookupElement> searchForLookups(final String targetClassQName,
final Set<String> contextRelevantTypes,
- final ChainCompletionContext completionContext) {
- final MethodChainsSearchService searchService = new MethodChainsSearchService(completionContext.getProject());
+ final ChainCompletionContext completionContext,
+ final boolean useBigrams) {
+ final MethodChainsSearchService searchService = new MethodChainsSearchService(completionContext.getProject(), useBigrams);
final List<MethodsChain> searchResult =
searchChains(targetClassQName, contextRelevantTypes, MAX_SEARCH_RESULT_SIZE, MAX_CHAIN_SIZE, completionContext, searchService);
if (searchResult.size() < MAX_SEARCH_RESULT_SIZE) {
@@ -100,7 +103,8 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
completionContext, searchService)) {
boolean insert = true;
for (final MethodsChain baseChain : searchResult) {
- if (baseChain.weakContains(chain)) {
+ final MethodsChain.CompareResult r = MethodsChain.compare(baseChain, chain, completionContext);
+ if (r != MethodsChain.CompareResult.NOT_EQUAL) {
insert = false;
break;
}
@@ -116,8 +120,19 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
});
}
}
- return MethodsChainLookupRangingHelper.chainsToWeightableLookupElements(filterTailAndGetSumLastMethodOccurrence(searchResult),
- completionContext);
+ final List<MethodsChain> chains = searchResult.size() > MAX_CHAIN_SIZE ? chooseHead(searchResult) : searchResult;
+ return MethodsChainLookupRangingHelper
+ .chainsToWeightableLookupElements(filterTailAndGetSumLastMethodOccurrence(chains), completionContext);
+ }
+
+ private static List<MethodsChain> chooseHead(final List<MethodsChain> elements) {
+ Collections.sort(elements, new Comparator<MethodsChain>() {
+ @Override
+ public int compare(final MethodsChain o1, final MethodsChain o2) {
+ return o2.getChainWeight() - o1.getChainWeight();
+ }
+ });
+ return elements.subList(0, MAX_CHAIN_SIZE);
}
@SuppressWarnings("unchecked")
@@ -188,8 +203,7 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
final MethodChainsSearchService searchService) {
return ChainsSearcher.search(searchService, targetQName, contextVarsQNames, maxResultSize, maxChainSize,
createNotDeprecatedMethodsResolver(JavaPsiFacade.getInstance(context.getProject()),
- context.getResolveScope()),
- context.getExcludedQNames(), context.getContextMethodName());
+ context.getResolveScope()), context.getExcludedQNames(), context);
}
private static FactoryMap<MethodIncompleteSignature, PsiMethod[]> createNotDeprecatedMethodsResolver(final JavaPsiFacade javaPsiFacade,
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionNewVariableLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionNewVariableLookupElement.java
index 53dc9bc9eed5..b775640edbdb 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionNewVariableLookupElement.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/ChainCompletionNewVariableLookupElement.java
@@ -1,10 +1,15 @@
package com.intellij.codeInsight.completion.methodChains.completion.lookup;
+import com.intellij.codeInsight.completion.CompletionInitializationContext;
import com.intellij.codeInsight.completion.InsertionContext;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
-import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.SuggestedNameInfo;
@@ -12,59 +17,92 @@ import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
+import java.util.Collection;
+
/**
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
-public class ChainCompletionNewVariableLookupElement extends LookupItem<PsiClass> {
+public class ChainCompletionNewVariableLookupElement extends LookupElementDecorator<LookupElement> {
+ private final static Logger log = Logger.getInstance(ChainCompletionNewVariableLookupElement.class);
- private final PsiClass psiClass;
- private final String newVarName;
+ private final PsiClass myPsiClass;
+ private final String myNewVarName;
- public ChainCompletionNewVariableLookupElement(final PsiClass psiClass, final String newVarName) {
- super(psiClass, newVarName);
- this.newVarName = newVarName;
- this.psiClass = psiClass;
+ public ChainCompletionNewVariableLookupElement(final PsiClass psiClass, final String newVarName, final LookupElement calledMethods) {
+ super(calledMethods);
+ myNewVarName = newVarName;
+ myPsiClass = psiClass;
}
- public static ChainCompletionNewVariableLookupElement create(final PsiClass psiClass) {
+ public static ChainCompletionNewVariableLookupElement create(final PsiClass psiClass, final LookupElement calledMethods) {
final Project project = psiClass.getProject();
- final SuggestedNameInfo suggestedNameInfo = JavaCodeStyleManager.getInstance(project).suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, JavaPsiFacade .getElementFactory( project).createType(psiClass));
- return new ChainCompletionNewVariableLookupElement(psiClass, chooseLongest(suggestedNameInfo.names));
+ final String newVarName = chooseLongestName(JavaCodeStyleManager.getInstance(project).
+ suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, JavaPsiFacade.getElementFactory(project).createType(psiClass)));
+ return new ChainCompletionNewVariableLookupElement(psiClass, newVarName, calledMethods);
}
@Override
public void handleInsert(final InsertionContext context) {
+ final RangeMarker rangeMarker = context.getDocument().createRangeMarker(context.getStartOffset(), context.getStartOffset());
+ getDelegate().handleInsert(context);
final PsiFile file = context.getFile();
- ((PsiJavaFile) file).importClass(psiClass);
- final PsiStatement statement = PsiTreeUtil.getParentOfType(file.findElementAt(context.getEditor().getCaretModel().getOffset()), PsiStatement.class);
+ ((PsiJavaFile)file).importClass(myPsiClass);
+ final PsiElement caretElement = file.findElementAt(context.getEditor().getCaretModel().getOffset());
+ if (caretElement == null) {
+ log.error("element on caret position MUST BE not null");
+ return;
+ }
+ final PsiStatement statement = (PsiStatement) caretElement.getPrevSibling();
final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(statement, PsiCodeBlock.class);
- assert codeBlock != null;
+ if (codeBlock == null) {
+ log.error("code block MUST BE not null");
+ return;
+ }
final Project project = context.getProject();
+ final Ref<PsiElement> insertedStatementRef = Ref.create();
+ final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
+ context.commitDocument();
new WriteCommandAction.Simple(project, file) {
@Override
protected void run() throws Throwable {
- codeBlock.addBefore(
- JavaPsiFacade.getElementFactory(
- project).
- createStatementFromText(String.format("%s %s = null;", psiClass.getName(), newVarName), null), statement);
+ final PsiStatement statementFromText = elementFactory.createStatementFromText(String.format("%s %s = null;", myPsiClass.getName(), myNewVarName), null);
+ insertedStatementRef.set(codeBlock.addBefore(statementFromText, statement));
}
}.execute();
+ final PsiLiteralExpression nullKeyword = findNull(insertedStatementRef.get());
PsiDocumentManager.getInstance(context.getProject()).doPostponedOperationsAndUnblockDocument(context.getDocument());
+ context.getDocument().insertString(rangeMarker.getStartOffset(), myNewVarName + ".");
+ context.commitDocument();
+ final int offset = nullKeyword.getTextOffset();
+ final int endOffset = offset + nullKeyword.getTextLength();
+ context.getEditor().getSelectionModel().setSelection(offset, endOffset);
+ context.getEditor().getCaretModel().moveToOffset(offset);
}
@NotNull
@Override
public String getLookupString() {
- return newVarName;
+ return getDelegate().getLookupString();
}
@Override
public void renderElement(final LookupElementPresentation presentation) {
super.renderElement(presentation);
- presentation.setItemText(newVarName);
+ presentation.setItemText(myNewVarName + "." + presentation.getItemText());
+ }
+
+ private static PsiLiteralExpression findNull(final PsiElement psiElement) {
+ final Collection<PsiLiteralExpression> literalExpressions = PsiTreeUtil.findChildrenOfType(psiElement, PsiLiteralExpression.class);
+ for (final PsiLiteralExpression literalExpression : literalExpressions) {
+ if (PsiKeyword.NULL.equals(literalExpression.getText())) {
+ return literalExpression;
+ }
+ }
+ throw new IllegalArgumentException();
}
- private static String chooseLongest(final String[] names) {
+ private static String chooseLongestName(final SuggestedNameInfo suggestedNameInfo) {
+ final String[] names = suggestedNameInfo.names;
String longestWord = names[0];
int maxLength = longestWord.length();
for (int i = 1; i < names.length; i++) {
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/WeightableChainLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/WeightableChainLookupElement.java
index e58d2c84e7df..16ee64688c41 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/WeightableChainLookupElement.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/completion/lookup/WeightableChainLookupElement.java
@@ -3,6 +3,7 @@ package com.intellij.codeInsight.completion.methodChains.completion.lookup;
import com.intellij.codeInsight.completion.methodChains.search.ChainRelevance;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
+import com.intellij.codeInsight.lookup.LookupElementPresentation;
import org.jetbrains.annotations.NotNull;
/**
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/CachedNotDeprecatedMethodsResolver.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/CachedNotDeprecatedMethodsResolver.java
deleted file mode 100644
index 018065a7ed56..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/CachedNotDeprecatedMethodsResolver.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.intellij.codeInsight.completion.methodChains.search;
-
-import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.JavaPsiFacade;
-import com.intellij.psi.PsiMethod;
-import com.intellij.psi.search.GlobalSearchScope;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
- */
-public class CachedNotDeprecatedMethodsResolver {
- private final Map<MethodIncompleteSignature, PsiMethod[]> myResolveLocalCache = new HashMap<MethodIncompleteSignature, PsiMethod[]>();
- private final JavaPsiFacade myJavaPsiFacade;
- private final GlobalSearchScope myScope;
-
- public CachedNotDeprecatedMethodsResolver(final Project project, final GlobalSearchScope scope) {
- myScope = scope;
- myJavaPsiFacade = JavaPsiFacade.getInstance(project);
- }
-
- @NotNull
- public PsiMethod[] resolveNotDeprecated(@NotNull final MethodIncompleteSignature methodInvocation) {
- final PsiMethod[] cached = myResolveLocalCache.get(methodInvocation);
- if (cached != null) {
- return cached;
- }
- final PsiMethod[] methods = methodInvocation.resolveNotDeprecated(myJavaPsiFacade, myScope);
- myResolveLocalCache.put(methodInvocation, methods);
- return methods;
- }
-}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainRelevance.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainRelevance.java
index 09e008a7aa4b..0aa7231ead1d 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainRelevance.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainRelevance.java
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.TestOnly;
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public class ChainRelevance implements Comparable<ChainRelevance> {
- public static final ChainRelevance LOWEST = new ChainRelevance(Integer.MAX_VALUE, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, false, false);
+ public static final ChainRelevance LOWEST = new ChainRelevance(Integer.MAX_VALUE, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, false, false, 0);
private final int myChainSize;
private final int myLastMethodOccurrences;
@@ -15,19 +15,22 @@ public class ChainRelevance implements Comparable<ChainRelevance> {
private final int myNotMatchedStringVars;
private final boolean myHasCallingVariableInContext;
private final boolean myFirstMethodStatic;
+ private final int myParametersInContext;
public ChainRelevance(final int chainSize,
final int lastMethodOccurrences,
final int unreachableParametersCount,
final int notMatchedStringVars,
final boolean hasCallingVariableInContext,
- final boolean firstMethodStatic) {
+ final boolean firstMethodStatic,
+ final int parametersInContext) {
myChainSize = chainSize;
myLastMethodOccurrences = lastMethodOccurrences;
myUnreachableParametersCount = unreachableParametersCount;
myNotMatchedStringVars = notMatchedStringVars;
myHasCallingVariableInContext = hasCallingVariableInContext;
myFirstMethodStatic = firstMethodStatic;
+ myParametersInContext = parametersInContext;
}
@TestOnly
@@ -62,16 +65,22 @@ public class ChainRelevance implements Comparable<ChainRelevance> {
@Override
public int compareTo(@NotNull final ChainRelevance that) {
+ if (myHasCallingVariableInContext && !that.myHasCallingVariableInContext) {
+ return 1;
+ }
+ if (that.myHasCallingVariableInContext && !myHasCallingVariableInContext) {
+ return -1;
+ }
if (myFirstMethodStatic && !that.myFirstMethodStatic) {
return -1;
}
if (that.myFirstMethodStatic && !myFirstMethodStatic) {
return 1;
}
- if (myHasCallingVariableInContext && !that.myHasCallingVariableInContext) {
+ if (myParametersInContext > that.myParametersInContext) {
return 1;
}
- if (that.myHasCallingVariableInContext && !myHasCallingVariableInContext) {
+ if (myParametersInContext <= that.myParametersInContext) {
return -1;
}
int sub = myLastMethodOccurrences - that.myLastMethodOccurrences;
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainsSearcher.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainsSearcher.java
index b47095a096f4..660e0f7f67c3 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainsSearcher.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ChainsSearcher.java
@@ -1,12 +1,15 @@
package com.intellij.codeInsight.completion.methodChains.search;
-import com.intellij.codeInsight.completion.methodChains.Constants;
+import com.intellij.codeInsight.completion.methodChains.completion.context.ChainCompletionContext;
import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature;
import com.intellij.compilerOutputIndex.impl.UsageIndexValue;
import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiMethod;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FactoryMap;
-import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
import java.util.*;
@@ -21,95 +24,59 @@ public class ChainsSearcher {
final int maxResultSize,
final int pathMaximalLength,
final FactoryMap<MethodIncompleteSignature, PsiMethod[]> resolver,
- final String contextMethodName) {
- return search(searchService, targetQName, contextQNames, maxResultSize, pathMaximalLength, resolver,
- Collections.<String>singleton(targetQName), contextMethodName);
- }
-
- public static List<MethodsChain> search(final MethodChainsSearchService searchService,
- final String targetQName,
- final Set<String> contextQNames,
- final int maxResultSize,
- final int pathMaximalLength,
- final FactoryMap<MethodIncompleteSignature, PsiMethod[]> resolver,
final Set<String> excludedParamsTypesQNames,
- final String contextMethodName) {
+ final ChainCompletionContext context) {
final SearchInitializer initializer = createInitializer(targetQName, resolver, searchService, excludedParamsTypesQNames);
- final ArrayList<MethodsChain> methodsChains = new ArrayList<MethodsChain>(maxResultSize);
- final MethodsChain firstBestMethodsChain =
- search(searchService, initializer, contextQNames, Collections.<String>emptySet(), pathMaximalLength, resolver, targetQName,
- excludedParamsTypesQNames, contextMethodName);
- if (firstBestMethodsChain != null) {
- methodsChains.add(firstBestMethodsChain);
- Set<Set<String>> excludedCombinations = MethodsChain.edgeCombinations(Collections.<Set<String>>emptySet(), firstBestMethodsChain);
- while (methodsChains.size() <= maxResultSize) {
- final Set<Set<String>> localExcludedCombinations = excludedCombinations;
- boolean allLocalsIsNull = true;
- final int beforeStepChainsCount = methodsChains.size();
- for (final Set<String> excludedEdges : localExcludedCombinations) {
- final MethodsChain local =
- search(searchService, initializer, contextQNames, excludedEdges, pathMaximalLength, resolver, targetQName,
- excludedParamsTypesQNames, contextMethodName);
- if (local != null) {
- allLocalsIsNull = false;
- }
- else {
- continue;
- }
- boolean add = true;
- for (int i = 0; i < methodsChains.size(); i++) {
- final MethodsChain chain = methodsChains.get(i);
- final MethodsChain.CompareResult compareResult = MethodsChain.compare(local, chain);
- if (compareResult == MethodsChain.CompareResult.EQUAL || compareResult == MethodsChain.CompareResult.RIGHT_CONTAINS_LEFT) {
- add = false;
- break;
- }
- else if (compareResult == MethodsChain.CompareResult.LEFT_CONTAINS_RIGHT) {
- methodsChains.set(i, local);
- add = false;
- break;
- }
- }
- if (add) {
- methodsChains.add(local);
- if (methodsChains.size() >= maxResultSize) {
- return methodsChains;
- }
- excludedCombinations = MethodsChain.edgeCombinations(excludedCombinations, local);
- }
- }
- if (allLocalsIsNull || beforeStepChainsCount == methodsChains.size()) {
- return methodsChains;
- }
- }
- }
- return methodsChains;
+ return search(searchService, initializer, contextQNames, pathMaximalLength, maxResultSize, resolver, targetQName,
+ excludedParamsTypesQNames, context);
}
private static SearchInitializer createInitializer(final String targetQName,
- final FactoryMap<MethodIncompleteSignature, PsiMethod[]> context,
+ final FactoryMap<MethodIncompleteSignature, PsiMethod[]> resolver,
final MethodChainsSearchService searchService,
final Set<String> excludedParamsTypesQNames) {
- return new SearchInitializer(searchService.getMethods(targetQName), context, targetQName, excludedParamsTypesQNames);
+ return new SearchInitializer(searchService.getMethods(targetQName), resolver, targetQName, excludedParamsTypesQNames);
}
- @Nullable
- private static MethodsChain search(final MethodChainsSearchService searchService,
- final SearchInitializer initializer,
- final Set<String> toSet,
- final Set<String> excludedEdgeNames,
- final int pathMaximalLength,
- final FactoryMap<MethodIncompleteSignature, PsiMethod[]> resolver,
- final String targetQName,
- final Set<String> excludedParamsTypesQNames,
- final String contextMethodName) {
+ @NotNull
+ private static List<MethodsChain> search(final MethodChainsSearchService searchService,
+ final SearchInitializer initializer,
+ final Set<String> toSet,
+ final int pathMaximalLength,
+ final int maxResultSize,
+ final FactoryMap<MethodIncompleteSignature, PsiMethod[]> resolver,
+ final String targetQName,
+ final Set<String> excludedParamsTypesQNames,
+ final ChainCompletionContext context) {
final Set<String> allExcludedNames = MethodChainsSearchUtil.unionToHashSet(excludedParamsTypesQNames, targetQName);
- ProgressManager.checkCanceled();
- final SearchInitializer.InitResult initResult = initializer.init(excludedEdgeNames, toSet, searchService, contextMethodName);
+ final SearchInitializer.InitResult initResult = initializer.init(Collections.<String>emptySet());
+
final Map<MethodIncompleteSignature, MethodsChain> knownDistance = initResult.getChains();
- final PriorityQueue<WeightAware<MethodIncompleteSignature>> q =
- new PriorityQueue<WeightAware<MethodIncompleteSignature>>(initResult.getVertexes());
- MethodsChain result = initResult.getCurrentBestTargetChain();
+
+ final List<WeightAware<MethodIncompleteSignature>> allInitialVertexes = initResult.getVertexes();
+
+ final LinkedList<WeightAware<Pair<MethodIncompleteSignature, MethodsChain>>> q =
+ new LinkedList<WeightAware<Pair<MethodIncompleteSignature, MethodsChain>>>(ContainerUtil.map(allInitialVertexes,
+ new Function<WeightAware<MethodIncompleteSignature>, WeightAware<Pair<MethodIncompleteSignature, MethodsChain>>>() {
+ @Override
+ public WeightAware<Pair<MethodIncompleteSignature, MethodsChain>> fun(
+ final WeightAware<MethodIncompleteSignature> methodIncompleteSignatureWeightAware) {
+ return new WeightAware<Pair<MethodIncompleteSignature, MethodsChain>>(
+ new Pair<MethodIncompleteSignature, MethodsChain>(
+ methodIncompleteSignatureWeightAware
+ .getUnderlying(),
+ new MethodsChain(resolver.get(
+ methodIncompleteSignatureWeightAware
+ .getUnderlying()),
+ methodIncompleteSignatureWeightAware
+ .getWeight(),
+ methodIncompleteSignatureWeightAware
+ .getUnderlying()
+ .getOwner())),
+ methodIncompleteSignatureWeightAware
+ .getWeight());
+ }
+ }));
int maxWeight = 0;
for (final MethodsChain methodsChain : knownDistance.values()) {
@@ -118,89 +85,175 @@ public class ChainsSearcher {
}
}
- final WeightAware<MethodIncompleteSignature> maxVertex = q.peek();
- final int maxDistance;
- if (maxVertex != null) {
- maxDistance = maxVertex.getWeight();
- }
- else {
- return null;
- }
+ final ResultHolder result = new ResultHolder(context);
while (!q.isEmpty()) {
- final WeightAware<MethodIncompleteSignature> currentVertex = q.poll();
+ ProgressManager.checkCanceled();
+ final WeightAware<Pair<MethodIncompleteSignature, MethodsChain>> currentVertex = q.poll();
final int currentVertexDistance = currentVertex.getWeight();
- if (currentVertexDistance * Constants.CHAIN_SEARCH_MAGIC_RATIO < maxDistance) {
- return result;
- }
- final MethodIncompleteSignature currentVertexUnderlying = currentVertex.getUnderlying();
- final MethodsChain currentVertexMethodsChain = knownDistance.get(currentVertexUnderlying);
+ final Pair<MethodIncompleteSignature, MethodsChain> currentVertexUnderlying = currentVertex.getUnderlying();
+ final MethodsChain currentVertexMethodsChain = knownDistance.get(currentVertexUnderlying.getFirst());
if (currentVertexDistance != currentVertexMethodsChain.getChainWeight()) {
continue;
}
- final SortedSet<UsageIndexValue> bigrams = searchService.getBigram(currentVertexUnderlying);
- int bigramsSumWeight = 0;
- int maxUpdatedWeight = 0;
+ if (currentVertex.getUnderlying().getFirst().isStatic() || toSet.contains(currentVertex.getUnderlying().getFirst().getOwner())) {
+ result.add(currentVertex.getUnderlying().getSecond());
+ continue;
+ }
+ final SortedSet<UsageIndexValue> bigrams = searchService.getBigram(currentVertexUnderlying.getFirst());
+ final MaxSizeTreeSet<WeightAware<MethodIncompleteSignature>> currentSignatures =
+ new MaxSizeTreeSet<WeightAware<MethodIncompleteSignature>>(maxResultSize);
for (final UsageIndexValue indexValue : bigrams) {
final MethodIncompleteSignature vertex = indexValue.getMethodIncompleteSignature();
final int occurrences = indexValue.getOccurrences();
- bigramsSumWeight += occurrences;
- final boolean canBeResult = vertex.isStatic() || toSet.contains(vertex.getOwner());
- if (!vertex.getOwner().equals(targetQName) || canBeResult) {
+ if (!vertex.getOwner().equals(targetQName)) {
final int vertexDistance = Math.min(currentVertexDistance, occurrences);
final MethodsChain knownVertexMethodsChain = knownDistance.get(vertex);
- if ((knownVertexMethodsChain == null || knownVertexMethodsChain.getChainWeight() < vertexDistance) &&
- (result == null || result.getChainWeight() < vertexDistance)) {
- if (occurrences * Constants.CHAIN_SEARCH_MAGIC_RATIO >= currentVertexMethodsChain.getChainWeight()) {
+ if ((knownVertexMethodsChain == null || knownVertexMethodsChain.getChainWeight() < vertexDistance)) {
+ if (currentSignatures.isEmpty() || currentSignatures.last().getWeight() < vertexDistance) {
final MethodIncompleteSignature methodInvocation = indexValue.getMethodIncompleteSignature();
final PsiMethod[] psiMethods = resolver.get(methodInvocation);
-
if (psiMethods.length != 0 && MethodChainsSearchUtil.checkParametersForTypesQNames(psiMethods, allExcludedNames)) {
- final MethodsChain newBestMethodsChain = currentVertexMethodsChain.addEdge(psiMethods);
- if (canBeResult) {
- result = newBestMethodsChain;
- }
- else if (newBestMethodsChain.size() < pathMaximalLength - 1) {
- maxUpdatedWeight = Math.max(maxUpdatedWeight, newBestMethodsChain.getChainWeight());
- q.add(new WeightAware<MethodIncompleteSignature>(indexValue.getMethodIncompleteSignature(),
- newBestMethodsChain.getChainWeight()));
+ final MethodsChain newBestMethodsChain =
+ currentVertexMethodsChain.addEdge(psiMethods, indexValue.getMethodIncompleteSignature().getOwner(), vertexDistance);
+ if (newBestMethodsChain.size() <= pathMaximalLength - 1) {
+ currentSignatures
+ .add(new WeightAware<MethodIncompleteSignature>(indexValue.getMethodIncompleteSignature(), vertexDistance));
}
knownDistance.put(vertex, newBestMethodsChain);
}
}
- else if (!allExcludedNames.contains(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName()) &&
- searchService.isSingleton(currentVertexMethodsChain.getFirstQualifierClass(), contextMethodName) &&
- (searchService.isRelevantMethodForNotOverriden(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName(),
- currentVertexMethodsChain.getOneOfFirst().getName()) ||
- searchService.isRelevantMethodForField(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName(),
- currentVertexMethodsChain.getOneOfFirst().getName()))) {
- result = currentVertexMethodsChain;
+ }
+ }
+ }
+ boolean updated = false;
+ if (!currentSignatures.isEmpty()) {
+ boolean isBreak = false;
+ for (final WeightAware<MethodIncompleteSignature> sign : currentSignatures) {
+ final PsiMethod[] resolved = resolver.get(sign.getUnderlying());
+ if (!isBreak) {
+ if (sign.getWeight() * maxResultSize > currentVertex.getWeight()) {
+ final boolean stopChain = sign.getUnderlying().isStatic() || toSet.contains(sign.getUnderlying().getOwner());
+ if (stopChain) {
+ updated = true;
+ result.add(currentVertex.getUnderlying().getSecond().addEdge(resolved, sign.getUnderlying().getOwner(), sign.getWeight()));
+ continue;
+ }
+ else {
+ updated = true;
+ final MethodsChain methodsChain =
+ currentVertexUnderlying.second.addEdge(resolved, sign.getUnderlying().getOwner(), sign.getWeight());
+ q.add(new WeightAware<Pair<MethodIncompleteSignature, MethodsChain>>(
+ new Pair<MethodIncompleteSignature, MethodsChain>(sign.getUnderlying(), methodsChain), sign.getWeight()));
+ continue;
+ }
}
}
+ final MethodsChain methodsChain =
+ currentVertexUnderlying.second.addEdge(resolved, sign.getUnderlying().getOwner(), sign.getWeight());
+ if (ParametersMatcher.matchParameters(methodsChain, context).noUnmatchedAndHasMatched()) {
+ updated = true;
+ q.addFirst(new WeightAware<Pair<MethodIncompleteSignature, MethodsChain>>(
+ new Pair<MethodIncompleteSignature, MethodsChain>(sign.getUnderlying(), methodsChain), sign.getWeight()));
+ }
+ isBreak = true;
}
}
- //if ((result == null || maxUpdatedWeight * Constants.CHAIN_SEARCH_MAGIC_RATIO2 <= bigramsSumWeight)
- // && bigramsSumWeight * Constants.CHAIN_SEARCH_MAGIC_RATIO >= currentVertexMethodsChain.getChainWeight()) {
- // return currentVertexMethodsChain;
- //}
-
- if ((currentVertexMethodsChain.isStaticChain() ||
- !allExcludedNames.contains(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName())) &&
- bigramsSumWeight * Constants.CHAIN_SEARCH_MAGIC_RATIO <= currentVertexDistance &&
- (result == null || result.getChainWeight() < currentVertexDistance) &&
- (currentVertexMethodsChain.isStaticChain() ||
- searchService.isSingleton(currentVertexMethodsChain.getFirstQualifierClass(), contextMethodName) &&
- (searchService.isRelevantMethodForNotOverriden(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName(),
- currentVertexMethodsChain.getOneOfFirst().getName()) ||
- searchService.isRelevantMethodForField(currentVertexMethodsChain.getFirstQualifierClass().getQualifiedName(),
- currentVertexMethodsChain.getOneOfFirst().getName())))) {
- result = currentVertexMethodsChain;
+ if (!updated &&
+ (currentVertex.getUnderlying().getFirst().isStatic() ||
+ !targetQName.equals(currentVertex.getUnderlying().getFirst().getOwner()))) {
+ result.add(currentVertex.getUnderlying().getSecond());
}
+ if (result.size() > maxResultSize) {
+ return result.getResult();
+ }
+ }
+ return result.getResult();
+ }
+
+ private static class ResultHolder {
+
+ private final List<MethodsChain> myResult;
+ private final ChainCompletionContext myContext;
+
+ private ResultHolder(final ChainCompletionContext context) {
+ myContext = context;
+ myResult = new ArrayList<MethodsChain>();
}
- if (result != null && result.getChainWeight() * Constants.CHAIN_SEARCH_MAGIC_RATIO >= maxWeight) {
- return result;
+ public void add(final MethodsChain newChain) {
+ if (myResult.isEmpty()) {
+ myResult.add(newChain);
+ return;
+ }
+ boolean doAdd = true;
+ final Stack<Integer> indexesToRemove = new Stack<Integer>();
+ for (int i = 0; i < myResult.size(); i++) {
+ final MethodsChain chain = myResult.get(i);
+ //
+ final MethodsChain.CompareResult r = MethodsChain.compare(chain, newChain, myContext);
+ switch (r) {
+ case LEFT_CONTAINS_RIGHT:
+ indexesToRemove.add(i);
+ break;
+ case RIGHT_CONTAINS_LEFT:
+ case EQUAL:
+ doAdd = false;
+ break;
+ case NOT_EQUAL:
+ break;
+ }
+ }
+ while (!indexesToRemove.empty()) {
+ myResult.remove((int)indexesToRemove.pop());
+ }
+ if (doAdd) {
+ myResult.add(newChain);
+ }
+ }
+
+ public List<MethodsChain> getResult() {
+ return myResult;
+ }
+
+ public int size() {
+ return myResult.size();
+ }
+ }
+
+ private static int sumWeight(MaxSizeTreeSet<WeightAware<MethodIncompleteSignature>> weightAwareSignatures) {
+ int weight = 0;
+ for (WeightAware<MethodIncompleteSignature> weightAware : weightAwareSignatures) {
+ weight += weightAware.getWeight();
+ }
+ return weight;
+ }
+
+ private static boolean doChoose(final SortedSet<UsageIndexValue> bigrams, final int currentWeight, final int maxResultSize) {
+ if (bigrams.size() == 1) {
+ return true;
+ }
+ int sumWeight = 0;
+ for (final UsageIndexValue bigram : bigrams) {
+ sumWeight += bigram.getOccurrences();
+ }
+ if (Math.abs(sumWeight - currentWeight) < currentWeight / maxResultSize) {
+ return true;
+ }
+ final List<UsageIndexValue> essentialValues = new ArrayList<UsageIndexValue>();
+ Integer max = null;
+ for (UsageIndexValue bigram : bigrams) {
+ if (max == null) {
+ max = bigram.getOccurrences();
+ }
+ if (max / bigram.getOccurrences() > maxResultSize) {
+ break;
+ }
+ essentialValues.add(bigram);
+ if (essentialValues.size() > maxResultSize) {
+ return false;
+ }
}
- return null;
+ return true;
}
-}
+} \ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MaxSizeTreeSet.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MaxSizeTreeSet.java
new file mode 100644
index 000000000000..535cf090df2c
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MaxSizeTreeSet.java
@@ -0,0 +1,209 @@
+package com.intellij.codeInsight.completion.methodChains.search;
+
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+/**
+ * @author Dmitry Batkovich
+ */
+public class MaxSizeTreeSet<E> implements NavigableSet<E> {
+
+ @NotNull
+ private final NavigableSet<E> myUnderlying;
+ private final int myMaxSize;
+
+ public MaxSizeTreeSet(final int maxSize) {
+ myMaxSize = maxSize;
+ if (myMaxSize < 1) {
+ throw new IllegalArgumentException();
+ }
+ myUnderlying = new TreeSet<E>();
+ }
+
+ public E lower(final E e) {
+ return myUnderlying.lower(e);
+ }
+
+ public E floor(final E e) {
+ return myUnderlying.floor(e);
+ }
+
+ public E ceiling(final E e) {
+ return myUnderlying.ceiling(e);
+ }
+
+ public E higher(final E e) {
+ return myUnderlying.higher(e);
+ }
+
+ @Override
+ public E pollFirst() {
+ return myUnderlying.pollFirst();
+ }
+
+ @Override
+ public E pollLast() {
+ return myUnderlying.pollLast();
+ }
+
+ @NotNull
+ @Override
+ public Iterator<E> iterator() {
+ return myUnderlying.iterator();
+ }
+
+ @NotNull
+ @Override
+ public NavigableSet<E> descendingSet() {
+ return myUnderlying.descendingSet();
+ }
+
+ @NotNull
+ @Override
+ public Iterator<E> descendingIterator() {
+ return myUnderlying.descendingIterator();
+ }
+
+ @NotNull
+ public NavigableSet<E> subSet(final E fromElement, final boolean fromInclusive, final E toElement, final boolean toInclusive) {
+ return myUnderlying.subSet(fromElement, fromInclusive, toElement, toInclusive);
+ }
+
+ @NotNull
+ public NavigableSet<E> headSet(final E toElement, final boolean inclusive) {
+ return myUnderlying.headSet(toElement, inclusive);
+ }
+
+ @NotNull
+ public NavigableSet<E> tailSet(final E fromElement, final boolean inclusive) {
+ return myUnderlying.tailSet(fromElement, inclusive);
+ }
+
+ @NotNull
+ public SortedSet<E> subSet(final E fromElement, final E toElement) {
+ return myUnderlying.subSet(fromElement, toElement);
+ }
+
+ @NotNull
+ public SortedSet<E> headSet(final E toElement) {
+ return myUnderlying.headSet(toElement);
+ }
+
+ @NotNull
+ public SortedSet<E> tailSet(final E fromElement) {
+ return myUnderlying.tailSet(fromElement);
+ }
+
+ @Nullable
+ @Override
+ public Comparator<? super E> comparator() {
+ return myUnderlying.comparator();
+ }
+
+ @Override
+ public E first() {
+ return myUnderlying.first();
+ }
+
+ @Override
+ public E last() {
+ return myUnderlying.last();
+ }
+
+ @Override
+ public int size() {
+ return myUnderlying.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return myUnderlying.isEmpty();
+ }
+
+ @Override
+ public boolean contains(final Object o) {
+ return myUnderlying.contains(o);
+ }
+
+ @NotNull
+ @Override
+ public Object[] toArray() {
+ return myUnderlying.toArray();
+ }
+
+ @NotNull
+ @Override
+ public <T> T[] toArray(final T[] a) {
+ return myUnderlying.toArray(a);
+ }
+
+ public boolean add(final E e) {
+ if (myUnderlying.size() == myMaxSize) {
+ //noinspection ConstantConditions
+ final Comparator<? super E> comparator = comparator();
+ if ((comparator == null ? ((Comparable)e).compareTo(last()) : comparator.compare(e, last())) < 0) {
+ final boolean isAdded = myUnderlying.add(e);
+ if (isAdded) {
+ pollLast();
+ return true;
+ }
+ }
+ return false;
+ }
+ return myUnderlying.add(e);
+ }
+
+ @Override
+ public boolean remove(final Object o) {
+ return myUnderlying.remove(o);
+ }
+
+ @Override
+ public boolean containsAll(final Collection<?> c) {
+ return myUnderlying.containsAll(c);
+ }
+
+ public boolean addAll(final Collection<? extends E> c) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean retainAll(final Collection<?> c) {
+ return myUnderlying.retainAll(c);
+ }
+
+ @Override
+ public boolean removeAll(final Collection<?> c) {
+ return myUnderlying.removeAll(c);
+ }
+
+ @Override
+ public void clear() {
+ myUnderlying.clear();
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MaxSizeTreeSet)) return false;
+
+ final MaxSizeTreeSet that = (MaxSizeTreeSet)o;
+
+ if (!myUnderlying.equals(that.myUnderlying)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return myUnderlying.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return myUnderlying.toString();
+ }
+}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchService.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchService.java
index 0bc1991c715a..2c004593929e 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchService.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodChainsSearchService.java
@@ -4,17 +4,10 @@ import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature;
import com.intellij.compilerOutputIndex.impl.MethodsUsageIndex;
import com.intellij.compilerOutputIndex.impl.UsageIndexValue;
import com.intellij.compilerOutputIndex.impl.bigram.BigramMethodsUsageIndex;
-import com.intellij.compilerOutputIndex.impl.callingLocation.MethodNameAndQualifier;
-import com.intellij.codeInsight.completion.methodChains.search.service.OverridenMethodsService;
-import com.intellij.codeInsight.completion.methodChains.search.service.SingletonService;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Pair;
-import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiManager;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import java.util.HashMap;
-import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
@@ -26,20 +19,14 @@ public class MethodChainsSearchService {
private final MethodsUsageIndex myMethodsUsageIndex;
private final BigramMethodsUsageIndex myBigramMethodsUsageIndex;
- private final SingletonService mySingletonService;
- private final OverridenMethodsService myOverridenMethodsService;
private final Project myProject;
- private final Map<String, Boolean> mySingletonLocalCache;
+ private final boolean myUseBigrams;
- public MethodChainsSearchService(final Project project) {
- myOverridenMethodsService = new OverridenMethodsService(project);
+ public MethodChainsSearchService(final Project project, final boolean useBigrams) {
+ myUseBigrams = useBigrams;
myMethodsUsageIndex = MethodsUsageIndex.getInstance(project);
myBigramMethodsUsageIndex = BigramMethodsUsageIndex.getInstance(project);
- mySingletonService = new SingletonService(project);
myProject = project;
-
- mySingletonLocalCache = new HashMap<String, Boolean>();
- mySingletonLocalCache.put(null, false);
}
public Project getProject() {
@@ -49,9 +36,11 @@ public class MethodChainsSearchService {
@NotNull
@SuppressWarnings("unchecked")
public SortedSet<UsageIndexValue> getBigram(final MethodIncompleteSignature methodIncompleteSignature) {
- final TreeSet<UsageIndexValue> value = myBigramMethodsUsageIndex.getValues(methodIncompleteSignature);
- if (value != null) {
- return value;
+ final TreeSet<UsageIndexValue> values = myUseBigrams
+ ? myBigramMethodsUsageIndex.getValues(methodIncompleteSignature)
+ : myMethodsUsageIndex.getValues(methodIncompleteSignature.getOwner());
+ if (values != null) {
+ return values;
}
return EMPTY_SORTED_SET;
}
@@ -66,28 +55,7 @@ public class MethodChainsSearchService {
return EMPTY_SORTED_SET;
}
- public boolean isSingleton(@NotNull final PsiClass psiClass, final String contextMethodName) {
- return isSingleton(psiClass.getQualifiedName(), contextMethodName);
- }
-
- public boolean isSingleton(@Nullable final String typeQName, final String methodName) {
- Boolean isSingleton = mySingletonLocalCache.get(typeQName);
- if (isSingleton == null) {
- isSingleton = mySingletonService.isSingleton(typeQName, methodName);
- mySingletonLocalCache.put(typeQName, isSingleton);
- }
- return isSingleton;
- }
-
- public boolean isRelevantMethodForField(@NotNull final String className, @NotNull final String methodName) {
- final Pair<Integer, Integer> occurrences =
- myOverridenMethodsService.getMethodUsageInFieldContext(new MethodNameAndQualifier(methodName, className));
- return occurrences.getFirst() > occurrences.getSecond();
- }
-
- public boolean isRelevantMethodForNotOverriden(@NotNull final String className, @NotNull final String methodName) {
- final Pair<Integer, Integer> occurrences =
- myOverridenMethodsService.getMethodsUsageInOverridenContext(new MethodNameAndQualifier(methodName, className));
- return occurrences.getFirst() < occurrences.getSecond();
+ public PsiManager getPsiManager() {
+ return PsiManager.getInstance(getProject());
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChain.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChain.java
index c7f11c3af979..517a1d6181b8 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChain.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChain.java
@@ -1,11 +1,15 @@
package com.intellij.codeInsight.completion.methodChains.search;
+import com.intellij.codeInsight.completion.methodChains.completion.context.ChainCompletionContext;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.*;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.PsiMethod;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
import static com.intellij.util.containers.ContainerUtil.reverse;
@@ -15,27 +19,26 @@ import static com.intellij.util.containers.ContainerUtil.reverse;
public class MethodsChain {
private final List<PsiMethod[]> myRevertedPath;
private final int myWeight;
+ //
+ // chain qualifier class could be different with method.getContainingClass()
+ private final String myQualifierClassName;
- public MethodsChain(final PsiMethod[] methods, final int weight) {
- this(ContainerUtil.<PsiMethod[]>newArrayList(methods), weight);
+ public MethodsChain(final PsiMethod[] methods, final int weight, final String qualifierClassName) {
+ this(ContainerUtil.<PsiMethod[]>newArrayList(methods), weight, qualifierClassName);
}
- public MethodsChain(final List<PsiMethod[]> revertedPath, final int weight) {
+ public MethodsChain(final List<PsiMethod[]> revertedPath, final int weight, final String qualifierClassName) {
myRevertedPath = revertedPath;
myWeight = weight;
+ myQualifierClassName = qualifierClassName;
}
public int size() {
return myRevertedPath.size();
}
- public boolean isStaticChain() {
- return myRevertedPath.get(myRevertedPath.size() - 1)[0].hasModifierProperty(PsiModifier.STATIC);
- }
-
- @Nullable
- public PsiClass getFirstQualifierClass() {
- return myRevertedPath.isEmpty() ? null : myRevertedPath.get(myRevertedPath.size() - 1)[0].getContainingClass();
+ public String getQualifierClassName() {
+ return myQualifierClassName;
}
@Nullable
@@ -51,43 +54,11 @@ public class MethodsChain {
return myWeight;
}
- public MethodsChain addEdge(final PsiMethod[] psiMethods) {
+ public MethodsChain addEdge(final PsiMethod[] psiMethods, final String newQualifierClassName, final int newWeight) {
final List<PsiMethod[]> newRevertedPath = new ArrayList<PsiMethod[]>(myRevertedPath.size() + 1);
newRevertedPath.addAll(myRevertedPath);
newRevertedPath.add(psiMethods);
- return new MethodsChain(newRevertedPath, myWeight);
- }
-
- /**
- * checking only method names
- */
- public boolean weakContains(final MethodsChain otherChain) {
- if (otherChain.myRevertedPath.isEmpty()) {
- return true;
- }
- if (myRevertedPath.isEmpty()) {
- return false;
- }
- final Iterator<PsiMethod[]> otherChainIterator = otherChain.myRevertedPath.iterator();
- String otherChainCurrentName = otherChainIterator.next()[0].getName();
- boolean checkingStarted = false;
- for (final PsiMethod[] methods : myRevertedPath) {
- final String thisCurrentName = methods[0].getName();
- if (!checkingStarted && thisCurrentName.equals(otherChainCurrentName)) {
- checkingStarted = true;
- }
- if (checkingStarted) {
- if (otherChainIterator.hasNext()) {
- otherChainCurrentName = otherChainIterator.next()[0].getName();
- if (!otherChainCurrentName.equals(thisCurrentName)) {
- return false;
- }
- } else {
- return false;
- }
- }
- }
- return !otherChainIterator.hasNext();
+ return new MethodsChain(newRevertedPath, newWeight, newQualifierClassName);
}
@Override
@@ -95,34 +66,8 @@ public class MethodsChain {
return StringUtil.join(myRevertedPath, "<-");
}
- public static Set<Set<String>> edgeCombinations(final Set<Set<String>> oldCombinations,
- final MethodsChain methodsChain) {
- if (oldCombinations.isEmpty()) {
- final Set<Set<String>> result = new HashSet<Set<String>>(methodsChain.myRevertedPath.size());
- for (final PsiMethod[] e : methodsChain.myRevertedPath) {
- final Set<String> set = new HashSet<String>();
- set.add(e[0].getName());
- result.add(set);
- }
- return result;
- } else {
- final Set<Set<String>> newTail = new HashSet<Set<String>>(oldCombinations.size() * methodsChain.size());
- for (final PsiMethod[] e : methodsChain.myRevertedPath) {
- final String methodName = e[0].getName();
- for (final Set<String> tailSet : oldCombinations) {
- final Set<String> newSet = new HashSet<String>(tailSet);
- newSet.add(methodName);
- if (!oldCombinations.contains(newSet)) {
- newTail.add(newSet);
- }
- }
- }
- return newTail;
- }
- }
-
@SuppressWarnings("ConstantConditions")
- public static CompareResult compare(final MethodsChain left, final MethodsChain right) {
+ public static CompareResult compare(final MethodsChain left, final MethodsChain right, final ChainCompletionContext context) {
if (left.size() == 0) {
return CompareResult.RIGHT_CONTAINS_LEFT;
}
@@ -132,13 +77,13 @@ public class MethodsChain {
final Iterator<PsiMethod[]> leftIterator = left.myRevertedPath.iterator();
final Iterator<PsiMethod[]> rightIterator = right.myRevertedPath.iterator();
- final PsiManager psiManager = PsiManager.getInstance(left.getFirstQualifierClass().getProject());
while (leftIterator.hasNext() && rightIterator.hasNext()) {
final PsiMethod thisNext = leftIterator.next()[0];
final PsiMethod thatNext = rightIterator.next()[0];
- if (((thisNext.isConstructor() != thatNext.isConstructor()))
- || !thisNext.getName().equals(thatNext.getName())
- || !psiManager.areElementsEquivalent(thisNext.getContainingClass(), thatNext.getContainingClass())) {
+ if (thisNext == null || thatNext == null) {
+ throw new NullPointerException();
+ }
+ if (((thisNext.isConstructor() != thatNext.isConstructor())) || !thisNext.getName().equals(thatNext.getName())) {
return CompareResult.NOT_EQUAL;
}
}
@@ -148,7 +93,27 @@ public class MethodsChain {
if (!leftIterator.hasNext() && rightIterator.hasNext()) {
return CompareResult.RIGHT_CONTAINS_LEFT;
}
- return CompareResult.EQUAL;
+
+
+ return hasBaseMethod(left.getPath().get(0), right.getPath().get(0), PsiManager.getInstance(context.getProject()))
+ ? CompareResult.EQUAL
+ : CompareResult.NOT_EQUAL;
+ }
+
+ private static boolean hasBaseMethod(final PsiMethod[] left, final PsiMethod[] right, final PsiManager psiManager) {
+ for (PsiMethod rightMethod : right) {
+ final PsiMethod[] rightSupers = rightMethod.findDeepestSuperMethods();
+ if (rightSupers.length != 0) {
+ for (final PsiMethod leftMethod : left) {
+ final PsiMethod[] leftSupers = leftMethod.findDeepestSuperMethods();
+ if (leftSupers.length != 0) {
+ if (psiManager.areElementsEquivalent(leftSupers[0], rightSupers[0])) {
+ return true;
+ }
+ }
+ }
+ }
+ } return false;
}
public enum CompareResult {
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChainLookupRangingHelper.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChainLookupRangingHelper.java
index 58a76937b801..cd6d5516bd40 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChainLookupRangingHelper.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/MethodsChainLookupRangingHelper.java
@@ -53,10 +53,11 @@ public class MethodsChainLookupRangingHelper {
final int lastMethodWeight = chain.getChainWeight();
int unreachableParametersCount = 0;
int notMatchedStringVars = 0;
+ int matchedParametersInContext = 0;
Boolean isFirstMethodStatic = null;
Boolean hasCallingVariableInContext = null;
LookupElement chainLookupElement = null;
-
+ PsiClass newVariableClass = null;
final NullableNotNullManager nullableNotNullManager = NullableNotNullManager.getInstance(context.getProject());
for (final PsiMethod[] psiMethods : chain.getPath()) {
@@ -68,40 +69,58 @@ public class MethodsChainLookupRangingHelper {
if (isFirstMethodStatic == null) {
isFirstMethodStatic = psiMethods[0].hasModifierProperty(PsiModifier.STATIC);
}
- final MethodProcResult procResult =
- processMethod(method, context, lastMethodWeight, chainLookupElement == null, nullableNotNullManager);
+ final PsiClass qualifierClass;
+ final boolean isHead = chainLookupElement == null;
+ if (isHead) {
+ final String qualifierClassName = chain.getQualifierClassName();
+ qualifierClass = JavaPsiFacade.getInstance(context.getProject()).
+ findClass(qualifierClassName, context.getResolveScope());
+ }
+ else {
+ qualifierClass = null;
+ }
+
+ final MethodProcResult procResult = processMethod(method, qualifierClass, context, lastMethodWeight, isHead, nullableNotNullManager);
if (procResult == null) {
return null;
}
if (hasCallingVariableInContext == null) {
hasCallingVariableInContext = procResult.hasCallingVariableInContext();
}
+ if (isHead && procResult.isIntroduceNewVariable()) {
+ newVariableClass = qualifierClass;
+ }
+ matchedParametersInContext += procResult.getMatchedParametersInContext();
unreachableParametersCount += procResult.getUnreachableParametersCount();
notMatchedStringVars += procResult.getNotMatchedStringVars();
- chainLookupElement = chainLookupElement == null
- ? procResult.getLookupElement()
- : new JavaChainLookupElement(chainLookupElement, procResult.getLookupElement());
+ chainLookupElement =
+ isHead ? procResult.getLookupElement() : new JavaChainLookupElement(chainLookupElement, procResult.getLookupElement());
+ }
+
+ if (newVariableClass != null) {
+ chainLookupElement = ChainCompletionNewVariableLookupElement.create(newVariableClass, chainLookupElement);
}
- final ChainRelevance relevance = new ChainRelevance(chainSize,
- lastMethodWeight,
- unreachableParametersCount,
- notMatchedStringVars,
- hasCallingVariableInContext,
- isFirstMethodStatic);
+ final ChainRelevance relevance =
+ new ChainRelevance(chainSize, lastMethodWeight, unreachableParametersCount, notMatchedStringVars, hasCallingVariableInContext,
+ isFirstMethodStatic, matchedParametersInContext);
return new WeightableChainLookupElement(chainLookupElement, relevance);
}
+ @Nullable
private static MethodProcResult processMethod(@NotNull final PsiMethod method,
+ @Nullable final PsiClass qualifierClass,
final ChainCompletionContext context,
final int weight,
final boolean isHeadMethod,
final NullableNotNullManager nullableNotNullManager) {
int unreachableParametersCount = 0;
int notMatchedStringVars = 0;
+ int matchedParametersInContext = 0;
boolean hasCallingVariableInContext = false;
+ boolean introduceNewVariable = false;
final PsiParameterList parameterList = method.getParameterList();
final TIntObjectHashMap<SubLookupElement> parametersMap = new TIntObjectHashMap<SubLookupElement>(parameterList.getParametersCount());
final PsiParameter[] parameters = parameterList.getParameters();
@@ -123,18 +142,21 @@ public class MethodsChainLookupRangingHelper {
final PsiVariable contextVariable = ContainerUtil.getFirstItem(contextVariables, null);
if (contextVariable != null) {
if (contextVariables.size() == 1) parametersMap.put(i, new VariableSubLookupElement(contextVariable));
+ matchedParametersInContext++;
continue;
}
final Collection<ContextRelevantVariableGetter> relevantVariablesGetters = context.getRelevantVariablesGetters(typeQName);
final ContextRelevantVariableGetter contextVariableGetter = ContainerUtil.getFirstItem(relevantVariablesGetters, null);
if (contextVariableGetter != null) {
if (relevantVariablesGetters.size() == 1) parametersMap.put(i, contextVariableGetter.createSubLookupElement());
+ matchedParametersInContext++;
continue;
}
final Collection<PsiMethod> containingClassMethods = context.getContainingClassMethods(typeQName);
final PsiMethod contextRelevantGetter = ContainerUtil.getFirstItem(containingClassMethods, null);
if (contextRelevantGetter != null) {
if (containingClassMethods.size() == 1) parametersMap.put(i, new GetterLookupSubLookupElement(method.getName()));
+ matchedParametersInContext++;
continue;
}
final ContextRelevantStaticMethod contextRelevantStaticMethod =
@@ -144,6 +166,7 @@ public class MethodsChainLookupRangingHelper {
// In most cases it is not really relevant
//
//parametersMap.put(i, contextRelevantStaticMethod.createLookupElement());
+ matchedParametersInContext++;
continue;
}
if (!nullableNotNullManager.isNullable(parameter, true)) {
@@ -155,14 +178,15 @@ public class MethodsChainLookupRangingHelper {
final LookupElement lookupElement;
if (isHeadMethod) {
if (method.hasModifierProperty(PsiModifier.STATIC)) {
+ hasCallingVariableInContext = true;
lookupElement = createLookupElement(method, parametersMap);
}
else if (method.isConstructor()) {
return null;
}
else {
- final PsiClass containingClass = method.getContainingClass();
- final String classQName = containingClass.getQualifiedName();
+ @SuppressWarnings("ConstantConditions")
+ final String classQName = qualifierClass.getQualifiedName();
if (classQName == null) return null;
final Object e = ContainerUtil.getFirstItem(context.getContextRefElements(classQName), null);
if (e != null) {
@@ -182,16 +206,23 @@ public class MethodsChainLookupRangingHelper {
}
lookupElement = new JavaChainLookupElement(firstChainElement, createLookupElement(method, parametersMap));
}
- else lookupElement = context.getContainingClassQNames().contains(classQName)
- ? createLookupElement(method, parametersMap)
- : new JavaChainLookupElement(ChainCompletionNewVariableLookupElement.create(containingClass),
- createLookupElement(method, parametersMap));
+ else {
+ lookupElement = createLookupElement(method, parametersMap);
+ if (!context.getContainingClassQNames().contains(classQName)) {
+ introduceNewVariable = true;
+ }
+ }
}
}
else {
lookupElement = createLookupElement(method, parametersMap);
}
- return new MethodProcResult(lookupElement, unreachableParametersCount, notMatchedStringVars, hasCallingVariableInContext);
+ return new MethodProcResult(lookupElement,
+ unreachableParametersCount,
+ notMatchedStringVars,
+ hasCallingVariableInContext,
+ introduceNewVariable,
+ matchedParametersInContext);
}
private static class MethodProcResult {
@@ -199,15 +230,25 @@ public class MethodsChainLookupRangingHelper {
private final int myUnreachableParametersCount;
private final int myNotMatchedStringVars;
private final boolean myHasCallingVariableInContext;
+ private final boolean myIntroduceNewVariable;
+ private final int myMatchedParametersInContext;
private MethodProcResult(final LookupElement methodLookup,
final int unreachableParametersCount,
final int notMatchedStringVars,
- final boolean hasCallingVariableInContext) {
+ final boolean hasCallingVariableInContext,
+ final boolean introduceNewVariable,
+ final int matchedParametersInContext) {
myMethodLookup = methodLookup;
myUnreachableParametersCount = unreachableParametersCount;
myNotMatchedStringVars = notMatchedStringVars;
myHasCallingVariableInContext = hasCallingVariableInContext;
+ myIntroduceNewVariable = introduceNewVariable;
+ myMatchedParametersInContext = matchedParametersInContext;
+ }
+
+ private boolean isIntroduceNewVariable() {
+ return myIntroduceNewVariable;
}
private boolean hasCallingVariableInContext() {
@@ -225,6 +266,10 @@ public class MethodsChainLookupRangingHelper {
private int getNotMatchedStringVars() {
return myNotMatchedStringVars;
}
+
+ public int getMatchedParametersInContext() {
+ return myMatchedParametersInContext;
+ }
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ParametersMatcher.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ParametersMatcher.java
new file mode 100644
index 000000000000..2c2a563cef8c
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/ParametersMatcher.java
@@ -0,0 +1,82 @@
+package com.intellij.codeInsight.completion.methodChains.search;
+
+import com.intellij.codeInsight.completion.methodChains.completion.context.ChainCompletionContext;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiParameter;
+import com.intellij.psi.PsiPrimitiveType;
+import com.intellij.psi.PsiType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.NavigableSet;
+import java.util.TreeSet;
+
+/**
+ * @author Dmitry Batkovich
+ */
+public class ParametersMatcher {
+
+ public static MatchResult matchParameters(final MethodsChain chain, final ChainCompletionContext context) {
+ MatchResult overallResult = EMPTY;
+ for (final PsiMethod[] methods : chain.getPath()) {
+ final NavigableSet<MatchResult> matchResults = new TreeSet<MatchResult>();
+ for (final PsiMethod method : methods) {
+ matchResults.add(matchParameters(method, context));
+ }
+ final MatchResult best = matchResults.first();
+ overallResult = overallResult.add(best);
+ }
+ return overallResult;
+ }
+
+ public static MatchResult matchParameters(final PsiMethod method, final ChainCompletionContext context) {
+ int matched = 0;
+ int unMatched = 0;
+ for (final PsiParameter parameter : method.getParameterList().getParameters()) {
+ final PsiType type = parameter.getType();
+ if (context.contains(type.getCanonicalText()) || type instanceof PsiPrimitiveType) {
+ matched++;
+ }
+ else {
+ unMatched++;
+ }
+ }
+ return new MatchResult(matched, unMatched);
+ }
+
+ private static final MatchResult EMPTY = new MatchResult(0, 0);
+
+ public static class MatchResult implements Comparable<MatchResult> {
+ private final int myMatched;
+ private final int myUnMatched;
+
+ private MatchResult(final int matched, final int unMatched) {
+ myMatched = matched;
+ myUnMatched = unMatched;
+ }
+
+ public int getMatched() {
+ return myMatched;
+ }
+
+ public int getUnMatched() {
+ return myUnMatched;
+ }
+
+ public MatchResult add(final MatchResult other) {
+ return new MatchResult(getMatched() + other.getMatched(), getUnMatched() + other.getUnMatched());
+ }
+
+ public boolean noUnmatchedAndHasMatched() {
+ return myUnMatched == 0 && myMatched != 0;
+ }
+
+ @Override
+ public int compareTo(@NotNull final MatchResult other) {
+ final int sub = getUnMatched() - other.getUnMatched();
+ if (sub != 0) {
+ return sub;
+ }
+ return getMatched() - other.getMatched();
+ }
+ }
+}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/SearchInitializer.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/SearchInitializer.java
index 1f9831361299..b89edb677836 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/SearchInitializer.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/SearchInitializer.java
@@ -3,11 +3,8 @@ package com.intellij.codeInsight.completion.methodChains.search;
import com.intellij.codeInsight.completion.methodChains.Constants;
import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature;
import com.intellij.compilerOutputIndex.impl.UsageIndexValue;
-import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
-import com.intellij.psi.PsiModifier;
import com.intellij.util.containers.FactoryMap;
-import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -15,9 +12,8 @@ import java.util.*;
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
*/
public class SearchInitializer {
- private final List<WeightAware<MethodIncompleteSignature>> myVertexes;
+ private final List<WeightAware<MethodIncompleteSignature>> myVertices;
private final LinkedHashMap<MethodIncompleteSignature, MethodsChain> myChains;
- private final Map<MethodIncompleteSignature, Integer> myOccurrencesMap;
private final FactoryMap<MethodIncompleteSignature, PsiMethod[]> myResolver;
public SearchInitializer(final SortedSet<UsageIndexValue> indexValues,
@@ -26,9 +22,8 @@ public class SearchInitializer {
final Set<String> excludedParamsTypesQNames) {
myResolver = resolver;
final int size = indexValues.size();
- myVertexes = new ArrayList<WeightAware<MethodIncompleteSignature>>(size);
+ myVertices = new ArrayList<WeightAware<MethodIncompleteSignature>>(size);
myChains = new LinkedHashMap<MethodIncompleteSignature, MethodsChain>(size);
- myOccurrencesMap = new HashMap<MethodIncompleteSignature, Integer>(size);
add(indexValues, MethodChainsSearchUtil.unionToHashSet(excludedParamsTypesQNames, targetQName));
}
@@ -39,7 +34,8 @@ public class SearchInitializer {
final int occurrences = indexValue.getOccurrences();
if (bestOccurrences == -1) {
bestOccurrences = occurrences;
- } else if (bestOccurrences > occurrences * Constants.CHAIN_SEARCH_MAGIC_RATIO) {
+ }
+ else if (bestOccurrences > occurrences * Constants.CHAIN_SEARCH_MAGIC_RATIO) {
return;
}
}
@@ -51,65 +47,40 @@ public class SearchInitializer {
final PsiMethod[] psiMethods = myResolver.get(methodInvocation);
if (psiMethods.length != 0 && MethodChainsSearchUtil.checkParametersForTypesQNames(psiMethods, excludedParamsTypesQNames)) {
final int occurrences = indexValue.getOccurrences();
- final MethodsChain methodsChain = new MethodsChain(psiMethods, occurrences);
+ final MethodsChain methodsChain = new MethodsChain(psiMethods, occurrences, indexValue.getMethodIncompleteSignature().getOwner());
myChains.put(methodInvocation, methodsChain);
- myVertexes.add(new WeightAware<MethodIncompleteSignature>(methodInvocation, occurrences));
- myOccurrencesMap.put(methodInvocation, occurrences);
+ myVertices.add(new WeightAware<MethodIncompleteSignature>(methodInvocation, occurrences));
return true;
}
return false;
}
- public InitResult init(final Set<String> excludedEdgeNames,
- final Set<String> contextQNames,
- final MethodChainsSearchService searchService,
- final String contextMethodName) {
- final int size = myVertexes.size();
- int bestOccurrences = 0;
- MethodsChain bestTargetMethodChain = null;
+ public InitResult init(final Set<String> excludedEdgeNames) {
+ final int size = myVertices.size();
final List<WeightAware<MethodIncompleteSignature>> initedVertexes = new ArrayList<WeightAware<MethodIncompleteSignature>>(size);
- final LinkedHashMap<MethodIncompleteSignature, MethodsChain> initedChains = new LinkedHashMap<MethodIncompleteSignature, MethodsChain>(size);
+ final LinkedHashMap<MethodIncompleteSignature, MethodsChain> initedChains =
+ new LinkedHashMap<MethodIncompleteSignature, MethodsChain>(size);
final Iterator<Map.Entry<MethodIncompleteSignature, MethodsChain>> chainsIterator = myChains.entrySet().iterator();
- for (final WeightAware<MethodIncompleteSignature> vertex : myVertexes) {
+ for (final WeightAware<MethodIncompleteSignature> vertex : myVertices) {
final Map.Entry<MethodIncompleteSignature, MethodsChain> chainEntry = chainsIterator.next();
final MethodIncompleteSignature method = vertex.getUnderlying();
if (!excludedEdgeNames.contains(method.getName())) {
initedVertexes.add(vertex);
final MethodsChain methodsChain = chainEntry.getValue();
initedChains.put(chainEntry.getKey(), methodsChain);
- if (contextQNames.contains(method.getOwner())) {
- final Integer occurrences = myOccurrencesMap.get(method);
- if (occurrences > bestOccurrences) {
- final PsiMethod oneOfFirst = methodsChain.getOneOfFirst();
- if (oneOfFirst != null && oneOfFirst.hasModifierProperty(PsiModifier.STATIC)) {
- bestTargetMethodChain = methodsChain;
- bestOccurrences = occurrences;
- continue;
- }
- final PsiClass firstQualifierClass = methodsChain.getFirstQualifierClass();
- if (firstQualifierClass != null && (searchService.isSingleton(firstQualifierClass, contextMethodName)
- || contextQNames.contains(firstQualifierClass.getQualifiedName()))) {
- bestTargetMethodChain = methodsChain;
- bestOccurrences = occurrences;
- }
- }
- }
}
}
- return new InitResult(initedVertexes, initedChains, bestTargetMethodChain);
+ return new InitResult(initedVertexes, initedChains);
}
public static class InitResult {
private final List<WeightAware<MethodIncompleteSignature>> myVertexes;
private final LinkedHashMap<MethodIncompleteSignature, MethodsChain> myChains;
- private final MethodsChain myCurrentBestTargetChain;
private InitResult(final List<WeightAware<MethodIncompleteSignature>> vertexes,
- final LinkedHashMap<MethodIncompleteSignature, MethodsChain> chains,
- final @Nullable MethodsChain currentBestTargetChain) {
- this.myVertexes = vertexes;
- this.myChains = chains;
- this.myCurrentBestTargetChain = currentBestTargetChain;
+ final LinkedHashMap<MethodIncompleteSignature, MethodsChain> chains) {
+ myVertexes = vertexes;
+ myChains = chains;
}
public List<WeightAware<MethodIncompleteSignature>> getVertexes() {
@@ -119,10 +90,5 @@ public class SearchInitializer {
public LinkedHashMap<MethodIncompleteSignature, MethodsChain> getChains() {
return myChains;
}
-
- @Nullable
- public MethodsChain getCurrentBestTargetChain() {
- return myCurrentBestTargetChain;
- }
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/WeightAware.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/WeightAware.java
index 617053d57baf..7fd682457348 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/WeightAware.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/WeightAware.java
@@ -24,6 +24,10 @@ public class WeightAware<V> implements Comparable<WeightAware<V>> {
@Override
public int compareTo(@NotNull final WeightAware<V> that) {
- return -getWeight() + that.getWeight();
+ final int sub = -getWeight() + that.getWeight();
+ if (sub != 0) {
+ return sub;
+ }
+ return myUnderlying.hashCode() - that.myUnderlying.hashCode();
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/OverridenMethodsService.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/OverridenMethodsService.java
deleted file mode 100644
index f310a463b49c..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/OverridenMethodsService.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.intellij.codeInsight.completion.methodChains.search.service;
-
-import com.google.common.collect.Multiset;
-import com.intellij.compilerOutputIndex.impl.MethodIncompleteSignature;
-import com.intellij.compilerOutputIndex.impl.callingLocation.CallingLocation;
-import com.intellij.compilerOutputIndex.impl.callingLocation.MethodCallingLocationIndex;
-import com.intellij.compilerOutputIndex.impl.callingLocation.MethodNameAndQualifier;
-import com.intellij.compilerOutputIndex.impl.callingLocation.VariableType;
-import com.intellij.compilerOutputIndex.impl.quickInheritance.QuickInheritanceIndex;
-import com.intellij.compilerOutputIndex.impl.quickInheritance.QuickMethodsIndex;
-import com.intellij.compilerOutputIndex.impl.quickInheritance.QuickOverrideUtil;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Pair;
-
-/**
- * @author Dmitry Batkovich
- */
-public class OverridenMethodsService {
-
- private final QuickMethodsIndex myQuickMethodsIndex;
- private final QuickInheritanceIndex myQuickInheritanceIndex;
- private final MethodCallingLocationIndex myMethodCallingLocationIndex;
-
- public OverridenMethodsService(final Project project) {
- myQuickInheritanceIndex = QuickInheritanceIndex.getInstance(project);
- myQuickMethodsIndex = QuickMethodsIndex.getInstance(project);
- myMethodCallingLocationIndex = MethodCallingLocationIndex.getInstance(project);
- }
-
- public boolean isMethodOverriden(final String classQName, final String methodName) {
- return QuickOverrideUtil.isMethodOverriden(classQName, methodName, myQuickInheritanceIndex, myQuickMethodsIndex);
- }
-
- public Pair<Integer, Integer> getMethodsUsageInOverridenContext(final MethodNameAndQualifier method) {
- final Multiset<MethodIncompleteSignature> locationsAsParam = myMethodCallingLocationIndex.getLocationsAsParam(method);
- int overridenOccurrences = 0;
- int nonOverridenOccurrences = 0;
- for (final Multiset.Entry<MethodIncompleteSignature> e : locationsAsParam.entrySet()) {
- final MethodIncompleteSignature sign = e.getElement();
- final boolean methodOverriden = isMethodOverriden(sign.getOwner(), sign.getName());
- if (methodOverriden) {
- overridenOccurrences++;
- }
- else {
- nonOverridenOccurrences++;
- }
- }
-
- return Pair.create(overridenOccurrences, nonOverridenOccurrences);
- }
-
- public Pair<Integer, Integer> getMethodUsageInFieldContext(final MethodNameAndQualifier method) {
- int asField = 0;
- int notField = 0;
- for (final CallingLocation callingLocation : myMethodCallingLocationIndex.getAllLocations(method)) {
- if (callingLocation.getVariableType().equals(VariableType.FIELD)) {
- asField++;
- }
- else {
- notField++;
- }
- }
- return Pair.create(asField, notField);
- }
-}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/SingletonService.java b/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/SingletonService.java
deleted file mode 100644
index 4f27ad24cf1f..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/completion/methodChains/search/service/SingletonService.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.intellij.codeInsight.completion.methodChains.search.service;
-
-import com.intellij.codeInsight.completion.methodChains.Constants;
-import com.intellij.compilerOutputIndex.impl.singleton.MethodShortSignatureWithWeight;
-import com.intellij.compilerOutputIndex.impl.singleton.ParamsInMethodOccurrencesIndex;
-import com.intellij.compilerOutputIndex.impl.singleton.TwinVariablesIndex;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Pair;
-import com.intellij.psi.CommonClassNames;
-import com.intellij.psi.JavaPsiFacade;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.search.GlobalSearchScope;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Dmitry Batkovich
- */
-public class SingletonService {
- private final TwinVariablesIndex myTwinVariablesIndex;
- private final ParamsInMethodOccurrencesIndex myParamsInMethodOccurrencesIndex;
- private final GlobalSearchScope myAllScope;
- private final JavaPsiFacade myJavaPsiFacade;
-
- private final Map<String, Boolean> myLocalCache;
-
- public SingletonService(final Project project) {
- myTwinVariablesIndex = TwinVariablesIndex.getInstance(project);
- myParamsInMethodOccurrencesIndex = ParamsInMethodOccurrencesIndex.getInstance(project);
- myAllScope = GlobalSearchScope.allScope(project);
- myJavaPsiFacade = JavaPsiFacade.getInstance(project);
-
- myLocalCache = new HashMap<String, Boolean>();
- myLocalCache.put(null, false);
- }
-
- public boolean isSingleton(@Nullable final String typeQName, final @NotNull String contextMethodName) {
- final Boolean isSingletonCached = myLocalCache.get(typeQName);
- if (isSingletonCached == null) {
- assert typeQName != null;
- final PsiClass aClass = myJavaPsiFacade.findClass(typeQName, myAllScope);
- if (aClass == null) {
- myLocalCache.put(typeQName, false);
- return false;
- }
- for (final PsiClass psiClass : aClass.getInterfaces()) {
- final String qualifiedName = psiClass.getQualifiedName();
- if (CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName) || !isSingleton(qualifiedName, contextMethodName)) {
- myLocalCache.put(typeQName, false);
- return false;
- }
- }
- final boolean isSingleton = hasTwinsFeature(typeQName) && isSuitableTypeFor(typeQName, contextMethodName);
- myLocalCache.put(typeQName, isSingleton);
- return isSingleton;
- }
- return isSingletonCached;
- }
-
- public boolean hasTwinsFeature(final String typeQName) {
- final List<Integer> twinInfo = myTwinVariablesIndex.getTwinInfo(typeQName);
- if (twinInfo.isEmpty()) {
- return false;
- }
- int ones = 0;
- for (final int i : twinInfo) {
- if (i == 1) {
- ones++;
- }
- }
- return (twinInfo.size() - ones) * Constants.SINGLETON_MAGIC_RATIO < twinInfo.size();
- }
-
- private boolean isSuitableTypeFor(final String typeName, final String methodName) {
- final Pair<List<MethodShortSignatureWithWeight>, Integer> parameterOccurrences =
- myParamsInMethodOccurrencesIndex.getParameterOccurrences(typeName);
- if (parameterOccurrences.getSecond() == 0) {
- return true;
- }
- final List<MethodShortSignatureWithWeight> contextMethods = parameterOccurrences.getFirst();
- final MethodShortSignatureWithWeight last = contextMethods.get(contextMethods.size() - 1);
- return last.getMethodShortSignature().getName().equals(methodName) || last.getWeight() * Constants.SINGLETON_MAGIC_RATIO2 <= parameterOccurrences.getSecond();
- }
-
-}