Как проверить, используется ли результат выражения в пользовательском правиле Android lint

Я пытаюсь написать правило lint, чтобы поймать места, где результат функции RxJava2 никак не используется. Например:

final Observable<String> observable = getObservable();
observable.subscribe(this::onSuccess, this::onError);

В RxJava2 функция subscribe возвращает Disposable, который следует использовать для отмены подписки, если экземпляр программы/класса каким-то образом "заканчивается", чтобы предотвратить утечку памяти. Я хочу, чтобы моя сборка завершилась неудачей, если будут обнаружены подобные случаи.

Этот конкретный метод (и все остальные, которые меня интересуют) помечен io.reactivex.annotations.CheckReturnValue:

@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {
    return subscribe(onNext, onError, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}

Мой план состоит в том, чтобы написать пользовательское правило lint, которое:

  • Ищет выражения, которые возвращают результат метода, аннотированного io.reactivex.annotations.CheckReturnValue.
  • Отфильтруйте результаты поиска, указав только те выражения, результат которых никогда не используется.

Например, вот некоторые случаи, которые не должны дать сбой:

final CompositeDisposable compositeDisposable = new CompositeDisposable();
// Result of subscribe passed into another function
compositeDisposable.add(observable.subscribe(this::onSuccess, this::onError).dispose());

// Result of subscribe stored in a variable
final Disposable disposable = observable.subscribe(this::onSuccess, this::onError);

// Result of subscribe used
observable.subscribe(this::onSuccess, this::onError).dispose();

Мне удалось написать правило lint, которое находит экземпляры выражений вызова, результат которых помечен CheckReturnValue, но я изо всех сил пытаюсь понять, как использовать API-интерфейсы JetBrains UAST/PSI, чтобы определить, используется ли результат. Это мое правило до сих пор:

class RxJava2CheckReturnValueMethodNotAssigned : Detector(), Detector.UastScanner {
    override fun getApplicableUastTypes() = listOf(UCallExpression::class.java)

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

    class CheckReturnValueVisitor(private val context: JavaContext) : UElementHandler() {

        override fun visitCallExpression(node: UCallExpression) {
            val method = node.resolve() ?: return
            if (!isCheckReturnValueAnnotatedMethod(method)) {
                return
            }
            if (!isResultOfCallUsed(node)) {
                return
            }

            reportIssue(node)
        }

        private fun isCheckReturnValueAnnotatedMethod(method: PsiMethod): Boolean {
            return context.evaluator.getAllAnnotations(method, true)
                .any { "io.reactivex.annotations.CheckReturnValue" == it.qualifiedName }
        }

        private fun isResultOfCallUsed(node: UCallExpression): Boolean {
            // Need to check is the result of the expression is used in some way
            return false
        }

        private fun reportIssue(node: UCallExpression) {
            // SNIP...
        }
    }
}

В настоящее время это не работает, поскольку сообщает обо всех случаях использования любой функции, помеченной CheckReturnValue.


person oggmonster    schedule 04.04.2018    source источник
comment
Android Lint уже делает это?   -  person nhaarman    schedule 04.04.2018
comment
@nhaarman Это отображается в Android Studio, но я не знаю, как повысить серьезность до уровня ошибки или, по крайней мере, сгенерировать его в выходном файле lint. Любые идеи о том, как это сделать?   -  person oggmonster    schedule 04.04.2018
comment
Если вы просто хотите повысить уровень серьезности, вы можете добавить что-то вроде <issue id="CheckReturnValue" severity="error" /> в свой файл lint.xml.   -  person marianosimone    schedule 10.04.2018


Ответы (1)


Насколько я знаю, node.resolve() часто возвращает null

person YouCii    schedule 21.05.2020