diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt index a0ac46fbdf4..c45c1d6912f 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.cli.jvm.compiler import com.intellij.psi.PsiManager -import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.CachedValue import org.jetbrains.kotlin.asJava.LightClassBuilder import org.jetbrains.kotlin.asJava.LightClassGenerationSupport @@ -25,7 +24,9 @@ import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder import org.jetbrains.kotlin.asJava.builder.LightClassDataHolderImpl +import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass import org.jetbrains.kotlin.asJava.classes.KtUltraLightClassForFacade +import org.jetbrains.kotlin.asJava.classes.KtUltraLightClassForScript import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* @@ -52,7 +53,9 @@ class CliLightClassGenerationSupport(private val traceHolder: CliTraceHolder) : files: Collection ): KtUltraLightClassForFacade? = null - override fun createUltraLightClass(element: KtClassOrObject) = null + override fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass? = null + + override fun createUltraLightClassForScript(script: KtScript): KtUltraLightClassForScript? = null override fun createDataHolderForClass(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder.ForClass { //force resolve companion for light class generation diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt index 02031349ac9..532b798df52 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt @@ -19,15 +19,11 @@ package org.jetbrains.kotlin.asJava import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import com.intellij.psi.PsiManager -import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.CachedValue import org.jetbrains.kotlin.asJava.builder.LightClassBuilderResult import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder -import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade -import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass -import org.jetbrains.kotlin.asJava.classes.KtUltraLightClassForFacade -import org.jetbrains.kotlin.asJava.classes.KtUltraLightSupport +import org.jetbrains.kotlin.asJava.classes.* import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* @@ -50,6 +46,8 @@ abstract class LightClassGenerationSupport { abstract fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass? + abstract fun createUltraLightClassForScript(script: KtScript): KtUltraLightClassForScript? + abstract fun createUltraLightClassForFacade( manager: PsiManager, facadeClassFqName: FqName, diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForScript.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForScript.kt index 0d6729185ae..0810f629a8f 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForScript.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForScript.kt @@ -1,29 +1,26 @@ /* - * Copyright 2010-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.asJava.classes import com.intellij.openapi.util.Comparing import com.intellij.openapi.util.Key +import com.intellij.openapi.util.registry.Registry import com.intellij.psi.* +import com.intellij.psi.impl.PsiSuperMethodImplUtil +import com.intellij.psi.impl.java.stubs.PsiJavaFileStub import com.intellij.psi.impl.light.LightEmptyImplementsList import com.intellij.psi.impl.light.LightModifierList import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager +import com.intellij.util.IncorrectOperationException import org.jetbrains.annotations.NonNls +import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService +import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.builder.LightClassData import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForScript import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass @@ -31,13 +28,20 @@ import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtCodeFragment import org.jetbrains.kotlin.psi.KtScript import javax.swing.Icon -class KtLightClassForScript private constructor( - val script: KtScript, - private val lightClassDataCache: CachedValue -) : KtLazyLightClass(script.manager) { +open class KtLightClassForScript(val script: KtScript) : KtLazyLightClass(script.manager) { + + protected open fun getLightClassDataHolder(): LightClassDataHolder.ForScript = + getLightClassCachedValue(script).value + + override val lightClassData: LightClassData + get() = getLightClassDataHolder().findDataForScript(script.fqName) + + protected open val javaFileStub: PsiJavaFileStub? + get() = getLightClassDataHolder().javaFileStub private val hashCode: Int = computeHashCode() @@ -49,10 +53,11 @@ class KtLightClassForScript private constructor( private val _containingFile by lazyPub { FakeFileForLightClass( - script.containingKtFile, - lightClass = { this }, - stub = { lightClassDataCache.value.javaFileStub }, - packageFqName = packageFqName) + script.containingKtFile, + lightClass = { this }, + stub = { javaFileStub }, + packageFqName = packageFqName, + ) } override val kotlinOrigin: KtClassOrObject? get() = null @@ -85,17 +90,19 @@ class KtLightClassForScript private constructor( override fun getImplementsList() = implementsList + override fun getExtendsList(): PsiReferenceList? = implementsList + override fun getImplementsListTypes(): Array = PsiClassType.EMPTY_ARRAY override fun getInterfaces(): Array = PsiClass.EMPTY_ARRAY override fun getOwnInnerClasses(): List { return script.declarations.filterIsInstance() - // workaround for ClassInnerStuffCache not supporting classes with null names, see KT-13927 - // inner classes with null names can't be searched for and can't be used from java anyway - // we can't prohibit creating light classes with null names either since they can contain members - .filter { it.name != null } - .mapNotNull { KtLightClassForSourceDeclaration.create(it) } + // workaround for ClassInnerStuffCache not supporting classes with null names, see KT-13927 + // inner classes with null names can't be searched for and can't be used from java anyway + // we can't prohibit creating light classes with null names either since they can contain members + .filter { it.name != null } + .mapNotNull { KtLightClassForSourceDeclaration.create(it) } } override fun getInitializers(): Array = PsiClassInitializer.EMPTY_ARRAY @@ -106,17 +113,49 @@ class KtLightClassForScript private constructor( override fun isValid() = script.isValid - override fun copy() = KtLightClassForScript(script, lightClassDataCache) - - override val lightClassData = lightClassDataCache.value.findDataForScript(script.fqName) + override fun copy() = KtLightClassForScript(script) override fun getNavigationElement() = script override fun isEquivalentTo(another: PsiElement?): Boolean = - another is PsiClass && Comparing.equal(another.qualifiedName, qualifiedName) + another is PsiClass && Comparing.equal(another.qualifiedName, qualifiedName) override fun getElementIcon(flags: Int): Icon? = throw UnsupportedOperationException("This should be done by JetIconProvider") + override val originKind: LightClassOriginKind get() = LightClassOriginKind.SOURCE + + override fun getLBrace(): PsiElement? = null + + override fun getRBrace(): PsiElement? = null + + override fun getVisibleSignatures(): MutableCollection = PsiSuperMethodImplUtil.getVisibleSignatures(this) + + override fun setName(name: String): PsiElement? = throw IncorrectOperationException() + + override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean { + return baseClass.qualifiedName == CommonClassNames.JAVA_LANG_OBJECT + } + + override fun isInheritorDeep(baseClass: PsiClass?, classToByPass: PsiClass?): Boolean = false + + override fun getSuperClass(): PsiClass? { + return JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_OBJECT, resolveScope) + } + + override fun getSupers(): Array { + return superClass?.let { arrayOf(it) } ?: arrayOf() + } + + override fun getSuperTypes(): Array { + return arrayOf(PsiType.getJavaLangObject(manager, resolveScope)) + } + + override fun getNameIdentifier(): PsiIdentifier? = null + + override fun getParent(): PsiElement = containingFile + + override fun getScope(): PsiElement = parent + override fun hashCode() = hashCode private fun computeHashCode(): Int { @@ -146,16 +185,39 @@ class KtLightClassForScript private constructor( private val JAVA_API_STUB_FOR_SCRIPT = Key.create>("JAVA_API_STUB_FOR_SCRIPT") - fun create(script: KtScript): KtLightClassForScript = KtLightClassForScript(script, getLightClassCachedValue(script)) + fun create(script: KtScript): KtLightClassForScript? = + CachedValuesManager.getCachedValue(script) { + CachedValueProvider.Result + .create( + createNoCache(script, KtUltraLightSupport.forceUsingOldLightClasses), + KotlinModificationTrackerService.getInstance(script.project).outOfBlockModificationTracker, + ) + } + + fun createNoCache(script: KtScript, forceUsingOldLightClasses: Boolean): KtLightClassForScript? { + val containingFile = script.containingFile + if (containingFile is KtCodeFragment) { + // Avoid building light classes for code fragments + return null + } + + if (!forceUsingOldLightClasses && Registry.`is`("kotlin.use.ultra.light.classes", true)) { + LightClassGenerationSupport.getInstance(script.project).createUltraLightClassForScript(script)?.let { return it } + } + + return KtLightClassForScript(script) + } fun getLightClassCachedValue(script: KtScript): CachedValue { - return script.getUserData(JAVA_API_STUB_FOR_SCRIPT) ?: - createCachedValueForScript(script).also { script.putUserData(JAVA_API_STUB_FOR_SCRIPT, it) } + return script.getUserData(JAVA_API_STUB_FOR_SCRIPT) ?: createCachedValueForScript(script).also { + script.putUserData( + JAVA_API_STUB_FOR_SCRIPT, + it, + ) + } } private fun createCachedValueForScript(script: KtScript): CachedValue = - CachedValuesManager.getManager(script.project).createCachedValue(LightClassDataProviderForScript(script), false) + CachedValuesManager.getManager(script.project).createCachedValue(LightClassDataProviderForScript(script), false) } - - override val originKind: LightClassOriginKind get() = LightClassOriginKind.SOURCE } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt index 30788e3807a..29d894435ce 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt @@ -462,9 +462,16 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor override fun getInitializers(): Array = emptyArray() override fun getContainingClass(): PsiClass? { + val containingBody = classOrObject.parent as? KtClassBody val containingClass = containingBody?.parent as? KtClassOrObject - return containingClass?.let { create(it) } + containingClass?.let { return create(it) } + + val containingBlock = classOrObject.parent as? KtBlockExpression + val containingScript = containingBlock?.parent as? KtScript + containingScript?.let { return KtLightClassForScript.create(it) } + + return null } override fun getParent(): PsiElement? = containingClass ?: containingFile diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForScript.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForScript.kt new file mode 100644 index 00000000000..fa921dd1177 --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForScript.kt @@ -0,0 +1,137 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiModifier +import com.intellij.psi.PsiType +import com.intellij.psi.impl.java.stubs.PsiJavaFileStub +import com.intellij.psi.impl.light.LightMethodBuilder +import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService +import org.jetbrains.kotlin.asJava.builder.LightClassData +import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.KtScript + +class KtUltraLightClassForScript( + script: KtScript, + private val support: KtUltraLightSupport, +) : KtLightClassForScript(script) { + + override val clsDelegate: PsiClass get() = invalidAccess() + + override val lightClassData: LightClassData get() = invalidAccess() + + override fun getLightClassDataHolder(): LightClassDataHolder.ForScript = invalidAccess() + + override val javaFileStub: PsiJavaFileStub? = null + + private val membersBuilder by lazyPub { + UltraLightMembersCreator( + containingClass = this, + containingClassIsNamedObject = false, + containingClassIsSealed = true, + mangleInternalFunctions = true, + support = support, + ) + } + + internal inner class KtUltraLightScriptMainParameter(mainMethod: KtUltraLightMethod) : + KtUltraLightParameter( + name = "args", + kotlinOrigin = null, + support = support, + ultraLightMethod = mainMethod + ) { + + override fun getType(): PsiType = + PsiType.getJavaLangString(manager, resolveScope).createArrayType() + + override fun isVarArgs(): Boolean = false + + override val qualifiedNameForNullabilityAnnotation: String? = null + } + + private fun MutableList.addScriptDefaultMethods() { + val defaultConstructor = KtUltraLightMethodForSourceDeclaration( + delegate = LightMethodBuilder(manager, language, name).setConstructor(true).addModifier(PsiModifier.PUBLIC), + declaration = script, + support = support, + containingClass = this@KtUltraLightClassForScript, + methodIndex = METHOD_INDEX_FOR_DEFAULT_CTOR, + ) + add(defaultConstructor) + + val methodBuilder = LightMethodBuilder(manager, language, "main").apply { + isConstructor = false + addModifiers(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) + setMethodReturnType(PsiType.VOID) + } + + val mainMethod = KtUltraLightMethodForSourceDeclaration( + delegate = methodBuilder, + declaration = script, + support = support, + containingClass = this@KtUltraLightClassForScript, + methodIndex = METHOD_INDEX_FOR_SCRIPT_MAIN, + ) + + methodBuilder.addParameter(KtUltraLightScriptMainParameter(mainMethod)) + + add(mainMethod) + } + + private fun ownMethods(): List { + val result = mutableListOf() + + result.addScriptDefaultMethods() + + for (declaration in script.declarations.filterNot { it.isHiddenByDeprecation(support) }) { + when (declaration) { + is KtNamedFunction -> result.addAll(membersBuilder.createMethods(declaration, forceStatic = false)) + is KtProperty -> result.addAll( + membersBuilder.propertyAccessors(declaration, declaration.isVar, forceStatic = false, onlyJvmStatic = false), + ) + } + } + return result + } + + private val _ownMethods: CachedValue> = CachedValuesManager.getManager(project).createCachedValue( + { + CachedValueProvider.Result.create( + ownMethods(), + KotlinModificationTrackerService.getInstance(project).outOfBlockModificationTracker, + ) + }, + false, + ) + + override fun getOwnMethods(): List = _ownMethods.value + + private val _ownFields: List by lazyPub { + + val result = arrayListOf() + val usedNames = hashSetOf() + + for (property in script.declarations.filterIsInstance()) { + membersBuilder + .createPropertyField(property, usedNames, forceStatic = false) + ?.let(result::add) + } + result + } + + override fun getOwnFields(): List = _ownFields + + override fun copy(): KtLightClassForScript = KtUltraLightClassForScript(script, support) +} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt index c88505bddab..fc38a83c5d2 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt @@ -37,7 +37,8 @@ internal const val METHOD_INDEX_FOR_SETTER = 2 internal const val METHOD_INDEX_FOR_DEFAULT_CTOR = 3 internal const val METHOD_INDEX_FOR_NO_ARG_OVERLOAD_CTOR = 4 internal const val METHOD_INDEX_FOR_NON_ORIGIN_METHOD = 5 -internal const val METHOD_INDEX_BASE = 6 +internal const val METHOD_INDEX_FOR_SCRIPT_MAIN = 6 +internal const val METHOD_INDEX_BASE = 7 internal abstract class KtUltraLightMethod( internal val delegate: PsiMethod, 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 9852312005a..8e49b55908d 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 @@ -24,6 +24,9 @@ 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.java.stubs.ClsStubPsiFactory +import com.intellij.psi.impl.java.stubs.PsiJavaFileStub +import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl import com.intellij.psi.impl.source.PsiFileImpl import com.intellij.psi.impl.source.SourceTreeToPsiMap import com.intellij.psi.impl.source.tree.TreeElement @@ -41,7 +44,7 @@ import java.lang.ref.Reference open class FakeFileForLightClass( val ktFile: KtFile, private val lightClass: () -> KtLightClass, - private val stub: () -> PsiClassHolderFileStub<*>, + private val stub: () -> PsiClassHolderFileStub<*>?, private val packageFqName: FqName = ktFile.packageFqName ) : ClsFileImpl(ktFile.viewProvider) { @@ -50,7 +53,14 @@ open class FakeFileForLightClass( override fun getPackageName() = packageFqName.asString() - override fun getStub() = stub() + private fun createFakeJavaFileStub(): PsiJavaFileStub { + val javaFileStub = PsiJavaFileStubImpl(packageFqName.asString(), /*compiled = */true) + javaFileStub.psiFactory = ClsStubPsiFactory.INSTANCE + javaFileStub.psi = this + return javaFileStub + } + + override fun getStub() = stub() ?: createFakeJavaFileStub() override fun getClasses() = arrayOf(lightClass()) diff --git a/compiler/testData/asJava/ultraLightScripts/FunsPropsAndFields.kts b/compiler/testData/asJava/ultraLightScripts/FunsPropsAndFields.kts new file mode 100644 index 00000000000..6e4cfe4c1d6 --- /dev/null +++ b/compiler/testData/asJava/ultraLightScripts/FunsPropsAndFields.kts @@ -0,0 +1,9 @@ + +fun testFun(i: Int): String = i.toString() + +val testPropVal = 42 + +var testPropVar = 42 + +@JvmField +val testField = 42 \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightScripts/HelloWorld.kts b/compiler/testData/asJava/ultraLightScripts/HelloWorld.kts new file mode 100644 index 00000000000..45c53a23c2f --- /dev/null +++ b/compiler/testData/asJava/ultraLightScripts/HelloWorld.kts @@ -0,0 +1,2 @@ + +println("Hello world!") diff --git a/compiler/testData/asJava/ultraLightScripts/InnerClasses.kts b/compiler/testData/asJava/ultraLightScripts/InnerClasses.kts new file mode 100644 index 00000000000..58fccbb1153 --- /dev/null +++ b/compiler/testData/asJava/ultraLightScripts/InnerClasses.kts @@ -0,0 +1,11 @@ +class Bar(val a: Int) { + val b: Int = { 0 }() + + fun getAPlusB() = a + b + + class Baz { + fun doSomething() { + + } + } +} diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 83cbd69de5b..a9e6a3f864c 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidSyntheticPrope import org.jetbrains.kotlin.asJava.classes.AbstractUltraLightClassLoadingTest import org.jetbrains.kotlin.asJava.classes.AbstractUltraLightClassSanityTest import org.jetbrains.kotlin.asJava.classes.AbstractUltraLightFacadeClassTest +import org.jetbrains.kotlin.asJava.classes.AbstractUltraLightScriptLoadingTest import org.jetbrains.kotlin.checkers.* import org.jetbrains.kotlin.copyright.AbstractUpdateKotlinCopyrightTest import org.jetbrains.kotlin.findUsages.AbstractFindUsagesTest @@ -1016,7 +1017,9 @@ fun main(args: Array) { testClass { model("asJava/ultraLightClasses", pattern = KT_OR_KTS) } - + testClass { + model("asJava/ultraLightScripts", pattern = KT_OR_KTS) + } testClass { model("asJava/ultraLightFacades", pattern = KT_OR_KTS) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt index b99ad5bb5ad..65e280c6e18 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt @@ -128,8 +128,7 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG override fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass? { if (element.shouldNotBeVisibleAsLightClass() || - element is KtEnumEntry || - element.containingKtFile.safeIsScript() + element is KtEnumEntry ) { return null } @@ -150,6 +149,9 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG } } + override fun createUltraLightClassForScript(script: KtScript): KtUltraLightClassForScript? = + KtUltraLightClassForScript(script, support = KtUltraLightSupportImpl(script)) + private fun KtFile.hasAlias(shortName: Name?): Boolean { if (shortName == null) return false return allAliases(this)[shortName.asString()] == true diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightClassSanityTest.kt b/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightClassSanityTest.kt index 34c1a502c2e..9544538e22d 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightClassSanityTest.kt +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightClassSanityTest.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.asJava.classes import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager import org.jetbrains.kotlin.idea.perf.UltraLightChecker import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor @@ -26,6 +27,10 @@ abstract class AbstractUltraLightClassSanityTest : KotlinLightCodeInsightFixture UltraLightChecker.checkForReleaseCoroutine(sourceText, module) + if (file.safeIsScript()) { + ScriptConfigurationManager.updateScriptDependenciesSynchronously(file) + } + UltraLightChecker.checkClassEquivalence(file) } } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightScriptLoadingTest.kt b/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightScriptLoadingTest.kt new file mode 100644 index 00000000000..be718152d07 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightScriptLoadingTest.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.intellij.testFramework.LightProjectDescriptor +import junit.framework.TestCase +import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager +import org.jetbrains.kotlin.idea.perf.UltraLightChecker +import org.jetbrains.kotlin.idea.perf.UltraLightChecker.checkDescriptorsLeak +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.psi.KtFile +import java.io.File + +abstract class AbstractUltraLightScriptLoadingTest : KotlinLightCodeInsightFixtureTestCase() { + override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE + + fun doTest(testDataPath: String) { + val sourceText = File(testDataPath).readText() + val file = myFixture.addFileToProject(testDataPath, sourceText) as KtFile + + UltraLightChecker.checkForReleaseCoroutine(sourceText, module) + + TestCase.assertNotNull(file.script) + val script = file.script!! + + ScriptConfigurationManager.updateScriptDependenciesSynchronously(file) + + val ultraLightClass = UltraLightChecker.checkScriptEquivalence(script) + checkDescriptorsLeak(ultraLightClass) + } +} diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightScriptLoadingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightScriptLoadingTestGenerated.java new file mode 100644 index 00000000000..caab4e55ace --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightScriptLoadingTestGenerated.java @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/asJava/ultraLightScripts") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class UltraLightScriptLoadingTestGenerated extends AbstractUltraLightScriptLoadingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInUltraLightScripts() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/asJava/ultraLightScripts"), Pattern.compile("^(.+)\\.(kt|kts)$"), null, true); + } + + @TestMetadata("FunsPropsAndFields.kts") + public void testFunsPropsAndFields() throws Exception { + runTest("compiler/testData/asJava/ultraLightScripts/FunsPropsAndFields.kts"); + } + + @TestMetadata("HelloWorld.kts") + public void testHelloWorld() throws Exception { + runTest("compiler/testData/asJava/ultraLightScripts/HelloWorld.kts"); + } + + @TestMetadata("InnerClasses.kts") + public void testInnerClasses() throws Exception { + runTest("compiler/testData/asJava/ultraLightScripts/InnerClasses.kts"); + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt b/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt index 92f7399d700..41aa54341b2 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt @@ -17,17 +17,22 @@ import com.intellij.testFramework.UsefulTestCase import com.intellij.util.PairProcessor import com.intellij.util.ref.DebugReflectionUtil import junit.framework.TestCase +import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.classes.* import org.jetbrains.kotlin.asJava.elements.KtLightNullabilityAnnotation import org.jetbrains.kotlin.asJava.elements.KtLightPsiArrayInitializerMemberValue import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager import org.jetbrains.kotlin.idea.project.languageVersionSettings +import org.jetbrains.kotlin.j2k.getContainingClass import org.jetbrains.kotlin.load.kotlin.NON_EXISTENT_CLASS_NAME import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtScript import org.junit.Assert import kotlin.test.assertFails @@ -57,7 +62,6 @@ object UltraLightChecker { fun allClasses(file: KtFile): List = SyntaxTraverser.psiTraverser(file).filter(KtClassOrObject::class.java).toList() - fun checkFacadeEquivalence( fqName: FqName, searchScope: GlobalSearchScope, @@ -92,6 +96,25 @@ object UltraLightChecker { return ultraLightClass } + fun checkScriptEquivalence(script: KtScript): KtLightClass { + + val ultraLightScript: KtLightClass? + + val oldForceFlag = KtUltraLightSupport.forceUsingOldLightClasses + try { + KtUltraLightSupport.forceUsingOldLightClasses = false + ultraLightScript = KotlinAsJavaSupport.getInstance(script.project).getLightClassForScript(script) + TestCase.assertTrue(ultraLightScript is KtUltraLightClassForScript) + ultraLightScript!! + val gold = KtLightClassForScript.createNoCache(script, forceUsingOldLightClasses = true) + checkClassEquivalenceByRendering(gold, ultraLightScript) + } finally { + KtUltraLightSupport.forceUsingOldLightClasses = oldForceFlag + } + + return ultraLightScript!! + } + private fun checkClassEquivalenceByRendering(gold: PsiClass?, ultraLightClass: PsiClass) { if (gold != null) { Assert.assertFalse(gold.javaClass.name.contains("Ultra"))