build fix

This commit is contained in:
Dmitry Batkovich
2013-10-31 10:49:12 +04:00
parent f5ed1c11ea
commit 627a698370
16 changed files with 293 additions and 158 deletions

View File

@@ -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) {

View File

@@ -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;
}
}
}

View File

@@ -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) {

View File

@@ -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;
}
}

View File

@@ -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 {

View File

@@ -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() {

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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));
}
}

View File

@@ -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()]);
}

View File

@@ -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;
}
}

View File

@@ -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 {
}

View File

@@ -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) {

View File

@@ -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()));
}

View File

@@ -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"