in gdscript/src/main/kotlin/gdscript/psi/utils/GdClassMemberUtil.kt [518:627]
fun listClassMemberDeclarations(
element: PsiElement,
static: Boolean? = false,
search: String? = null,
constructors: Boolean = false,
isRecursive: Boolean = false,
): MutableList<PsiElement> {
val classElement = when (element) {
is GdFile, is GdClassDeclTl -> element
else -> GdClassUtil.getOwningClassElement(element)
}
val members = mutableListOf<PsiElement>()
if (search != null) {
val project = element.project
val scope = GlobalSearchScope.fileScope(element.containingFile)
GdMethodDeclIndex.INSTANCE.getScoped(search, project, scope).firstOrNull()?.let {
if ((static == null || it.isStatic == static)) {
if (constructors || !it.isConstructor) {
if (GdClassUtil.getOwningClassElement(it) == classElement) {
return mutableListOf(it)
}
}
}
}
GdConstDeclIndex.INSTANCE.getScoped(search, project, scope).firstOrNull()
?.let { if (GdClassUtil.getOwningClassElement(it) == classElement) it else null }?.let { return mutableListOf(it) }
GdEnumDeclIndex.INSTANCE.getScoped(search, project, scope).firstOrNull()
?.let { if (GdClassUtil.getOwningClassElement(it) == classElement) it else null }?.let { return mutableListOf(it) }
GdSignalDeclIndex.INSTANCE.getScoped(search, project, scope).firstOrNull()
?.let { if (GdClassUtil.getOwningClassElement(it) == classElement) it else null }?.let { return mutableListOf(it) }
GdClassVarDeclIndex.INSTANCE.getScoped(search, project, scope).firstOrNull()
?.let { if (GdClassUtil.getOwningClassElement(it) == classElement) it else null }
?.let { if (static != true || it.isStatic) return mutableListOf(it) }
PsiTreeUtil.getStubChildrenOfTypeAsList(classElement, GdClassDeclTl::class.java).forEach {
if (it.name == search) return mutableListOf(it)
if (isRecursive) {
members.addAll(listClassMemberDeclarations(it, static, search))
if (members.size > 0) return members
}
}
if (classElement is GdClassDeclTl && !isRecursive) {
PsiTreeUtil.getStubChildrenOfTypeAsList(classElement.parent, GdClassDeclTl::class.java).forEach {
if (it.name == search) return mutableListOf(it)
members.addAll(listClassMemberDeclarations(it, static, search, false, true))
if (members.size > 0) return members
}
}
// TODO Create stub for unnamed enums
PsiTreeUtil.getStubChildrenOfTypeAsList(classElement, GdEnumDeclTl::class.java).forEach {
if (it.name.isBlank()) {
it.enumValueList.forEach { value ->
if (value.enumValueNmi.name == search) return mutableListOf(value)
}
}
}
} else {
// When completing with a qualifier (static or instance), avoid mixing in file-level declarations,
// which would otherwise expose unrelated top-level classes like the qualifier's ancestors.
if (classElement is PsiFile && static != null) {
return mutableListOf()
}
PsiTreeUtil.getStubChildrenOfTypeAsList(classElement, GdConstDeclTl::class.java).forEach {
members.add(it)
}
PsiTreeUtil.getStubChildrenOfTypeAsList(classElement, GdEnumDeclTl::class.java).forEach {
if (it.name.isNotBlank()) {
members.add(it)
} else {
it.enumValueList.forEach { value ->
members.add(value)
}
}
}
PsiTreeUtil.getStubChildrenOfTypeAsList(classElement, GdSignalDeclTl::class.java).forEach {
members.add(it)
}
PsiTreeUtil.getStubChildrenOfTypeAsList(classElement, GdClassDeclTl::class.java).forEach {
// For completion and general member listing, include only direct inner classes,
// not members of their inner trees. Deeper members are reachable after further qualification.
members.add(it)
}
if (classElement is GdClassDeclTl && !isRecursive) {
PsiTreeUtil.getStubChildrenOfTypeAsList(classElement.parent, GdClassDeclTl::class.java).forEach {
members.addAll(listClassMemberDeclarations(it, static, null, false, true))
}
}
PsiTreeUtil.getStubChildrenOfTypeAsList(classElement, GdClassVarDeclTl::class.java).forEach {
if (static != true || it.isStatic) {
members.add(it)
}
}
PsiTreeUtil.getStubChildrenOfTypeAsList(classElement, GdMethodDeclTl::class.java).forEach {
if ((static == null || it.isStatic == static)) {
if (constructors || !it.isConstructor) {
members.add(it)
}
}
}
}
if (search != null) return mutableListOf()
return members
}