mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
go back to using non-stub index for functional expressions, because the inevitable stub-AST switch is quite more expensive than finding element by offset (because a lot less code blocks will be parsed in the latter case)
This commit is contained in:
+349
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.psi.impl.java;
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.lang.LighterAST;
|
||||
import com.intellij.lang.LighterASTNode;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiBinaryExpression;
|
||||
import com.intellij.psi.impl.java.stubs.FunctionalExpressionKey;
|
||||
import com.intellij.psi.impl.source.Constants;
|
||||
import com.intellij.psi.impl.source.JavaFileElementType;
|
||||
import com.intellij.psi.impl.source.JavaLightTreeUtil;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.impl.source.tree.LightTreeUtil;
|
||||
import com.intellij.psi.impl.source.tree.RecursiveLighterASTNodeWalkingVisitor;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.indexing.*;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.DataInputOutputUtil;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
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.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.intellij.psi.impl.source.tree.JavaElementType.*;
|
||||
|
||||
public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension<FunctionalExpressionKey, TIntArrayList> implements PsiDependentIndex {
|
||||
public static final ID<FunctionalExpressionKey, TIntArrayList> INDEX_ID = ID.create("java.fun.expression");
|
||||
private static final KeyDescriptor<FunctionalExpressionKey> KEY_DESCRIPTOR = new KeyDescriptor<FunctionalExpressionKey>() {
|
||||
@Override
|
||||
public int getHashCode(FunctionalExpressionKey value) {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEqual(FunctionalExpressionKey val1, FunctionalExpressionKey val2) {
|
||||
return val1.equals(val2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, FunctionalExpressionKey value) throws IOException {
|
||||
value.serializeKey(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionalExpressionKey read(@NotNull DataInput in) throws IOException {
|
||||
return FunctionalExpressionKey.deserializeKey(in);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private static FunctionalExpressionKey.Location calcLocation(LighterAST tree, LighterASTNode funExpr) {
|
||||
LighterASTNode call = getContainingCall(tree, funExpr);
|
||||
List<LighterASTNode> args = JavaLightTreeUtil.getArgList(tree, call);
|
||||
int argIndex = args == null ? -1 : getArgIndex(args, funExpr);
|
||||
String methodName = call == null ? null : getCalledMethodName(tree, call);
|
||||
return methodName == null || argIndex < 0
|
||||
? createTypedLocation(tree, funExpr)
|
||||
: new FunctionalExpressionKey.CallLocation(methodName, args.size(), argIndex, StreamApiDetector.isStreamApiCall(tree, call));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static FunctionalExpressionKey.Location createTypedLocation(LighterAST tree, LighterASTNode funExpr) {
|
||||
LighterASTNode scope = skipExpressionsUp(tree, funExpr, TokenSet.create(LOCAL_VARIABLE, FIELD, TYPE_CAST_EXPRESSION, RETURN_STATEMENT));
|
||||
if (scope != null) {
|
||||
if (scope.getTokenType() == RETURN_STATEMENT) {
|
||||
scope = LightTreeUtil.getParentOfType(tree, scope,
|
||||
TokenSet.create(METHOD),
|
||||
TokenSet.orSet(ElementType.MEMBER_BIT_SET, TokenSet.create(LAMBDA_EXPRESSION)));
|
||||
}
|
||||
|
||||
LighterASTNode typeElement = LightTreeUtil.firstChildOfType(tree, scope, TYPE);
|
||||
String typeText = JavaLightTreeUtil.getNameIdentifierText(tree, LightTreeUtil.firstChildOfType(tree, typeElement, JAVA_CODE_REFERENCE));
|
||||
if (typeText != null) {
|
||||
return new FunctionalExpressionKey.TypedLocation(typeText);
|
||||
}
|
||||
}
|
||||
return FunctionalExpressionKey.Location.UNKNOWN;
|
||||
}
|
||||
|
||||
private static int getArgIndex(List<LighterASTNode> args, LighterASTNode expr) {
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
if (args.get(i).getEndOffset() >= expr.getEndOffset()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static FunctionalExpressionKey.CoarseType calcType(final LighterAST tree, LighterASTNode funExpr) {
|
||||
if (funExpr.getTokenType() == METHOD_REF_EXPRESSION) return FunctionalExpressionKey.CoarseType.UNKNOWN;
|
||||
|
||||
LighterASTNode block = LightTreeUtil.firstChildOfType(tree, funExpr, CODE_BLOCK);
|
||||
if (block == null) {
|
||||
LighterASTNode expr = findExpressionChild(funExpr, tree);
|
||||
return isBooleanExpression(tree, expr) ? FunctionalExpressionKey.CoarseType.BOOLEAN : FunctionalExpressionKey.CoarseType.UNKNOWN;
|
||||
}
|
||||
|
||||
final Ref<Boolean> returnsSomething = Ref.create(null);
|
||||
final AtomicBoolean isBoolean = new AtomicBoolean();
|
||||
final AtomicBoolean hasStatements = new AtomicBoolean();
|
||||
new RecursiveLighterASTNodeWalkingVisitor(tree) {
|
||||
@Override
|
||||
public void visitNode(@NotNull LighterASTNode element) {
|
||||
IElementType type = element.getTokenType();
|
||||
if (type == LAMBDA_EXPRESSION || ElementType.MEMBER_BIT_SET.contains(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == RETURN_STATEMENT) {
|
||||
LighterASTNode expr = findExpressionChild(element, tree);
|
||||
returnsSomething.set(expr != null);
|
||||
if (isBooleanExpression(tree, expr)) {
|
||||
isBoolean.set(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == EXPRESSION_STATEMENT) {
|
||||
hasStatements.set(true);
|
||||
}
|
||||
|
||||
super.visitNode(element);
|
||||
}
|
||||
}.visitNode(block);
|
||||
|
||||
if (isBoolean.get()) {
|
||||
return FunctionalExpressionKey.CoarseType.BOOLEAN;
|
||||
}
|
||||
|
||||
if (returnsSomething.isNull()) {
|
||||
return hasStatements.get() ? FunctionalExpressionKey.CoarseType.VOID : FunctionalExpressionKey.CoarseType.UNKNOWN;
|
||||
}
|
||||
|
||||
return returnsSomething.get() ? FunctionalExpressionKey.CoarseType.NON_VOID : FunctionalExpressionKey.CoarseType.VOID;
|
||||
}
|
||||
|
||||
private static LighterASTNode findExpressionChild(@NotNull LighterASTNode element, LighterAST tree) {
|
||||
return LightTreeUtil.firstChildOfType(tree, element, ElementType.EXPRESSION_BIT_SET);
|
||||
}
|
||||
|
||||
private static boolean isBooleanExpression(LighterAST tree, @Nullable LighterASTNode expr) {
|
||||
if (expr == null) return false;
|
||||
|
||||
IElementType type = expr.getTokenType();
|
||||
if (type == LITERAL_EXPRESSION) {
|
||||
IElementType child = tree.getChildren(expr).get(0).getTokenType();
|
||||
return child == JavaTokenType.TRUE_KEYWORD || child == JavaTokenType.FALSE_KEYWORD;
|
||||
}
|
||||
if (type == POLYADIC_EXPRESSION || type == BINARY_EXPRESSION) {
|
||||
return LightTreeUtil.firstChildOfType(tree, expr, PsiBinaryExpression.BOOLEAN_OPERATION_TOKENS) != null;
|
||||
}
|
||||
if (type == PREFIX_EXPRESSION) {
|
||||
return tree.getChildren(expr).get(0).getTokenType() == JavaTokenType.EXCL;
|
||||
}
|
||||
if (type == PARENTH_EXPRESSION) {
|
||||
return isBooleanExpression(tree, findExpressionChild(expr, tree));
|
||||
}
|
||||
if (type == CONDITIONAL_EXPRESSION) {
|
||||
List<LighterASTNode> children = LightTreeUtil.getChildrenOfType(tree, expr, ElementType.EXPRESSION_BIT_SET);
|
||||
return children.size() == 3 && (isBooleanExpression(tree, children.get(1)) || isBooleanExpression(tree, children.get(2)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int getFunExprParameterCount(LighterAST tree, LighterASTNode funExpr) {
|
||||
if (funExpr.getTokenType() == METHOD_REF_EXPRESSION) return FunctionalExpressionKey.UNKNOWN_PARAM_COUNT;
|
||||
|
||||
assert funExpr.getTokenType() == LAMBDA_EXPRESSION;
|
||||
|
||||
LighterASTNode paramList = LightTreeUtil.firstChildOfType(tree, funExpr, PARAMETER_LIST);
|
||||
assert paramList != null;
|
||||
return LightTreeUtil.getChildrenOfType(tree, paramList, Constants.PARAMETER_BIT_SET).size();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getCalledMethodName(LighterAST tree, LighterASTNode call) {
|
||||
if (call.getTokenType() == NEW_EXPRESSION) {
|
||||
LighterASTNode anonClass = LightTreeUtil.firstChildOfType(tree, call, ANONYMOUS_CLASS);
|
||||
LighterASTNode ref = LightTreeUtil.firstChildOfType(tree, anonClass != null ? anonClass : call, JAVA_CODE_REFERENCE);
|
||||
return ref == null ? null : JavaLightTreeUtil.getNameIdentifierText(tree, ref);
|
||||
}
|
||||
|
||||
LighterASTNode methodExpr = tree.getChildren(call).get(0);
|
||||
if (LightTreeUtil.firstChildOfType(tree, methodExpr, JavaTokenType.SUPER_KEYWORD) != null) {
|
||||
return getSuperClassName(tree, call);
|
||||
}
|
||||
if (LightTreeUtil.firstChildOfType(tree, methodExpr, JavaTokenType.THIS_KEYWORD) != null) {
|
||||
return JavaLightTreeUtil.getNameIdentifierText(tree, findClass(tree, call));
|
||||
}
|
||||
|
||||
return JavaLightTreeUtil.getNameIdentifierText(tree, methodExpr);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getSuperClassName(LighterAST tree, LighterASTNode call) {
|
||||
LighterASTNode aClass = findClass(tree, call);
|
||||
LighterASTNode extendsList = LightTreeUtil.firstChildOfType(tree, aClass, EXTENDS_LIST);
|
||||
return JavaLightTreeUtil.getNameIdentifierText(tree, LightTreeUtil.firstChildOfType(tree, extendsList, JAVA_CODE_REFERENCE));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LighterASTNode getContainingCall(LighterAST tree, LighterASTNode node) {
|
||||
LighterASTNode expressionList = skipExpressionsUp(tree, node, TokenSet.create(EXPRESSION_LIST));
|
||||
if (expressionList != null) {
|
||||
LighterASTNode parent = tree.getParent(expressionList);
|
||||
if (parent != null && parent.getTokenType() == ANONYMOUS_CLASS) {
|
||||
parent = tree.getParent(parent);
|
||||
}
|
||||
if (parent != null && (parent.getTokenType() == METHOD_CALL_EXPRESSION || parent.getTokenType() == NEW_EXPRESSION)) {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static LighterASTNode skipExpressionsUp(LighterAST tree, @NotNull LighterASTNode node, TokenSet types) {
|
||||
node = tree.getParent(node);
|
||||
while (node != null) {
|
||||
final IElementType type = node.getTokenType();
|
||||
if (types.contains(type)) return node;
|
||||
if (type != PARENTH_EXPRESSION && type != CONDITIONAL_EXPRESSION) return null;
|
||||
node = tree.getParent(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static LighterASTNode findClass(LighterAST tree, LighterASTNode node) {
|
||||
while (node != null) {
|
||||
final IElementType type = node.getTokenType();
|
||||
if (type == CLASS) return node;
|
||||
node = tree.getParent(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KeyDescriptor<FunctionalExpressionKey> getKeyDescriptor() {
|
||||
return KEY_DESCRIPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ID<FunctionalExpressionKey, TIntArrayList> getName() {
|
||||
return INDEX_ID;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataIndexer<FunctionalExpressionKey, TIntArrayList, FileContent> getIndexer() {
|
||||
return inputData -> {
|
||||
Map<FunctionalExpressionKey, TIntArrayList> result = new HashMap<>();
|
||||
|
||||
LighterAST tree = ((FileContentImpl)inputData).getLighterASTForPsiDependentIndex();
|
||||
new RecursiveLighterASTNodeWalkingVisitor(tree) {
|
||||
@Override
|
||||
public void visitNode(@NotNull LighterASTNode element) {
|
||||
if (element.getTokenType() == METHOD_REF_EXPRESSION ||
|
||||
element.getTokenType() == LAMBDA_EXPRESSION) {
|
||||
FunctionalExpressionKey key = new FunctionalExpressionKey(getFunExprParameterCount(tree, element),
|
||||
calcType(tree, element),
|
||||
calcLocation(tree, element));
|
||||
TIntArrayList list = result.get(key);
|
||||
if (list == null) {
|
||||
result.put(key, list = new TIntArrayList());
|
||||
}
|
||||
list.add(element.getStartOffset());
|
||||
}
|
||||
|
||||
super.visitNode(element);
|
||||
}
|
||||
}.visitNode(tree.getRoot());
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataExternalizer<TIntArrayList> getValueExternalizer() {
|
||||
return new DataExternalizer<TIntArrayList>() {
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, TIntArrayList value) throws IOException {
|
||||
DataInputOutputUtil.writeINT(out, value.size());
|
||||
for (int i = 0; i < value.size(); i++) {
|
||||
DataInputOutputUtil.writeINT(out, value.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TIntArrayList read(@NotNull DataInput in) throws IOException {
|
||||
int length = DataInputOutputUtil.readINT(in);
|
||||
TIntArrayList list = new TIntArrayList(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
list.add(DataInputOutputUtil.readINT(in));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FileBasedIndex.InputFilter getInputFilter() {
|
||||
return new DefaultFileTypeSpecificInputFilter(JavaFileType.INSTANCE) {
|
||||
@Override
|
||||
public boolean acceptInput(@NotNull VirtualFile file) {
|
||||
return super.acceptInput(file) && JavaFileElementType.isInSourceContent(file);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dependsOnFileContent() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package com.intellij.psi.impl.java.stubs.index;
|
||||
|
||||
import com.intellij.psi.PsiFunctionalExpression;
|
||||
import com.intellij.psi.impl.java.stubs.FunctionalExpressionKey;
|
||||
import com.intellij.psi.stubs.AbstractStubIndex;
|
||||
import com.intellij.psi.stubs.StubIndexKey;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
public class JavaFunctionalExpressionIndex extends AbstractStubIndex<FunctionalExpressionKey, PsiFunctionalExpression> {
|
||||
private static final KeyDescriptor<FunctionalExpressionKey> KEY_DESCRIPTOR = new KeyDescriptor<FunctionalExpressionKey>() {
|
||||
@Override
|
||||
public int getHashCode(FunctionalExpressionKey value) {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEqual(FunctionalExpressionKey val1, FunctionalExpressionKey val2) {
|
||||
return val1.equals(val2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, FunctionalExpressionKey value) throws IOException {
|
||||
value.serializeKey(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionalExpressionKey read(@NotNull DataInput in) throws IOException {
|
||||
return FunctionalExpressionKey.deserializeKey(in);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KeyDescriptor<FunctionalExpressionKey> getKeyDescriptor() {
|
||||
return KEY_DESCRIPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public StubIndexKey<FunctionalExpressionKey, PsiFunctionalExpression> getKey() {
|
||||
return JavaStubIndexKeys.FUNCTIONAL_EXPRESSIONS;
|
||||
}
|
||||
|
||||
}
|
||||
+67
-32
@@ -32,12 +32,12 @@ import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.JavaFunctionalExpressionIndex;
|
||||
import com.intellij.psi.impl.java.stubs.FunctionalExpressionKey;
|
||||
import com.intellij.psi.impl.java.stubs.FunctionalExpressionKey.CallLocation;
|
||||
import com.intellij.psi.impl.java.stubs.FunctionalExpressionKey.Location;
|
||||
import com.intellij.psi.impl.java.stubs.JavaMethodElementType;
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaMethodParameterTypesIndex;
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaStubIndexKeys;
|
||||
import com.intellij.psi.search.*;
|
||||
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
|
||||
import com.intellij.psi.search.searches.FunctionalExpressionSearch;
|
||||
@@ -48,6 +48,7 @@ import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -57,7 +58,7 @@ import java.util.stream.*;
|
||||
import static com.intellij.util.ObjectUtils.assertNotNull;
|
||||
|
||||
public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunctionalExpression, FunctionalExpressionSearch.SearchParameters> {
|
||||
private static final Logger LOG = Logger.getInstance("#" + JavaFunctionalExpressionSearcher.class.getName());
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.search.JavaFunctionalExpressionSearcher");
|
||||
/**
|
||||
* The least number of candidate files with functional expressions that directly scanning them becomes expensive
|
||||
* and more advanced ways of searching become necessary: e.g. first searching for methods where the functional interface class is used
|
||||
@@ -104,22 +105,37 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
if (descriptor == null) return;
|
||||
|
||||
MultiMap<Location, GlobalSearchScope> queries = collectQueryKeys(descriptor, highLevelModules);
|
||||
for (PsiFunctionalExpression expression : getCandidates(descriptor, queries)) {
|
||||
if (!processExpression(consumer, funInterface, expression)) {
|
||||
for (Map.Entry<VirtualFile, Collection<Integer>> entry : getCandidateOffsets(descriptor, queries).entrySet()) {
|
||||
if (!processFile(consumer, funInterface, entry.getKey(), entry.getValue())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean processExpression(@NotNull Processor<PsiFunctionalExpression> consumer,
|
||||
PsiClass aClass,
|
||||
PsiFunctionalExpression expression) {
|
||||
private static boolean processFile(@NotNull Processor<PsiFunctionalExpression> consumer,
|
||||
PsiClass samClass,
|
||||
VirtualFile vFile, Collection<Integer> offsets) {
|
||||
return ReadAction.compute(() -> {
|
||||
if (expression.isValid() &&
|
||||
InheritanceUtil.isInheritorOrSelf(PsiUtil.resolveClassInType(expression.getFunctionalInterfaceType()), aClass, true)) {
|
||||
if (!consumer.process(expression)) {
|
||||
return false;
|
||||
if (!samClass.isValid()) return true;
|
||||
|
||||
PsiFile file = samClass.getManager().findFile(vFile);
|
||||
if (!(file instanceof PsiJavaFile)) {
|
||||
LOG.error("Non-java file " + file + "; " + vFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
for (Integer offset : offsets) {
|
||||
PsiFunctionalExpression expression = PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiFunctionalExpression.class, false);
|
||||
if (expression == null || expression.getTextRange().getStartOffset() != offset) {
|
||||
LOG.error("Fun expression not found in " + file + " at " + offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InheritanceUtil.isInheritorOrSelf(PsiUtil.resolveClassInType(expression.getFunctionalInterfaceType()), samClass, true)) {
|
||||
if (!consumer.process(expression)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,30 +144,49 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<? extends PsiFunctionalExpression> getCandidates(SamDescriptor descriptor, MultiMap<Location, GlobalSearchScope> queries) {
|
||||
MultiMap<PsiFile, PsiFunctionalExpression> exprs = MultiMap.createLinked();
|
||||
for (Map.Entry<Location, Collection<GlobalSearchScope>> entry : queries.entrySet()) {
|
||||
ReadAction.run(() -> {
|
||||
ProgressManager.checkCanceled();
|
||||
GlobalSearchScope combinedScope = descriptor.useScope.intersectWith(
|
||||
GlobalSearchScope.union(entry.getValue().toArray(new GlobalSearchScope[0])));
|
||||
for (FunctionalExpressionKey key : descriptor.generateKeys(entry.getKey())) {
|
||||
StubIndex.getInstance().processElements(JavaStubIndexKeys.FUNCTIONAL_EXPRESSIONS, key,
|
||||
descriptor.samClass.getProject(), combinedScope, null,
|
||||
PsiFunctionalExpression.class,
|
||||
expression -> {
|
||||
exprs.putValue(expression.getContainingFile(), expression);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
private static MultiMap<VirtualFile, Integer> getCandidateOffsets(SamDescriptor descriptor, MultiMap<Location, GlobalSearchScope> queries) {
|
||||
MultiMap<VirtualFile, Integer> result = MultiMap.create();
|
||||
for (Location location : queries.keySet()) {
|
||||
MultiMap<VirtualFile, Integer> offsets = getOffsetsForLocation(descriptor, location, queries.get(location));
|
||||
result.putAllValues(offsets);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
logIfLarge(offsets, location);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<? extends PsiFunctionalExpression> result = exprs.values();
|
||||
LOG.info("checking " + result.size() + " fun-expressions in " + exprs.size() + " files");
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("checking " + result.values().size() + " fun-expressions in " + result.keySet().size() + " files");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void logIfLarge(MultiMap<VirtualFile, Integer> offsets, Location location) {
|
||||
int delta = offsets.values().size();
|
||||
if (delta > 5) {
|
||||
String sample = offsets.entrySet().stream().limit(10).map(e -> e.getKey().getName() + "->" + e.getValue()).collect(Collectors.joining(", "));
|
||||
LOG.debug(delta + " expressions for " + location + "; " + sample);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static MultiMap<VirtualFile, Integer> getOffsetsForLocation(SamDescriptor descriptor, Location location, Collection<GlobalSearchScope> scopes) {
|
||||
MultiMap<VirtualFile, Integer> map = MultiMap.create();
|
||||
ReadAction.run(() -> {
|
||||
ProgressManager.checkCanceled();
|
||||
GlobalSearchScope combinedScope = descriptor.useScope.intersectWith(
|
||||
GlobalSearchScope.union(scopes.toArray(new GlobalSearchScope[0])));
|
||||
for (FunctionalExpressionKey key : descriptor.generateKeys(location)) {
|
||||
FileBasedIndex.getInstance().processValues(JavaFunctionalExpressionIndex.INDEX_ID, key, null, (file, offsets) -> {
|
||||
for (int i : offsets.toNativeArray()) {
|
||||
map.putValue(file, i);
|
||||
}
|
||||
return true;
|
||||
}, new JavaSourceFilterScope(combinedScope));
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static MultiMap<Location, GlobalSearchScope> collectQueryKeys(SamDescriptor descriptor, Set<Module> candidateModules) {
|
||||
MultiMap<Location, GlobalSearchScope> queries = MultiMap.createSet();
|
||||
@@ -273,7 +308,7 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
Project project = descriptor.samClass.getProject();
|
||||
index.processElements(key, assertNotNull(descriptor.samClass.getName()), project, descriptor.useScope.intersectWith(visibleFromCandidates), PsiMethod.class, methodProcessor);
|
||||
index.processElements(key, JavaMethodElementType.TYPE_PARAMETER_PSEUDO_NAME, project, visibleFromCandidates, PsiMethod.class, methodProcessor);
|
||||
LOG.info("#methods: " + methods.size());
|
||||
LOG.debug("#methods: " + methods.size());
|
||||
return methods;
|
||||
}
|
||||
});
|
||||
@@ -282,7 +317,7 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
@NotNull
|
||||
private static Set<String> collectMethodNamesCalledWithFunExpressions(SamDescriptor descriptor) {
|
||||
Set<String> usedMethodNames = new HashSet<>();
|
||||
StubIndex.getInstance().processAllKeys(JavaStubIndexKeys.FUNCTIONAL_EXPRESSIONS, key -> {
|
||||
FileBasedIndex.getInstance().processAllKeys(JavaFunctionalExpressionIndex.INDEX_ID, key -> {
|
||||
ProgressManager.checkCanceled();
|
||||
if (key.canRepresent(descriptor.samParamCount, descriptor.booleanCompatible, descriptor.isVoid) &&
|
||||
key.location instanceof CallLocation) {
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.java.stubs;
|
||||
package com.intellij.psi.impl.java;
|
||||
|
||||
import com.intellij.lang.LighterAST;
|
||||
import com.intellij.lang.LighterASTNode;
|
||||
+2
-210
@@ -17,31 +17,14 @@ package com.intellij.psi.impl.java.stubs;
|
||||
|
||||
import com.intellij.lang.LighterAST;
|
||||
import com.intellij.lang.LighterASTNode;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiBinaryExpression;
|
||||
import com.intellij.psi.PsiFunctionalExpression;
|
||||
import com.intellij.psi.impl.java.stubs.FunctionalExpressionKey.CoarseType;
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaStubIndexKeys;
|
||||
import com.intellij.psi.impl.source.Constants;
|
||||
import com.intellij.psi.impl.source.JavaLightTreeUtil;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.impl.source.tree.LightTreeUtil;
|
||||
import com.intellij.psi.impl.source.tree.RecursiveLighterASTNodeWalkingVisitor;
|
||||
import com.intellij.psi.stubs.IndexSink;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.psi.stubs.StubInputStream;
|
||||
import com.intellij.psi.stubs.StubOutputStream;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.intellij.psi.impl.source.tree.JavaElementType.*;
|
||||
|
||||
public abstract class FunctionalExpressionElementType<T extends PsiFunctionalExpression> extends JavaStubElementType<FunctionalExpressionStub<T>,T> {
|
||||
public FunctionalExpressionElementType(String debugName) {
|
||||
@@ -50,211 +33,20 @@ public abstract class FunctionalExpressionElementType<T extends PsiFunctionalExp
|
||||
|
||||
@Override
|
||||
public void serialize(@NotNull FunctionalExpressionStub<T> stub, @NotNull StubOutputStream dataStream) throws IOException {
|
||||
stub.getIndexKey().serializeKey(dataStream);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FunctionalExpressionStub<T> deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
|
||||
return new FunctionalExpressionStub<T>(parentStub, this, FunctionalExpressionKey.deserializeKey(dataStream));
|
||||
return new FunctionalExpressionStub<T>(parentStub, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void indexStub(@NotNull FunctionalExpressionStub<T> stub, @NotNull IndexSink sink) {
|
||||
sink.occurrence(JavaStubIndexKeys.FUNCTIONAL_EXPRESSIONS, stub.getIndexKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionalExpressionStub<T> createStub(LighterAST tree, LighterASTNode funExpr, StubElement parentStub) {
|
||||
return new FunctionalExpressionStub<T>(parentStub, this,
|
||||
new FunctionalExpressionKey(getFunExprParameterCount(tree, funExpr),
|
||||
calcType(tree, funExpr),
|
||||
calcLocation(tree, funExpr)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static FunctionalExpressionKey.Location calcLocation(LighterAST tree, LighterASTNode funExpr) {
|
||||
LighterASTNode call = getContainingCall(tree, funExpr);
|
||||
List<LighterASTNode> args = JavaLightTreeUtil.getArgList(tree, call);
|
||||
int argIndex = args == null ? -1 : getArgIndex(args, funExpr);
|
||||
String methodName = call == null ? null : getCalledMethodName(tree, call);
|
||||
return methodName == null || argIndex < 0
|
||||
? createTypedLocation(tree, funExpr)
|
||||
: new FunctionalExpressionKey.CallLocation(methodName, args.size(), argIndex, StreamApiDetector.isStreamApiCall(tree, call));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static FunctionalExpressionKey.Location createTypedLocation(LighterAST tree, LighterASTNode funExpr) {
|
||||
LighterASTNode scope = skipExpressionsUp(tree, funExpr, TokenSet.create(LOCAL_VARIABLE, FIELD, TYPE_CAST_EXPRESSION, RETURN_STATEMENT));
|
||||
if (scope != null) {
|
||||
if (scope.getTokenType() == RETURN_STATEMENT) {
|
||||
scope = LightTreeUtil.getParentOfType(tree, scope,
|
||||
TokenSet.create(METHOD),
|
||||
TokenSet.orSet(ElementType.MEMBER_BIT_SET, TokenSet.create(LAMBDA_EXPRESSION)));
|
||||
}
|
||||
|
||||
LighterASTNode typeElement = LightTreeUtil.firstChildOfType(tree, scope, TYPE);
|
||||
String typeText = JavaLightTreeUtil.getNameIdentifierText(tree, LightTreeUtil.firstChildOfType(tree, typeElement, JAVA_CODE_REFERENCE));
|
||||
if (typeText != null) {
|
||||
return new FunctionalExpressionKey.TypedLocation(typeText);
|
||||
}
|
||||
}
|
||||
return FunctionalExpressionKey.Location.UNKNOWN;
|
||||
}
|
||||
|
||||
private static int getArgIndex(List<LighterASTNode> args, LighterASTNode expr) {
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
if (args.get(i).getEndOffset() >= expr.getEndOffset()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static CoarseType calcType(final LighterAST tree, LighterASTNode funExpr) {
|
||||
if (funExpr.getTokenType() == METHOD_REF_EXPRESSION) return CoarseType.UNKNOWN;
|
||||
|
||||
LighterASTNode block = LightTreeUtil.firstChildOfType(tree, funExpr, CODE_BLOCK);
|
||||
if (block == null) {
|
||||
LighterASTNode expr = findExpressionChild(funExpr, tree);
|
||||
return isBooleanExpression(tree, expr) ? CoarseType.BOOLEAN : CoarseType.UNKNOWN;
|
||||
}
|
||||
|
||||
final Ref<Boolean> returnsSomething = Ref.create(null);
|
||||
final AtomicBoolean isBoolean = new AtomicBoolean();
|
||||
final AtomicBoolean hasStatements = new AtomicBoolean();
|
||||
new RecursiveLighterASTNodeWalkingVisitor(tree) {
|
||||
@Override
|
||||
public void visitNode(@NotNull LighterASTNode element) {
|
||||
IElementType type = element.getTokenType();
|
||||
if (type == LAMBDA_EXPRESSION || ElementType.MEMBER_BIT_SET.contains(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == RETURN_STATEMENT) {
|
||||
LighterASTNode expr = findExpressionChild(element, tree);
|
||||
returnsSomething.set(expr != null);
|
||||
if (isBooleanExpression(tree, expr)) {
|
||||
isBoolean.set(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == EXPRESSION_STATEMENT) {
|
||||
hasStatements.set(true);
|
||||
}
|
||||
|
||||
super.visitNode(element);
|
||||
}
|
||||
}.visitNode(block);
|
||||
|
||||
if (isBoolean.get()) {
|
||||
return CoarseType.BOOLEAN;
|
||||
}
|
||||
|
||||
if (returnsSomething.isNull()) {
|
||||
return hasStatements.get() ? CoarseType.VOID : CoarseType.UNKNOWN;
|
||||
}
|
||||
|
||||
return returnsSomething.get() ? CoarseType.NON_VOID : CoarseType.VOID;
|
||||
}
|
||||
|
||||
private static LighterASTNode findExpressionChild(@NotNull LighterASTNode element, LighterAST tree) {
|
||||
return LightTreeUtil.firstChildOfType(tree, element, ElementType.EXPRESSION_BIT_SET);
|
||||
}
|
||||
|
||||
private static boolean isBooleanExpression(LighterAST tree, @Nullable LighterASTNode expr) {
|
||||
if (expr == null) return false;
|
||||
|
||||
IElementType type = expr.getTokenType();
|
||||
if (type == LITERAL_EXPRESSION) {
|
||||
IElementType child = tree.getChildren(expr).get(0).getTokenType();
|
||||
return child == JavaTokenType.TRUE_KEYWORD || child == JavaTokenType.FALSE_KEYWORD;
|
||||
}
|
||||
if (type == POLYADIC_EXPRESSION || type == BINARY_EXPRESSION) {
|
||||
return LightTreeUtil.firstChildOfType(tree, expr, PsiBinaryExpression.BOOLEAN_OPERATION_TOKENS) != null;
|
||||
}
|
||||
if (type == PREFIX_EXPRESSION) {
|
||||
return tree.getChildren(expr).get(0).getTokenType() == JavaTokenType.EXCL;
|
||||
}
|
||||
if (type == PARENTH_EXPRESSION) {
|
||||
return isBooleanExpression(tree, findExpressionChild(expr, tree));
|
||||
}
|
||||
if (type == CONDITIONAL_EXPRESSION) {
|
||||
List<LighterASTNode> children = LightTreeUtil.getChildrenOfType(tree, expr, ElementType.EXPRESSION_BIT_SET);
|
||||
return children.size() == 3 && (isBooleanExpression(tree, children.get(1)) || isBooleanExpression(tree, children.get(2)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int getFunExprParameterCount(LighterAST tree, LighterASTNode funExpr) {
|
||||
if (funExpr.getTokenType() == METHOD_REF_EXPRESSION) return FunctionalExpressionKey.UNKNOWN_PARAM_COUNT;
|
||||
|
||||
assert funExpr.getTokenType() == LAMBDA_EXPRESSION;
|
||||
|
||||
LighterASTNode paramList = LightTreeUtil.firstChildOfType(tree, funExpr, PARAMETER_LIST);
|
||||
assert paramList != null;
|
||||
return LightTreeUtil.getChildrenOfType(tree, paramList, Constants.PARAMETER_BIT_SET).size();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getCalledMethodName(LighterAST tree, LighterASTNode call) {
|
||||
if (call.getTokenType() == NEW_EXPRESSION) {
|
||||
LighterASTNode anonClass = LightTreeUtil.firstChildOfType(tree, call, ANONYMOUS_CLASS);
|
||||
LighterASTNode ref = LightTreeUtil.firstChildOfType(tree, anonClass != null ? anonClass : call, JAVA_CODE_REFERENCE);
|
||||
return ref == null ? null : JavaLightTreeUtil.getNameIdentifierText(tree, ref);
|
||||
}
|
||||
|
||||
LighterASTNode methodExpr = tree.getChildren(call).get(0);
|
||||
if (LightTreeUtil.firstChildOfType(tree, methodExpr, JavaTokenType.SUPER_KEYWORD) != null) {
|
||||
return getSuperClassName(tree, call);
|
||||
}
|
||||
if (LightTreeUtil.firstChildOfType(tree, methodExpr, JavaTokenType.THIS_KEYWORD) != null) {
|
||||
return JavaLightTreeUtil.getNameIdentifierText(tree, findClass(tree, call));
|
||||
}
|
||||
|
||||
return JavaLightTreeUtil.getNameIdentifierText(tree, methodExpr);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getSuperClassName(LighterAST tree, LighterASTNode call) {
|
||||
LighterASTNode aClass = findClass(tree, call);
|
||||
LighterASTNode extendsList = LightTreeUtil.firstChildOfType(tree, aClass, EXTENDS_LIST);
|
||||
return JavaLightTreeUtil.getNameIdentifierText(tree, LightTreeUtil.firstChildOfType(tree, extendsList, JAVA_CODE_REFERENCE));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LighterASTNode getContainingCall(LighterAST tree, LighterASTNode node) {
|
||||
LighterASTNode expressionList = skipExpressionsUp(tree, node, TokenSet.create(EXPRESSION_LIST));
|
||||
if (expressionList != null) {
|
||||
LighterASTNode parent = tree.getParent(expressionList);
|
||||
if (parent != null && parent.getTokenType() == ANONYMOUS_CLASS) {
|
||||
parent = tree.getParent(parent);
|
||||
}
|
||||
if (parent != null && (parent.getTokenType() == METHOD_CALL_EXPRESSION || parent.getTokenType() == NEW_EXPRESSION)) {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static LighterASTNode skipExpressionsUp(LighterAST tree, @NotNull LighterASTNode node, TokenSet types) {
|
||||
node = tree.getParent(node);
|
||||
while (node != null) {
|
||||
final IElementType type = node.getTokenType();
|
||||
if (types.contains(type)) return node;
|
||||
if (type != PARENTH_EXPRESSION && type != CONDITIONAL_EXPRESSION) return null;
|
||||
node = tree.getParent(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static LighterASTNode findClass(LighterAST tree, LighterASTNode node) {
|
||||
while (node != null) {
|
||||
final IElementType type = node.getTokenType();
|
||||
if (type == CLASS) return node;
|
||||
node = tree.getParent(node);
|
||||
}
|
||||
return null;
|
||||
return new FunctionalExpressionStub<T>(parentStub, this);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-9
@@ -19,19 +19,11 @@ import com.intellij.psi.PsiFunctionalExpression;
|
||||
import com.intellij.psi.stubs.IStubElementType;
|
||||
import com.intellij.psi.stubs.StubBase;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class FunctionalExpressionStub<T extends PsiFunctionalExpression> extends StubBase<T> {
|
||||
@NotNull private final FunctionalExpressionKey myIndexKey;
|
||||
|
||||
protected FunctionalExpressionStub(StubElement parent,
|
||||
IStubElementType elementType, @NotNull FunctionalExpressionKey indexKey) {
|
||||
protected FunctionalExpressionStub(StubElement parent, IStubElementType elementType) {
|
||||
super(parent, elementType);
|
||||
myIndexKey = indexKey;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionalExpressionKey getIndexKey() {
|
||||
return myIndexKey;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.intellij.psi.impl.java.stubs.index;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.stubs.FunctionalExpressionKey;
|
||||
import com.intellij.psi.stubs.StubIndexKey;
|
||||
|
||||
/**
|
||||
@@ -32,7 +31,6 @@ public class JavaStubIndexKeys {
|
||||
public static final StubIndexKey<String, PsiAnonymousClass> ANONYMOUS_BASEREF = StubIndexKey.createIndexKey("java.anonymous.baseref");
|
||||
public static final StubIndexKey<String, PsiMethod> METHOD_TYPES = StubIndexKey.createIndexKey("java.method.parameter.types");
|
||||
public static final StubIndexKey<String, PsiClass> CLASS_SHORT_NAMES = StubIndexKey.createIndexKey("java.class.shortname");
|
||||
public static final StubIndexKey<FunctionalExpressionKey, PsiFunctionalExpression> FUNCTIONAL_EXPRESSIONS = StubIndexKey.createIndexKey("java.functional.expressions");
|
||||
public static final StubIndexKey<Integer, PsiClass> CLASS_FQN = StubIndexKey.createIndexKey("java.class.fqn");
|
||||
public static final StubIndexKey<String, PsiJavaModule> MODULE_NAMES = StubIndexKey.createIndexKey("java.module.name");
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ import java.io.IOException;
|
||||
* @author max
|
||||
*/
|
||||
public class JavaFileElementType extends ILightStubFileElementType<PsiJavaFileStub> {
|
||||
public static final int STUB_VERSION = 34;
|
||||
public static final int STUB_VERSION = 35;
|
||||
|
||||
public JavaFileElementType() {
|
||||
super("java.FILE", JavaLanguage.INSTANCE);
|
||||
@@ -56,6 +56,10 @@ public class JavaFileElementType extends ILightStubFileElementType<PsiJavaFileSt
|
||||
|
||||
@Override
|
||||
public boolean shouldBuildStubFor(final VirtualFile file) {
|
||||
return isInSourceContent(file);
|
||||
}
|
||||
|
||||
public static boolean isInSourceContent(@NotNull VirtualFile file) {
|
||||
final VirtualFile dir = file.getParent();
|
||||
return dir == null || dir.getUserData(LanguageLevel.KEY) != null;
|
||||
}
|
||||
|
||||
@@ -1541,8 +1541,8 @@
|
||||
<stubIndex implementation="com.intellij.psi.impl.java.stubs.index.JavaSuperClassNameOccurenceIndex"/>
|
||||
<stubIndex implementation="com.intellij.psi.impl.java.stubs.index.JavaMethodParameterTypesIndex"/>
|
||||
<stubIndex implementation="com.intellij.psi.impl.java.stubs.index.JavaModuleNameIndex"/>
|
||||
<stubIndex implementation="com.intellij.psi.impl.java.stubs.index.JavaFunctionalExpressionIndex"/>
|
||||
|
||||
<fileBasedIndex implementation="com.intellij.psi.impl.java.JavaFunctionalExpressionIndex"/>
|
||||
<fileBasedIndex implementation="com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisIndex"/>
|
||||
<fileBasedIndex implementation="com.intellij.psi.RefQueueIndex"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user