mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
method chain search use PsiType-s instead of raw strings
This commit is contained in:
+4
-3
@@ -41,9 +41,10 @@ public class CachedRelevantStaticMethodSearcher {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<ContextRelevantStaticMethod> getRelevantStaticMethods(final String resultQualifiedClassName, final int minOccurrence) {
|
||||
public List<ContextRelevantStaticMethod> getRelevantStaticMethods(final PsiType type, final int minOccurrence) {
|
||||
String resultQualifiedClassName = type.getCanonicalText();
|
||||
if (resultQualifiedClassName == null ||
|
||||
ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(resultQualifiedClassName) ||
|
||||
ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(type) ||
|
||||
myCompletionContext.getTarget().getClassQName().equals(resultQualifiedClassName)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -104,7 +105,7 @@ public class CachedRelevantStaticMethodSearcher {
|
||||
final String shortClassName = typeAsShortString(type);
|
||||
if (targetTypeShortName.equals(shortClassName)) return false;
|
||||
if (!ChainCompletionStringUtil.isShortNamePrimitiveOrArrayOfPrimitives(shortClassName) &&
|
||||
!completionContext.contains(type.getCanonicalText())) {
|
||||
!completionContext.contains(type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-40
@@ -15,14 +15,11 @@
|
||||
*/
|
||||
package com.intellij.compiler.classFilesIndex.chainsSearch;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtilRt;
|
||||
import com.intellij.psi.CommonClassNames;
|
||||
import com.intellij.psi.PsiPrimitiveType;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -36,11 +33,21 @@ public final class ChainCompletionStringUtil {
|
||||
* isPrimitiveOrArrayOfPrimitives("java.lang.Object") == true
|
||||
* isPrimitiveOrArrayOfPrimitives("java.lang.Class") == true
|
||||
*/
|
||||
public static boolean isPrimitiveOrArrayOfPrimitives(final @Nullable String typeQName) {
|
||||
if (typeQName == null) {
|
||||
return false;
|
||||
public static boolean isPrimitiveOrArrayOfPrimitives(@NotNull PsiType type) {
|
||||
type = type.getDeepComponentType();
|
||||
if (type instanceof PsiPrimitiveType) return true;
|
||||
if (!(type instanceof PsiClassType)) return false;
|
||||
if (PRIMITIVES_SHORT_NAMES.contains(((PsiClassType)type).getClassName())) return false;
|
||||
final PsiClass resolvedClass = ((PsiClassType)type).resolve();
|
||||
if (resolvedClass == null) return false;
|
||||
final String qName = resolvedClass.getQualifiedName();
|
||||
if (qName == null) return false;
|
||||
for (String name : PRIMITIVES_NAMES) {
|
||||
if (name.equals(qName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return PRIMITIVES_NAMES.contains(deleteArraySigns(typeQName));
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isShortNamePrimitiveOrArrayOfPrimitives(final @Nullable String shortName) {
|
||||
@@ -58,35 +65,8 @@ public final class ChainCompletionStringUtil {
|
||||
return nameWithoutArraySign;
|
||||
}
|
||||
|
||||
private static final Set<String> PRIMITIVES_NAMES = new HashSet<>();
|
||||
private static final Set<String> PRIMITIVES_SHORT_NAMES = new HashSet<>();
|
||||
|
||||
static {
|
||||
fillPrimitivesNames(PsiType.BOOLEAN);
|
||||
fillPrimitivesNames(PsiType.INT);
|
||||
fillPrimitivesNames(PsiType.LONG);
|
||||
fillPrimitivesNames(PsiType.DOUBLE);
|
||||
fillPrimitivesNames(PsiType.FLOAT);
|
||||
fillPrimitivesNames(PsiType.SHORT);
|
||||
fillPrimitivesNames(PsiType.CHAR);
|
||||
fillPrimitivesNames(PsiType.BYTE);
|
||||
fillPrimitivesNames(PsiType.VOID);
|
||||
|
||||
fillNonPrimitiveNames(CommonClassNames.JAVA_LANG_STRING);
|
||||
fillNonPrimitiveNames(CommonClassNames.JAVA_LANG_OBJECT);
|
||||
fillNonPrimitiveNames(CommonClassNames.JAVA_LANG_CLASS);
|
||||
}
|
||||
|
||||
private static void fillNonPrimitiveNames(final String typeAsString) {
|
||||
PRIMITIVES_NAMES.add(typeAsString);
|
||||
PRIMITIVES_SHORT_NAMES.add(StringUtilRt.getShortName(typeAsString));
|
||||
}
|
||||
|
||||
private static void fillPrimitivesNames(final PsiPrimitiveType type) {
|
||||
PRIMITIVES_NAMES.add(type.getBoxedTypeName());
|
||||
PRIMITIVES_NAMES.add(type.getCanonicalText());
|
||||
|
||||
PRIMITIVES_SHORT_NAMES.add(StringUtilRt.getShortName(type.getBoxedTypeName()));
|
||||
PRIMITIVES_SHORT_NAMES.add(type.getCanonicalText());
|
||||
}
|
||||
private static final String[] PRIMITIVES_NAMES = new String [] {CommonClassNames.JAVA_LANG_STRING,
|
||||
CommonClassNames.JAVA_LANG_OBJECT,
|
||||
CommonClassNames.JAVA_LANG_CLASS};
|
||||
private static final Set<String> PRIMITIVES_SHORT_NAMES = ContainerUtil.set("String", "Object", "Class");
|
||||
}
|
||||
|
||||
+16
-25
@@ -22,38 +22,30 @@ import com.intellij.compiler.classFilesIndex.impl.MethodIncompleteSignature;
|
||||
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.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public final class ChainsSearcher {
|
||||
public class ChainsSearcher {
|
||||
private static final Logger LOG = Logger.getInstance(ChainsSearcher.class);
|
||||
|
||||
private ChainsSearcher() {
|
||||
}
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(ChainsSearcher.class);
|
||||
private static final double NEXT_METHOD_IN_CHAIN_RATIO = 1.5;
|
||||
|
||||
@NotNull
|
||||
public static List<MethodsChain> search(final int pathMaximalLength,
|
||||
final TargetType targetType,
|
||||
final Set<String> contextQNames,
|
||||
final Set<PsiType> contextQNames,
|
||||
final int maxResultSize,
|
||||
final ChainCompletionContext context,
|
||||
final CompilerReferenceServiceEx methodsUsageIndexReader) {
|
||||
final SearchInitializer initializer = createInitializer(targetType, context.getExcludedQNames(), methodsUsageIndexReader, context);
|
||||
if (initializer == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return search(methodsUsageIndexReader,
|
||||
final CompilerReferenceServiceEx compilerReferenceServiceEx) {
|
||||
final SearchInitializer initializer = createInitializer(targetType, compilerReferenceServiceEx, context);
|
||||
return search(compilerReferenceServiceEx,
|
||||
initializer,
|
||||
contextQNames,
|
||||
pathMaximalLength,
|
||||
@@ -62,25 +54,24 @@ public final class ChainsSearcher {
|
||||
context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
private static SearchInitializer createInitializer(final TargetType target,
|
||||
final Set<String> excludedParamsTypesQNames,
|
||||
final CompilerReferenceServiceEx methodsUsageIndexReader,
|
||||
final CompilerReferenceServiceEx compilerReferenceServiceEx,
|
||||
final ChainCompletionContext context) {
|
||||
final SortedSet<OccurrencesAware<MethodIncompleteSignature>> methods = methodsUsageIndexReader.getMethods(target.getClassQName());
|
||||
return new SearchInitializer(methods, target.getClassQName(), excludedParamsTypesQNames, context);
|
||||
final SortedSet<OccurrencesAware<MethodIncompleteSignature>> methods = compilerReferenceServiceEx.getMethods(target.getClassQName());
|
||||
return new SearchInitializer(methods, target.getPsiType(), context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<MethodsChain> search(final CompilerReferenceServiceEx indexReader,
|
||||
final SearchInitializer initializer,
|
||||
final Set<String> toSet,
|
||||
final Set<PsiType> toSet,
|
||||
final int pathMaximalLength,
|
||||
final int maxResultSize,
|
||||
final String targetQName,
|
||||
final ChainCompletionContext context) {
|
||||
final Set<String> allExcludedNames = MethodChainsSearchUtil.joinToHashSet(context.getExcludedQNames(), targetQName);
|
||||
final SearchInitializer.InitResult initResult = initializer.init(Collections.<String>emptySet());
|
||||
final Set<PsiType> allExcludedNames = Collections.singleton(context.getTarget().getPsiType());
|
||||
final SearchInitializer.InitResult initResult = initializer.init(Collections.emptySet());
|
||||
|
||||
final Map<MethodIncompleteSignature, MethodsChain> knownDistance = initResult.getChains();
|
||||
|
||||
@@ -143,7 +134,7 @@ public final class ChainsSearcher {
|
||||
if (currentVertexMethodsChain.size() < pathMaximalLength - 1) {
|
||||
final MethodIncompleteSignature methodInvocation = indexValue.getUnderlying();
|
||||
final PsiMethod[] psiMethods = context.resolveNotDeprecated(methodInvocation);
|
||||
if (psiMethods.length != 0 && MethodChainsSearchUtil.checkParametersForTypesQNames(psiMethods, allExcludedNames)) {
|
||||
if (psiMethods.length != 0 && !MethodChainsSearchUtil.doesMethodsContainParameters(psiMethods, allExcludedNames)) {
|
||||
final MethodsChain newBestMethodsChain =
|
||||
currentVertexMethodsChain.addEdge(psiMethods, indexValue.getUnderlying().getOwner(), vertexDistance);
|
||||
currentSignatures
|
||||
|
||||
+58
-57
@@ -16,77 +16,78 @@
|
||||
package com.intellij.compiler.classFilesIndex.chainsSearch;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.text.EditDistance;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public final class MethodChainsSearchUtil {
|
||||
private final static int COMMON_PART_MIN_LENGTH = 3;
|
||||
|
||||
private MethodChainsSearchUtil() {
|
||||
}
|
||||
|
||||
public static boolean isSimilar(@NotNull final String target,
|
||||
@NotNull final String candidate) {
|
||||
return EditDistance.levenshtein(target, sanitizedToLowerCase(candidate), true) >= COMMON_PART_MIN_LENGTH;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String sanitizedToLowerCase(@NotNull final String name) {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
final char ch = name.charAt(i);
|
||||
if (Character.isLetter(ch)) {
|
||||
result.append(Character.toLowerCase(ch));
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod getMethodWithMinNotPrimitiveParameters(final @NotNull PsiMethod[] methods,
|
||||
final Set<String> excludedParamsQNames) {
|
||||
PsiMethod minMethod = null;
|
||||
int minParametersCount = Integer.MAX_VALUE;
|
||||
for (final PsiMethod method : methods) {
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
boolean doContinue = false;
|
||||
int parametersCount = parameterList.getParametersCount();
|
||||
for (final PsiParameter p : parameterList.getParameters()) {
|
||||
if (!(p.getType() instanceof PsiPrimitiveType)) {
|
||||
if (excludedParamsQNames.contains(p.getType().getCanonicalText())) {
|
||||
doContinue = true;
|
||||
break;
|
||||
}
|
||||
parametersCount++;
|
||||
}
|
||||
}
|
||||
if (doContinue) {
|
||||
continue;
|
||||
}
|
||||
if (parametersCount < minParametersCount) {
|
||||
if (parametersCount == 0) {
|
||||
return method;
|
||||
}
|
||||
minParametersCount = parametersCount;
|
||||
minMethod = method;
|
||||
}
|
||||
}
|
||||
return minMethod;
|
||||
final @NotNull Set<String> excludedQNames) {
|
||||
return Stream.of(methods)
|
||||
.filter(m -> !containsParameter(m, excludedQNames))
|
||||
.sorted(Comparator.comparing(MethodChainsSearchUtil::getNonPrimitiveParameterCount))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public static boolean checkParametersForTypesQNames(final PsiMethod[] psiMethods, final Set<String> excludedTypesQNames) {
|
||||
if (psiMethods.length == 0) {
|
||||
return true;
|
||||
private static boolean containsParameter(@NotNull PsiMethod method, @NotNull Set<String> excludedQNames) {
|
||||
for (PsiParameter parameter : method.getParameterList().getParameters()) {
|
||||
final PsiType t = parameter.getType();
|
||||
final boolean matched = isRawTypeOneOf(t, excludedQNames);
|
||||
if (matched) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (final PsiMethod method : psiMethods) {
|
||||
boolean hasTargetInParams = false;
|
||||
for (final PsiParameter param : method.getParameterList().getParameters()) {
|
||||
final String paramType = param.getType().getCanonicalText();
|
||||
if (excludedTypesQNames.contains(paramType)) {
|
||||
hasTargetInParams = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasTargetInParams) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isRawTypeOneOf(@NotNull PsiType type, @NotNull Set<String> qNames) {
|
||||
final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(type);
|
||||
return aClass != null && qNames.contains(aClass.getQualifiedName());
|
||||
}
|
||||
|
||||
private static int getNonPrimitiveParameterCount(PsiMethod method) {
|
||||
return (int)Stream.of(method.getParameterList().getParameters())
|
||||
.map(p -> p.getType())
|
||||
.filter(t -> !TypeConversionUtil.isPrimitiveAndNotNull(t))
|
||||
.count();
|
||||
}
|
||||
|
||||
public static boolean doesMethodsContainParameters(@NotNull final PsiMethod[] psiMethods,
|
||||
@NotNull final Set<PsiType> parameterRawTypes) {
|
||||
for (PsiMethod m : psiMethods) {
|
||||
//TODO
|
||||
//if (!containsParameter(m, parameterRawTypes)) {
|
||||
// return true;
|
||||
//}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static <T> HashSet<T> joinToHashSet(final Collection<T> collection, final T... items) {
|
||||
final HashSet<T> result = new HashSet<>();
|
||||
result.addAll(collection);
|
||||
Collections.addAll(result, items);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+25
-39
@@ -17,16 +17,15 @@ package com.intellij.compiler.classFilesIndex.chainsSearch;
|
||||
|
||||
import com.intellij.codeInsight.NullableNotNullManager;
|
||||
import com.intellij.codeInsight.completion.JavaChainLookupElement;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ContextRelevantStaticMethod;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ContextRelevantVariableGetter;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.VariableLookupItem;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.ChainCompletionNewVariableLookupElement;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.WeightableChainLookupElement;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.GetterLookupSubLookupElement;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.SubLookupElement;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.VariableSubLookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.VariableLookupItem;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ContextRelevantStaticMethod;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
@@ -41,9 +40,6 @@ import java.util.List;
|
||||
import static com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.ChainCompletionLookupElementUtil.createLookupElement;
|
||||
import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
|
||||
*/
|
||||
public class MethodsChainLookupRangingHelper {
|
||||
|
||||
public static List<LookupElement> chainsToWeightableLookupElements(final List<MethodsChain> chains,
|
||||
@@ -144,40 +140,26 @@ public class MethodsChainLookupRangingHelper {
|
||||
final PsiParameter[] parameters = parameterList.getParameters();
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
final PsiParameter parameter = parameters[i];
|
||||
final String typeQName = parameter.getType().getCanonicalText();
|
||||
if (JAVA_LANG_STRING.equals(typeQName)) {
|
||||
final PsiVariable relevantStringVar = context.findRelevantStringInContext(parameter.getName());
|
||||
if (relevantStringVar == null) {
|
||||
final PsiType type = parameter.getType();
|
||||
if (type.equalsToText(JAVA_LANG_STRING)) {
|
||||
final PsiElement relevantStringElement = context.findRelevantStringInContext(parameter.getName());
|
||||
if (relevantStringElement == null) {
|
||||
notMatchedStringVars++;
|
||||
}
|
||||
else {
|
||||
parametersMap.put(i, new VariableSubLookupElement(relevantStringVar));
|
||||
parametersMap.put(i, createSubLookup(relevantStringElement));
|
||||
}
|
||||
}
|
||||
else if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(typeQName)) {
|
||||
final Collection<PsiVariable> contextVariables = context.getVariables(typeQName);
|
||||
final PsiVariable contextVariable = ContainerUtil.getFirstItem(contextVariables, null);
|
||||
else if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(type)) {
|
||||
final Collection<PsiElement> contextVariables = context.getQualifiers(type);
|
||||
final PsiElement 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()));
|
||||
if (contextVariables.size() == 1) parametersMap.put(i, createSubLookup(contextVariable));
|
||||
matchedParametersInContext++;
|
||||
continue;
|
||||
}
|
||||
final ContextRelevantStaticMethod contextRelevantStaticMethod =
|
||||
ContainerUtil.getFirstItem(staticMethodSearcher.getRelevantStaticMethods(typeQName, weight), null);
|
||||
ContainerUtil.getFirstItem(staticMethodSearcher.getRelevantStaticMethods(type, weight), null);
|
||||
if (contextRelevantStaticMethod != null) {
|
||||
//
|
||||
// In most cases it is not really relevant
|
||||
@@ -201,10 +183,7 @@ public class MethodsChainLookupRangingHelper {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
final String classQName = qualifierClass.getQualifiedName();
|
||||
if (classQName == null) return null;
|
||||
final Object e = ContainerUtil.getFirstItem(context.getContextRefElements(classQName), null);
|
||||
final Object e = ContainerUtil.getFirstItem(context.getQualifiers(qualifierClass), null);
|
||||
if (e != null) {
|
||||
final LookupElement firstChainElement;
|
||||
if (e instanceof PsiVariable) {
|
||||
@@ -224,9 +203,9 @@ public class MethodsChainLookupRangingHelper {
|
||||
}
|
||||
else {
|
||||
lookupElement = createLookupElement(method, parametersMap);
|
||||
if (!context.getContainingClassQNames().contains(classQName)) {
|
||||
introduceNewVariable = true;
|
||||
}
|
||||
//if (!context.getContainingClassQNames().contains(classQName)) {
|
||||
// introduceNewVariable = true;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,6 +220,13 @@ public class MethodsChainLookupRangingHelper {
|
||||
matchedParametersInContext);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static SubLookupElement createSubLookup(PsiElement relevantStringElement) {
|
||||
return relevantStringElement instanceof PsiMethod
|
||||
? new GetterLookupSubLookupElement((PsiMethod)relevantStringElement)
|
||||
: new VariableSubLookupElement((PsiVariable)relevantStringElement);
|
||||
}
|
||||
|
||||
private static class MethodProcResult {
|
||||
private final LookupElement myMethodLookup;
|
||||
private final int myUnreachableParametersCount;
|
||||
|
||||
-111
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiParameter;
|
||||
import com.intellij.psi.PsiPrimitiveType;
|
||||
import com.intellij.psi.PsiType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
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<>();
|
||||
for (final PsiMethod method : methods) {
|
||||
matchResults.add(matchParameters(method, context, chain.getExcludedQNames()));
|
||||
}
|
||||
final MatchResult best = matchResults.first();
|
||||
overallResult = overallResult.add(best);
|
||||
}
|
||||
return overallResult;
|
||||
}
|
||||
|
||||
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();
|
||||
final String canonicalText = type.getCanonicalText();
|
||||
if (context.contains(canonicalText) || type instanceof PsiPrimitiveType) {
|
||||
matched++;
|
||||
}
|
||||
else {
|
||||
unMatched++;
|
||||
}
|
||||
if (context.getTarget().getClassQName().equals(canonicalText) || additionalExcludedNames.contains(canonicalText)) {
|
||||
hasTarget = true;
|
||||
}
|
||||
}
|
||||
return new MatchResult(matched, unMatched, hasTarget);
|
||||
}
|
||||
|
||||
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, final boolean hasTarget) {
|
||||
myMatched = matched;
|
||||
myUnMatched = unMatched;
|
||||
myHasTarget = hasTarget;
|
||||
}
|
||||
|
||||
public int getMatched() {
|
||||
return myMatched;
|
||||
}
|
||||
|
||||
public int getUnMatched() {
|
||||
return myUnMatched;
|
||||
}
|
||||
|
||||
public boolean hasTarget() {
|
||||
return myHasTarget;
|
||||
}
|
||||
|
||||
public MatchResult add(final MatchResult other) {
|
||||
return new MatchResult(getMatched() + other.getMatched(), getUnMatched() + other.getUnMatched(), other.myHasTarget || myHasTarget);
|
||||
}
|
||||
|
||||
public boolean noUnmatchedAndHasMatched() {
|
||||
return myUnMatched == 0 && myMatched != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull final MatchResult other) {
|
||||
final int sub = getUnMatched() - other.getUnMatched();
|
||||
if (sub != 0) {
|
||||
return sub;
|
||||
}
|
||||
return getMatched() - other.getMatched();
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -16,30 +16,30 @@
|
||||
package com.intellij.compiler.classFilesIndex.chainsSearch;
|
||||
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.context.ChainCompletionContext;
|
||||
import com.intellij.compiler.classFilesIndex.impl.MethodIncompleteSignature;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.compiler.classFilesIndex.impl.MethodIncompleteSignature;
|
||||
import com.intellij.psi.PsiType;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SearchInitializer {
|
||||
private final static int CHAIN_SEARCH_MAGIC_RATIO = 12;
|
||||
private final static int CHAIN_SEARCH_MAGIC_RATIO = 10;
|
||||
|
||||
private final LinkedHashMap<MethodIncompleteSignature, Pair<MethodsChain, Integer>> myChains;
|
||||
private final ChainCompletionContext myContext;
|
||||
|
||||
public SearchInitializer(final SortedSet<OccurrencesAware<MethodIncompleteSignature>> indexValues,
|
||||
final String targetQName,
|
||||
final Set<String> excludedParamsTypesQNames,
|
||||
final PsiType target,
|
||||
final ChainCompletionContext context) {
|
||||
myContext = context;
|
||||
final int size = indexValues.size();
|
||||
myChains = new LinkedHashMap<>(size);
|
||||
add(indexValues, MethodChainsSearchUtil.joinToHashSet(excludedParamsTypesQNames, targetQName));
|
||||
add(indexValues, Collections.singleton(target));
|
||||
}
|
||||
|
||||
private void add(final Collection<OccurrencesAware<MethodIncompleteSignature>> indexValues,
|
||||
final Set<String> excludedParamsTypesQNames) {
|
||||
final Set<PsiType> excludedParamsTypesQNames) {
|
||||
int bestOccurrences = -1;
|
||||
for (final OccurrencesAware<MethodIncompleteSignature> indexValue : indexValues) {
|
||||
if (add(indexValue, excludedParamsTypesQNames)) {
|
||||
@@ -54,10 +54,10 @@ public class SearchInitializer {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean add(final OccurrencesAware<MethodIncompleteSignature> indexValue, final Set<String> excludedParamsTypesQNames) {
|
||||
private boolean add(final OccurrencesAware<MethodIncompleteSignature> indexValue, final Set<PsiType> excludedParamsTypesQNames) {
|
||||
final MethodIncompleteSignature methodInvocation = indexValue.getUnderlying();
|
||||
final PsiMethod[] psiMethods = myContext.resolveNotDeprecated(methodInvocation);
|
||||
if (psiMethods.length != 0 && MethodChainsSearchUtil.checkParametersForTypesQNames(psiMethods, excludedParamsTypesQNames)) {
|
||||
if (psiMethods.length != 0 && !MethodChainsSearchUtil.doesMethodsContainParameters(psiMethods, excludedParamsTypesQNames)) {
|
||||
final int occurrences = indexValue.getOccurrences();
|
||||
final MethodsChain methodsChain = new MethodsChain(psiMethods, occurrences, indexValue.getUnderlying().getOwner());
|
||||
myChains.put(methodInvocation, Pair.create(methodsChain, occurrences));
|
||||
|
||||
+2
-6
@@ -23,11 +23,7 @@ import com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl;
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
import static com.intellij.patterns.StandardPatterns.or;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
|
||||
*/
|
||||
public final class CompletionContributorPatternUtil {
|
||||
|
||||
public class CompletionContributorPatternUtil {
|
||||
private CompletionContributorPatternUtil() {}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -42,7 +38,7 @@ public final class CompletionContributorPatternUtil {
|
||||
.inside(PsiMethod.class);
|
||||
}
|
||||
|
||||
public static ElementPattern<PsiElement> patternForMethodParameter() {
|
||||
public static ElementPattern<PsiElement> patternForMethodCallParameter() {
|
||||
return psiElement().withSuperParent(3, PsiMethodCallExpressionImpl.class);
|
||||
}
|
||||
}
|
||||
|
||||
+29
-29
@@ -9,9 +9,9 @@ import com.intellij.compiler.classFilesIndex.chainsSearch.ChainsSearcher;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.MethodsChain;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.MethodsChainLookupRangingHelper;
|
||||
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.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.*;
|
||||
@@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.compiler.classFilesIndex.chainsSearch.completion.CompletionContributorPatternUtil.patternForMethodParameter;
|
||||
import static com.intellij.compiler.classFilesIndex.chainsSearch.completion.CompletionContributorPatternUtil.patternForMethodCallParameter;
|
||||
import static com.intellij.compiler.classFilesIndex.chainsSearch.completion.CompletionContributorPatternUtil.patternForVariableAssignment;
|
||||
import static com.intellij.patterns.PsiJavaPatterns.or;
|
||||
|
||||
@@ -34,18 +34,17 @@ import static com.intellij.patterns.PsiJavaPatterns.or;
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
private final static boolean IS_UNIT_TEST_MODE = ApplicationManager.getApplication().isUnitTestMode();
|
||||
private static final Logger LOG = Logger.getInstance(MethodsChainsCompletionContributor.class);
|
||||
|
||||
public static final int INVOCATIONS_THRESHOLD = 2;
|
||||
private static final boolean IS_UNIT_TEST_MODE = ApplicationManager.getApplication().isUnitTestMode();
|
||||
private static final int MAX_SEARCH_RESULT_SIZE = 5;
|
||||
private static final int MAX_CHAIN_SIZE = 4;
|
||||
private static final int FILTER_RATIO = 10;
|
||||
public static final CompletionType COMPLETION_TYPE = IS_UNIT_TEST_MODE ? CompletionType.BASIC : CompletionType.SMART;
|
||||
|
||||
private final static int MAX_SEARCH_RESULT_SIZE = 5;
|
||||
private final static int MAX_CHAIN_SIZE = 4;
|
||||
private final static int FILTER_RATIO = 10;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public MethodsChainsCompletionContributor() {
|
||||
final ElementPattern<PsiElement> pattern = or(patternForMethodParameter(), patternForVariableAssignment());
|
||||
final ElementPattern<PsiElement> pattern = or(patternForMethodCallParameter(), patternForVariableAssignment());
|
||||
extend(COMPLETION_TYPE, pattern, new CompletionProvider<CompletionParameters>() {
|
||||
@Override
|
||||
protected void addCompletions(final @NotNull CompletionParameters parameters,
|
||||
@@ -54,15 +53,15 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
final ChainCompletionContext completionContext = extractContext(parameters);
|
||||
if (completionContext == null) return;
|
||||
|
||||
final Set<String> contextTypesKeysSet = completionContext.getContextTypes();
|
||||
final Set<String> contextRelevantTypes = new HashSet<>(contextTypesKeysSet.size() + 1);
|
||||
for (final String type : contextTypesKeysSet) {
|
||||
final Set<PsiType> contextTypesKeysSet = completionContext.getContextTypes();
|
||||
final Set<PsiType> contextRelevantTypes = new HashSet<>(contextTypesKeysSet.size() + 1);
|
||||
for (final PsiType type : contextTypesKeysSet) {
|
||||
if (!ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(type)) {
|
||||
contextRelevantTypes.add(type);
|
||||
}
|
||||
}
|
||||
final TargetType target = completionContext.getTarget();
|
||||
contextRelevantTypes.remove(target.getClassQName());
|
||||
contextRelevantTypes.remove(target.getPsiType());
|
||||
final List<LookupElement> elementsFoundByMethodsChainsSearch = searchForLookups(target, contextRelevantTypes, completionContext);
|
||||
if (!IS_UNIT_TEST_MODE) {
|
||||
result.runRemainingContributors(parameters, completionResult -> {
|
||||
@@ -87,7 +86,7 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
|
||||
private static List<LookupElement> searchForLookups(final TargetType target,
|
||||
final Set<String> contextRelevantTypes,
|
||||
final Set<PsiType> contextRelevantTypes,
|
||||
final ChainCompletionContext completionContext) {
|
||||
final Project project = completionContext.getProject();
|
||||
final CompilerReferenceServiceEx methodsUsageIndexReader = (CompilerReferenceServiceEx)CompilerReferenceService.getInstance(project);
|
||||
@@ -137,22 +136,16 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
return elements.subList(0, MAX_CHAIN_SIZE);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
private static ChainCompletionContext extractContext(final CompletionParameters parameters) {
|
||||
final PsiElement parent = PsiTreeUtil
|
||||
.getParentOfType(parameters.getPosition(), PsiAssignmentExpression.class, PsiLocalVariable.class, PsiMethodCallExpression.class);
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
final PsiElement parent = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiAssignmentExpression.class, PsiLocalVariable.class, PsiMethodCallExpression.class);
|
||||
LOG.assertTrue(parent != null, "A completion position should match to a pattern");
|
||||
|
||||
if (parent instanceof PsiAssignmentExpression) {
|
||||
return tryExtractContextFromAssignment((PsiAssignmentExpression)parent);
|
||||
return extractContextFromAssignment((PsiAssignmentExpression)parent);
|
||||
}
|
||||
if (parent instanceof PsiLocalVariable) {
|
||||
final PsiLocalVariable localVariable = (PsiLocalVariable)parent;
|
||||
return ContextUtil.createContext(localVariable.getType(), localVariable.getName(),
|
||||
PsiTreeUtil.getParentOfType(parent, PsiDeclarationStatement.class));
|
||||
return extractContextFromVariable((PsiLocalVariable)parent);
|
||||
}
|
||||
final PsiMethod method = ((PsiMethodCallExpression)parent).resolveMethod();
|
||||
if (method == null) return null;
|
||||
@@ -163,19 +156,26 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
final PsiParameter[] methodParameters = method.getParameterList().getParameters();
|
||||
if (exprPosition < methodParameters.length) {
|
||||
final PsiParameter methodParameter = methodParameters[exprPosition];
|
||||
return ContextUtil
|
||||
.createContext(methodParameter.getType(), null, PsiTreeUtil.getParentOfType(expression, PsiDeclarationStatement.class));
|
||||
return ChainCompletionContext.createContext(methodParameter.getType(), null, PsiTreeUtil.getParentOfType(expression, PsiDeclarationStatement.class));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ChainCompletionContext tryExtractContextFromAssignment(final PsiAssignmentExpression assignmentExpression) {
|
||||
private static ChainCompletionContext extractContextFromVariable(PsiLocalVariable localVariable) {
|
||||
final PsiType varType = localVariable.getType();
|
||||
final String varName = localVariable.getName();
|
||||
final PsiDeclarationStatement declaration = PsiTreeUtil.getParentOfType(localVariable, PsiDeclarationStatement.class);
|
||||
return ChainCompletionContext.createContext(varType, varName, declaration);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ChainCompletionContext extractContextFromAssignment(final PsiAssignmentExpression assignmentExpression) {
|
||||
final PsiType type = assignmentExpression.getLExpression().getType();
|
||||
final PsiIdentifier identifier = PsiTreeUtil.getChildOfType(assignmentExpression.getLExpression(), PsiIdentifier.class);
|
||||
if (identifier == null) return null;
|
||||
final String identifierText = identifier.getText();
|
||||
return ContextUtil.createContext(type, identifierText, assignmentExpression);
|
||||
return ChainCompletionContext.createContext(type, identifierText, assignmentExpression);
|
||||
}
|
||||
|
||||
private static List<MethodsChain> filterTailAndGetSumLastMethodOccurrence(final List<MethodsChain> chains) {
|
||||
@@ -198,7 +198,7 @@ public class MethodsChainsCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
|
||||
private static List<MethodsChain> searchChains(final TargetType target,
|
||||
final Set<String> contextVarsQNames,
|
||||
final Set<PsiType> contextVarsQNames,
|
||||
final int maxResultSize,
|
||||
final int maxChainSize,
|
||||
final ChainCompletionContext context,
|
||||
|
||||
+3
-2
@@ -16,6 +16,7 @@
|
||||
package com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub;
|
||||
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -25,8 +26,8 @@ public class GetterLookupSubLookupElement implements SubLookupElement {
|
||||
private final String myVariableName;
|
||||
private final String myMethodName;
|
||||
|
||||
public GetterLookupSubLookupElement(final String methodName) {
|
||||
this(null, methodName);
|
||||
public GetterLookupSubLookupElement(final PsiMethod method) {
|
||||
this(null, method.getName());
|
||||
}
|
||||
|
||||
public GetterLookupSubLookupElement(@Nullable final String variableName, final String methodName) {
|
||||
|
||||
+163
-98
@@ -15,134 +15,97 @@
|
||||
*/
|
||||
package com.intellij.compiler.classFilesIndex.chainsSearch.context;
|
||||
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.CachedRelevantStaticMethodSearcher;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.ChainCompletionStringUtil;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.MethodChainsSearchUtil;
|
||||
import com.intellij.compiler.classFilesIndex.impl.MethodIncompleteSignature;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.openapi.util.UserDataHolder;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.scope.BaseScopeProcessor;
|
||||
import com.intellij.psi.scope.ElementClassHint;
|
||||
import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.psi.util.PropertyUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.compiler.classFilesIndex.impl.MethodIncompleteSignature;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class ChainCompletionContext {
|
||||
@NotNull
|
||||
private final TargetType myTarget;
|
||||
private final Set<String> myContainingClassQNames;
|
||||
private final MultiMap<String, PsiVariable> myContextVars;
|
||||
private final MultiMap<String, PsiMethod> myContainingClassGetters;
|
||||
private final MultiMap<String, ContextRelevantVariableGetter> myContextVarsGetters;
|
||||
private final Map<String, PsiVariable> myStringVars;
|
||||
private final Set<String> myExcludedQNames;
|
||||
@NotNull
|
||||
private final List<PsiNamedElement> myContextElements;
|
||||
@NotNull
|
||||
private final List<PsiNamedElement> myContextStrings;
|
||||
@NotNull
|
||||
private final PsiElement myContext;
|
||||
@NotNull
|
||||
private final GlobalSearchScope myResolveScope;
|
||||
@NotNull
|
||||
private final Project myProject;
|
||||
@NotNull
|
||||
private final PsiManager myPsiManager;
|
||||
@NotNull
|
||||
private final MethodIncompleteSignatureResolver myNotDeprecatedMethodsResolver;
|
||||
|
||||
private final NotNullLazyValue<Set<String>> contextTypesQNames = new NotNullLazyValue<Set<String>>() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@NotNull
|
||||
@Override
|
||||
protected Set<String> compute() {
|
||||
return unionToHashSet(myContainingClassQNames,
|
||||
myContextVars.keySet(),
|
||||
myContainingClassGetters.keySet(),
|
||||
myContextVarsGetters.keySet());
|
||||
}
|
||||
};
|
||||
|
||||
public Set<String> getExcludedQNames() {
|
||||
return myExcludedQNames;
|
||||
}
|
||||
|
||||
ChainCompletionContext(final TargetType target,
|
||||
final Set<String> containingClassQNames,
|
||||
final MultiMap<String, PsiVariable> contextVars,
|
||||
final MultiMap<String, PsiMethod> containingClassGetters,
|
||||
final MultiMap<String, ContextRelevantVariableGetter> contextVarsGetters,
|
||||
final Map<String, PsiVariable> stringVars,
|
||||
final Set<String> excludedQNames,
|
||||
final Project project,
|
||||
final GlobalSearchScope resolveScope) {
|
||||
public ChainCompletionContext(@NotNull TargetType target,
|
||||
@NotNull List<PsiNamedElement> contextElements,
|
||||
@NotNull List<PsiNamedElement> contextStrings,
|
||||
@NotNull PsiElement context) {
|
||||
myTarget = target;
|
||||
myContainingClassQNames = containingClassQNames;
|
||||
myContextVars = contextVars;
|
||||
myContainingClassGetters = containingClassGetters;
|
||||
myContextVarsGetters = contextVarsGetters;
|
||||
myStringVars = stringVars;
|
||||
myExcludedQNames = excludedQNames;
|
||||
myResolveScope = resolveScope;
|
||||
myProject = project;
|
||||
myPsiManager = PsiManager.getInstance(project);
|
||||
myNotDeprecatedMethodsResolver = new MethodIncompleteSignatureResolver(JavaPsiFacade.getInstance(project), resolveScope);
|
||||
myContextElements = contextElements;
|
||||
myContextStrings = contextStrings;
|
||||
myContext = context;
|
||||
myResolveScope = context.getResolveScope();
|
||||
myProject = context.getProject();
|
||||
myPsiManager = PsiManager.getInstance(myProject);
|
||||
myNotDeprecatedMethodsResolver = new MethodIncompleteSignatureResolver(JavaPsiFacade.getInstance(myProject), myResolveScope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TargetType getTarget() {
|
||||
return myTarget;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiVariable findRelevantStringInContext(@Nullable final String stringParamName) {
|
||||
if (stringParamName == null) {
|
||||
return null;
|
||||
}
|
||||
for (final Map.Entry<String, PsiVariable> e : myStringVars.entrySet()) {
|
||||
if (ChainCompletionContextStringUtil.isSimilar(e.getKey(), stringParamName)) {
|
||||
return e.getValue();
|
||||
@NotNull
|
||||
public List<PsiNamedElement> getContextElements() {
|
||||
return myContextElements;
|
||||
}
|
||||
|
||||
public boolean contains(@Nullable final PsiType type) {
|
||||
if (type == null) return false;
|
||||
final Set<PsiType> types = getContextTypes();
|
||||
if (types.contains(type)) return true;
|
||||
for (PsiType contextType : types) {
|
||||
if (type.isAssignableFrom(contextType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public Set<String> getContainingClassQNames() {
|
||||
return myContainingClassQNames;
|
||||
}
|
||||
|
||||
public Collection<PsiVariable> getVariables(final String typeQName) {
|
||||
return myContextVars.get(typeQName);
|
||||
}
|
||||
|
||||
public Collection<PsiMethod> getContainingClassMethods(final String typeQName) {
|
||||
return myContainingClassGetters.get(typeQName);
|
||||
}
|
||||
|
||||
public Collection<ContextRelevantVariableGetter> getRelevantVariablesGetters(final String typeQName) {
|
||||
return myContextVarsGetters.get(typeQName);
|
||||
}
|
||||
|
||||
public Collection<?> getContextRefElements(final String typeQName) {
|
||||
final Collection<PsiVariable> variables = getVariables(typeQName);
|
||||
final Collection<PsiMethod> containingClassMethods = getContainingClassMethods(typeQName);
|
||||
final Collection<UserDataHolder> refElements = new ArrayList<>(variables.size() + containingClassMethods.size());
|
||||
refElements.addAll(variables);
|
||||
refElements.addAll(containingClassMethods);
|
||||
for (final ContextRelevantVariableGetter contextRelevantVariableGetter : getRelevantVariablesGetters(typeQName)) {
|
||||
refElements.add(contextRelevantVariableGetter.createLookupElement());
|
||||
}
|
||||
return refElements;
|
||||
}
|
||||
|
||||
public boolean contains(@Nullable final String typeQualifierName) {
|
||||
return typeQualifierName != null && contextTypesQNames.getValue().contains(typeQualifierName);
|
||||
}
|
||||
|
||||
public Set<String> getContextTypes() {
|
||||
return contextTypesQNames.getValue();
|
||||
@NotNull
|
||||
public Set<PsiType> getContextTypes() {
|
||||
return myContextElements.stream().map(ChainCompletionContext::getType).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GlobalSearchScope getResolveScope() {
|
||||
return myResolveScope;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiManager getPsiManager() {
|
||||
return myPsiManager;
|
||||
}
|
||||
@@ -152,11 +115,113 @@ public class ChainCompletionContext {
|
||||
return myNotDeprecatedMethodsResolver.get(methodIncompleteSignature);
|
||||
}
|
||||
|
||||
private static <T> HashSet<T> unionToHashSet(final Collection<T>... collections) {
|
||||
final HashSet<T> res = new HashSet<>();
|
||||
for (final Collection<T> set : collections) {
|
||||
res.addAll(set);
|
||||
@Nullable
|
||||
public PsiElement findRelevantStringInContext(String stringParameterName) {
|
||||
String sanitizedTarget = MethodChainsSearchUtil.sanitizedToLowerCase(stringParameterName);
|
||||
return myContextStrings.stream().filter(e -> {
|
||||
String name = e.getName();
|
||||
return name != null && MethodChainsSearchUtil.isSimilar(sanitizedTarget, name);
|
||||
}).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public Collection<PsiElement> getQualifiers(@Nullable PsiClass targetType) {
|
||||
if (targetType == null) return Collections.emptyList();
|
||||
return getQualifiers(JavaPsiFacade.getInstance(myProject).getElementFactory().createType(targetType));
|
||||
}
|
||||
|
||||
public Collection<PsiElement> getQualifiers(@NotNull PsiType targetType) {
|
||||
return myContextElements.stream().filter(e -> {
|
||||
final PsiType elementType = getType(e);
|
||||
return elementType != null && targetType.isAssignableFrom(elementType);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ChainCompletionContext createContext(final @Nullable PsiType variableType,
|
||||
final @Nullable String variableName,
|
||||
final @Nullable PsiElement containingElement) {
|
||||
if (containingElement == null) return null;
|
||||
final TargetType target = TargetType.create(variableType);
|
||||
if (target == null) return null;
|
||||
|
||||
final ContextProcessor processor = new ContextProcessor(null, containingElement.getProject(), containingElement);
|
||||
PsiScopesUtil.treeWalkUp(processor, containingElement, containingElement.getContainingFile());
|
||||
final List<PsiNamedElement> contextElements = processor.getContextElements();
|
||||
final List<PsiNamedElement> contextStrings = processor.getContextStrings();
|
||||
|
||||
return new ChainCompletionContext(target, contextElements, contextStrings, containingElement);
|
||||
}
|
||||
|
||||
private static class ContextProcessor extends BaseScopeProcessor implements ElementClassHint {
|
||||
private final List<PsiNamedElement> myContextElements = new SmartList<>();
|
||||
private final List<PsiNamedElement> myContextStrings = new SmartList<>();
|
||||
private final PsiVariable myCompletionVariable;
|
||||
private final PsiResolveHelper myResolveHelper;
|
||||
private final PsiElement myPlace;
|
||||
|
||||
private ContextProcessor(@Nullable PsiVariable variable,
|
||||
@NotNull Project project,
|
||||
@NotNull PsiElement place) {
|
||||
myCompletionVariable = variable;
|
||||
myResolveHelper = PsiResolveHelper.SERVICE.getInstance(project);
|
||||
myPlace = place;
|
||||
}
|
||||
return res;
|
||||
|
||||
@Override
|
||||
public boolean shouldProcess(DeclarationKind kind) {
|
||||
return kind == DeclarationKind.ENUM_CONST ||
|
||||
kind == DeclarationKind.FIELD ||
|
||||
kind == DeclarationKind.METHOD ||
|
||||
kind == DeclarationKind.VARIABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) {
|
||||
if ((!(element instanceof PsiMethod) || PropertyUtil.isSimplePropertyAccessor((PsiMethod)element)) &&
|
||||
(!(element instanceof PsiMember) || myResolveHelper.isAccessible((PsiMember)element, myPlace, null))) {
|
||||
final PsiType type = getType(element);
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
if (ChainCompletionStringUtil.isPrimitiveOrArrayOfPrimitives(type)) {
|
||||
if (type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
|
||||
myContextStrings.add((PsiNamedElement)element);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
myContextElements.add((PsiNamedElement)element);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getHint(@NotNull Key<T> hintKey) {
|
||||
if (hintKey == ElementClassHint.KEY) {
|
||||
return (T)this;
|
||||
}
|
||||
return super.getHint(hintKey);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<PsiNamedElement> getContextElements() {
|
||||
myContextElements.remove(myCompletionVariable);
|
||||
return myContextElements;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<PsiNamedElement> getContextStrings() {
|
||||
return myContextStrings;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiType getType(PsiElement element) {
|
||||
if (element instanceof PsiVariable) {
|
||||
return ((PsiVariable)element).getType();
|
||||
}
|
||||
if (element instanceof PsiMethod) {
|
||||
return ((PsiMethod)element).getReturnType();
|
||||
}
|
||||
throw new AssertionError(element);
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.context;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
class ChainCompletionContextStringUtil {
|
||||
|
||||
private ChainCompletionContextStringUtil(){}
|
||||
|
||||
private final static int COMMON_PART_MIN_LENGTH = 3;
|
||||
|
||||
public static boolean isSimilar(@NotNull final String varName,
|
||||
@NotNull final String parameterName) {
|
||||
final String sanitizedParamName = sanitizedToLowerCase(parameterName);
|
||||
if (StringUtil.commonPrefix(varName, sanitizedParamName).length() >= COMMON_PART_MIN_LENGTH) {
|
||||
return true;
|
||||
}
|
||||
final String suffix = StringUtil.commonSuffix(varName, sanitizedParamName);
|
||||
return suffix.length() >= COMMON_PART_MIN_LENGTH;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String sanitizedToLowerCase(@NotNull final String name) {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
final char ch = name.charAt(i);
|
||||
if (Character.isLetter(ch)) {
|
||||
result.append(Character.toLowerCase(ch));
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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.context;
|
||||
|
||||
import com.intellij.codeInsight.completion.JavaChainLookupElement;
|
||||
import com.intellij.codeInsight.completion.JavaMethodCallElement;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.GetterLookupSubLookupElement;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.sub.SubLookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.VariableLookupItem;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiVariable;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich <dmitry.batkovich@jetbrains.com>
|
||||
*/
|
||||
public class ContextRelevantVariableGetter {
|
||||
private final PsiVariable myVariable;
|
||||
private final PsiMethod myMethod;
|
||||
|
||||
public ContextRelevantVariableGetter(final PsiVariable variable, final PsiMethod method) {
|
||||
myVariable = variable;
|
||||
myMethod = method;
|
||||
}
|
||||
|
||||
public SubLookupElement createSubLookupElement() {
|
||||
return new GetterLookupSubLookupElement(myVariable.getName(), myMethod.getName());
|
||||
}
|
||||
|
||||
public LookupElement createLookupElement() {
|
||||
return new JavaChainLookupElement(new VariableLookupItem(myVariable), new JavaMethodCallElement(myMethod));
|
||||
}
|
||||
}
|
||||
-257
@@ -1,257 +0,0 @@
|
||||
/*
|
||||
* 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.context;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public final class ContextUtil {
|
||||
@Nullable
|
||||
public static ChainCompletionContext createContext(final @Nullable PsiType variableType,
|
||||
final @Nullable String variableName,
|
||||
final @Nullable PsiElement containingElement) {
|
||||
if (variableType == null || containingElement == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(containingElement, PsiMethod.class);
|
||||
if (method == null) {
|
||||
return null;
|
||||
}
|
||||
final PsiClass aClass = method.getContainingClass();
|
||||
if (aClass == null) {
|
||||
return null;
|
||||
}
|
||||
final Set<String> containingClassQNames = resolveSupersNamesRecursively(aClass);
|
||||
|
||||
final List<PsiVariable> contextVars = new SmartList<>();
|
||||
for (final PsiField field : aClass.getFields()) {
|
||||
final PsiClass containingClass = field.getContainingClass();
|
||||
if (containingClass != null) {
|
||||
if ((field.hasModifierProperty(PsiModifier.PUBLIC) ||
|
||||
field.hasModifierProperty(PsiModifier.PROTECTED) ||
|
||||
((field.hasModifierProperty(PsiModifier.PRIVATE) || field.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) &&
|
||||
aClass.isEquivalentTo(containingClass))) && !field.getName().equals(variableName)) {
|
||||
contextVars.add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.addAll(contextVars, method.getParameterList().getParameters());
|
||||
|
||||
final PsiCodeBlock methodBody = method.getBody();
|
||||
assert methodBody != null;
|
||||
boolean processMethodTail = false;
|
||||
final List<PsiElement> afterElements = new ArrayList<>();
|
||||
for (final PsiElement element : methodBody.getChildren()) {
|
||||
if (element.isEquivalentTo(containingElement)) {
|
||||
if (variableType instanceof PsiClassType) {
|
||||
processMethodTail = true;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (element instanceof PsiDeclarationStatement) {
|
||||
if (processMethodTail) {
|
||||
afterElements.add(element);
|
||||
}
|
||||
else {
|
||||
for (final PsiElement declaredElement : ((PsiDeclarationStatement)element).getDeclaredElements()) {
|
||||
if (declaredElement instanceof PsiLocalVariable &&
|
||||
(variableName == null || !variableName.equals(((PsiLocalVariable)declaredElement).getName()))) {
|
||||
contextVars.add((PsiVariable)declaredElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Set<String> excludedQNames = processMethodTail
|
||||
? generateExcludedQNames(afterElements, ((PsiClassType)variableType).resolve(), variableName,
|
||||
contextVars)
|
||||
: Collections.<String>emptySet();
|
||||
|
||||
final List<PsiMethod> contextMethods = new ArrayList<>();
|
||||
for (final PsiMethod psiMethod : aClass.getMethods()) {
|
||||
if ((psiMethod.hasModifierProperty(PsiModifier.PROTECTED) || psiMethod.hasModifierProperty(PsiModifier.PRIVATE)) &&
|
||||
psiMethod.getParameterList().getParametersCount() == 0) {
|
||||
contextMethods.add(psiMethod);
|
||||
}
|
||||
}
|
||||
|
||||
return create(target, contextVars, contextMethods, containingClassQNames, containingElement.getProject(),
|
||||
containingElement.getResolveScope(), excludedQNames);
|
||||
}
|
||||
|
||||
private static Set<String> generateExcludedQNames(final List<PsiElement> tailElements,
|
||||
final @Nullable PsiClass psiClass,
|
||||
final @Nullable String varName,
|
||||
final List<PsiVariable> contextVars) {
|
||||
if (psiClass == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
final String classQName = psiClass.getQualifiedName();
|
||||
if (classQName == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
final Set<String> excludedQNames = new HashSet<>();
|
||||
if (!tailElements.isEmpty()) {
|
||||
final Set<String> contextVarTypes = new HashSet<>();
|
||||
final Map<String, PsiVariable> contextVarNamesToVar = new HashMap<>();
|
||||
for (final PsiVariable var : contextVars) {
|
||||
contextVarTypes.add(var.getType().getCanonicalText());
|
||||
contextVarNamesToVar.put(var.getName(), var);
|
||||
}
|
||||
for (final PsiElement element : tailElements) {
|
||||
final Collection<PsiMethodCallExpression> methodCallExpressions =
|
||||
PsiTreeUtil.findChildrenOfType(element, PsiMethodCallExpression.class);
|
||||
for (final PsiMethodCallExpression methodCallExpression : methodCallExpressions) {
|
||||
final PsiExpressionList args = methodCallExpression.getArgumentList();
|
||||
final PsiMethod resolvedMethod = methodCallExpression.resolveMethod();
|
||||
if (resolvedMethod != null) {
|
||||
final PsiType returnType = resolvedMethod.getReturnType();
|
||||
if (returnType != null) {
|
||||
final String returnTypeAsString = returnType.getCanonicalText();
|
||||
for (final PsiExpression expression : args.getExpressions()) {
|
||||
final String qVarName = expression.getText();
|
||||
if (qVarName != null) {
|
||||
if (contextVarNamesToVar.containsKey(qVarName) || qVarName.equals(varName)) {
|
||||
excludedQNames.add(returnTypeAsString);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!contextVarTypes.contains(returnTypeAsString)) {
|
||||
excludedQNames.add(returnTypeAsString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return excludedQNames;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ChainCompletionContext create(final TargetType target,
|
||||
final List<PsiVariable> contextVars,
|
||||
final List<PsiMethod> contextMethods,
|
||||
final Set<String> containingClassQNames,
|
||||
final Project project,
|
||||
final GlobalSearchScope resolveScope,
|
||||
final Set<String> excludedQNames) {
|
||||
final MultiMap<String, PsiVariable> classQNameToVariable = new MultiMap<>();
|
||||
final MultiMap<String, PsiMethod> containingClassGetters = new MultiMap<>();
|
||||
final MultiMap<String, ContextRelevantVariableGetter> contextVarsGetters = new MultiMap<>();
|
||||
final Map<String, PsiVariable> stringVars = new HashMap<>();
|
||||
|
||||
for (final PsiMethod method : contextMethods) {
|
||||
final PsiType returnType = method.getReturnType();
|
||||
if (returnType != null) {
|
||||
final String returnTypeQName = returnType.getCanonicalText();
|
||||
containingClassGetters.putValue(returnTypeQName, method);
|
||||
}
|
||||
}
|
||||
|
||||
for (final PsiVariable var : contextVars) {
|
||||
final PsiType type = var.getType();
|
||||
final Set<String> classQNames = new HashSet<>();
|
||||
if (type instanceof PsiClassType) {
|
||||
if (JAVA_LANG_STRING_SHORT_NAME.equals(((PsiClassType)type).getClassName())) {
|
||||
final String varName = var.getName();
|
||||
if (varName != null) {
|
||||
stringVars.put(ChainCompletionContextStringUtil.sanitizedToLowerCase(varName), var);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
final PsiClass aClass = ((PsiClassType)type).resolve();
|
||||
if (aClass != null) {
|
||||
final String classQName = type.getCanonicalText();
|
||||
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 PsiType returnType = method.getReturnType();
|
||||
if (returnType != null) {
|
||||
final String getterReturnTypeQName = returnType.getCanonicalText();
|
||||
contextVarsGetters.putValue(getterReturnTypeQName, new ContextRelevantVariableGetter(var, method));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
final String classQName = type.getCanonicalText();
|
||||
classQNames.add(classQName);
|
||||
}
|
||||
for (final String qName : classQNames) {
|
||||
classQNameToVariable.putValue(qName, var);
|
||||
}
|
||||
}
|
||||
return new ChainCompletionContext(target, containingClassQNames, classQNameToVariable, containingClassGetters,
|
||||
contextVarsGetters, stringVars, excludedQNames, project, resolveScope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<String> resolveSupersNamesRecursively(@Nullable final PsiClass psiClass) {
|
||||
final Set<String> result = new HashSet<>();
|
||||
if (psiClass != null) {
|
||||
for (final PsiClass superClass : psiClass.getSupers()) {
|
||||
final String qualifiedName = superClass.getQualifiedName();
|
||||
if (!CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName)) {
|
||||
if (qualifiedName != null) {
|
||||
result.add(qualifiedName);
|
||||
}
|
||||
result.addAll(resolveSupersNamesRecursively(superClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private final static String JAVA_LANG_STRING_SHORT_NAME = StringUtil.getShortName(CommonClassNames.JAVA_LANG_STRING);
|
||||
}
|
||||
+13
-2
@@ -51,7 +51,18 @@ public class TargetType {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TargetType create(final PsiArrayType arrayType) {
|
||||
public static TargetType create(final PsiType type) {
|
||||
if (type instanceof PsiArrayType) {
|
||||
return create((PsiArrayType)type);
|
||||
}
|
||||
else if (type instanceof PsiClassType) {
|
||||
return create((PsiClassType)type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TargetType create(final PsiArrayType arrayType) {
|
||||
PsiType currentComponentType = arrayType.getComponentType();
|
||||
while (currentComponentType instanceof PsiArrayType) {
|
||||
currentComponentType = ((PsiArrayType)currentComponentType).getComponentType();
|
||||
@@ -64,7 +75,7 @@ public class TargetType {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TargetType create(final PsiClassType classType) {
|
||||
private static TargetType create(final PsiClassType classType) {
|
||||
final PsiClassType.ClassResolveResult resolvedGenerics = classType.resolveGenerics();
|
||||
final PsiClass resolvedClass = resolvedGenerics.getElement();
|
||||
if (resolvedClass == null) {
|
||||
|
||||
+2
-3
@@ -18,7 +18,6 @@ package com.intellij.codeInsight.completion;
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.ChainRelevance;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.MethodsChainsCompletionContributor;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.ChainCompletionMethodCallLookupElement;
|
||||
import com.intellij.compiler.classFilesIndex.chainsSearch.completion.lookup.WeightableChainLookupElement;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
@@ -236,7 +235,7 @@ public class MethodChainsCompletionTest extends AbstractCompilerAwareTest {
|
||||
.setValue(ChainCompletionMethodCallLookupElement.PROP_METHODS_CHAIN_COMPLETION_AUTO_COMPLETION, String.valueOf(true));
|
||||
compileAndIndexData(TEST_INDEX_FILE_NAME);
|
||||
myFixture.configureByFiles(getBeforeCompletionFilePath());
|
||||
myFixture.complete(CompletionType.BASIC, MethodsChainsCompletionContributor.INVOCATIONS_THRESHOLD);
|
||||
myFixture.complete(CompletionType.BASIC);
|
||||
PropertiesComponent.getInstance(getProject())
|
||||
.setValue(ChainCompletionMethodCallLookupElement.PROP_METHODS_CHAIN_COMPLETION_AUTO_COMPLETION, String.valueOf(false));
|
||||
myFixture.checkResultByFile(getAfterCompletionFilePath());
|
||||
@@ -257,7 +256,7 @@ public class MethodChainsCompletionTest extends AbstractCompilerAwareTest {
|
||||
private LookupElement[] runCompletion() {
|
||||
myFixture.configureByFiles(getTestCompletionFilePath());
|
||||
final LookupElement[] lookupElements =
|
||||
myFixture.complete(CompletionType.BASIC, MethodsChainsCompletionContributor.INVOCATIONS_THRESHOLD);
|
||||
myFixture.complete(CompletionType.BASIC);
|
||||
return lookupElements == null ? LookupElement.EMPTY_ARRAY : lookupElements;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user