Detekt return type annotations always empty

562 views Asked by At

I am trying to write a check to prevent returning a Type with a certain annotation.

Such as,

const val TEST_CONTENT = 
        """
        | package sample.test
        |
        | @Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)
        | annotation class SampleAnnotation
        | 
        | @SampleAnnotation
        | internal interface ConditionalReturnedType 
        |
        | interface TestCase {
        |   // this is not allowed
        |   fun someFunction(whatever: String): ConditionalReturnedType
        | }
        """.trimIndent()

and the rule that I have so far is as following

override fun visitNamedFunction(function: KtNamedFunction) {
    super.visitNamedFunction(function)
    if (BindingContext.EMPTY == bindingContext) {
      return
    }

    val returnType = function.createTypeBindingForReturnType(bindingContext)?.type ?: return

    // HERE Annotations is always EMPTY
    val annotations = returnType.annotations
    val hasRequiredAnnotation = annotations.hasAnnotation(FqName("SampleAnnotation"))
    if (!hasRequiredAnnotation) return

    if (isAnAllowedCondition(function, returnType)) {
      // Allow returning the type for this condition
      return
    }

    report(CodeSmell(/** */))
  }

I can verify that returnType is correct, but annotations for the type are always empty. Is there an alternative way of getting annotations or am I doing some rookie mistake here? :)

My Test is as following,

@Test
fun `negative cuz it doesnt match allowed conditions`() {
  val actual = subject.compileAndLintWithContext(ENVIRONMENT.env, TEST_CONTENT)
  assertThat(actual).hasSize(1)
  assertThat(actual[0].message)
      .isEqualTo("Ops. You shouldn't return that.")
}
1

There are 1 answers

0
yahya On BEST ANSWER

So, there were 2 issues.

  1. I added visitClass and checked the annotation there as well, and it was always empty - which was weird and made me realise the issue is with the test. For some reason, having the code block with | made annotation line to be removed while compiling. | @SampleAnnotation this was not exist in compiled file at all. Removing the | solves that.
  2. For some reason, it doesn't look like that annotations field is populated in KotlinType for returnType. So instead, I needed to reach to KtClass object somehow adding the following I was able to get the annotation.
val returnType = function.createTypeBindingForReturnType(bindingContext)?.type ?: return
val annotations = returnType.constructor.declarationDescriptor?.annotations ?: return
val isAnnotated = annotations.any { it.type.toString() == "SampleAnnotation" }