Skip to content

Commit 163f930

Browse files
committed
Add validation for invalid custom function calls in SQL inspections
1 parent 91cf7b2 commit 163f930

File tree

7 files changed

+121
-7
lines changed

7 files changed

+121
-7
lines changed

src/main/kotlin/org/domaframework/doma/intellij/common/sql/directive/DirectiveCompletion.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@
1616
package org.domaframework.doma.intellij.common.sql.directive
1717

1818
import com.intellij.codeInsight.completion.CompletionResultSet
19-
import com.intellij.openapi.project.Project
2019
import com.intellij.psi.PsiElement
2120
import com.intellij.psi.PsiFile
2221

2322
class DirectiveCompletion(
2423
private val originalFile: PsiFile,
2524
private val bindText: String,
2625
private val element: PsiElement,
27-
private val project: Project,
2826
private val result: CompletionResultSet,
2927
) {
3028
fun directiveHandle(symbol: String): Boolean {
@@ -56,7 +54,6 @@ class DirectiveCompletion(
5654
element = element,
5755
result = result,
5856
bindText = bindText,
59-
project = project,
6057
).directiveHandle()
6158

6259
else -> return false

src/main/kotlin/org/domaframework/doma/intellij/common/sql/directive/StaticDirectiveHandler.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ package org.domaframework.doma.intellij.common.sql.directive
1717

1818
import com.intellij.codeInsight.completion.CompletionResultSet
1919
import com.intellij.openapi.module.Module
20-
import com.intellij.openapi.project.Project
2120
import com.intellij.psi.PsiElement
2221
import com.intellij.psi.util.PsiTreeUtil
2322
import com.intellij.psi.util.elementType
@@ -34,7 +33,6 @@ class StaticDirectiveHandler(
3433
private val element: PsiElement,
3534
private val result: CompletionResultSet,
3635
private val bindText: String,
37-
private val project: Project,
3836
) : DirectiveHandler(originalFile) {
3937
override fun directiveHandle(): Boolean {
4038
var handleResult = false
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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+
/**
26+
* Non-existent package name or class
27+
*/
28+
open class ValidationInvalidFunctionCallResult(
29+
override val identify: PsiElement,
30+
override val shortName: String,
31+
) : ValidationResult(identify, null, shortName) {
32+
override fun setHighlight(
33+
highlightRange: TextRange,
34+
identify: PsiElement,
35+
holder: ProblemsHolder,
36+
parent: PsiParentClass?,
37+
project: Project,
38+
) {
39+
val project = identify.project
40+
holder.registerProblem(
41+
identify,
42+
MessageBundle.message(
43+
"inspection.invalid.sql.customFunction",
44+
identify.text ?: "",
45+
),
46+
problemHighlightType(project, shortName),
47+
highlightRange,
48+
)
49+
}
50+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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.processor
17+
18+
import com.intellij.codeInspection.ProblemsHolder
19+
import com.intellij.psi.PsiMethod
20+
import org.domaframework.doma.intellij.common.helper.ExpressionFunctionsHelper
21+
import org.domaframework.doma.intellij.common.sql.validator.result.ValidationInvalidFunctionCallResult
22+
import org.domaframework.doma.intellij.extension.getJavaClazz
23+
import org.domaframework.doma.intellij.psi.SqlElFunctionCallExpr
24+
import org.domaframework.doma.intellij.setting.state.DomaToolsCustomFunctionSettings
25+
26+
class InspectionFunctionCallVisitorProcessor(
27+
val shortName: String,
28+
private val element: SqlElFunctionCallExpr,
29+
) : InspectionVisitorProcessor(shortName) {
30+
fun check(holder: ProblemsHolder) {
31+
val project = element.project
32+
val expressionHelper = ExpressionFunctionsHelper
33+
val expressionFunctionalInterface = expressionHelper.setExpressionFunctionsInterface(project)
34+
35+
val functionName = element.elIdExpr
36+
val expressionFunctionSetting = DomaToolsCustomFunctionSettings.getInstance(project)
37+
val customFunctionClassNames = expressionFunctionSetting.state.customFunctionClassNames
38+
39+
var methods: Array<out PsiMethod?> = emptyArray()
40+
customFunctionClassNames.takeWhile { clazz ->
41+
val expressionClazz = project.getJavaClazz(clazz)
42+
if (expressionClazz != null && expressionHelper.isInheritor(expressionClazz)) {
43+
methods = expressionClazz.findMethodsByName(functionName.text, true)
44+
}
45+
methods.isEmpty()
46+
}
47+
48+
if (methods.isEmpty()) {
49+
methods = expressionFunctionalInterface?.findMethodsByName(functionName.text, true) ?: emptyArray()
50+
}
51+
52+
if (methods.isEmpty()) {
53+
ValidationInvalidFunctionCallResult(
54+
functionName,
55+
shortName,
56+
).highlightElement(holder)
57+
}
58+
}
59+
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ import org.domaframework.doma.intellij.common.isJavaOrKotlinFileType
2424
import org.domaframework.doma.intellij.extension.psi.isFirstElement
2525
import org.domaframework.doma.intellij.inspection.sql.processor.InspectionFieldAccessVisitorProcessor
2626
import org.domaframework.doma.intellij.inspection.sql.processor.InspectionForDirectiveVisitorProcessor
27+
import org.domaframework.doma.intellij.inspection.sql.processor.InspectionFunctionCallVisitorProcessor
2728
import org.domaframework.doma.intellij.inspection.sql.processor.InspectionPrimaryVisitorProcessor
2829
import org.domaframework.doma.intellij.inspection.sql.processor.InspectionStaticFieldAccessVisitorProcessor
2930
import org.domaframework.doma.intellij.psi.SqlElFieldAccessExpr
3031
import org.domaframework.doma.intellij.psi.SqlElForDirective
32+
import org.domaframework.doma.intellij.psi.SqlElFunctionCallExpr
3133
import org.domaframework.doma.intellij.psi.SqlElPrimaryExpr
3234
import org.domaframework.doma.intellij.psi.SqlElStaticFieldAccessExpr
3335
import org.domaframework.doma.intellij.psi.SqlTypes
@@ -48,6 +50,12 @@ class SqlInspectionVisitor(
4850
}
4951
}
5052

53+
override fun visitElFunctionCallExpr(element: SqlElFunctionCallExpr) {
54+
super.visitElFunctionCallExpr(element)
55+
val processor = InspectionFunctionCallVisitorProcessor(this.shortName, element)
56+
processor.check(holder)
57+
}
58+
5159
override fun visitElStaticFieldAccessExpr(element: SqlElStaticFieldAccessExpr) {
5260
super.visitElStaticFieldAccessExpr(element)
5361
val processor = InspectionStaticFieldAccessVisitorProcessor(this.shortName)

src/main/resources/messages/DomaToolsBundle.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ inspection.invalid.sql.staticProperty=[{0}] is not a public or static property i
1717
inspection.invalid.sql.testdata=Bind variables must be followed by test data
1818
inspection.invalid.sql.classpath=A non-existent package or class name was specified [{0}]
1919
inspection.invalid.sql.iterable=The type that can be used in the for directive is an Iterable type
20-
inspection.invalid.dao.duplicate=An element name that is a duplicate of an element name defined in SQL is used
20+
inspection.invalid.dao.duplicate=An element name that is a duplicate of an element name defined in SQL is used
21+
inspection.invalid.sql.customFunction=The function [{0}] is not defined in the registered custom function classes

src/main/resources/messages/DomaToolsBundle_ja.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ inspection.invalid.sql.staticProperty=[{0}]\u0020\u306F\u30AF\u30E9\u30B9\u0020[
1717
inspection.invalid.sql.testdata=\u30D0\u30A4\u30F3\u30C9\u5909\u6570\u306E\u5F8C\u308D\u306B\u306F\u30C6\u30B9\u30C8\u30C7\u30FC\u30BF\u304C\u5FC5\u8981\u3067\u3059
1818
inspection.invalid.sql.classpath=\u5B58\u5728\u3057\u306A\u3044\u30D1\u30C3\u30B1\u30FC\u30B8\u307E\u305F\u306F\u30AF\u30E9\u30B9\u540D\u304C\u6307\u5B9A\u3055\u308C\u307E\u3057\u305F\u3002:[{0}]
1919
inspection.invalid.sql.iterable=\u0066\u006F\u0072\u30C7\u30A3\u30EC\u30AF\u30C6\u30A3\u30D6\u306B\u4F7F\u7528\u3067\u304D\u308B\u578B\u306F\u0049\u0074\u0065\u0072\u0061\u0062\u006C\u0065\u578B\u3067\u3059
20-
inspection.invalid.dao.duplicate=\u0053\u0051\u004C\u5185\u3067\u5B9A\u7FA9\u3055\u308C\u305F\u8981\u7D20\u540D\u3068\u91CD\u8907\u3057\u305F\u8981\u7D20\u540D\u304C\u4F7F\u7528\u3055\u308C\u3066\u3044\u307E\u3059
20+
inspection.invalid.dao.duplicate=\u0053\u0051\u004C\u5185\u3067\u5B9A\u7FA9\u3055\u308C\u305F\u8981\u7D20\u540D\u3068\u91CD\u8907\u3057\u305F\u8981\u7D20\u540D\u304C\u4F7F\u7528\u3055\u308C\u3066\u3044\u307E\u3059
21+
inspection.invalid.sql.customFunction=\u767B\u9332\u3055\u308C\u305F\u30AB\u30B9\u30BF\u30E0\u95A2\u6570\u30AF\u30E9\u30B9\u306B\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u306A\u3044\u95A2\u6570\u304C\u547C\u3073\u51FA\u3055\u308C\u3066\u3044\u307E\u3059:[{0}]

0 commit comments

Comments
 (0)