Skip to content

Commit 32a52e4

Browse files
committed
Type resolution for elements defined in the for directive
1 parent 7cc4a56 commit 32a52e4

16 files changed

+925
-473
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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
17+
18+
import com.intellij.psi.PsiClassType
19+
import com.intellij.psi.PsiType
20+
21+
class PsiClassTypeUtil {
22+
companion object {
23+
fun getPsiTypeByList(
24+
classType: PsiClassType,
25+
useListParam: Boolean,
26+
): PsiType? {
27+
if (classType.className == "List" && useListParam) {
28+
return classType.parameters.firstOrNull()
29+
}
30+
return classType
31+
}
32+
}
33+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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.foritem
17+
18+
import com.intellij.psi.PsiClassType
19+
import com.intellij.psi.PsiElement
20+
import com.intellij.psi.PsiParameter
21+
import org.domaframework.doma.intellij.common.psi.PsiParentClass
22+
import org.domaframework.doma.intellij.extension.psi.DomaAnnotationType
23+
import org.domaframework.doma.intellij.extension.psi.getIterableClazz
24+
25+
/**
26+
* In the For directive, define the element based on the Dao parameter.
27+
* %for [ForItem] : [ForDeclarationDaoBaseItem]
28+
* %for [ForItem] : [ForDeclarationItem]
29+
* ...
30+
*/
31+
class ForDeclarationDaoBaseItem(
32+
override val element: PsiElement,
33+
val daoParameter: PsiParameter,
34+
val nestIndex: Int,
35+
val domaAnnotationType: DomaAnnotationType,
36+
) : ForDeclarationItem(element) {
37+
fun getPsiParentClass(): PsiParentClass? {
38+
var i = 0
39+
var nestClassType: PsiClassType? =
40+
(daoParameter.getIterableClazz(domaAnnotationType.isBatchAnnotation()).type as PsiClassType)
41+
if (domaAnnotationType.isBatchAnnotation()) {
42+
nestClassType?.parameters?.firstOrNull() as PsiClassType?
43+
}
44+
45+
while (i <= nestIndex) {
46+
nestClassType = nestClassType?.parameters?.firstOrNull() as PsiClassType?
47+
i++
48+
}
49+
return nestClassType?.let { PsiParentClass(it) }
50+
}
51+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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.foritem
17+
18+
import com.intellij.psi.PsiElement
19+
import com.intellij.psi.util.PsiTreeUtil
20+
import org.domaframework.doma.intellij.psi.SqlElFieldAccessExpr
21+
import org.domaframework.doma.intellij.psi.SqlElIdExpr
22+
23+
/**
24+
* definition source in the For directive
25+
* %for [ForItem] : [ForDeclarationItem]
26+
*/
27+
open class ForDeclarationItem(
28+
override val element: PsiElement,
29+
) : ForDirectiveItemBase(element) {
30+
fun getDeclarationChildren(): List<PsiElement> =
31+
if (element is SqlElFieldAccessExpr) {
32+
PsiTreeUtil.getChildrenOfType(element, SqlElIdExpr::class.java)?.toList() ?: emptyList()
33+
} else {
34+
listOf(element)
35+
}
36+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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.foritem
17+
18+
import com.intellij.psi.PsiElement
19+
20+
abstract class ForDirectiveItemBase(
21+
open val element: PsiElement,
22+
)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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.foritem
17+
18+
import com.intellij.psi.PsiElement
19+
import com.intellij.psi.util.PsiTreeUtil
20+
import org.domaframework.doma.intellij.psi.SqlElForDirective
21+
22+
/**
23+
* Elements defined within the For directive
24+
* %for [ForItem] : [ForDeclarationItem]
25+
*/
26+
class ForItem(
27+
override val element: PsiElement,
28+
) : ForDirectiveItemBase(element) {
29+
fun getParentForDirectiveExpr() = PsiTreeUtil.getParentOfType(element, SqlElForDirective::class.java)
30+
}

src/main/kotlin/org/domaframework/doma/intellij/extension/psi/PsiMethodExtension.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import com.intellij.psi.PsiType
2323
import com.intellij.psi.PsiTypeParameterList
2424
import com.intellij.psi.impl.compiled.ClsClassImpl
2525
import com.intellij.psi.impl.compiled.ClsTypeParametersListImpl
26-
import com.intellij.psi.impl.source.PsiClassReferenceType
2726

2827
fun PsiMethod.findParameter(searchName: String): PsiParameter? = this.methodParameters.firstOrNull { it.name == searchName }
2928

@@ -32,6 +31,7 @@ val PsiMethod.methodParameters: List<PsiParameter>
3231

3332
fun PsiMethod.searchParameter(searchName: String): List<PsiParameter> = this.methodParameters.filter { it.name.startsWith(searchName) }
3433

34+
@OptIn(ExperimentalStdlibApi::class)
3535
fun PsiMethod.getDomaAnnotationType(): DomaAnnotationType {
3636
DomaAnnotationType.entries.forEach {
3737
if (AnnotationUtil.findAnnotation(this, it.fqdn) != null) {
@@ -49,14 +49,16 @@ fun PsiMethod.getMethodReturnType(
4949
topElementType: PsiType,
5050
index: Int,
5151
): PsiClassType? {
52+
// TODO:When handling properties that return a List type from a field or method,
53+
// the defined type cannot be obtained, so it is not supported.
5254
val returnType = this.returnType as? PsiClassType
5355
val cls = returnType?.resolve()?.parent as? ClsTypeParametersListImpl
5456
val listType = ((cls as? PsiTypeParameterList)?.parent as? ClsClassImpl)
5557

5658
if (returnType?.name == "E" && listType?.qualifiedName == "java.util.List") {
5759
var count = 1
58-
var type: PsiType? = (topElementType as? PsiClassReferenceType)?.parameters?.firstOrNull()
59-
while (index >= count && type != null && type is PsiClassReferenceType) {
60+
var type: PsiType? = (topElementType as? PsiClassType)?.parameters?.firstOrNull()
61+
while (index >= count && type != null && type is PsiClassType) {
6062
type = type.parameters.firstOrNull()
6163
count++
6264
}

src/main/kotlin/org/domaframework/doma/intellij/extension/psi/PsiParameterExtension.kt

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,41 @@
1515
*/
1616
package org.domaframework.doma.intellij.extension.psi
1717

18+
import com.intellij.psi.PsiClassType
1819
import com.intellij.psi.PsiParameter
19-
import com.intellij.psi.impl.source.PsiClassReferenceType
2020
import org.domaframework.doma.intellij.common.psi.PsiParentClass
21+
import org.domaframework.doma.intellij.common.sql.PsiClassTypeUtil
2122

2223
/**
2324
* For List type, if the annotation type is Batch type,
2425
* return the content type.
2526
*/
26-
fun PsiParameter.getIterableClazz(annotationType: DomaAnnotationType): PsiParentClass {
27-
val immediate: PsiClassReferenceType? = this.type as? PsiClassReferenceType
28-
if (immediate != null) {
29-
if (immediate.name == "List" && annotationType.isBatchAnnotation()) {
30-
val listType =
31-
(this.type as PsiClassReferenceType).parameters.firstOrNull()
32-
?: return PsiParentClass(this.type)
33-
return PsiParentClass(listType)
34-
}
27+
fun PsiParameter.getIterableClazz(annotationType: DomaAnnotationType): PsiParentClass = getIterableClazz(annotationType.isBatchAnnotation())
28+
29+
fun PsiParameter.getIterableClazz(useListParam: Boolean): PsiParentClass {
30+
val immediate = this.type as? PsiClassType
31+
val classType = immediate?.let { PsiClassTypeUtil.getPsiTypeByList(it, useListParam) }
32+
if (classType != null) {
33+
return PsiParentClass(classType)
3534
}
3635
return PsiParentClass(this.type)
3736
}
3837

3938
val PsiParameter.isFunctionClazz: Boolean
4039
get() =
41-
(this.typeElement?.type as? PsiClassReferenceType)
40+
(this.typeElement?.type as? PsiClassType)
4241
?.resolve()
4342
?.qualifiedName
4443
?.contains("java.util.function") == true
4544

4645
val PsiParameter.isSelectOption: Boolean
4746
get() =
48-
(this.typeElement?.type as? PsiClassReferenceType)
47+
(this.typeElement?.type as? PsiClassType)
4948
?.resolve()
5049
?.qualifiedName == "org.seasar.doma.jdbc.SelectOptions"
5150

5251
val PsiParameter.isCollector: Boolean
5352
get() =
54-
(this.typeElement?.type as? PsiClassReferenceType)
53+
(this.typeElement?.type as? PsiClassType)
5554
?.resolve()
5655
?.qualifiedName == "java.util.stream.Collector"

src/main/kotlin/org/domaframework/doma/intellij/extension/psi/SqlElForDirectiveExtension.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,18 @@ package org.domaframework.doma.intellij.extension.psi
1717

1818
import com.intellij.psi.PsiElement
1919
import com.intellij.psi.util.PsiTreeUtil
20+
import org.domaframework.doma.intellij.common.sql.foritem.ForDeclarationItem
21+
import org.domaframework.doma.intellij.psi.SqlElFieldAccessExpr
2022
import org.domaframework.doma.intellij.psi.SqlElForDirective
2123
import org.domaframework.doma.intellij.psi.SqlElIdExpr
2224

2325
fun SqlElForDirective.getForItem(): PsiElement? =
2426
PsiTreeUtil
2527
.getChildOfType(this, SqlElIdExpr::class.java)
28+
29+
fun SqlElForDirective.getForItemDeclaration(): ForDeclarationItem? {
30+
val declarationElm =
31+
PsiTreeUtil.getChildrenOfType(this, SqlElFieldAccessExpr::class.java)?.last()
32+
?: PsiTreeUtil.getChildrenOfType(this, SqlElIdExpr::class.java)?.last()
33+
return declarationElm?.let { ForDeclarationItem(it) }
34+
}

0 commit comments

Comments
 (0)