Store ABI version along with serialized descriptors

KotlinInfo annotation now has a version() field, which should be equal to the
compiler's JvmAbi.VERSION in order for this class to properly load and be used.

Create ErrorReporter class, which has a trace to which it can report errors
(now only related to ABI version). This is done because a dependency of
DeserializedDescriptorResolver from BindingTrace would be confusing.
Implementation of ErrorReporter will probably need to change when we untie
deserialization from java-resolve.

Check if PsiClass is actually a compiled class before trying to load serialized
data from it: otherwise it can be a Java source, as was in wrongAbiVersion()
test, and ASM will fail when trying to read that file. Rewrite the test so that
it now has a compiled Kotlin classes to check against (also include sources to
recompile this binary data later, although it won't probably be needed)
This commit is contained in:
Alexander Udalov
2013-07-09 21:04:39 +04:00
parent cc4fd008ad
commit 6ae81c3ade
20 changed files with 170 additions and 68 deletions
@@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer;
import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver;
@@ -64,6 +65,7 @@ public class InjectorForJavaDescriptorResolver {
private final JavaSignatureResolver javaSignatureResolver;
private final DeserializedDescriptorResolver deserializedDescriptorResolver;
private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
private final ErrorReporter errorReporter;
private final JavaNamespaceResolver javaNamespaceResolver;
private final JavaConstructorResolver javaConstructorResolver;
private final JavaInnerClassResolver javaInnerClassResolver;
@@ -93,6 +95,7 @@ public class InjectorForJavaDescriptorResolver {
this.javaSignatureResolver = new JavaSignatureResolver();
this.deserializedDescriptorResolver = new DeserializedDescriptorResolver();
this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer();
this.errorReporter = new ErrorReporter();
this.javaNamespaceResolver = new JavaNamespaceResolver();
this.javaConstructorResolver = new JavaConstructorResolver();
this.javaInnerClassResolver = new JavaInnerClassResolver();
@@ -155,12 +158,15 @@ public class InjectorForJavaDescriptorResolver {
javaSignatureResolver.setJavaSemanticServices(javaSemanticServices);
deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer);
deserializedDescriptorResolver.setErrorReporter(errorReporter);
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver);
annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder);
errorReporter.setTrace(bindingTrace);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
@@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer;
import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver;
@@ -64,6 +65,7 @@ public class InjectorForJavaSemanticServices {
private final JavaSignatureResolver javaSignatureResolver;
private final DeserializedDescriptorResolver deserializedDescriptorResolver;
private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
private final ErrorReporter errorReporter;
private final JavaNamespaceResolver javaNamespaceResolver;
private final JavaConstructorResolver javaConstructorResolver;
private final JavaInnerClassResolver javaInnerClassResolver;
@@ -91,6 +93,7 @@ public class InjectorForJavaSemanticServices {
this.javaSignatureResolver = new JavaSignatureResolver();
this.deserializedDescriptorResolver = new DeserializedDescriptorResolver();
this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer();
this.errorReporter = new ErrorReporter();
this.javaNamespaceResolver = new JavaNamespaceResolver();
this.javaConstructorResolver = new JavaConstructorResolver();
this.javaInnerClassResolver = new JavaInnerClassResolver();
@@ -155,12 +158,15 @@ public class InjectorForJavaSemanticServices {
javaSignatureResolver.setJavaSemanticServices(javaSemanticServices);
deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer);
deserializedDescriptorResolver.setErrorReporter(errorReporter);
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver);
annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder);
errorReporter.setTrace(bindingTrace);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
@@ -60,6 +60,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaSignatureResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer;
import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaInnerClassResolver;
@@ -114,6 +115,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
private final JavaSignatureResolver javaSignatureResolver;
private final DeserializedDescriptorResolver deserializedDescriptorResolver;
private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
private final ErrorReporter errorReporter;
private final JavaNamespaceResolver javaNamespaceResolver;
private final JavaConstructorResolver javaConstructorResolver;
private final JavaInnerClassResolver javaInnerClassResolver;
@@ -169,6 +171,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
this.javaSignatureResolver = new JavaSignatureResolver();
this.deserializedDescriptorResolver = new DeserializedDescriptorResolver();
this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer();
this.errorReporter = new ErrorReporter();
this.javaNamespaceResolver = new JavaNamespaceResolver();
this.javaConstructorResolver = new JavaConstructorResolver();
this.javaInnerClassResolver = new JavaInnerClassResolver();
@@ -333,12 +336,15 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
javaSignatureResolver.setJavaSemanticServices(javaSemanticServices);
deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer);
deserializedDescriptorResolver.setErrorReporter(errorReporter);
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
annotationDescriptorDeserializer.setJavaClassResolver(javaClassResolver);
annotationDescriptorDeserializer.setPsiClassFinder(psiClassFinder);
errorReporter.setTrace(bindingTrace);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
@@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.resolve.java;
import com.intellij.psi.PsiClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.java.kt.PsiAnnotationWithAbiVersion;
import org.jetbrains.jet.util.slicedmap.BasicWritableSlice;
import org.jetbrains.jet.util.slicedmap.Slices;
import org.jetbrains.jet.util.slicedmap.WritableSlice;
@@ -29,19 +28,20 @@ public class AbiVersionUtil {
new BasicWritableSlice<PsiClass, Integer>(Slices.ONLY_REWRITE_TO_EQUAL, true);
public static final int INVALID_VERSION = -1;
private AbiVersionUtil() {
}
public static boolean isAbiVersionCompatible(int abiVersion) {
return abiVersion == JvmAbi.VERSION;
}
public static void checkAbiVersion(
@NotNull PsiClass psiClass,
@NotNull PsiAnnotationWithAbiVersion versionAnnotation,
@NotNull BindingTrace trace) {
if (!versionAnnotation.isDefined()) return;
public static void checkAbiVersion(@NotNull PsiClass psiClass, int version, @NotNull BindingTrace trace) {
if (!isAbiVersionCompatible(version)) {
reportIncompatibleAbiVersion(psiClass, version, trace);
}
}
int abiVersion = versionAnnotation.getAbiVersion();
if (isAbiVersionCompatible(abiVersion)) return;
trace.record(ABI_VERSION_ERRORS, psiClass, abiVersion);
public static void reportIncompatibleAbiVersion(@NotNull PsiClass psiClass, int version, @NotNull BindingTrace trace) {
trace.record(ABI_VERSION_ERRORS, psiClass, version);
}
}
@@ -26,7 +26,7 @@ public class JvmAbi {
* This constant is used to identify binary format (class file) versions
* If you change class file metadata format and/or naming conventions, please increase this number
*/
public static final int VERSION = 6;
public static final int VERSION = 7;
public static final String TRAIT_IMPL_CLASS_NAME = "$TImpl";
public static final String TRAIT_IMPL_SUFFIX = "$" + TRAIT_IMPL_CLASS_NAME;
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
import org.jetbrains.jet.lang.resolve.name.FqName;
@@ -44,6 +45,7 @@ import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.asm4.ClassReader.*;
import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCompatible;
import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_KOTLIN;
import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.getVirtualFile;
import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.kotlinFqNameToJavaFqName;
@@ -59,6 +61,8 @@ public final class DeserializedDescriptorResolver {
private JavaClassResolver javaClassResolver;
private ErrorReporter errorReporter;
@NotNull
private final DescriptorFinder javaDescriptorFinder = new DescriptorFinder() {
@Nullable
@@ -89,6 +93,11 @@ public final class DeserializedDescriptorResolver {
this.javaClassResolver = javaClassResolver;
}
@Inject
public void setErrorReporter(ErrorReporter errorReporter) {
this.errorReporter = errorReporter;
}
@Nullable
public ClassDescriptor resolveClass(
@NotNull FqName fqName,
@@ -97,28 +106,25 @@ public final class DeserializedDescriptorResolver {
) {
VirtualFile virtualFile = getVirtualFile(psiClass, fqName, containingDeclaration);
if (virtualFile == null) {
// TODO: use ErrorReporter here
return null;
}
ClassData classData = readClassDataFromClassFile(virtualFile);
ClassData classData = readClassDataFromClassFile(virtualFile, psiClass);
if (classData == null) {
return null;
}
return deserializeClass(classData, fqName, containingDeclaration);
}
@NotNull
public JetScope createKotlinPackageScope(
@NotNull FqName fqName,
@NotNull PsiClass kotlinPackagePsiClass,
@NotNull NamespaceDescriptor packageDescriptor
) {
@Nullable
public JetScope createKotlinPackageScope(@NotNull PsiClass kotlinPackagePsiClass, @NotNull NamespaceDescriptor packageDescriptor) {
VirtualFile virtualFile = kotlinPackagePsiClass.getContainingFile().getVirtualFile();
if (virtualFile == null) {
throw new IllegalStateException("Could not find virtual file for " + fqName.asString());
return null;
}
PackageData packageData = readPackageDataFromClassFile(virtualFile);
PackageData packageData = readPackageDataFromClassFile(virtualFile, kotlinPackagePsiClass);
if (packageData == null) {
throw new IllegalStateException("No KotlinInfo annotation stored for " + fqName.asString());
return null;
}
return DeserializedPackageMemberScope.createScopeFromPackageData(packageDescriptor, packageData, javaDescriptorFinder,
annotationDeserializer, storageManager);
@@ -143,33 +149,32 @@ public final class DeserializedDescriptorResolver {
}
@Nullable
private static ClassData readClassDataFromClassFile(@NotNull VirtualFile virtualFile) {
String[] data = getKotlinInfoDataFromClassFile(virtualFile);
if (data == null) return null;
return JavaProtoBufUtil.readClassDataFrom(data);
private ClassData readClassDataFromClassFile(@NotNull VirtualFile virtualFile, @NotNull PsiClass psiClass) {
String[] data = readData(virtualFile, psiClass);
return data == null ? null : JavaProtoBufUtil.readClassDataFrom(data);
}
@Nullable
private static PackageData readPackageDataFromClassFile(@NotNull VirtualFile virtualFile) {
String[] data = getKotlinInfoDataFromClassFile(virtualFile);
if (data == null) return null;
return JavaProtoBufUtil.readPackageDataFrom(data);
private PackageData readPackageDataFromClassFile(@NotNull VirtualFile virtualFile, @NotNull PsiClass psiClass) {
String[] data = readData(virtualFile, psiClass);
return data == null ? null : JavaProtoBufUtil.readPackageDataFrom(data);
}
@Nullable
private static String[] getKotlinInfoDataFromClassFile(@NotNull VirtualFile virtualFile) {
private String[] readData(@NotNull VirtualFile virtualFile, @NotNull PsiClass psiClass) {
GetKotlinInfoDataVisitor visitor = visitClassFile(virtualFile);
if (visitor == null) {
return null;
}
int version = visitor.getVersion();
String[] data = visitor.getData();
if (data == null) {
return null;
if (isAbiVersionCompatible(version)) {
return data;
}
return data;
if (data != null) {
errorReporter.reportIncompatibleAbiVersion(psiClass, version);
}
return null;
}
@Nullable
@NotNull
private static GetKotlinInfoDataVisitor visitClassFile(@NotNull VirtualFile virtualFile) {
try {
InputStream inputStream = virtualFile.getInputStream();
@@ -193,6 +198,8 @@ public final class DeserializedDescriptorResolver {
super(Opcodes.ASM4);
}
private int version = AbiVersionUtil.INVALID_VERSION;
@Nullable
private String[] data = null;
@@ -204,11 +211,29 @@ public final class DeserializedDescriptorResolver {
return new AnnotationVisitor(Opcodes.ASM4) {
@Override
public AnnotationVisitor visitArray(String name) {
if (!name.equals("data")) {
public void visit(String name, Object value) {
if (name.equals("version")) {
version = (Integer) value;
}
else if (isAbiVersionCompatible(version)) {
throw new IllegalStateException("Unexpected argument " + name + " for annotation " + KOTLIN_INFO_TYPE);
}
}
@Override
public AnnotationVisitor visitArray(String name) {
if (name.equals("data")) {
return stringArrayVisitor();
}
else if (isAbiVersionCompatible(version)) {
throw new IllegalStateException("Unexpected array argument " + name + " for annotation " + KOTLIN_INFO_TYPE);
}
return super.visitArray(name);
}
@NotNull
private AnnotationVisitor stringArrayVisitor() {
final List<String> strings = new ArrayList<String>(1);
return new AnnotationVisitor(Opcodes.ASM4) {
@Override
@@ -229,6 +254,10 @@ public final class DeserializedDescriptorResolver {
};
}
public int getVersion() {
return version;
}
@Nullable
public String[] getData() {
return data;
@@ -0,0 +1,37 @@
/*
* 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.lang.resolve.java.resolver;
import com.intellij.psi.PsiClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil;
import javax.inject.Inject;
public class ErrorReporter {
private BindingTrace trace;
@Inject
public void setTrace(BindingTrace trace) {
this.trace = trace;
}
public void reportIncompatibleAbiVersion(@NotNull PsiClass psiClass, int version) {
AbiVersionUtil.reportIncompatibleAbiVersion(psiClass, version, trace);
}
}
@@ -237,7 +237,6 @@ public final class JavaClassResolver {
@NotNull FqName fqName, @NotNull PsiClass psiClass,
@NotNull PostponedTasks taskList
) {
checkFqNamesAreConsistent(psiClass, fqName);
DescriptorResolverUtils.checkPsiClassIsNotJet(psiClass);
@@ -267,7 +266,9 @@ public final class JavaClassResolver {
@NotNull ClassOrNamespaceDescriptor containingDeclaration
) {
JetClassAnnotation jetClassAnnotation = JetClassAnnotation.get(psiClass);
AbiVersionUtil.checkAbiVersion(psiClass, jetClassAnnotation, trace);
if (jetClassAnnotation.isDefined()) {
AbiVersionUtil.checkAbiVersion(psiClass, jetClassAnnotation.getAbiVersion(), trace);
}
ClassKind kind = getClassKind(psiClass, jetClassAnnotation);
ClassPsiDeclarationProvider classData = semanticServices.getPsiDeclarationProviderFactory().createBinaryClassData(psiClass);
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.java.resolver;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.psi.*;
import com.intellij.psi.impl.compiled.ClsClassImpl;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -36,6 +37,7 @@ import org.jetbrains.jet.lang.resolve.java.provider.MembersCache;
import org.jetbrains.jet.lang.resolve.java.scope.JavaBaseScope;
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassStaticMembersScope;
import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScopeWithoutMembers;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiClassWrapper;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -44,6 +46,8 @@ import java.util.Collections;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.INVALID_VERSION;
public final class JavaNamespaceResolver {
@NotNull
@@ -160,12 +164,24 @@ public final class JavaNamespaceResolver {
if (psiPackage != null) {
PsiClass psiClass = getPsiClassForJavaPackageScope(fqName);
trace.record(JavaBindingContext.JAVA_NAMESPACE_KIND, namespaceDescriptor, JavaNamespaceKind.PROPER);
if (psiClass == null || !isCompiledKotlinClass(psiClass)) {
return new JavaPackageScopeWithoutMembers(namespaceDescriptor, javaSemanticServices.getPsiDeclarationProviderFactory()
.createDeclarationProviderForNamespaceWithoutMembers(psiPackage), fqName, javaSemanticServices);
if (psiClass != null) {
boolean compiledKotlinClass = isCompiledKotlinClass(psiClass);
if (isOldKotlinPackageClass(psiClass) && !compiledKotlinClass) {
// If psiClass has old annotations (@JetPackage) but doesn't have @KotlinInfo, report ABI version error
AbiVersionUtil.checkAbiVersion(psiClass, INVALID_VERSION, trace);
}
if (compiledKotlinClass) {
// If psiClass has @KotlinInfo (regardless of whether it has @JetPackage or not), deserialize it to Kotlin descriptor.
// Note that @KotlinInfo may still have an old ABI version, in which case null is returned by createKotlinPackageScope
JetScope kotlinPackageScope = deserializedDescriptorResolver.createKotlinPackageScope(psiClass, namespaceDescriptor);
if (kotlinPackageScope != null) return kotlinPackageScope;
}
}
return createScopeForKotlinPackageClass(fqName, namespaceDescriptor, psiClass);
// Otherwise (if psiClass is null or doesn't have a supported Kotlin annotation), it's a Java class and the package is empty
return new JavaPackageScopeWithoutMembers(namespaceDescriptor, javaSemanticServices.getPsiDeclarationProviderFactory()
.createDeclarationProviderForNamespaceWithoutMembers(psiPackage), fqName, javaSemanticServices);
}
PsiClass psiClass = psiClassFinder.findPsiClass(fqName, PsiClassFinder.RuntimeClassesHandleMode.IGNORE);
@@ -185,19 +201,21 @@ public final class JavaNamespaceResolver {
fqName, javaSemanticServices);
}
private static boolean isCompiledKotlinClass(@NotNull PsiClass psiClass) {
PsiModifierList list = psiClass.getModifierList();
return list != null && list.findAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getFqName().asString()) != null;
private static boolean isOldKotlinPackageClass(@NotNull PsiClass psiClass) {
return new PsiClassWrapper(psiClass).getJetPackageClass().isDefined();
}
@NotNull
private JetScope createScopeForKotlinPackageClass(
@NotNull FqName fqName,
@NotNull NamespaceDescriptor namespaceDescriptor,
@NotNull PsiClass psiClass
) {
//TODO: check abi version
return deserializedDescriptorResolver.createKotlinPackageScope(fqName, psiClass, namespaceDescriptor);
private static boolean isCompiledKotlinClass(@NotNull PsiClass psiClass) {
// TODO: merge this method with DescriptorResolverUtils#isKotlinClass
// NOTE: we need to check against ClsClassImpl because it can be a Java source, pretending to be a Kotlin class.
// In that case we can't really read the annotation from psiClass's virtual file
if (psiClass instanceof ClsClassImpl) {
PsiModifierList list = psiClass.getModifierList();
if (list != null) {
return list.findAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getFqName().asString()) != null;
}
}
return false;
}
private void cache(@NotNull FqName fqName, @Nullable JetScope packageScope) {