diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/KtFakeLightClass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/KtFakeLightClass.kt index fde02b30b72..9e64528cce8 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/KtFakeLightClass.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/KtFakeLightClass.kt @@ -16,12 +16,12 @@ package org.jetbrains.kotlin.idea.caches.lightClasses -import com.intellij.psi.PsiClass -import com.intellij.psi.PsiElementFactory -import com.intellij.psi.PsiMethod -import com.intellij.psi.PsiType +import com.intellij.ide.highlighter.JavaFileType +import com.intellij.openapi.project.Project +import com.intellij.psi.* import com.intellij.psi.impl.light.AbstractLightClass import com.intellij.psi.impl.light.LightMethod +import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.LightClassInheritanceHelper import org.jetbrains.kotlin.asJava.elements.KtLightElement @@ -32,13 +32,14 @@ import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.resolve.DescriptorUtils +import javax.swing.Icon // Used as a placeholder when actual light class does not exist (expect-classes, for example) // The main purpose is to allow search of inheritors within hierarchies containing such classes class KtFakeLightClass(override val kotlinOrigin: KtClassOrObject) : AbstractLightClass(kotlinOrigin.manager, KotlinLanguage.INSTANCE), KtLightClass { - private val _delegate by lazy { PsiElementFactory.SERVICE.getInstance(kotlinOrigin.project).createClass("dummy") } + private val _delegate by lazy { DummyJavaPsiFactory.createDummyClass(kotlinOrigin.project) } private val _containingClass by lazy { kotlinOrigin.containingClassOrObject?.let { KtFakeLightClass(it) } } override val clsDelegate get() = _delegate @@ -74,7 +75,7 @@ class KtFakeLightMethod private constructor( ktClassOrObject: KtClassOrObject ) : LightMethod( ktDeclaration.manager, - PsiElementFactory.SERVICE.getInstance(ktDeclaration.project).createMethod("dummy", PsiType.VOID), + DummyJavaPsiFactory.createDummyVoidMethod(ktDeclaration.project), KtFakeLightClass(ktClassOrObject), KotlinLanguage.INSTANCE ), KtLightElement { @@ -84,7 +85,7 @@ class KtFakeLightMethod private constructor( override fun getName() = ktDeclaration.name ?: "" override fun getNavigationElement() = ktDeclaration - override fun getIcon(flags: Int) = ktDeclaration.getIcon(flags) + override fun getIcon(flags: Int): Icon? = ktDeclaration.getIcon(flags) override fun getUseScope() = ktDeclaration.useScope companion object { @@ -93,4 +94,32 @@ class KtFakeLightMethod private constructor( return KtFakeLightMethod(ktDeclaration, ktClassOrObject) } } +} + +private object DummyJavaPsiFactory { + fun createDummyVoidMethod(project: Project): PsiMethod { + // Can't use PsiElementFactory.createMethod() because of formatting in PsiElementFactoryImpl. + val name = "dummy" + val returnType = PsiType.VOID + + val canonicalText = GenericsUtil.getVariableTypeByExpressionType(returnType).getCanonicalText(true) + val file = createDummyJavaFile(project, "class _Dummy_ { public $canonicalText $name() {\n} }") + val klass = file.classes.singleOrNull() + ?: throw IncorrectOperationException("Class was not created. Method name: $name; return type: $canonicalText") + + return klass.methods.singleOrNull() + ?: throw IncorrectOperationException("Method was not created. Method name: $name; return type: $canonicalText") + } + + fun createDummyClass(project: Project): PsiClass = PsiElementFactory.SERVICE.getInstance(project).createClass("dummy") + + private fun createDummyJavaFile(project: Project, text: String): PsiJavaFile { + return PsiFileFactory.getInstance(project).createFileFromText( + DUMMY_FILE_NAME, + JavaFileType.INSTANCE, + text + ) as PsiJavaFile + } + + private val DUMMY_FILE_NAME = "_Dummy_." + JavaFileType.INSTANCE.defaultExtension } \ No newline at end of file