EA-476002 IAE: JavaClassInheritorsSearcher.$$$reportNull$$$0

GitOrigin-RevId: 08b0c9a377283954c4978bad963d2d78f5331cc7
This commit is contained in:
Alexey Kudravtsev
2022-03-30 14:49:01 +02:00
committed by intellij-monorepo-bot
parent 24406fbd3d
commit 9493da7062
2 changed files with 18 additions and 15 deletions

View File

@@ -82,6 +82,10 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, Cla
for (final PsiClass subClass : cached) {
ProgressManager.checkCanceled();
if (subClass == null) {
// PsiAnchor failed to retrieve?
continue;
}
if (ReadAction.compute(() ->
checkCandidate(subClass, parameters) && !consumer.process(subClass))) {
return;
@@ -90,17 +94,17 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, Cla
}
@NotNull
private static Iterable<PsiClass> getOrComputeSubClasses(@NotNull Project project,
@NotNull PsiClass baseClass,
@NotNull SearchScope searchScopeForNonPhysical,
boolean includeAnonymous) {
private static Iterable<@NotNull PsiClass> getOrComputeSubClasses(@NotNull Project project,
@NotNull PsiClass baseClass,
@NotNull SearchScope searchScopeForNonPhysical,
boolean includeAnonymous) {
HighlightingCaches caches = HighlightingCaches.getInstance(project);
ConcurrentMap<PsiClass, Iterable<PsiClass>> map = includeAnonymous ? caches.ALL_SUB_CLASSES : caches.ALL_SUB_CLASSES_NO_ANONYMOUS;
Iterable<PsiClass> cached = map.get(baseClass);
if (cached == null) {
// returns lazy collection of subclasses. Each call to next() leads to calculation of next batch of subclasses.
Function<PsiAnchor, PsiClass> converter =
anchor -> ReadAction.compute(() -> (PsiClass)anchor.retrieve());
Function<@NotNull PsiAnchor, @NotNull PsiClass> converter =
anchor -> ReadAction.compute(() -> (@NotNull PsiClass)anchor.retrieve());
Predicate<PsiClass> applicableFilter =
candidate -> !(candidate instanceof PsiAnonymousClass) && candidate != null && !candidate.hasModifierProperty(PsiModifier.FINAL);
// for non-physical elements ignore the cache completely because non-physical elements created so often/unpredictably so I can't figure out when to clear caches in this case
@@ -109,7 +113,7 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, Cla
LazyConcurrentCollection.MoreElementsGenerator<PsiAnchor, PsiClass> generator = (candidate, processor) ->
DirectClassInheritorsSearch.search(candidate, scopeToUse, includeAnonymous).allowParallelProcessing().forEach(subClass -> {
ProgressManager.checkCanceled();
PsiAnchor pointer = ReadAction.compute(() -> PsiAnchor.create(subClass));
@NotNull PsiAnchor pointer = ReadAction.compute(() -> PsiAnchor.create(subClass));
// append found result to subClasses as early as possible to allow other waiting threads to continue
processor.accept(pointer);
return true;

View File

@@ -37,7 +37,7 @@ class LazyConcurrentCollection<T,V> implements Iterable<V> {
// - 'candidatesToFindSubclassesIterator' points to the next element for which direct inheritors haven't been searched yet.
// - 'subClassIterator' created in AllSubClassesLazyCollection.iterator() maintains state of the AllSubClassesLazyCollection iterator in a lazy fashion.
// If more elements requested for this iterator, the processMoreSubclasses() is called which tries to populate 'subClasses' with more inheritors.
private final HashSetQueue<T> subClasses; // guarded by lock
private final HashSetQueue<@NotNull T> subClasses = new HashSetQueue<>(); // guarded by lock
private final Object lock = new Object(); // MUST NOT acquire read action inside this lock
@NotNull private final Function<? super T, ? extends V> myAnchorToValueConvertor;
@NotNull private final MoreElementsGenerator<? extends T, ? super V> myGenerator;
@@ -58,7 +58,6 @@ class LazyConcurrentCollection<T,V> implements Iterable<V> {
@NotNull Function<? super T, ? extends V> convertor,
@NotNull Predicate<? super V> applicableForGenerationFilter,
@NotNull MoreElementsGenerator<? extends T, ? super V> generator) {
subClasses = new HashSetQueue<>();
subClasses.add(seedElement);
myAnchorToValueConvertor = convertor;
myGenerator = generator;
@@ -68,7 +67,7 @@ class LazyConcurrentCollection<T,V> implements Iterable<V> {
@FunctionalInterface
interface MoreElementsGenerator<T,V> {
void generateMoreElementsFor(@NotNull V element, @NotNull Consumer<? super T> processor);
void generateMoreElementsFor(@NotNull V element, @NotNull Consumer<? super @NotNull T> processor);
}
@NotNull
@@ -107,7 +106,7 @@ class LazyConcurrentCollection<T,V> implements Iterable<V> {
};
}
// polls 'subClasses' for more sub classes and call generator.generateMoreElementsFor() on them
// polls 'subClasses' for more subclasses and call generator.generateMoreElementsFor() on them
// adds found classes to "subClasses" queue
// returns as soon as something was added
private void processMoreSubclasses(@NotNull Iterator<T> subClassIterator) {
@@ -119,7 +118,7 @@ class LazyConcurrentCollection<T,V> implements Iterable<V> {
ProgressManager.checkCanceled();
synchronized (lock) {
// Find the classes in subClasses collection to operate on
// (without advancing the candidatesToFindSubclassesIterator iterator - it will be moved after the class successfully handled - to protect against PCE, INRE, etc)
// (without advancing the candidatesToFindSubclassesIterator iterator - it will be moved after the class successfully handled - to protect against PCE, INRE, etc.)
// The found class will be marked as being analyzed - placed in classesBeingProcessed collection
HashSetQueue.PositionalIterator.IteratorPosition<T> startPosition = candidatesToFindSubclassesIterator.position().next();
Pair.NonNull<T,V> next = startPosition == null ? null : findNextClassInQueue(startPosition);
@@ -147,7 +146,7 @@ class LazyConcurrentCollection<T,V> implements Iterable<V> {
// aaaaaaaa! Other threads were unable to produce anything. That can be because:
// - the whole queue has been processed. => exit, return false
// - the other thread has been interrupted. => check the queue again to pickup the work it dropped.
// - the other thread has been interrupted. => check the queue again to pick up the work it dropped.
synchronized (lock) {
advanceIteratorOnSuccess(); // to skip unsuitable classes like final etc from the queue
if (!candidatesToFindSubclassesIterator.hasNext()) {
@@ -171,7 +170,7 @@ class LazyConcurrentCollection<T,V> implements Iterable<V> {
classesProcessed.add(anchor);
advanceIteratorOnSuccess();
if (subClassIterator.hasNext()) {
// we've added something to subClasses so we can return and the iterator can move forward at least once;
// we've added something to subClasses, so we can return and the iterator can move forward at least once;
// more elements will be added on the subsequent call to .next()
return;
}
@@ -190,7 +189,7 @@ class LazyConcurrentCollection<T,V> implements Iterable<V> {
// Found nothing, have to wait for other threads because:
// The first thread comes and takes a class off the queue to search for inheritors,
// the second thread comes and sees there is no classes in the queue.
// The second thread should not return nothing, it should wait for the first thread to finish.
// The second thread should not return nothing, it should wait for the first thread to finish instead.
//
// Wait within managedBlock to signal FJP this thread is locked (to avoid thread starvation and deadlocks)
AtomicBoolean hasNext = new AtomicBoolean();