Глубокий поиск использования значения поля - PullRequest
0 голосов
/ 04 июля 2019

Я хочу написать проверку, которая отслеживает вызовы методов для объекта, который находится в поле.Для меня алгоритм выглядит следующим образом:

  • Найти интересные поля,
  • найти все «прочитанные» использования данного поля
    • , если это вызов метода (например, field.method()), мы закончили
    • оператор, использующий это вызов метода, тоже
    • , если это присваивание (variable = field), отследите левую переменную / поле так жеway
    • , если он является параметром метода (method(field)), параметр метода трассировки использует
    • ну, это все возможно?

Первый прост: я хочу поддерживать Java и Kotlin, поэтому я расширил AbstractBaseUastLocalInspectionTool, переопределил checkField метод и добавил несколько проверок, которые помогают мне узнать, заинтересован ли я в этом поле.

Тогда, похоже, мне нужно поиск ссылок .Хорошо, ReferencesSearch.search(field.sourceElement).forEach { ... } будет вызывать мою лямбду для каждого использования моего поля, но теперь я застрял:

  1. Как классифицировать данные PsiReference с?Я могу получить PsiElement, и он может появиться PsiExpression или KtExpression.Но и это не может.Существует ли исчерпывающий список всех возможных случаев и способов их обработки (посещения)?

  2. PsiReference.element больше не является UAST.Должен ли я пропустить какой-либо элемент PSI через UastVisitorAdapter?

  3. Поиск использования, похоже, является распространенной схемой при разработке инспекций.Может быть, есть некоторые высокоуровневые абстракции, чтобы сделать это?

Когда я пытался извлечь имя метода из вызовов, я написал это, и я уверен, что много угловых случаевостаются необработанными:

private val PsiReference.outerMethodName: String? get() {
    val el = element
    if (el is PsiExpression) {
        ((el.parent as? PsiReferenceExpression)?.parent as? PsiMethodCallExpression)?.methodExpression?.let {
            if (this === it.qualifierExpression) {
                return it.referenceName
            }
        }
    }

    if (el is KtExpression) {
        el.context?.children?.let {
            if (it.size == 2 && (it[0] as? KtNameReferenceExpression)?.references?.firstOrNull() === this) {
                return (it[1] as? KtCallExpression)?.firstChild?.text
            }
        }
    }

    return null
}
...