Skip to content

Commit 3649cfb

Browse files
committed
Add support for Function subtype and Collector subtype in DAO method inspections
1 parent 712849b commit 3649cfb

File tree

6 files changed

+104
-24
lines changed

6 files changed

+104
-24
lines changed

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

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

1818
import com.intellij.codeInspection.ProblemsHolder
1919
import com.intellij.psi.PsiClassType
20+
import com.intellij.psi.PsiElement
2021
import com.intellij.psi.PsiType
2122
import org.domaframework.doma.intellij.common.psi.PsiDaoMethod
2223
import org.domaframework.doma.intellij.common.psi.PsiTypeChecker
@@ -83,44 +84,61 @@ class SelectParamTypeCheckProcessor(
8384
}
8485

8586
private fun checkStream(holder: ProblemsHolder) {
87+
val stream = DomaClassName.JAVA_STREAM.className
8688
val result =
8789
ValidationMethodSelectStrategyParamResult(
8890
method.nameIdentifier,
8991
shortName,
9092
"STREAM",
91-
DomaClassName.JAVA_FUNCTION.getGenericParamCanonicalText(DomaClassName.JAVA_STREAM.className),
93+
DomaClassName.JAVA_FUNCTION.className,
9294
)
95+
9396
val function = getMethodParamTargetType(DomaClassName.JAVA_FUNCTION.className)
9497
if (function == null) {
9598
result.highlightElement(holder)
9699
return
97100
}
98101

99-
val functionFirstParam = (function.type as? PsiClassType)?.parameters?.firstOrNull()
102+
val functionType = function.type
103+
val identifier = function.nameIdentifier ?: return
104+
105+
// Check if the first parameter of the function is a stream type
106+
val functionClass = project.getJavaClazz(functionType.canonicalText) ?: return
107+
var superCollection: PsiClassType? = functionType as PsiClassType?
108+
while (superCollection != null &&
109+
!DomaClassName.JAVA_FUNCTION.isTargetClassNameStartsWith(superCollection.canonicalText)
110+
) {
111+
superCollection =
112+
functionClass.superTypes
113+
.find { sp -> DomaClassName.JAVA_FUNCTION.isTargetClassNameStartsWith(sp.canonicalText) }
114+
}
115+
116+
val functionFirstParam = superCollection?.parameters?.firstOrNull()
100117
if (functionFirstParam == null ||
101118
!DomaClassName.JAVA_STREAM.isTargetClassNameStartsWith(functionFirstParam.canonicalText)
102119
) {
103120
result.highlightElement(holder)
104121
return
105122
}
106123

107-
// Check if the first parameter of the function is a stream type
108-
val streamTargetParam = (functionFirstParam as? PsiClassType)?.parameters?.firstOrNull()
109-
if (streamTargetParam == null) {
110-
generateTargetTypeResult("Unknown").highlightElement(holder)
124+
// Check if the first parameter of the stream is a valid type
125+
val streamParamClassType = functionFirstParam as? PsiClassType
126+
val strategyParamType = streamParamClassType?.parameters?.firstOrNull()
127+
if (strategyParamType == null) {
128+
generateTargetTypeResult(identifier, "Unknown", stream).highlightElement(holder)
111129
return
112130
}
113131

114-
val streamTargetTypeCanonicalText = streamTargetParam.canonicalText
115-
if (DomaClassName.MAP.isTargetClassNameStartsWith(streamTargetTypeCanonicalText)) {
116-
if (!checkMapType(streamTargetTypeCanonicalText)) {
117-
generateTargetTypeResult(streamTargetTypeCanonicalText).highlightElement(holder)
132+
val strategyParamTypeName = strategyParamType.canonicalText
133+
if (DomaClassName.MAP.isTargetClassNameStartsWith(strategyParamTypeName)) {
134+
if (!checkMapType(strategyParamTypeName)) {
135+
generateTargetTypeResult(identifier, strategyParamTypeName, stream).highlightElement(holder)
118136
}
119137
return
120138
}
121139

122-
if (!checkParamType(streamTargetParam)) {
123-
generateTargetTypeResult(streamTargetTypeCanonicalText).highlightElement(holder)
140+
if (!checkParamType(strategyParamType)) {
141+
generateTargetTypeResult(identifier, strategyParamTypeName, stream).highlightElement(holder)
124142
}
125143
}
126144

@@ -132,28 +150,42 @@ class SelectParamTypeCheckProcessor(
132150
"COLLECT",
133151
DomaClassName.JAVA_COLLECTOR.className,
134152
)
153+
val collector = DomaClassName.JAVA_COLLECTOR.className
135154
val collection = getMethodParamTargetType(DomaClassName.JAVA_COLLECTOR.className)
136155
if (collection == null) {
137156
result.highlightElement(holder)
138157
return
139158
}
140159

141-
val collectorTargetParam = (collection.type as? PsiClassType)?.parameters?.firstOrNull()
160+
val collectionType = collection.type
161+
val identifier = collection.nameIdentifier ?: return
162+
163+
val collectionClass = project.getJavaClazz(collectionType.canonicalText) ?: return
164+
var superCollection: PsiClassType? = collection.type as? PsiClassType
165+
while (superCollection != null &&
166+
!DomaClassName.JAVA_COLLECTOR.isTargetClassNameStartsWith(superCollection.canonicalText)
167+
) {
168+
superCollection =
169+
collectionClass.superTypes
170+
.find { sp -> DomaClassName.JAVA_COLLECTOR.isTargetClassNameStartsWith(sp.canonicalText) }
171+
}
172+
173+
val collectorTargetParam = superCollection?.parameters?.firstOrNull()
142174
if (collectorTargetParam == null) {
143-
generateTargetTypeResult("Unknown").highlightElement(holder)
175+
generateTargetTypeResult(identifier, "Unknown", collector).highlightElement(holder)
144176
return
145177
}
146178

147-
val streamTargetTypeCanonicalText = collectorTargetParam.canonicalText
148-
if (DomaClassName.MAP.isTargetClassNameStartsWith(streamTargetTypeCanonicalText)) {
149-
if (!checkMapType(streamTargetTypeCanonicalText)) {
150-
generateTargetTypeResult(streamTargetTypeCanonicalText).highlightElement(holder)
179+
val collectorTargetTypeCanonicalText = collectorTargetParam.canonicalText
180+
if (DomaClassName.MAP.isTargetClassNameStartsWith(collectorTargetTypeCanonicalText)) {
181+
if (!checkMapType(collectorTargetTypeCanonicalText)) {
182+
generateTargetTypeResult(identifier, collectorTargetTypeCanonicalText, collector).highlightElement(holder)
151183
}
152184
return
153185
}
154186

155187
if (!checkParamType(collectorTargetParam)) {
156-
generateTargetTypeResult(streamTargetTypeCanonicalText).highlightElement(holder)
188+
generateTargetTypeResult(identifier, collectorTargetTypeCanonicalText, collector).highlightElement(holder)
157189
}
158190
}
159191

@@ -167,11 +199,15 @@ class SelectParamTypeCheckProcessor(
167199
}
168200
}
169201

170-
fun generateTargetTypeResult(streamParamTypeName: String): ValidationMethodParamsSupportGenericParamResult =
202+
fun generateTargetTypeResult(
203+
target: PsiElement,
204+
paramTypeName: String,
205+
genericType: String,
206+
): ValidationMethodParamsSupportGenericParamResult =
171207
ValidationMethodParamsSupportGenericParamResult(
172-
method.nameIdentifier,
208+
target,
173209
shortName,
174-
streamParamTypeName,
175-
DomaClassName.JAVA_STREAM.className,
210+
paramTypeName,
211+
genericType,
176212
)
177213
}

src/test/kotlin/org/domaframework/doma/intellij/inspection/dao/AnnotationParamTypeCheckInspectionTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class AnnotationParamTypeCheckInspectionTest : DomaSqlTest() {
3939
myFixture.enableInspections(DaoMethodParamTypeInspection())
4040
addEntityJavaFile("Pckt.java")
4141
addEntityJavaFile("Packet.java")
42+
addOtherJavaFile("collector", "HogeCollector.java")
43+
addOtherJavaFile("function", "HogeFunction.java")
4244
testDaoNames.forEach { daoName ->
4345
addDaoJavaFile("$daoPackage/$daoName.java")
4446
}

src/test/kotlin/org/domaframework/doma/intellij/inspection/dao/AnnotationReturnTypeCheckInspectionTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class AnnotationReturnTypeCheckInspectionTest : DomaSqlTest() {
4343
addEntityJavaFile("Pckt.java")
4444
addOtherJavaFile("domain", "Hiredate.java")
4545
addOtherJavaFile("collector", "HogeCollector.java")
46+
addOtherJavaFile("function", "HogeFunction.java")
4647
myFixture.enableInspections(DaoMethodReturnTypeInspection())
4748
}
4849

src/test/testData/src/main/java/doma/example/dao/inspection/paramtype/SelectParamTestDao.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package doma.example.dao.inspection.paramtype;
22

3+
import java.util.Map;
34
import org.seasar.doma.*;
45
import org.seasar.doma.message.Message;
56
import doma.example.entity.*;
7+
import doma.example.collector.*;
8+
import doma.example.function.*;
69

710
import java.math.BigDecimal;
811
import java.util.Optional;
@@ -22,12 +25,16 @@ public interface SelectParamTestDao {
2225

2326
@Select(strategy = SelectType.STREAM)
2427
@Sql("Select 10000 from user where name = /* name */'name' and salary = /* salary */0")
25-
Stream<Packet> <error descr="When you specify SelectType.STREAM for the strategy element of @Select, the \"java.util.function.Function<java.util.stream.Stream>\" parameter is required for the method">selectReturnStreamWithStreamOption</error>(String name, BigDecimal salary);
28+
Stream<Packet> <error descr="When you specify SelectType.STREAM for the strategy element of @Select, the \"java.util.function.Function\" parameter is required for the method">selectReturnStreamWithStreamOption</error>(String name, BigDecimal salary);
2629

2730
@Select
2831
@Sql("Select 10000 from user")
2932
Stream<Packet> <error descr="When you use the \"java.util.function.Function\" parameter, SelectStrategyType.STREAM must be specified for the strategy element of @Select">selectReturnStreamWithOutStreamOption</error>(Function<Stream<Packet>, BigDecimal> streams);
3033

34+
@Select(strategy = SelectType.STREAM)
35+
@Sql("Select 10000 from user")
36+
BigDecimal selectFunctionInvalidParam(Function<Stream<Map<String, Pckt>>,BigDecimal> <error descr="\"java.util.Map<java.lang.String,doma.example.entity.Pckt>\" is illegal as the type argument of \"java.util.stream.Stream\"">function</error>, BigDecimal stream);
37+
3138
@Select(strategy = SelectType.STREAM)
3239
@Sql("Select 10000 from user")
3340
Integer selectReturnStream(Function<Stream<Pckt>, BigDecimal> stream);
@@ -49,12 +56,24 @@ public interface SelectParamTestDao {
4956
@Sql("select * from packet where salary > /* salary */0")
5057
Pckt <error descr="When you specify SelectType.COLLECT for the strategy element of @Select, the \"java.util.stream.Collector\" parameter is required for the method">selectWithOutCollector</error>(BigDecimal salary, Packet packet);
5158

59+
@Select(strategy = SelectType.COLLECT)
60+
@Sql("select * from packet where salary > /* salary */0")
61+
Pckt selectCollectorInvalidParam(BigDecimal salary, Collector<Packet, ?, Map<String, Packet>> collector);
62+
5263
@Select(strategy = SelectType.COLLECT)
5364
@Sql("select * from emp where salary > /* salary */0")
5465
Optional<Packet> selectCollectOptionalParamResult(BigDecimal salary,Collector<Packet, ?, Optional<Packet>> collector);
5566

5667
@Select(strategy = SelectType.COLLECT)
5768
@Sql("select * from emp where salary > /* salary */0")
5869
Pckt selectCollectAccumulation(BigDecimal salary, Collector<Packet, BigDecimal, Pckt> collector);
70+
71+
@Select(strategy = SelectType.COLLECT)
72+
@Sql("select * from emp where salary > /* salary */0")
73+
Pckt selectHogeCollect(BigDecimal salary, HogeCollector collector);
74+
75+
@Select(strategy = SelectType.STREAM)
76+
@Sql("select * from emp where salary > /* salary */0")
77+
String selectHogeCollect(BigDecimal salary, HogeFunction function);
5978
}
6079

src/test/testData/src/main/java/doma/example/dao/inspection/returntype/SelectReturnTypeTestDao.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import doma.example.entity.*;
1414
import doma.example.domain.*;
1515
import doma.example.collector.*;
16+
import doma.example.function.*;
1617

1718
@Dao
1819
public interface SelectReturnTypeTestDao {
@@ -126,5 +127,14 @@ public interface SelectReturnTypeTestDao {
126127
@Select(strategy = SelectType.COLLECT, mapKeyNaming = MapKeyNamingType.CAMEL_CASE)
127128
<R> R selectByIdAsMap(Integer id, Collector<Map<String, Object>, ?, R> collector);
128129

130+
@Select(strategy = SelectType.COLLECT)
131+
@Sql("select * from emp where salary > /* salary */0")
132+
Pckt selectHogeCollect(BigDecimal salary, HogeCollector collector);
133+
134+
@Select(strategy = SelectType.STREAM)
135+
@Sql("select * from emp where salary > /* salary */0")
136+
String selectHogeCollect(BigDecimal salary, HogeFunction function);
137+
138+
129139

130140
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package doma.example.function;
2+
3+
import java.util.function.Function;
4+
import java.util.stream.Stream;
5+
6+
public class HogeFunction implements Function<Stream<String>, String> {
7+
8+
@Override
9+
public String apply(Stream<String> t) {
10+
return null;
11+
}
12+
}

0 commit comments

Comments
 (0)