From 8d64a1335572ed643158c5acb1ccac29f4faa703 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 26 Aug 2016 17:47:47 +0200 Subject: [PATCH] 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 --- .../impl/PsiClassReferenceListStubImpl.java | 11 ++---- .../psi/impl/source/PsiClassImpl.java | 35 +++++++++++++------ .../com/intellij/psi/JavaStubsTest.groovy | 34 ++++++++++++++++++ 3 files changed, 60 insertions(+), 20 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassReferenceListStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassReferenceListStubImpl.java index 6f5d4c1afe47..0a3bfb6e5bcc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassReferenceListStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassReferenceListStubImpl.java @@ -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 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 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); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java index f44bfb96c9ed..e016b4279670 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java @@ -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> 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)parent).getPsi(); - } + return parent instanceof PsiClassStub ? ((PsiClassStub)parent).getPsi() : null; } PsiElement parent = getParent(); @@ -265,10 +259,29 @@ public class PsiClassImpl extends JavaStubPsiElement> 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 diff --git a/java/java-tests/testSrc/com/intellij/psi/JavaStubsTest.groovy b/java/java-tests/testSrc/com/intellij/psi/JavaStubsTest.groovy index feb672c3e4e8..bfc33f7fc4ef 100644 --- a/java/java-tests/testSrc/com/intellij/psi/JavaStubsTest.groovy +++ b/java/java-tests/testSrc/com/intellij/psi/JavaStubsTest.groovy @@ -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 {}") + def bar = myFixture.addClass("class Bar$i extends Foo$i {}") + + def app = ApplicationManager.application + app.executeOnPooledThread({ ReadAction.compute { bar.node } }) + def superType = app.executeOnPooledThread({ ReadAction.compute { bar.superTypes[0] }} as Callable).get() + assert foo == superType.resolve() + assert bar.typeParameters[0] == PsiUtil.resolveClassInClassTypeOnly(superType.parameters[0]) + } + } } \ No newline at end of file