[groovy] IDEA-207415: Better inspection on `includes` and `excludes`
authorKonstantin Nisht <konstantin.nisht@jetbrains.com>
Fri, 7 Aug 2020 14:34:22 +0000 (17:34 +0300)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Mon, 10 Aug 2020 13:53:51 +0000 (13:53 +0000)
GitOrigin-RevId: 1c613b6f4cee3d4ca117a268f146e0181136e1b3

plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/annotator/checkers/TupleConstructorAnnotationChecker.kt
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ast/GeneratedConstructorCollector.kt
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TupleConstructorTest.groovy

index 39d6da94165e2ffcd4dc959d381a4b3b3e54e2fb..3c8589b84042164450ae7c170f8ea63d4642a209 100644 (file)
@@ -9,16 +9,17 @@ import org.jetbrains.plugins.groovy.GroovyBundle
 import org.jetbrains.plugins.groovy.lang.psi.api.GrFunctionalExpression
 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation
 import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames
+import org.jetbrains.plugins.groovy.lang.resolve.ast.GeneratedConstructorCollector
 
 class TupleConstructorAnnotationChecker : CustomAnnotationChecker() {
 
   companion object {
-    fun registerIdentifierListError(holder: AnnotationHolder, element: PsiElement) =
+    private fun registerIdentifierListError(holder: AnnotationHolder, element: PsiElement) =
       holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("explicit.includes.and.excludes"))
         .range(element)
         .create()
 
-    fun registerClosureError(holder: AnnotationHolder, element: PsiElement) =
+    private fun registerClosureError(holder: AnnotationHolder, element: PsiElement) =
       holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("require.closure.as.attribute.value"))
         .range(element)
         .create()
@@ -28,10 +29,10 @@ class TupleConstructorAnnotationChecker : CustomAnnotationChecker() {
     if (annotation.qualifiedName != GroovyCommonClassNames.GROOVY_TRANSFORM_TUPLE_CONSTRUCTOR) {
       return false
     }
-    val excludes = AnnotationUtil.findDeclaredAttribute(annotation, "excludes")
+    val excludes = GeneratedConstructorCollector.getIdentifierList(annotation, "excludes")
     val includes = AnnotationUtil.findDeclaredAttribute(annotation, "includes")
-    if (includes != null && excludes != null) {
-      registerIdentifierListError(holder, excludes)
+    if (includes != null && excludes != null && excludes.isNotEmpty()) {
+      registerIdentifierListError(holder, AnnotationUtil.findDeclaredAttribute(annotation, "excludes")!!)
       registerIdentifierListError(holder, includes)
     }
     val pre = AnnotationUtil.findDeclaredAttribute(annotation, "pre")?.value
index 4bf151b0d4c6a747c60dae4fb89ec385926374f6..f4d833ca134d6601c69cb4c5e45aab67374fc3c5 100644 (file)
@@ -97,21 +97,19 @@ class GeneratedConstructorCollector(tupleConstructor: PsiAnnotation?,
 
     private fun String.isInternal(): Boolean = contains("$")
 
-    private fun getIdentifierList(annotation: PsiAnnotation, attributeName: String): List<String>? {
+    fun getIdentifierList(annotation: PsiAnnotation, attributeName: String): List<String>? {
       annotation.takeIf { it.hasAttribute(attributeName) } ?: return null
       val rawIdentifiers = GrAnnotationUtil.inferStringAttribute(annotation, attributeName)
-      return rawIdentifiers?.split(',')?.toList() ?: GrAnnotationUtil.getStringArrayValue(annotation, attributeName, false)
+      return rawIdentifiers?.split(',')?.mapNotNull { it.trim().takeUnless(CharSequence::isBlank) }?.toList()
+             ?: GrAnnotationUtil.getStringArrayValue(annotation, attributeName, false)
     }
 
     private fun collectNamesOrderInformation(tupleConstructor: PsiAnnotation): Pair<(String) -> Boolean, List<String>?> {
 
-      val excludesList = getIdentifierList(tupleConstructor, "excludes") ?: emptyList()
-      val excludes: List<String> = excludesList.mapNotNull { name -> name.trim().takeIf(CharSequence::isNotBlank) }
+      val excludes: List<String> = getIdentifierList(tupleConstructor, "excludes") ?: emptyList()
 
-      val includesList = getIdentifierList(tupleConstructor, "includes")
-      val includes: List<String>? = includesList
+      val includes: List<String>? = getIdentifierList(tupleConstructor, "includes")
         ?.takeUnless { Undefined.isUndefined(it.singleOrNull()) }
-        ?.mapNotNull { name -> name.trim().takeIf(CharSequence::isNotBlank) }
 
       val allowInternalNames = GrAnnotationUtil.inferBooleanAttribute(tupleConstructor, "allNames") ?: false
 
index 8ac1a5fcb10ab8d395bd08d6bbed00a5211d6312..667b392cb8e3b2a66ac77ed85189dd719823a065 100644 (file)
@@ -265,6 +265,14 @@ class Rr {}
 """
   }
 
+  @Test
+  void 'empty excludes'() {
+    highlightingTest """
+@groovy.transform.TupleConstructor(includes = "a", excludes = [])
+class Rr {}
+"""
+  }
+
   @Test
   void 'wrong expressions at pre and post'() {
     highlightingTest """