mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Methods chains completion for arrays
This commit is contained in:
+5
-5
@@ -33,16 +33,16 @@ public enum ClassFilesIndexFeature {
|
||||
@NotNull
|
||||
private final String myKey;
|
||||
@NotNull
|
||||
private final Collection<? extends MethodsUsageIndexConfigure> myRequiredIndicesConfigures;
|
||||
private final Collection<? extends ClassFilesIndexConfigure> myRequiredIndicesConfigures;
|
||||
|
||||
ClassFilesIndexFeature(@NotNull final String key,
|
||||
@NotNull final Collection<? extends MethodsUsageIndexConfigure> requiredIndicesConfigures) {
|
||||
@NotNull final Collection<? extends ClassFilesIndexConfigure> requiredIndicesConfigures) {
|
||||
myKey = key;
|
||||
myRequiredIndicesConfigures = requiredIndicesConfigures;
|
||||
}
|
||||
|
||||
ClassFilesIndexFeature(@NotNull final String key, @NotNull final MethodsUsageIndexConfigure requiredConfigure) {
|
||||
this(key, Collections.<MethodsUsageIndexConfigure>singleton(requiredConfigure));
|
||||
ClassFilesIndexFeature(@NotNull final String key, @NotNull final ClassFilesIndexConfigure requiredConfigure) {
|
||||
this(key, Collections.<ClassFilesIndexConfigure>singleton(requiredConfigure));
|
||||
}
|
||||
|
||||
public RegistryValue getRegistryValue() {
|
||||
@@ -70,7 +70,7 @@ public enum ClassFilesIndexFeature {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<? extends MethodsUsageIndexConfigure> getRequiredIndicesConfigures() {
|
||||
public Collection<? extends ClassFilesIndexConfigure> getRequiredIndicesConfigures() {
|
||||
return myRequiredIndicesConfigures;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -86,7 +86,7 @@ public class ClassFilesIndexFeaturesHolder extends AbstractProjectComponent {
|
||||
}
|
||||
for (final ClassFilesIndexFeature feature : ClassFilesIndexFeature.values()) {
|
||||
if (feature.isEnabled() && !myEnabledFeatures.containsKey(feature)) {
|
||||
for (final MethodsUsageIndexConfigure configure : feature.getRequiredIndicesConfigures()) {
|
||||
for (final ClassFilesIndexConfigure configure : feature.getRequiredIndicesConfigures()) {
|
||||
if (!myEnabledIndexReaders.containsKey(configure)) {
|
||||
notAvailableConfiguresVisitor.process(configure);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public class ClassFilesIndexFeaturesHolder extends AbstractProjectComponent {
|
||||
}
|
||||
|
||||
private synchronized void disposeFeature(final ClassFilesIndexFeature featureToRemove) {
|
||||
for (final MethodsUsageIndexConfigure requiredConfigure : featureToRemove.getRequiredIndicesConfigures()) {
|
||||
for (final ClassFilesIndexConfigure requiredConfigure : featureToRemove.getRequiredIndicesConfigures()) {
|
||||
boolean needClose = true;
|
||||
for (final ClassFilesIndexFeature enabledFeature : myEnabledFeatures.keySet()) {
|
||||
if (!enabledFeature.equals(featureToRemove) && enabledFeature.getRequiredIndicesConfigures().contains(requiredConfigure)) {
|
||||
@@ -116,10 +116,10 @@ public class ClassFilesIndexFeaturesHolder extends AbstractProjectComponent {
|
||||
if (myEnabledFeatures.containsKey(feature)) {
|
||||
throw new IllegalStateException(String.format("feature %s already contains", feature.getKey()));
|
||||
}
|
||||
final Map<MethodsUsageIndexConfigure, ClassFilesIndexReaderBase> newIndices =
|
||||
new HashMap<MethodsUsageIndexConfigure, ClassFilesIndexReaderBase>();
|
||||
final Map<ClassFilesIndexConfigure, ClassFilesIndexReaderBase> newIndices =
|
||||
new HashMap<ClassFilesIndexConfigure, ClassFilesIndexReaderBase>();
|
||||
FeatureState newFeatureState = FeatureState.AVAILABLE;
|
||||
for (final MethodsUsageIndexConfigure requiredConfigure : feature.getRequiredIndicesConfigures()) {
|
||||
for (final ClassFilesIndexConfigure requiredConfigure : feature.getRequiredIndicesConfigures()) {
|
||||
boolean isIndexAlreadyLoaded = false;
|
||||
for (final ClassFilesIndexFeature enabledFeature : myEnabledFeatures.keySet()) {
|
||||
if (enabledFeature.getRequiredIndicesConfigures().contains(requiredConfigure)) {
|
||||
|
||||
-4
@@ -55,9 +55,6 @@ public abstract class ClassFilesIndexReaderBase<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All inheritors MUST have constructor with only one parameter - Project
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
protected ClassFilesIndexReaderBase(final KeyDescriptor<K> keyDescriptor,
|
||||
final DataExternalizer<V> valueExternalizer,
|
||||
@@ -149,5 +146,4 @@ public abstract class ClassFilesIndexReaderBase<K, V> {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -52,7 +52,7 @@ public class CachedRelevantStaticMethodSearcher {
|
||||
final ChainCompletionContext completionContext) {
|
||||
if (resultQualifiedClassName == null ||
|
||||
ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(resultQualifiedClassName) ||
|
||||
completionContext.getTargetQName().equals(resultQualifiedClassName)) {
|
||||
completionContext.getTarget().equals(resultQualifiedClassName)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final TreeSet<UsageIndexValue> indexValues = myIndexReader.getMethods(resultQualifiedClassName);
|
||||
@@ -68,7 +68,7 @@ public class CachedRelevantStaticMethodSearcher {
|
||||
else {
|
||||
final PsiMethod[] methods = completionContext.resolveNotDeprecated(methodInvocation);
|
||||
method = MethodChainsSearchUtil
|
||||
.getMethodWithMinNotPrimitiveParameters(methods, Collections.singleton(completionContext.getTargetQName()));
|
||||
.getMethodWithMinNotPrimitiveParameters(methods, Collections.singleton(completionContext.getTarget().getClassQName()));
|
||||
myCachedResolveResults.put(methodInvocation, method);
|
||||
if (method == null) {
|
||||
return Collections.emptyList();
|
||||
|
||||
+46
-30
@@ -16,19 +16,19 @@
|
||||
package com.intellij.compiler.classFilesIndex.chainsSearch;
|
||||
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.TargetType;
|
||||
import com.intellij.compiler.classFilesIndex.impl.MethodsUsageIndexReader;
|
||||
import com.intellij.compiler.classFilesIndex.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.psi.*;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.classFilesIndex.indexer.impl.MethodIncompleteSignature;
|
||||
import org.jetbrains.jps.incremental.storage.BuildDataManager;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -42,21 +42,36 @@ public final class 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 MethodsUsageIndexReader indexReader,
|
||||
final String targetQName,
|
||||
public static List<MethodsChain> search(final int pathMaximalLength,
|
||||
final TargetType targetType,
|
||||
final Set<String> contextQNames,
|
||||
final int maxResultSize,
|
||||
final int pathMaximalLength,
|
||||
final ChainCompletionContext context) {
|
||||
final SearchInitializer initializer = createInitializer(targetQName, indexReader, context.getExcludedQNames(), context);
|
||||
return search(indexReader, initializer, contextQNames, pathMaximalLength, maxResultSize, targetQName, context);
|
||||
final ChainCompletionContext context,
|
||||
final MethodsUsageIndexReader methodsUsageIndexReader) {
|
||||
final SearchInitializer initializer =
|
||||
createInitializer(targetType,
|
||||
context.getExcludedQNames(),
|
||||
methodsUsageIndexReader,
|
||||
context);
|
||||
if (initializer == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return search(methodsUsageIndexReader,
|
||||
initializer,
|
||||
contextQNames,
|
||||
pathMaximalLength,
|
||||
maxResultSize,
|
||||
targetType.getClassQName(),
|
||||
context);
|
||||
}
|
||||
|
||||
private static SearchInitializer createInitializer(final String targetQName,
|
||||
final MethodsUsageIndexReader indexReader,
|
||||
@Nullable
|
||||
private static SearchInitializer createInitializer(final TargetType target,
|
||||
final Set<String> excludedParamsTypesQNames,
|
||||
final MethodsUsageIndexReader methodsUsageIndexReader,
|
||||
final ChainCompletionContext context) {
|
||||
return new SearchInitializer(indexReader.getMethods(targetQName), targetQName, excludedParamsTypesQNames, context);
|
||||
final TreeSet<UsageIndexValue> methods = methodsUsageIndexReader.getMethods(target.getClassQName());
|
||||
return new SearchInitializer(methods, target.getClassQName(), excludedParamsTypesQNames, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -80,22 +95,20 @@ public final class ChainsSearcher {
|
||||
@Override
|
||||
public WeightAware<Pair<MethodIncompleteSignature, MethodsChain>> fun(
|
||||
final WeightAware<MethodIncompleteSignature> methodIncompleteSignatureWeightAware) {
|
||||
final MethodIncompleteSignature
|
||||
underlying =
|
||||
methodIncompleteSignatureWeightAware
|
||||
.getUnderlying();
|
||||
final MethodIncompleteSignature underlying = methodIncompleteSignatureWeightAware.getUnderlying();
|
||||
return new WeightAware<Pair<MethodIncompleteSignature, MethodsChain>>(
|
||||
new Pair<MethodIncompleteSignature, MethodsChain>(
|
||||
underlying, new MethodsChain(
|
||||
context.resolveNotDeprecated(
|
||||
underlying),
|
||||
methodIncompleteSignatureWeightAware
|
||||
.getWeight(),
|
||||
underlying.getOwner())),
|
||||
methodIncompleteSignatureWeightAware
|
||||
.getWeight());
|
||||
underlying,
|
||||
new MethodsChain(context.resolveNotDeprecated(underlying),
|
||||
methodIncompleteSignatureWeightAware.getWeight(),
|
||||
underlying.getOwner()
|
||||
)
|
||||
),
|
||||
methodIncompleteSignatureWeightAware.getWeight()
|
||||
);
|
||||
}
|
||||
}));
|
||||
}
|
||||
));
|
||||
|
||||
int maxWeight = 0;
|
||||
for (final MethodsChain methodsChain : knownDistance.values()) {
|
||||
@@ -118,7 +131,8 @@ public final class ChainsSearcher {
|
||||
result.add(currentVertex.getUnderlying().getSecond());
|
||||
continue;
|
||||
}
|
||||
final SortedSet<UsageIndexValue> nextMethods = indexReader.getMethods(currentVertexUnderlying.getFirst().getOwner());
|
||||
final String currentReturnType = currentVertexUnderlying.getFirst().getOwner();
|
||||
final SortedSet<UsageIndexValue> nextMethods = indexReader.getMethods(currentReturnType);
|
||||
final MaxSizeTreeSet<WeightAware<MethodIncompleteSignature>> currentSignatures =
|
||||
new MaxSizeTreeSet<WeightAware<MethodIncompleteSignature>>(maxResultSize);
|
||||
for (final UsageIndexValue indexValue : nextMethods) {
|
||||
@@ -133,8 +147,10 @@ public final class ChainsSearcher {
|
||||
final MethodIncompleteSignature methodInvocation = indexValue.getMethodIncompleteSignature();
|
||||
final PsiMethod[] psiMethods = context.resolveNotDeprecated(methodInvocation);
|
||||
if (psiMethods.length != 0 && MethodChainsSearchUtil.checkParametersForTypesQNames(psiMethods, allExcludedNames)) {
|
||||
final MethodsChain newBestMethodsChain = currentVertexMethodsChain.addEdge(psiMethods, indexValue.getMethodIncompleteSignature().getOwner(), vertexDistance);
|
||||
currentSignatures.add(new WeightAware<MethodIncompleteSignature>(indexValue.getMethodIncompleteSignature(), vertexDistance));
|
||||
final MethodsChain newBestMethodsChain =
|
||||
currentVertexMethodsChain.addEdge(psiMethods, indexValue.getMethodIncompleteSignature().getOwner(), vertexDistance);
|
||||
currentSignatures
|
||||
.add(new WeightAware<MethodIncompleteSignature>(indexValue.getMethodIncompleteSignature(), vertexDistance));
|
||||
knownDistance.put(vertex, newBestMethodsChain);
|
||||
}
|
||||
}
|
||||
@@ -302,4 +318,4 @@ public final class ChainsSearcher {
|
||||
return resultHolder.getRawResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
-48
@@ -60,8 +60,7 @@ public class MethodsChainLookupRangingHelper {
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Nullable
|
||||
private static WeightableChainLookupElement chainToWeightableLookupElement(final MethodsChain chain,
|
||||
final ChainCompletionContext context) {
|
||||
private static LookupElement chainToWeightableLookupElement(final MethodsChain chain, final ChainCompletionContext context) {
|
||||
final int chainSize = chain.size();
|
||||
assert chainSize != 0;
|
||||
final int lastMethodWeight = chain.getChainWeight();
|
||||
@@ -76,7 +75,7 @@ public class MethodsChainLookupRangingHelper {
|
||||
|
||||
for (final PsiMethod[] psiMethods : chain.getPath()) {
|
||||
final PsiMethod method =
|
||||
MethodChainsSearchUtil.getMethodWithMinNotPrimitiveParameters(psiMethods, Collections.singleton(context.getTargetQName()));
|
||||
MethodChainsSearchUtil.getMethodWithMinNotPrimitiveParameters(psiMethods, Collections.singleton(context.getTarget().getClassQName()));
|
||||
if (method == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -141,52 +140,49 @@ public class MethodsChainLookupRangingHelper {
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
final PsiParameter parameter = parameters[i];
|
||||
final String typeQName = parameter.getType().getCanonicalText();
|
||||
if (typeQName != null) {
|
||||
if (JAVA_LANG_STRING.equals(typeQName)) {
|
||||
final PsiVariable relevantStringVar = context.findRelevantStringInContext(parameter.getName());
|
||||
if (relevantStringVar == null) {
|
||||
notMatchedStringVars++;
|
||||
}
|
||||
else {
|
||||
parametersMap.put(i, new VariableSubLookupElement(relevantStringVar));
|
||||
}
|
||||
if (JAVA_LANG_STRING.equals(typeQName)) {
|
||||
final PsiVariable relevantStringVar = context.findRelevantStringInContext(parameter.getName());
|
||||
if (relevantStringVar == null) {
|
||||
notMatchedStringVars++;
|
||||
}
|
||||
else if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(typeQName)) {
|
||||
final Collection<PsiVariable> contextVariables = context.getVariables(typeQName);
|
||||
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;
|
||||
}
|
||||
//todo
|
||||
final ContextRelevantStaticMethod contextRelevantStaticMethod =
|
||||
ContainerUtil.getFirstItem(context.getRelevantStaticMethods(typeQName, weight), null);
|
||||
if (contextRelevantStaticMethod != null) {
|
||||
//
|
||||
// In most cases it is not really relevant
|
||||
//
|
||||
//parametersMap.put(i, contextRelevantStaticMethod.createLookupElement());
|
||||
matchedParametersInContext++;
|
||||
continue;
|
||||
}
|
||||
if (!nullableNotNullManager.isNullable(parameter, true)) {
|
||||
unreachableParametersCount++;
|
||||
}
|
||||
else {
|
||||
parametersMap.put(i, new VariableSubLookupElement(relevantStringVar));
|
||||
}
|
||||
}
|
||||
else if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(typeQName)) {
|
||||
final Collection<PsiVariable> contextVariables = context.getVariables(typeQName);
|
||||
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 =
|
||||
ContainerUtil.getFirstItem(context.getRelevantStaticMethods(typeQName, weight), null);
|
||||
if (contextRelevantStaticMethod != null) {
|
||||
//
|
||||
// In most cases it is not really relevant
|
||||
//
|
||||
//parametersMap.put(i, contextRelevantStaticMethod.createLookupElement());
|
||||
matchedParametersInContext++;
|
||||
continue;
|
||||
}
|
||||
if (!nullableNotNullManager.isNullable(parameter, true)) {
|
||||
unreachableParametersCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ public final class ParametersMatcher {
|
||||
else {
|
||||
unMatched++;
|
||||
}
|
||||
if (context.getTargetQName().equals(canonicalText) || additionalExcludedNames.contains(canonicalText)) {
|
||||
if (context.getTarget().getClassQName().equals(canonicalText) || additionalExcludedNames.contains(canonicalText)) {
|
||||
hasTarget = true;
|
||||
}
|
||||
}
|
||||
|
||||
+46
-55
@@ -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.
|
||||
*/
|
||||
package com.intellij.compiler.classFilesIndex.chainsSearch.completion;
|
||||
|
||||
import com.intellij.codeInsight.completion.*;
|
||||
@@ -22,12 +7,14 @@ import com.intellij.compiler.classFilesIndex.api.index.ClassFilesIndexFeaturesHo
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.*;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ContextUtil;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.TargetType;
|
||||
import com.intellij.compiler.classFilesIndex.impl.MethodsUsageIndexReader;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.impl.source.PsiImmediateClassType;
|
||||
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.*;
|
||||
@@ -53,8 +40,8 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
|
||||
@Override
|
||||
public void fillCompletionVariants(final CompletionParameters parameters, final CompletionResultSet result) {
|
||||
if (parameters.getInvocationCount() >= INVOCATIONS_THRESHOLD
|
||||
&& ClassFilesIndexFeaturesHolder.getInstance(parameters.getPosition().getProject())
|
||||
if (parameters.getInvocationCount() >= INVOCATIONS_THRESHOLD &&
|
||||
ClassFilesIndexFeaturesHolder.getInstance(parameters.getPosition().getProject())
|
||||
.enableFeatureIfNeed(ClassFilesIndexFeature.METHOD_CHAINS_COMPLETION)) {
|
||||
super.fillCompletionVariants(parameters, result);
|
||||
}
|
||||
@@ -72,7 +59,6 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
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);
|
||||
for (final String type : contextTypesKeysSet) {
|
||||
@@ -80,9 +66,9 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
contextRelevantTypes.add(type);
|
||||
}
|
||||
}
|
||||
contextRelevantTypes.remove(targetClassQName);
|
||||
|
||||
final List<LookupElement> foundElements = searchForLookups(targetClassQName, contextRelevantTypes, completionContext);
|
||||
final TargetType target = completionContext.getTarget();
|
||||
contextRelevantTypes.remove(target.getClassQName());
|
||||
final List<LookupElement> elementsFoundByMethodsChainsSearch = searchForLookups(target, contextRelevantTypes, completionContext);
|
||||
if (!IS_UNIT_TEST_MODE) {
|
||||
result.runRemainingContributors(parameters, new Consumer<CompletionResult>() {
|
||||
@Override
|
||||
@@ -90,9 +76,9 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
final LookupElement lookupElement = completionResult.getLookupElement();
|
||||
final PsiElement lookupElementPsi = lookupElement.getPsiElement();
|
||||
if (lookupElementPsi != null) {
|
||||
for (final LookupElement element : foundElements) {
|
||||
for (final LookupElement element : elementsFoundByMethodsChainsSearch) {
|
||||
if (lookupElementPsi.isEquivalentTo(element.getPsiElement())) {
|
||||
foundElements.remove(element);
|
||||
elementsFoundByMethodsChainsSearch.remove(element);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -103,45 +89,50 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
} else {
|
||||
result.stopHere();
|
||||
}
|
||||
result.addAllElements(foundElements);
|
||||
result.addAllElements(elementsFoundByMethodsChainsSearch);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static List<LookupElement> searchForLookups(final String targetClassQName,
|
||||
private static List<LookupElement> searchForLookups(final TargetType target,
|
||||
final Set<String> contextRelevantTypes,
|
||||
final ChainCompletionContext completionContext) {
|
||||
final MethodsUsageIndexReader methodsUsageIndexReader = MethodsUsageIndexReader.getInstance(completionContext.getProject());
|
||||
final Project project = completionContext.getProject();
|
||||
final MethodsUsageIndexReader methodsUsageIndexReader = MethodsUsageIndexReader.getInstance(project);
|
||||
final List<MethodsChain> searchResult =
|
||||
searchChains(targetClassQName, contextRelevantTypes, MAX_SEARCH_RESULT_SIZE, MAX_CHAIN_SIZE, completionContext, methodsUsageIndexReader);
|
||||
searchChains(target, contextRelevantTypes, MAX_SEARCH_RESULT_SIZE, MAX_CHAIN_SIZE, completionContext, methodsUsageIndexReader);
|
||||
if (searchResult.size() < MAX_SEARCH_RESULT_SIZE) {
|
||||
final PsiClass aClass = JavaPsiFacade.getInstance(completionContext.getProject())
|
||||
.findClass(targetClassQName, GlobalSearchScope.allScope(completionContext.getProject()));
|
||||
if (aClass != null) {
|
||||
DirectClassInheritorsSearch.search(aClass).forEach(new Processor<PsiClass>() {
|
||||
if (!target.isArray()) {
|
||||
final List<MethodsChain> inheritorFilteredSearchResult = new SmartList<MethodsChain>();
|
||||
final Processor<TargetType> consumer = new Processor<TargetType>() {
|
||||
@Override
|
||||
public boolean process(final TargetType targetType) {
|
||||
for (final MethodsChain chain : searchChains(targetType, contextRelevantTypes, MAX_SEARCH_RESULT_SIZE, MAX_CHAIN_SIZE,
|
||||
completionContext, methodsUsageIndexReader)) {
|
||||
boolean insert = true;
|
||||
for (final MethodsChain baseChain : searchResult) {
|
||||
final MethodsChain.CompareResult r = MethodsChain.compare(baseChain, chain, completionContext.getPsiManager());
|
||||
if (r != MethodsChain.CompareResult.NOT_EQUAL) {
|
||||
insert = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (insert) {
|
||||
inheritorFilteredSearchResult.add(chain);
|
||||
}
|
||||
}
|
||||
searchResult.addAll(inheritorFilteredSearchResult);
|
||||
return searchResult.size() < MAX_SEARCH_RESULT_SIZE;
|
||||
}
|
||||
};
|
||||
DirectClassInheritorsSearch.search(((PsiClassType)target.getPsiType()).resolve()).forEach(new Processor<PsiClass>() {
|
||||
@Override
|
||||
public boolean process(final PsiClass psiClass) {
|
||||
final String inheritorQName = psiClass.getQualifiedName();
|
||||
if (!StringUtil.isEmpty(inheritorQName)) {
|
||||
final List<MethodsChain> inheritorFilteredSearchResult = new SmartList<MethodsChain>();
|
||||
//noinspection ConstantConditions
|
||||
for (final MethodsChain chain : searchChains(inheritorQName, contextRelevantTypes, MAX_SEARCH_RESULT_SIZE, MAX_CHAIN_SIZE,
|
||||
completionContext, methodsUsageIndexReader)) {
|
||||
boolean insert = true;
|
||||
for (final MethodsChain baseChain : searchResult) {
|
||||
final MethodsChain.CompareResult r = MethodsChain.compare(baseChain, chain, completionContext.getPsiManager());
|
||||
if (r != MethodsChain.CompareResult.NOT_EQUAL) {
|
||||
insert = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (insert) {
|
||||
inheritorFilteredSearchResult.add(chain);
|
||||
}
|
||||
}
|
||||
searchResult.addAll(inheritorFilteredSearchResult);
|
||||
if (inheritorQName == null) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return consumer.process(new TargetType(inheritorQName, false, new PsiImmediateClassType(psiClass, PsiSubstitutor.EMPTY)));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -221,12 +212,12 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
return filteredResult;
|
||||
}
|
||||
|
||||
private static List<MethodsChain> searchChains(final String targetQName,
|
||||
private static List<MethodsChain> searchChains(final TargetType target,
|
||||
final Set<String> contextVarsQNames,
|
||||
final int maxResultSize,
|
||||
final int maxChainSize,
|
||||
final ChainCompletionContext context,
|
||||
final MethodsUsageIndexReader methodsUsageIndexReader) {
|
||||
return ChainsSearcher.search(methodsUsageIndexReader, targetQName, contextVarsQNames, maxResultSize, maxChainSize, context);
|
||||
return ChainsSearcher.search(maxChainSize, target, contextVarsQNames, maxResultSize, context, methodsUsageIndexReader);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-9
@@ -19,10 +19,7 @@ import com.intellij.compiler.classFilesIndex.chainsSearch.CachedRelevantStaticMe
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.openapi.util.UserDataHolder;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiVariable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
@@ -44,7 +41,7 @@ public class ChainCompletionContext {
|
||||
}
|
||||
};
|
||||
private final PsiMethod myContextMethod;
|
||||
private final String myTargetQName;
|
||||
private final TargetType myTarget;
|
||||
private final Set<String> myContainingClassQNames;
|
||||
private final MultiMap<String, PsiVariable> myContextVars;
|
||||
private final MultiMap<String, PsiMethod> myContainingClassGetters;
|
||||
@@ -72,7 +69,7 @@ public class ChainCompletionContext {
|
||||
}
|
||||
|
||||
ChainCompletionContext(final PsiMethod contextMethod,
|
||||
final String targetQName,
|
||||
final TargetType target,
|
||||
final Set<String> containingClassQNames,
|
||||
final MultiMap<String, PsiVariable> contextVars,
|
||||
final MultiMap<String, PsiMethod> containingClassGetters,
|
||||
@@ -82,7 +79,7 @@ public class ChainCompletionContext {
|
||||
final Project project,
|
||||
final GlobalSearchScope resolveScope) {
|
||||
myContextMethod = contextMethod;
|
||||
myTargetQName = targetQName;
|
||||
myTarget = target;
|
||||
myContainingClassQNames = containingClassQNames;
|
||||
myContextVars = contextVars;
|
||||
myContainingClassGetters = containingClassGetters;
|
||||
@@ -104,8 +101,8 @@ public class ChainCompletionContext {
|
||||
return myContextMethodName.getValue();
|
||||
}
|
||||
|
||||
public String getTargetQName() {
|
||||
return myTargetQName;
|
||||
public TargetType getTarget() {
|
||||
return myTarget;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+21
-26
@@ -38,20 +38,18 @@ public final class ContextUtil {
|
||||
if (variableType == null || containingElement == null) {
|
||||
return null;
|
||||
}
|
||||
if (variableType instanceof PsiClassType) {
|
||||
final PsiClass aClass = ((PsiClassType)variableType).resolve();
|
||||
if (aClass != null) {
|
||||
if (aClass.hasTypeParameters()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final String targetQName = variableType.getCanonicalText();
|
||||
if (targetQName == null || targetQName.endsWith("[]")) {
|
||||
final TargetType target;
|
||||
if (variableType instanceof PsiClassType) {
|
||||
target = TargetType.create((PsiClassType)variableType);
|
||||
}
|
||||
else if (variableType instanceof PsiArrayType) {
|
||||
target = TargetType.create((PsiArrayType)variableType);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -121,7 +119,7 @@ public final class ContextUtil {
|
||||
}
|
||||
}
|
||||
|
||||
return create(method, targetQName, contextVars, contextMethods, containingClassQNames, containingElement.getProject(),
|
||||
return create(method, target, contextVars, contextMethods, containingClassQNames, containingElement.getProject(),
|
||||
containingElement.getResolveScope(), excludedQNames);
|
||||
}
|
||||
|
||||
@@ -177,7 +175,7 @@ public final class ContextUtil {
|
||||
|
||||
@Nullable
|
||||
private static ChainCompletionContext create(final PsiMethod contextMethod,
|
||||
final String targetQName,
|
||||
final TargetType target,
|
||||
final List<PsiVariable> contextVars,
|
||||
final List<PsiMethod> contextMethods,
|
||||
final Set<String> containingClassQNames,
|
||||
@@ -190,12 +188,10 @@ public final class ContextUtil {
|
||||
final Map<String, PsiVariable> stringVars = new HashMap<String, PsiVariable>();
|
||||
|
||||
for (final PsiMethod method : contextMethods) {
|
||||
PsiType returnType = method.getReturnType();
|
||||
final PsiType returnType = method.getReturnType();
|
||||
if (returnType != null) {
|
||||
final String returnTypeQName = returnType.getCanonicalText();
|
||||
if (returnTypeQName != null) {
|
||||
containingClassGetters.putValue(returnTypeQName, method);
|
||||
}
|
||||
containingClassGetters.putValue(returnTypeQName, method);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,13 +210,14 @@ public final class ContextUtil {
|
||||
final PsiClass aClass = ((PsiClassType)type).resolve();
|
||||
if (aClass != null) {
|
||||
final String classQName = type.getCanonicalText();
|
||||
if (!targetQName.equals(classQName)) {
|
||||
if (!target.getClassQName().equals(classQName)) {
|
||||
classQNames.add(classQName);
|
||||
classQNames.addAll(resolveSupersNamesRecursively(aClass));
|
||||
for (final PsiMethod method : aClass.getAllMethods()) {
|
||||
if (method.getParameterList().getParametersCount() == 0 && method.getName().startsWith("get")) {
|
||||
final String getterReturnTypeQName = method.getReturnType().getCanonicalText();
|
||||
if (getterReturnTypeQName != null) {
|
||||
final PsiType returnType = method.getReturnType();
|
||||
if (returnType != null) {
|
||||
final String getterReturnTypeQName = returnType.getCanonicalText();
|
||||
contextVarsGetters.putValue(getterReturnTypeQName, new ContextRelevantVariableGetter(var, method));
|
||||
}
|
||||
}
|
||||
@@ -230,15 +227,13 @@ public final class ContextUtil {
|
||||
}
|
||||
else {
|
||||
final String classQName = type.getCanonicalText();
|
||||
if (classQName != null) {
|
||||
classQNames.add(classQName);
|
||||
}
|
||||
classQNames.add(classQName);
|
||||
}
|
||||
for (final String qName : classQNames) {
|
||||
classQNameToVariable.putValue(qName, var);
|
||||
}
|
||||
}
|
||||
return new ChainCompletionContext(contextMethod, targetQName, containingClassQNames, classQNameToVariable, containingClassGetters,
|
||||
return new ChainCompletionContext(contextMethod, target, containingClassQNames, classQNameToVariable, containingClassGetters,
|
||||
contextVarsGetters, stringVars, excludedQNames, project, resolveScope);
|
||||
}
|
||||
|
||||
|
||||
+16
-2
@@ -57,8 +57,22 @@ final class MethodIncompleteSignatureResolver {
|
||||
for (final PsiMethod method : methods) {
|
||||
if (method.hasModifierProperty(PsiModifier.STATIC) == signature.isStatic()) {
|
||||
final PsiType returnType = method.getReturnType();
|
||||
if (returnType != null && returnType.equalsToText(signature.getReturnType())) {
|
||||
filtered.add(method);
|
||||
if (returnType != null) {
|
||||
if (returnType instanceof PsiClassType) {
|
||||
final PsiClass resolved = ((PsiClassType)returnType).resolve();
|
||||
if (resolved == null) {
|
||||
continue;
|
||||
}
|
||||
final String qualifiedName = resolved.getQualifiedName();
|
||||
if (qualifiedName == null) {
|
||||
continue;
|
||||
}
|
||||
if (qualifiedName.equals(signature.getReturnType())) {
|
||||
filtered.add(method);
|
||||
}
|
||||
} else if (returnType.equalsToText(signature.getReturnType())) {
|
||||
filtered.add(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
*/
|
||||
package com.intellij.compiler.classFilesIndex.chainsSearch.context;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class TargetType {
|
||||
|
||||
private final String myClassQName;
|
||||
private final boolean myArray;
|
||||
private final PsiType myPsiType;
|
||||
|
||||
public TargetType(final String classQName,
|
||||
final boolean isArray,
|
||||
final PsiType targetType) {
|
||||
myClassQName = classQName;
|
||||
myArray = isArray;
|
||||
myPsiType = targetType;
|
||||
}
|
||||
|
||||
public String getClassQName() {
|
||||
return myClassQName;
|
||||
}
|
||||
|
||||
public boolean isArray() {
|
||||
return myArray;
|
||||
}
|
||||
|
||||
public PsiType getPsiType() {
|
||||
return myPsiType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TargetType create(final PsiArrayType arrayType) {
|
||||
PsiType currentComponentType = arrayType.getComponentType();
|
||||
while (currentComponentType instanceof PsiArrayType) {
|
||||
currentComponentType = ((PsiArrayType)currentComponentType).getComponentType();
|
||||
}
|
||||
if (!(currentComponentType instanceof PsiClassType)) {
|
||||
return null;
|
||||
}
|
||||
final String targetQName = arrayType.getCanonicalText();
|
||||
return new TargetType(targetQName, true, arrayType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TargetType create(final PsiClassType classType) {
|
||||
final PsiClassType.ClassResolveResult resolvedGenerics = classType.resolveGenerics();
|
||||
final PsiClass resolvedClass = resolvedGenerics.getElement();
|
||||
if (resolvedClass == null) {
|
||||
return null;
|
||||
}
|
||||
final String classQName = resolvedClass.getQualifiedName();
|
||||
if (classQName == null) {
|
||||
return null;
|
||||
}
|
||||
if (resolvedClass.hasTypeParameters()) {
|
||||
return null;
|
||||
}
|
||||
return new TargetType(classQName, false, classType);
|
||||
}
|
||||
}
|
||||
-1
@@ -78,5 +78,4 @@ public class MethodsUsageIndexReader extends ClassFilesIndexReaderBase<String, T
|
||||
});
|
||||
return values;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
*/
|
||||
import java.jang.String;
|
||||
|
||||
class PsiMethod {
|
||||
}
|
||||
|
||||
interface PsiClass {
|
||||
PsiMethod[] getMethods();
|
||||
}
|
||||
|
||||
public class TestCompletion {
|
||||
|
||||
PsiClass c;
|
||||
|
||||
public void method() {
|
||||
PsiMethod[] m = <caret>
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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(PsiClass c) {
|
||||
c.getMethods();
|
||||
c.getMethods();
|
||||
c.getMethods();
|
||||
c.getMethods();
|
||||
c.getMethods();
|
||||
c.getMethods();
|
||||
c.getMethods();
|
||||
c.getMethods();
|
||||
}
|
||||
}
|
||||
|
||||
class PsiMethod {
|
||||
}
|
||||
|
||||
interface PsiClass {
|
||||
PsiMethod[] getMethods();
|
||||
}
|
||||
+12
-16
@@ -19,15 +19,16 @@ import com.intellij.openapi.compiler.CompilerMessage;
|
||||
import com.intellij.openapi.compiler.CompilerMessageCategory;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.testFramework.CompilerTester;
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
@@ -48,21 +49,16 @@ public abstract class AbstractCompilerAwareTest extends JavaCodeInsightFixtureTe
|
||||
}
|
||||
|
||||
protected final void compileAndIndexData(final String... fileNames) {
|
||||
final VirtualFile[] filesToCompile =
|
||||
ContainerUtil.map2Array(ContainerUtil.list(fileNames), new VirtualFile[fileNames.length], new Function<String, VirtualFile>() {
|
||||
@Override
|
||||
public VirtualFile fun(final String fileName) {
|
||||
try {
|
||||
return myFixture.addFileToProject(fileName, FileUtil.loadFile(new File(getTestDataPath() + getName() + "/" + fileName)))
|
||||
.getVirtualFile();
|
||||
}
|
||||
catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
try {
|
||||
for (String fileName : fileNames) {
|
||||
myFixture.addFileToProject(fileName, FileUtil.loadFile(new File(getTestDataPath() + getName() + "/" + fileName))).getVirtualFile();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
for (final CompilerMessage compilerMessage : myCompilerTester.rebuild()) {
|
||||
assertNotSame(CompilerMessageCategory.ERROR, compilerMessage.getCategory());
|
||||
assertNotSame(compilerMessage.getMessage(), CompilerMessageCategory.ERROR, compilerMessage.getCategory());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -251,8 +251,7 @@ public class MethodChainsCompletionTest extends AbstractCompilerAwareTest {
|
||||
private LookupElement[] runCompletion() {
|
||||
myFixture.configureByFiles(getTestCompletionFilePath());
|
||||
final LookupElement[] lookupElements =
|
||||
myFixture.complete(MethodsChainsCompletionContributor.COMPLETION_TYPE,
|
||||
MethodsChainsCompletionContributor.INVOCATIONS_THRESHOLD);
|
||||
myFixture.complete(CompletionType.BASIC, MethodsChainsCompletionContributor.INVOCATIONS_THRESHOLD);
|
||||
return lookupElements == null ? LookupElement.EMPTY_ARRAY : lookupElements;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,10 +46,12 @@ public class AsmUtil {
|
||||
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 isPrimitiveOrArray(final String asmType) {
|
||||
if (asmType.startsWith("[")) {
|
||||
return true;
|
||||
public static boolean isPrimitiveOrArrayOfPrimitives(final String asmType) {
|
||||
for (int i = 0; i < asmType.length(); i++) {
|
||||
if (asmType.charAt(i) != '[') {
|
||||
return ASM_PRIMITIVE_TYPES.contains(asmType.substring(i));
|
||||
}
|
||||
}
|
||||
return ASM_PRIMITIVE_TYPES.contains(asmType);
|
||||
throw new AssertionError("Illegal string: " + asmType);
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.jetbrains.jps.classFilesIndex.indexer.api;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.SLRUCache;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
@@ -27,6 +29,7 @@ import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
+6
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.jetbrains.jps.classFilesIndex.indexer.api;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Log;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.PersistentHashMap;
|
||||
import org.jetbrains.asm4.ClassReader;
|
||||
@@ -30,6 +32,8 @@ import java.util.Set;
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class ClassFilesIndexWriter<K, V> {
|
||||
private static final Logger LOG = Logger.getInstance(ClassFilesIndexWriter.class);
|
||||
|
||||
private final ClassFileIndexer<K, V> myIndexer;
|
||||
private final boolean myEmpty;
|
||||
protected final ClassFilesIndexStorage<K, V> myIndex;
|
||||
@@ -43,6 +47,7 @@ public class ClassFilesIndexWriter<K, V> {
|
||||
}
|
||||
ClassFilesIndexStorage<K, V> index = null;
|
||||
IOException exception = null;
|
||||
LOG.debug("start open... " + indexer.getIndexCanonicalName());
|
||||
for (int attempt = 0; attempt < 2; attempt++) {
|
||||
try {
|
||||
index = new ClassFilesIndexStorage<K, V>(storageDir, myIndexer.getKeyDescriptor(), myIndexer.getDataExternalizer());
|
||||
@@ -53,6 +58,7 @@ public class ClassFilesIndexWriter<K, V> {
|
||||
PersistentHashMap.deleteFilesStartingWith(ClassFilesIndexStorage.getIndexFile(storageDir));
|
||||
}
|
||||
}
|
||||
LOG.debug("opened " + indexer.getIndexCanonicalName());
|
||||
if (index == null) {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
|
||||
+10
-1
@@ -36,6 +36,8 @@ import org.jetbrains.jps.service.JpsServiceManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
@@ -46,6 +48,8 @@ public class ClassFilesIndicesBuilder extends BaseInstrumentingBuilder {
|
||||
private static final String PROGRESS_MESSAGE = "Indexing class-files...";
|
||||
public static final String PROPERTY_NAME = "intellij.compiler.output.index";
|
||||
|
||||
private final AtomicLong myMs = new AtomicLong(0);
|
||||
private final AtomicInteger myFilesCount = new AtomicInteger(0);
|
||||
private final Collection<ClassFilesIndexWriter> myIndexWriters = new ArrayList<ClassFilesIndexWriter>();
|
||||
|
||||
@Override
|
||||
@@ -89,11 +93,13 @@ public class ClassFilesIndicesBuilder extends BaseInstrumentingBuilder {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
final long ms = System.currentTimeMillis();
|
||||
for (final ClassFilesIndexWriter index : myIndexWriters) {
|
||||
index.close(context);
|
||||
}
|
||||
myIndexWriters.clear();
|
||||
LOG.info("class files indexing finished");
|
||||
myMs.addAndGet(System.currentTimeMillis() - ms);
|
||||
LOG.info("class files indexing finished for " + myFilesCount.get() + " files in " + myMs.get() + "ms");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -103,9 +109,12 @@ public class ClassFilesIndicesBuilder extends BaseInstrumentingBuilder {
|
||||
final ClassReader reader,
|
||||
final ClassWriter writer,
|
||||
final InstrumentationClassFinder finder) {
|
||||
final long ms = System.currentTimeMillis();
|
||||
for (final ClassFilesIndexWriter index : myIndexWriters) {
|
||||
index.update(compiled.getOutputFile().getPath(), reader);
|
||||
}
|
||||
myMs.addAndGet(System.currentTimeMillis() - ms);
|
||||
myFilesCount.incrementAndGet();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+11
@@ -17,6 +17,7 @@ package org.jetbrains.jps.classFilesIndex.indexer.impl;
|
||||
|
||||
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.jps.classFilesIndex.AsmUtil;
|
||||
|
||||
@@ -79,6 +80,16 @@ public class MethodIncompleteSignature {
|
||||
return myStatic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MethodIncompleteSignature{" +
|
||||
"myOwner='" + myOwner + '\'' +
|
||||
", myReturnType='" + myReturnType + '\'' +
|
||||
", myName='" + myName + '\'' +
|
||||
", myStatic=" + myStatic +
|
||||
'}';
|
||||
}
|
||||
|
||||
public final static Comparator<MethodIncompleteSignature> COMPARATOR = new Comparator<MethodIncompleteSignature>() {
|
||||
@Override
|
||||
public int compare(final MethodIncompleteSignature o1, final MethodIncompleteSignature o2) {
|
||||
|
||||
+5
-6
@@ -15,18 +15,15 @@
|
||||
*/
|
||||
package org.jetbrains.jps.classFilesIndex.indexer.impl;
|
||||
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.asm4.*;
|
||||
import org.jetbrains.jps.classFilesIndex.AsmUtil;
|
||||
import org.jetbrains.jps.classFilesIndex.TObjectIntHashMapExternalizer;
|
||||
import org.jetbrains.jps.classFilesIndex.indexer.api.ClassFileIndexer;
|
||||
import org.jetbrains.jps.classFilesIndex.indexer.api.ClassFilesIndicesBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -44,12 +41,14 @@ public class MethodsUsageIndexer extends ClassFileIndexer<String, TObjectIntHash
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<String, TObjectIntHashMap<MethodIncompleteSignature>> map(final ClassReader inputData) {
|
||||
final Map<String, TObjectIntHashMap<MethodIncompleteSignature>> map = new HashMap<String, TObjectIntHashMap<MethodIncompleteSignature>>();
|
||||
final Map<String, TObjectIntHashMap<MethodIncompleteSignature>> map =
|
||||
new HashMap<String, TObjectIntHashMap<MethodIncompleteSignature>>();
|
||||
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())) {
|
||||
if (MethodIncompleteSignature.CONSTRUCTOR_METHOD_NAME.equals(name) ||
|
||||
AsmUtil.isPrimitiveOrArrayOfPrimitives(returnType.getDescriptor())) {
|
||||
return;
|
||||
}
|
||||
final boolean isStatic = opcode == Opcodes.INVOKESTATIC;
|
||||
@@ -68,7 +67,7 @@ public class MethodsUsageIndexer extends ClassFileIndexer<String, TObjectIntHash
|
||||
final String[] exceptions) {
|
||||
return methodVisitor;
|
||||
}
|
||||
}, ClassReader.EXPAND_FRAMES);
|
||||
}, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user