Simplify logic in KotlinClassFileHeader

When processing annotations, we should ensure not only that we have no more
than one KotlinClass/KotlinPackage annotation, but any supported header type at
all. Also instead of throwing an exception it's safer to just log the error
This commit is contained in:
Alexander Udalov
2013-09-19 19:20:53 +04:00
parent 92cc0ddd1f
commit 1f466ff57d
@@ -1,3 +1,19 @@
/*
* 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; package org.jetbrains.jet.lang.resolve.java.resolver;
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger;
@@ -29,14 +45,14 @@ public final class KotlinClassFileHeader {
ClassReader reader = new ClassReader(virtualFile.contentsToByteArray()); ClassReader reader = new ClassReader(virtualFile.contentsToByteArray());
ReadDataFromAnnotationVisitor visitor = new ReadDataFromAnnotationVisitor(); ReadDataFromAnnotationVisitor visitor = new ReadDataFromAnnotationVisitor();
reader.accept(visitor, SKIP_CODE | SKIP_FRAMES | SKIP_DEBUG); reader.accept(visitor, SKIP_CODE | SKIP_FRAMES | SKIP_DEBUG);
if (visitor.type == null) { if (visitor.foundType == null) {
return null; return null;
} }
if (visitor.fqName == null) { if (visitor.fqName == null) {
LOG.error("File doesn't have a class name: " + virtualFile); LOG.error("File doesn't have a class name: " + virtualFile);
return null; return null;
} }
return new KotlinClassFileHeader(visitor.version, visitor.annotationData, visitor.type, visitor.fqName); return new KotlinClassFileHeader(visitor.version, visitor.annotationData, visitor.foundType, visitor.fqName);
} }
catch (IOException e) { catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@@ -50,25 +66,17 @@ public final class KotlinClassFileHeader {
OLD_CLASS(JvmAnnotationNames.OLD_JET_CLASS_ANNOTATION), OLD_CLASS(JvmAnnotationNames.OLD_JET_CLASS_ANNOTATION),
OLD_PACKAGE(JvmAnnotationNames.OLD_JET_PACKAGE_CLASS_ANNOTATION); OLD_PACKAGE(JvmAnnotationNames.OLD_JET_PACKAGE_CLASS_ANNOTATION);
@Nullable @NotNull
private final JvmClassName correspondingAnnotation; private final JvmClassName annotation;
private HeaderType(@Nullable JvmClassName annotation) { private HeaderType(@NotNull JvmClassName annotation) {
correspondingAnnotation = annotation; this.annotation = annotation;
}
private boolean isValidAnnotation() {
return this == CLASS || this == PACKAGE;
} }
@Nullable @Nullable
private static HeaderType byDescriptor(@NotNull String desc) { private static HeaderType byDescriptor(@NotNull String desc) {
for (HeaderType headerType : HeaderType.values()) { for (HeaderType headerType : HeaderType.values()) {
JvmClassName annotation = headerType.correspondingAnnotation; if (desc.equals(headerType.annotation.getDescriptor())) {
if (annotation == null) {
continue;
}
if (desc.equals(annotation.getDescriptor())) {
return headerType; return headerType;
} }
} }
@@ -118,7 +126,7 @@ 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 * @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() { public boolean isCompatibleKotlinCompiledFile() {
return type.isValidAnnotation() && isAbiVersionCompatible(version); return (type == HeaderType.CLASS || type == HeaderType.PACKAGE) && isAbiVersionCompatible(version);
} }
private static class ReadDataFromAnnotationVisitor extends ClassVisitor { private static class ReadDataFromAnnotationVisitor extends ClassVisitor {
@@ -126,7 +134,7 @@ public final class KotlinClassFileHeader {
@Nullable @Nullable
private String[] annotationData = null; private String[] annotationData = null;
@Nullable @Nullable
private HeaderType type = null; private HeaderType foundType = null;
@Nullable @Nullable
private FqName fqName = null; private FqName fqName = null;
@@ -140,22 +148,26 @@ public final class KotlinClassFileHeader {
} }
@Override @Override
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) { public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
HeaderType headerTypeByAnnotation = HeaderType.byDescriptor(desc); HeaderType newType = HeaderType.byDescriptor(desc);
if (headerTypeByAnnotation == null) { if (newType == null) return null;
if (foundType != null) {
LOG.error("Both annotations are present for compiled Kotlin file: " + foundType + " and " + newType);
return null; return null;
} }
boolean alreadyFoundValid = type != null && type.isValidAnnotation();
if (headerTypeByAnnotation.isValidAnnotation() && alreadyFoundValid) { foundType = newType;
throw new IllegalStateException("Both " + type.correspondingAnnotation + " and "
+ headerTypeByAnnotation.correspondingAnnotation + " present!"); if (newType == HeaderType.CLASS || newType == HeaderType.PACKAGE) {
} return kotlinClassOrPackageVisitor(desc);
if (!alreadyFoundValid) {
type = headerTypeByAnnotation;
}
if (!headerTypeByAnnotation.isValidAnnotation()) {
return null;
} }
return null;
}
@NotNull
private AnnotationVisitor kotlinClassOrPackageVisitor(final String desc) {
return new AnnotationVisitor(Opcodes.ASM4) { return new AnnotationVisitor(Opcodes.ASM4) {
@Override @Override
public void visit(String name, Object value) { public void visit(String name, Object value) {