Skip to content

Commit 610372d

Browse files
committed
Splitting the Reference class and caching reference resolution
1 parent 88702a0 commit 610372d

File tree

6 files changed

+249
-80
lines changed

6 files changed

+249
-80
lines changed

src/main/kotlin/org/domaframework/doma/intellij/common/psi/PsiPatternUtil.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import com.intellij.psi.util.elementType
2525
import com.intellij.psi.util.prevLeaf
2626
import com.intellij.psi.util.prevLeafs
2727
import com.intellij.util.ProcessingContext
28+
import org.domaframework.doma.intellij.psi.SqlElClass
29+
import org.domaframework.doma.intellij.psi.SqlElIdExpr
2830
import org.domaframework.doma.intellij.psi.SqlTypes
2931

3032
object PsiPatternUtil {
@@ -84,6 +86,22 @@ object PsiPatternUtil {
8486
},
8587
)
8688

89+
fun createReferencePattern(): PsiElementPattern.Capture<PsiElement> =
90+
PlatformPatterns.psiElement().with(
91+
object : PatternCondition<PsiElement>("PsiReferenceParentCondition") {
92+
override fun accepts(
93+
element: PsiElement,
94+
context: ProcessingContext?,
95+
): Boolean {
96+
if (element is SqlElClass) return true
97+
if (element is SqlElIdExpr) {
98+
return PsiTreeUtil.getParentOfType(element, SqlElClass::class.java) == null
99+
}
100+
return false
101+
}
102+
},
103+
)
104+
87105
/**
88106
* Get the string to search from the cursor position to the start of a block comment or a blank space
89107
* @return search Keyword
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright Doma Tools Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.domaframework.doma.intellij.reference
17+
18+
import com.intellij.psi.PsiElement
19+
import com.intellij.psi.PsiFile
20+
import com.intellij.psi.PsiReferenceBase
21+
import com.intellij.psi.util.CachedValue
22+
import com.intellij.psi.util.CachedValueProvider
23+
import com.intellij.psi.util.CachedValuesManager
24+
import com.intellij.psi.util.PsiModificationTracker
25+
import org.domaframework.doma.intellij.common.PluginLoggerUtil
26+
import org.domaframework.doma.intellij.common.isSupportFileType
27+
import org.domaframework.doma.intellij.common.psi.PsiStaticElement
28+
29+
class SqlElClassExprReference(
30+
element: PsiElement,
31+
) : PsiReferenceBase<PsiElement>(element) {
32+
init {
33+
println("SqlElClassExprReference initialized with element: ${element.text}")
34+
}
35+
36+
private val cachedResolve: CachedValue<PsiElement?> by lazy {
37+
CachedValuesManager.getManager(element.project).createCachedValue {
38+
val result = doResolve()
39+
CachedValueProvider.Result(result, PsiModificationTracker.MODIFICATION_COUNT)
40+
}
41+
}
42+
43+
val file: PsiFile? = element.containingFile
44+
45+
override fun resolve(): PsiElement? = cachedResolve.value
46+
47+
private fun doResolve(): PsiElement? {
48+
if (file == null || !isSupportFileType(file)) return null
49+
val startTime = System.nanoTime()
50+
return superResolveLogic(startTime, file) // 例: 実際の解決処理
51+
}
52+
53+
private fun superResolveLogic(
54+
startTime: Long,
55+
file: PsiFile,
56+
): PsiElement? {
57+
val variableName = element.text
58+
val psiStaticElement = PsiStaticElement(variableName, file)
59+
PluginLoggerUtil.countLogging(
60+
this::class.java.simpleName,
61+
"ReferenceStaticClass",
62+
"Reference",
63+
startTime,
64+
)
65+
return psiStaticElement.getRefClazz()
66+
}
67+
68+
override fun getVariants(): Array<Any> = emptyArray()
69+
}

src/main/kotlin/org/domaframework/doma/intellij/reference/SqlReference.kt renamed to src/main/kotlin/org/domaframework/doma/intellij/reference/SqlElIdExprReference.kt

Lines changed: 25 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -20,48 +20,61 @@ import com.intellij.psi.PsiFile
2020
import com.intellij.psi.PsiMethod
2121
import com.intellij.psi.PsiReferenceBase
2222
import com.intellij.psi.PsiType
23+
import com.intellij.psi.util.CachedValue
24+
import com.intellij.psi.util.CachedValueProvider
25+
import com.intellij.psi.util.CachedValuesManager
26+
import com.intellij.psi.util.PsiModificationTracker
2327
import com.intellij.psi.util.PsiTreeUtil
24-
import com.intellij.psi.util.PsiTypesUtil
2528
import com.intellij.psi.util.elementType
2629
import com.intellij.psi.util.nextLeafs
2730
import org.domaframework.doma.intellij.common.PluginLoggerUtil
2831
import org.domaframework.doma.intellij.common.dao.findDaoMethod
2932
import org.domaframework.doma.intellij.common.isSupportFileType
3033
import org.domaframework.doma.intellij.common.psi.PsiParentClass
31-
import org.domaframework.doma.intellij.common.psi.PsiStaticElement
3234
import org.domaframework.doma.intellij.extension.psi.findParameter
3335
import org.domaframework.doma.intellij.extension.psi.getDomaAnnotationType
3436
import org.domaframework.doma.intellij.extension.psi.getForItem
3537
import org.domaframework.doma.intellij.extension.psi.getIterableClazz
3638
import org.domaframework.doma.intellij.extension.psi.methodParameters
3739
import org.domaframework.doma.intellij.inspection.sql.inspector.SqlBindVariableValidInspector.BlockType
38-
import org.domaframework.doma.intellij.psi.SqlElClass
3940
import org.domaframework.doma.intellij.psi.SqlElFieldAccessExpr
4041
import org.domaframework.doma.intellij.psi.SqlElForDirective
4142
import org.domaframework.doma.intellij.psi.SqlElIdExpr
42-
import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr
4343
import org.domaframework.doma.intellij.psi.SqlTypes
4444

45-
class SqlReference(
45+
class SqlElIdExprReference(
4646
element: PsiElement,
4747
) : PsiReferenceBase<PsiElement>(element) {
48+
init {
49+
println("SqlElIdExprReference initialized with element: ${element.text}")
50+
}
51+
52+
private val cachedResolve: CachedValue<PsiElement?> by lazy {
53+
CachedValuesManager.getManager(element.project).createCachedValue {
54+
val result = doResolve()
55+
CachedValueProvider.Result(result, PsiModificationTracker.MODIFICATION_COUNT)
56+
}
57+
}
58+
4859
val file: PsiFile? = element.containingFile
4960

5061
data class ForIfDirectiveBlock(
5162
val type: BlockType,
5263
val element: PsiElement,
5364
)
5465

55-
override fun resolve(): PsiElement? {
66+
override fun resolve(): PsiElement? = cachedResolve.value
67+
68+
private fun doResolve(): PsiElement? {
5669
if (file == null || !isSupportFileType(file)) return null
5770
val startTime = System.nanoTime()
58-
val variableName = element.text
59-
60-
val staticDirective = getStaticDirective(element, variableName, startTime)
61-
if (staticDirective != null) {
62-
return staticDirective
63-
}
71+
return superResolveLogic(startTime, file)
72+
}
6473

74+
private fun superResolveLogic(
75+
startTime: Long,
76+
file: PsiFile,
77+
): PsiElement? {
6578
val targetElement = getBlockCommentElements(element)
6679
if (targetElement.isEmpty()) return null
6780

@@ -89,69 +102,10 @@ class SqlReference(
89102

90103
else -> getReferenceEntity(daoMethod, targetElement, startTime)
91104
}
92-
93-
return null
94105
}
95106

96107
override fun getVariants(): Array<Any> = emptyArray()
97108

98-
private fun getStaticDirective(
99-
staticDirection: PsiElement?,
100-
elementName: String,
101-
startTime: Long,
102-
): PsiElement? {
103-
if (staticDirection == null) return null
104-
val file: PsiFile = file ?: return null
105-
// Jump to class definition
106-
val classParent = PsiTreeUtil.getParentOfType(staticDirection, SqlElClass::class.java)
107-
if (classParent != null) {
108-
val psiStaticElement = PsiStaticElement(staticDirection.text, file)
109-
PluginLoggerUtil.countLogging(
110-
this::class.java.simpleName,
111-
"ReferenceStaticClass",
112-
"Reference",
113-
startTime,
114-
)
115-
return psiStaticElement.getRefClazz()
116-
}
117-
118-
// Jump from field or method to definition (assuming the top element is static)
119-
val staticAccessParent =
120-
PsiTreeUtil.getParentOfType(staticDirection, SqlElStaticFieldAccessExpr::class.java)
121-
if (staticAccessParent != null) {
122-
val firstChildText =
123-
staticAccessParent.children
124-
.firstOrNull()
125-
?.text ?: ""
126-
val psiStaticElement =
127-
PsiStaticElement(
128-
firstChildText,
129-
file,
130-
)
131-
val javaClazz = psiStaticElement.getRefClazz() ?: return null
132-
val psiParentClass = PsiParentClass(PsiTypesUtil.getClassType(javaClazz))
133-
psiParentClass.findField(elementName)?.let {
134-
PluginLoggerUtil.countLogging(
135-
this::class.java.simpleName,
136-
"ReferenceStaticField",
137-
"Reference",
138-
startTime,
139-
)
140-
return it
141-
}
142-
psiParentClass.findMethod(elementName)?.let {
143-
PluginLoggerUtil.countLogging(
144-
this::class.java.simpleName,
145-
"ReferenceStaticMethod",
146-
"Reference",
147-
startTime,
148-
)
149-
return it
150-
}
151-
}
152-
return null
153-
}
154-
155109
private fun getBlockCommentElements(element: PsiElement): List<PsiElement> {
156110
val fieldAccessExpr = PsiTreeUtil.getParentOfType(element, SqlElFieldAccessExpr::class.java)
157111
val nodeElm =
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright Doma Tools Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.domaframework.doma.intellij.reference
17+
18+
import com.intellij.psi.PsiElement
19+
import com.intellij.psi.PsiFile
20+
import com.intellij.psi.PsiReferenceBase
21+
import com.intellij.psi.util.CachedValue
22+
import com.intellij.psi.util.CachedValueProvider
23+
import com.intellij.psi.util.CachedValuesManager
24+
import com.intellij.psi.util.PsiModificationTracker
25+
import com.intellij.psi.util.PsiTreeUtil
26+
import com.intellij.psi.util.PsiTypesUtil
27+
import org.domaframework.doma.intellij.common.PluginLoggerUtil
28+
import org.domaframework.doma.intellij.common.isSupportFileType
29+
import org.domaframework.doma.intellij.common.psi.PsiParentClass
30+
import org.domaframework.doma.intellij.common.psi.PsiStaticElement
31+
import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr
32+
33+
class SqlElStaticFieldReference(
34+
element: PsiElement,
35+
) : PsiReferenceBase<PsiElement>(element) {
36+
init {
37+
println("SqlElStaticFieldReference initialized with element: ${element.text}")
38+
}
39+
40+
private val cachedResolve: CachedValue<PsiElement?> by lazy {
41+
CachedValuesManager.getManager(element.project).createCachedValue {
42+
val result = doResolve()
43+
CachedValueProvider.Result(result, PsiModificationTracker.MODIFICATION_COUNT)
44+
}
45+
}
46+
47+
val file: PsiFile? = element.containingFile
48+
49+
override fun resolve(): PsiElement? = cachedResolve.value
50+
51+
private fun doResolve(): PsiElement? {
52+
if (file == null || !isSupportFileType(file)) return null
53+
val startTime = System.nanoTime()
54+
return superResolveLogic(startTime)
55+
}
56+
57+
private fun superResolveLogic(startTime: Long): PsiElement? {
58+
val variableName = element.text
59+
val staticDirective = getStaticDirective(element, variableName, startTime)
60+
if (staticDirective != null) {
61+
return staticDirective
62+
}
63+
64+
return null
65+
}
66+
67+
override fun getVariants(): Array<Any> = emptyArray()
68+
69+
private fun getStaticDirective(
70+
staticDirection: PsiElement?,
71+
elementName: String,
72+
startTime: Long,
73+
): PsiElement? {
74+
if (staticDirection == null) return null
75+
val file: PsiFile = file ?: return null
76+
77+
// Jump from field or method to definition (assuming the top element is static)
78+
val staticAccessParent =
79+
PsiTreeUtil.getParentOfType(staticDirection, SqlElStaticFieldAccessExpr::class.java)
80+
if (staticAccessParent != null) {
81+
val firstChildText =
82+
staticAccessParent.children
83+
.firstOrNull()
84+
?.text ?: ""
85+
val psiStaticElement =
86+
PsiStaticElement(
87+
firstChildText,
88+
file,
89+
)
90+
val javaClazz = psiStaticElement.getRefClazz() ?: return null
91+
val psiParentClass = PsiParentClass(PsiTypesUtil.getClassType(javaClazz))
92+
psiParentClass.findField(elementName)?.let {
93+
PluginLoggerUtil.countLogging(
94+
this::class.java.simpleName,
95+
"ReferenceStaticField",
96+
"Reference",
97+
startTime,
98+
)
99+
return it
100+
}
101+
psiParentClass.findMethod(elementName)?.let {
102+
PluginLoggerUtil.countLogging(
103+
this::class.java.simpleName,
104+
"ReferenceStaticMethod",
105+
"Reference",
106+
startTime,
107+
)
108+
return it
109+
}
110+
}
111+
return null
112+
}
113+
}

src/main/kotlin/org/domaframework/doma/intellij/reference/SqlPsiReferenceProvider.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,36 @@ package org.domaframework.doma.intellij.reference
1818
import com.intellij.psi.PsiElement
1919
import com.intellij.psi.PsiReference
2020
import com.intellij.psi.PsiReferenceProvider
21+
import com.intellij.psi.util.PsiTreeUtil
2122
import com.intellij.util.ProcessingContext
2223
import org.domaframework.doma.intellij.psi.SqlCustomElExpr
24+
import org.domaframework.doma.intellij.psi.SqlElClass
25+
import org.domaframework.doma.intellij.psi.SqlElIdExpr
26+
import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr
2327

2428
class SqlPsiReferenceProvider : PsiReferenceProvider() {
2529
override fun getReferencesByElement(
2630
element: PsiElement,
2731
context: ProcessingContext,
2832
): Array<out PsiReference?> {
2933
if (element !is SqlCustomElExpr) return PsiReference.EMPTY_ARRAY
30-
return arrayOf(SqlReference(element))
34+
35+
return when (element) {
36+
is SqlElClass -> arrayOf(SqlElClassExprReference(element))
37+
is SqlElIdExpr ->
38+
if (PsiTreeUtil.getParentOfType(element, SqlElClass::class.java) != null) {
39+
arrayOf(SqlElClassExprReference(element))
40+
} else if (PsiTreeUtil.getParentOfType(
41+
element,
42+
SqlElStaticFieldAccessExpr::class.java,
43+
) != null
44+
) {
45+
arrayOf(SqlElStaticFieldReference(element))
46+
} else {
47+
arrayOf(SqlElIdExprReference(element))
48+
}
49+
50+
else -> PsiReference.EMPTY_ARRAY
51+
}
3152
}
3253
}

0 commit comments

Comments
 (0)