diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/header/KotlinClassFileHeader.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/header/KotlinClassFileHeader.java index 85a899c0b9e..8815cea621f 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/header/KotlinClassFileHeader.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/header/KotlinClassFileHeader.java @@ -36,63 +36,45 @@ import java.util.List; import static org.jetbrains.asm4.ClassReader.*; import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCompatible; -public final class KotlinClassFileHeader { +public abstract class KotlinClassFileHeader { private static final Logger LOG = Logger.getInstance(KotlinClassFileHeader.class); @Nullable public static KotlinClassFileHeader readKotlinHeaderFromClassFile(@NotNull VirtualFile virtualFile) { try { ClassReader reader = new ClassReader(virtualFile.contentsToByteArray()); - ReadDataFromAnnotationVisitor visitor = new ReadDataFromAnnotationVisitor(); - reader.accept(visitor, SKIP_CODE | SKIP_FRAMES | SKIP_DEBUG); - if (visitor.foundType == null) { + ReadDataFromAnnotationVisitor v = new ReadDataFromAnnotationVisitor(); + reader.accept(v, SKIP_CODE | SKIP_FRAMES | SKIP_DEBUG); + if (v.foundType == null) { return null; } - if (visitor.fqName == null) { + if (v.fqName == null) { LOG.error("File doesn't have a class name: " + virtualFile); return null; } - return new KotlinClassFileHeader(visitor.version, visitor.annotationData, visitor.foundType, visitor.fqName); + + switch (v.foundType) { + case CLASS: + return SerializedDataHeader.create(v.version, v.annotationData, SerializedDataHeader.Kind.CLASS, v.fqName); + case PACKAGE: + return SerializedDataHeader.create(v.version, v.annotationData, SerializedDataHeader.Kind.PACKAGE, v.fqName); + case OLD_CLASS: + case OLD_PACKAGE: + return new OldAnnotationHeader(v.fqName); + default: + throw new UnsupportedOperationException("Unknown HeaderType: " + v.foundType); + } } catch (IOException e) { throw new RuntimeException(e); } } - @SuppressWarnings("deprecation") - public enum HeaderType { - CLASS(JvmAnnotationNames.KOTLIN_CLASS), - PACKAGE(JvmAnnotationNames.KOTLIN_PACKAGE), - OLD_CLASS(JvmAnnotationNames.OLD_JET_CLASS_ANNOTATION), - OLD_PACKAGE(JvmAnnotationNames.OLD_JET_PACKAGE_CLASS_ANNOTATION); - - @NotNull - private final JvmClassName annotation; - - private HeaderType(@NotNull JvmClassName annotation) { - this.annotation = annotation; - } - - @Nullable - private static HeaderType byDescriptor(@NotNull String desc) { - for (HeaderType headerType : HeaderType.values()) { - if (desc.equals(headerType.annotation.getDescriptor())) { - return headerType; - } - } - return null; - } - } - private final int version; - private final String[] annotationData; - private final HeaderType type; private final FqName fqName; - private KotlinClassFileHeader(int version, @Nullable String[] annotationData, @NotNull HeaderType type, @NotNull FqName fqName) { + protected KotlinClassFileHeader(int version, @NotNull FqName fqName) { this.version = version; - this.annotationData = annotationData; - this.type = type; this.fqName = fqName; } @@ -100,20 +82,6 @@ public final class KotlinClassFileHeader { return version; } - @Nullable - public String[] getAnnotationData() { - if (isCompatibleKotlinCompiledFile() && annotationData == null) { - LOG.error("Kotlin annotation " + type + " is incorrect for class: " + fqName); - return null; - } - return annotationData; - } - - @NotNull - public HeaderType getType() { - return type; - } - /** * @return FQ name for class header or package class FQ name for package header (e.g. test.TestPackage) */ @@ -126,10 +94,35 @@ public final class KotlinClassFileHeader { * @return true if this is a header for compiled Kotlin file with correct abi version which can be processed by compiler or the IDE */ public boolean isCompatibleKotlinCompiledFile() { - return (type == HeaderType.CLASS || type == HeaderType.PACKAGE) && isAbiVersionCompatible(version); + return isAbiVersionCompatible(version); } private static class ReadDataFromAnnotationVisitor extends ClassVisitor { + @SuppressWarnings("deprecation") + private enum HeaderType { + CLASS(JvmAnnotationNames.KOTLIN_CLASS), + PACKAGE(JvmAnnotationNames.KOTLIN_PACKAGE), + OLD_CLASS(JvmAnnotationNames.OLD_JET_CLASS_ANNOTATION), + OLD_PACKAGE(JvmAnnotationNames.OLD_JET_PACKAGE_CLASS_ANNOTATION); + + @NotNull + private final JvmClassName annotation; + + private HeaderType(@NotNull JvmClassName annotation) { + this.annotation = annotation; + } + + @Nullable + private static HeaderType byDescriptor(@NotNull String desc) { + for (HeaderType headerType : HeaderType.values()) { + if (desc.equals(headerType.annotation.getDescriptor())) { + return headerType; + } + } + return null; + } + } + private int version = AbiVersionUtil.INVALID_VERSION; @Nullable private String[] annotationData = null; diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/header/OldAnnotationHeader.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/header/OldAnnotationHeader.java new file mode 100644 index 00000000000..f29d92fd711 --- /dev/null +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/header/OldAnnotationHeader.java @@ -0,0 +1,27 @@ +/* + * 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.header; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil; +import org.jetbrains.jet.lang.resolve.name.FqName; + +public class OldAnnotationHeader extends KotlinClassFileHeader { + protected OldAnnotationHeader(@NotNull FqName fqName) { + super(AbiVersionUtil.INVALID_VERSION, fqName); + } +} diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/header/SerializedDataHeader.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/header/SerializedDataHeader.java new file mode 100644 index 00000000000..6dadf4262a3 --- /dev/null +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/header/SerializedDataHeader.java @@ -0,0 +1,61 @@ +/* + * 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.header; + +import com.intellij.openapi.diagnostic.Logger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.resolve.name.FqName; + +import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCompatible; + +public class SerializedDataHeader extends KotlinClassFileHeader { + private static final Logger LOG = Logger.getInstance(SerializedDataHeader.class); + + public enum Kind { + CLASS, + PACKAGE + } + + private final String[] data; + private final Kind kind; + + private SerializedDataHeader(int version, @Nullable String[] annotationData, @NotNull Kind kind, @NotNull FqName fqName) { + super(version, fqName); + this.data = annotationData; + this.kind = kind; + } + + @Nullable + public static SerializedDataHeader create(int version, @Nullable String[] annotationData, @NotNull Kind kind, @NotNull FqName fqName) { + if (isAbiVersionCompatible(version) && annotationData == null) { + LOG.error("Kotlin annotation " + kind + " is incorrect for class: " + fqName); + return null; + } + return new SerializedDataHeader(version, annotationData, kind, fqName); + } + + @Nullable + public String[] getAnnotationData() { + return data; + } + + @NotNull + public Kind getKind() { + return kind; + } +} diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/DeserializedDescriptorResolver.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/DeserializedDescriptorResolver.java index d4888218ee3..a358ed57f18 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/DeserializedDescriptorResolver.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/DeserializedDescriptorResolver.java @@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.resolve.java.header.KotlinClassFileHeader; +import org.jetbrains.jet.lang.resolve.java.header.SerializedDataHeader; import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; @@ -34,7 +35,6 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope; import javax.inject.Inject; import java.util.Collection; -import static org.jetbrains.jet.lang.resolve.java.AbiVersionUtil.isAbiVersionCompatible; import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.IGNORE_KOTLIN_SOURCES; import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_KOTLIN_SOURCES; import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.kotlinFqNameToJavaFqName; @@ -127,14 +127,13 @@ public final class DeserializedDescriptorResolver { @Nullable private String[] readData(@NotNull VirtualFile virtualFile) { KotlinClassFileHeader header = KotlinClassFileHeader.readKotlinHeaderFromClassFile(virtualFile); - if (header == null) { - return null; + if (header instanceof SerializedDataHeader && header.isCompatibleKotlinCompiledFile()) { + return ((SerializedDataHeader) header).getAnnotationData(); } - int version = header.getVersion(); - if (!isAbiVersionCompatible(version)) { - errorReporter.reportIncompatibleAbiVersion(header.getFqName(), virtualFile, version); - return null; + + if (header != null) { + errorReporter.reportIncompatibleAbiVersion(header.getFqName(), virtualFile, header.getVersion()); } - return header.getAnnotationData(); + return null; } } diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java index a6aea3eb93b..df6ae5fa630 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java @@ -30,6 +30,7 @@ import org.jetbrains.jet.descriptors.serialization.*; import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.resolve.java.JavaResolverPsiUtils; import org.jetbrains.jet.lang.resolve.java.header.KotlinClassFileHeader; +import org.jetbrains.jet.lang.resolve.java.header.SerializedDataHeader; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.util.QualifiedNamesUtil; @@ -104,8 +105,8 @@ public class JetFromJavaDescriptorHelper { VirtualFile virtualFile = getVirtualFileForPsiClass(psiClass); if (virtualFile != null) { KotlinClassFileHeader header = KotlinClassFileHeader.readKotlinHeaderFromClassFile(virtualFile); - if (header != null) { - String[] data = header.getAnnotationData(); + if (header instanceof SerializedDataHeader) { + String[] data = ((SerializedDataHeader) header).getAnnotationData(); if (data != null) { return JavaProtoBufUtil.readClassDataFrom(data); } @@ -119,8 +120,8 @@ public class JetFromJavaDescriptorHelper { VirtualFile virtualFile = getVirtualFileForPsiClass(psiClass); if (virtualFile != null) { KotlinClassFileHeader header = KotlinClassFileHeader.readKotlinHeaderFromClassFile(virtualFile); - if (header != null) { - String[] data = header.getAnnotationData(); + if (header instanceof SerializedDataHeader) { + String[] data = ((SerializedDataHeader) header).getAnnotationData(); if (data != null) { return JavaProtoBufUtil.readPackageDataFrom(data); } diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.java b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.java index c17c338e8e2..7c52dd19643 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.java @@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.resolve.BindingTraceContext; import org.jetbrains.jet.lang.resolve.MemberComparator; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.header.KotlinClassFileHeader; +import org.jetbrains.jet.lang.resolve.java.header.SerializedDataHeader; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.renderer.DescriptorRenderer; import org.jetbrains.jet.renderer.DescriptorRendererBuilder; @@ -48,7 +49,7 @@ public final class DecompiledDataFactory { @NotNull private final JavaDescriptorResolver javaDescriptorResolver; @NotNull - private final KotlinClassFileHeader kotlinClassFileHeader; + private final SerializedDataHeader classFileHeader; @NotNull private final VirtualFile classFile; @NotNull @@ -62,8 +63,8 @@ public final class DecompiledDataFactory { this.javaDescriptorResolver = injector.getJavaDescriptorResolver(); KotlinClassFileHeader header = KotlinClassFileHeader.readKotlinHeaderFromClassFile(classFile); - assert header != null : "Decompiled data factory shouldn't be called on an unsupported file: " + classFile; - this.kotlinClassFileHeader = header; + assert header instanceof SerializedDataHeader : "Decompiled data factory shouldn't be called on an unsupported file: " + classFile; + this.classFileHeader = (SerializedDataHeader) header; } @NotNull @@ -72,10 +73,10 @@ public final class DecompiledDataFactory { } private JetDecompiledData build() { - FqName packageFqName = kotlinClassFileHeader.getFqName().parent(); + FqName packageFqName = classFileHeader.getFqName().parent(); appendDecompiledTextAndPackageName(packageFqName); - KotlinClassFileHeader.HeaderType type = kotlinClassFileHeader.getType(); - if (type == KotlinClassFileHeader.HeaderType.PACKAGE) { + SerializedDataHeader.Kind kind = classFileHeader.getKind(); + if (kind == SerializedDataHeader.Kind.PACKAGE) { NamespaceDescriptor nd = javaDescriptorResolver.resolveNamespace(packageFqName, INCLUDE_KOTLIN_SOURCES); if (nd != null) { for (DeclarationDescriptor member : sortDeclarations(nd.getMemberScope().getAllDescriptors())) { @@ -88,13 +89,15 @@ public final class DecompiledDataFactory { } } } - else { - assert type == KotlinClassFileHeader.HeaderType.CLASS; - ClassDescriptor cd = javaDescriptorResolver.resolveClass(kotlinClassFileHeader.getFqName(), INCLUDE_KOTLIN_SOURCES); + else if (kind == SerializedDataHeader.Kind.CLASS) { + ClassDescriptor cd = javaDescriptorResolver.resolveClass(classFileHeader.getFqName(), INCLUDE_KOTLIN_SOURCES); if (cd != null) { appendDescriptor(cd, ""); } } + else { + throw new UnsupportedOperationException("Unknown header kind: " + kind); + } JetFile jetFile = JetDummyClassFileViewProvider.createJetFile(PsiManager.getInstance(project), classFile, builder.toString()); return new JetDecompiledData(jetFile, renderedDescriptorsToRange); diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java index 0cf7234628a..950d079f2a1 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java @@ -20,6 +20,7 @@ import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.resolve.java.header.KotlinClassFileHeader; +import org.jetbrains.jet.lang.resolve.java.header.SerializedDataHeader; public final class DecompiledUtils { @@ -29,7 +30,7 @@ public final class DecompiledUtils { } //TODO: check index KotlinClassFileHeader header = KotlinClassFileHeader.readKotlinHeaderFromClassFile(file); - return header != null && header.isCompatibleKotlinCompiledFile(); + return header instanceof SerializedDataHeader && header.isCompatibleKotlinCompiledFile(); } private DecompiledUtils() { diff --git a/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java b/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java index ee5435d884d..0485176d125 100644 --- a/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java +++ b/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java @@ -7,6 +7,7 @@ import com.intellij.util.indexing.*; import com.intellij.util.io.KeyDescriptor; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.resolve.java.header.KotlinClassFileHeader; +import org.jetbrains.jet.lang.resolve.java.header.SerializedDataHeader; import org.jetbrains.jet.lang.resolve.name.FqName; import java.io.DataInput; @@ -58,7 +59,7 @@ public final class KotlinClassFileIndex extends ScalarIndexExtension { public Map map(FileContent inputData) { try { KotlinClassFileHeader header = KotlinClassFileHeader.readKotlinHeaderFromClassFile(inputData.getFile()); - if (header != null && header.isCompatibleKotlinCompiledFile()) { + if (header instanceof SerializedDataHeader && header.isCompatibleKotlinCompiledFile()) { return Collections.singletonMap(header.getFqName(), null); } }