# Frequently Asked Questions This chapter contains a random collection of questions people have asked in the past. ### My detector callbacks aren't invoked If you've for example implemented the Detector callback for visiting method calls, `visitMethodCall`, notice how the third parameter is a `PsiMethod`, and that it is not nullable: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ open fun visitMethodCall( context: JavaContext, node: UCallExpression, method: PsiMethod ) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This passes in the method that has been called. When lint is visiting the AST, it will resolve calls, and if the called method cannot be resolved, the callback won't be called. This happens when the classpath that lint has been configured with does not contain everything needed. When lint is running from Gradle, this shouldn't happen; the build system should have a complete classpath and pass it to Lint (or the build wouldn't have succeeded in the first place). This usually comes up in unit tests for lint, where you've added a test case which is referencing some API for some library, but the library itself isn't part of the test. The solution for this is to create stubs for the part of the API you care about. This is discussed in more detail in the [unit testing](unit-testing.md.html) chapter. ### My lint check works from the unit test but not in the IDE There are several things to check if you have a lint check which works correctly from your unit test but not in the IDE. 1. First check that the lint jar is packaged correctly; use `jar tvf lint.jar` to look at the jar file to make sure it contains the service loader registration of your issue registry, and `javap -classpath lint.jar com.example.YourIssueRegistry` to inspect your issue registry. 2. If that's correct, the next thing to check is that lint is actually loading your issue registry. First look in the IDE log (from the Help menu) to make sure there aren't log messages from lint explaining why it can't load the registry, for example because it does not specify a valid applicable API range. 3. If there's no relevant warning in the log, try setting the `$ANDROID_LINT_JARS` environment variable to point directly to your lint jar file and restart Studio to make sure that that works. 4. Next, try running **Analyze | Inspect Code...**. This runs lint on the whole project. If that works, then the issue is that your lint check isn't eligible to run “on the fly”; the reason for this is that your implementation scope registers more than one scope, which says that your lint check can only run if lint gets to look at both types of files, and in the editor, only the current file is analyzed by lint. However, you can still make the check work on the fly by specifying additional analysis scopes; see the API guide for more information about this. ### `visitAnnotationUsage` isn't called for annotations If you want to just visit any annotation declarations (e.g. `@Foo` on method `foo`), don't use the `applicableAnnotations` and `visitAnnotationUsage` machinery. The purpose of that facility is to look at *elements* that are being combined with annotated elements, such as a method call to a method whose return value has been annotated, or an argument to a method a method parameter that has been annotated, or assigning an assigned value to an annotated variable, etc. If you just want to look at annotations, use `getApplicableUastTypes` with `UAnnotation::class.java`, and a `UElementHandler` which overrides `visitAnnotation`. ### How do I check if a UAST or PSI element is for Java or Kotlin? To check whether an element is in Java or Kotlin, call one of the package level methods in the detector API (and from Java, you can access them as utility methods on the “Lint” class) : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~kotlin package com.android.tools.lint.detector.api /** Returns true if the given element is written in Java. */ fun isJava(element: PsiElement?): Boolean { /* ... */ } /** Returns true if the given language is Kotlin. */ fun isKotlin(language: Language?): Boolean { /* ... */ } /** Returns true if the given language is Java. */ fun isJava(language: Language?): Boolean { /* ... */ } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you have a `UElement` and need a `PsiElement` for the above method, see the next question. ### What if I need a `PsiElement` and I have a `UElement` ? If you have a `UElement`, you can get the underlying source PSI element by calling `element.sourcePsi`. ### How do I get the `UMethod` for a `PsiMethod` ? Call `psiMethod.toUElementOfType<UMethod>()`. Note that this may return null if UAST cannot find valid Java or Kotlin source code for the method. For `PsiField` and `PsiClass` instances use the equivalent `toUElementOfType` type arguments. ### How do get a `JavaEvaluator`? The `Context` passed into most of the `Detector` callback methods relevant to Kotlin and Java analysis is of type `JavaContext`, and it has a public `evaluator` property which provides a `JavaEvaluator` you can use in your analysis. If you need one outside of that scenario (this is not common) you can construct one directly by instantiating a `DefaultJavaEvaluator`; the constructor parameters are nullable, and are only needed for a couple of operations on the evaluator. ### How do I check whether an element is internal? First get a `JavaEvaluator` as explained above, then call this evaluator method: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ open fun isInternal(owner: PsiModifierListOwner?): Boolean { /* ... */ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (Note that a `PsiModifierListOwner` is an interface which includes `PsiMethod`, `PsiClass`, `PsiField`, `PsiMember`, `PsiVariable`, etc.) ### Is element inline, sealed, operator, infix, suspend, data? Get the `JavaEvaluator` as explained above, and then call one of these evaluator method: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ open fun isData(owner: PsiModifierListOwner?): Boolean { /* ... */ open fun isInline(owner: PsiModifierListOwner?): Boolean { /* ... */ open fun isLateInit(owner: PsiModifierListOwner?): Boolean { /* ... */ open fun isSealed(owner: PsiModifierListOwner?): Boolean { /* ... */ open fun isOperator(owner: PsiModifierListOwner?): Boolean { /* ... */ open fun isInfix(owner: PsiModifierListOwner?): Boolean { /* ... */ open fun isSuspend(owner: PsiModifierListOwner?): Boolean { /* ... */ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ### How do I look up a class if I have its fully qualified name? Get the `JavaEvaluator` as explained above, then call `evaluator.findClass(qualifiedName: String)`. Note that the result is nullable. ### How do I look up a class if I have a PsiType? Get the `JavaEvaluator` as explained above, then call `evaluator.getTypeClass`. To go from a class to its type, use `getClassType`. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~kotlin abstract fun getClassType(psiClass: PsiClass?): PsiClassType? abstract fun getTypeClass(psiType: PsiType?): PsiClass? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ### How do I look up hierarchy annotations for an element? You can directly look up annotations via the modified list of PsiElement or the annotations for a `UAnnotated` element, but if you want to search the inheritance hierarchy for annotations (e.g. if a method is overriding another, get any annotations specified on super implementations), use one of these two evaluator methods: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~kotlin abstract fun getAllAnnotations( owner: UAnnotated, inHierarchy: Boolean ): List abstract fun getAllAnnotations( owner: PsiModifierListOwner, inHierarchy: Boolean ): Array ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ### How do I look up if a class is a subclass of another? To see if a method is a direct member of a particular named class, use the following method in `JavaEvaluator`: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~kotlin fun isMemberInClass(member: PsiMember?, className: String): Boolean { } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To see if a method is a member in any *subclass* of a named class, use ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~kotlin open fun isMemberInSubClassOf( member: PsiMember, className: String, strict: Boolean = false ): Boolean { /* ... */ } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Here, use `strict = true` if you don't want to include members in the named class itself as a match. To see if a class extends another or implements an interface, use one of these methods. Again, `strict` controls whether we include the super class or super interface itself as a match. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ abstract fun extendsClass( cls: PsiClass?, className: String, strict: Boolean = false ): Boolean abstract fun implementsInterface( cls: PsiClass, interfaceName: String, strict: Boolean = false ): Boolean ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ### How do I know which parameter a call argument corresponds to? In Java, matching up the arguments in a call with the parameters in the called method is easy: the first argument corresponds to the first parameter, the second argument corresponds to the second parameter and so on. If there are more arguments than parameters, the last arguments are all vararg arguments to the last parameter. In Kotlin, it's much more complicated. With named parameters, but arguments can appear in any order, and with default parameters, only some of them may be specified. And if it's an extension method, the first argument passed to a `PsiMethod` is actually the instance itself. Lint has a utility method to help with this on the `JavaEvaluator`: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ open fun computeArgumentMapping( call: UCallExpression, method: PsiMethod ): Map<UExpression, PsiParameter> { /* ... */ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This returns a map from UAST expressions (each argument to a UAST call is a `UExpression`, and these are the `valueArguments` property on the `UCallExpression`) to each corresponding `PsiParameter` on the `PsiMethod` that the method calls. ### How can my lint checks target two different versions of lint? If you need to ship different versions of your lint checks to target different versions of lint (because perhaps you need to work both with an older version of lint, and a newer version that has a different API), the way to do this (as of Lint 7.0) is to use the `maxApi` property on the `IssueRegistry`. In the service loader registration (`META-INF/services`), register *two* issue registries; one for each implementation, and mark the older one with the right `minApi` to `maxApi` range, and the newer one with `minApi` following the previous registry's `maxApi`. (Both `minApi` and `maxApi` are inclusive). When lint loads the issue registries it will ignore registries with a range outside of the current API level. ### Can I make my lint check “not suppressible?” In some (hopefully rare) cases, you may want your lint checks to not be suppressible using the normal mechanisms -- suppress annotations, comments, lint.xml files, baselines, and so on. The usecase for this is typically strict company guidelines around compliance or security and you want to remove the easy possibility of just silencing the check. This is possible as part of the issue registration. After creating your `Issue`, set the `suppressNames` property to an **empty** collection. ### Why are overloaded operators not handled? Kotlin supports overloaded operators, but these are not handled as calls in the AST -- instead, an implicit `get` or `set` method from an array access will show up as a `UArrayAccessExpression`. Lint has specific support to help handling these scenarios; see the “Implicit Calls” section in the [basics chapter](basics.md.html). ### How do I check out the current lint source code? ```shell $ git clone --branch=mirror-goog-studio-main --single-branch \ https://android.googlesource.com/platform/tools/base Cloning into 'base'... remote: Total 648820 (delta 325442), reused 635137 (delta 325442) Receiving objects: 100% (648820/648820), 1.26 GiB | 15.52 MiB/s, done. Resolving deltas: 100% (325442/325442), done. Updating files: 100% (14416/14416), done. $ du -sh base 1.8G base $ cd base/lint $ ls .editorconfig BUILD build.gradle libs/ .gitignore MODULE_LICENSE_APACHE2 cli/ $ ls libs/ intellij-core/ kotlin-compiler/ lint-api/ lint-checks/ lint-gradle/ lint-model/ lint-tests/ uast/ ``` ### Where do I find examples of lint checks? The built-in lint checks are a good source. Check out the source code as shown above and look in `lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/` or browse sources online: [](https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/) ### How do I analyze details about Kotlin? The new Kotlin Analysis API offers access to detailed information about Kotlin (types, resolution, as well as information the compiler has figured out such as smart casts, nullability, deprecation info, and so on). There are more details about this, as well as a number of recipes, in the [AST Analysis chapter](ast-analysis.md.html).