Я хочу написать проверку, которая отслеживает вызовы методов для объекта, который находится в поле.Для меня алгоритм выглядит следующим образом:
- Найти интересные поля,
- найти все «прочитанные» использования данного поля
- , если это вызов метода (например,
field.method()
), мы закончили - оператор, использующий это вызов метода, тоже
- , если это присваивание (
variable = field
), отследите левую переменную / поле так жеway - , если он является параметром метода (
method(field)
), параметр метода трассировки использует - ну, это все возможно?
Первый прост: я хочу поддерживать Java и Kotlin, поэтому я расширил AbstractBaseUastLocalInspectionTool
, переопределил checkField
метод и добавил несколько проверок, которые помогают мне узнать, заинтересован ли я в этом поле.
Тогда, похоже, мне нужно поиск ссылок .Хорошо, ReferencesSearch.search(field.sourceElement).forEach { ... }
будет вызывать мою лямбду для каждого использования моего поля, но теперь я застрял:
Как классифицировать данные PsiReference
с?Я могу получить PsiElement
, и он может появиться PsiExpression
или KtExpression
.Но и это не может.Существует ли исчерпывающий список всех возможных случаев и способов их обработки (посещения)?
PsiReference.element
больше не является UAST.Должен ли я пропустить какой-либо элемент PSI через UastVisitorAdapter
?
Поиск использования, похоже, является распространенной схемой при разработке инспекций.Может быть, есть некоторые высокоуровневые абстракции, чтобы сделать это?
Когда я пытался извлечь имя метода из вызовов, я написал это, и я уверен, что много угловых случаевостаются необработанными:
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
}