0

I am writing a custom android lint to help to check if the private attributes match naming convention.

I used the test cases to verify my implementation. I used a method called isPrivateOrParameterInPrivateMethod() to check if it is private or not but it seems return true everytime I run it.

And I cannot find any documentation about this method (org.jetbrains.kotlin.asJava.classesisPrivateOrParameterInPrivateMethod). If I used it incorrectly, I would like to know.

Appreciate any comment or advice

class PrivateVariableMPrefixDetector : Detector(), Detector.UastScanner {
    override fun getApplicableUastTypes() = listOf<Class<out UElement>>(UVariable::class.java)

    override fun createUastHandler(context: JavaContext) =
        NamingPatternHandler(context)

    class NamingPatternHandler(private val context: JavaContext) : UElementHandler() {
        override fun visitVariable(node: UVariable) {
            node.takeIf { it.isPrivateOrParameterInPrivateMethod() }
                ?.takeUnless { node.name?.first()?.equals('m') ?: false }
                ?.run {
                    process(node, node)
                }
        }

        private fun process(scope: UElement, declaration: PsiNamedElement) {
            context.report(
                ISSUE_PRIVATE_VAR_PREFIX_WITH_M,
                scope,
                context.getNameLocation(scope),
                "${declaration.name} is not named with prefix m"
            )
        }
    }
}

Test Case

@Test
    fun should_not_warn_when_public_variable_is_not_stated_with_m_prefix() {
        TestLintTask.lint()
            .files(
                TestFiles.kt(
                    """
                        class Foo {
                             val binding 
                        }
              """
                ).indented()
            )
            .issues(ISSUE_PRIVATE_VAR_PREFIX_WITH_M)
            .run()
            .expectClean()
    }
Long Ranger
  • 5,888
  • 8
  • 43
  • 72

1 Answers1

0

Updated on 13/12/2020

There is a class JavaEvaluator inside the JavaContext, and I found some useful method to check the explicit modifier for the variable which suits my cases

class MyHandler(private val context: JavaContext) : UElementHandler() {
     override fun visitField(node: UField) {
            val isConstant = node.isFinal && node.isStatic
            val isEnumConstant = node is UEnumConstant
            if (!isConstant && !isEnumConstant) {
                node.takeIf {
                    context.evaluator.hasModifiers(node, KtTokens.PRIVATE_KEYWORD)
                }?.run {
                        process(node, node)
                    }
            }
        }
}

Outdated

After putting an effort on it, I found the following solution works. Although I still dun quite understand the meaning of node.sourcePsi, i will make it work first. Appreciate any advice or suggestion

        node.takeIf { node.sourcePsi?.text?.startsWith("private") ?: false }
            ?.takeUnless { node.name.first() == 'm' && node.name.getOrNull(1)?.isUpperCase() ?: false }
            ?.run {
                process(node, node)
            }
Long Ranger
  • 5,888
  • 8
  • 43
  • 72
  • 1
    `sourcePsi` is the source file where you've defined this attribute represented as `PsiElement`, I recommend you to install Intellij PsiViewer plugin, it will give you a better understanding of how your source file interpreted to Psi* link: https://www.jetbrains.com/help/idea/psi-viewer.html – MR3YY Oct 02 '20 at 18:13