Skip to content

Commit e575532

Browse files
committed
Add TypeUtil utility class for type checks and refactor parameter validation in DAO methods
1 parent c2737c0 commit e575532

25 files changed

+218
-110
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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.util
17+
18+
import com.intellij.codeInsight.AnnotationUtil
19+
import com.intellij.openapi.project.Project
20+
import com.intellij.psi.PsiClassType
21+
import com.intellij.psi.PsiType
22+
import org.domaframework.doma.intellij.common.psi.PsiTypeChecker
23+
import org.domaframework.doma.intellij.extension.getJavaClazz
24+
import org.domaframework.doma.intellij.extension.psi.getClassAnnotation
25+
import org.domaframework.doma.intellij.extension.psi.isDomain
26+
import org.domaframework.doma.intellij.extension.psi.isEntity
27+
28+
object TypeUtil {
29+
/**
30+
* Unwraps the type parameter from Optional if present, otherwise returns the original type.
31+
*/
32+
fun unwrapOptional(type: PsiType?): PsiType? {
33+
if (type == null) return null
34+
if (DomaClassName.OPTIONAL.isTargetClassNameStartsWith(type.canonicalText)) {
35+
val classType = type as? PsiClassType
36+
return classType?.parameters?.firstOrNull()
37+
}
38+
return type
39+
}
40+
41+
/**
42+
* Checks if the given type is an entity.
43+
*/
44+
fun isEntity(
45+
type: PsiType?,
46+
project: Project,
47+
): Boolean {
48+
val clazz = type?.canonicalText?.let { project.getJavaClazz(it) }
49+
return clazz?.isEntity() == true
50+
}
51+
52+
fun isImmutableEntity(
53+
project: Project,
54+
canonicalText: String,
55+
): Boolean {
56+
val returnTypeClass = project.getJavaClazz(canonicalText)
57+
val entity =
58+
returnTypeClass?.getClassAnnotation(DomaClassName.ENTITY.className) ?: return false
59+
return entity.let { entity ->
60+
AnnotationUtil.getBooleanAttributeValue(entity, "immutable") == true
61+
} == true ||
62+
returnTypeClass.isRecord == true
63+
}
64+
65+
/**
66+
* Checks if the given type is a domain.
67+
*/
68+
fun isDomain(
69+
type: PsiType?,
70+
project: Project,
71+
): Boolean {
72+
val clazz = type?.canonicalText?.let { project.getJavaClazz(it) }
73+
return clazz?.isDomain() == true
74+
}
75+
76+
/**
77+
* Checks if the given type is a valid Map<String, Object>.
78+
*/
79+
fun isValidMapType(type: PsiType?): Boolean {
80+
val canonical = type?.canonicalText?.replace(" ", "") ?: return false
81+
val expected =
82+
DomaClassName.MAP
83+
.getGenericParamCanonicalText(
84+
DomaClassName.STRING.className,
85+
DomaClassName.OBJECT.className,
86+
).replace(" ", "")
87+
return canonical == expected
88+
}
89+
90+
/**
91+
* Checks if the given type is a base class type or an optional wrapper type.
92+
*/
93+
fun isBaseOrOptionalWrapper(type: PsiType?): Boolean {
94+
if (type == null) return false
95+
return PsiTypeChecker.isBaseClassType(type) || DomaClassName.isOptionalWrapperType(type.canonicalText)
96+
}
97+
}

src/main/kotlin/org/domaframework/doma/intellij/common/validation/result/ValidationMethodParamsIterableEntityResult.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import org.domaframework.doma.intellij.bundle.MessageBundle
2222
import org.domaframework.doma.intellij.common.psi.PsiParentClass
2323

2424
class ValidationMethodParamsIterableEntityResult(
25-
override val identify: PsiElement?,
25+
override val identify: PsiElement,
2626
override val shortName: String = "",
2727
) : ValidationResult(identify, null, shortName) {
2828
override fun setHighlight(

src/main/kotlin/org/domaframework/doma/intellij/common/validation/result/ValidationMethodSelectStrategyReturnTypeResult.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import org.domaframework.doma.intellij.common.psi.PsiParentClass
2424
class ValidationMethodSelectStrategyReturnTypeResult(
2525
override val identify: PsiElement?,
2626
override val shortName: String = "",
27-
private val resultType: String,
27+
private val matchResultType: String,
28+
private val paramType: String,
2829
) : ValidationResult(identify, null, shortName) {
2930
override fun setHighlight(
3031
highlightRange: TextRange,
@@ -37,7 +38,8 @@ class ValidationMethodSelectStrategyReturnTypeResult(
3738
identify,
3839
MessageBundle.message(
3940
"inspection.invalid.dao.select.returnType.strategy",
40-
resultType,
41+
matchResultType,
42+
paramType,
4143
),
4244
problemHighlightType(project, shortName),
4345
highlightRange,

src/main/kotlin/org/domaframework/doma/intellij/inspection/dao/processor/FactoryAnnotationType.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@
1515
*/
1616
package org.domaframework.doma.intellij.inspection.dao.processor
1717

18+
/**
19+
* Enum representing factory annotation types for Doma DAO methods.
20+
*
21+
* Each entry defines the fully qualified annotation name, the expected return type,
22+
* and the required parameter count for the factory method.
23+
*
24+
* @property fqdn The fully qualified name of the annotation.
25+
* @property returnType The expected return type for the factory.
26+
* @property paramCount The number of parameters required by the factory method.
27+
*/
1828
enum class FactoryAnnotationType(
1929
val fqdn: String,
2030
val returnType: String,

src/main/kotlin/org/domaframework/doma/intellij/inspection/dao/processor/StrategyParam.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,30 @@ package org.domaframework.doma.intellij.inspection.dao.processor
1717

1818
import org.domaframework.doma.intellij.common.util.DomaClassName
1919

20+
/**
21+
* Represents a strategy parameter for Doma DAO method inspections.
22+
*
23+
* Provides methods to determine if the parameter is a stream or collect type
24+
* in the context of select operations.
25+
*
26+
* @property fieldName The name of the field.
27+
* @property isSelectType True if the parent class is a select type.
28+
*/
2029
class StrategyParam(
2130
val fieldName: String = "",
2231
parentClassName: String?,
2332
) {
2433
private val isSelectType: Boolean = parentClassName == DomaClassName.SELECT_TYPE.className
2534

35+
/**
36+
* Checks if the parameter represents a stream type.
37+
* @return True if the field is STREAM and the parent is select type.
38+
*/
2639
fun isStream(): Boolean = fieldName == "STREAM" && isSelectType
2740

41+
/**
42+
* Checks if the parameter represents a collect type.
43+
* @return True if the field is COLLECT and the parent is select type.
44+
*/
2845
fun isCollect(): Boolean = fieldName == "COLLECT" && isSelectType
2946
}

src/main/kotlin/org/domaframework/doma/intellij/inspection/dao/processor/TypeCheckerProcessor.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ import org.domaframework.doma.intellij.extension.getJavaClazz
2828
import org.domaframework.doma.intellij.extension.psi.getSuperType
2929
import org.domaframework.doma.intellij.extension.psi.isDomain
3030

31+
/**
32+
* Abstract base class for type checking processors in DAO inspections.
33+
*
34+
* Provides utility methods for retrieving annotations, parameters, and checking types
35+
* in the context of Doma DAO method inspections.
36+
*
37+
* @property method The inspected DAO method.
38+
* @property project The IntelliJ project instance.
39+
*/
3140
abstract class TypeCheckerProcessor(
3241
psiDaoMethod: PsiDaoMethod,
3342
) {

src/main/kotlin/org/domaframework/doma/intellij/inspection/dao/processor/paramtype/BatchParamTypeCheckProcessor.kt

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ import com.intellij.codeInspection.ProblemsHolder
1919
import com.intellij.psi.PsiClassType
2020
import org.domaframework.doma.intellij.common.psi.PsiDaoMethod
2121
import org.domaframework.doma.intellij.common.sql.PsiClassTypeUtil
22+
import org.domaframework.doma.intellij.common.util.TypeUtil
2223
import org.domaframework.doma.intellij.common.validation.result.ValidationMethodParamsCountResult
2324
import org.domaframework.doma.intellij.common.validation.result.ValidationMethodParamsIterableEntityResult
2425
import org.domaframework.doma.intellij.extension.getJavaClazz
25-
import org.domaframework.doma.intellij.extension.psi.isEntity
2626
import org.domaframework.doma.intellij.extension.psi.psiClassType
2727

2828
/**
@@ -86,13 +86,9 @@ class BatchParamTypeCheckProcessor(
8686

8787
val iterableClassType = param.type as? PsiClassType
8888
iterableClassType?.parameters?.firstOrNull()?.let { iterableParam ->
89-
project
90-
.getJavaClazz(iterableParam.canonicalText)
91-
?.let {
92-
if (!it.isEntity()) {
93-
resultParamType.highlightElement(holder)
94-
}
95-
}
89+
if (!TypeUtil.isEntity(iterableParam, project)) {
90+
resultParamType.highlightElement(holder)
91+
}
9692
return
9793
}
9894
resultParamType.highlightElement(holder)

src/main/kotlin/org/domaframework/doma/intellij/inspection/dao/processor/paramtype/ProcedureParamTypeCheckProcessor.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ class ProcedureParamTypeCheckProcessor(
6969
/**
7070
* Validates the type of parameter based on its annotation.
7171
*
72+
* Checks if the parameter type is valid for the given annotation type in the context of the DAO method.
73+
*
74+
* @param psiDaoMethod The DAO method containing the parameter.
7275
* @param paramAnnotationType The type of the annotation on the parameter.
7376
* @param param The parameter to be validated.
7477
* @param holder The ProblemsHolder instance used to report validation issues.

src/main/kotlin/org/domaframework/doma/intellij/inspection/dao/processor/paramtype/SqlProcessorParamTypeCheckProcessor.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,7 @@ class SqlProcessorParamTypeCheckProcessor(
5151
* @param holder The ProblemsHolder instance used to report validation issues.
5252
*/
5353
override fun checkParams(holder: ProblemsHolder) {
54-
val parameters = method.parameterList.parameters
55-
val biFunctionParam =
56-
parameters.firstOrNull { param ->
57-
param.type.canonicalText.startsWith(biFunctionClassName)
58-
}
54+
val biFunctionParam = getMethodParamTargetType(biFunctionClassName)
5955
if (biFunctionParam == null) {
6056
ValidationMethodHasRequireClassParamResult(
6157
method.nameIdentifier,

src/main/kotlin/org/domaframework/doma/intellij/inspection/dao/processor/paramtype/UpdateParamTypeCheckProcessor.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ package org.domaframework.doma.intellij.inspection.dao.processor.paramtype
1717

1818
import com.intellij.codeInspection.ProblemsHolder
1919
import org.domaframework.doma.intellij.common.psi.PsiDaoMethod
20+
import org.domaframework.doma.intellij.common.util.TypeUtil
2021
import org.domaframework.doma.intellij.common.validation.result.ValidationMethodParamTypeResult
21-
import org.domaframework.doma.intellij.extension.getJavaClazz
22-
import org.domaframework.doma.intellij.extension.psi.isEntity
2322

2423
/**
2524
* Processor for checking the parameter types of DAO methods annotated with @Insert,@Update,@Delete.
@@ -58,11 +57,9 @@ class UpdateParamTypeCheckProcessor(
5857

5958
// Check if the method has a parameter of type entity
6059
val param = method.parameterList.parameters.firstOrNull()
61-
val paramClass = project.getJavaClazz(param?.type?.canonicalText ?: "")
62-
val identifier = param?.nameIdentifier ?: return
63-
if (paramClass == null || !paramClass.isEntity()) {
60+
if (!TypeUtil.isEntity(param?.type, project)) {
6461
ValidationMethodParamTypeResult(
65-
identifier,
62+
param?.nameIdentifier,
6663
shortName,
6764
"an entity",
6865
).highlightElement(holder)

0 commit comments

Comments
 (0)