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 ebc5914c282..74e62bac511 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 @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.builder.* import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade +import org.jetbrains.kotlin.asJava.classes.KtLightClassForScript import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -92,10 +93,18 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup ) } - private fun getContext(): LightClassConstructionContext { - return LightClassConstructionContext(bindingContext, module) + override fun createDataHolderForFacade(files: Collection, builder: LightClassBuilder): LightClassDataHolder.ForFacade { + val (stub, _, diagnostics) = builder(getContext()) + return LightClassDataHolderImpl(stub, diagnostics) } + override fun createDataHolderForScript(script: KtScript, builder: LightClassBuilder): LightClassDataHolder.ForScript { + val (stub, _, diagnostics) = builder(getContext()) + return LightClassDataHolderImpl(stub, diagnostics) + } + + private fun getContext(): LightClassConstructionContext = LightClassConstructionContext(bindingContext, module) + override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection { return ResolveSessionUtils.getClassDescriptorsByFqName(module, fqName).mapNotNull { val element = DescriptorToSourceUtils.getSourceFromDescriptor(it) @@ -143,9 +152,9 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup }) } - override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? { - return KtLightClassForSourceDeclaration.create(classOrObject) - } + override fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? = KtLightClassForSourceDeclaration.create(classOrObject) + + override fun getLightClassForScript(script: KtScript): KtLightClassForScript? = KtLightClassForScript.create(script) override fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor? { return bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration) @@ -163,6 +172,16 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup KtLightClassForFacade.createForFacade(psiManager, facadeFqName, scope, filesForFacade)) } + override fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection { + if (scriptFqName.isRoot) { + return emptyList() + } + + return findFilesForPackage(scriptFqName.parent(), scope).mapNotNull { file -> + file.script?.takeIf { it.fqName == scriptFqName }?.let { it -> getLightClassForScript(it) } + } + } + override fun getKotlinInternalClasses(fqName: FqName, scope: GlobalSearchScope): Collection { // return emptyList() @@ -176,11 +195,6 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup } } - override fun createDataHolderForFacade(files: Collection, builder: LightClassBuilder): LightClassDataHolder.ForFacade { - val (stub, _, diagnostics) = builder(getContext()) - return LightClassDataHolderImpl(stub, diagnostics) - } - override fun createTrace(): BindingTraceContext { return NoScopeRecordCliBindingTrace() } 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 4a587d6a8d2..68df43a1478 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt @@ -22,12 +22,10 @@ import com.intellij.psi.PsiClass import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.asJava.builder.* import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.KtLightClassForScript import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.psi.KtClassOrObject -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext typealias LightClassBuilder = (LightClassConstructionContext) -> LightClassBuilderResult @@ -38,6 +36,8 @@ abstract class LightClassGenerationSupport { abstract fun createDataHolderForFacade(files: Collection, builder: LightClassBuilder): LightClassDataHolder.ForFacade + abstract fun createDataHolderForScript(script: KtScript, builder: LightClassBuilder): LightClassDataHolder.ForScript + abstract fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection /* @@ -61,6 +61,8 @@ abstract class LightClassGenerationSupport { abstract fun getLightClass(classOrObject: KtClassOrObject): KtLightClass? + abstract fun getLightClassForScript(script: KtScript): KtLightClassForScript? + abstract fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor? abstract fun analyze(element: KtElement): BindingContext @@ -69,6 +71,8 @@ abstract class LightClassGenerationSupport { abstract fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection + abstract fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection + abstract fun getKotlinInternalClasses(fqName: FqName, scope: GlobalSearchScope): Collection abstract fun getFacadeClassesInPackage(packageFqName: FqName, scope: GlobalSearchScope): Collection diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataHolder.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataHolder.kt index 01c8d0261dd..004011c0082 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataHolder.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataHolder.kt @@ -53,6 +53,10 @@ interface LightClassDataHolder { interface ForFacade : LightClassDataHolder { fun findDataForFacade(classFqName: FqName): LightClassData = findData { it.findDelegate(classFqName) } } + + interface ForScript : ForClass { + fun findDataForScript(scriptFqName: FqName): LightClassData = findData { it.findDelegate(scriptFqName) } + } } interface LightClassData { @@ -85,7 +89,7 @@ object InvalidLightClassDataHolder : LightClassDataHolder.ForClass { class LightClassDataHolderImpl( override val javaFileStub: PsiJavaFileStub, override val extraDiagnostics: Diagnostics -) : LightClassDataHolder.ForClass, LightClassDataHolder.ForFacade { +) : LightClassDataHolder.ForClass, LightClassDataHolder.ForFacade, LightClassDataHolder.ForScript { override fun findData(findDelegate: (PsiJavaFileStub) -> PsiClass) = findDelegate(javaFileStub).let(::LightClassDataImpl) } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt index 8ff3af30e02..f60539f909c 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt @@ -128,6 +128,31 @@ sealed class LightClassDataProviderForFileFacade constructor( } +class LightClassDataProviderForScript(private val script: KtScript) : CachedValueProvider { + private fun computeLightClassData(): LightClassDataHolder.ForScript { + return LightClassGenerationSupport.getInstance(script.project).createDataHolderForScript(script) { + constructionContext -> + buildLightClass( + script.fqName.parent(), + listOf(script.containingKtFile), + ClassFilterForScript(script), + constructionContext + ) generate@ { + state, files -> + val scriptFile = files.first() + val codegen = state.factory.forPackage(scriptFile.packageFqName, files) + codegen.generate(CompilationErrorHandler.THROW_EXCEPTION) + state.factory.done() + } + } + } + + override fun compute(): CachedValueProvider.Result? = + CachedValueProvider.Result.create(computeLightClassData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) + + override fun toString(): String = this::class.java.name + " for ${script.fqName}" +} + interface StubComputationTracker { fun onStubComputed(javaFileStub: PsiJavaFileStub, context: LightClassConstructionContext) } @@ -181,3 +206,17 @@ object ClassFilterForFacade : GenerationState.GenerateClassFilter() { override fun shouldGeneratePackagePart(ktFile: KtFile) = true override fun shouldGenerateScript(script: KtScript) = false } + +private class ClassFilterForScript(val script: KtScript) : GenerationState.GenerateClassFilter() { + override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean = + shouldGenerateClass(processingClassOrObject) + + override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean = + processingClassOrObject.isAncestor(script, true) + + override fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject): Boolean = true + + override fun shouldGeneratePackagePart(ktFile: KtFile): Boolean = script.containingKtFile === ktFile + + override fun shouldGenerateScript(script: KtScript): Boolean = this.script === script +} 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 new file mode 100644 index 00000000000..0d6729185ae --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForScript.kt @@ -0,0 +1,161 @@ +/* + * 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. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.intellij.openapi.util.Comparing +import com.intellij.openapi.util.Key +import com.intellij.psi.* +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.CachedValuesManager +import org.jetbrains.annotations.NonNls +import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder +import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForScript +import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass +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.KtScript +import javax.swing.Icon + +class KtLightClassForScript private constructor( + val script: KtScript, + private val lightClassDataCache: CachedValue +) : KtLazyLightClass(script.manager) { + + private val hashCode: Int = computeHashCode() + + private val packageFqName: FqName = script.fqName.parent() + + private val modifierList: PsiModifierList = LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC) + + private val implementsList: LightEmptyImplementsList = LightEmptyImplementsList(manager) + + private val _containingFile by lazyPub { + FakeFileForLightClass( + script.containingKtFile, + lightClass = { this }, + stub = { lightClassDataCache.value.javaFileStub }, + packageFqName = packageFqName) + } + + override val kotlinOrigin: KtClassOrObject? get() = null + + val fqName: FqName = script.fqName + + override fun getModifierList() = modifierList + + override fun hasModifierProperty(@NonNls name: String) = modifierList.hasModifierProperty(name) + + override fun isDeprecated() = false + + override fun isInterface() = false + + override fun isAnnotationType() = false + + override fun isEnum() = false + + override fun getContainingClass() = null + + override fun getContainingFile() = _containingFile + + override fun hasTypeParameters() = false + + override fun getTypeParameters(): Array = PsiTypeParameter.EMPTY_ARRAY + + override fun getTypeParameterList() = null + + override fun getDocComment() = null + + override fun getImplementsList() = 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) } + } + + override fun getInitializers(): Array = PsiClassInitializer.EMPTY_ARRAY + + override fun getName() = script.fqName.shortName().asString() + + override fun getQualifiedName() = script.fqName.asString() + + override fun isValid() = script.isValid + + override fun copy() = KtLightClassForScript(script, lightClassDataCache) + + override val lightClassData = lightClassDataCache.value.findDataForScript(script.fqName) + + override fun getNavigationElement() = script + + override fun isEquivalentTo(another: PsiElement?): Boolean = + another is PsiClass && Comparing.equal(another.qualifiedName, qualifiedName) + + override fun getElementIcon(flags: Int): Icon? = throw UnsupportedOperationException("This should be done by JetIconProvider") + + override fun hashCode() = hashCode + + private fun computeHashCode(): Int { + var result = manager.hashCode() + result = 31 * result + script.hashCode() + return result + } + + override fun equals(other: Any?): Boolean { + if (other == null || this::class.java != other::class.java) { + return false + } + + val lightClass = other as KtLightClassForScript + if (this === other) return true + + if (this.hashCode != lightClass.hashCode) return false + if (manager != lightClass.manager) return false + if (script != lightClass.script) return false + + return true + } + + override fun toString() = "${KtLightClassForScript::class.java.simpleName}:${script.fqName}" + + companion object { + + private val JAVA_API_STUB_FOR_SCRIPT = Key.create>("JAVA_API_STUB_FOR_SCRIPT") + + fun create(script: KtScript): KtLightClassForScript = KtLightClassForScript(script, getLightClassCachedValue(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) } + } + + private fun createCachedValueForScript(script: KtScript): CachedValue = + 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/KtLightClassForSourceDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt index 9598f5ceac6..07aa00d3c6b 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt @@ -39,10 +39,7 @@ import org.jetbrains.kotlin.asJava.ImpreciseResolveResult import org.jetbrains.kotlin.asJava.ImpreciseResolveResult.UNSURE import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.LightClassUtil -import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder -import org.jetbrains.kotlin.asJava.builder.LightClassData -import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder -import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForClassOrObject +import org.jetbrains.kotlin.asJava.builder.* import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier import org.jetbrains.kotlin.asJava.elements.KtLightModifierList @@ -334,7 +331,7 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC fun create(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? { - if (classOrObject.containingKtFile.isScript() || classOrObject.hasModifier(KtTokens.HEADER_KEYWORD)) { + if (classOrObject.hasModifier(KtTokens.HEADER_KEYWORD)) { return null } @@ -366,10 +363,11 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC } fun getLightClassDataHolder(classOrObject: KtClassOrObject): LightClassDataHolder.ForClass { - return getLightClassCachedValue(classOrObject).value + return classOrObject.containingKtFile.script?.let { KtLightClassForScript.getLightClassCachedValue(it).value } ?: + getLightClassCachedValue(classOrObject).value } - fun getLightClassCachedValue(classOrObject: KtClassOrObject): CachedValue { + private fun getLightClassCachedValue(classOrObject: KtClassOrObject): CachedValue { var value = getOutermostClassOrObject(classOrObject).getUserData(JAVA_API_STUB) // stub computed for outer class can be used for inner/nested ?: classOrObject.getUserData(JAVA_API_STUB) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.java b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.java index 530941dfdd2..072669c48b3 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.java +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/finder/JavaElementFinder.java @@ -33,10 +33,7 @@ import org.jetbrains.kotlin.asJava.LightClassGenerationSupport; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqNamesUtilKt; -import org.jetbrains.kotlin.psi.KtClass; -import org.jetbrains.kotlin.psi.KtClassOrObject; -import org.jetbrains.kotlin.psi.KtEnumEntry; -import org.jetbrains.kotlin.psi.KtFile; +import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.jvm.KotlinFinderMarker; import java.util.Collection; @@ -90,7 +87,6 @@ public class JavaElementFinder extends PsiElementFinder implements KotlinFinderM FqName qualifiedName = new FqName(qualifiedNameString); findClassesAndObjects(qualifiedName, scope, answer); - answer.addAll(lightClassGenerationSupport.getFacadeClasses(qualifiedName, scope)); answer.addAll(lightClassGenerationSupport.getKotlinInternalClasses(qualifiedName, scope)); diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt index 09b13bccfd8..9466b7a96e0 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt @@ -20,6 +20,7 @@ import com.intellij.psi.* import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade +import org.jetbrains.kotlin.asJava.classes.KtLightClassForScript import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry import org.jetbrains.kotlin.asJava.elements.KtLightElement import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier @@ -52,6 +53,8 @@ fun KtFile.findFacadeClass(): KtLightClass? { .firstOrNull { it is KtLightClassForFacade && this in it.files } as? KtLightClass } +fun KtScript.toLightClass(): KtLightClassForScript? = LightClassGenerationSupport.getInstance(project).getLightClassForScript(this) + fun KtElement.toLightElements(): List = when (this) { is KtClassOrObject -> listOfNotNull(toLightClass()) diff --git a/compiler/testData/asJava/lightClasses/script/HelloWorld.java b/compiler/testData/asJava/lightClasses/script/HelloWorld.java new file mode 100644 index 00000000000..4535105e778 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/script/HelloWorld.java @@ -0,0 +1,3 @@ +public class HelloWorld extends kotlin.script.templates.standard.ScriptTemplateWithArgs { + public HelloWorld(java.lang.String[] p) { /* compiled code */ } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/script/HelloWorld.kts b/compiler/testData/asJava/lightClasses/script/HelloWorld.kts new file mode 100644 index 00000000000..dc1115e5f26 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/script/HelloWorld.kts @@ -0,0 +1,3 @@ +// HelloWorld + +println("Hello world!") \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/script/InnerClasses.java b/compiler/testData/asJava/lightClasses/script/InnerClasses.java new file mode 100644 index 00000000000..88edae1b5e0 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/script/InnerClasses.java @@ -0,0 +1,22 @@ +public class InnerClasses extends kotlin.script.templates.standard.ScriptTemplateWithArgs { + public InnerClasses(java.lang.String[] p) { /* compiled code */ } + + public static final class Bar { + private final int b = 0; + private final int a; + + public final int getB() { /* compiled code */ } + + public final int getAPlusB() { /* compiled code */ } + + public final int getA() { /* compiled code */ } + + public Bar(int a) { /* compiled code */ } + + public static final class Baz { + public final void doSomething() { /* compiled code */ } + + public Baz() { /* compiled code */ } + } + } +} diff --git a/compiler/testData/asJava/lightClasses/script/InnerClasses.kts b/compiler/testData/asJava/lightClasses/script/InnerClasses.kts new file mode 100644 index 00000000000..032168916f5 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/script/InnerClasses.kts @@ -0,0 +1,13 @@ +// InnerClasses + +class Bar(val a: Int) { + val b: Int = 0 + + fun getAPlusB() = a + b + + class Baz { + fun doSomething() { + + } + } +} \ No newline at end of file diff --git a/compiler/tests-common/org/jetbrains/kotlin/asJava/LightClassTestCommon.kt b/compiler/tests-common/org/jetbrains/kotlin/asJava/LightClassTestCommon.kt index c319b13e148..8ba81ecde41 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/asJava/LightClassTestCommon.kt +++ b/compiler/tests-common/org/jetbrains/kotlin/asJava/LightClassTestCommon.kt @@ -33,7 +33,7 @@ object LightClassTestCommon { expectedFile: File, testDataFile: File, findLightClass: (String) -> PsiClass?, - normalizeText: (String) -> String = { it } + normalizeText: (String) -> String ) { val text = FileUtil.loadFile(testDataFile, true) val matcher = SUBJECT_FQ_NAME_PATTERN.matcher(text) @@ -57,8 +57,8 @@ object LightClassTestCommon { val buffer = StringBuilder() (delegate as ClsElementImpl).appendMirrorText(0, buffer) - val actual = normalizeText(buffer.toString()) - return actual + + return normalizeText(buffer.toString()) } // Actual text for light class is generated with ClsElementImpl.appendMirrorText() that can find empty DefaultImpl inner class in stubs diff --git a/compiler/tests-common/org/jetbrains/kotlin/checkers/KotlinMultiFileTestWithJava.java b/compiler/tests-common/org/jetbrains/kotlin/checkers/KotlinMultiFileTestWithJava.java index 751aba0c1b0..895270b059d 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/checkers/KotlinMultiFileTestWithJava.java +++ b/compiler/tests-common/org/jetbrains/kotlin/checkers/KotlinMultiFileTestWithJava.java @@ -81,7 +81,7 @@ public abstract class KotlinMultiFileTestWithJava extends KtUsefulTestCase CollectionsKt.plus(Collections.singletonList(KotlinTestUtils.getAnnotationsJar()), getExtraClasspath()), isJavaSourceRootNeeded() ? Collections.singletonList(javaFilesDir) : Collections.emptyList() ); - configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition.INSTANCE); + configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition.INSTANCE); if (isKotlinSourceRootNeeded()) { ContentRootsKt.addKotlinSourceRoot(configuration, kotlinSourceRoot.getPath()); } @@ -157,7 +157,7 @@ public abstract class KotlinMultiFileTestWithJava extends KtUsefulTestCase writeSourceFile(fileName, text, javaFilesDir); } - if (fileName.endsWith(".kt") && kotlinSourceRoot != null) { + if ((fileName.endsWith(".kt") || fileName.endsWith(".kts")) && kotlinSourceRoot != null) { writeSourceFile(fileName, text, kotlinSourceRoot); } diff --git a/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java b/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java index 9f9ba2a03be..05a3c78c064 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java +++ b/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java @@ -563,7 +563,7 @@ public class KotlinTestUtils { else { //noinspection ConstantConditions for (File childFile : file.listFiles()) { - if (childFile.getName().endsWith(".kt")) { + if (childFile.getName().endsWith(".kt") || childFile.getName().endsWith(".kts")) { ktFiles.add(loadJetFile(environment.getProject(), childFile)); } } diff --git a/compiler/tests/org/jetbrains/kotlin/asJava/AbstractCompilerLightClassTest.kt b/compiler/tests/org/jetbrains/kotlin/asJava/AbstractCompilerLightClassTest.kt index ca038a8fc68..807284a0a96 100644 --- a/compiler/tests/org/jetbrains/kotlin/asJava/AbstractCompilerLightClassTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/asJava/AbstractCompilerLightClassTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * 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. @@ -14,63 +14,50 @@ * limitations under the License. */ -package org.jetbrains.kotlin.asJava; +package org.jetbrains.kotlin.asJava -import com.intellij.psi.search.GlobalSearchScope; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.asJava.finder.JavaElementFinder; -import org.jetbrains.kotlin.checkers.KotlinMultiFileTestWithJava; -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; -import org.jetbrains.kotlin.test.ConfigurationKind; -import org.jetbrains.kotlin.test.KotlinTestUtils; -import org.jetbrains.kotlin.utils.ExceptionUtilsKt; +import com.intellij.psi.PsiClass +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.asJava.finder.JavaElementFinder +import org.jetbrains.kotlin.checkers.KotlinMultiFileTestWithJava +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.test.ConfigurationKind +import org.jetbrains.kotlin.test.KotlinTestUtils +import java.io.File -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.Map; +abstract class AbstractCompilerLightClassTest : KotlinMultiFileTestWithJava() { + override fun getConfigurationKind(): ConfigurationKind = ConfigurationKind.ALL -public abstract class AbstractCompilerLightClassTest extends KotlinMultiFileTestWithJava { - @NotNull - @Override - protected ConfigurationKind getConfigurationKind() { - return ConfigurationKind.ALL; + override fun isKotlinSourceRootNeeded(): Boolean = true + + override fun doMultiFileTest(file: File, modules: MutableMap, files: MutableList) { + val environment = createEnvironment(file) + val expectedFile = KotlinTestUtils.replaceExtension(file, "java") + LightClassTestCommon.testLightClass( + expectedFile, + file, + { fqname -> findLightClass(environment, fqname) }, + LightClassTestCommon::removeEmptyDefaultImpls + ) } - @Override - protected boolean isKotlinSourceRootNeeded() { - return true; - } + override fun createTestModule(name: String): Void? = null - @NotNull - public static JavaElementFinder createFinder(@NotNull KotlinCoreEnvironment environment) throws IOException { - // We need to resolve all the files in order too fill in the trace that sits inside LightClassGenerationSupport - KotlinTestUtils.resolveAllKotlinFiles(environment); + override fun createTestFile(module: Void?, fileName: String, text: String, directives: Map): Void? = null - return JavaElementFinder.getInstance(environment.getProject()); - } + companion object { + fun findLightClass(environment: KotlinCoreEnvironment, fqname: String): PsiClass? { + KotlinTestUtils.resolveAllKotlinFiles(environment) - @Override - protected void doMultiFileTest(File file, Map modules, List files) throws IOException { - KotlinCoreEnvironment environment = createEnvironment(file); - File expectedFile = KotlinTestUtils.replaceExtension(file, "java"); - LightClassTestCommon.INSTANCE.testLightClass(expectedFile, file, s -> { - try { - return createFinder(environment).findClass(s, GlobalSearchScope.allScope(environment.getProject())); - } - catch (IOException e) { - throw ExceptionUtilsKt.rethrow(e); - } - }, LightClassTestCommon.INSTANCE::removeEmptyDefaultImpls); - } + val lightCLassForScript = LightClassGenerationSupport + .getInstance(environment.project) + .getScriptClasses(FqName(fqname), GlobalSearchScope.allScope(environment.project)) + .firstOrNull() - @Override - protected Void createTestModule(@NotNull String name) { - return null; - } - - @Override - protected Void createTestFile(Void module, String fileName, String text, Map directives) { - return null; + return lightCLassForScript ?: JavaElementFinder + .getInstance(environment.project) + .findClass(fqname, GlobalSearchScope.allScope(environment.project)) + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java index fa4bea1dbd5..65aa7c5e94a 100644 --- a/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java @@ -33,7 +33,7 @@ import java.util.regex.Pattern; @RunWith(JUnit3RunnerWithInners.class) public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassTest { public void testAllFilesPresentInLightClasses() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true, "local", "ideRegression"); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true, "local", "ideRegression"); } @TestMetadata("AnnotationClass.kt") @@ -155,7 +155,7 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT @RunWith(JUnit3RunnerWithInners.class) public static class CompilationErrors extends AbstractCompilerLightClassTest { public void testAllFilesPresentInCompilationErrors() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/compilationErrors"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/compilationErrors"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("AnnotationModifiers.kt") @@ -206,7 +206,7 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT @RunWith(JUnit3RunnerWithInners.class) public static class Delegation extends AbstractCompilerLightClassTest { public void testAllFilesPresentInDelegation() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/delegation"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/delegation"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("Function.kt") @@ -220,12 +220,6 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/delegation/Property.kt"); doTest(fileName); } - - @TestMetadata("WithPlatformTypes.NoCompile.kt") - public void testWithPlatformTypes_NoCompile() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.NoCompile.kt"); - doTest(fileName); - } } @TestMetadata("compiler/testData/asJava/lightClasses/facades") @@ -233,13 +227,7 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT @RunWith(JUnit3RunnerWithInners.class) public static class Facades extends AbstractCompilerLightClassTest { public void testAllFilesPresentInFacades() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/facades"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); - } - - @TestMetadata("EmptyFile.NoCompile.kt") - public void testEmptyFile_NoCompile() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/facades/EmptyFile.NoCompile.kt"); - doTest(fileName); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/facades"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("MultiFile.kt") @@ -266,7 +254,7 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT @RunWith(JUnit3RunnerWithInners.class) public static class NullabilityAnnotations extends AbstractCompilerLightClassTest { public void testAllFilesPresentInNullabilityAnnotations() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/nullabilityAnnotations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/nullabilityAnnotations"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("Class.kt") @@ -383,7 +371,7 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT @RunWith(JUnit3RunnerWithInners.class) public static class Object extends AbstractCompilerLightClassTest { public void testAllFilesPresentInObject() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/object"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/object"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("SimpleObject.kt") @@ -398,7 +386,7 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT @RunWith(JUnit3RunnerWithInners.class) public static class PublicField extends AbstractCompilerLightClassTest { public void testAllFilesPresentInPublicField() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/publicField"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/publicField"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("CompanionObject.kt") @@ -413,4 +401,25 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT doTest(fileName); } } + + @TestMetadata("compiler/testData/asJava/lightClasses/script") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Script extends AbstractCompilerLightClassTest { + public void testAllFilesPresentInScript() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/script"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("HelloWorld.kts") + public void testHelloWorld() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/script/HelloWorld.kts"); + doTest(fileName); + } + + @TestMetadata("InnerClasses.kts") + public void testInnerClasses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/script/InnerClasses.kts"); + doTest(fileName); + } + } } diff --git a/compiler/tests/org/jetbrains/kotlin/asJava/KotlinAsJavaTestBase.java b/compiler/tests/org/jetbrains/kotlin/asJava/KotlinAsJavaTestBase.java index 644ec6fdffa..2321feff0e8 100644 --- a/compiler/tests/org/jetbrains/kotlin/asJava/KotlinAsJavaTestBase.java +++ b/compiler/tests/org/jetbrains/kotlin/asJava/KotlinAsJavaTestBase.java @@ -54,8 +54,9 @@ public abstract class KotlinAsJavaTestBase extends KotlinTestWithEnvironment { @Override protected void setUp() throws Exception { super.setUp(); - - finder = AbstractCompilerLightClassTest.createFinder(getEnvironment()); + KotlinCoreEnvironment environment = getEnvironment(); + KotlinTestUtils.resolveAllKotlinFiles(environment); + finder = JavaElementFinder.getInstance(environment.getProject()); } @Override diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 632db2c572c..fa30190ca31 100755 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -197,6 +197,8 @@ import java.util.* import java.util.regex.Pattern @Language("RegExp") private val KT_OR_KTS = """^(.+)\.(kt|kts)$""" +@Language("RegExp") private val KT_OR_KTS_WITHOUT_DOTS_IN_NAME = """^([^.]+)\.(kt|kts)$""" + @Language("RegExp") private val KT_WITHOUT_DOTS_IN_NAME = """^([^.]+)\.kt$""" fun main(args: Array) { @@ -467,7 +469,7 @@ fun main(args: Array) { } testClass { - model("asJava/lightClasses", excludeDirs = listOf("local", "ideRegression")) + model("asJava/lightClasses", excludeDirs = listOf("local", "ideRegression"), pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME) } testClass { @@ -1129,11 +1131,11 @@ fun main(args: Array) { } testClass { - model("asJava/lightClasses", excludeDirs = listOf("delegation"), pattern = KT_WITHOUT_DOTS_IN_NAME) + model("asJava/lightClasses", excludeDirs = listOf("delegation"), pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME) } testClass { - model("asJava/lightClasses", excludeDirs = listOf("local", "compilationErrors", "ideRegression"), pattern = KT_WITHOUT_DOTS_IN_NAME) + model("asJava/lightClasses", excludeDirs = listOf("local", "compilationErrors", "ideRegression"), pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME) } } 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 42fd7af1d12..7ba33ee9e69 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 @@ -27,10 +27,7 @@ import org.jetbrains.kotlin.asJava.LightClassBuilder import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.builder.ClsWrapperStubPsiFactory import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder -import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage -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.asJava.classes.* import org.jetbrains.kotlin.asJava.finder.JavaElementFinder import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil @@ -84,6 +81,14 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG ) } + override fun createDataHolderForScript(script: KtScript, builder: LightClassBuilder): LightClassDataHolder.ForScript { + return LazyLightClassDataHolder.ForScript( + builder, + exactContextProvider = { IDELightClassContexts.contextForScript(script) }, + dummyContextProvider = { IDELightClassContexts.lightContextForScript(script) } + ) + } + override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection { return runReadAction { KotlinFullClassNameIndex.getInstance().get(fqName.asString(), project, sourceAndClassFiles(searchScope, project)) @@ -131,6 +136,8 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG return null } + override fun getLightClassForScript(script: KtScript): KtLightClassForScript? = KtLightClassForScript.create(script) + private fun withFakeLightClasses( lightClassForFacade: KtLightClassForFacade?, facadeFiles: List @@ -155,6 +162,12 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG } } + override fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection { + return KotlinScriptFqnIndex.instance.get(scriptFqName.asString(), project, scope).mapNotNull { + getLightClassForScript(it) + } + } + override fun getKotlinInternalClasses(fqName: FqName, scope: GlobalSearchScope): Collection { if (fqName.isRoot) return emptyList() diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/IDELightClassContexts.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/IDELightClassContexts.kt index 3b542eefaac..d6c182fcb96 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/IDELightClassContexts.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/IDELightClassContexts.kt @@ -129,6 +129,21 @@ object IDELightClassContexts { return IDELightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor, EXACT) } + fun contextForScript(script: KtScript): LightClassConstructionContext { + val resolutionFacade = script.getResolutionFacade() + val bindingContext = resolutionFacade.analyze(script) + + val descriptor = bindingContext[BindingContext.SCRIPT, script] + if (descriptor == null) { + LOG.warn("No script descriptor in context for script: " + script.getElementTextWithContext()) + return IDELightClassConstructionContext(bindingContext, resolutionFacade.moduleDescriptor, EXACT) + } + + ForceResolveUtil.forceResolveAllContents(descriptor) + + return IDELightClassConstructionContext(bindingContext, resolutionFacade.moduleDescriptor, EXACT) + } + fun lightContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext? { if (!isDummyResolveApplicable(classOrObject)) return null @@ -139,6 +154,26 @@ object IDELightClassContexts { return IDELightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor, LIGHT) } + fun lightContextForFacade(files: List): LightClassConstructionContext { + val representativeFile = files.first() + val resolveSession = setupAdHocResolve(representativeFile.project, representativeFile.getResolutionFacade().moduleDescriptor, files) + + forceResolvePackageDeclarations(files, resolveSession) + + return IDELightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor, LIGHT) + } + + fun lightContextForScript(script: KtScript): LightClassConstructionContext { + val resolveSession = setupAdHocResolve( + script.project, + script.getResolutionFacade().moduleDescriptor, + listOf(script.containingKtFile)) + + ForceResolveUtil.forceResolveAllContents(resolveSession.resolveToDescriptor(script)) + + return IDELightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor, LIGHT) + } + private fun isDummyResolveApplicable(classOrObject: KtClassOrObject): Boolean { if (classOrObject.hasLightClassMatchingErrors) return false @@ -193,15 +228,6 @@ object IDELightClassContexts { return result } - fun lightContextForFacade(files: List): LightClassConstructionContext { - val representativeFile = files.first() - val resolveSession = setupAdHocResolve(representativeFile.project, representativeFile.getResolutionFacade().moduleDescriptor, files) - - forceResolvePackageDeclarations(files, resolveSession) - - return IDELightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor, LIGHT) - } - fun forceResolvePackageDeclarations(files: Collection, session: ResolveSession) { for (file in files) { if (file.isScript()) continue diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/LazyLightClassDataHolder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/LazyLightClassDataHolder.kt index efe50a02e69..d28e49eafd6 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/LazyLightClassDataHolder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/LazyLightClassDataHolder.kt @@ -74,6 +74,10 @@ sealed class LazyLightClassDataHolder( builder: LightClassBuilder, exactContextProvider: ExactLightClassContextProvider, dummyContextProvider: DummyLightClassContextProvider ) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForFacade + class ForScript( + builder: LightClassBuilder, exactContextProvider: ExactLightClassContextProvider, dummyContextProvider: DummyLightClassContextProvider + ) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForScript + private inner class LazyLightClassData( findDelegate: (LightClassBuilderResult) -> PsiClass ) : LightClassData { diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt index 78c35de3af2..df9b622e593 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt @@ -32,6 +32,7 @@ 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.asJava.elements.* +import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.idea.KotlinDaemonAnalyzerTestCase import org.jetbrains.kotlin.idea.caches.resolve.LightClassLazinessChecker.Tracker.Level.* import org.jetbrains.kotlin.idea.caches.resolve.lightClasses.IDELightClassConstructionContext @@ -53,9 +54,13 @@ import kotlin.test.assertTrue abstract class AbstractIdeLightClassTest : KotlinLightCodeInsightFixtureTestCase() { fun doTest(testDataPath: String) { - val extraFilePath = testDataPath.replace(".kt", ".extra.kt") - val testFiles = if (File(extraFilePath).isFile) listOf(testDataPath, extraFilePath) else listOf(testDataPath) + val extraFilePath = when { + testDataPath.endsWith(".kt") -> testDataPath.replace(".kt", ".extra.kt") + testDataPath.endsWith(".kts") -> testDataPath.replace(".kts", ".extra.kts") + else -> error("Invalid test data extension") + } + val testFiles = if (File(extraFilePath).isFile) listOf(testDataPath, extraFilePath) else listOf(testDataPath) val lazinessMode = lazinessModeByFileText(testDataPath) myFixture.configureByFiles(*testFiles.toTypedArray()) @@ -91,11 +96,13 @@ abstract class AbstractIdeCompiledLightClassTest : KotlinDaemonAnalyzerTestCase( val testName = getTestName(false) if (KotlinTestUtils.isAllFilesPresentTest(testName)) return - val filePath = "${KotlinTestUtils.getTestsRoot(this::class.java)}/${getTestName(false)}.kt" + val filePathWithoutExtension = "${KotlinTestUtils.getTestsRoot(this::class.java)}/${getTestName(false)}" + val testFile = File("$filePathWithoutExtension.kt").takeIf { it.exists() } ?: + File("$filePathWithoutExtension.kts").takeIf { it.exists() } - Assert.assertTrue("File doesn't exist $filePath", File(filePath).exists()) + Assert.assertNotNull("Test file not found!", testFile) - val libraryJar = MockLibraryUtil.compileJvmLibraryToJar(filePath, libName()) + val libraryJar = MockLibraryUtil.compileJvmLibraryToJar(testFile!!.canonicalPath, libName()) val jarUrl = "jar://" + FileUtilRt.toSystemIndependentName(libraryJar.absolutePath) + "!/" ModuleRootModificationUtil.addModuleLibrary(module, jarUrl) } @@ -128,6 +135,7 @@ private fun testLightClass(expected: File, testData: File, normalize: (String) - .replace("java.lang.String s1", "java.lang.String p1") .replace("java.lang.String s2", "java.lang.String p2") .replace("java.lang.Object o)", "java.lang.Object p)") + .replace("java.lang.String[] strings", "java.lang.String[] p") .removeLinesStartingWith("@" + JvmAnnotationNames.METADATA_FQ_NAME.asString()) .run(normalize) } @@ -135,6 +143,10 @@ private fun testLightClass(expected: File, testData: File, normalize: (String) - } private fun findClass(fqName: String, ktFile: KtFile?, project: Project): PsiClass? { + ktFile?.script?.let { + return it.toLightClass() + } + return JavaPsiFacade.getInstance(project).findClass(fqName, GlobalSearchScope.allScope(project)) ?: PsiTreeUtil.findChildrenOfType(ktFile, KtClassOrObject::class.java) .find { fqName.endsWith(it.nameAsName!!.asString()) } diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java index 0a6c0a0853a..2ef24284324 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java @@ -33,7 +33,7 @@ import java.util.regex.Pattern; @RunWith(JUnit3RunnerWithInners.class) public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLightClassTest { public void testAllFilesPresentInLightClasses() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true, "local", "compilationErrors", "ideRegression"); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true, "local", "compilationErrors", "ideRegression"); } @TestMetadata("AnnotationClass.kt") @@ -155,7 +155,7 @@ public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLight @RunWith(JUnit3RunnerWithInners.class) public static class Delegation extends AbstractIdeCompiledLightClassTest { public void testAllFilesPresentInDelegation() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/delegation"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/delegation"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("Function.kt") @@ -176,7 +176,7 @@ public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLight @RunWith(JUnit3RunnerWithInners.class) public static class Facades extends AbstractIdeCompiledLightClassTest { public void testAllFilesPresentInFacades() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/facades"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/facades"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("MultiFile.kt") @@ -203,7 +203,7 @@ public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLight @RunWith(JUnit3RunnerWithInners.class) public static class NullabilityAnnotations extends AbstractIdeCompiledLightClassTest { public void testAllFilesPresentInNullabilityAnnotations() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/nullabilityAnnotations"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/nullabilityAnnotations"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("Class.kt") @@ -320,7 +320,7 @@ public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLight @RunWith(JUnit3RunnerWithInners.class) public static class Object extends AbstractIdeCompiledLightClassTest { public void testAllFilesPresentInObject() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/object"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/object"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("SimpleObject.kt") @@ -335,7 +335,7 @@ public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLight @RunWith(JUnit3RunnerWithInners.class) public static class PublicField extends AbstractIdeCompiledLightClassTest { public void testAllFilesPresentInPublicField() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/publicField"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/publicField"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("CompanionObject.kt") @@ -350,4 +350,25 @@ public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLight doTest(fileName); } } + + @TestMetadata("compiler/testData/asJava/lightClasses/script") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Script extends AbstractIdeCompiledLightClassTest { + public void testAllFilesPresentInScript() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/script"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("HelloWorld.kts") + public void testHelloWorld() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/script/HelloWorld.kts"); + doTest(fileName); + } + + @TestMetadata("InnerClasses.kts") + public void testInnerClasses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/script/InnerClasses.kts"); + doTest(fileName); + } + } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java index 3064c928bb6..99dd5ead8cc 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java @@ -33,7 +33,7 @@ import java.util.regex.Pattern; @RunWith(JUnit3RunnerWithInners.class) public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { public void testAllFilesPresentInLightClasses() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true, "delegation"); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true, "delegation"); } @TestMetadata("AnnotationClass.kt") @@ -155,7 +155,7 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { @RunWith(JUnit3RunnerWithInners.class) public static class CompilationErrors extends AbstractIdeLightClassTest { public void testAllFilesPresentInCompilationErrors() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/compilationErrors"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/compilationErrors"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("AnnotationModifiers.kt") @@ -206,7 +206,7 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { @RunWith(JUnit3RunnerWithInners.class) public static class Facades extends AbstractIdeLightClassTest { public void testAllFilesPresentInFacades() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/facades"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/facades"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("MultiFile.kt") @@ -233,7 +233,7 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { @RunWith(JUnit3RunnerWithInners.class) public static class IdeRegression extends AbstractIdeLightClassTest { public void testAllFilesPresentInIdeRegression() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/ideRegression"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/ideRegression"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("AllOpenAnnotatedClasses.kt") @@ -290,7 +290,7 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { @RunWith(JUnit3RunnerWithInners.class) public static class Local extends AbstractIdeLightClassTest { public void testAllFilesPresentInLocal() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/local"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/local"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("DollarsInNameLocal.kt") @@ -305,7 +305,7 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { @RunWith(JUnit3RunnerWithInners.class) public static class NullabilityAnnotations extends AbstractIdeLightClassTest { public void testAllFilesPresentInNullabilityAnnotations() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/nullabilityAnnotations"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/nullabilityAnnotations"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("Class.kt") @@ -422,7 +422,7 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { @RunWith(JUnit3RunnerWithInners.class) public static class Object extends AbstractIdeLightClassTest { public void testAllFilesPresentInObject() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/object"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/object"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("SimpleObject.kt") @@ -437,7 +437,7 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { @RunWith(JUnit3RunnerWithInners.class) public static class PublicField extends AbstractIdeLightClassTest { public void testAllFilesPresentInPublicField() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/publicField"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/publicField"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); } @TestMetadata("CompanionObject.kt") @@ -452,4 +452,25 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { doTest(fileName); } } + + @TestMetadata("compiler/testData/asJava/lightClasses/script") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Script extends AbstractIdeLightClassTest { + public void testAllFilesPresentInScript() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/script"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("HelloWorld.kts") + public void testHelloWorld() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/script/HelloWorld.kts"); + doTest(fileName); + } + + @TestMetadata("InnerClasses.kts") + public void testInnerClasses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/script/InnerClasses.kts"); + doTest(fileName); + } + } }