mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-05 01:50:56 +07:00
relevant method chain completion: chains ended with casts are valid too
This commit is contained in:
@@ -30,7 +30,6 @@ import com.intellij.util.indexing.StorageException;
|
||||
import com.intellij.util.indexing.ValueContainer;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.backwardRefs.CompilerBackwardReferenceIndex;
|
||||
@@ -179,22 +178,20 @@ class CompilerReferenceReader {
|
||||
return myIndex;
|
||||
}
|
||||
|
||||
TObjectIntHashMap<LightRef> getTypeCasts(@NotNull LightRef.LightClassHierarchyElementDef castType, @NotNull TIntHashSet fileIds) throws StorageException {
|
||||
TObjectIntHashMap<LightRef> typeCastStats = new TObjectIntHashMap<>();
|
||||
@NotNull
|
||||
OccurrenceCounter<LightRef> getTypeCastOperands(@NotNull LightRef.LightClassHierarchyElementDef castType, @Nullable TIntHashSet fileIds) throws StorageException {
|
||||
OccurrenceCounter<LightRef> result = new OccurrenceCounter<>();
|
||||
myIndex.get(CompilerIndices.BACK_CAST).getData(castType).forEach(new ValueContainer.ContainerAction<Collection<LightRef>>() {
|
||||
@Override
|
||||
public boolean perform(int id, Collection<LightRef> values) {
|
||||
if (!fileIds.contains(id)) return true;
|
||||
if (fileIds != null && !fileIds.contains(id)) return true;
|
||||
for (LightRef ref : values) {
|
||||
if (!typeCastStats.adjustValue(ref, 1)) {
|
||||
typeCastStats.put(ref, 1);
|
||||
}
|
||||
result.add(ref);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return typeCastStats;
|
||||
return result;
|
||||
}
|
||||
|
||||
static boolean exists(Project project) {
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
package com.intellij.compiler.backwardRefs;
|
||||
|
||||
import com.intellij.compiler.CompilerReferenceService;
|
||||
import com.intellij.compiler.chainsSearch.MethodRefAndOccurrences;
|
||||
import com.intellij.compiler.chainsSearch.ChainOpAndOccurrences;
|
||||
import com.intellij.compiler.chainsSearch.MethodCall;
|
||||
import com.intellij.compiler.chainsSearch.TypeCast;
|
||||
import com.intellij.compiler.chainsSearch.context.ChainCompletionContext;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -35,9 +37,13 @@ public abstract class CompilerReferenceServiceEx extends CompilerReferenceServic
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract SortedSet<MethodRefAndOccurrences> findMethodReferenceOccurrences(@NotNull String rawReturnType,
|
||||
@SignatureData.IteratorKind byte iteratorKind,
|
||||
@NotNull ChainCompletionContext context)
|
||||
public abstract SortedSet<ChainOpAndOccurrences<MethodCall>> findMethodReferenceOccurrences(@NotNull String rawReturnType,
|
||||
@SignatureData.IteratorKind byte iteratorKind,
|
||||
@NotNull ChainCompletionContext context)
|
||||
throws ReferenceIndexUnavailableException;
|
||||
|
||||
@Nullable
|
||||
public abstract ChainOpAndOccurrences<TypeCast> getMostUsedTypeCast(@NotNull String operandQName)
|
||||
throws ReferenceIndexUnavailableException;
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -21,7 +21,8 @@ import com.intellij.compiler.backwardRefs.view.CompilerReferenceHierarchyTestInf
|
||||
import com.intellij.compiler.backwardRefs.view.DirtyScopeTestInfo;
|
||||
import com.intellij.compiler.chainsSearch.ChainSearchMagicConstants;
|
||||
import com.intellij.compiler.chainsSearch.MethodCall;
|
||||
import com.intellij.compiler.chainsSearch.MethodRefAndOccurrences;
|
||||
import com.intellij.compiler.chainsSearch.ChainOpAndOccurrences;
|
||||
import com.intellij.compiler.chainsSearch.TypeCast;
|
||||
import com.intellij.compiler.chainsSearch.context.ChainCompletionContext;
|
||||
import com.intellij.compiler.server.BuildManager;
|
||||
import com.intellij.compiler.server.BuildManagerListener;
|
||||
@@ -60,8 +61,6 @@ import com.intellij.util.io.PersistentEnumeratorBase;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import gnu.trove.TObjectIntProcedure;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -223,9 +222,9 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public SortedSet<MethodRefAndOccurrences> findMethodReferenceOccurrences(@NotNull String rawReturnType,
|
||||
@SignatureData.IteratorKind byte iteratorKind,
|
||||
@NotNull ChainCompletionContext context) {
|
||||
public SortedSet<ChainOpAndOccurrences<MethodCall>> findMethodReferenceOccurrences(@NotNull String rawReturnType,
|
||||
@SignatureData.IteratorKind byte iteratorKind,
|
||||
@NotNull ChainCompletionContext context) {
|
||||
try {
|
||||
myReadDataLock.lock();
|
||||
try {
|
||||
@@ -244,15 +243,15 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp
|
||||
.distinct()
|
||||
.map(r -> {
|
||||
int count = myReader.getOccurrenceCount(r);
|
||||
return count <= 1 ? null : new MethodRefAndOccurrences(
|
||||
return count <= 1 ? null : new ChainOpAndOccurrences<>(
|
||||
new MethodCall((LightRef.JavaLightMethodRef)r, sd, context),
|
||||
count);
|
||||
}))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.groupingBy(x -> x.getSignature(), Collectors.summarizingInt(x -> x.getOccurrenceCount())))
|
||||
.collect(Collectors.groupingBy(x -> x.getOperation(), Collectors.summarizingInt(x -> x.getOccurrenceCount())))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(e -> new MethodRefAndOccurrences(e.getKey(), (int)e.getValue().getSum()))
|
||||
.map(e -> new ChainOpAndOccurrences<>(e.getKey(), (int)e.getValue().getSum()))
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
finally {
|
||||
@@ -265,6 +264,31 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ChainOpAndOccurrences<TypeCast> getMostUsedTypeCast(@NotNull String operandQName)
|
||||
throws ReferenceIndexUnavailableException {
|
||||
try {
|
||||
myReadDataLock.lock();
|
||||
try {
|
||||
if (myReader == null) throw new ReferenceIndexUnavailableException();
|
||||
int nameId = getNameId(operandQName);
|
||||
if (nameId == 0) return null;
|
||||
LightRef.JavaLightClassRef target = new LightRef.JavaLightClassRef(nameId);
|
||||
OccurrenceCounter<LightRef> typeCasts = myReader.getTypeCastOperands(target, null);
|
||||
LightRef bestCast = typeCasts.getBest();
|
||||
if (bestCast == null) return null;
|
||||
return new ChainOpAndOccurrences<>(new TypeCast((LightRef.LightClassHierarchyElementDef)bestCast, target, this), typeCasts.getBestOccurrences());
|
||||
}
|
||||
finally {
|
||||
myReadDataLock.unlock();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
onException(e, "best type cast search");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* finds one best candidate to do a cast type before given method call (eg.: <code>((B) a).someMethod()</code>). Follows given formula:
|
||||
*
|
||||
@@ -282,25 +306,11 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceServiceEx imp
|
||||
|
||||
LightRef.LightClassHierarchyElementDef owner = method.getOwner();
|
||||
|
||||
TObjectIntHashMap<LightRef> typeCasts = myReader.getTypeCasts(owner, ids);
|
||||
|
||||
LightRef[] best = {null};
|
||||
int[] bestFileCount = {0};
|
||||
|
||||
typeCasts.forEachEntry(new TObjectIntProcedure<LightRef>() {
|
||||
@Override
|
||||
public boolean execute(LightRef operandType, int matchedFileCount) {
|
||||
if (ids.size() > probabilityThreshold * (ids.size() - matchedFileCount)) {
|
||||
if (best[0] == null || bestFileCount[0] < matchedFileCount) {
|
||||
best[0] = operandType;
|
||||
bestFileCount[0] = matchedFileCount;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return (LightRef.LightClassHierarchyElementDef)best[0];
|
||||
OccurrenceCounter<LightRef> bestTypeCast = myReader.getTypeCastOperands(owner, ids);
|
||||
LightRef best = bestTypeCast.getBest();
|
||||
return best != null && ids.size() > probabilityThreshold * (ids.size() - bestTypeCast.getBestOccurrences())
|
||||
? (LightRef.LightClassHierarchyElementDef)best
|
||||
: null;
|
||||
}
|
||||
finally {
|
||||
myReadDataLock.unlock();
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.backwardRefs;
|
||||
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class OccurrenceCounter<T> {
|
||||
private final TObjectIntHashMap<T> myOccurrenceMap;
|
||||
private T myBest;
|
||||
private int myBestOccurrences;
|
||||
|
||||
OccurrenceCounter() {
|
||||
myOccurrenceMap = new TObjectIntHashMap<>();
|
||||
}
|
||||
|
||||
void add(@NotNull T element) {
|
||||
int prevOccurrences = myOccurrenceMap.get(element);
|
||||
if (prevOccurrences == 0) {
|
||||
myOccurrenceMap.put(element, 1);
|
||||
} else {
|
||||
myOccurrenceMap.adjustValue(element, 1);
|
||||
}
|
||||
|
||||
if (myBest == null) {
|
||||
myBestOccurrences = 1;
|
||||
myBest = element;
|
||||
} else if (myBest.equals(element)) {
|
||||
myBestOccurrences++;
|
||||
} else {
|
||||
myBestOccurrences = prevOccurrences + 1;
|
||||
myBest = element;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
T getBest() {
|
||||
return myBest;
|
||||
}
|
||||
|
||||
int getBestOccurrences() {
|
||||
return myBestOccurrences;
|
||||
}
|
||||
}
|
||||
@@ -17,17 +17,17 @@ package com.intellij.compiler.chainsSearch;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MethodRefAndOccurrences implements Comparable<MethodRefAndOccurrences> {
|
||||
private final MethodCall mySignature;
|
||||
public class ChainOpAndOccurrences<T extends RefChainOperation> implements Comparable<ChainOpAndOccurrences> {
|
||||
private final T myOp;
|
||||
private final int myOccurrences;
|
||||
|
||||
public MethodRefAndOccurrences(final MethodCall signature, final int occurrences) {
|
||||
mySignature = signature;
|
||||
public ChainOpAndOccurrences(final T op, final int occurrences) {
|
||||
myOp = op;
|
||||
myOccurrences = occurrences;
|
||||
}
|
||||
|
||||
public MethodCall getSignature() {
|
||||
return mySignature;
|
||||
public T getOperation() {
|
||||
return myOp;
|
||||
}
|
||||
|
||||
public int getOccurrenceCount() {
|
||||
@@ -35,16 +35,16 @@ public class MethodRefAndOccurrences implements Comparable<MethodRefAndOccurrenc
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull final MethodRefAndOccurrences that) {
|
||||
public int compareTo(@NotNull final ChainOpAndOccurrences that) {
|
||||
final int sub = -getOccurrenceCount() + that.getOccurrenceCount();
|
||||
if (sub != 0) {
|
||||
return sub;
|
||||
}
|
||||
return mySignature.hashCode() - that.mySignature.hashCode();
|
||||
return myOp.hashCode() - that.myOp.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getOccurrenceCount() + " for " + mySignature;
|
||||
return getOccurrenceCount() + " for " + myOp;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ public interface ChainOperation {
|
||||
myCastClass = castClass;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiClass getCastClass() {
|
||||
return myCastClass;
|
||||
}
|
||||
|
||||
@@ -41,12 +41,20 @@ public class ChainSearcher {
|
||||
private static SearchInitializer createInitializer(ChainSearchTarget target,
|
||||
CompilerReferenceServiceEx referenceServiceEx,
|
||||
ChainCompletionContext context) {
|
||||
SortedSet<MethodRefAndOccurrences> methods = Collections.emptySortedSet();
|
||||
SortedSet<ChainOpAndOccurrences<? extends RefChainOperation>> operations = new TreeSet<>();
|
||||
for (byte kind : target.getArrayKind()) {
|
||||
SortedSet<MethodRefAndOccurrences> currentMethods = referenceServiceEx.findMethodReferenceOccurrences(target.getClassQName(), kind, context);
|
||||
methods = methods == null ? currentMethods : unionSortedSet(currentMethods, methods);
|
||||
SortedSet<ChainOpAndOccurrences<MethodCall>> methods = referenceServiceEx.findMethodReferenceOccurrences(target.getClassQName(), kind, context);
|
||||
operations.addAll(methods);
|
||||
}
|
||||
return new SearchInitializer(methods, context);
|
||||
|
||||
if (operations.isEmpty()) {
|
||||
ChainOpAndOccurrences<TypeCast> typeCast = referenceServiceEx.getMostUsedTypeCast(target.getClassQName());
|
||||
if (typeCast != null) {
|
||||
operations.add(typeCast);
|
||||
}
|
||||
}
|
||||
|
||||
return new SearchInitializer(operations, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -68,22 +76,22 @@ public class ChainSearcher {
|
||||
|
||||
// otherwise try to find chain continuation
|
||||
boolean updated = false;
|
||||
SortedSet<MethodRefAndOccurrences> candidates = referenceServiceEx.findMethodReferenceOccurrences(head.getQualifierRawName(), SignatureData.ZERO_DIM, context);
|
||||
SortedSet<ChainOpAndOccurrences<MethodCall>> candidates = referenceServiceEx.findMethodReferenceOccurrences(head.getQualifierRawName(), SignatureData.ZERO_DIM, context);
|
||||
LightRef ref = head.getLightRef();
|
||||
for (MethodRefAndOccurrences candidate : candidates) {
|
||||
for (ChainOpAndOccurrences<MethodCall> candidate : candidates) {
|
||||
if (candidate.getOccurrenceCount() * ChainSearchMagicConstants.FILTER_RATIO < currentChain.getChainWeight()) {
|
||||
break;
|
||||
}
|
||||
MethodCall sign = candidate.getSignature();
|
||||
MethodCall sign = candidate.getOperation();
|
||||
if ((sign.isStatic() || !sign.getQualifierRawName().equals(context.getTarget().getClassQName())) &&
|
||||
(!(ref instanceof LightRef.JavaLightMethodRef) ||
|
||||
referenceServiceEx.mayHappen(candidate.getSignature().getLightRef(), ref, ChainSearchMagicConstants.METHOD_PROBABILITY_THRESHOLD))) {
|
||||
referenceServiceEx.mayHappen(candidate.getOperation().getLightRef(), ref, ChainSearchMagicConstants.METHOD_PROBABILITY_THRESHOLD))) {
|
||||
|
||||
OperationChain
|
||||
continuation = currentChain.continuationWithMethod(candidate.getSignature(), candidate.getOccurrenceCount(), context);
|
||||
continuation = currentChain.continuationWithMethod(candidate.getOperation(), candidate.getOccurrenceCount(), context);
|
||||
if (continuation != null) {
|
||||
boolean stopChain =
|
||||
candidate.getSignature().isStatic() || context.hasQualifier(context.resolvePsiClass(candidate.getSignature().getQualifierDef()));
|
||||
candidate.getOperation().isStatic() || context.hasQualifier(context.resolvePsiClass(candidate.getOperation().getQualifierDef()));
|
||||
if (stopChain) {
|
||||
addChainIfNotPresent(continuation, result);
|
||||
}
|
||||
@@ -126,7 +134,7 @@ public class ChainSearcher {
|
||||
List<OperationChain> result,
|
||||
ChainCompletionContext context,
|
||||
CompilerReferenceServiceEx referenceServiceEx) {
|
||||
RefChainOperation signature = currentChain.getHeadMethodCall();
|
||||
RefChainOperation signature = currentChain.getHead();
|
||||
// type cast + introduced qualifier: it's too complex chain
|
||||
if (currentChain.hasCast()) return;
|
||||
if (!context.getTarget().getClassQName().equals(signature.getQualifierRawName())) {
|
||||
@@ -148,6 +156,7 @@ public class ChainSearcher {
|
||||
private static boolean addChainIfTerminal(OperationChain currentChain, List<OperationChain> result, int pathMaximalLength,
|
||||
ChainCompletionContext context) {
|
||||
RefChainOperation signature = currentChain.getHeadMethodCall();
|
||||
if (signature == null) return false;
|
||||
RefChainOperation head = currentChain.getHead();
|
||||
if (((MethodCall)signature).isStatic() ||
|
||||
context.hasQualifier(context.resolvePsiClass(head.getQualifierDef())) ||
|
||||
|
||||
@@ -40,25 +40,35 @@ public class OperationChain {
|
||||
private final PsiClass myQualifierClass;
|
||||
|
||||
@Nullable
|
||||
public static OperationChain create(@NotNull MethodCall signature,
|
||||
public static OperationChain create(@NotNull RefChainOperation operation,
|
||||
int weight,
|
||||
@NotNull ChainCompletionContext context) {
|
||||
PsiClass qualifier = context.resolvePsiClass(signature.getQualifierDef());
|
||||
if (qualifier == null || (!signature.isStatic() && InheritanceUtil.isInheritorOrSelf(context.getTarget().getTargetClass(), qualifier, true))) {
|
||||
return null;
|
||||
if (operation instanceof MethodCall) {
|
||||
MethodCall signature = (MethodCall) operation;
|
||||
PsiClass qualifier = context.resolvePsiClass(signature.getQualifierDef());
|
||||
if (qualifier == null || (!signature.isStatic() && InheritanceUtil.isInheritorOrSelf(context.getTarget().getTargetClass(), qualifier, true))) {
|
||||
return null;
|
||||
}
|
||||
PsiMethod[] methods = context.resolve(signature);
|
||||
if (methods.length == 0) return null;
|
||||
Set<PsiClass> classes = Arrays.stream(methods)
|
||||
.flatMap(m -> Arrays.stream(m.getParameterList().getParameters()))
|
||||
.map(p -> PsiUtil.resolveClassInType(p.getType()))
|
||||
.collect(Collectors.toSet());
|
||||
PsiClass contextClass = context.getTarget().getTargetClass();
|
||||
if (classes.contains(contextClass)) {
|
||||
return null;
|
||||
}
|
||||
classes.add(contextClass);
|
||||
return new OperationChain(qualifier, new ChainOperation[] {new ChainOperation.MethodCall(methods)}, signature, signature, weight);
|
||||
}
|
||||
PsiMethod[] methods = context.resolve(signature);
|
||||
if (methods.length == 0) return null;
|
||||
Set<PsiClass> classes = Arrays.stream(methods)
|
||||
.flatMap(m -> Arrays.stream(m.getParameterList().getParameters()))
|
||||
.map(p -> PsiUtil.resolveClassInType(p.getType()))
|
||||
.collect(Collectors.toSet());
|
||||
PsiClass contextClass = context.getTarget().getTargetClass();
|
||||
if (classes.contains(contextClass)) {
|
||||
return null;
|
||||
else {
|
||||
TypeCast cast = (TypeCast)operation;
|
||||
PsiClass operand = context.resolvePsiClass(cast.getLightRef());
|
||||
PsiClass castType = context.resolvePsiClass(cast.getCastTypeRef());
|
||||
if (operand == null || castType == null) return null;
|
||||
return new OperationChain(operand, new ChainOperation[] {new ChainOperation.TypeCast(operand, castType)}, cast, null, weight);
|
||||
}
|
||||
classes.add(contextClass);
|
||||
return new OperationChain(qualifier, new ChainOperation[] {new ChainOperation.MethodCall(methods)}, signature, signature, weight);
|
||||
}
|
||||
|
||||
private OperationChain(@NotNull PsiClass qualifierClass,
|
||||
@@ -77,7 +87,7 @@ public class OperationChain {
|
||||
return Arrays.stream(myReverseOperations).anyMatch(op -> op instanceof ChainOperation.TypeCast);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nullable
|
||||
public MethodCall getHeadMethodCall() {
|
||||
return myHeadMethodCall;
|
||||
}
|
||||
@@ -118,20 +128,18 @@ public class OperationChain {
|
||||
ChainOperation[] newReverseOperations = new ChainOperation[length() + 1];
|
||||
System.arraycopy(myReverseOperations, 0, newReverseOperations, 0, myReverseOperations.length);
|
||||
newReverseOperations[length()] = head.getPath()[0];
|
||||
return new OperationChain(head.getQualifierClass(), newReverseOperations, head.getHead(), signature, Math.min(weight, getChainWeight()));
|
||||
return new OperationChain(head.getQualifierClass(), newReverseOperations, head.getHead() , signature, Math.min(weight, getChainWeight()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
OperationChain continuationWithCast(@NotNull TypeCast cast,
|
||||
@NotNull ChainCompletionContext context) {
|
||||
PsiClass operand = context.resolvePsiClass(cast.getLightRef());
|
||||
PsiClass castType = context.resolvePsiClass(cast.getCastTypeRef());
|
||||
if (operand == null || castType == null) return null;
|
||||
|
||||
OperationChain head = create(cast, 0, context);
|
||||
if (head == null) return null;
|
||||
ChainOperation[] newReverseOperations = new ChainOperation[length() + 1];
|
||||
System.arraycopy(myReverseOperations, 0, newReverseOperations, 0, myReverseOperations.length);
|
||||
newReverseOperations[length()] = new ChainOperation.TypeCast(operand, castType);
|
||||
return new OperationChain(operand, newReverseOperations, cast, myHeadMethodCall, getChainWeight());
|
||||
newReverseOperations[length()] = head.getPath()[0];
|
||||
return new OperationChain(head.getQualifierClass(), newReverseOperations, head.getHead(), myHeadMethodCall, getChainWeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,9 +22,9 @@ import java.util.*;
|
||||
public class SearchInitializer {
|
||||
private final ChainCompletionContext myContext;
|
||||
private final LinkedList<OperationChain> myQueue;
|
||||
private final LinkedHashMap<MethodCall, OperationChain> myChains;
|
||||
private final LinkedHashMap<RefChainOperation, OperationChain> myChains;
|
||||
|
||||
public SearchInitializer(SortedSet<MethodRefAndOccurrences> indexValues,
|
||||
public SearchInitializer(SortedSet<ChainOpAndOccurrences<? extends RefChainOperation>> indexValues,
|
||||
ChainCompletionContext context) {
|
||||
myContext = context;
|
||||
int size = indexValues.size();
|
||||
@@ -33,7 +33,7 @@ public class SearchInitializer {
|
||||
myQueue = new LinkedList<>();
|
||||
myChains = new LinkedHashMap<>(chains.size());
|
||||
for (OperationChain chain : chains) {
|
||||
MethodCall signature = (MethodCall)chain.getHead();
|
||||
RefChainOperation signature = chain.getHead();
|
||||
myQueue.add(chain);
|
||||
myChains.put(signature, chain);
|
||||
}
|
||||
@@ -43,15 +43,15 @@ public class SearchInitializer {
|
||||
return myQueue;
|
||||
}
|
||||
|
||||
public LinkedHashMap<MethodCall, OperationChain> getChains() {
|
||||
public LinkedHashMap<RefChainOperation, OperationChain> getChains() {
|
||||
return myChains;
|
||||
}
|
||||
|
||||
private void populateFrequentlyUsedMethod(SortedSet<MethodRefAndOccurrences> signatures,
|
||||
private void populateFrequentlyUsedMethod(SortedSet<? extends ChainOpAndOccurrences> operations,
|
||||
List<OperationChain> chains) {
|
||||
int bestOccurrences = -1;
|
||||
for (MethodRefAndOccurrences indexValue : signatures) {
|
||||
OperationChain operationChain = OperationChain.create(indexValue.getSignature(), indexValue.getOccurrenceCount(), myContext);
|
||||
for (ChainOpAndOccurrences indexValue : operations) {
|
||||
OperationChain operationChain = OperationChain.create(indexValue.getOperation(), indexValue.getOccurrenceCount(), myContext);
|
||||
if (operationChain != null) {
|
||||
chains.add(operationChain);
|
||||
int occurrences = indexValue.getOccurrenceCount();
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
interface InspectionManager {
|
||||
static InspectionManager getInstance() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
interface InspectionManagerEx extends InspectionManager {
|
||||
}
|
||||
|
||||
class Test {
|
||||
void m() {
|
||||
InspectionManagerEx m1 = <caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
interface InspectionManager {
|
||||
static InspectionManager getInstance() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
interface InspectionManagerEx extends InspectionManager {
|
||||
}
|
||||
|
||||
class Test {
|
||||
void m() {
|
||||
InspectionManagerEx m1 = (InspectionManagerEx)InspectionManager.getInstance();
|
||||
InspectionManagerEx m2 = (InspectionManagerEx)InspectionManager.getInstance();
|
||||
InspectionManagerEx m3 = (InspectionManagerEx)InspectionManager.getInstance();
|
||||
InspectionManagerEx m4 = (InspectionManagerEx)InspectionManager.getInstance();
|
||||
InspectionManagerEx m5 = (InspectionManagerEx)InspectionManager.getInstance();
|
||||
InspectionManagerEx m6 = (InspectionManagerEx)InspectionManager.getInstance();
|
||||
InspectionManagerEx m7 = (InspectionManagerEx)InspectionManager.getInstance();
|
||||
InspectionManagerEx m8 = (InspectionManagerEx)InspectionManager.getInstance();
|
||||
InspectionManagerEx m9 = (InspectionManagerEx)InspectionManager.getInstance();
|
||||
InspectionManagerEx m0 = (InspectionManagerEx)InspectionManager.getInstance();
|
||||
}
|
||||
}
|
||||
@@ -257,6 +257,11 @@ public class MethodChainsCompletionTest extends AbstractCompilerAwareTest {
|
||||
assertEquals("(InspectionManagerEx)getInstance().createContext", element.toString());
|
||||
}
|
||||
|
||||
public void testChainEndedWithCast() {
|
||||
JavaRelevantChainLookupElement element = assertOneElement(doCompletion());
|
||||
assertEquals("(InspectionManagerEx)getInstance", element.toString());
|
||||
}
|
||||
|
||||
public void assertAdvisorLookupElementEquals(String lookupText,
|
||||
int unreachableParametersCount,
|
||||
int chainSize,
|
||||
|
||||
Reference in New Issue
Block a user