Skip to content

Commit

Permalink
Merge pull request #7 from vlang/v-inspections
Browse files Browse the repository at this point in the history
cyclic import detection inspection
  • Loading branch information
JalonSolov authored Jun 8, 2024
2 parents 92acce9 + d8a0853 commit 7ed9b75
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,46 @@ import io.vlang.ide.inspections.VlangBaseInspection
import io.vlang.lang.psi.VlangFile
import io.vlang.lang.psi.VlangImportName
import io.vlang.lang.psi.VlangVisitor
import io.vlang.lang.psi.impl.VlangModule

class VlangCircularImportInspection : VlangBaseInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {

fun hasCircularImport(module: VlangModule, visited: MutableSet<VlangModule>): Boolean {
if (module in visited) return true // circular import detected, stop here

visited.add(module)
module.directory.files.filterIsInstance<VlangFile>().forEach { file ->
val imports = file.getImports()
for (import in imports) {
import.resolve().firstOrNull()?.let{
return hasCircularImport(it, visited)
}
}
}
visited.remove(module)

return false // exhausted dfs search, no circular import detected
}

return object : VlangVisitor() {

override fun visitImportName(importName: VlangImportName) {

super.visitImportName(importName)
val currentModule = importName.containingFile.containingDirectory
val importList = importName.resolve().toList()

// check for circular import
importList.forEach { module ->
val files = module.directory.files.filterIsInstance<VlangFile>()
for (file in files) {
val imports = file.getImports()
if (imports.any { it.name == currentModule.name }) {
holder.registerProblem(
importName,
"Circular import detected",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
)
}
if(hasCircularImport(module, mutableSetOf())){
holder.registerProblem(
importName,
"Circular import detected",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
)
}
} // end check for circular import
}

}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,28 @@ import io.vlang.ide.inspections.general.VlangCircularImportInspection
import io.vlang.integration.IntegrationTestBase

class CircularImportInspectionsTest : IntegrationTestBase() {

fun `test simple circular import`() = doTest {
directory("first") {
file("utils.v", """
fileNoLangInj("utils.v",
"""
module first
import second
pub fn util(){
second.util()
}
""".trimIndent())
}

directory("second") {
file("utils.v", """
fileNoLangInj("utils.v",
"""
module second
import <warning descr="Circular import detected">first</warning>
pub fn util() {
first.util()
}
Expand All @@ -32,4 +35,56 @@ class CircularImportInspectionsTest : IntegrationTestBase() {
testInspections()
}
}

fun `test three way import cycle`() = doTest {

directory("first") {
fileNoLangInj("utils.v",
"""
module first
import second
pub fn util(){
second.util()
}
""".trimIndent())
}

directory("second") {
fileNoLangInj("utils.v",
"""
module second
import third
pub fn util() {
third.util()
}
""".trimIndent())
}

directory("third") {
fileNoLangInj("utils.v",
"""
module third
import <warning descr="Circular import detected">first</warning>
pub fn util() {
first.util()
}
""".trimIndent())

enableInspection(VlangCircularImportInspection())
testInspections()
}

}

//extension lambda to create file without language Sytax injection
val fileNoLangInj : DirectoryContext.(name: String, text: String) -> Unit = { name, text ->
file(name, text)
}

}

0 comments on commit 7ed9b75

Please sign in to comment.