mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
build fix
This commit is contained in:
@@ -58,11 +58,9 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
protected void addCompletions(final @NotNull CompletionParameters parameters,
|
||||
final ProcessingContext context,
|
||||
final @NotNull CompletionResultSet result) {
|
||||
|
||||
final ChainCompletionContext completionContext = extractContext(parameters);
|
||||
if (completionContext == null) return;
|
||||
|
||||
|
||||
final String targetClassQName = completionContext.getTargetQName();
|
||||
final Set<String> contextTypesKeysSet = completionContext.getContextTypes();
|
||||
final Set<String> contextRelevantTypes = new HashSet<String>(contextTypesKeysSet.size() + 1);
|
||||
@@ -73,9 +71,7 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
contextRelevantTypes.remove(targetClassQName);
|
||||
|
||||
//final boolean useBigrams = ApplicationManager.getApplication().isUnitTestMode() || parameters.getInvocationCount() == 3;
|
||||
final boolean useBigrams = true;
|
||||
final List<LookupElement> foundElements = searchForLookups(targetClassQName, contextRelevantTypes, completionContext, useBigrams);
|
||||
final List<LookupElement> foundElements = searchForLookups(targetClassQName, contextRelevantTypes, completionContext);
|
||||
result.addAllElements(foundElements);
|
||||
}
|
||||
});
|
||||
@@ -83,9 +79,8 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
|
||||
private static List<LookupElement> searchForLookups(final String targetClassQName,
|
||||
final Set<String> contextRelevantTypes,
|
||||
final ChainCompletionContext completionContext,
|
||||
final boolean useBigrams) {
|
||||
final MethodChainsSearchService searchService = new MethodChainsSearchService(completionContext.getProject(), useBigrams);
|
||||
final ChainCompletionContext completionContext) {
|
||||
final MethodChainsSearchService searchService = new MethodChainsSearchService(completionContext.getProject());
|
||||
final List<MethodsChain> searchResult =
|
||||
searchChains(targetClassQName, contextRelevantTypes, MAX_SEARCH_RESULT_SIZE, MAX_CHAIN_SIZE, completionContext, searchService);
|
||||
if (searchResult.size() < MAX_SEARCH_RESULT_SIZE) {
|
||||
|
||||
@@ -3,9 +3,13 @@ package com.intellij.codeInsight.completion.methodChains.search;
|
||||
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.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
@@ -16,7 +20,12 @@ import java.util.*;
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class ChainsSearcher {
|
||||
public final class ChainsSearcher {
|
||||
private ChainsSearcher() {
|
||||
}
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(ChainsSearcher.class);
|
||||
private static final double NEXT_METHOD_IN_CHAIN_RATIO = 1.5;
|
||||
|
||||
public static List<MethodsChain> search(final MethodChainsSearchService searchService,
|
||||
final String targetQName,
|
||||
@@ -86,7 +95,6 @@ public class ChainsSearcher {
|
||||
}
|
||||
|
||||
final ResultHolder result = new ResultHolder(context);
|
||||
|
||||
while (!q.isEmpty()) {
|
||||
ProgressManager.checkCanceled();
|
||||
final WeightAware<Pair<MethodIncompleteSignature, MethodsChain>> currentVertex = q.poll();
|
||||
@@ -100,13 +108,13 @@ public class ChainsSearcher {
|
||||
result.add(currentVertex.getUnderlying().getSecond());
|
||||
continue;
|
||||
}
|
||||
final SortedSet<UsageIndexValue> bigrams = searchService.getBigram(currentVertexUnderlying.getFirst());
|
||||
final SortedSet<UsageIndexValue> nextMethods = searchService.getMethods(currentVertexUnderlying.getFirst().getOwner());
|
||||
final MaxSizeTreeSet<WeightAware<MethodIncompleteSignature>> currentSignatures =
|
||||
new MaxSizeTreeSet<WeightAware<MethodIncompleteSignature>>(maxResultSize);
|
||||
for (final UsageIndexValue indexValue : bigrams) {
|
||||
for (final UsageIndexValue indexValue : nextMethods) {
|
||||
final MethodIncompleteSignature vertex = indexValue.getMethodIncompleteSignature();
|
||||
final int occurrences = indexValue.getOccurrences();
|
||||
if (!vertex.getOwner().equals(targetQName)) {
|
||||
if (vertex.isStatic() || !vertex.getOwner().equals(targetQName)) {
|
||||
final int vertexDistance = Math.min(currentVertexDistance, occurrences);
|
||||
final MethodsChain knownVertexMethodsChain = knownDistance.get(vertex);
|
||||
if ((knownVertexMethodsChain == null || knownVertexMethodsChain.getChainWeight() < vertexDistance)) {
|
||||
@@ -124,6 +132,9 @@ public class ChainsSearcher {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean updated = false;
|
||||
@@ -132,7 +143,7 @@ public class ChainsSearcher {
|
||||
for (final WeightAware<MethodIncompleteSignature> sign : currentSignatures) {
|
||||
final PsiMethod[] resolved = resolver.get(sign.getUnderlying());
|
||||
if (!isBreak) {
|
||||
if (sign.getWeight() * maxResultSize > currentVertex.getWeight()) {
|
||||
if (sign.getWeight() * NEXT_METHOD_IN_CHAIN_RATIO > currentVertex.getWeight()) {
|
||||
final boolean stopChain = sign.getUnderlying().isStatic() || toSet.contains(sign.getUnderlying().getOwner());
|
||||
if (stopChain) {
|
||||
updated = true;
|
||||
@@ -151,7 +162,8 @@ public class ChainsSearcher {
|
||||
}
|
||||
final MethodsChain methodsChain =
|
||||
currentVertexUnderlying.second.addEdge(resolved, sign.getUnderlying().getOwner(), sign.getWeight());
|
||||
if (ParametersMatcher.matchParameters(methodsChain, context).noUnmatchedAndHasMatched()) {
|
||||
final ParametersMatcher.MatchResult parametersMatchResult = ParametersMatcher.matchParameters(methodsChain, context);
|
||||
if (parametersMatchResult.noUnmatchedAndHasMatched() && parametersMatchResult.hasTarget()) {
|
||||
updated = true;
|
||||
q.addFirst(new WeightAware<Pair<MethodIncompleteSignature, MethodsChain>>(
|
||||
new Pair<MethodIncompleteSignature, MethodsChain>(sign.getUnderlying(), methodsChain), sign.getWeight()));
|
||||
@@ -171,8 +183,15 @@ public class ChainsSearcher {
|
||||
return result.getResult();
|
||||
}
|
||||
|
||||
private static class ResultHolder {
|
||||
private static MethodsChain createChainFromFirstElement(final MethodsChain chain, final PsiClass newQualifierClass) {
|
||||
final String qualifiedClassName = newQualifierClass.getQualifiedName();
|
||||
if (qualifiedClassName == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return new MethodsChain(chain.getFirst(), chain.getChainWeight(), qualifiedClassName);
|
||||
}
|
||||
|
||||
private static class ResultHolder {
|
||||
private final List<MethodsChain> myResult;
|
||||
private final ChainCompletionContext myContext;
|
||||
|
||||
@@ -212,48 +231,67 @@ public class ChainsSearcher {
|
||||
}
|
||||
}
|
||||
|
||||
public List<MethodsChain> getResult() {
|
||||
public List<MethodsChain> getRawResult() {
|
||||
return myResult;
|
||||
}
|
||||
|
||||
public List<MethodsChain> getResult() {
|
||||
return findSimilar(reduceChainsSize(myResult, PsiManager.getInstance(myContext.getProject())), myContext);
|
||||
}
|
||||
|
||||
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();
|
||||
private static List<MethodsChain> reduceChainsSize(final List<MethodsChain> chains, final PsiManager psiManager) {
|
||||
return ContainerUtil.map(chains, new Function<MethodsChain, MethodsChain>() {
|
||||
@Override
|
||||
public MethodsChain fun(final MethodsChain chain) {
|
||||
final Iterator<PsiMethod[]> chainIterator = chain.iterator();
|
||||
if (!chainIterator.hasNext()) {
|
||||
LOG.error("empty chain");
|
||||
return chain;
|
||||
}
|
||||
final PsiMethod[] first = chainIterator.next();
|
||||
while (chainIterator.hasNext()) {
|
||||
final PsiMethod psiMethod = chainIterator.next()[0];
|
||||
if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
continue;
|
||||
}
|
||||
final PsiClass current = psiMethod.getContainingClass();
|
||||
if (current == null) {
|
||||
LOG.error("containing class must be not null");
|
||||
return chain;
|
||||
}
|
||||
final PsiMethod[] currentMethods = current.findMethodsByName(first[0].getName(), true);
|
||||
if (currentMethods.length != 0) {
|
||||
for (final PsiMethod f : first) {
|
||||
final PsiMethod[] fSupers = f.findDeepestSuperMethods();
|
||||
final PsiMethod fSuper = fSupers.length == 0 ? first[0] : fSupers[0];
|
||||
for (final PsiMethod currentMethod : currentMethods) {
|
||||
if (psiManager.areElementsEquivalent(currentMethod, fSuper)) {
|
||||
return createChainFromFirstElement(chain, currentMethod.getContainingClass());
|
||||
}
|
||||
for (final PsiMethod method : currentMethod.findDeepestSuperMethods()) {
|
||||
if (psiManager.areElementsEquivalent(method, fSuper)) {
|
||||
return createChainFromFirstElement(chain, method.getContainingClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return chain;
|
||||
}
|
||||
});
|
||||
}
|
||||
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;
|
||||
private static List<MethodsChain> findSimilar(final List<MethodsChain> chains, final ChainCompletionContext context) {
|
||||
final ResultHolder resultHolder = new ResultHolder(context);
|
||||
for (final MethodsChain chain : chains) {
|
||||
resultHolder.add(chain);
|
||||
}
|
||||
return resultHolder.getRawResult();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.intellij.codeInsight.completion.methodChains.search;
|
||||
|
||||
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.openapi.project.Project;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -18,14 +16,10 @@ public class MethodChainsSearchService {
|
||||
private final static SortedSet EMPTY_SORTED_SET = new TreeSet();
|
||||
|
||||
private final MethodsUsageIndex myMethodsUsageIndex;
|
||||
private final BigramMethodsUsageIndex myBigramMethodsUsageIndex;
|
||||
private final Project myProject;
|
||||
private final boolean myUseBigrams;
|
||||
|
||||
public MethodChainsSearchService(final Project project, final boolean useBigrams) {
|
||||
myUseBigrams = useBigrams;
|
||||
public MethodChainsSearchService(final Project project) {
|
||||
myMethodsUsageIndex = MethodsUsageIndex.getInstance(project);
|
||||
myBigramMethodsUsageIndex = BigramMethodsUsageIndex.getInstance(project);
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@@ -33,18 +27,6 @@ public class MethodChainsSearchService {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@SuppressWarnings("unchecked")
|
||||
public SortedSet<UsageIndexValue> getBigram(final MethodIncompleteSignature methodIncompleteSignature) {
|
||||
final TreeSet<UsageIndexValue> values = myUseBigrams
|
||||
? myBigramMethodsUsageIndex.getValues(methodIncompleteSignature)
|
||||
: myMethodsUsageIndex.getValues(methodIncompleteSignature.getOwner());
|
||||
if (values != null) {
|
||||
return values;
|
||||
}
|
||||
return EMPTY_SORTED_SET;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@SuppressWarnings("unchecked")
|
||||
public SortedSet<UsageIndexValue> getMethods(final String targetQName) {
|
||||
|
||||
@@ -4,13 +4,12 @@ import com.intellij.codeInsight.completion.methodChains.completion.context.Chain
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.psi.PsiParameter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.util.containers.ContainerUtil.findAll;
|
||||
import static com.intellij.util.containers.ContainerUtil.reverse;
|
||||
|
||||
/**
|
||||
@@ -23,27 +22,41 @@ public class MethodsChain {
|
||||
// chain qualifier class could be different with method.getContainingClass()
|
||||
private final String myQualifierClassName;
|
||||
|
||||
private final Set<String> myExcludedQNames;
|
||||
|
||||
public MethodsChain(final PsiMethod[] methods, final int weight, final String qualifierClassName) {
|
||||
this(ContainerUtil.<PsiMethod[]>newArrayList(methods), weight, qualifierClassName);
|
||||
this(Collections.singletonList(methods), weight, qualifierClassName, chooseParametersQNames(methods));
|
||||
}
|
||||
|
||||
public MethodsChain(final List<PsiMethod[]> revertedPath, final int weight, final String qualifierClassName) {
|
||||
private MethodsChain(final List<PsiMethod[]> revertedPath,
|
||||
final int weight,
|
||||
final String qualifierClassName,
|
||||
final Set<String> excludedQNames) {
|
||||
myRevertedPath = revertedPath;
|
||||
myWeight = weight;
|
||||
myQualifierClassName = qualifierClassName;
|
||||
myExcludedQNames = excludedQNames;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return myRevertedPath.size();
|
||||
}
|
||||
|
||||
public Set<String> getExcludedQNames() {
|
||||
return myExcludedQNames;
|
||||
}
|
||||
|
||||
public String getQualifierClassName() {
|
||||
return myQualifierClassName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiMethod getOneOfFirst() {
|
||||
return (myRevertedPath.isEmpty() || myRevertedPath.get(0).length == 0) ? null : myRevertedPath.get(myRevertedPath.size() - 1)[0];
|
||||
public Iterator<PsiMethod[]> iterator() {
|
||||
return myRevertedPath.iterator();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiMethod[] getFirst() {
|
||||
return myRevertedPath.get(0);
|
||||
}
|
||||
|
||||
public List<PsiMethod[]> getPath() {
|
||||
@@ -54,13 +67,18 @@ public class MethodsChain {
|
||||
return myWeight;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
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, newWeight, newQualifierClassName);
|
||||
return new MethodsChain(newRevertedPath,
|
||||
newWeight,
|
||||
newQualifierClassName,
|
||||
joinSets(myExcludedQNames, chooseParametersQNames(psiMethods)));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringUtil.join(myRevertedPath, "<-");
|
||||
@@ -100,8 +118,15 @@ public class MethodsChain {
|
||||
: CompareResult.NOT_EQUAL;
|
||||
}
|
||||
|
||||
public enum CompareResult {
|
||||
LEFT_CONTAINS_RIGHT,
|
||||
RIGHT_CONTAINS_LEFT,
|
||||
EQUAL,
|
||||
NOT_EQUAL
|
||||
}
|
||||
|
||||
private static boolean hasBaseMethod(final PsiMethod[] left, final PsiMethod[] right, final PsiManager psiManager) {
|
||||
for (PsiMethod rightMethod : right) {
|
||||
for (final PsiMethod rightMethod : right) {
|
||||
final PsiMethod[] rightSupers = rightMethod.findDeepestSuperMethods();
|
||||
if (rightSupers.length != 0) {
|
||||
for (final PsiMethod leftMethod : left) {
|
||||
@@ -113,13 +138,26 @@ public class MethodsChain {
|
||||
}
|
||||
}
|
||||
}
|
||||
} return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public enum CompareResult {
|
||||
LEFT_CONTAINS_RIGHT,
|
||||
RIGHT_CONTAINS_LEFT,
|
||||
EQUAL,
|
||||
NOT_EQUAL
|
||||
private static Set<String> joinSets(final Set<String>... sets) {
|
||||
final Set<String> result = new HashSet<String>();
|
||||
for (final Set<String> set : sets) {
|
||||
for (final String s : set) {
|
||||
result.add(s);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Set<String> chooseParametersQNames(final PsiMethod[] methods) {
|
||||
final Set<String> qNames = new HashSet<String>();
|
||||
for (final PsiParameter methodParameter : methods[0].getParameterList().getParameters()) {
|
||||
qNames.add(methodParameter.getType().getCanonicalText());
|
||||
}
|
||||
return qNames;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -192,7 +192,6 @@ public class MethodsChainLookupRangingHelper {
|
||||
if (e != null) {
|
||||
final LookupElement firstChainElement;
|
||||
if (e instanceof PsiVariable) {
|
||||
hasCallingVariableInContext = true;
|
||||
firstChainElement = new VariableLookupItem((PsiVariable)e);
|
||||
}
|
||||
else if (e instanceof PsiMethod) {
|
||||
@@ -204,6 +203,7 @@ public class MethodsChainLookupRangingHelper {
|
||||
else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
hasCallingVariableInContext = true;
|
||||
lookupElement = new JavaChainLookupElement(firstChainElement, createLookupElement(method, parametersMap));
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -8,19 +8,22 @@ import com.intellij.psi.PsiType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class ParametersMatcher {
|
||||
public final class ParametersMatcher {
|
||||
|
||||
private 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));
|
||||
matchResults.add(matchParameters(method, context, chain.getExcludedQNames()));
|
||||
}
|
||||
final MatchResult best = matchResults.first();
|
||||
overallResult = overallResult.add(best);
|
||||
@@ -28,30 +31,37 @@ public class ParametersMatcher {
|
||||
return overallResult;
|
||||
}
|
||||
|
||||
public static MatchResult matchParameters(final PsiMethod method, final ChainCompletionContext context) {
|
||||
private static MatchResult matchParameters(final PsiMethod method, final ChainCompletionContext context, final Set<String> additionalExcludedNames) {
|
||||
int matched = 0;
|
||||
int unMatched = 0;
|
||||
boolean hasTarget = false;
|
||||
for (final PsiParameter parameter : method.getParameterList().getParameters()) {
|
||||
final PsiType type = parameter.getType();
|
||||
if (context.contains(type.getCanonicalText()) || type instanceof PsiPrimitiveType) {
|
||||
final String canonicalText = type.getCanonicalText();
|
||||
if (context.contains(canonicalText) || type instanceof PsiPrimitiveType) {
|
||||
matched++;
|
||||
}
|
||||
else {
|
||||
unMatched++;
|
||||
}
|
||||
if (context.getTargetQName().equals(canonicalText) || additionalExcludedNames.contains(canonicalText)) {
|
||||
hasTarget = true;
|
||||
}
|
||||
}
|
||||
return new MatchResult(matched, unMatched);
|
||||
return new MatchResult(matched, unMatched, hasTarget);
|
||||
}
|
||||
|
||||
private static final MatchResult EMPTY = new MatchResult(0, 0);
|
||||
private static final MatchResult EMPTY = new MatchResult(0, 0, false);
|
||||
|
||||
public static class MatchResult implements Comparable<MatchResult> {
|
||||
private final int myMatched;
|
||||
private final int myUnMatched;
|
||||
private final boolean myHasTarget;
|
||||
|
||||
private MatchResult(final int matched, final int unMatched) {
|
||||
private MatchResult(final int matched, final int unMatched, final boolean hasTarget) {
|
||||
myMatched = matched;
|
||||
myUnMatched = unMatched;
|
||||
myHasTarget = hasTarget;
|
||||
}
|
||||
|
||||
public int getMatched() {
|
||||
@@ -62,8 +72,12 @@ public class ParametersMatcher {
|
||||
return myUnMatched;
|
||||
}
|
||||
|
||||
public boolean hasTarget() {
|
||||
return myHasTarget;
|
||||
}
|
||||
|
||||
public MatchResult add(final MatchResult other) {
|
||||
return new MatchResult(getMatched() + other.getMatched(), getUnMatched() + other.getUnMatched());
|
||||
return new MatchResult(getMatched() + other.getMatched(), getUnMatched() + other.getUnMatched(), other.myHasTarget || myHasTarget);
|
||||
}
|
||||
|
||||
public boolean noUnmatchedAndHasMatched() {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.PsiMethod;
|
||||
@@ -12,6 +11,8 @@ import java.util.*;
|
||||
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
|
||||
*/
|
||||
public class SearchInitializer {
|
||||
private final static int CHAIN_SEARCH_MAGIC_RATIO = 12;
|
||||
|
||||
private final List<WeightAware<MethodIncompleteSignature>> myVertices;
|
||||
private final LinkedHashMap<MethodIncompleteSignature, MethodsChain> myChains;
|
||||
private final FactoryMap<MethodIncompleteSignature, PsiMethod[]> myResolver;
|
||||
@@ -35,7 +36,7 @@ public class SearchInitializer {
|
||||
if (bestOccurrences == -1) {
|
||||
bestOccurrences = occurrences;
|
||||
}
|
||||
else if (bestOccurrences > occurrences * Constants.CHAIN_SEARCH_MAGIC_RATIO) {
|
||||
else if (bestOccurrences > occurrences * CHAIN_SEARCH_MAGIC_RATIO) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ package com.intellij.compilerOutputIndex.api.fs;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.asm4.Opcodes;
|
||||
import org.jetbrains.asm4.Type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
|
||||
@@ -52,4 +54,32 @@ public final class AsmUtil implements Opcodes {
|
||||
private static String asJavaInnerClassQName(final String byteCodeClassQName) {
|
||||
return StringUtil.replaceChar(byteCodeClassQName, '$', '.');
|
||||
}
|
||||
|
||||
//char
|
||||
//double
|
||||
//float
|
||||
//int
|
||||
//long
|
||||
//short
|
||||
//boolean
|
||||
//byte
|
||||
//void
|
||||
//Object
|
||||
//String
|
||||
//Class
|
||||
private static final Set<String> ASM_PRIMITIVE_TYPES = ContainerUtil.newHashSet("C", "D", "F", "I", "J", "S", "Z", "B", "V",
|
||||
"Ljava/lang/Object;",
|
||||
"Ljava/lang/String;",
|
||||
"Ljava/lang/Class;");
|
||||
|
||||
public static boolean isPrimitive(final String asmType) {
|
||||
return ASM_PRIMITIVE_TYPES.contains(asmType);
|
||||
}
|
||||
|
||||
public static boolean isPrimitiveOrArray(final String asmType) {
|
||||
if (asmType.startsWith("[")) {
|
||||
return true;
|
||||
}
|
||||
return isPrimitive(asmType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.intellij.compilerOutputIndex.api.indexer;
|
||||
|
||||
import com.intellij.compilerOutputIndex.impl.MethodsUsageIndex;
|
||||
import com.intellij.compilerOutputIndex.impl.bigram.BigramMethodsUsageIndex;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.registry.RegistryValue;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -31,7 +30,7 @@ import java.util.Collections;
|
||||
@SuppressWarnings("unchecked")
|
||||
public enum CompilerOutputIndexFeature {
|
||||
METHOD_CHAINS_COMPLETION("completion.enable.relevant.method.chain.suggestions", ContainerUtil
|
||||
.<Class<? extends CompilerOutputBaseIndex>>newArrayList(BigramMethodsUsageIndex.class, MethodsUsageIndex.class));
|
||||
.<Class<? extends CompilerOutputBaseIndex>>newArrayList(MethodsUsageIndex.class));
|
||||
|
||||
@NotNull
|
||||
private final String myKey;
|
||||
|
||||
@@ -11,11 +11,7 @@ public final class CompilerOutputIndexUtil {
|
||||
private CompilerOutputIndexUtil() {}
|
||||
|
||||
public static <K, V> ID<K, V> generateIndexId(final String indexName, final Project project) {
|
||||
return ID.create(String.format("compilerOutputIndex.%s.%d", indexName, Math.abs(project.getBasePath().hashCode())));
|
||||
}
|
||||
|
||||
public static boolean isSetterOrConstructorMethodName(final String methodName) {
|
||||
return MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME.equals(methodName) || methodName.startsWith("set");
|
||||
|
||||
final String hash = Integer.toHexString(project.getBasePath().hashCode());
|
||||
return ID.create(String.format("compilerOutputIndex.%s.%s", indexName, hash));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.intellij.compilerOutputIndex.impl;
|
||||
|
||||
import com.intellij.compilerOutputIndex.api.fs.AsmUtil;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
@@ -12,6 +13,7 @@ import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
@@ -44,6 +46,13 @@ public class MethodIncompleteSignature {
|
||||
return new MethodIncompleteSignature(className, className, CONSTRUCTOR_METHOD_NAME, true);
|
||||
}
|
||||
|
||||
public MethodIncompleteSignature toExternalRepresentation() {
|
||||
return new MethodIncompleteSignature(AsmUtil.getQualifiedClassName(getOwner()),
|
||||
AsmUtil.getQualifiedClassName(getReturnType()),
|
||||
getName(),
|
||||
isStatic());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getOwner() {
|
||||
return myOwner;
|
||||
@@ -87,6 +96,14 @@ public class MethodIncompleteSignature {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filtered.size() > 1) {
|
||||
Collections.sort(filtered, new Comparator<PsiMethod>() {
|
||||
@Override
|
||||
public int compare(final PsiMethod o1, final PsiMethod o2) {
|
||||
return o1.getParameterList().getParametersCount() - o2.getParameterList().getParametersCount();
|
||||
}
|
||||
});
|
||||
}
|
||||
return filtered.toArray(new PsiMethod[filtered.size()]);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,32 +3,47 @@ package com.intellij.compilerOutputIndex.impl;
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.intellij.compilerOutputIndex.api.fs.AsmUtil;
|
||||
import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputBaseIndex;
|
||||
import com.intellij.compilerOutputIndex.api.indexer.CompilerOutputIndexer;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.ModuleRootModel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.indexing.DataIndexer;
|
||||
import com.intellij.util.indexing.ID;
|
||||
import com.intellij.util.indexing.StorageException;
|
||||
import com.intellij.util.indexing.ValueContainer;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.asm4.ClassReader;
|
||||
import org.jetbrains.asm4.ClassVisitor;
|
||||
import org.jetbrains.asm4.MethodVisitor;
|
||||
import org.jetbrains.asm4.Opcodes;
|
||||
import org.jetbrains.asm4.Type;
|
||||
import org.jetbrains.asm4.tree.ClassNode;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
|
||||
*/
|
||||
public class MethodsUsageIndex extends CompilerOutputBaseGramsIndex<String> {
|
||||
public class MethodsUsageIndex extends CompilerOutputBaseIndex<String, Multiset<MethodIncompleteSignature>> {
|
||||
|
||||
public static MethodsUsageIndex getInstance(final Project project) {
|
||||
return CompilerOutputIndexer.getInstance(project).getIndex(MethodsUsageIndex.class);
|
||||
}
|
||||
|
||||
public MethodsUsageIndex(final Project project) {
|
||||
super(new EnumeratorStringDescriptor(), project);
|
||||
super(new EnumeratorStringDescriptor(),
|
||||
new GuavaHashMultiSetExternalizer<MethodIncompleteSignature>(MethodIncompleteSignature.createKeyDescriptor()), project);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -38,25 +53,33 @@ public class MethodsUsageIndex extends CompilerOutputBaseGramsIndex<String> {
|
||||
@Override
|
||||
public Map<String, Multiset<MethodIncompleteSignature>> map(final ClassNode inputData) {
|
||||
final Map<String, Multiset<MethodIncompleteSignature>> map = new HashMap<String, Multiset<MethodIncompleteSignature>>();
|
||||
for (final ClassFileData.MethodData data : new ClassFileData(inputData).getMethodDatas()) {
|
||||
for (final ClassFileData.MethodInsnSignature ms : data.getMethodInsnSignatures()) {
|
||||
final String ownerClassName = AsmUtil.getQualifiedClassName(ms.getOwner());
|
||||
final String returnType = AsmUtil.getReturnType(ms.getDesc());
|
||||
if (MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME.equals(ms.getName())) {
|
||||
addToIndex(map, ownerClassName, MethodIncompleteSignature.constructor(ownerClassName));
|
||||
final MethodVisitor methodVisitor = new MethodVisitor(Opcodes.ASM4) {
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
|
||||
final Type returnType = Type.getReturnType(desc);
|
||||
if (MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME.equals(name) ||
|
||||
AsmUtil.isPrimitiveOrArray(returnType.getDescriptor())) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
final boolean isStatic = ms.getOpcode() == Opcodes.INVOKESTATIC;
|
||||
if (!ownerClassName.equals(returnType) || isStatic) {
|
||||
addToIndex(map, returnType, new MethodIncompleteSignature(ownerClassName, returnType, ms.getName(), isStatic));
|
||||
}
|
||||
final String returnClassName = returnType.getInternalName();
|
||||
final boolean isStatic = opcode == Opcodes.INVOKESTATIC;
|
||||
if (!owner.equals(returnClassName) || isStatic) {
|
||||
addToIndex(map, returnClassName, new MethodIncompleteSignature(owner, returnClassName, name, isStatic));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
inputData.accept(new ClassVisitor(Opcodes.ASM4) {
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int access,
|
||||
final String name,
|
||||
final String desc,
|
||||
final String signature,
|
||||
final String[] exceptions) {
|
||||
return methodVisitor;
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -67,17 +90,46 @@ public class MethodsUsageIndex extends CompilerOutputBaseGramsIndex<String> {
|
||||
|
||||
@Override
|
||||
protected int getVersion() {
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public TreeSet<UsageIndexValue> getValues(final String key) {
|
||||
try {
|
||||
final ValueContainer<Multiset<MethodIncompleteSignature>> valueContainer = myIndex.getData(key);
|
||||
final Multiset<MethodIncompleteSignature> rawValues = HashMultiset.create();
|
||||
valueContainer.forEach(new ValueContainer.ContainerAction<Multiset<MethodIncompleteSignature>>() {
|
||||
@Override
|
||||
public boolean perform(final int id, final Multiset<MethodIncompleteSignature> values) {
|
||||
for (final Multiset.Entry<MethodIncompleteSignature> entry : values.entrySet()) {
|
||||
rawValues.add(entry.getElement(), entry.getCount());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return rawValuesToValues(rawValues);
|
||||
}
|
||||
catch (final StorageException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void addToIndex(final Map<String, Multiset<MethodIncompleteSignature>> map,
|
||||
final String key,
|
||||
final String internalClassName,
|
||||
final MethodIncompleteSignature mi) {
|
||||
Multiset<MethodIncompleteSignature> occurrences = map.get(key);
|
||||
final String className = AsmUtil.getQualifiedClassName(internalClassName);
|
||||
Multiset<MethodIncompleteSignature> occurrences = map.get(className);
|
||||
if (occurrences == null) {
|
||||
occurrences = HashMultiset.create();
|
||||
map.put(key, occurrences);
|
||||
map.put(className, occurrences);
|
||||
}
|
||||
occurrences.add(mi);
|
||||
}
|
||||
}
|
||||
|
||||
private static TreeSet<UsageIndexValue> rawValuesToValues(final Multiset<MethodIncompleteSignature> rawValues) {
|
||||
final TreeSet<UsageIndexValue> values = new TreeSet<UsageIndexValue>();
|
||||
for (final Multiset.Entry<MethodIncompleteSignature> entry : rawValues.entrySet()) {
|
||||
values.add(new UsageIndexValue(entry.getElement().toExternalRepresentation(), entry.getCount()));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
interface PsiManager {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
public class TestIndex {
|
||||
|
||||
public void statMethod(PsiMethodCallExpression e) {
|
||||
|
||||
@@ -66,6 +66,10 @@ public class MethodChainsCompletionTest extends AbstractCompilerAwareTest {
|
||||
assertAdvisorLookupElementEquals("p.getBaseDir", 0, 8, 1, 0, assertOneElement(doCompletion()));
|
||||
}
|
||||
|
||||
public void testOneChainContainsOther2() {
|
||||
assertLookupElementStringEquals(assertOneElement(doCompletion()), "getManager");
|
||||
}
|
||||
|
||||
public void testTwoVariablesWithOneTypeOrSuperType() {
|
||||
assertAdvisorLookupElementEquals("c.getProject", 0, 4, 1, 0, assertOneElement(doCompletion()));
|
||||
}
|
||||
|
||||
@@ -1461,7 +1461,6 @@
|
||||
<gotoDeclarationHandler implementation="com.intellij.codeInsight.navigation.actions.GotoLambdaParameterHandler"/>
|
||||
|
||||
<java.compilerOutputIndex implementation="com.intellij.compilerOutputIndex.impl.MethodsUsageIndex"/>
|
||||
<java.compilerOutputIndex implementation="com.intellij.compilerOutputIndex.impl.bigram.BigramMethodsUsageIndex"/>
|
||||
<completion.contributor language="JAVA" id="methodsChainsCompletionContributor" order="first"
|
||||
implementationClass="com.intellij.codeInsight.completion.methodChains.completion.MethodsChainsCompletionContributor"/>
|
||||
<weigher order="first" key="completion" id="methodsChains"
|
||||
|
||||
Reference in New Issue
Block a user