Skip to content

Commit

Permalink
Implement IDL -> C++ navigation and vice versa
Browse files Browse the repository at this point in the history
  • Loading branch information
mattco98 committed Jan 20, 2024
1 parent 18290d5 commit 27acc29
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 22 deletions.
45 changes: 29 additions & 16 deletions src/main/kotlin/me/mattco/serenityos/idl/IDLLineMarkerProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.intellij.codeInsight.daemon.LineMarkerInfo
import com.intellij.codeInsight.daemon.LineMarkerProvider
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder
import com.intellij.icons.AllIcons
import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.PsiElement
import com.intellij.psi.util.descendantsOfType
import com.jetbrains.cidr.lang.psi.OCFunctionDeclaration
Expand All @@ -17,22 +18,33 @@ import me.mattco.serenityos.idl.psi.api.IDLConstructor
import me.mattco.serenityos.idl.psi.api.IDLOperation

class IDLLineMarkerProvider : LineMarkerProvider {
override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? {
// TODO: IDL -> C++ doesn't work at all
// if (element is IDLDeclaration) {
// val cppDecls = element.idlProject.findCppDeclarations(
// element.containingFile.parent?.virtualFile ?: return null,
// element.name ?: return null,
// )
//
// // TODO: This should probably only ever be a single element
// val decl = cppDecls.firstOrNull() ?: return null
// return NavigationGutterIconBuilder.create(AllIcons.Gutter.ImplementedMethod)
// .setTarget(decl)
// .setTooltipText("Jump to C++ implementation")
// .createLineMarkerInfo(element.nameIdentifier ?: return null)
// }
override fun collectSlowLineMarkers(
elements: MutableList<out PsiElement>,
result: MutableCollection<in LineMarkerInfo<*>>
) {
ProgressManager.checkCanceled()

for (element in elements) {
if (element !is IDLDeclaration)
continue

val cppDecls = element.idlProject.findCppDeclarations(
element.containingFile.parent?.virtualFile ?: continue,
element.name ?: continue,
)

// TODO: This should probably only ever be a single element
val decl = cppDecls.firstOrNull() ?: continue
result.add(
NavigationGutterIconBuilder.create(AllIcons.Gutter.ImplementedMethod)
.setTarget(decl)
.setTooltipText("Jump to C++ implementation")
.createLineMarkerInfo(element.nameIdentifier ?: continue)
)
}
}

override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? {
if (element is OCStructLike) {
val idlDecls = element.idlProject.findIDLDeclarations(
element.containingFile.parent?.virtualFile ?: return null,
Expand All @@ -51,7 +63,8 @@ class IDLLineMarkerProvider : LineMarkerProvider {
// only show an icon for the struct
if (element is OCFunctionDeclaration && !element.containingOCFile.isHeader) {
val ns = element.namespaceQualifier?.text ?: (element.parent as? OCStructLike)?.name ?: return null
val idlDecls = element.idlProject.findIDLDeclarations(element.containingFile.parent?.virtualFile ?: return null, ns)
val idlDecls =
element.idlProject.findIDLDeclarations(element.containingFile.parent?.virtualFile ?: return null, ns)
idlDecls.forEach {
val member = findIDLMember(it, element.name ?: return@forEach)
if (member != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.toNioPathOrNull
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.search.FilenameIndex
import com.intellij.psi.search.GlobalSearchScopes
import com.intellij.psi.util.elementType
import com.intellij.psi.util.findParentInFile
import com.jetbrains.cidr.lang.parser.OCElementTypes
import com.jetbrains.cidr.lang.psi.OCCppNamespace
import com.jetbrains.cidr.lang.psi.OCElement
import com.jetbrains.cidr.lang.psi.OCFile
import com.jetbrains.cidr.lang.psi.OCStructLike
import me.mattco.serenityos.idl.descendentsOfType
Expand Down Expand Up @@ -44,9 +50,22 @@ class IDLProjectServiceImpl(private val project: Project) : IDLProjectService {
return emptySet()

val scope = GlobalSearchScopes.directoryScope(project, directory, true)
val virtualFiles = FilenameIndex.getAllFilesByExt(project, "idl", scope)
val declarations = mutableSetOf<IDLDeclaration>()
val manager = PsiManager.getInstance(project)
val declarations = mutableSetOf<IDLDeclaration>()

// Try to find an exact match first
var virtualFiles = FilenameIndex.getVirtualFilesByName("$name.idl", scope)
if (virtualFiles.isNotEmpty()) {
val file = manager.findFile(virtualFiles.first()) as? IDLFile ?: return emptySet()
// Assume that if this file doesn't have it, then we won't be able to find it
val decl = IDLResolver(file).findDeclaration(name)
if (decl != null)
declarations.add(decl)

return declarations
}

virtualFiles = FilenameIndex.getAllFilesByExt(project, "idl", scope)
virtualFiles.forEach {
val file = manager.findFile(it) as? IDLFile ?: return@forEach
val decl = IDLResolver(file).findDeclaration(name)
Expand All @@ -61,9 +80,23 @@ class IDLProjectServiceImpl(private val project: Project) : IDLProjectService {
return emptySet()

val scope = GlobalSearchScopes.directoryScope(project, directory, true)
val virtualFiles = FilenameIndex.getAllFilesByExt(project, "h", scope)
val declarations = mutableSetOf<OCStructLike>()
val manager = PsiManager.getInstance(project)
val declarations = mutableSetOf<OCStructLike>()

// Try to find an exact match first
var virtualFiles = FilenameIndex.getVirtualFilesByName("$name.h", scope)
if (virtualFiles.isNotEmpty()) {
val file = manager.findFile(virtualFiles.first()) as? OCFile ?: return emptySet()
// Assume that if this file doesn't have it, then we won't be able to find it
for (decl in file.descendentsOfType<OCStructLike>()) {
if (decl.name == name && hasWebNamespace(decl))
declarations.add(decl)
}

return declarations
}

virtualFiles = FilenameIndex.getAllFilesByExt(project, "h", scope)
for (virtualFile in virtualFiles) {
val file = manager.findFile(virtualFile) as? OCFile ?: continue
for (decl in file.descendentsOfType<OCStructLike>()) {
Expand All @@ -76,12 +109,17 @@ class IDLProjectServiceImpl(private val project: Project) : IDLProjectService {
}

private fun hasWebNamespace(struct: OCStructLike): Boolean {
var ns = struct.namespaceQualifier
var ns = getNamespace(struct)
while (ns != null) {
if (ns.name == "Web")
return true
ns = ns.namespaceQualifier
ns = getNamespace(ns)
}
return false
}

private fun getNamespace(element: OCElement): OCCppNamespace? {
val namespace = element.findParentInFile { it.elementType == OCElementTypes.CPP_NAMESPACE }
return if (namespace == null) null else namespace as OCCppNamespace
}
}

0 comments on commit 27acc29

Please sign in to comment.