Annotation on a function literal cannot be written to binary if it has FUNCTION target and the literal is inlined

This commit is contained in:
Mikhail Glukhikh
2015-09-23 15:46:34 +03:00
parent 6b9e2b0bbb
commit bd7ccc0138
6 changed files with 64 additions and 4 deletions
@@ -120,6 +120,7 @@ public interface Errors {
DiagnosticFactory1<JetAnnotationEntry, String> WRONG_ANNOTATION_TARGET = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<JetAnnotationEntry, String, String> WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET = DiagnosticFactory2.create(ERROR);
DiagnosticFactory0<JetAnnotationEntry> REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetAnnotationEntry> NON_SOURCE_ANNOTATION_ON_INLINED_FUNCTION_LITERAL = DiagnosticFactory0.create(ERROR);
// Annotations
@@ -127,6 +127,7 @@ public class DefaultErrorMessages {
MAP.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING);
MAP.put(WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET, "This annotation is not applicable to target ''{0}'' and use site target ''@{1}''", TO_STRING, TO_STRING);
MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable");
MAP.put(NON_SOURCE_ANNOTATION_ON_INLINED_FUNCTION_LITERAL, "Function literal here is an inlined argument so this annotation cannot be stored anywhere");
MAP.put(INAPPLICABLE_TARGET_ON_PROPERTY, "''@{0}'' annotations could be applied only to property declarations", TO_STRING);
MAP.put(INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD, "Property has neither a backing field nor a delegate");
@@ -874,7 +874,7 @@ public class JetPsiUtil {
else if (parent instanceof JetValueArgument || parent instanceof JetValueArgumentList) {
parent = parent.getParent();
}
else if (parent instanceof JetFunctionLiteralExpression) {
else if (parent instanceof JetFunctionLiteralExpression || parent instanceof JetAnnotatedExpression) {
parent = parent.getParent();
}
else {
@@ -28,7 +28,10 @@ import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.isRepeatableAnnotation
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAnnotationRetention
import org.jetbrains.kotlin.resolve.inline.InlineUtil
public class AnnotationChecker(private val additionalCheckers: Iterable<AdditionalAnnotationChecker>) {
@@ -92,11 +95,28 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
it in applicableTargets && (useSiteTarget == null || KotlinTarget.USE_SITE_MAPPING[useSiteTarget] == it)
}
if (check(actualTargets.defaultTargets) || check(actualTargets.canBeSubstituted)) return
fun checkUselessFunctionLiteralAnnotation() {
// TODO: tests on different JetAnnotatedExpression (?!)
if (KotlinTarget.FUNCTION !in applicableTargets) return
val annotatedExpression = entry.parent as? JetAnnotatedExpression ?: return
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: return
val retention = descriptor.type.constructor.declarationDescriptor?.getAnnotationRetention()
if (retention == KotlinRetention.SOURCE) return
if (useSiteTarget != null && actualTargets.onlyWithUseSiteTarget.any {
val functionLiteralExpression = annotatedExpression.baseExpression as? JetFunctionLiteralExpression ?: return
if (InlineUtil.isInlinedArgument(functionLiteralExpression.functionLiteral, trace.bindingContext, false)) {
trace.report(Errors.NON_SOURCE_ANNOTATION_ON_INLINED_FUNCTION_LITERAL.on(entry))
}
}
fun applicableWithUseSiteTarget() = useSiteTarget != null && actualTargets.onlyWithUseSiteTarget.any {
it in applicableTargets && KotlinTarget.USE_SITE_MAPPING[useSiteTarget] == it
}) return
}
if (check(actualTargets.defaultTargets) || check(actualTargets.canBeSubstituted) || applicableWithUseSiteTarget()) {
checkUselessFunctionLiteralAnnotation()
return
}
if (useSiteTarget != null) {
trace.report(Errors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET.on(