From 11c5595382709daa902bbeefafa5c3b7f45ba679 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 19 Jul 2018 09:49:56 +0200 Subject: [PATCH] java fun expr search: search at up-to-date offsets (EA-115728 - assert: JavaFunctionalExpressionSearcher.lambda$processFile$) --- .../psi/impl/java/FunExprOccurrence.java | 32 ++------ .../java/JavaFunctionalExpressionIndex.java | 43 +++++------ .../JavaFunctionalExpressionSearcher.java | 74 ++++++++++++------- 3 files changed, 72 insertions(+), 77 deletions(-) diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/FunExprOccurrence.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/FunExprOccurrence.java index d10bc3df8fc6..be82dba5819a 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/FunExprOccurrence.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/FunExprOccurrence.java @@ -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 referenceContext; - public FunExprOccurrence(int funExprOffset, - int argIndex, - List referenceContext) { - this.funExprOffset = funExprOffset; + public FunExprOccurrence(int argIndex, List 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 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 { diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/JavaFunctionalExpressionIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/JavaFunctionalExpressionIndex.java index cdbb367b1702..a5dbabf7ed65 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/JavaFunctionalExpressionIndex.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/JavaFunctionalExpressionIndex.java @@ -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> implements PsiDependentIndex { - public static final ID> INDEX_ID = ID.create("java.fun.expression"); +public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension> implements PsiDependentIndex { + public static final ID> INDEX_ID = ID.create("java.fun.expression"); private static final KeyDescriptor KEY_DESCRIPTOR = new KeyDescriptor() { @Override public int getHashCode(FunctionalExpressionKey value) { @@ -339,18 +338,18 @@ public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension> getName() { + public ID> getName() { return INDEX_ID; } @NotNull @Override - public DataIndexer, FileContent> getIndexer() { + public DataIndexer, FileContent> getIndexer() { return inputData -> { CharSequence text = inputData.getContentAsText(); int[] offsets = ArrayUtil.mergeArrays( @@ -358,7 +357,7 @@ public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension> result = new HashMap<>(); + Map> result = new HashMap<>(); LighterAST tree = ((FileContentImpl)inputData).getLighterASTForPsiDependentIndex(); FileLocalResolver resolver = new FileLocalResolver(tree); @@ -371,11 +370,8 @@ public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension list = result.get(key); - if (list == null) { - result.put(key, list = new SmartList<>()); - } - list.add(createOccurrence(element, resolver)); + Map map = result.computeIfAbsent(key, __ -> new LinkedHashMap<>()); + map.put(element.getStartOffset(), createOccurrence(element, resolver)); } } @@ -398,30 +394,31 @@ public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension> getValueExternalizer() { - return new DataExternalizer>() { + public DataExternalizer> getValueExternalizer() { + return new DataExternalizer>() { @Override - public void save(@NotNull DataOutput out, List value) throws IOException { + public void save(@NotNull DataOutput out, Map value) throws IOException { DataInputOutputUtil.writeINT(out, value.size()); - for (FunExprOccurrence info : value) { - info.serialize(out); + for (Map.Entry entry : value.entrySet()) { + DataInputOutputUtil.writeINT(out, entry.getKey()); + entry.getValue().serialize(out); } } @Override - public List read(@NotNull DataInput in) throws IOException { + public Map read(@NotNull DataInput in) throws IOException { int length = DataInputOutputUtil.readINT(in); - List list = new SmartList<>(); + Map 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; } }; } diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java index 87a1d2469bce..124cb0a34ca2 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaFunctionalExpressionSearcher.java @@ -54,8 +54,6 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase consumer) { List 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 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 getAllOccurrences(List descriptors) { MultiMap 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 descriptors, Project project, PairProcessor> processor) { + private static void processIndexValues(List descriptors, + VirtualFile inFile, + FileBasedIndex.ValueProcessor> 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 descriptors, Project project, PairProcessor> processor) { if (descriptors.isEmpty()) return; List samClasses = ContainerUtil.map(descriptors, d -> d.samClass); @@ -151,10 +153,10 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase toLoad = filterInapplicable(samClasses, vFile, allCandidates.get(vFile), project); + Set 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 filterInapplicable(List samClasses, - VirtualFile vFile, - Collection occurrences, Project project) { + private static Set filterInapplicable(List samClasses, + VirtualFile vFile, + Collection 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 consumer, List descriptors, - VirtualFile vFile, Collection offsets) { - return ReadAction.compute(() -> { + VirtualFile vFile, Set 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 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 getOccurrenceOffsets(List descriptors, + VirtualFile vFile, + Set occurrences) { + List offsets = new ArrayList<>(); + processIndexValues(descriptors, vFile, (__, infos) -> { + for (Map.Entry entry : infos.entrySet()) { + if (occurrences.contains(entry.getValue())) { + offsets.add(entry.getKey()); + } + } + return true; + }); + return offsets; + } + private static boolean hasType(List descriptors, PsiFunctionalExpression expression) { if (!canHaveType(expression, ContainerUtil.map(descriptors, d -> d.samClass))) return false; @@ -268,6 +286,7 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase keys; GlobalSearchScope effectiveUseScope; SamDescriptor(PsiClass samClass, PsiMethod samMethod, PsiType samType, GlobalSearchScope useScope) { @@ -277,9 +296,10 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase generateKeys() { + private List generateKeys() { String name = samClass.isValid() ? samClass.getName() : null; if (name == null) return Collections.emptyList();