Skip to content

Commit 353f2cf

Browse files
committed
Fix primitive type property check
1 parent 2e0e8bf commit 353f2cf

File tree

7 files changed

+120
-14
lines changed

7 files changed

+120
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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.validation.result
17+
18+
import com.intellij.codeInspection.ProblemsHolder
19+
import com.intellij.openapi.util.TextRange
20+
import com.intellij.psi.PsiElement
21+
import org.domaframework.doma.intellij.bundle.MessageBundle
22+
import org.domaframework.doma.intellij.common.psi.PsiParentClass
23+
24+
/**
25+
* Validation result for annotation option primitive field errors.
26+
* This is used when an include/exclude option references a nested property on a primitive type field.
27+
*/
28+
class ValidationAnnotationOptionPrimitiveFieldResult(
29+
override val identify: PsiElement?,
30+
override val shortName: String = "",
31+
private val fieldPath: String,
32+
private val primitiveFieldName: String,
33+
private val optionName: String,
34+
private val fieldType: String, // Keep for potential future use but not used in message
35+
) : ValidationResult(identify, null, shortName) {
36+
override fun setHighlight(
37+
highlightRange: TextRange,
38+
identify: PsiElement,
39+
holder: ProblemsHolder,
40+
parent: PsiParentClass?,
41+
) {
42+
val project = identify.project
43+
holder.registerProblem(
44+
identify,
45+
MessageBundle.message(
46+
"inspection.invalid.dao.annotation.option.primitive",
47+
fieldPath,
48+
primitiveFieldName,
49+
optionName,
50+
),
51+
problemHighlightType(project, shortName),
52+
highlightRange,
53+
)
54+
}
55+
}

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

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,18 @@ import com.intellij.psi.PsiClass
2222
import com.intellij.psi.PsiClassType
2323
import com.intellij.psi.PsiField
2424
import com.intellij.psi.PsiLiteralExpression
25+
import com.intellij.psi.PsiPrimitiveType
26+
import com.intellij.psi.PsiType
2527
import org.domaframework.doma.intellij.common.psi.PsiDaoMethod
2628
import org.domaframework.doma.intellij.common.util.TypeUtil
2729
import org.domaframework.doma.intellij.common.validation.result.ValidationAnnotationOptionEmbeddableResult
2830
import org.domaframework.doma.intellij.common.validation.result.ValidationAnnotationOptionParameterResult
31+
import org.domaframework.doma.intellij.common.validation.result.ValidationAnnotationOptionPrimitiveFieldResult
2932
import org.domaframework.doma.intellij.extension.getJavaClazz
3033
import org.domaframework.doma.intellij.extension.psi.DomaAnnotationType
3134
import org.domaframework.doma.intellij.extension.psi.isEmbeddable
3235
import org.domaframework.doma.intellij.extension.psi.isEntity
36+
import org.domaframework.doma.intellij.extension.psi.psiClassType
3337
import org.domaframework.doma.intellij.inspection.dao.processor.TypeCheckerProcessor
3438

3539
/**
@@ -101,32 +105,47 @@ class DaoAnnotationOptionParameterCheckProcessor(
101105
val project = method.project
102106
arrayValues.map { fields ->
103107
val valueFields = fields.text.replace("\"", "").split(".")
104-
var searchParamClass: PsiClass? = entityClass
105-
var preSearchParamClass: PsiClass? = entityClass
108+
var searchParamType: PsiType = entityClass.psiClassType
109+
var searchParamClass: PsiClass? = project.getJavaClazz(searchParamType)
106110
var hasError = false
107-
valueFields.map { field ->
108-
searchParamClass
109-
?.fields
110-
?.find { property -> isOptionTargetProperty(property, field, project) }
111-
?.let { f ->
112-
preSearchParamClass = searchParamClass
113-
searchParamClass = project.getJavaClazz(f.type) ?: return@map
114-
}
115-
?: run {
111+
112+
valueFields.forEachIndexed { index, field ->
113+
val currentField =
114+
searchParamClass
115+
?.fields
116+
?.find { property -> isOptionTargetProperty(property, field, project) }
117+
if (searchParamType is PsiPrimitiveType) {
118+
// This is a primitive/basic type but there are more fields after it
119+
ValidationAnnotationOptionPrimitiveFieldResult(
120+
fields,
121+
shortName,
122+
fields.text.replace("\"", ""),
123+
field,
124+
optionName,
125+
field,
126+
).highlightElement(holder)
127+
hasError = true
128+
return@map
129+
} else {
130+
if (currentField != null) {
131+
searchParamType = currentField.type
132+
searchParamClass = project.getJavaClazz(searchParamType)
133+
} else {
116134
ValidationAnnotationOptionParameterResult(
117135
fields,
118136
shortName,
119137
field,
120138
optionName,
121139
searchParamClass?.name ?: "Unknown",
122-
getTargetOptionProperties(preSearchParamClass),
140+
getTargetOptionProperties(searchParamClass),
123141
).highlightElement(holder)
124142
hasError = true
125143
return@map
126144
}
145+
}
127146
}
128147
// Error if the last field is Embeddable
129-
if (!hasError && searchParamClass?.isEmbeddable() == true) {
148+
if (searchParamClass?.isEmbeddable() == true) {
130149
ValidationAnnotationOptionEmbeddableResult(
131150
fields,
132151
shortName,

src/main/resources/messages/DomaToolsBundle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,4 @@ inspection.invalid.dao.sqlProcessor.params.biFunction.param.second=The second ty
3838
inspection.invalid.dao.sqlProcessor.params.biFunction.param.invalid=The type argument at index {0} is not supported
3939
inspection.invalid.dao.annotation.option.field=Field [{0}] specified in [{1}] option does not exist in "{2}". Available fields: [{3}]
4040
inspection.invalid.dao.annotation.option.embeddable=Field [{0}] specified in [{1}] option is an Embeddable type "{2}". Must specify its properties. Available properties: [{3}]
41+
inspection.invalid.dao.annotation.option.primitive=Field path [{0}] specified in [{2}] option is invalid. Field [{1}] is a primitive type and does not have nested properties

src/main/resources/messages/DomaToolsBundle_ja.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ inspection.invalid.dao.sqlProcessor.params.biFunction.param.first=\u0042\u0069\u
3737
inspection.invalid.dao.sqlProcessor.params.biFunction.param.second=\u0042\u0069\u0046\u0075\u006E\u0063\u0074\u0069\u006F\u006E\u306E\u0032\u756A\u76EE\u306E\u8981\u7D20\u306F\u300C{0}\u300D\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059
3838
inspection.invalid.dao.sqlProcessor.params.biFunction.param.invalid={0}\u756A\u76EE\u306E\u8981\u7D20\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093
3939
inspection.invalid.dao.annotation.option.field=[{1}]\u30AA\u30D7\u30B7\u30E7\u30F3\u3067\u6307\u5B9A\u3055\u308C\u305F\u30D5\u30A3\u30FC\u30EB\u30C9[{0}]\u306F"{2}"\u306B\u5B58\u5728\u3057\u307E\u305B\u3093\u3002\u5229\u7528\u53EF\u80FD\u306A\u30D5\u30A3\u30FC\u30EB\u30C9: [{3}]
40-
inspection.invalid.dao.annotation.option.embeddable=[{1}]\u30AA\u30D7\u30B7\u30E7\u30F3\u3067\u6307\u5B9A\u3055\u308C\u305F\u30D5\u30A3\u30FC\u30EB\u30C9[{0}]\u306FEmbeddable\u578B"{2}"\u3067\u3059\u3002\u305D\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u6307\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u5229\u7528\u53EF\u80FD\u306A\u30D7\u30ED\u30D1\u30C6\u30A3: [{3}]
40+
inspection.invalid.dao.annotation.option.embeddable=[{1}]\u30AA\u30D7\u30B7\u30E7\u30F3\u3067\u6307\u5B9A\u3055\u308C\u305F\u30D5\u30A3\u30FC\u30EB\u30C9[{0}]\u306FEmbeddable\u578B"{2}"\u3067\u3059\u3002\u305D\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u6307\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u5229\u7528\u53EF\u80FD\u306A\u30D7\u30ED\u30D1\u30C6\u30A3: [{3}]
41+
inspection.invalid.dao.annotation.option.primitive=[{2}]\u30AA\u30D7\u30B7\u30E7\u30F3\u3067\u6307\u5B9A\u3055\u308C\u305F\u30D5\u30A3\u30FC\u30EB\u30C9\u30D1\u30B9[{0}]\u306F\u7121\u52B9\u3067\u3059\u3002\u30D5\u30A3\u30FC\u30EB\u30C9[{1}]\u306F\u30D7\u30EA\u30DF\u30C6\u30A3\u30D6\u578B\u3067\u3042\u308A\u3001\u30CD\u30B9\u30C8\u3055\u308C\u305F\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u6301\u3061\u307E\u305B\u3093

src/test/testData/src/main/java/doma/example/dao/inspection/option/AnnotationOptionTestDao_base.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,18 @@ public interface AnnotationOptionTestDao {
7777
@MultiInsert(returning = @Returning(include = {"email"},
7878
exclude = {"embeddableEntity.salary"}))
7979
List<Department> multiInsertReturning(List<Department> departments);
80+
81+
// Dont array properties
82+
@Update(returning = @Returning(include = "embeddableEntity.age"))
83+
Department updateSingleInclude(Department department);
84+
85+
@Insert(returning = @Returning(exclude = "embeddableEntity"))
86+
Department insertSingleExclude(Department department);
87+
88+
// Primitive types
89+
@Update(include = "embeddableEntity.subId")
90+
int updatePrimitiveProperty(Department department);
91+
92+
@Insert(exclude = "embeddableEntity.subId.get")
93+
int insertPrimitiveProperty(Department department);
8094
}

src/test/testData/src/main/java/doma/example/dao/inspection/option/AnnotationOptionTestDao_highlight.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,18 @@ public interface AnnotationOptionTestDao {
7777
@MultiInsert(returning = @Returning(include = {<error descr="Field [email] specified in [include] option does not exist in \"Department\". Available fields: [id, name, location, managerCount, embeddableEntity, embeddableEntity2] ">"email"},
7878
exclude = {<error descr="Field [salary] specified in [exclude] option does not exist in \"ClientUser\". Available fields: [id, name, location, managerCount, embeddableEntity, embeddableEntity2] ">"embeddableEntity.salary"</error>}))
7979
List<Department> multiInsertReturning(List<Department> departments);
80+
81+
// Dont array properties
82+
@Update(returning = @Returning(include = "embeddableEntity.age"))
83+
Department updateSingleInclude(Department department);
84+
85+
@Insert(returning = @Returning(exclude = <error descr="Field [age] specified in [include] option does not exist in \"ClientUser\". Available fields: [id, name, number, childEmbedded, childEmbedded2] ">"embeddableEntity"</error>))
86+
Department insertSingleExclude(Department department);
87+
88+
// Primitive types
89+
@Update(include = "embeddableEntity.subId")
90+
int updatePrimitiveProperty(Department department);
91+
92+
@Insert(exclude = <error descr="Field path [subId. get] specified in [exclude] option is invalid. Field [get] is a primitive type and does not have nested properties ">"embeddableEntity.subId.get"</error>)
93+
int insertPrimitiveProperty(Department department);
8094
}

src/test/testData/src/main/java/doma/example/entity/Department.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ public class Department {
1111
public String location;
1212
public Integer managerCount;
1313

14+
int subId;
15+
1416
@Embedded
1517
public ClientUser embeddableEntity;
1618
@Embedded

0 commit comments

Comments
 (0)