mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
java fun expr search: search at up-to-date offsets (EA-115728 - assert: JavaFunctionalExpressionSearcher.lambda$processFile$)
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package com.intellij.psi.impl.java;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.intellij.openapi.util.io.DataInputOutputUtilRt;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.search.ApproximateResolver;
|
||||
@@ -30,7 +31,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -38,19 +38,14 @@ import java.util.Set;
|
||||
* @author peter
|
||||
*/
|
||||
public class FunExprOccurrence {
|
||||
public final int funExprOffset;
|
||||
private final int argIndex;
|
||||
private final List<ReferenceChainLink> referenceContext;
|
||||
|
||||
public FunExprOccurrence(int funExprOffset,
|
||||
int argIndex,
|
||||
List<ReferenceChainLink> referenceContext) {
|
||||
this.funExprOffset = funExprOffset;
|
||||
public FunExprOccurrence(int argIndex, List<ReferenceChainLink> referenceContext) {
|
||||
this.argIndex = argIndex;
|
||||
this.referenceContext = referenceContext;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -58,7 +53,6 @@ public class FunExprOccurrence {
|
||||
|
||||
FunExprOccurrence that = (FunExprOccurrence)o;
|
||||
|
||||
if (funExprOffset != that.funExprOffset) return false;
|
||||
if (argIndex != that.argIndex) return false;
|
||||
if (!referenceContext.equals(that.referenceContext)) return false;
|
||||
|
||||
@@ -67,41 +61,25 @@ public class FunExprOccurrence {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = funExprOffset;
|
||||
result = 31 * result + argIndex;
|
||||
result = 31 * result + referenceContext.hashCode();
|
||||
return result;
|
||||
return 31 * argIndex + referenceContext.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("offset", funExprOffset)
|
||||
.add("argIndex", argIndex)
|
||||
.add("chain", referenceContext)
|
||||
.toString();
|
||||
}
|
||||
|
||||
void serialize(DataOutput out) throws IOException {
|
||||
DataInputOutputUtil.writeINT(out, funExprOffset);
|
||||
DataInputOutputUtil.writeINT(out, argIndex);
|
||||
|
||||
DataInputOutputUtil.writeINT(out, referenceContext.size());
|
||||
for (ReferenceChainLink link : referenceContext) {
|
||||
serializeLink(out, link);
|
||||
}
|
||||
DataInputOutputUtilRt.writeSeq(out, referenceContext, link -> serializeLink(out, link));
|
||||
}
|
||||
|
||||
static FunExprOccurrence deserialize(DataInput in) throws IOException {
|
||||
int offset = DataInputOutputUtil.readINT(in);
|
||||
int argIndex = DataInputOutputUtil.readINT(in);
|
||||
|
||||
int contextSize = DataInputOutputUtil.readINT(in);
|
||||
List<ReferenceChainLink> context = new ArrayList<>(contextSize);
|
||||
for (int i = 0; i < contextSize; i++) {
|
||||
context.add(deserializeLink(in));
|
||||
}
|
||||
return new FunExprOccurrence(offset, argIndex, context);
|
||||
return new FunExprOccurrence(argIndex, DataInputOutputUtilRt.readSeq(in, () -> deserializeLink(in)));
|
||||
}
|
||||
|
||||
private static void serializeLink(DataOutput out, ReferenceChainLink link) throws IOException {
|
||||
|
||||
+20
-23
@@ -35,7 +35,6 @@ import com.intellij.psi.impl.source.tree.RecursiveLighterASTNodeWalkingVisitor;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.JBIterable;
|
||||
import com.intellij.util.indexing.*;
|
||||
@@ -54,8 +53,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.intellij.psi.impl.source.tree.JavaElementType.*;
|
||||
|
||||
public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension<FunctionalExpressionKey, List<FunExprOccurrence>> implements PsiDependentIndex {
|
||||
public static final ID<FunctionalExpressionKey, List<FunExprOccurrence>> INDEX_ID = ID.create("java.fun.expression");
|
||||
public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension<FunctionalExpressionKey, Map<Integer, FunExprOccurrence>> implements PsiDependentIndex {
|
||||
public static final ID<FunctionalExpressionKey, Map<Integer, FunExprOccurrence>> INDEX_ID = ID.create("java.fun.expression");
|
||||
private static final KeyDescriptor<FunctionalExpressionKey> KEY_DESCRIPTOR = new KeyDescriptor<FunctionalExpressionKey>() {
|
||||
@Override
|
||||
public int getHashCode(FunctionalExpressionKey value) {
|
||||
@@ -339,18 +338,18 @@ public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension<Funct
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ID<FunctionalExpressionKey, List<FunExprOccurrence>> getName() {
|
||||
public ID<FunctionalExpressionKey, Map<Integer, FunExprOccurrence>> getName() {
|
||||
return INDEX_ID;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataIndexer<FunctionalExpressionKey, List<FunExprOccurrence>, FileContent> getIndexer() {
|
||||
public DataIndexer<FunctionalExpressionKey, Map<Integer, FunExprOccurrence>, FileContent> getIndexer() {
|
||||
return inputData -> {
|
||||
CharSequence text = inputData.getContentAsText();
|
||||
int[] offsets = ArrayUtil.mergeArrays(
|
||||
@@ -358,7 +357,7 @@ public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension<Funct
|
||||
new StringSearcher("::", true, true).findAllOccurrences(text));
|
||||
if (offsets.length == 0) return Collections.emptyMap();
|
||||
|
||||
Map<FunctionalExpressionKey, List<FunExprOccurrence>> result = new HashMap<>();
|
||||
Map<FunctionalExpressionKey, Map<Integer, FunExprOccurrence>> result = new HashMap<>();
|
||||
LighterAST tree = ((FileContentImpl)inputData).getLighterASTForPsiDependentIndex();
|
||||
FileLocalResolver resolver = new FileLocalResolver(tree);
|
||||
|
||||
@@ -371,11 +370,8 @@ public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension<Funct
|
||||
FunctionalExpressionKey key = new FunctionalExpressionKey(getFunExprParameterCount(tree, element),
|
||||
calcReturnType(tree, element),
|
||||
calcExprType(element, resolver));
|
||||
List<FunExprOccurrence> list = result.get(key);
|
||||
if (list == null) {
|
||||
result.put(key, list = new SmartList<>());
|
||||
}
|
||||
list.add(createOccurrence(element, resolver));
|
||||
Map<Integer, FunExprOccurrence> map = result.computeIfAbsent(key, __ -> new LinkedHashMap<>());
|
||||
map.put(element.getStartOffset(), createOccurrence(element, resolver));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,30 +394,31 @@ public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension<Funct
|
||||
}
|
||||
}
|
||||
|
||||
return new FunExprOccurrence(funExpr.getStartOffset(), argIndex,
|
||||
createCallChain(resolver, chainExpr));
|
||||
return new FunExprOccurrence(argIndex, createCallChain(resolver, chainExpr));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataExternalizer<List<FunExprOccurrence>> getValueExternalizer() {
|
||||
return new DataExternalizer<List<FunExprOccurrence>>() {
|
||||
public DataExternalizer<Map<Integer, FunExprOccurrence>> getValueExternalizer() {
|
||||
return new DataExternalizer<Map<Integer, FunExprOccurrence>>() {
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, List<FunExprOccurrence> value) throws IOException {
|
||||
public void save(@NotNull DataOutput out, Map<Integer, FunExprOccurrence> value) throws IOException {
|
||||
DataInputOutputUtil.writeINT(out, value.size());
|
||||
for (FunExprOccurrence info : value) {
|
||||
info.serialize(out);
|
||||
for (Map.Entry<Integer, FunExprOccurrence> entry : value.entrySet()) {
|
||||
DataInputOutputUtil.writeINT(out, entry.getKey());
|
||||
entry.getValue().serialize(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FunExprOccurrence> read(@NotNull DataInput in) throws IOException {
|
||||
public Map<Integer, FunExprOccurrence> read(@NotNull DataInput in) throws IOException {
|
||||
int length = DataInputOutputUtil.readINT(in);
|
||||
List<FunExprOccurrence> list = new SmartList<>();
|
||||
Map<Integer, FunExprOccurrence> map = new LinkedHashMap<>();
|
||||
for (int i = 0; i < length; i++) {
|
||||
list.add(FunExprOccurrence.deserialize(in));
|
||||
int offset = DataInputOutputUtil.readINT(in);
|
||||
map.put(offset, FunExprOccurrence.deserialize(in));
|
||||
}
|
||||
return list;
|
||||
return map;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+47
-27
@@ -54,8 +54,6 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
public void processQuery(@NotNull SearchParameters p, @NotNull Processor<? super PsiFunctionalExpression> consumer) {
|
||||
List<SamDescriptor> descriptors = calcDescriptors(p);
|
||||
Project project = PsiUtilCore.getProjectInReadAction(p.getElementToSearch());
|
||||
if (project == null) return;
|
||||
|
||||
SearchScope searchScope = ReadAction.compute(() -> p.getEffectiveSearchScope());
|
||||
if (searchScope instanceof GlobalSearchScope && !performSearchUsingCompilerIndices(descriptors,
|
||||
(GlobalSearchScope)searchScope,
|
||||
@@ -70,10 +68,10 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
PsiManager manager = ReadAction.compute(() -> p.getElementToSearch().getManager());
|
||||
manager.startBatchFilesProcessingMode();
|
||||
try {
|
||||
processOffsets(descriptors, project, (file, offsets) -> {
|
||||
processOffsets(descriptors, project, (file, occurrences) -> {
|
||||
fileCount.incrementAndGet();
|
||||
exprCount.addAndGet(offsets.size());
|
||||
return processFile(consumer, descriptors, file, offsets);
|
||||
exprCount.addAndGet(occurrences.size());
|
||||
return processFile(consumer, descriptors, file, occurrences);
|
||||
});
|
||||
}
|
||||
finally {
|
||||
@@ -128,22 +126,26 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
@NotNull
|
||||
private static MultiMap<VirtualFile, FunExprOccurrence> getAllOccurrences(List<SamDescriptor> descriptors) {
|
||||
MultiMap<VirtualFile, FunExprOccurrence> result = MultiMap.createLinkedSet();
|
||||
for (SamDescriptor descriptor : descriptors) {
|
||||
descriptor.dumbService.runReadActionInSmartMode(() -> {
|
||||
for (FunctionalExpressionKey key : descriptor.generateKeys()) {
|
||||
FileBasedIndex.getInstance().processValues(JavaFunctionalExpressionIndex.INDEX_ID, key, null, (file, infos) -> {
|
||||
ProgressManager.checkCanceled();
|
||||
result.putValues(file, infos);
|
||||
return true;
|
||||
}, new JavaSourceFilterScope(descriptor.effectiveUseScope));
|
||||
}
|
||||
});
|
||||
}
|
||||
descriptors.get(0).dumbService.runReadActionInSmartMode(() -> processIndexValues(descriptors, null, (file, infos) -> {
|
||||
result.putValues(file, infos.values());
|
||||
return true;
|
||||
}));
|
||||
LOG.debug("Found " + result.values().size() + " fun-expressions in " + result.keySet().size() + " files");
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void processOffsets(List<SamDescriptor> descriptors, Project project, PairProcessor<VirtualFile, List<Integer>> processor) {
|
||||
private static void processIndexValues(List<SamDescriptor> descriptors,
|
||||
VirtualFile inFile,
|
||||
FileBasedIndex.ValueProcessor<Map<Integer, FunExprOccurrence>> processor) {
|
||||
for (SamDescriptor descriptor : descriptors) {
|
||||
GlobalSearchScope scope = new JavaSourceFilterScope(descriptor.effectiveUseScope);
|
||||
for (FunctionalExpressionKey key : descriptor.keys) {
|
||||
FileBasedIndex.getInstance().processValues(JavaFunctionalExpressionIndex.INDEX_ID, key, inFile, processor, scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processOffsets(List<SamDescriptor> descriptors, Project project, PairProcessor<VirtualFile, Set<FunExprOccurrence>> processor) {
|
||||
if (descriptors.isEmpty()) return;
|
||||
|
||||
List<PsiClass> samClasses = ContainerUtil.map(descriptors, d -> d.samClass);
|
||||
@@ -151,10 +153,10 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
if (allCandidates.isEmpty()) return;
|
||||
|
||||
for (VirtualFile vFile : putLikelyFilesFirst(descriptors, allCandidates.keySet(), project)) {
|
||||
List<FunExprOccurrence> toLoad = filterInapplicable(samClasses, vFile, allCandidates.get(vFile), project);
|
||||
Set<FunExprOccurrence> toLoad = filterInapplicable(samClasses, vFile, allCandidates.get(vFile), project);
|
||||
if (!toLoad.isEmpty()) {
|
||||
LOG.trace("To load " + vFile.getPath() + " with values: " + toLoad);
|
||||
if (!processor.process(vFile, ContainerUtil.map(toLoad, it -> it.funExprOffset))) {
|
||||
if (!processor.process(vFile, toLoad)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -170,24 +172,25 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<FunExprOccurrence> filterInapplicable(List<PsiClass> samClasses,
|
||||
VirtualFile vFile,
|
||||
Collection<FunExprOccurrence> occurrences, Project project) {
|
||||
private static Set<FunExprOccurrence> filterInapplicable(List<PsiClass> samClasses,
|
||||
VirtualFile vFile,
|
||||
Collection<FunExprOccurrence> occurrences, Project project) {
|
||||
return DumbService.getInstance(project).runReadActionInSmartMode(
|
||||
() -> project.isDisposed() ? Collections.emptyList()
|
||||
: ContainerUtil.filter(occurrences, it -> it.canHaveType(samClasses, vFile)));
|
||||
() -> new HashSet<>(ContainerUtil.filter(occurrences, it -> it.canHaveType(samClasses, vFile))));
|
||||
}
|
||||
|
||||
private static boolean processFile(@NotNull Processor<? super PsiFunctionalExpression> consumer,
|
||||
List<SamDescriptor> descriptors,
|
||||
VirtualFile vFile, Collection<Integer> offsets) {
|
||||
return ReadAction.compute(() -> {
|
||||
VirtualFile vFile, Set<FunExprOccurrence> occurrences) {
|
||||
return descriptors.get(0).dumbService.runReadActionInSmartMode(() -> {
|
||||
PsiFile file = descriptors.get(0).samClass.getManager().findFile(vFile);
|
||||
if (!(file instanceof PsiJavaFile)) {
|
||||
LOG.error("Non-java file " + file + "; " + vFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
List<Integer> offsets = getOccurrenceOffsets(descriptors, vFile, occurrences);
|
||||
|
||||
for (Integer offset : offsets) {
|
||||
PsiFunctionalExpression expression = PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiFunctionalExpression.class, false);
|
||||
if (expression == null || expression.getTextRange().getStartOffset() != offset) {
|
||||
@@ -204,6 +207,21 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
});
|
||||
}
|
||||
|
||||
private static List<Integer> getOccurrenceOffsets(List<SamDescriptor> descriptors,
|
||||
VirtualFile vFile,
|
||||
Set<FunExprOccurrence> occurrences) {
|
||||
List<Integer> offsets = new ArrayList<>();
|
||||
processIndexValues(descriptors, vFile, (__, infos) -> {
|
||||
for (Map.Entry<Integer, FunExprOccurrence> entry : infos.entrySet()) {
|
||||
if (occurrences.contains(entry.getValue())) {
|
||||
offsets.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return offsets;
|
||||
}
|
||||
|
||||
private static boolean hasType(List<SamDescriptor> descriptors, PsiFunctionalExpression expression) {
|
||||
if (!canHaveType(expression, ContainerUtil.map(descriptors, d -> d.samClass))) return false;
|
||||
|
||||
@@ -268,6 +286,7 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
final boolean booleanCompatible;
|
||||
final boolean isVoid;
|
||||
final DumbService dumbService;
|
||||
final List<FunctionalExpressionKey> keys;
|
||||
GlobalSearchScope effectiveUseScope;
|
||||
|
||||
SamDescriptor(PsiClass samClass, PsiMethod samMethod, PsiType samType, GlobalSearchScope useScope) {
|
||||
@@ -277,9 +296,10 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
this.booleanCompatible = FunctionalExpressionKey.isBooleanCompatible(samType);
|
||||
this.isVoid = PsiType.VOID.equals(samType);
|
||||
this.dumbService = DumbService.getInstance(samClass.getProject());
|
||||
keys = generateKeys();
|
||||
}
|
||||
|
||||
List<FunctionalExpressionKey> generateKeys() {
|
||||
private List<FunctionalExpressionKey> generateKeys() {
|
||||
String name = samClass.isValid() ? samClass.getName() : null;
|
||||
if (name == null) return Collections.emptyList();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user