@@ -22,25 +22,37 @@ import com.intellij.psi.PsiReferenceBase
2222import com.intellij.psi.PsiType
2323import com.intellij.psi.util.PsiTreeUtil
2424import com.intellij.psi.util.PsiTypesUtil
25+ import com.intellij.psi.util.elementType
26+ import com.intellij.psi.util.nextLeafs
2527import org.domaframework.doma.intellij.common.PluginLoggerUtil
2628import org.domaframework.doma.intellij.common.dao.findDaoMethod
2729import org.domaframework.doma.intellij.common.isSupportFileType
2830import org.domaframework.doma.intellij.common.psi.PsiParentClass
2931import org.domaframework.doma.intellij.common.psi.PsiStaticElement
3032import org.domaframework.doma.intellij.extension.psi.findParameter
3133import org.domaframework.doma.intellij.extension.psi.getDomaAnnotationType
34+ import org.domaframework.doma.intellij.extension.psi.getForItem
3235import org.domaframework.doma.intellij.extension.psi.getIterableClazz
3336import org.domaframework.doma.intellij.extension.psi.methodParameters
37+ import org.domaframework.doma.intellij.inspection.sql.inspector.SqlBindVariableValidInspector.BlockType
3438import org.domaframework.doma.intellij.psi.SqlElClass
3539import org.domaframework.doma.intellij.psi.SqlElFieldAccessExpr
40+ import org.domaframework.doma.intellij.psi.SqlElForDirective
3641import org.domaframework.doma.intellij.psi.SqlElIdExpr
42+ import org.domaframework.doma.intellij.psi.SqlElPrimaryExpr
3743import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr
44+ import org.domaframework.doma.intellij.psi.SqlTypes
3845
3946class SqlReference (
4047 element : PsiElement ,
4148) : PsiReferenceBase<PsiElement>(element) {
4249 val file: PsiFile ? = element.containingFile
4350
51+ data class ForIfDirectiveBlock (
52+ val type : BlockType ,
53+ val element : PsiElement ,
54+ )
55+
4456 override fun resolve (): PsiElement ? {
4557 if (file == null || ! isSupportFileType(file)) return null
4658 val startTime = System .nanoTime()
@@ -54,6 +66,18 @@ class SqlReference(
5466 val targetElement = getBlockCommentElements(element)
5567 if (targetElement.isEmpty()) return null
5668
69+ val topElm = targetElement.firstOrNull() as SqlElPrimaryExpr
70+ findInForDirectiveBlock(topElm)
71+ ?.let {
72+ PluginLoggerUtil .countLogging(
73+ this ::class .java.simpleName,
74+ " ReferenceForDirective" ,
75+ " Reference" ,
76+ startTime,
77+ )
78+ return it
79+ }
80+
5781 val daoMethod = findDaoMethod(file) ? : return null
5882
5983 return when (element.textOffset) {
@@ -94,7 +118,8 @@ class SqlReference(
94118 }
95119
96120 // Jump from field or method to definition (assuming the top element is static)
97- val staticAccessParent = PsiTreeUtil .getParentOfType(staticDirection, SqlElStaticFieldAccessExpr ::class .java)
121+ val staticAccessParent =
122+ PsiTreeUtil .getParentOfType(staticDirection, SqlElStaticFieldAccessExpr ::class .java)
98123 if (staticAccessParent != null ) {
99124 val firstChildText =
100125 staticAccessParent.children
@@ -234,4 +259,58 @@ class SqlReference(
234259 }
235260 return null
236261 }
262+
263+ private fun findInForDirectiveBlock (targetElement : PsiElement ): PsiElement ? {
264+ val forBlocks = getForDirectiveBlock(targetElement)
265+ val targetName =
266+ targetElement.text
267+ .replace(" _has_next" , " " )
268+ .replace(" _index" , " " )
269+ val matchForDirectiveItem = forBlocks.lastOrNull { it.element.text == targetName }
270+ if (matchForDirectiveItem != null ) {
271+ return matchForDirectiveItem.element
272+ }
273+ return null
274+ }
275+
276+ private fun getForDirectiveBlock (targetElement : PsiElement ): List <ForIfDirectiveBlock > {
277+ val topElm = targetElement.containingFile.firstChild ? : return emptyList()
278+ val directiveBlocks =
279+ topElm.nextLeafs
280+ .filter { elm ->
281+ elm.elementType == SqlTypes .EL_FOR ||
282+ elm.elementType == SqlTypes .EL_IF ||
283+ elm.elementType == SqlTypes .EL_END
284+ }.map {
285+ when (it.elementType) {
286+ SqlTypes .EL_FOR -> {
287+ (it.parent as ? SqlElForDirective )
288+ ?.getForItem()
289+ ?.let { item ->
290+ ForIfDirectiveBlock (
291+ BlockType .FOR ,
292+ item,
293+ )
294+ } ? : ForIfDirectiveBlock (
295+ BlockType .FOR ,
296+ it,
297+ )
298+ }
299+
300+ SqlTypes .EL_IF -> ForIfDirectiveBlock (BlockType .IF , it)
301+ else -> ForIfDirectiveBlock (BlockType .END , it)
302+ }
303+ }
304+ val preBlocks =
305+ directiveBlocks
306+ .filter { it.element.textOffset <= targetElement.textOffset }
307+ val stack = mutableListOf<ForIfDirectiveBlock >()
308+ preBlocks.forEach { block ->
309+ when (block.type) {
310+ BlockType .FOR , BlockType .IF -> stack.add(block)
311+ BlockType .END -> if (stack.isNotEmpty()) stack.removeAt(stack.lastIndex)
312+ }
313+ }
314+ return stack.filter { it.type == BlockType .FOR }
315+ }
237316}
0 commit comments