@@ -33,18 +33,26 @@ import org.domaframework.doma.intellij.bundle.MessageBundle
3333import org.domaframework.doma.intellij.common.dao.getDaoClass
3434import org.domaframework.doma.intellij.common.isJavaOrKotlinFileType
3535import org.domaframework.doma.intellij.common.psi.PsiDaoMethod
36+ import org.domaframework.doma.intellij.common.util.ForDirectiveUtil
3637import org.domaframework.doma.intellij.extension.findFile
38+ import org.domaframework.doma.intellij.extension.psi.getForItem
3739import org.domaframework.doma.intellij.extension.psi.isCollector
3840import org.domaframework.doma.intellij.extension.psi.isFunctionClazz
3941import org.domaframework.doma.intellij.extension.psi.isSelectOption
4042import org.domaframework.doma.intellij.extension.psi.methodParameters
41- import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr
43+ import org.domaframework.doma.intellij.psi.SqlElForDirective
44+ import org.domaframework.doma.intellij.psi.SqlElPrimaryExpr
4245import org.domaframework.doma.intellij.psi.SqlTypes
4346
4447/* *
4548 * Check if Dao method arguments are used in the corresponding SQL file
4649 */
4750class DaoMethodVariableInspector : AbstractBaseJavaLocalInspectionTool () {
51+ private data class DaoMethodVariableVisitorResult (
52+ val elements : List <PsiParameter >,
53+ val deplicateForItemElements : List <PsiParameter >,
54+ )
55+
4856 override fun getDisplayName (): String = " Method argument usage check"
4957
5058 override fun getShortName (): String = " org.domaframework.doma.intellij.variablechecker"
@@ -76,38 +84,65 @@ class DaoMethodVariableInspector : AbstractBaseJavaLocalInspectionTool() {
7684 method.project.findFile(it)
7785 } ? : return
7886
79- findElementsInSqlFile(sqlFileManager, methodParameters.toList()).forEach { arg ->
80- holder.registerProblem(
81- (arg.originalElement as PsiParameterImpl ).nameIdentifier,
82- MessageBundle .message(" inspection.dao.method.variable.error" , arg.name),
83- ProblemHighlightType .ERROR ,
84- )
87+ val params = methodParameters.toList()
88+ val result = findElementsInSqlFile(sqlFileManager, params)
89+ params.forEach { param ->
90+ if (! result.elements.contains(param)) {
91+ val message =
92+ if (result.deplicateForItemElements.contains(param)) {
93+ MessageBundle .message(" inspection.invalid.dao.duplicate" )
94+ } else {
95+ MessageBundle .message(
96+ " inspection.dao.method.variable.error" ,
97+ param.name,
98+ )
99+ }
100+ holder.registerProblem(
101+ (param.originalElement as PsiParameterImpl ).nameIdentifier,
102+ message,
103+ ProblemHighlightType .ERROR ,
104+ )
105+ }
85106 }
86107 }
87108 }
88109 }
89110
90- fun findElementsInSqlFile (
111+ private fun findElementsInSqlFile (
91112 sqlFile : PsiFile ,
92113 args : List <PsiParameter >,
93- ): List < PsiParameter > {
114+ ): DaoMethodVariableVisitorResult {
94115 val elements = mutableListOf<PsiParameter >()
116+ val deplicateForItemElements = mutableListOf<PsiParameter >()
95117 var iterator: Iterator <PsiParameter >
96118 sqlFile.accept(
97119 object : PsiRecursiveElementVisitor () {
98120 // Recursively explore child elements in a file with PsiRecursiveElementVisitor.
99121 override fun visitElement (element : PsiElement ) {
100- if (element.elementType == SqlTypes .EL_IDENTIFIER && element.prevSibling?.elementType != SqlTypes .DOT ) {
122+ if ((
123+ element.elementType == SqlTypes .EL_IDENTIFIER ||
124+ element is SqlElPrimaryExpr
125+ ) &&
126+ element.prevSibling?.elementType != SqlTypes .DOT
127+ ) {
101128 iterator = args.minus(elements.toSet()).iterator()
102129 while (iterator.hasNext()) {
103130 val arg = iterator.next()
104- val fieldAccessExpr =
105- PsiTreeUtil .getParentOfType(
106- element,
107- SqlElStaticFieldAccessExpr ::class .java,
108- )
109- if (fieldAccessExpr == null && element.text == arg.name) {
110- elements.add(arg)
131+ if (element.text == arg.name) {
132+ // Check if you are in a For directive
133+ val elementParent = PsiTreeUtil .getParentOfType(element, SqlElForDirective ::class .java)
134+ val isForItemSide = elementParent?.getForItem()?.textOffset == element.textOffset
135+
136+ // Check if the element name definition source is in the for directive
137+ val forDirectiveBlocks =
138+ ForDirectiveUtil .getForDirectiveBlocks(element)
139+ val forItem = ForDirectiveUtil .findForItem(element, forDirectives = forDirectiveBlocks)
140+
141+ if (forItem != null || isForItemSide) {
142+ deplicateForItemElements.add(arg)
143+ } else {
144+ elements.add(arg)
145+ }
111146 break
112147 }
113148 }
@@ -116,6 +151,7 @@ class DaoMethodVariableInspector : AbstractBaseJavaLocalInspectionTool() {
116151 }
117152 },
118153 )
119- return args.minus(elements.toSet())
154+ val result = DaoMethodVariableVisitorResult (elements, deplicateForItemElements)
155+ return result
120156 }
121157}
0 commit comments