Skip to content

Commit 6038e90

Browse files
committed
Enable navigation and linkage between DAO files and SQL files without relying on cached paths
1 parent 0f9d791 commit 6038e90

File tree

7 files changed

+115
-152
lines changed

7 files changed

+115
-152
lines changed

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

Lines changed: 11 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import com.intellij.openapi.module.Module
2020
import com.intellij.openapi.project.Project
2121
import com.intellij.openapi.roots.ModuleRootManager
2222
import com.intellij.openapi.vfs.VirtualFile
23-
import org.domaframework.doma.intellij.common.CommonPathParameterUtil.refreshModulePaths
2423
import org.jetbrains.jps.model.java.JavaResourceRootType
2524
import org.jetbrains.jps.model.java.JavaSourceRootType
2625
import java.util.concurrent.ConcurrentHashMap
@@ -35,31 +34,28 @@ object CommonPathParameterUtil {
3534
/**
3635
* Holds directory information for a module.
3736
*
38-
* @property moduleBasePaths The base path of the module.
3937
* @property moduleSourceDirectories List of source directories.
4038
* @property moduleResourceDirectories List of resource directories.
4139
* @property moduleTestSourceDirectories List of test source directories.
4240
* @property moduleTestResourceDirectories List of test resource directories.
4341
*/
4442
data class ModulePaths(
45-
val moduleBasePaths: List<VirtualFile>,
4643
val moduleSourceDirectories: List<VirtualFile>,
4744
val moduleResourceDirectories: List<VirtualFile>,
4845
val moduleTestSourceDirectories: List<VirtualFile>,
4946
val moduleTestResourceDirectories: List<VirtualFile>,
5047
)
5148

5249
// Cache for each module's directory information.
53-
private val modulePathCache = ConcurrentHashMap<Int, ModulePaths>()
50+
private val modulePathCache = ConcurrentHashMap<String, ModulePaths>()
5451

5552
/**
5653
* Returns the directory information for the specified module (uses cache if available).
57-
* If the module's directory structure has changed, call [refreshModulePaths] to update the cache.
5854
*
5955
* @param module The module to retrieve directory information for.
6056
* @return The cached or newly computed ModulePaths.
6157
*/
62-
fun getModulePaths(module: Module): ModulePaths = modulePathCache[module.hashCode()] ?: refreshModulePaths(module)
58+
fun getModulePaths(module: Module): ModulePaths? = modulePathCache[module.name]
6359

6460
/**
6561
* Checks if a given path is a generated directory based on annotation processor settings.
@@ -87,8 +83,7 @@ object CommonPathParameterUtil {
8783
* @param module The module to refresh.
8884
* @return The updated ModulePaths.
8985
*/
90-
fun refreshModulePaths(module: Module): ModulePaths {
91-
var basePath = mutableListOf<VirtualFile>()
86+
fun refreshModulePaths(module: Module) {
9287
val sourceDirs = mutableListOf<VirtualFile>()
9388
val resourceDirs = mutableListOf<VirtualFile>()
9489
val testSourceDirs = mutableListOf<VirtualFile>()
@@ -98,7 +93,6 @@ object CommonPathParameterUtil {
9893
moduleManager.contentEntries.forEach { entry ->
9994
val entryFile = entry.file
10095
if (entryFile != null && !isGeneratedDirectory(module, entryFile.path)) {
101-
entry.file?.let { basePath.add(it) }
10296
entry.sourceFolders.forEach { folder ->
10397
val file = folder.file
10498
if (file != null) {
@@ -130,14 +124,12 @@ object CommonPathParameterUtil {
130124

131125
val paths =
132126
ModulePaths(
133-
basePath,
134127
sourceDirs,
135128
resourceDirs,
136129
testSourceDirs,
137130
testResourceDirs,
138131
)
139-
modulePathCache[module.hashCode()] = paths
140-
return paths
132+
modulePathCache[module.name] = paths
141133
}
142134

143135
/**
@@ -151,7 +143,7 @@ object CommonPathParameterUtil {
151143
module: Module,
152144
file: VirtualFile,
153145
): Boolean {
154-
val paths = getModulePaths(module)
146+
val paths = getModulePaths(module) ?: return false
155147
if (paths.moduleTestSourceDirectories.any { file.path.contains(it.path) }) return true
156148
if (paths.moduleTestResourceDirectories.any { file.path.contains(it.path) }) return true
157149
return false
@@ -168,30 +160,14 @@ object CommonPathParameterUtil {
168160
fun getResources(
169161
module: Module,
170162
file: VirtualFile,
171-
): List<VirtualFile> =
172-
if (isTest(module, file)) {
173-
getModulePaths(module).moduleTestResourceDirectories
163+
): List<VirtualFile> {
164+
val modulePaths = getModulePaths(module) ?: return emptyList()
165+
return if (isTest(module, file)) {
166+
modulePaths.moduleTestResourceDirectories
174167
} else {
175-
getModulePaths(module).moduleResourceDirectories
176-
}
177-
178-
/**
179-
* Returns the source directories for the given file in the specified module.
180-
* If the file is in a test directory, test source directories are returned.
181-
*
182-
* @param module The module to check.
183-
* @param file The file to check.
184-
* @return List of source directories.
185-
*/
186-
fun getSources(
187-
module: Module,
188-
file: VirtualFile,
189-
): List<VirtualFile> =
190-
if (isTest(module, file)) {
191-
getModulePaths(module).moduleTestSourceDirectories
192-
} else {
193-
getModulePaths(module).moduleSourceDirectories
168+
modulePaths.moduleResourceDirectories
194169
}
170+
}
195171

196172
/**
197173
* Clears the module directory cache. Call this if the module structure changes.

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

Lines changed: 39 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,11 @@ import org.domaframework.doma.intellij.common.getJarRoot
3434
import org.domaframework.doma.intellij.common.getMethodDaoFilePath
3535
import org.domaframework.doma.intellij.common.isInjectionSqlFile
3636
import org.domaframework.doma.intellij.common.isSupportFileType
37-
import org.domaframework.doma.intellij.common.sourceExtensionNames
38-
import org.domaframework.doma.intellij.extension.findFile
3937
import org.domaframework.doma.intellij.extension.getContentRoot
4038
import org.domaframework.doma.intellij.extension.getJavaClazz
4139
import org.domaframework.doma.intellij.extension.getModule
40+
import org.domaframework.doma.intellij.extension.getSourceRootDir
4241
import org.jetbrains.kotlin.idea.base.util.module
43-
import java.nio.file.Paths
4442

4543
/**
4644
* Get DAO method corresponding to SQL file
@@ -58,36 +56,24 @@ fun findDaoMethod(
5856
return PsiTreeUtil.getParentOfType(originalFile.context, PsiMethod::class.java)
5957
}
6058
} else if (isSupportFileType(originalFile)) {
61-
// TODO: Add Support Kotlin
6259
val methodName = virtualFile.nameWithoutExtension
6360
val daoFile = daoFile ?: findDaoFile(project, originalFile) ?: return null
6461
if (module != null) {
65-
val relativePath =
62+
val contentRootPath = project.getContentRoot(virtualFile)?.path ?: return null
63+
val daoJavaFile =
6664
getDaoPathFromSqlFilePath(
6765
originalFile,
68-
project.getContentRoot(virtualFile)?.path ?: "",
69-
)
70-
// get ClassPath with package name
71-
val daoClassName: String =
72-
relativePath
73-
.substringBefore(".")
74-
.replace("/", ".")
75-
.replace("\\", ".")
76-
.replace("..", ".")
77-
.trim('.')
66+
contentRootPath,
67+
) ?: return null
7868

79-
val daoJavaFile = project.findFile(daoFile)
80-
val isTest = CommonPathParameterUtil.isTest(module, originalFile.virtualFile)
81-
findDaoClass(module, isTest, daoClassName)
82-
?.let { daoClass ->
83-
val daoMethod =
84-
// TODO Support Kotlin Project
85-
when (daoJavaFile) {
86-
is PsiJavaFile -> findUseSqlDaoMethod(daoJavaFile, methodName)
87-
else -> null
88-
}
89-
return daoMethod
69+
// TODO Support Kotlin Project
70+
val daoFile = daoJavaFile.containingFile
71+
val daoMethod =
72+
when (daoFile) {
73+
is PsiJavaFile -> findUseSqlDaoMethod(daoFile, methodName)
74+
else -> null
9075
}
76+
return daoMethod
9177
} else {
9278
val fileType = getExtension(daoFile.fileType.name)
9379
val jarRootPath = virtualFile.path.substringBefore("jar!").plus("jar!")
@@ -133,78 +119,36 @@ fun findDaoFile(
133119
if (contentRoot == null) {
134120
return getJarRoot(virtualFile, sqlFile)
135121
}
136-
return searchDaoFile(sqlFile.module, contentRoot, sqlFile)
122+
return getDaoPathFromSqlFilePath(
123+
sqlFile,
124+
contentRoot.path,
125+
)?.containingFile?.virtualFile
137126
}
138127

139-
/**
140-
* DAO file search for SQL file
141-
*/
142-
private fun searchDaoFile(
143-
module: Module?,
144-
contentRoot: VirtualFile?,
145-
sqlFile: PsiFile,
146-
): VirtualFile? {
147-
val contentRootPath = contentRoot?.path ?: return null
148-
val pathParams = module?.let { CommonPathParameterUtil.getModulePaths(it) } ?: return null
149-
val moduleBaseName =
150-
pathParams.moduleBasePaths
151-
.find { baseName -> Paths.get(contentRootPath).startsWith(Paths.get(baseName.path)) }
152-
?.nameWithoutExtension ?: ""
153-
// TODO: Add Support Kotlin
154-
val relativeDaoFilePaths =
155-
getDaoPathFromSqlFilePath(sqlFile, contentRoot.path)
156-
val sources = CommonPathParameterUtil.getSources(module, sqlFile.virtualFile)
157-
158-
if (contentRootPath.endsWith(moduleBaseName) == true) {
159-
sources.forEach { source ->
160-
sourceExtensionNames.forEach { extension ->
161-
val fileExtension = getExtension(extension)
162-
val findDaoFile =
163-
contentRoot.findFileByRelativePath("${source.nameWithoutExtension}$relativeDaoFilePaths.$fileExtension")
164-
if (findDaoFile != null) return findDaoFile
165-
}
166-
}
167-
}
168-
return null
169-
}
170-
171-
private fun findDaoClass(
172-
module: Module,
173-
includeTest: Boolean,
174-
daoClassName: String,
175-
): PsiClass? = module.getJavaClazz(includeTest, daoClassName)
176-
177128
/**
178129
* Generate DAO deployment path from SQL file path
179130
* @param sqlFile SQL File
180-
* @param projectRootPath project content Root Path
131+
* @param contentRootPath project content Root Path
181132
* @return
182133
*/
183134
private fun getDaoPathFromSqlFilePath(
184135
sqlFile: PsiFile,
185-
projectRootPath: String,
186-
): String {
136+
contentRootPath: String,
137+
): PsiClass? {
187138
if (isInjectionSqlFile(sqlFile)) {
188-
return ""
189-
}
190-
val module = sqlFile.module
191-
val sqlPath = sqlFile.virtualFile?.path ?: return ""
192-
var relativeFilePath = sqlPath.substring(projectRootPath.length)
193-
if (!relativeFilePath.startsWith("/")) {
194-
relativeFilePath = "/$relativeFilePath"
139+
return null
195140
}
196-
val resources =
197-
module?.let { CommonPathParameterUtil.getResources(it, sqlFile.virtualFile) }
198-
?: emptyList()
141+
val module = sqlFile.module ?: return null
142+
val sqlPath = sqlFile.virtualFile?.path ?: return null
143+
val relativePath =
144+
sqlPath.substringAfter(contentRootPath, "").replace("/$RESOURCES_META_INF_PATH", "")
145+
val resourcesRootPath = module.project.getSourceRootDir(sqlFile.virtualFile)?.name ?: ""
146+
val isTest = CommonPathParameterUtil.isTest(module, sqlFile.virtualFile)
199147

200-
return resources
201-
.find { resource ->
202-
relativeFilePath.startsWith("/${resource.nameWithoutExtension}/")
203-
}?.let { resource ->
204-
relativeFilePath
205-
.replace("${resource.nameWithoutExtension}/$RESOURCES_META_INF_PATH/", "")
206-
.replace("/${sqlFile.name}", "")
207-
} ?: ""
148+
val packageName = relativePath.replaceFirst("/$resourcesRootPath/", "").replace("/${sqlFile.name}", "").replace("/", ".")
149+
val daoClassFile = module.getJavaClazz(isTest, packageName)
150+
151+
return daoClassFile
208152
}
209153

210154
/**
@@ -219,30 +163,14 @@ fun getRelativeSqlFilePathFromDaoFilePath(
219163
): String {
220164
if (module == null) return ""
221165
val extension = daoFile.fileType.defaultExtension
166+
val sourceRoot = module.project.getSourceRootDir(daoFile) ?: return ""
167+
168+
val project = module.project
169+
val sourceRootParent = project.getContentRoot(daoFile) ?: return ""
222170
val daoFilePath = daoFile.path
223-
val pathParams = CommonPathParameterUtil.getModulePaths(module)
224-
val containsModuleBaseName =
225-
pathParams.moduleBasePaths
226-
.find { basePath -> daoFilePath.contains("${basePath.path}/") }
227-
?.path ?: return ""
228-
var relativeSqlFilePath =
229-
daoFilePath
230-
.replaceFirst(containsModuleBaseName, "")
231-
.replace(".$extension", "")
232-
val sources = CommonPathParameterUtil.getSources(module, daoFile)
233-
sources
234-
.find {
235-
daoFilePath
236-
.startsWith(containsModuleBaseName.plus("/${it.nameWithoutExtension}/"))
237-
}?.let { source ->
238-
val startSourceName = "/${source.nameWithoutExtension}"
239-
if (relativeSqlFilePath.startsWith("$startSourceName/")) {
240-
relativeSqlFilePath =
241-
relativeSqlFilePath.replaceFirst(
242-
startSourceName,
243-
RESOURCES_META_INF_PATH,
244-
)
245-
}
246-
}
247-
return relativeSqlFilePath
171+
172+
return daoFilePath
173+
.substringAfter(sourceRootParent.path)
174+
.replaceFirst("/${sourceRoot.name}", RESOURCES_META_INF_PATH)
175+
.replace(".$extension", "")
248176
}

src/main/kotlin/org/domaframework/doma/intellij/common/psi/PsiDaoMethod.kt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import org.domaframework.doma.intellij.extension.findFile
4040
import org.domaframework.doma.intellij.extension.getContentRoot
4141
import org.domaframework.doma.intellij.extension.getModule
4242
import org.domaframework.doma.intellij.extension.getResourcesSQLFile
43+
import org.domaframework.doma.intellij.extension.getSourceRootDir
4344
import org.domaframework.doma.intellij.extension.psi.DomaAnnotationType
4445
import org.domaframework.doma.intellij.setting.SqlLanguage
4546
import org.jetbrains.kotlin.idea.base.util.module
@@ -180,11 +181,15 @@ class PsiDaoMethod(
180181
val rootDir = psiProject.getContentRoot(daoFile) ?: return@runReadAction
181182
val sqlFile = File(sqlFilePath)
182183
val sqlFileName = sqlFile.name
183-
val resourceDir =
184-
psiMethod.module
185-
?.let { CommonPathParameterUtil.getResources(it, daoFile).firstOrNull() }
186-
?: return@runReadAction
187-
val parentDir = "${resourceDir.nameWithoutExtension}/${sqlFile.parent?.replace("\\", "/")}"
184+
val module = psiMethod.module ?: return@runReadAction
185+
val isTest = CommonPathParameterUtil.isTest(module, daoFile)
186+
187+
val sqlDir = sqlFilePath.replace("/$sqlFileName", "")
188+
val existSqlDir = module.getResourcesSQLFile("$RESOURCES_META_INF_PATH/$sqlDir", isTest)
189+
val resourceDir = existSqlDir ?.let { psiProject.getSourceRootDir(it) }
190+
val resourcesDirPath = resourceDir?.nameWithoutExtension ?: "resources"
191+
192+
val parentDir = "$resourcesDirPath/${sqlFile.parent?.replace("\\", "/")}"
188193
val parenDirPathSpirit = parentDir.split("/").toTypedArray()
189194

190195
WriteCommandAction.runWriteCommandAction(psiProject) {

src/main/kotlin/org/domaframework/doma/intellij/extension/ProjectExtensions.kt

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

1818
import com.intellij.openapi.module.Module
1919
import com.intellij.openapi.project.Project
20+
import com.intellij.openapi.roots.ProjectFileIndex
2021
import com.intellij.openapi.roots.ProjectRootManager
2122
import com.intellij.openapi.vfs.VirtualFile
2223
import com.intellij.psi.JavaPsiFacade
@@ -51,3 +52,5 @@ fun Project.getJavaClazz(fqdn: String): PsiClass? {
5152
GlobalSearchScope.allScope(this),
5253
)
5354
}
55+
56+
fun Project.getSourceRootDir(file: VirtualFile): VirtualFile? = ProjectFileIndex.getInstance(this).getSourceRootForFile(file)

src/main/kotlin/org/domaframework/doma/intellij/setting/DomaToolStartupActivity.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,20 @@ import org.domaframework.doma.intellij.common.util.PluginUtil
2222

2323
class DomaToolStartupActivity : ProjectActivity {
2424
override suspend fun execute(project: Project) {
25+
setProperty()
26+
registerModuleRootListener(project)
27+
}
28+
29+
private fun setProperty() {
2530
System.setProperty("org.domaframework.doma.intellij.log.path", PathManager.getLogPath())
2631
System.setProperty(
2732
"org.domaframework.doma.intellij.plugin.version",
2833
PluginUtil.getVersion(),
2934
)
30-
3135
println("PluginVersion: ${System.getProperty("org.domaframework.doma.intellij.plugin.version")} ")
3236
}
37+
38+
private fun registerModuleRootListener(project: Project) {
39+
DomaToolsModuleRootListener.updateModuleDirectoryCache(project)
40+
}
3341
}

0 commit comments

Comments
 (0)