Skip to content

Commit d7e22b7

Browse files
authored
Merge pull request #20 from domaframework/fix/reference-checks-for-repeated-elements-for-directive
Fix: Reference checks for repeated elements in the for directive do not work correctly
2 parents ea6be1a + 0e84e25 commit d7e22b7

File tree

8 files changed

+196
-100
lines changed

8 files changed

+196
-100
lines changed

src/main/kotlin/org/domaframework/doma/intellij/action/sql/JumpToDaoFromSQLAction.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class JumpToDaoFromSQLAction : AnAction() {
3737
currentFile = e.getData(CommonDataKeys.PSI_FILE) ?: return
3838
findDaoMethod(currentFile!!) ?: return
3939
e.presentation.isEnabledAndVisible =
40-
isSupportFileType(currentFile!!.virtualFile)
40+
isSupportFileType(currentFile!!)
4141
}
4242

4343
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
@@ -53,7 +53,7 @@ class JumpToDaoFromSQLAction : AnAction() {
5353
)
5454

5555
val project = e.project ?: return
56-
val daoFile = findDaoFile(project, currentFile?.virtualFile!!) ?: return
56+
val daoFile = findDaoFile(project, currentFile!!) ?: return
5757

5858
jumpToDaoMethod(project, currentFile?.virtualFile?.nameWithoutExtension!!, daoFile)
5959
PluginLoggerUtil.countLoggingByAction(

src/main/kotlin/org/domaframework/doma/intellij/action/sql/JumpToDeclarationFromSqlAction.kt

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
*/
1616
package org.domaframework.doma.intellij.action.sql
1717

18+
import com.intellij.lang.injection.InjectedLanguageManager
1819
import com.intellij.openapi.actionSystem.ActionUpdateThread
1920
import com.intellij.openapi.actionSystem.AnAction
2021
import com.intellij.openapi.actionSystem.AnActionEvent
2122
import com.intellij.openapi.actionSystem.CommonDataKeys
2223
import com.intellij.psi.PsiElement
2324
import com.intellij.psi.PsiFile
25+
import com.intellij.psi.PsiLiteralExpression
2426
import com.intellij.psi.PsiMethod
2527
import com.intellij.psi.PsiType
2628
import com.intellij.psi.tree.IFileElementType
@@ -35,7 +37,6 @@ import org.domaframework.doma.intellij.common.psi.PsiStaticElement
3537
import org.domaframework.doma.intellij.extension.psi.findParameter
3638
import org.domaframework.doma.intellij.extension.psi.getDomaAnnotationType
3739
import org.domaframework.doma.intellij.extension.psi.getIterableClazz
38-
import org.domaframework.doma.intellij.extension.psi.initPsiFileAndElement
3940
import org.domaframework.doma.intellij.extension.psi.isNotWhiteSpace
4041
import org.domaframework.doma.intellij.extension.psi.methodParameters
4142
import org.domaframework.doma.intellij.psi.SqlElClass
@@ -54,15 +55,23 @@ class JumpToDeclarationFromSqlAction : AnAction() {
5455
override fun update(e: AnActionEvent) {
5556
e.presentation.isEnabledAndVisible = false
5657
val editor = e.getData(CommonDataKeys.EDITOR) ?: return
57-
val caretOffset = editor.caretModel.offset
58+
val caretOffset = editor.caretModel.primaryCaret.selectionStart
5859

5960
currentFile = e.getData(CommonDataKeys.PSI_FILE) ?: return
6061
currentFile?.let { element = it.findElementAt(caretOffset) ?: return }
6162
if (element == null) return
6263

6364
val project = element?.project ?: return
6465
if (isJavaOrKotlinFileType(currentFile ?: return)) {
65-
currentFile = currentFile!!.initPsiFileAndElement(project, caretOffset)
66+
val injectedLanguageManager =
67+
InjectedLanguageManager.getInstance(project)
68+
val literal = PsiTreeUtil.getParentOfType(element, PsiLiteralExpression::class.java)
69+
currentFile =
70+
injectedLanguageManager
71+
.getInjectedPsiFiles(literal!!)
72+
?.firstOrNull()
73+
?.first as? PsiFile
74+
element = currentFile?.findElementAt(countInjectionOffset(literal, caretOffset))
6675
}
6776
findDaoMethod(currentFile ?: return) ?: return
6877

@@ -77,6 +86,31 @@ class JumpToDeclarationFromSqlAction : AnAction() {
7786
if (targetElement.isNotEmpty()) e.presentation.isEnabledAndVisible = true
7887
}
7988

89+
private fun countInjectionOffset(
90+
literal: PsiLiteralExpression,
91+
caretOffset: Int,
92+
): Int {
93+
val quoteCount = countLeadingDoubleQuotes(literal.text)
94+
val literalOffset = caretOffset - literal.textOffset
95+
val indentCount =
96+
literal.text.substring(0, literalOffset)
97+
val indentRegex = Regex("(?<=\\n)[ \\t]+")
98+
val indentSpacesCount = indentRegex.findAll(indentCount).sumOf { it.value.length }
99+
return literalOffset - quoteCount - indentSpacesCount
100+
}
101+
102+
private fun countLeadingDoubleQuotes(s: String): Int {
103+
var count = 0
104+
for (char in s) {
105+
if (char == '"') {
106+
count++
107+
} else {
108+
break
109+
}
110+
}
111+
return count
112+
}
113+
80114
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
81115

82116
override fun actionPerformed(e: AnActionEvent) {

src/main/kotlin/org/domaframework/doma/intellij/common/FileTypeCheck.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,24 @@ fun isJavaOrKotlinFileType(daoFile: PsiFile): Boolean {
4848
/*
4949
* Determine whether the open file is an SQL template file extension
5050
*/
51-
fun isSupportFileType(file: VirtualFile): Boolean {
52-
val extension = file.extension
51+
fun isSupportFileType(file: PsiFile): Boolean {
52+
val extension = file.fileType.defaultExtension
5353
return when (extension) {
5454
"sql", "script" -> true
5555
else -> false
5656
}
5757
}
5858

59+
fun isInjectionSqlFile(file: PsiFile): Boolean {
60+
val extension = file.fileType.defaultExtension
61+
val filePath = file.virtualFile.path
62+
return when (extension) {
63+
"sql" -> true
64+
else -> false
65+
} &&
66+
!(filePath.endsWith(".sql") || filePath.endsWith(".script"))
67+
}
68+
5969
/**
6070
* Dao file search for SQL files
6171
*/

src/main/kotlin/org/domaframework/doma/intellij/common/dao/DaoMethodUtil.kt

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package org.domaframework.doma.intellij.common.dao
1717

18-
import com.intellij.openapi.fileTypes.FileTypeManager
1918
import com.intellij.openapi.module.Module
2019
import com.intellij.openapi.project.Project
2120
import com.intellij.openapi.vfs.VirtualFile
@@ -27,6 +26,7 @@ import com.intellij.psi.util.PsiTreeUtil
2726
import org.domaframework.doma.intellij.common.CommonPathParameter.Companion.RESOURCES_META_INF_PATH
2827
import org.domaframework.doma.intellij.common.CommonPathParameter.Companion.RESOURCES_PATH
2928
import org.domaframework.doma.intellij.common.getExtension
29+
import org.domaframework.doma.intellij.common.isInjectionSqlFile
3030
import org.domaframework.doma.intellij.common.isSupportFileType
3131
import org.domaframework.doma.intellij.common.searchDaoFile
3232
import org.domaframework.doma.intellij.extension.findFile
@@ -40,15 +40,18 @@ import org.domaframework.doma.intellij.extension.getModule
4040
fun findDaoMethod(originalFile: PsiFile): PsiMethod? {
4141
val project = originalFile.project
4242
val module = project.getModule(originalFile.virtualFile) ?: return null
43-
val fileType = FileTypeManager.getInstance().getFileTypeByFile(originalFile.virtualFile)
4443

45-
if (isSupportFileType(originalFile.virtualFile)) {
44+
if (isInjectionSqlFile(originalFile)) {
45+
originalFile.let {
46+
return PsiTreeUtil.getParentOfType(originalFile.context, PsiMethod::class.java)
47+
}
48+
} else if (isSupportFileType(originalFile)) {
4649
// TODO: Add Support Kotlin
4750
val fileTypeName = "JAVA"
48-
val daoFile = findDaoFile(project, originalFile.virtualFile) ?: return null
51+
val daoFile = findDaoFile(project, originalFile) ?: return null
4952
val relativePath =
5053
formatDaoPathFromSqlFilePath(
51-
originalFile.virtualFile,
54+
originalFile,
5255
project.getContentRoot(originalFile.virtualFile)?.path ?: "",
5356
fileTypeName,
5457
)
@@ -71,10 +74,6 @@ fun findDaoMethod(originalFile: PsiFile): PsiMethod? {
7174
}
7275
return daoMethod
7376
}
74-
} else if (fileType.defaultExtension == "sql") {
75-
originalFile.let {
76-
return PsiTreeUtil.getParentOfType(originalFile.context, PsiMethod::class.java)
77-
}
7877
}
7978
return null
8079
}
@@ -84,14 +83,15 @@ fun findDaoMethod(originalFile: PsiFile): PsiMethod? {
8483
*/
8584
fun findDaoFile(
8685
project: Project,
87-
sqlFile: VirtualFile,
86+
sqlFile: PsiFile,
8887
): VirtualFile? {
89-
project.getModule(sqlFile) ?: return null
90-
val contentRoot = project.getContentRoot(sqlFile) ?: return null
88+
val virtualFile = sqlFile.virtualFile ?: return null
89+
project.getModule(virtualFile) ?: return null
90+
val contentRoot = project.getContentRoot(virtualFile) ?: return null
9191
// TODO: Add Support Kotlin
9292
val relativeFilePath =
9393
formatDaoPathFromSqlFilePath(sqlFile, contentRoot.path, "JAVA")
94-
return searchDaoFile(contentRoot, sqlFile.path, relativeFilePath)
94+
return searchDaoFile(contentRoot, virtualFile.path, relativeFilePath)
9595
}
9696

9797
private fun findDaoClass(
@@ -103,11 +103,15 @@ private fun findDaoClass(
103103
* Generate Dao deployment path from SQL file path
104104
*/
105105
fun formatDaoPathFromSqlFilePath(
106-
relativeBaseSqlFile: VirtualFile,
106+
relativeBaseSqlFile: PsiFile,
107107
projectRootPath: String,
108108
extension: String,
109109
): String {
110-
var relativeFilePath = relativeBaseSqlFile.path.substring(projectRootPath.length)
110+
if (isInjectionSqlFile(relativeBaseSqlFile)) {
111+
return ""
112+
}
113+
val sqlPath = relativeBaseSqlFile.virtualFile.path
114+
var relativeFilePath = sqlPath.substring(projectRootPath.length)
111115
if (!relativeFilePath.startsWith("/")) {
112116
relativeFilePath = "/$relativeFilePath"
113117
}

src/main/kotlin/org/domaframework/doma/intellij/gutter/sql/SqlLineMakerProvider.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.domaframework.doma.intellij.common.PluginLoggerUtil
2929
import org.domaframework.doma.intellij.common.dao.findDaoFile
3030
import org.domaframework.doma.intellij.common.dao.findDaoMethod
3131
import org.domaframework.doma.intellij.common.dao.jumpToDaoMethod
32+
import org.domaframework.doma.intellij.common.isInjectionSqlFile
3233
import org.domaframework.doma.intellij.common.isSupportFileType
3334
import org.jetbrains.kotlin.idea.core.util.toPsiFile
3435
import java.awt.event.MouseEvent
@@ -43,18 +44,18 @@ class SqlLineMakerProvider : RelatedItemLineMarkerProvider() {
4344
result: MutableCollection<in RelatedItemLineMarkerInfo<*>>,
4445
) {
4546
val project = e.project
46-
val virtualFile = e.containingFile.virtualFile
47-
if (!isSupportFileType(virtualFile)) return
47+
val file = e.containingFile ?: return
48+
if (!isSupportFileType(file) || isInjectionSqlFile(file)) return
4849
// Display only on the first line
4950
if (e.originalElement.parent.originalElement !is PsiFile ||
50-
e.textRange.startOffset != e.containingFile.textRange.startOffset
51+
e.textRange.startOffset != file.textRange.startOffset
5152
) {
5253
return
5354
}
5455

5556
val identifier = e.firstChild ?: e
5657
val daoFile =
57-
findDaoFile(project, virtualFile)?.let {
58+
findDaoFile(project, file)?.let {
5859
findDaoMethod(e.containingFile) ?: return
5960
it
6061
} ?: return
@@ -65,7 +66,7 @@ class SqlLineMakerProvider : RelatedItemLineMarkerProvider() {
6566
identifier.textRange,
6667
getIcon(daoFile.toPsiFile(project)),
6768
getToolTipTitle(daoFile.toPsiFile(project)),
68-
getHandler(daoFile, identifier, virtualFile.nameWithoutExtension),
69+
getHandler(daoFile, identifier, file.virtualFile.nameWithoutExtension),
6970
GutterIconRenderer.Alignment.RIGHT,
7071
) {
7172
ArrayList<GotoRelatedItem>()

0 commit comments

Comments
 (0)