add LightTreeUtil.processLeavesAtOffsets to speed up indices that walk text occurrences (IDEA-211564)

GitOrigin-RevId: cdc48ae3679e43a5ca7b87d0c371ecb6ab78cc19
This commit is contained in:
peter
2019-04-24 19:12:44 +02:00
committed by intellij-monorepo-bot
parent 34f13deda3
commit d841318606
4 changed files with 68 additions and 69 deletions

View File

@@ -4,30 +4,29 @@ package com.intellij.psi.impl.java;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.lang.LighterAST;
import com.intellij.lang.LighterASTNode;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.impl.source.JavaFileElementType;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.impl.source.tree.RecursiveLighterASTNodeWalkingVisitor;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.impl.source.tree.LightTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.*;
import com.intellij.util.io.BooleanDataDescriptor;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.DataInputOutputUtil;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.text.StringSearcher;
import gnu.trove.THashMap;
import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class JavaBinaryPlusExpressionIndex extends FileBasedIndexExtension<Boolean, JavaBinaryPlusExpressionIndex.PlusOffsets> implements PsiDependentIndex {
public static final ID<Boolean, PlusOffsets> INDEX_ID = ID.create("java.binary.plus.expression");
@@ -43,24 +42,22 @@ public class JavaBinaryPlusExpressionIndex extends FileBasedIndexExtension<Boole
public DataIndexer<Boolean, PlusOffsets, FileContent> getIndexer() {
return inputData -> {
CharSequence text = inputData.getContentAsText();
if (text.chars().noneMatch(c -> c == '+')) return Collections.emptyMap();
int[] offsets = new StringSearcher("+", true, true).findAllOccurrences(text);
if (offsets.length == 0) return Collections.emptyMap();
LighterAST tree = ((FileContentImpl)inputData).getLighterASTForPsiDependentIndex();
TIntArrayList result = new TIntArrayList(1);
new RecursiveLighterASTNodeWalkingVisitor(tree) {
@Override
public void visitNode(@NotNull LighterASTNode element) {
super.visitNode(element);
ProgressManager.checkCanceled();
if ((element.getTokenType() == JavaElementType.BINARY_EXPRESSION ||
element.getTokenType() == JavaElementType.POLYADIC_EXPRESSION)) {
int[] offsets = getStringConcatenationPlusOffsets(element, tree);
if (offsets != null) {
result.add(offsets);
}
}
TIntArrayList result = new TIntArrayList(offsets.length);
Map<LighterASTNode, Boolean> stringConcatenations = new HashMap<>();
LightTreeUtil.processLeavesAtOffsets(offsets, tree, (leaf, offset) -> {
LighterASTNode element = leaf == null ? null : tree.getParent(leaf);
if (element == null) return;
if ((element.getTokenType() == JavaElementType.BINARY_EXPRESSION
|| element.getTokenType() == JavaElementType.POLYADIC_EXPRESSION) &&
!stringConcatenations.computeIfAbsent(element, __ -> isStringConcatenation(element, tree))) {
result.add(offset);
}
}.visitNode(tree.getRoot());
});
THashMap<Boolean, PlusOffsets> resultMap = ContainerUtil.newTroveMap();
resultMap.put(Boolean.TRUE, new PlusOffsets(result.toNativeArray()));
return resultMap;
@@ -143,26 +140,10 @@ public class JavaBinaryPlusExpressionIndex extends FileBasedIndexExtension<Boole
}
}
@Nullable
private static int[] getStringConcatenationPlusOffsets(@NotNull LighterASTNode concatExpr, @NotNull LighterAST tree) {
TIntArrayList result = null;
boolean nonLiteralOccurred = false;
for (LighterASTNode child : tree.getChildren(concatExpr)) {
IElementType childTokenType = child.getTokenType();
if (ElementType.EXPRESSION_BIT_SET.contains(childTokenType)) {
if (!nonLiteralOccurred && !JavaElementType.LITERAL_EXPRESSION.equals(childTokenType)) {
nonLiteralOccurred = true;
}
continue;
}
if (JavaTokenType.PLUS.equals(childTokenType)) {
if (result == null) {
result = new TIntArrayList();
}
result.add(child.getStartOffset());
continue;
}
}
return result == null || !nonLiteralOccurred ? null : result.toNativeArray();
private static boolean isStringConcatenation(@NotNull LighterASTNode concatExpr, @NotNull LighterAST tree) {
return LightTreeUtil
.getChildrenOfType(tree, concatExpr, ElementType.EXPRESSION_BIT_SET)
.stream()
.allMatch(e -> e.getTokenType() == JavaElementType.LITERAL_EXPRESSION);
}
}

View File

@@ -376,10 +376,9 @@ public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension<Funct
LighterAST tree = ((FileContentImpl)inputData).getLighterASTForPsiDependentIndex();
FileLocalResolver resolver = new FileLocalResolver(tree);
for (int offset : offsets) {
LighterASTNode leaf = LightTreeUtil.findLeafElementAt(tree, offset);
LighterASTNode element = leaf == null ? null : tree.getParent(leaf);
if (element == null) continue;
LightTreeUtil.processLeavesAtOffsets(offsets, tree, (leaf, offset) -> {
LighterASTNode element = tree.getParent(leaf);
if (element == null) return;
if (element.getTokenType() == METHOD_REF_EXPRESSION || element.getTokenType() == LAMBDA_EXPRESSION) {
FunctionalExpressionKey key = new FunctionalExpressionKey(getFunExprParameterCount(tree, element),
@@ -388,7 +387,7 @@ public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension<Funct
Map<Integer, FunExprOccurrence> map = result.computeIfAbsent(key, __ -> new LinkedHashMap<>());
map.put(element.getStartOffset(), createOccurrence(element, resolver));
}
}
});
return result;
};

View File

@@ -57,11 +57,10 @@ public class JavaNullMethodArgumentIndex extends ScalarIndexExtension<JavaNullMe
return Collections.emptyMap();
}
StringSearcher searcher = new StringSearcher(PsiKeyword.NULL, true, true);
LighterAST lighterAst = ((FileContentImpl)inputData).getLighterASTForPsiDependentIndex();
CharSequence text = inputData.getContentAsText();
Set<LighterASTNode> calls = findCallsWithNulls(lighterAst, text, searcher);
Set<LighterASTNode> calls = findCallsWithNulls(lighterAst, text);
if (calls.isEmpty()) return Collections.emptyMap();
Map<MethodCallData, Void> result = new THashMap<>();
@@ -81,10 +80,11 @@ public class JavaNullMethodArgumentIndex extends ScalarIndexExtension<JavaNullMe
}
@NotNull
private static Set<LighterASTNode> findCallsWithNulls(@NotNull LighterAST lighterAst, @NotNull CharSequence text, @NotNull StringSearcher searcher) {
private static Set<LighterASTNode> findCallsWithNulls(@NotNull LighterAST lighterAst,
@NotNull CharSequence text) {
Set<LighterASTNode> calls = new HashSet<>();
searcher.processOccurrences(text, offset -> {
LighterASTNode leaf = LightTreeUtil.findLeafElementAt(lighterAst, offset);
int[] occurrences = new StringSearcher(PsiKeyword.NULL, true, true).findAllOccurrences(text);
LightTreeUtil.processLeavesAtOffsets(occurrences, lighterAst, (leaf, offset) -> {
LighterASTNode literal = leaf == null ? null : lighterAst.getParent(leaf);
if (isNullLiteral(lighterAst, literal)) {
LighterASTNode exprList = lighterAst.getParent(literal);
@@ -92,7 +92,6 @@ public class JavaNullMethodArgumentIndex extends ScalarIndexExtension<JavaNullMe
ContainerUtil.addIfNotNull(calls, LightTreeUtil.getParentOfType(lighterAst, exprList, Lazy.CALL_TYPES, ElementType.MEMBER_BIT_SET));
}
}
return true;
});
return calls;
}