blob: 08d1776f9a5d5082c90550a2181a49f7cb0f6e69 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.idea.fir.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiVariable
import com.intellij.psi.util.PsiUtilCore
import com.intellij.psi.util.parentOfType
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle
import org.jetbrains.kotlin.idea.highlighter.textAttributesKeyForPropertyDeclaration
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtBackingFieldSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.idea.highlighter.NameHighlighter
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal class VariableReferenceHighlightingVisitor(
analysisSession: KtAnalysisSession,
holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
if (!NameHighlighter.namesHighlightingEnabled) return
if (expression.isAssignmentReference()) return
if (expression.isByNameArgumentReference()) return
if (expression.parent is KtInstanceExpressionWithLabel) return
if (expression.isAutoCreatedItParameter()) {
createInfoAnnotation(
expression,
KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type"),
Colors.FUNCTION_LITERAL_DEFAULT_PARAMETER
)
return
}
with(analysisSession) {
val targetSymbol = expression.mainReference.resolveToSymbol()
val target = expression.mainReference.resolve()
when {
targetSymbol is KtBackingFieldSymbol -> Colors.BACKING_FIELD_VARIABLE
target is PsiMethod -> Colors.SYNTHETIC_EXTENSION_PROPERTY
target != null -> textAttributesKeyForPropertyDeclaration(target)
else -> null
}?.let { attribute ->
highlightName(expression, attribute)
if (target?.isMutableVariable() == true || targetSymbol != null && isBackingFieldReferencingMutableVariable(targetSymbol)) {
highlightName(expression, Colors.MUTABLE_VARIABLE)
}
}
}
}
@Suppress("unused")
private fun KtAnalysisSession.isBackingFieldReferencingMutableVariable(symbol: KtSymbol): Boolean {
if (symbol !is KtBackingFieldSymbol) return false
return !symbol.owningProperty.isVal
}
private fun KtSimpleNameExpression.isByNameArgumentReference() =
parent is KtValueArgumentName
private fun KtSimpleNameExpression.isAutoCreatedItParameter(): Boolean {
return getReferencedName() == "it" // todo
}
}
private fun PsiElement.isMutableVariable() = when {
this is KtValVarKeywordOwner && PsiUtilCore.getElementType(valOrVarKeyword) == KtTokens.VAR_KEYWORD -> true
this is PsiVariable && !hasModifierProperty(PsiModifier.FINAL) -> true
else -> false
}
private fun KtSimpleNameExpression.isAssignmentReference(): Boolean {
if (this !is KtOperationReferenceExpression) return false
return operationSignTokenType == KtTokens.EQ
}
|