Skip to content

Commit 0292420

Browse files
authored
Merge pull request #136 from domaframework/feature/check-testdata-after-blockcomment
Add SQL test data validation inspections
2 parents 5b54352 + b91947d commit 0292420

File tree

20 files changed

+460
-51
lines changed

20 files changed

+460
-51
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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.common.sql.validator.result
17+
18+
import com.intellij.codeInspection.ProblemsHolder
19+
import com.intellij.openapi.project.Project
20+
import com.intellij.openapi.util.TextRange
21+
import com.intellij.psi.PsiElement
22+
import org.domaframework.doma.intellij.bundle.MessageBundle
23+
import org.domaframework.doma.intellij.common.psi.PsiParentClass
24+
25+
class ValidationTestDataResult(
26+
override val identify: PsiElement?,
27+
override val shortName: String = "",
28+
) : ValidationResult(identify, null, shortName) {
29+
override fun setHighlight(
30+
highlightRange: TextRange,
31+
identify: PsiElement,
32+
holder: ProblemsHolder,
33+
parent: PsiParentClass?,
34+
project: Project,
35+
) {
36+
val project = identify.project
37+
holder.registerProblem(
38+
identify,
39+
MessageBundle.message("inspection.invalid.sql.testdata"),
40+
problemHighlightType(project, shortName),
41+
highlightRange,
42+
)
43+
}
44+
}

src/main/kotlin/org/domaframework/doma/intellij/inspection/sql/inspector/SqlBindVariableValidInspector.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ package org.domaframework.doma.intellij.inspection.sql.inspector
1818
import com.intellij.codeHighlighting.HighlightDisplayLevel
1919
import com.intellij.codeInspection.LocalInspectionTool
2020
import com.intellij.codeInspection.ProblemsHolder
21-
import org.domaframework.doma.intellij.inspection.sql.SqlInspectionVisitor
21+
import org.domaframework.doma.intellij.inspection.sql.visitor.SqlInspectionVisitor
2222
import org.domaframework.doma.intellij.psi.SqlVisitor
2323

2424
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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.inspection.sql.inspector
17+
18+
import com.intellij.codeHighlighting.HighlightDisplayLevel
19+
import com.intellij.codeInspection.LocalInspectionTool
20+
import com.intellij.codeInspection.ProblemsHolder
21+
import org.domaframework.doma.intellij.inspection.sql.visitor.SqlTestDataAfterBlockCommentVisitor
22+
import org.domaframework.doma.intellij.psi.SqlVisitor
23+
24+
/**
25+
* Code inspection for SQL bind variables
26+
*/
27+
class SqlTestDataAfterBlockCommentValidValidInspector : LocalInspectionTool() {
28+
override fun getDisplayName(): String = "Check whether test data exists after the bind variable"
29+
30+
override fun getShortName(): String = "org.domaframework.doma.intellij.existaftertestdata"
31+
32+
override fun getGroupDisplayName(): String = "DomaTools"
33+
34+
override fun isEnabledByDefault(): Boolean = true
35+
36+
override fun getDefaultLevel(): HighlightDisplayLevel = HighlightDisplayLevel.Companion.ERROR
37+
38+
override fun runForWholeFile(): Boolean = true
39+
40+
override fun buildVisitor(
41+
holder: ProblemsHolder,
42+
isOnTheFly: Boolean,
43+
): SqlVisitor = SqlTestDataAfterBlockCommentVisitor(holder, this.shortName)
44+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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.inspection.sql.provider
17+
18+
import com.intellij.codeInspection.InspectionToolProvider
19+
import com.intellij.codeInspection.LocalInspectionTool
20+
import org.domaframework.doma.intellij.inspection.sql.inspector.SqlTestDataAfterBlockCommentValidValidInspector
21+
22+
class SqlTestDataAfterBlockCommentValidProvider : InspectionToolProvider {
23+
override fun getInspectionClasses(): Array<Class<out LocalInspectionTool>> =
24+
arrayOf(
25+
SqlTestDataAfterBlockCommentValidValidInspector::class.java,
26+
)
27+
}

src/main/kotlin/org/domaframework/doma/intellij/inspection/sql/SqlInspectionVisitor.kt renamed to src/main/kotlin/org/domaframework/doma/intellij/inspection/sql/visitor/SqlInspectionVisitor.kt

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.domaframework.doma.intellij.inspection.sql
16+
package org.domaframework.doma.intellij.inspection.sql.visitor
1717

1818
import com.intellij.codeInspection.ProblemsHolder
19-
import com.intellij.lang.injection.InjectedLanguageManager
20-
import com.intellij.openapi.project.Project
2119
import com.intellij.psi.PsiElement
2220
import com.intellij.psi.PsiFile
2321
import com.intellij.psi.PsiLiteralExpression
@@ -42,25 +40,14 @@ import org.domaframework.doma.intellij.inspection.ForDirectiveInspection
4240
import org.domaframework.doma.intellij.psi.SqlElFieldAccessExpr
4341
import org.domaframework.doma.intellij.psi.SqlElForDirective
4442
import org.domaframework.doma.intellij.psi.SqlElIdExpr
45-
import org.domaframework.doma.intellij.psi.SqlElNewExpr
4643
import org.domaframework.doma.intellij.psi.SqlElPrimaryExpr
4744
import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr
4845
import org.domaframework.doma.intellij.psi.SqlTypes
49-
import org.domaframework.doma.intellij.psi.SqlVisitor
5046

5147
class SqlInspectionVisitor(
5248
private val holder: ProblemsHolder,
5349
private val shortName: String,
54-
) : SqlVisitor() {
55-
var file: PsiFile? = null
56-
57-
private fun setFile(element: PsiElement): Boolean {
58-
if (file == null) {
59-
file = element.containingFile
60-
}
61-
return false
62-
}
63-
50+
) : SqlVisitorBase() {
6451
override fun visitElement(element: PsiElement) {
6552
if (setFile(element)) return
6653
val visitFile: PsiFile = file ?: return
@@ -135,38 +122,6 @@ class SqlInspectionVisitor(
135122
}
136123
}
137124

138-
/**
139-
* For processing inside Sql annotations, get it as an injected custom language
140-
*/
141-
private fun initInjectionElement(
142-
basePsiFile: PsiFile,
143-
project: Project,
144-
literal: PsiLiteralExpression,
145-
): PsiFile? =
146-
when (isJavaOrKotlinFileType(basePsiFile)) {
147-
true -> {
148-
val injectedLanguageManager =
149-
InjectedLanguageManager.getInstance(project)
150-
injectedLanguageManager
151-
.getInjectedPsiFiles(literal)
152-
?.firstOrNull()
153-
?.first as? PsiFile
154-
}
155-
156-
false -> null
157-
}
158-
159-
private fun isLiteralOrStatic(targetElement: PsiElement): Boolean =
160-
(
161-
targetElement.firstChild?.elementType == SqlTypes.EL_STRING ||
162-
targetElement.firstChild?.elementType == SqlTypes.EL_CHAR ||
163-
targetElement.firstChild?.elementType == SqlTypes.EL_NUMBER ||
164-
targetElement.firstChild?.elementType == SqlTypes.EL_NULL ||
165-
targetElement.firstChild?.elementType == SqlTypes.BOOLEAN ||
166-
targetElement.firstChild is SqlElNewExpr ||
167-
targetElement.text.startsWith("@")
168-
)
169-
170125
private fun getFieldAccessBlocks(element: SqlElFieldAccessExpr): List<SqlElIdExpr> {
171126
val blockElements = element.accessElements
172127
(blockElements.firstOrNull() as? SqlElPrimaryExpr)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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.inspection.sql.visitor
17+
18+
import com.intellij.codeInspection.ProblemsHolder
19+
import com.intellij.psi.PsiComment
20+
import com.intellij.psi.PsiElement
21+
import com.intellij.psi.PsiFile
22+
import com.intellij.psi.PsiLiteralExpression
23+
import com.intellij.psi.util.PsiTreeUtil
24+
import org.domaframework.doma.intellij.common.isInjectionSqlFile
25+
import org.domaframework.doma.intellij.common.isJavaOrKotlinFileType
26+
import org.domaframework.doma.intellij.common.sql.validator.result.ValidationTestDataResult
27+
import org.domaframework.doma.intellij.psi.SqlBlockComment
28+
import org.domaframework.doma.intellij.psi.SqlElElseifDirective
29+
import org.domaframework.doma.intellij.psi.SqlElForDirective
30+
import org.domaframework.doma.intellij.psi.SqlElIfDirective
31+
import org.domaframework.doma.intellij.psi.SqlTypes
32+
import org.toml.lang.psi.ext.elementType
33+
34+
class SqlTestDataAfterBlockCommentVisitor(
35+
private val holder: ProblemsHolder,
36+
private val shortName: String,
37+
) : SqlVisitorBase() {
38+
override fun visitElement(element: PsiElement) {
39+
if (setFile(element)) return
40+
val visitFile: PsiFile = file ?: return
41+
if (isJavaOrKotlinFileType(visitFile) && element is PsiLiteralExpression) {
42+
val injectionFile = initInjectionElement(visitFile, element.project, element) ?: return
43+
injectionFile.accept(this)
44+
super.visitElement(element)
45+
}
46+
if (isInjectionSqlFile(visitFile)) {
47+
element.acceptChildren(this)
48+
}
49+
}
50+
51+
override fun visitBlockComment(element: SqlBlockComment) {
52+
super.visitBlockComment(element)
53+
if (hasOtherBindVariable(element)) return
54+
55+
val nextElement = element.nextSibling ?: return
56+
if (isSqlLiteral(nextElement)) return
57+
58+
val result = ValidationTestDataResult(element, shortName)
59+
result.highlightElement(holder)
60+
}
61+
62+
/**
63+
* Check to Exist other bind variable in the block comment
64+
*/
65+
private fun hasOtherBindVariable(element: PsiElement): Boolean {
66+
val directive =
67+
PsiTreeUtil.getChildOfType(element, SqlElForDirective::class.java)
68+
?: PsiTreeUtil.getChildOfType(element, SqlElIfDirective::class.java)
69+
?: PsiTreeUtil.getChildOfType(element, SqlElElseifDirective::class.java)
70+
val endDirective =
71+
PsiTreeUtil
72+
.getChildrenOfType(element, PsiElement::class.java)
73+
?.find {
74+
it.elementType == SqlTypes.EL_END ||
75+
it.elementType == SqlTypes.HASH ||
76+
it.elementType == SqlTypes.EL_POPULATE
77+
}
78+
if (directive != null || endDirective != null) return true
79+
80+
val content = PsiTreeUtil.getChildOfType(element, PsiComment::class.java)
81+
return content != null
82+
}
83+
84+
private fun isSqlLiteral(element: PsiElement): Boolean =
85+
element.elementType == SqlTypes.STRING ||
86+
element.elementType == SqlTypes.BOOLEAN ||
87+
element.elementType == SqlTypes.NUMBER ||
88+
element.elementType == SqlTypes.NULL ||
89+
listOf("true", "false", "null").contains(element.text) ||
90+
element.text.matches(Regex("^\\d+$"))
91+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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.inspection.sql.visitor
17+
18+
import com.intellij.lang.injection.InjectedLanguageManager
19+
import com.intellij.openapi.project.Project
20+
import com.intellij.psi.PsiElement
21+
import com.intellij.psi.PsiFile
22+
import com.intellij.psi.PsiLiteralExpression
23+
import com.intellij.psi.util.elementType
24+
import org.domaframework.doma.intellij.common.isJavaOrKotlinFileType
25+
import org.domaframework.doma.intellij.psi.SqlElNewExpr
26+
import org.domaframework.doma.intellij.psi.SqlTypes
27+
import org.domaframework.doma.intellij.psi.SqlVisitor
28+
29+
open class SqlVisitorBase : SqlVisitor() {
30+
var file: PsiFile? = null
31+
32+
protected fun setFile(element: PsiElement): Boolean {
33+
if (file == null) {
34+
file = element.containingFile
35+
}
36+
return false
37+
}
38+
39+
/**
40+
* For processing inside Sql annotations, get it as an injected custom language
41+
*/
42+
protected fun initInjectionElement(
43+
basePsiFile: PsiFile,
44+
project: Project,
45+
literal: PsiLiteralExpression,
46+
): PsiFile? =
47+
when (isJavaOrKotlinFileType(basePsiFile)) {
48+
true -> {
49+
val injectedLanguageManager =
50+
InjectedLanguageManager.getInstance(project)
51+
injectedLanguageManager
52+
.getInjectedPsiFiles(literal)
53+
?.firstOrNull()
54+
?.first as? PsiFile
55+
}
56+
57+
false -> null
58+
}
59+
60+
protected fun isLiteralOrStatic(targetElement: PsiElement): Boolean =
61+
(
62+
targetElement.firstChild?.elementType == SqlTypes.EL_STRING ||
63+
targetElement.firstChild?.elementType == SqlTypes.EL_CHAR ||
64+
targetElement.firstChild?.elementType == SqlTypes.EL_NUMBER ||
65+
targetElement.firstChild?.elementType == SqlTypes.EL_NULL ||
66+
targetElement.firstChild?.elementType == SqlTypes.BOOLEAN ||
67+
targetElement.firstChild is SqlElNewExpr ||
68+
targetElement.text.startsWith("@")
69+
)
70+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
<inspectionToolProvider implementation="org.domaframework.doma.intellij.inspection.dao.provider.SqlFileExistProvider" />
5252
<inspectionToolProvider implementation="org.domaframework.doma.intellij.inspection.sql.provider.SqlBindVariableValidProvider" />
5353
<inspectionToolProvider implementation="org.domaframework.doma.intellij.inspection.dao.provider.DaoMethodVariableProvider" />
54+
<inspectionToolProvider implementation="org.domaframework.doma.intellij.inspection.sql.provider.SqlTestDataAfterBlockCommentValidProvider" />
5455

5556
<!-- Completion -->
5657
<completion.contributor language="DomaSql"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<html lang="en">
2+
<body>
3+
<p>
4+
Displays an error or warning if there is no test data after a bind variable.
5+
</p>
6+
</body>
7+
</html>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<html lang="en">
22
<body>
33
<p>
4-
Doma Tools displays warnings or errors for unused method arguments in SQL
4+
Doma Tools displays warnings or errors for unused method arguments in SQL.
55
</p>
66
</body>
77
</html>

0 commit comments

Comments
 (0)