diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/FakeFileForLightClass.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/FakeFileForLightClass.kt index 920bd5eb8d8..9852312005a 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/FakeFileForLightClass.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/FakeFileForLightClass.kt @@ -16,17 +16,27 @@ package org.jetbrains.kotlin.asJava.elements +import com.intellij.lang.java.JavaLanguage +import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.vfs.VirtualFile import com.intellij.pom.java.LanguageLevel import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiFileFactory import com.intellij.psi.impl.compiled.ClsFileImpl +import com.intellij.psi.impl.source.PsiFileImpl +import com.intellij.psi.impl.source.SourceTreeToPsiMap +import com.intellij.psi.impl.source.tree.TreeElement import com.intellij.psi.stubs.PsiClassHolderFileStub +import com.intellij.psi.util.PsiUtil +import com.intellij.reference.SoftReference +import com.intellij.util.AstLoadingFilter import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtFile +import java.lang.ref.Reference open class FakeFileForLightClass( val ktFile: KtFile, @@ -51,6 +61,37 @@ open class FakeFileForLightClass( // TODO: More complex traversal logic may be implemented when necessary } + @Volatile + private var myMirrorFileElement: Reference? = null + private val myMirrorLock: Any = Any() + + override fun getMirror(): PsiElement { + SoftReference.dereference(myMirrorFileElement)?.let { return it.psi } + + val mirrorElement = synchronized(myMirrorLock) { + SoftReference.dereference(myMirrorFileElement)?.let { return@synchronized it } + + val file = this.virtualFile + AstLoadingFilter.assertTreeLoadingAllowed(file) + val classes: Array = this.classes + val fileName = (if (classes.isNotEmpty()) classes[0].name else file.nameWithoutExtension) + ".java" + val document = FileDocumentManager.getInstance().getDocument(file) ?: error(file.url) + + val factory = PsiFileFactory.getInstance(this.manager.project) + val mirror = factory.createFileFromText(fileName, JavaLanguage.INSTANCE, document.immutableCharSequence, false, false, true) + mirror.putUserData(PsiUtil.FILE_LANGUAGE_LEVEL_KEY, this.languageLevel) + val mirrorTreeElement = SourceTreeToPsiMap.psiToTreeNotNull(mirror) + if (mirror is PsiFileImpl) { + mirror.originalFile = this + } + mirrorTreeElement.also { + myMirrorFileElement = SoftReference(it) + } + } + + return mirrorElement.psi + } + // this should be equal to current compiler target language level override fun getLanguageLevel() = LanguageLevel.JDK_1_6