mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
function expression search optimization: index for method names with function expression argument
This commit is contained in:
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.openapi.project.Project;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.impl.search.JavaSourceFilterScope;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubs.StringStubIndexExtension;
|
||||
import com.intellij.psi.stubs.StubIndex;
|
||||
import com.intellij.psi.stubs.StubIndexKey;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class JavaMethodParameterTypesIndex extends StringStubIndexExtension<PsiMethod> {
|
||||
|
||||
private static final JavaMethodParameterTypesIndex ourInstance = new JavaMethodParameterTypesIndex();
|
||||
public static JavaMethodParameterTypesIndex getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public StubIndexKey<String, PsiMethod> getKey() {
|
||||
return JavaStubIndexKeys.METHOD_TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PsiMethod> get(@NotNull final String s, @NotNull final Project project, @NotNull final GlobalSearchScope scope) {
|
||||
return StubIndex.getElements(getKey(), s, project, new JavaSourceFilterScope(scope), PsiMethod.class);
|
||||
}
|
||||
}
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.search;
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.*;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.DataInputOutputUtil;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class JavaFunctionalExpressionIndex extends FileBasedIndexExtension<String, Collection<JavaFunctionalExpressionIndex.IndexHolder>> implements PsiDependentIndex {
|
||||
public static final ID<String, Collection<IndexHolder>> JAVA_FUNCTIONAL_EXPRESSION_INDEX_ID = ID.create("java.functional.expression");
|
||||
private static final String THIS_REF_NAME = "this";
|
||||
private static final String SUPER_REF_NAME = "super";
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ID<String, Collection<IndexHolder>> getName() {
|
||||
return JAVA_FUNCTIONAL_EXPRESSION_INDEX_ID;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataIndexer<String, Collection<IndexHolder>, FileContent> getIndexer() {
|
||||
return new DataIndexer<String, Collection<IndexHolder>, FileContent>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<String, Collection<IndexHolder>> map(@NotNull FileContent inputData) {
|
||||
final CharSequence contentAsText = inputData.getContentAsText();
|
||||
if (!StringUtil.contains(contentAsText, "::") && !StringUtil.contains(contentAsText, "->")) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
final PsiFile file = ((FileContentImpl)inputData).getPsiFileForPsiDependentIndex();
|
||||
if (!(file instanceof PsiJavaFile) || !JavaStubElementTypes.JAVA_FILE.shouldBuildStubFor(inputData.getFile())) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
final HashMap<String, Collection<IndexHolder>> methodsMap = ContainerUtil.newHashMap();
|
||||
for (PsiFunctionalExpression expression : SyntaxTraverser.psiTraverser().withRoot(file).filter(PsiFunctionalExpression.class)) {
|
||||
final PsiExpressionList expressionList =
|
||||
PsiTreeUtil.getParentOfType(expression, PsiExpressionList.class, true, PsiStatement.class, PsiModifierListOwner.class);
|
||||
if (expressionList != null) {
|
||||
final PsiElement parent = expressionList.getParent();
|
||||
String methodName = null;
|
||||
if (parent instanceof PsiMethodCallExpression) {
|
||||
methodName = ((PsiMethodCallExpression)parent).getMethodExpression().getReferenceName();
|
||||
if (methodName != null) {
|
||||
final boolean thisRef = methodName.equals(THIS_REF_NAME);
|
||||
if (thisRef || methodName.equals(SUPER_REF_NAME)) {
|
||||
methodName = null;
|
||||
final PsiClass containingClass = PsiTreeUtil.getParentOfType(parent, PsiClass.class);
|
||||
if (containingClass != null) {
|
||||
if (thisRef) {
|
||||
methodName = containingClass.getName();
|
||||
} else {
|
||||
final PsiReferenceList extendsList = containingClass.getExtendsList();
|
||||
if (extendsList != null) {
|
||||
final PsiJavaCodeReferenceElement[] referenceElements = extendsList.getReferenceElements();
|
||||
if (referenceElements.length > 0) {
|
||||
methodName = referenceElements[0].getReferenceName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiNewExpression) {
|
||||
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)parent).getClassOrAnonymousClassReference();
|
||||
if (classReference != null) {
|
||||
methodName = classReference.getReferenceName();
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiEnumConstant) {
|
||||
final PsiClass containingClass = ((PsiEnumConstant)parent).getContainingClass();
|
||||
if (containingClass != null) {
|
||||
final String shortEnumName = containingClass.getName();
|
||||
if (shortEnumName != null) { //should be always true as enums can't be local
|
||||
methodName = shortEnumName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (methodName != null) {
|
||||
Collection<IndexHolder> holders = methodsMap.get(methodName);
|
||||
if (holders == null) {
|
||||
holders = new HashSet<IndexHolder>();
|
||||
methodsMap.put(methodName, holders);
|
||||
}
|
||||
holders.add(new IndexHolder(expression instanceof PsiLambdaExpression ? ((PsiLambdaExpression)expression).getParameterList().getParametersCount() : -1,
|
||||
expressionList.getExpressions().length,
|
||||
LambdaUtil.getLambdaIdx(expressionList, expression)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return methodsMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KeyDescriptor<String> getKeyDescriptor() {
|
||||
return EnumeratorStringDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataExternalizer<Collection<IndexHolder>> getValueExternalizer() {
|
||||
return new DataExternalizer<Collection<IndexHolder>>() {
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, Collection<IndexHolder> holders) throws IOException {
|
||||
DataInputOutputUtil.writeINT(out, holders.size());
|
||||
for (IndexHolder holder : holders) {
|
||||
DataInputOutputUtil.writeINT(out, holder.getLambdaParamsNumber());
|
||||
DataInputOutputUtil.writeINT(out, holder.getMethodArgsLength());
|
||||
DataInputOutputUtil.writeINT(out, holder.getFunctionExpressionIndex());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<IndexHolder> read(@NotNull DataInput in) throws IOException {
|
||||
int l = DataInputOutputUtil.readINT(in);
|
||||
final Collection<IndexHolder> holders = new HashSet<IndexHolder>(l);
|
||||
while (l-- > 0) {
|
||||
holders.add(new IndexHolder(DataInputOutputUtil.readINT(in),
|
||||
DataInputOutputUtil.readINT(in),
|
||||
DataInputOutputUtil.readINT(in)));
|
||||
}
|
||||
return holders;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FileBasedIndex.InputFilter getInputFilter() {
|
||||
return new DefaultFileTypeSpecificInputFilter(JavaFileType.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dependsOnFileContent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static class IndexHolder {
|
||||
private final int myLambdaParamsNumber;
|
||||
private final int myMethodArgsLength;
|
||||
private final int myFunctionExpressionIndex;
|
||||
|
||||
public IndexHolder(int lambdaParamsNumber, int methodArgsLength, int functionExpressionIndex) {
|
||||
myLambdaParamsNumber = lambdaParamsNumber;
|
||||
myMethodArgsLength = methodArgsLength;
|
||||
myFunctionExpressionIndex = functionExpressionIndex;
|
||||
}
|
||||
|
||||
public int getLambdaParamsNumber() {
|
||||
return myLambdaParamsNumber;
|
||||
}
|
||||
|
||||
public int getMethodArgsLength() {
|
||||
return myMethodArgsLength;
|
||||
}
|
||||
|
||||
public int getFunctionExpressionIndex() {
|
||||
return myFunctionExpressionIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
IndexHolder holder = (IndexHolder)o;
|
||||
|
||||
if (myLambdaParamsNumber != holder.myLambdaParamsNumber) return false;
|
||||
if (myMethodArgsLength != holder.myMethodArgsLength) return false;
|
||||
if (myFunctionExpressionIndex != holder.myFunctionExpressionIndex) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myLambdaParamsNumber;
|
||||
result = 31 * result + myMethodArgsLength;
|
||||
result = 31 * result + myFunctionExpressionIndex;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+162
-54
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.search;
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadActionProcessor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
@@ -24,26 +24,28 @@ import com.intellij.openapi.module.impl.scopes.ModulesScope;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.LanguageLevelModuleExtension;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.stubs.JavaMethodElementType;
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaMethodParameterTypesIndex;
|
||||
import com.intellij.psi.search.*;
|
||||
import com.intellij.psi.search.searches.FunctionalExpressionSearch;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.QueryExecutor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class JavaFunctionalExpressionSearcher implements QueryExecutor<PsiFunctionalExpression, FunctionalExpressionSearch.SearchParameters> {
|
||||
@@ -86,50 +88,8 @@ public class JavaFunctionalExpressionSearcher implements QueryExecutor<PsiFuncti
|
||||
}), consumer, highLevelModules);
|
||||
}
|
||||
|
||||
public static boolean collectFunctionalExpressions(final PsiClass aClass,
|
||||
final SearchScope searchScope,
|
||||
final Processor<PsiFunctionalExpression> consumer,
|
||||
final Set<Module> highLevelModules) {
|
||||
final Project project = PsiUtilCore.getProjectInReadAction(aClass);
|
||||
final GlobalSearchScope scope = ApplicationManager.getApplication().runReadAction(new Computable<GlobalSearchScope>() {
|
||||
@Override
|
||||
public GlobalSearchScope compute() {
|
||||
return prepareScopeToProcessFiles(highLevelModules, aClass, searchScope, project);
|
||||
}
|
||||
});
|
||||
final ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex();
|
||||
final HashSet<VirtualFile> files = new HashSet<VirtualFile>();
|
||||
CommonProcessors.CollectProcessor<VirtualFile> processor = new CommonProcessors.CollectProcessor<VirtualFile>(files) {
|
||||
@Override
|
||||
protected boolean accept(VirtualFile virtualFile) {
|
||||
return scope.contains(virtualFile) && virtualFile.getFileType() == JavaFileType.INSTANCE && index.isInSource(virtualFile);
|
||||
}
|
||||
};
|
||||
|
||||
final PsiSearchHelperImpl helper = (PsiSearchHelperImpl)PsiSearchHelper.SERVICE.getInstance(project);
|
||||
helper.processFilesWithText(scope, UsageSearchContext.IN_CODE, true, "::", processor);
|
||||
helper.processFilesWithText(scope, UsageSearchContext.IN_CODE, true, "->", processor);
|
||||
LOG.info("#files: " + files.size());
|
||||
|
||||
final PsiManager psiManager = PsiManager.getInstance(project);
|
||||
for (final VirtualFile file : files) {
|
||||
if (!ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
return processFileWithFunctionalInterfaces(aClass, consumer, psiManager, file);
|
||||
}
|
||||
})) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static GlobalSearchScope prepareScopeToProcessFiles(final Set<Module> highLevelModules,
|
||||
final PsiClass aClass,
|
||||
final SearchScope searchScope,
|
||||
final Project project) {
|
||||
final SearchScope useScope = searchScope.intersectWith(aClass.getUseScope());
|
||||
|
||||
private static GlobalSearchScope convertToGlobalScope(Project project, SearchScope useScope) {
|
||||
final GlobalSearchScope scope;
|
||||
if (useScope instanceof GlobalSearchScope) {
|
||||
scope = (GlobalSearchScope)useScope;
|
||||
@@ -145,16 +105,162 @@ public class JavaFunctionalExpressionSearcher implements QueryExecutor<PsiFuncti
|
||||
scope = GlobalSearchScope.filesScope(project, files);
|
||||
}
|
||||
else {
|
||||
scope = new ModulesScope(highLevelModules, project).intersectWith(new EverythingGlobalScope(project));
|
||||
scope = new EverythingGlobalScope(project);
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
public static boolean collectFunctionalExpressions(final PsiClass aClass,
|
||||
final SearchScope searchScope,
|
||||
final Processor<PsiFunctionalExpression> consumer,
|
||||
final Set<Module> highLevelModules) {
|
||||
final Project project = PsiUtilCore.getProjectInReadAction(aClass);
|
||||
final ModulesScope modulesScope = new ModulesScope(highLevelModules, project);
|
||||
final GlobalSearchScope useScope = ApplicationManager.getApplication().runReadAction(new Computable<GlobalSearchScope>() {
|
||||
@Override
|
||||
public GlobalSearchScope compute() {
|
||||
return modulesScope.intersectWith(convertToGlobalScope(project, searchScope.intersectWith(aClass.getUseScope())));
|
||||
}
|
||||
});
|
||||
|
||||
final PsiSearchHelperImpl helper = (PsiSearchHelperImpl)PsiSearchHelper.SERVICE.getInstance(project);
|
||||
final HashSet<VirtualFile> files = new HashSet<VirtualFile>();
|
||||
final CommonProcessors.CollectProcessor<VirtualFile> processor = new CommonProcessors.CollectProcessor<VirtualFile>(files);
|
||||
helper.processFilesWithText(useScope, UsageSearchContext.IN_CODE, true, "::", processor);
|
||||
helper.processFilesWithText(useScope, UsageSearchContext.IN_CODE, true, "->", processor);
|
||||
|
||||
final GlobalSearchScope filesScope = GlobalSearchScope.filesScope(project, files);
|
||||
|
||||
final Collection<PsiMethod> lambdaCandidates = ApplicationManager.getApplication().runReadAction(new Computable<Collection<PsiMethod>>() {
|
||||
@Override
|
||||
public Collection<PsiMethod> compute() {
|
||||
final String functionalInterfaceName = aClass.getName();
|
||||
JavaMethodParameterTypesIndex parameterTypesIndex = JavaMethodParameterTypesIndex.getInstance();
|
||||
|
||||
LinkedHashSet<PsiMethod> methods = new LinkedHashSet<PsiMethod>(parameterTypesIndex.get(functionalInterfaceName, project, useScope));
|
||||
|
||||
methods.addAll(parameterTypesIndex.get(JavaMethodElementType.TYPE_PARAMETER_PSEUDO_NAME, project,
|
||||
GlobalSearchScope.allScope(project)));
|
||||
return methods;
|
||||
}
|
||||
});
|
||||
|
||||
final LinkedHashSet<VirtualFile> usageFiles = new LinkedHashSet<VirtualFile>();
|
||||
final MethodSignature functionalInterfaceMethod = ApplicationManager.getApplication().runReadAction(new Computable<MethodSignature>() {
|
||||
@Override
|
||||
public MethodSignature compute() {
|
||||
return LambdaUtil.getFunction(aClass);
|
||||
}
|
||||
});
|
||||
LOG.assertTrue(functionalInterfaceMethod != null);
|
||||
final int expectedFunExprParamsCount = functionalInterfaceMethod.getParameterTypes().length;
|
||||
final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance();
|
||||
for (final PsiMethod psiMethod : lambdaCandidates) {
|
||||
final int parametersCount = psiMethod.getParameterList().getParametersCount();
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
final boolean varArgs = psiMethod.isVarArgs();
|
||||
final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
|
||||
final GlobalSearchScope methodUseScope = modulesScope.intersectWith(convertToGlobalScope(project, psiMethod.getUseScope()));
|
||||
fileBasedIndex.processValues(JavaFunctionalExpressionIndex.JAVA_FUNCTIONAL_EXPRESSION_INDEX_ID, psiMethod.getName(), null,
|
||||
new FileBasedIndex.ValueProcessor<Collection<JavaFunctionalExpressionIndex.IndexHolder>>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile file, Collection<JavaFunctionalExpressionIndex.IndexHolder> holders) {
|
||||
for (JavaFunctionalExpressionIndex.IndexHolder holder : holders) {
|
||||
if (holder.getLambdaParamsNumber() == expectedFunExprParamsCount &&
|
||||
(varArgs ? holder.getMethodArgsLength() >= parametersCount - 1 : holder.getMethodArgsLength() == parametersCount) &&
|
||||
canBeFunctional(holder)
|
||||
) {
|
||||
usageFiles.add(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean canBeFunctional(JavaFunctionalExpressionIndex.IndexHolder holder) {
|
||||
final int paramIdx = holder.getFunctionExpressionIndex();
|
||||
final PsiClass functionalCandidate = PsiUtil.resolveClassInClassTypeOnly(parameters[paramIdx].getType());
|
||||
return functionalCandidate instanceof PsiTypeParameter ||
|
||||
LambdaUtil.isFunctionalClass(functionalCandidate);
|
||||
}
|
||||
}, useScope.intersectWith(methodUseScope));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new ModulesScope(highLevelModules, project).intersectWith(scope);
|
||||
collectFilesWithAssignments(aClass, filesScope, usageFiles);
|
||||
|
||||
LOG.info("#usage files: " + usageFiles.size());
|
||||
return ContainerUtil.process(usageFiles, new ReadActionProcessor<VirtualFile>() {
|
||||
@Override
|
||||
public boolean processInReadAction(VirtualFile file) {
|
||||
return processFileWithFunctionalInterfaces(aClass, expectedFunExprParamsCount, consumer, file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect files where:
|
||||
* aClass is used, e.g. in type declaration or method return type;
|
||||
* fields with type aClass are used on the left side of assignments. Should find Bar of the following example
|
||||
<pre/>
|
||||
class Foo {
|
||||
Runnable myRunnable;
|
||||
}
|
||||
|
||||
class Bar {
|
||||
void foo(Foo foo){
|
||||
foo.myRunnable = () -> {};
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
*/
|
||||
private static void collectFilesWithAssignments(PsiClass aClass,
|
||||
GlobalSearchScope filesScope,
|
||||
final LinkedHashSet<VirtualFile> usageFiles) {
|
||||
final Set<PsiField> fields = new LinkedHashSet<PsiField>();
|
||||
for (final PsiReference reference : ReferencesSearch.search(aClass, filesScope)) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final PsiElement element = reference.getElement();
|
||||
if (element != null) {
|
||||
ContainerUtil.addIfNotNull(usageFiles, PsiUtilCore.getVirtualFile(element));
|
||||
final PsiElement parent = element.getParent();
|
||||
if (parent instanceof PsiTypeElement) {
|
||||
final PsiElement gParent = parent.getParent();
|
||||
if (gParent instanceof PsiField &&
|
||||
!((PsiField)gParent).hasModifierProperty(PsiModifier.PRIVATE) &&
|
||||
!((PsiField)gParent).hasModifierProperty(PsiModifier.FINAL)) {
|
||||
fields.add((PsiField)gParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (PsiField field : fields) {
|
||||
ReferencesSearch.search(field, filesScope).forEach(new ReadActionProcessor<PsiReference>() {
|
||||
@Override
|
||||
public boolean processInReadAction(PsiReference fieldRef) {
|
||||
final PsiElement fieldElement = fieldRef.getElement();
|
||||
final PsiAssignmentExpression varElementParent = PsiTreeUtil.getParentOfType(fieldElement, PsiAssignmentExpression.class);
|
||||
if (varElementParent != null && PsiTreeUtil.isAncestor(varElementParent.getLExpression(), fieldElement, false)) {
|
||||
ContainerUtil.addIfNotNull(usageFiles, PsiUtilCore.getVirtualFile(fieldElement));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean processFileWithFunctionalInterfaces(final PsiClass aClass,
|
||||
final int expectedParamCount,
|
||||
final Processor<PsiFunctionalExpression> consumer,
|
||||
final PsiManager psiManager, VirtualFile file) {
|
||||
final PsiFile psiFile = psiManager.findFile(file);
|
||||
VirtualFile file) {
|
||||
final PsiFile psiFile = aClass.getManager().findFile(file);
|
||||
if (psiFile != null) {
|
||||
final Ref<Boolean> ref = new Ref<Boolean>(true);
|
||||
psiFile.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@@ -178,7 +284,9 @@ public class JavaFunctionalExpressionSearcher implements QueryExecutor<PsiFuncti
|
||||
@Override
|
||||
public void visitLambdaExpression(PsiLambdaExpression expression) {
|
||||
super.visitLambdaExpression(expression);
|
||||
visitFunctionalExpression(expression);
|
||||
if (expression.getParameterList().getParametersCount() == expectedParamCount) {
|
||||
visitFunctionalExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user