fix some stub/AST inconsistencies in java PsiClass

* getContainingClass worked differently for local classes
* supertype generic parameters could be resolved to null if AST loading occurred concurrently
This commit is contained in:
peter
2016-08-26 17:52:23 +02:00
parent da17a27b35
commit 8d64a13355
3 changed files with 60 additions and 20 deletions
@@ -19,8 +19,6 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.compiled.ClsJavaCodeReferenceElementImpl;
import com.intellij.psi.impl.java.stubs.JavaClassReferenceListElementType;
import com.intellij.psi.impl.java.stubs.PsiClassReferenceListStub;
import com.intellij.psi.impl.java.stubs.PsiClassStub;
import com.intellij.psi.impl.source.PsiClassImpl;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl;
import com.intellij.psi.stubs.StubBase;
@@ -72,7 +70,7 @@ public class PsiClassReferenceListStubImpl extends StubBase<PsiReferenceList> im
final boolean compiled = ((JavaClassReferenceListElementType)getStubType()).isCompiled(this);
if (compiled) {
for (int i = 0; i < types.length; i++) {
types[i] = new PsiClassReferenceType(new ClsJavaCodeReferenceElementImpl(getPsi(), StringRef.toString(myNames[i])), null);
types[i] = new PsiClassReferenceType(new ClsJavaCodeReferenceElementImpl(getPsi(), myNames[i].toString()), null);
}
}
else {
@@ -81,13 +79,8 @@ public class PsiClassReferenceListStubImpl extends StubBase<PsiReferenceList> im
int nullCount = 0;
final PsiReferenceList psi = getPsi();
for (int i = 0; i < types.length; i++) {
PsiElement context = psi;
if (getParentStub() instanceof PsiClassStub) {
context = ((PsiClassImpl)getParentStub().getPsi()).calcBasesResolveContext(PsiNameHelper.getShortClassName(StringRef.toString(myNames[i])), psi);
}
try {
final PsiJavaCodeReferenceElement ref = factory.createReferenceFromText(StringRef.toString(myNames[i]), context);
final PsiJavaCodeReferenceElement ref = factory.createReferenceFromText(myNames[i].toString(), psi);
((PsiJavaCodeReferenceElementImpl)ref).setKindWhenDummy(PsiJavaCodeReferenceElementImpl.CLASS_NAME_KIND);
types[i] = factory.createType(ref);
}
@@ -28,10 +28,11 @@ import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.*;
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
import com.intellij.psi.impl.java.stubs.PsiClassInitializerStub;
import com.intellij.psi.impl.java.stubs.PsiClassStub;
import com.intellij.psi.impl.java.stubs.PsiMethodStub;
import com.intellij.psi.impl.source.tree.ChildRole;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.impl.source.tree.SharedImplUtil;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.search.SearchScope;
@@ -40,7 +41,6 @@ import com.intellij.psi.stubs.PsiFileStub;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -245,13 +245,7 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements
final PsiClassStub stub = getStub();
if (stub != null) {
StubElement parent = stub.getParentStub();
while (parent != null && !(parent instanceof PsiClassStub)) {
parent = parent.getParentStub();
}
if (parent != null) {
return ((PsiClassStub<? extends PsiClass>)parent).getPsi();
}
return parent instanceof PsiClassStub ? ((PsiClassStub<?>)parent).getPsi() : null;
}
PsiElement parent = getParent();
@@ -265,10 +259,29 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements
@Override
public PsiElement getContext() {
final PsiClass cc = getContainingClass();
return cc != null ? cc : super.getContext();
StubElement contextStub = getContextStub();
if (contextStub != null) {
return contextStub.getPsi();
}
return super.getContext();
}
@Nullable
private StubElement getContextStub() {
PsiClassStub<?> stub = getStub();
if (stub == null) return null;
// if AST is not loaded, then we only can need context to resolve supertype references
// this can be done by stubs unless there are local/anonymous classes referencing other local classes
StubElement parent = stub.getParentStub();
if (parent instanceof PsiClassInitializerStub || parent instanceof PsiMethodStub) {
if (parent.getChildrenByType(JavaStubElementTypes.CLASS, PsiElement.ARRAY_FACTORY).length <= 1) {
parent = parent.getParentStub();
}
}
return parent instanceof PsiClassStub ? parent : null;
}
@Override
@NotNull
@@ -16,12 +16,18 @@
package com.intellij.psi
import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ReadAction
import com.intellij.psi.impl.source.PsiClassImpl
import com.intellij.psi.impl.source.PsiFileImpl
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.searches.AnnotatedElementsSearch
import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.psi.util.PsiUtil
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import java.util.concurrent.Callable
class JavaStubsTest extends LightCodeInsightFixtureTestCase {
void "test resolve from annotation method default"() {
@@ -95,4 +101,32 @@ class JavaStubsTest extends LightCodeInsightFixtureTestCase {
assert m1.getCanonicalText(true) == "@Foo.TA int"
assert p1.getCanonicalText(true) == "@Foo.TA int"
}
public void "test containing class of an local class is null"() {
def foo = myFixture.addClass("class Foo {{ class Bar extends Foo {} }}")
def bar = ClassInheritorsSearch.search(foo).findFirst()
def file = (PsiFileImpl)foo.containingFile
assert !file.contentsLoaded
assert bar.containingClass == null
assert !file.contentsLoaded
bar.node
assert bar.containingClass == null
assert file.contentsLoaded
}
public void "test stub-based super class type parameter resolve"() {
for (int i = 0; i < 100; i++) {
def foo = myFixture.addClass("class Foo$i<T> {}")
def bar = myFixture.addClass("class Bar$i<T> extends Foo$i<T> {}")
def app = ApplicationManager.application
app.executeOnPooledThread({ ReadAction.compute { bar.node } })
def superType = app.executeOnPooledThread({ ReadAction.compute { bar.superTypes[0] }} as Callable<PsiClassType>).get()
assert foo == superType.resolve()
assert bar.typeParameters[0] == PsiUtil.resolveClassInClassTypeOnly(superType.parameters[0])
}
}
}