Fix caching of light class data for nested classes

This commit is contained in:
Alexey Sedunov
2013-12-17 17:03:51 +04:00
parent 09642df623
commit 1d03f9f151
31 changed files with 378 additions and 54 deletions
@@ -367,4 +367,40 @@ public class CodegenBinding {
return null;
}
@NotNull
public static Collection<ClassDescriptor> getAllInnerClasses(
@NotNull BindingContext bindingContext, @NotNull ClassDescriptor outermostClass
) {
Collection<ClassDescriptor> innerClasses = bindingContext.get(INNER_CLASSES, outermostClass);
if (innerClasses == null || innerClasses.isEmpty()) return Collections.emptySet();
Set<ClassDescriptor> allInnerClasses = new HashSet<ClassDescriptor>();
Deque<ClassDescriptor> stack = new ArrayDeque<ClassDescriptor>(innerClasses);
do {
ClassDescriptor currentClass = stack.pop();
if (allInnerClasses.add(currentClass)) {
Collection<ClassDescriptor> nextClasses = bindingContext.get(INNER_CLASSES, currentClass);
if (nextClasses != null) {
for (ClassDescriptor nextClass : nextClasses) {
stack.push(nextClass);
}
}
}
} while (!stack.isEmpty());
return allInnerClasses;
}
@NotNull
public static String getJvmInternalName(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) {
Type asmType = bindingContext.get(CodegenBinding.ASM_TYPE, classDescriptor);
assert (asmType != null);
String jvmInternalName = asmType.getClassName();
assert (jvmInternalName != null);
return jvmInternalName;
}
}
@@ -1,29 +0,0 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.asJava
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.resolve.BindingContext
import com.intellij.psi.PsiElement
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
data class GeneratedLightClassData(
val javaFileStub: PsiJavaFileStub,
val jvmInternalName: String,
val descriptor: ClassDescriptor?
)
@@ -34,10 +34,10 @@ import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.NamespaceCodegen;
import org.jetbrains.jet.codegen.binding.CodegenBinding;
@@ -48,13 +48,15 @@ import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.lang.InlineUtil;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
public class KotlinJavaFileStubProvider implements CachedValueProvider<GeneratedLightClassData> {
public class KotlinJavaFileStubProvider implements CachedValueProvider<LightClassStubWithData> {
@NotNull
public static KotlinJavaFileStubProvider createForPackageClass(
@@ -82,8 +84,8 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<Generated
@NotNull
@Override
public GeneratedLightClassData createStubWithName(PsiJavaFileStub javaFileStub, BindingContext bindingContext) {
return new GeneratedLightClassData(javaFileStub, "", null);
public LightClassStubWithData createLightClassStubWithData(PsiJavaFileStub javaFileStub, BindingContext bindingContext) {
return new LightClassStubWithData(javaFileStub, KotlinPackageLightClassData.instance$);
}
@NotNull
@@ -120,17 +122,32 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<Generated
@NotNull
@Override
public GeneratedLightClassData createStubWithName(PsiJavaFileStub javaFileStub, BindingContext bindingContext) {
public LightClassStubWithData createLightClassStubWithData(PsiJavaFileStub javaFileStub, BindingContext bindingContext) {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject);
assert (classDescriptor != null);
Type asmType = bindingContext.get(CodegenBinding.ASM_TYPE, classDescriptor);
assert (asmType != null);
String jvmInternalName = CodegenBinding.getJvmInternalName(bindingContext, classDescriptor);
Collection<ClassDescriptor> allInnerClasses = CodegenBinding.getAllInnerClasses(bindingContext, classDescriptor);
String jvmInternalName = asmType.getClassName();
assert (jvmInternalName != null);
Map<JetClassOrObject, LightClassDataForKotlinClass> innerClassesMap = ContainerUtil.newHashMap();
for (ClassDescriptor innerClassDescriptor : allInnerClasses) {
JetClassOrObject innerClass = (JetClassOrObject) BindingContextUtils.descriptorToDeclaration(
bindingContext, innerClassDescriptor
);
if (innerClass == null) continue;
return new GeneratedLightClassData(javaFileStub, jvmInternalName, classDescriptor);
InnerKotlinClassLightClassData innerLightClassData = new InnerKotlinClassLightClassData(
CodegenBinding.getJvmInternalName(bindingContext, innerClassDescriptor),
innerClass,
innerClassDescriptor
);
innerClassesMap.put(innerClass, innerLightClassData);
}
return new LightClassStubWithData(
javaFileStub,
new OutermostKotlinClassLightClassData(jvmInternalName, classOrObject, classDescriptor, innerClassesMap)
);
}
@NotNull
@@ -173,7 +190,7 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<Generated
@Nullable
@Override
public Result<GeneratedLightClassData> compute() {
public Result<LightClassStubWithData> compute() {
FqName packageFqName = stubGenerationStrategy.getPackageFqName();
Collection<JetFile> files = stubGenerationStrategy.getFiles();
@@ -221,7 +238,7 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<Generated
}
return Result.create(
stubGenerationStrategy.createStubWithName(javaFileStub, bindingContext),
stubGenerationStrategy.createLightClassStubWithData(javaFileStub, bindingContext),
local ? PsiModificationTracker.MODIFICATION_COUNT : PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
);
}
@@ -283,7 +300,7 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<Generated
private interface StubGenerationStrategy {
@NotNull LightClassConstructionContext createLightClassConstructionContext(@NotNull Collection<JetFile> files);
@NotNull
GeneratedLightClassData createStubWithName(PsiJavaFileStub javaFileStub, BindingContext bindingContext);
LightClassStubWithData createLightClassStubWithData(PsiJavaFileStub javaFileStub, BindingContext bindingContext);
@NotNull Collection<JetFile> getFiles();
@NotNull FqName getPackageFqName();
boolean generateDeclaredClasses();
@@ -42,7 +42,8 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.binding.PsiCodegenPredictor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.ResolvePackage;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker;
import org.jetbrains.jet.lang.resolve.name.FqName;
@@ -59,7 +60,7 @@ import java.util.List;
import static org.jetbrains.jet.lexer.JetTokens.*;
public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightClass implements KotlinLightClass, JetJavaMirrorMarker {
private final static Key<CachedValue<GeneratedLightClassData>> JAVA_API_STUB = Key.create("JAVA_API_STUB");
private final static Key<CachedValue<LightClassStubWithData>> JAVA_API_STUB = Key.create("JAVA_API_STUB");
@Nullable
public static KotlinLightClassForExplicitDeclaration create(@NotNull PsiManager manager, @NotNull JetClassOrObject classOrObject) {
@@ -77,7 +78,7 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC
private static String getJvmInternalName(JetClassOrObject classOrObject) {
if (JetPsiUtil.isLocal(classOrObject)) {
return getGeneratedLightClassData(classOrObject).getJvmInternalName();
return getLightClassDataExactly(classOrObject).getJvmInternalName();
}
return PsiCodegenPredictor.getPredefinedJvmInternalName(classOrObject);
}
@@ -156,24 +157,21 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC
@NotNull
private PsiJavaFileStub getJavaFileStub() {
return getGeneratedLightClassData().getJavaFileStub();
return getLightClassStubWithData().getJavaFileStub();
}
@NotNull
private ClassDescriptor getDescriptor() {
ClassDescriptor descriptor = getGeneratedLightClassData().getDescriptor();
assert descriptor != null;
return descriptor;
return getLightClassDataExactly(classOrObject).getDescriptor();
}
@NotNull
private GeneratedLightClassData getGeneratedLightClassData() {
return getGeneratedLightClassData(classOrObject);
private LightClassStubWithData getLightClassStubWithData() {
return getLightClassStubWithData(classOrObject);
}
@NotNull
private static GeneratedLightClassData getGeneratedLightClassData(JetClassOrObject classOrObject) {
private static LightClassStubWithData getLightClassStubWithData(JetClassOrObject classOrObject) {
JetClassOrObject outermostClassOrObject = getOutermostClassOrObject(classOrObject);
return CachedValuesManager.getManager(classOrObject.getProject()).getCachedValue(
outermostClassOrObject,
@@ -183,6 +181,18 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC
);
}
@NotNull
private static LightClassDataForKotlinClass getLightClassDataExactly(JetClassOrObject classOrObject) {
OutermostKotlinClassLightClassData data =
(OutermostKotlinClassLightClassData) getLightClassStubWithData(classOrObject).getClassData();
if (data.getClassOrObject().equals(classOrObject)) return data;
LightClassDataForKotlinClass innerClassData = data.getAllInnerClasses().get(classOrObject);
assert innerClassData != null;
return innerClassData;
}
@NotNull
private static JetClassOrObject getOutermostClassOrObject(@NotNull JetClassOrObject classOrObject) {
JetClassOrObject outermostClass = JetPsiUtil.getOutermostClassOrObject(classOrObject);
@@ -47,7 +47,7 @@ public class KotlinLightClassForPackage extends KotlinWrappingLightClass impleme
private final GlobalSearchScope searchScope;
private final Collection<JetFile> files;
private final int hashCode;
private final CachedValue<GeneratedLightClassData> javaFileStub;
private final CachedValue<LightClassStubWithData> javaFileStub;
private final PsiModifierList modifierList;
private final LightEmptyImplementsList implementsList;
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.asJava
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.psi.JetClassOrObject
trait LightClassData {
val jvmInternalName: String
}
trait LightClassDataForKotlinClass: LightClassData {
val classOrObject: JetClassOrObject
val descriptor: ClassDescriptor
}
object KotlinPackageLightClassData: LightClassData {
override val jvmInternalName: String = ""
}
data class InnerKotlinClassLightClassData(
override val jvmInternalName: String,
override val classOrObject: JetClassOrObject,
override val descriptor: ClassDescriptor
): LightClassDataForKotlinClass
data class OutermostKotlinClassLightClassData(
override val jvmInternalName: String,
override val classOrObject: JetClassOrObject,
override val descriptor: ClassDescriptor,
val allInnerClasses: Map<JetClassOrObject, LightClassDataForKotlinClass>
): LightClassDataForKotlinClass
data class LightClassStubWithData(
val javaFileStub: PsiJavaFileStub,
val classData: LightClassData
)
@@ -0,0 +1,5 @@
// PSI_ELEMENT: com.intellij.psi.PsiClass
// OPTIONS: derivedClasses
public class <caret>A {
}
@@ -0,0 +1,11 @@
public class Outer {
public open class X: A()
public trait T: A
public class Inner {
public open class Y: X()
public class Z: Y(), T
}
}
@@ -0,0 +1,5 @@
Unclassified usage (2: 23) public open class X: A()
Unclassified usage (4: 18) public trait T: A
Unclassified usage (7: 27) public open class Y: X()
Unclassified usage (9: 22) public class Z: Y(), T
Unclassified usage (9: 22) public class Z: Y(), T
@@ -0,0 +1,5 @@
// PSI_ELEMENT: com.intellij.psi.PsiClass
// OPTIONS: derivedClasses
public class <caret>A {
}
@@ -0,0 +1,10 @@
class Outer {
public trait T: A
public object O1: A()
class Inner {
public object O2: T
}
}
@@ -0,0 +1,3 @@
Unclassified usage (2: 18) public trait T: A
Unclassified usage (4: 19) public object O1: A()
Unclassified usage (7: 23) public object O2: T
@@ -0,0 +1,5 @@
// PSI_ELEMENT: com.intellij.psi.PsiClass
// OPTIONS: implementingClasses
public interface <caret>A {
}
@@ -0,0 +1,11 @@
class Outer {
public open class X: A
public trait T: A
class Inner {
public open class Y: X()
public class Z: Y(), T
}
}
@@ -0,0 +1,4 @@
Unclassified usage (2: 23) public open class X: A
Unclassified usage (7: 27) public open class Y: X()
Unclassified usage (9: 22) public class Z: Y(), T
Unclassified usage (9: 22) public class Z: Y(), T
@@ -0,0 +1,5 @@
// PSI_ELEMENT: com.intellij.psi.PsiClass
// OPTIONS: implementingClasses
public interface <caret>A {
}
@@ -0,0 +1,9 @@
class Outer {
public open class T: A
public object O1: A()
class Inner {
public object O2: T()
}
}
@@ -0,0 +1,3 @@
Unclassified usage (2: 23) public open class T: A
Unclassified usage (4: 19) public object O1: A()
Unclassified usage (7: 23) public object O2: T()
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
trait X {
}
open class <caret>A: X {
}
trait Y: X {
}
@@ -0,0 +1,21 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
class Outer {
open class B: A() {
}
open class C: Y {
}
class Inner {
trait Z: A {
}
class U: Z {
}
}
}
@@ -0,0 +1,2 @@
Unclassified usage (17: 15) class U: Z {
Unclassified usage (4: 16) open class B: A() {
@@ -0,0 +1,5 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
open class <caret>A {
}
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
class Outer {
trait Z: A {
}
object O1: A()
class Inner {
object O2: Z
}
}
@@ -0,0 +1,2 @@
Unclassified usage (11: 16) object O2: Z
Unclassified usage (8: 12) object O1: A()
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
trait <caret>X {
}
open class A: X {
}
trait Y: X {
}
@@ -0,0 +1,21 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
class Outer {
open class B: A() {
}
open class C: Y {
}
class Inner {
trait Z: A {
}
trait U: Z {
}
}
}
@@ -0,0 +1,3 @@
Unclassified usage (4: 16) open class B: A() {
Unclassified usage (7: 12) open class A: X {
Unclassified usage (8: 16) open class C: Y {
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
trait <caret>X {
}
open class A: X {
}
trait Y: X {
}
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetClass
// OPTIONS: derivedClasses
class Outer {
object O1: A() {
}
class Inner {
object O2: X {
}
}
}
@@ -0,0 +1,3 @@
Unclassified usage (4: 12) object O1: A() {
Unclassified usage (7: 12) open class A: X {
Unclassified usage (9: 16) object O2: X {
@@ -135,6 +135,16 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
doTest("idea/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedClasses.0.kt");
}
@TestMetadata("kotlinClassDerivedInnerClasses.0.kt")
public void testKotlinClassDerivedInnerClasses() throws Exception {
doTest("idea/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedInnerClasses.0.kt");
}
@TestMetadata("kotlinClassDerivedInnerObjects.0.kt")
public void testKotlinClassDerivedInnerObjects() throws Exception {
doTest("idea/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedInnerObjects.0.kt");
}
@TestMetadata("kotlinClassDerivedLocalClasses.0.kt")
public void testKotlinClassDerivedLocalClasses() throws Exception {
doTest("idea/testData/findUsages/kotlin/findClassUsages/kotlinClassDerivedLocalClasses.0.kt");
@@ -240,6 +250,16 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
doTest("idea/testData/findUsages/kotlin/findClassUsages/kotlinTraitDerivedClasses.0.kt");
}
@TestMetadata("kotlinTraitDerivedInnerClasses.0.kt")
public void testKotlinTraitDerivedInnerClasses() throws Exception {
doTest("idea/testData/findUsages/kotlin/findClassUsages/kotlinTraitDerivedInnerClasses.0.kt");
}
@TestMetadata("kotlinTraitDerivedInnerObjects.0.kt")
public void testKotlinTraitDerivedInnerObjects() throws Exception {
doTest("idea/testData/findUsages/kotlin/findClassUsages/kotlinTraitDerivedInnerObjects.0.kt");
}
@TestMetadata("kotlinTraitDerivedLocalClasses.0.kt")
public void testKotlinTraitDerivedLocalClasses() throws Exception {
doTest("idea/testData/findUsages/kotlin/findClassUsages/kotlinTraitDerivedLocalClasses.0.kt");
@@ -571,6 +591,16 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
doTest("idea/testData/findUsages/java/findJavaClassUsages/JKClassDerivedClasses.0.java");
}
@TestMetadata("JKClassDerivedInnerClasses.0.java")
public void testJKClassDerivedInnerClasses() throws Exception {
doTest("idea/testData/findUsages/java/findJavaClassUsages/JKClassDerivedInnerClasses.0.java");
}
@TestMetadata("JKClassDerivedInnerObjects.0.java")
public void testJKClassDerivedInnerObjects() throws Exception {
doTest("idea/testData/findUsages/java/findJavaClassUsages/JKClassDerivedInnerObjects.0.java");
}
@TestMetadata("JKClassDerivedLocalClasses.0.java")
public void testJKClassDerivedLocalClasses() throws Exception {
doTest("idea/testData/findUsages/java/findJavaClassUsages/JKClassDerivedLocalClasses.0.java");
@@ -616,6 +646,16 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
doTest("idea/testData/findUsages/java/findJavaClassUsages/JKInterfaceDerivedClasses.0.java");
}
@TestMetadata("JKInterfaceDerivedInnerClasses.0.java")
public void testJKInterfaceDerivedInnerClasses() throws Exception {
doTest("idea/testData/findUsages/java/findJavaClassUsages/JKInterfaceDerivedInnerClasses.0.java");
}
@TestMetadata("JKInterfaceDerivedInnerObjects.0.java")
public void testJKInterfaceDerivedInnerObjects() throws Exception {
doTest("idea/testData/findUsages/java/findJavaClassUsages/JKInterfaceDerivedInnerObjects.0.java");
}
@TestMetadata("JKInterfaceDerivedLocalClasses.0.java")
public void testJKInterfaceDerivedLocalClasses() throws Exception {
doTest("idea/testData/findUsages/java/findJavaClassUsages/JKInterfaceDerivedLocalClasses.0.java");