Report errors for annotations with BINARY or RUNTIME retention on file classes.

This commit is contained in:
Dmitry Petrov
2015-09-15 18:49:18 +03:00
parent eba9f0f0ad
commit da026f1480
9 changed files with 129 additions and 5 deletions
@@ -61,6 +61,7 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
MAP.put(ErrorsJvm.DEPRECATED_ANNOTATION_METHOD_CALL, "Annotation methods are deprecated. Use property instead");
MAP.put(ErrorsJvm.DEPRECATED_JAVA_ANNOTATION, "This annotation is deprecated in Kotlin. Use ''{0}'' instead", Renderers.TO_STRING);
MAP.put(ErrorsJvm.NON_SOURCE_REPEATED_ANNOTATION, "Only annotations with SOURCE retention can be repeated on JVM version before 1.8");
MAP.put(ErrorsJvm.ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES, "Annotation {0} is not applicable to the multi-file classes", Renderers.TO_STRING);
MAP.put(ErrorsJvm.NO_REFLECTION_IN_CLASS_PATH, "Call uses reflection API which is not found in compilation classpath. " +
"Make sure you have kotlin-reflect.jar in the classpath");
@@ -55,10 +55,11 @@ public interface ErrorsJvm {
DiagnosticFactory0<JetDeclaration> EXTERNAL_DECLARATION_IN_TRAIT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<JetDeclaration> EXTERNAL_DECLARATION_CANNOT_BE_INLINED = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<JetExpression> POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetElement> DEPRECATED_ANNOTATION_METHOD_CALL = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<JetExpression> POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetElement> DEPRECATED_ANNOTATION_METHOD_CALL = DiagnosticFactory0.create(WARNING);
DiagnosticFactory1<JetAnnotationEntry, FqName> DEPRECATED_JAVA_ANNOTATION = DiagnosticFactory1.create(WARNING);
DiagnosticFactory0<JetAnnotationEntry> NON_SOURCE_REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetAnnotationEntry> NON_SOURCE_REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<JetAnnotationEntry, FqName> ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<JetElement> TRAIT_CANT_CALL_DEFAULT_METHOD_VIA_SUPER = DiagnosticFactory0.create(ERROR);
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.jvm.RuntimeAssertionsTypeChecker
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.load.java.lazy.types.isMarkedNotNull
@@ -49,6 +50,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.getAnnotationRetention
import org.jetbrains.kotlin.resolve.descriptorUtil.isRepeatableAnnotation
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmOverloadsAnnotation
@@ -92,7 +94,10 @@ public object JvmPlatformConfigurator : PlatformConfigurator(
additionalSymbolUsageValidators = listOf(),
additionalAnnotationCheckers = listOf(RepeatableAnnotationChecker)
additionalAnnotationCheckers = listOf(
RepeatableAnnotationChecker,
FileClassAnnotationsChecker
)
) {
override fun configure(container: StorageComponentContainer) {
@@ -126,6 +131,34 @@ public object RepeatableAnnotationChecker: AdditionalAnnotationChecker {
}
}
public object FileClassAnnotationsChecker: AdditionalAnnotationChecker {
// JvmName & JvmMultifileClass annotations are applicable to multi-file class parts regardless of their retention.
private val ALWAYS_APPLICABLE = hashSetOf(JvmFileClassUtil.JVM_NAME, JvmFileClassUtil.JVM_MULTIFILE_CLASS)
override fun checkEntries(entries: List<JetAnnotationEntry>, actualTargets: List<KotlinTarget>, trace: BindingTrace) {
val fileAnnotationsToCheck = arrayListOf<Pair<JetAnnotationEntry, ClassDescriptor>>()
for (entry in entries) {
if (entry.useSiteTarget?.getAnnotationUseSiteTarget() != AnnotationUseSiteTarget.FILE) continue
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue
val classDescriptor = TypeUtils.getClassDescriptor(descriptor.type) ?: continue
// This check matters for the applicable annotations only.
val applicableTargets = AnnotationChecker.applicableTargetSet(classDescriptor)
if (applicableTargets == null || !applicableTargets.contains(KotlinTarget.FILE)) continue
fileAnnotationsToCheck.add(Pair(entry, classDescriptor))
}
if (!fileAnnotationsToCheck.any { it.second.classId.asSingleFqName() == JvmFileClassUtil.JVM_MULTIFILE_CLASS }) return
for ((entry, classDescriptor) in fileAnnotationsToCheck) {
val classFqName = classDescriptor.classId.asSingleFqName()
if (ALWAYS_APPLICABLE.contains(classFqName)) continue
if (classDescriptor.getAnnotationRetention() != KotlinRetention.SOURCE) {
trace.report(ErrorsJvm.ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES.on(entry, classFqName))
}
}
}
}
public class LocalFunInlineChecker : DeclarationChecker {
override fun check(
@@ -1,6 +1,6 @@
package test
@kotlin.jvm.JvmName(name = "bar") public fun foo(): kotlin.Unit
public fun foo(): kotlin.Unit
public open class PlatformName {
public constructor PlatformName()
@@ -0,0 +1,12 @@
// FILE: annotations.kt
@Target(AnnotationTarget.CLASS)
public annotation class ClassAnn
@Target(AnnotationTarget.FILE)
public annotation class FileAnn
// FILE: 1.kt
<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@file:ClassAnn<!>
// FILE: 2.kr
@file:FileAnn
@@ -0,0 +1,19 @@
@file:JvmName("MultifileClass")
@file:JvmMultifileClass
<!ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES!>@file:FileAnn<!>
<!ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES!>@file:FileBinaryAnn<!>
@file:FileSourceAnn
@Target(AnnotationTarget.FILE)
@Retention(AnnotationRetention.RUNTIME)
public annotation class FileAnn
@Target(AnnotationTarget.FILE)
@Retention(AnnotationRetention.BINARY)
public annotation class FileBinaryAnn
@Target(AnnotationTarget.FILE)
@Retention(AnnotationRetention.SOURCE)
public annotation class FileSourceAnn
@@ -0,0 +1,40 @@
// FILE: test.kt
@file:JvmName("MultifileClass")
@file:JvmMultifileClass
<!ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES!>@file:JavaAnn<!>
<!ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES!>@file:JavaClassAnn<!>
@file:JavaSourceAnn
// FILE: JavaAnn.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface JavaAnn {
}
// FILE: JavaClassAnn.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface JavaClassAnn {
}
// FILE: JavaSourceAnn.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface JavaSourceAnn {
}
@@ -1232,6 +1232,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("FileAnnotations.kt")
public void testFileAnnotations() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/FileAnnotations.kt");
doTest(fileName);
}
@TestMetadata("GetterAnnotations.kt")
public void testGetterAnnotations() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/GetterAnnotations.kt");
@@ -128,6 +128,18 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/jvmName.kt");
doTest(fileName);
}
@TestMetadata("multifileClassPart.kt")
public void testMultifileClassPart() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/multifileClassPart.kt");
doTest(fileName);
}
@TestMetadata("multifileClassPartWithJavaAnnotation.kt")
public void testMultifileClassPartWithJavaAnnotation() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/multifileClassPartWithJavaAnnotation.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant")