Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ enum class DomaClassName(
SELECT_TYPE("org.seasar.doma.SelectType"),

ENTITY("org.seasar.doma.Entity"),
DATATYPE("org.seasar.doma.DataType"),
;

fun isTargetClassNameStartsWith(paramTypeCanonicalNames: String): Boolean = paramTypeCanonicalNames.startsWith(this.className)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.intellij.psi.PsiType
import org.domaframework.doma.intellij.common.psi.PsiTypeChecker
import org.domaframework.doma.intellij.extension.getJavaClazz
import org.domaframework.doma.intellij.extension.psi.getClassAnnotation
import org.domaframework.doma.intellij.extension.psi.isDataType
import org.domaframework.doma.intellij.extension.psi.isDomain
import org.domaframework.doma.intellij.extension.psi.isEntity

Expand Down Expand Up @@ -73,6 +74,17 @@ object TypeUtil {
return clazz?.isDomain() == true
}

/**
* Checks if the given type is a data type.
*/
fun isDataType(
type: PsiType?,
project: Project,
): Boolean {
val clazz = type?.canonicalText?.let { project.getJavaClazz(it) }
return clazz?.isDataType() == true
}

/**
* Checks if the given type is a valid Map<String, Object>.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ fun PsiClass.isEntity(): Boolean = this.getClassAnnotation(DomaClassName.ENTITY.

fun PsiClass.isDomain(): Boolean = this.getClassAnnotation(DomaClassName.DOMAIN.className) != null

fun PsiClass.isDataType(): Boolean = this.getClassAnnotation(DomaClassName.DATATYPE.className) != null && this.isRecord

fun PsiClassType.getSuperType(superClassName: String): PsiClassType? {
var parent: PsiClassType? = this
while (parent != null && !parent.canonicalText.startsWith(superClassName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import org.domaframework.doma.intellij.common.psi.PsiTypeChecker
import org.domaframework.doma.intellij.common.util.DomaClassName
import org.domaframework.doma.intellij.extension.getJavaClazz
import org.domaframework.doma.intellij.extension.psi.getSuperType
import org.domaframework.doma.intellij.extension.psi.isDataType
import org.domaframework.doma.intellij.extension.psi.isDomain

/**
Expand Down Expand Up @@ -90,12 +91,12 @@ abstract class TypeCheckerProcessor(
val optionalParam = paramClassType.parameters.firstOrNull()
return optionalParam?.let {
val optionalParamClass = project.getJavaClazz(it.canonicalText)
optionalParamClass?.isDomain() == true || PsiTypeChecker.isBaseClassType(it)
optionalParamClass?.isDomain() == true || optionalParamClass?.isDataType() == true || PsiTypeChecker.isBaseClassType(it)
} == true
}

val paramClass = project.getJavaClazz(paramType.canonicalText)
return paramClass?.isDomain() == true
return paramClass?.isDomain() == true || paramClass?.isDataType() == true
}

protected fun checkMapType(paramTypeCanonicalText: String): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import org.domaframework.doma.intellij.common.util.DomaClassName
import org.domaframework.doma.intellij.common.validation.result.ValidationMethodParamsSupportGenericParamResult
import org.domaframework.doma.intellij.common.validation.result.ValidationMethodProcedureParamTypeResult
import org.domaframework.doma.intellij.extension.getJavaClazz
import org.domaframework.doma.intellij.extension.psi.isDataType
import org.domaframework.doma.intellij.extension.psi.isDomain
import org.domaframework.doma.intellij.extension.psi.isEntity

Expand All @@ -46,14 +47,15 @@ class ProcedureFunctionResultSetParamAnnotationTypeChecker(
val optionalParamClass = project.getJavaClazz(it.canonicalText)
optionalParamClass?.isDomain() == true ||
optionalParamClass?.isEntity() == true ||
optionalParamClass?.isDataType() == true ||
PsiTypeChecker.isBaseClassType(
it,
)
} == true
}

val paramClass = project.getJavaClazz(paramType.canonicalText)
return paramClass?.isDomain() == true
return paramClass?.isDomain() == true || paramClass?.isDataType() == true
}

override fun checkParam(
Expand Down Expand Up @@ -101,7 +103,7 @@ class ProcedureFunctionResultSetParamAnnotationTypeChecker(

val paramClass = project.getJavaClazz(listParamType.canonicalText)

if (checkParamType(listParamType) || paramClass?.isEntity() == true) return
if (checkParamType(listParamType) || paramClass?.isEntity() == true || paramClass?.isDataType() == true) return
result.highlightElement(holder)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,19 @@ class BatchParamTypeCheckProcessor(

val iterableClassType = param.type as? PsiClassType
iterableClassType?.parameters?.firstOrNull()?.let { iterableParam ->
if (!TypeUtil.isEntity(iterableParam, project)) {
resultParamType.highlightElement(holder)
// Check if @Sql annotation is present or sqlFile=true
if (psiDaoMethod.useSqlAnnotation() || psiDaoMethod.sqlFileOption) {
if (!TypeUtil.isEntity(iterableParam, project) &&
!TypeUtil.isDomain(iterableParam, project) &&
!TypeUtil.isDataType(iterableParam, project)
) {
resultParamType.highlightElement(holder)
}
} else {
// When @Sql annotation is present or sqlFile=true, only Entity types are allowed
if (!TypeUtil.isEntity(iterableParam, project)) {
resultParamType.highlightElement(holder)
}
}
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.domaframework.doma.intellij.common.validation.result.ValidationMethod
import org.domaframework.doma.intellij.common.validation.result.ValidationMethodSelectStrategyParamResult
import org.domaframework.doma.intellij.extension.getJavaClazz
import org.domaframework.doma.intellij.extension.psi.getSuperClassType
import org.domaframework.doma.intellij.extension.psi.isDataType
import org.domaframework.doma.intellij.extension.psi.isDomain
import org.domaframework.doma.intellij.extension.psi.isEntity
import org.domaframework.doma.intellij.inspection.dao.processor.StrategyParam
Expand All @@ -49,12 +50,13 @@ class SelectParamTypeCheckProcessor(
val optionalParamClass = project.getJavaClazz(it.canonicalText)
optionalParamClass?.isDomain() == true ||
PsiTypeChecker.isBaseClassType(it) ||
optionalParamClass?.isEntity() == true
optionalParamClass?.isEntity() == true ||
optionalParamClass?.isDataType() == true
} == true
}

val paramClass = project.getJavaClazz(paramType.canonicalText)
return paramClass?.isDomain() == true || paramClass?.isEntity() == true
return paramClass?.isDomain() == true || paramClass?.isEntity() == true || paramClass?.isDataType() == true
}

override fun checkParams(holder: ProblemsHolder) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class FunctionReturnTypeCheckProcessor(
}
}

if (TypeUtil.isDomain(checkType, project) || TypeUtil.isEntity(checkType, project)) {
if (TypeUtil.isDomain(checkType, project) || TypeUtil.isEntity(checkType, project) || TypeUtil.isDataType(checkType, project)) {
return null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class SelectReturnTypeCheckProcessor(
}
}

if (TypeUtil.isDomain(checkType, project) || TypeUtil.isEntity(checkType, project)) {
if (TypeUtil.isDomain(checkType, project) || TypeUtil.isEntity(checkType, project) || TypeUtil.isDataType(checkType, project)) {
return null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class AnnotationParamTypeCheckInspectionTest : DomaSqlTest() {
"ScriptParamTestDao",
"SqlProcessorParamTestDao",
"FactoryParamTestDao",
"DataTypeParamTypeTestDao",
)
private val daoPackage = "inspection/paramtype"

Expand All @@ -43,6 +44,7 @@ class AnnotationParamTypeCheckInspectionTest : DomaSqlTest() {
addOtherJavaFile("collector", "HogeCollector.java")
addOtherJavaFile("function", "HogeFunction.java")
addOtherJavaFile("function", "HogeBiFunction.java")
addOtherJavaFile("domain", "Salary.java")
testDaoNames.forEach { daoName ->
addDaoJavaFile("$daoPackage/$daoName.java")
}
Expand Down Expand Up @@ -87,4 +89,9 @@ class AnnotationParamTypeCheckInspectionTest : DomaSqlTest() {
val dao = findDaoClass("$daoPackage.FactoryParamTestDao")
myFixture.testHighlighting(false, false, false, dao.containingFile.virtualFile)
}

fun testDataTypeParam() {
val dao = findDaoClass("$daoPackage.DataTypeParamTypeTestDao")
myFixture.testHighlighting(false, false, false, dao.containingFile.virtualFile)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class AnnotationReturnTypeCheckInspectionTest : DomaSqlTest() {
"ProcedureReturnTypeTestDao",
"FunctionReturnTypeTestDao",
"FactoryReturnTypeTestDao",
"DataTypeReturnTypeTestDao",
)
private val daoPackage = "inspection/returntype"

Expand All @@ -43,6 +44,7 @@ class AnnotationReturnTypeCheckInspectionTest : DomaSqlTest() {
addEntityJavaFile("Packet.java")
addEntityJavaFile("Pckt.java")
addOtherJavaFile("domain", "Hiredate.java")
addOtherJavaFile("domain", "Salary.java")
addOtherJavaFile("collector", "HogeCollector.java")
addOtherJavaFile("function", "HogeFunction.java")
addOtherJavaFile("function", "HogeBiFunction.java")
Expand Down Expand Up @@ -88,4 +90,9 @@ class AnnotationReturnTypeCheckInspectionTest : DomaSqlTest() {
val dao = findDaoClass("$daoPackage.FactoryReturnTypeTestDao")
myFixture.testHighlighting(false, false, false, dao.containingFile.virtualFile)
}

fun testDataTypeReturnTypeCheckProcessor() {
val dao = findDaoClass("$daoPackage.DataTypeReturnTypeTestDao")
myFixture.testHighlighting(false, false, false, dao.containingFile.virtualFile)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package doma.example.dao.inspection.returntype;

import org.seasar.doma.*;
import doma.example.domain.Salary;
import org.seasar.doma.jdbc.Reference;
import org.seasar.doma.jdbc.Result;

import java.util.List;
import java.util.Optional;

@Dao
public interface DataTypeReturnTypeTestDao {

@Select
@Sql("select * from salary where id = /*salary.value*/0")
Salary selectSalary(Salary salary);

@Select
@Sql("select * from salary where id = /*salary.value*/0")
Optional<Salary> selectOptSalary(Salary salary) ;

@Update
@Sql("UPDATE salary SET val = /*salary.value*/0")
int updateSalaryWithSql1(Salary salary);

@Update
@Sql("UPDATE salary SET val = /*salary.value*/0")
Result<Salary> <error descr="The return type must be \"int\"">updateSalaryWithSql2</error>(Salary salary);

@Insert
@Sql("INSERT INTO salary (val) VALUES (/*salary.value*/0)")
int insertSalaryWithSql(Salary salary);

@Insert
@Sql("INSERT INTO salary (val) VALUES (/*salary.value*/0)")
Result<Salary> <error descr="The return type must be \"int\"">insertSalaryWithSql2</error>(Salary salary);

@Delete
@Sql("DELETE FROM salary WHERE val = /*salary.value*/0 ")
int deleteSalaryWithSql(Salary salary);

@Delete
@Sql("DELETE FROM salary WHERE val = /*salary.value*/0 ")
Result<Salary> <error descr="The return type must be \"int\"">deleteSalaryWithSql2</error>(Salary salary);

@BatchUpdate
@Sql("UPDATE salary SET val = /*salary.value*/0")
int[] batchUpdateSalaryWithSql(List<Salary> salary);

@BatchUpdate
@Sql("UPDATE salary SET val = /*salary.value*/0")
<error descr="Cannot resolve symbol 'BatchResult'">BatchResult</error><Salary> <error descr="The return type must be \"int[]\"">batchUpdateSalaryWithSql2</error>(List<Salary> salary);

@BatchInsert
@Sql("INSERT INTO salary (val) VALUES (/*salary.value*/0)")
int[] batchInsertSalaryWithSql(List<Salary> salary);

@BatchInsert
@Sql("INSERT INTO salary (val) VALUES (/*salary.value*/0)")
<error descr="Cannot resolve symbol 'BatchResult'">BatchResult</error><Salary> <error descr="The return type must be \"int[]\"">batchInsertSalaryWithSql2</error>(List<Salary> salary);

@BatchDelete
@Sql("DELETE FROM salary WHERE val = /*salary.value*/0 ")
int[] batchDeleteSalaryWithSql(List<Salary> salary);

@BatchDelete
@Sql("DELETE FROM salary WHERE val = /*salary.value*/0 ")
<error descr="Cannot resolve symbol 'BatchResult'">BatchResult</error><Salary> <error descr="The return type must be \"int[]\"">batchDeleteSalaryWithSql2</error>(List<Salary> salary);

@Function
List<Salary> getTopSalaries(@In Salary limit);

@Function
Optional<Salary> getMaxSalary(@InOut Reference<Salary> percentage, @ResultSet List<Salary> resultSet);

@Procedure
void computeBonus(@In Salary employeeId);

@Procedure
void adjustSalaries(@InOut Reference<Salary> percentage, @ResultSet List<Salary> resultSet);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package doma.example.domain;

import java.math.BigDecimal;
import org.seasar.doma.DataType;

@DataType
public record Salary(BigDecimal value) {
}
Loading