Allow to turn the first parameter of a SAM-converted lambda into the receiver (KT-12848)

This commit is contained in:
Yan Zhulanow
2016-12-06 20:03:27 +03:00
parent fc8cc217dc
commit cbef0250aa
57 changed files with 935 additions and 148 deletions
+107 -101
View File
@@ -1,103 +1,109 @@
<component name="ArtifactManager">
<artifact name="KotlinPlugin">
<output-path>$PROJECT_DIR$/out/artifacts/Kotlin</output-path>
<properties id="ant-postprocessing">
<options enabled="true">
<file>file://$PROJECT_DIR$/idea-runner/runner.xml</file>
<target>copy-runtime-for-idea-plugin</target>
</options>
</properties>
<root id="root">
<element id="directory" name="lib">
<element id="archive" name="kotlin-plugin.jar">
<element id="module-output" name="backend" />
<element id="module-output" name="frontend" />
<element id="module-output" name="descriptors" />
<element id="module-output" name="frontend.java" />
<element id="module-output" name="descriptor.loader.java" />
<element id="module-output" name="idea" />
<element id="module-output" name="light-classes" />
<element id="module-output" name="util" />
<element id="module-output" name="util.runtime" />
<element id="module-output" name="j2k" />
<element id="module-output" name="js.frontend" />
<element id="module-output" name="js.parser" />
<element id="module-output" name="cli-common" />
<element id="module-output" name="idea-jps-common" />
<element id="module-output" name="preloader" />
<element id="module-output" name="deserialization" />
<element id="module-output" name="backend-common" />
<element id="library" level="project" name="builtins" />
<element id="module-output" name="js.dart-ast" />
<element id="directory" name="kotlin">
<element id="dir-copy" path="$PROJECT_DIR$/core/builtins/native/kotlin" />
<element id="dir-copy" path="$PROJECT_DIR$/core/builtins/src/kotlin" />
</element>
<element id="module-output" name="eval4j" />
<element id="module-output" name="idea-analysis" />
<element id="module-output" name="ide-common" />
<element id="file-copy" path="$PROJECT_DIR$/resources/kotlinManifest.properties" />
<element id="module-output" name="idea-android" />
<element id="module-output" name="idea-android-output-parser" />
<element id="module-output" name="js.serializer" />
<element id="module-output" name="serialization" />
<element id="module-output" name="idea-completion" />
<element id="module-output" name="idea-core" />
<element id="module-output" name="container" />
<element id="module-output" name="daemon-common" />
<element id="module-output" name="idea-repl" />
<element id="module-output" name="idea-live-templates" />
<element id="module-output" name="resolution" />
<element id="module-output" name="plugin-api" />
<element id="module-output" name="idea-ultimate" />
<element id="module-output" name="formatter" />
<element id="module-output" name="idea-maven" />
<element id="extracted-dir" path="$PROJECT_DIR$/dependencies/protobuf-2.6.1.jar" path-in-jar="/" />
<element id="module-output" name="backend.common" />
<element id="module-output" name="ir.tree" />
<element id="module-output" name="backend.jvm" />
<element id="module-output" name="ir.psi2ir" />
<element id="module-output" name="annotation-based-compiler-plugins-ide-support" />
</element>
<element id="library" level="project" name="javax.inject" />
<element id="directory" name="jps">
<element id="artifact" artifact-name="KotlinJpsPlugin" />
</element>
<element id="library" level="project" name="markdown" />
<element id="archive" name="kotlin-android-extensions-plugin.jar">
<element id="module-output" name="android-extensions-idea" />
</element>
<element id="archive" name="kotlin-android-extensions-compiler-plugin.jar">
<element id="module-output" name="android-extensions-compiler" />
</element>
<element id="archive" name="android-lint.jar">
<element id="module-output" name="uast-kotlin" />
<element id="module-output" name="lint-idea" />
<element id="module-output" name="uast-java" />
<element id="module-output" name="uast-common" />
<element id="module-output" name="lint-checks" />
<element id="library" level="project" name="guava" />
<element id="module-output" name="lint-api" />
<element id="module-output" name="uast-android" />
</element>
<element id="archive" name="allopen-ide-plugin.jar">
<element id="module-output" name="allopen-ide" />
</element>
<element id="archive" name="allopen-compiler-plugin.jar">
<element id="module-output" name="allopen-cli" />
</element>
<element id="archive" name="noarg-compiler-plugin.jar">
<element id="module-output" name="noarg-cli" />
</element>
<element id="archive" name="noarg-ide-plugin.jar">
<element id="module-output" name="noarg-ide" />
</element>
<element id="file-copy" path="$PROJECT_DIR$/dist/kotlinc/lib/kotlin-daemon-client.jar" />
<element id="file-copy" path="$PROJECT_DIR$/dist/kotlinc/lib/kotlin-script-runtime.jar" />
</element>
<element id="directory" name="kotlinc">
<element id="dir-copy" path="$PROJECT_DIR$/dist/kotlinc" />
</element>
</root>
</artifact>
<artifact name="KotlinPlugin">
<output-path>$PROJECT_DIR$/out/artifacts/Kotlin</output-path>
<properties id="ant-postprocessing">
<options enabled="true">
<file>file://$PROJECT_DIR$/idea-runner/runner.xml</file>
<target>copy-runtime-for-idea-plugin</target>
</options>
</properties>
<root id="root">
<element id="directory" name="lib">
<element id="archive" name="kotlin-plugin.jar">
<element id="module-output" name="backend" />
<element id="module-output" name="frontend" />
<element id="module-output" name="descriptors" />
<element id="module-output" name="frontend.java" />
<element id="module-output" name="descriptor.loader.java" />
<element id="module-output" name="idea" />
<element id="module-output" name="light-classes" />
<element id="module-output" name="util" />
<element id="module-output" name="util.runtime" />
<element id="module-output" name="j2k" />
<element id="module-output" name="js.frontend" />
<element id="module-output" name="js.parser" />
<element id="module-output" name="cli-common" />
<element id="module-output" name="idea-jps-common" />
<element id="module-output" name="preloader" />
<element id="module-output" name="deserialization" />
<element id="module-output" name="backend-common" />
<element id="library" level="project" name="builtins" />
<element id="module-output" name="js.dart-ast" />
<element id="directory" name="kotlin">
<element id="dir-copy" path="$PROJECT_DIR$/core/builtins/native/kotlin" />
<element id="dir-copy" path="$PROJECT_DIR$/core/builtins/src/kotlin" />
</element>
<element id="module-output" name="eval4j" />
<element id="module-output" name="idea-analysis" />
<element id="module-output" name="ide-common" />
<element id="file-copy" path="$PROJECT_DIR$/resources/kotlinManifest.properties" />
<element id="module-output" name="idea-android" />
<element id="module-output" name="idea-android-output-parser" />
<element id="module-output" name="js.serializer" />
<element id="module-output" name="serialization" />
<element id="module-output" name="idea-completion" />
<element id="module-output" name="idea-core" />
<element id="module-output" name="container" />
<element id="module-output" name="daemon-common" />
<element id="module-output" name="idea-repl" />
<element id="module-output" name="idea-live-templates" />
<element id="module-output" name="resolution" />
<element id="module-output" name="plugin-api" />
<element id="module-output" name="idea-ultimate" />
<element id="module-output" name="formatter" />
<element id="module-output" name="idea-maven" />
<element id="extracted-dir" path="$PROJECT_DIR$/dependencies/protobuf-2.6.1.jar" path-in-jar="/" />
<element id="module-output" name="backend.common" />
<element id="module-output" name="ir.tree" />
<element id="module-output" name="backend.jvm" />
<element id="module-output" name="ir.psi2ir" />
<element id="module-output" name="annotation-based-compiler-plugins-ide-support" />
</element>
<element id="library" level="project" name="javax.inject" />
<element id="directory" name="jps">
<element id="artifact" artifact-name="KotlinJpsPlugin" />
</element>
<element id="library" level="project" name="markdown" />
<element id="archive" name="kotlin-android-extensions-plugin.jar">
<element id="module-output" name="android-extensions-idea" />
</element>
<element id="archive" name="kotlin-android-extensions-compiler-plugin.jar">
<element id="module-output" name="android-extensions-compiler" />
</element>
<element id="archive" name="android-lint.jar">
<element id="module-output" name="uast-kotlin" />
<element id="module-output" name="lint-idea" />
<element id="module-output" name="uast-java" />
<element id="module-output" name="uast-common" />
<element id="module-output" name="lint-checks" />
<element id="library" level="project" name="guava" />
<element id="module-output" name="lint-api" />
<element id="module-output" name="uast-android" />
</element>
<element id="archive" name="allopen-ide-plugin.jar">
<element id="module-output" name="allopen-ide" />
</element>
<element id="archive" name="allopen-compiler-plugin.jar">
<element id="module-output" name="allopen-cli" />
</element>
<element id="archive" name="noarg-compiler-plugin.jar">
<element id="module-output" name="noarg-cli" />
</element>
<element id="archive" name="noarg-ide-plugin.jar">
<element id="module-output" name="noarg-ide" />
</element>
<element id="file-copy" path="$PROJECT_DIR$/dist/kotlinc/lib/kotlin-daemon-client.jar" />
<element id="file-copy" path="$PROJECT_DIR$/dist/kotlinc/lib/kotlin-script-runtime.jar" />
<element id="archive" name="sam-with-receiver-compiler-plugin.jar">
<element id="module-output" name="sam-with-receiver-cli" />
</element>
<element id="archive" name="sam-with-receiver-ide-plugin.jar">
<element id="module-output" name="sam-with-receiver-ide" />
</element>
</element>
<element id="directory" name="kotlinc">
<element id="dir-copy" path="$PROJECT_DIR$/dist/kotlinc" />
</element>
</root>
</artifact>
</component>
+2
View File
@@ -85,6 +85,8 @@
<module fileurl="file://$PROJECT_DIR$/core/reflection.jvm/reflection.jvm.iml" filepath="$PROJECT_DIR$/core/reflection.jvm/reflection.jvm.iml" group="core" />
<module fileurl="file://$PROJECT_DIR$/compiler/resolution/resolution.iml" filepath="$PROJECT_DIR$/compiler/resolution/resolution.iml" group="compiler" />
<module fileurl="file://$PROJECT_DIR$/core/runtime.jvm/runtime.jvm.iml" filepath="$PROJECT_DIR$/core/runtime.jvm/runtime.jvm.iml" group="core" />
<module fileurl="file://$PROJECT_DIR$/plugins/sam-with-receiver/sam-with-receiver-cli/sam-with-receiver-cli.iml" filepath="$PROJECT_DIR$/plugins/sam-with-receiver/sam-with-receiver-cli/sam-with-receiver-cli.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/sam-with-receiver/sam-with-receiver-ide/sam-with-receiver-ide.iml" filepath="$PROJECT_DIR$/plugins/sam-with-receiver/sam-with-receiver-ide/sam-with-receiver-ide.iml" />
<module fileurl="file://$PROJECT_DIR$/core/script.runtime/script.runtime.iml" filepath="$PROJECT_DIR$/core/script.runtime/script.runtime.iml" group="core" />
<module fileurl="file://$PROJECT_DIR$/compiler/serialization/serialization.iml" filepath="$PROJECT_DIR$/compiler/serialization/serialization.iml" group="compiler" />
<module fileurl="file://$PROJECT_DIR$/compiler/tests-common/tests-common.iml" filepath="$PROJECT_DIR$/compiler/tests-common/tests-common.iml" group="compiler" />
+25 -2
View File
@@ -865,6 +865,29 @@
<fileset dir="${basedir}/plugins/noarg/noarg-cli/src" includes="META-INF/services/**"/>
</jar>
</target>
<target name="sam-with-receiver-compiler-plugin">
<cleandir dir="${output}/classes/sam-with-receiver-compiler-plugin"/>
<javac2 destdir="${output}/classes/sam-with-receiver-compiler-plugin" debug="true" debuglevel="lines,vars,source" includeAntRuntime="false">
<withKotlin modulename="noarg">
<compilerarg value="-version"/>
</withKotlin>
<skip pattern="kotlin/Metadata"/>
<src>
<pathelement path="plugins/sam-with-receiver/src"/>
</src>
<classpath>
<pathelement path="${idea.sdk}/core/intellij-core.jar"/>
<pathelement path="${kotlin-home}/lib/kotlin-compiler.jar"/>
</classpath>
</javac2>
<jar destfile="${kotlin-home}/lib/sam-with-receiver-compiler-plugin.jar">
<fileset dir="${output}/classes/sam-with-receiver-compiler-plugin"/>
<zipfileset file="${kotlin-home}/build.txt" prefix="META-INF"/>
<fileset dir="${basedir}/plugins/sam-with-receiver/src" includes="META-INF/services/**"/>
</jar>
</target>
<target name="annotation-processing-under-jdk8">
<property environment="env"/>
@@ -1273,11 +1296,11 @@
depends="builtins,stdlib,kotlin-test,core,reflection,pack-runtime,pack-runtime-sources,script-runtime,mock-runtime-for-test"/>
<target name="dist"
depends="clean,init,prepare-dist,preloader,runner,serialize-builtins,compiler,compiler-sources,kotlin-build-common,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,allopen-compiler-plugin,noarg-compiler-plugin,annotation-processing-under-jdk8,daemon-client,kotlin-build-common-test"
depends="clean,init,prepare-dist,preloader,runner,serialize-builtins,compiler,compiler-sources,kotlin-build-common,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,allopen-compiler-plugin,noarg-compiler-plugin,sam-with-receiver-compiler-plugin,annotation-processing-under-jdk8,daemon-client,kotlin-build-common-test"
description="Builds redistributables from sources"/>
<target name="dist-quick"
depends="clean,init,prepare-dist,preloader,serialize-builtins,compiler-quick,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,allopen-compiler-plugin,noarg-compiler-plugin,annotation-processing-under-jdk8"
depends="clean,init,prepare-dist,preloader,serialize-builtins,compiler-quick,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,allopen-compiler-plugin,noarg-compiler-plugin,sam-with-receiver-compiler-plugin,annotation-processing-under-jdk8"
description="Builds everything, but classes are reused from project out dir, doesn't run proguard and javadoc"/>
<target name="dist-quick-compiler-only"
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.load.java.JavaClassFinderImpl
import org.jetbrains.kotlin.load.java.components.*
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
import org.jetbrains.kotlin.load.java.sam.SamConversionResolverImpl
import org.jetbrains.kotlin.load.java.sam.SamWithReceiverResolver
import org.jetbrains.kotlin.load.kotlin.DeserializationComponentsForJava
import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinderFactory
import org.jetbrains.kotlin.platform.JvmBuiltIns
@@ -68,7 +69,8 @@ fun StorageComponentContainer.configureJavaTopDownAnalysis(
useImpl<TraceBasedErrorReporter>()
useImpl<PsiBasedExternalAnnotationResolver>()
useImpl<JavaPropertyInitializerEvaluatorImpl>()
useInstance(SamConversionResolverImpl)
useImpl<SamWithReceiverResolver>()
useImpl<SamConversionResolverImpl>()
useImpl<JavaSourceElementFactoryImpl>()
useInstance(InternalFlexibleTypeTransformer)
@@ -25,9 +25,10 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaClassConstructorDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.SimpleType
object SamConversionResolverImpl : SamConversionResolver {
class SamConversionResolverImpl(val storageManager: StorageManager, val samWithReceiverResolver: SamWithReceiverResolver): SamConversionResolver {
override fun resolveSamConstructor(constructorOwner: DeclarationDescriptor, classifier: () -> ClassifierDescriptor?): SamConstructorDescriptor? {
val classifierDescriptor = classifier()
if (classifierDescriptor !is LazyJavaClassDescriptor || classifierDescriptor.functionTypeForSamInterface == null) return null
@@ -44,8 +45,13 @@ object SamConversionResolverImpl : SamConversionResolver {
}
}
private val functionTypesForSamInterfaces = storageManager.createCacheWithNullableValues<JavaClassDescriptor, SimpleType>()
override fun resolveFunctionTypeIfSamInterface(classDescriptor: JavaClassDescriptor): SimpleType? {
val abstractMethod = SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(classDescriptor) ?: return null
return SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(abstractMethod)
return functionTypesForSamInterfaces.computeIfAbsent(classDescriptor) {
val abstractMethod = SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(classDescriptor) ?: return@computeIfAbsent null
val shouldConvertFirstParameterToDescriptor = samWithReceiverResolver.shouldConvertFirstSamParameterToReceiver(abstractMethod)
SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(abstractMethod, shouldConvertFirstParameterToDescriptor)
}
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2016 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.load.java.sam
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
class SamWithReceiverResolver {
private val extensions = mutableListOf<Extension>()
fun registerExtension(extension: Extension) {
extensions += extension
}
fun shouldConvertFirstSamParameterToReceiver(function: FunctionDescriptor): Boolean {
return extensions.any { it.shouldConvertFirstSamParameterToReceiver(function) }
}
interface Extension {
fun shouldConvertFirstSamParameterToReceiver(function: FunctionDescriptor): Boolean
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.load.java.sam;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
@@ -23,19 +24,19 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension;
import org.jetbrains.kotlin.load.java.descriptors.*;
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.name.SpecialNames;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.util.FunctionTypeResolveUtilsKt;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.jvm.JavaResolverUtils;
import org.jetbrains.kotlin.resolve.source.PsiSourceElement;
import org.jetbrains.kotlin.types.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
import static org.jetbrains.kotlin.types.Variance.IN_VARIANCE;
@@ -97,18 +98,33 @@ public class SingleAbstractMethodUtils {
}
@NotNull
public static SimpleType getFunctionTypeForAbstractMethod(@NotNull FunctionDescriptor function) {
public static SimpleType getFunctionTypeForAbstractMethod(
@NotNull FunctionDescriptor function,
boolean shouldConvertFirstParameterToDescriptor
) {
KotlinType returnType = function.getReturnType();
assert returnType != null : "function is not initialized: " + function;
List<ValueParameterDescriptor> valueParameters = function.getValueParameters();
List<KotlinType> parameterTypes = new ArrayList<KotlinType>(valueParameters.size());
List<Name> parameterNames = new ArrayList<Name>(valueParameters.size());
for (ValueParameterDescriptor parameter : valueParameters) {
int startIndex = 0;
KotlinType receiverType = null;
if (shouldConvertFirstParameterToDescriptor && !function.getValueParameters().isEmpty()) {
receiverType = valueParameters.get(0).getType();
startIndex = 1;
}
for (int i = startIndex; i < valueParameters.size(); ++i) {
ValueParameterDescriptor parameter = valueParameters.get(i);
parameterTypes.add(parameter.getType());
parameterNames.add(function.hasSynthesizedParameterNames() ? SpecialNames.NO_NAME_PROVIDED : parameter.getName());
}
return FunctionTypeResolveUtilsKt.createFunctionType(
DescriptorUtilsKt.getBuiltIns(function), Annotations.Companion.getEMPTY(), null, parameterTypes, parameterNames, returnType
DescriptorUtilsKt.getBuiltIns(function), Annotations.Companion.getEMPTY(),
receiverType, parameterTypes, parameterNames, returnType
);
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.descriptors.PackagePartProvider
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.frontend.java.di.createContainerForLazyResolveWithJava
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolverImpl
@@ -91,6 +92,9 @@ object JvmAnalyzerFacade : AnalyzerFacade<JvmPlatformParameters>() {
useBuiltInsProvider = false, // TODO: load built-ins from module dependencies in IDE
useLazyResolve = true
)
StorageComponentContainerContributor.getInstances(project).forEach { it.onContainerComposed(container, moduleInfo) }
val resolveSession = container.get<ResolveSession>()
val javaDescriptorResolver = container.get<JavaDescriptorResolver>()
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.PackagePartProvider
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDependenciesImpl
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.frontend.java.di.createContainerForTopDownAnalyzerForJvm
import org.jetbrains.kotlin.frontend.java.di.initJvmBuiltInsForTopDownAnalysis
import org.jetbrains.kotlin.frontend.java.di.initialize
@@ -80,6 +81,8 @@ object TopDownAnalyzerFacadeForJVM {
project, files, trace, configuration, packagePartProvider, declarationProviderFactory, sourceModuleSearchScope
)
StorageComponentContainerContributor.getInstances(project).forEach { it.onContainerComposed(container, null) }
val module = container.get<ModuleDescriptor>()
val moduleContext = container.get<ModuleContext>()
@@ -24,9 +24,9 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.TypeUtils
interface AnnotationBasedExtension {
fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner): List<String>
fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List<String>
fun DeclarationDescriptor.hasSpecialAnnotation(modifierListOwner: KtModifierListOwner): Boolean {
fun DeclarationDescriptor.hasSpecialAnnotation(modifierListOwner: KtModifierListOwner?): Boolean {
if (annotations.any { it.isASpecialAnnotation(modifierListOwner) }) return true
if (this is ClassDescriptor) {
@@ -40,7 +40,7 @@ interface AnnotationBasedExtension {
}
private fun AnnotationDescriptor.isASpecialAnnotation(
modifierListOwner: KtModifierListOwner,
modifierListOwner: KtModifierListOwner?,
allowMetaAnnotations: Boolean = true
): Boolean {
val annotationType = type.constructor.declarationDescriptor ?: return false
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.extensions
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.resolve.BindingContext
@@ -37,4 +38,6 @@ interface DeclarationAttributeAltererExtension {
currentModality: Modality,
bindingContext: BindingContext
): Modality? = null
fun shouldConvertFirstSAMParameterToReceiver(function: FunctionDescriptor) : Boolean = false
}
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.extensions
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.resolve.TargetPlatform
@@ -24,5 +26,7 @@ interface StorageComponentContainerContributor {
"org.jetbrains.kotlin.storageComponentContainerContributor", StorageComponentContainerContributor::class.java
)
fun addDeclarations(container: StorageComponentContainer, platform: TargetPlatform)
fun addDeclarations(container: StorageComponentContainer, platform: TargetPlatform) {}
fun onContainerComposed(container: ComponentProvider, moduleInfo: ModuleInfo?) {}
}
@@ -34,6 +34,9 @@ open class KotlinScriptDefinition(val template: KClass<out Any>) {
// TODO: consider creating separate type (subtype? for kotlin scripts)
open val fileType: LanguageFileType = KotlinFileType.INSTANCE
open val annotationsForSamWithReceivers: List<String>
get() = emptyList()
open fun <TF> isScript(file: TF): Boolean =
getFileName(file).endsWith(KotlinParserDefinition.STD_SCRIPT_EXT)
@@ -23,6 +23,7 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope;
import junit.framework.TestCase;
import kotlin.TuplesKt;
import kotlin.collections.CollectionsKt;
import kotlin.collections.MapsKt;
@@ -189,7 +190,7 @@ public abstract class AbstractDiagnosticsTest extends BaseDiagnosticsTest {
}
else {
File lazyLogFile = getLazyLogFile(testDataFile);
assertFalse("No lazy log expected, but found: " + lazyLogFile.getAbsolutePath(), lazyLogFile.exists());
TestCase.assertFalse("No lazy log expected, but found: " + lazyLogFile.getAbsolutePath(), lazyLogFile.exists());
}
Throwable exceptionFromDescriptorValidation = null;
@@ -225,7 +226,7 @@ public abstract class AbstractDiagnosticsTest extends BaseDiagnosticsTest {
KotlinTestUtils.assertEqualsToFile(testDataFile, actualText.toString());
assertTrue("Diagnostics mismatch. See the output above", ok);
TestCase.assertTrue("Diagnostics mismatch. See the output above", ok);
// now we throw a previously found error, if any
if (exceptionFromDescriptorValidation != null) {
@@ -440,7 +441,7 @@ public abstract class AbstractDiagnosticsTest extends BaseDiagnosticsTest {
return InTextDirectivesUtils.isDirectiveDefined(file.expectedText, "// SKIP_TXT");
}
})) {
assertFalse(".txt file should not exist if SKIP_TXT directive is used: " + expectedFile, expectedFile.exists());
TestCase.assertFalse(".txt file should not exist if SKIP_TXT directive is used: " + expectedFile, expectedFile.exists());
return;
}
@@ -452,7 +453,7 @@ public abstract class AbstractDiagnosticsTest extends BaseDiagnosticsTest {
for (Iterator<TestModule> module = CollectionsKt.sorted(modules.keySet()).iterator(); module.hasNext(); ) {
ModuleDescriptorImpl moduleDescriptor = modules.get(module.next());
PackageViewDescriptor aPackage = moduleDescriptor.getPackage(FqName.ROOT);
assertFalse(aPackage.isEmpty());
TestCase.assertFalse(aPackage.isEmpty());
if (isMultiModuleTest) {
rootPackageText.append(String.format("// -- Module: %s --\n", moduleDescriptor.getName()));
@@ -587,8 +588,8 @@ public abstract class AbstractDiagnosticsTest extends BaseDiagnosticsTest {
DiagnosticUtils.LineAndColumn lineAndColumn =
DiagnosticUtils.getLineAndColumnInPsiFile(element.getContainingFile(), element.getTextRange());
assertTrue("Resolved call for '" + element.getText() + "'" + lineAndColumn + " is not completed",
((MutableResolvedCall<?>) resolvedCall).isCompleted());
TestCase.assertTrue("Resolved call for '" + element.getText() + "'" + lineAndColumn + " is not completed",
((MutableResolvedCall<?>) resolvedCall).isCompleted());
}
checkResolvedCallsInDiagnostics(bindingContext);
@@ -633,8 +634,8 @@ public abstract class AbstractDiagnosticsTest extends BaseDiagnosticsTest {
DiagnosticUtils.LineAndColumn lineAndColumn =
DiagnosticUtils.getLineAndColumnInPsiFile(element.getContainingFile(), element.getTextRange());
assertTrue("Resolved calls stored in " + diagnostic.getFactory().getName() + "\n" +
"for '" + element.getText() + "'" + lineAndColumn + " are not completed",
allCallsAreCompleted);
TestCase.assertTrue("Resolved calls stored in " + diagnostic.getFactory().getName() + "\n" +
"for '" + element.getText() + "'" + lineAndColumn + " are not completed",
allCallsAreCompleted);
}
}
@@ -53,7 +53,7 @@ import org.jetbrains.kotlin.utils.toReadOnlyList
import java.util.*
class LazyJavaClassDescriptor(
outerContext: LazyJavaResolverContext,
val outerContext: LazyJavaResolverContext,
containingDeclaration: DeclarationDescriptor,
private val jClass: JavaClass,
private val additionalSupertypeClassDescriptor: ClassDescriptor? = null
@@ -123,10 +123,6 @@ class LazyJavaClassDescriptor(
override val annotations by c.storageManager.createLazyValue { c.resolveAnnotations(jClass) }
private val functionTypeForSamInterface = c.storageManager.createNullableLazyValue {
c.components.samConversionResolver.resolveFunctionTypeIfSamInterface(this)
}
private val declaredParameters = c.storageManager.createLazyValue {
jClass.typeParameters.map {
p ->
@@ -137,7 +133,7 @@ class LazyJavaClassDescriptor(
override fun getDeclaredTypeParameters() = declaredParameters()
override fun getFunctionTypeForSamInterface(): SimpleType? = functionTypeForSamInterface()
override fun getFunctionTypeForSamInterface(): SimpleType? = c.components.samConversionResolver.resolveFunctionTypeIfSamInterface(this)
override fun toString() = "Lazy Java class ${this.fqNameUnsafe}"
@@ -163,6 +163,7 @@ import org.jetbrains.kotlin.shortenRefs.AbstractShortenRefsTest
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.types.AbstractTypeBindingTest
import org.jetbrains.kotlin.idea.refactoring.AbstractNameSuggestionProviderTest
import org.jetbrains.kotlin.samWithReceiver.AbstractSamWithReceiverTest
import java.io.File
import java.lang.IllegalArgumentException
import java.util.*
@@ -1172,6 +1173,12 @@ fun main(args: Array<String>) {
}
}
testGroup("plugins/plugins-tests/tests", "plugins/sam-with-receiver/sam-with-receiver-cli/testData") {
testClass<AbstractSamWithReceiverTest> {
model("diagnostics")
}
}
testGroup("plugins/android-extensions/android-extensions-idea/tests", "plugins/android-extensions/android-extensions-idea/testData") {
testClass<AbstractAndroidCompletionTest>() {
model("android/completion", recursive = false, extension = null)
@@ -76,15 +76,16 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
}
private val facadesForScriptDependencies: SLRUCache<KotlinScriptExternalDependencies, ProjectResolutionFacade> =
object : SLRUCache<KotlinScriptExternalDependencies, ProjectResolutionFacade>(2, 3) {
override fun createValue(key: KotlinScriptExternalDependencies?): ProjectResolutionFacade {
return createFacadeForScriptDependencies(ScriptDependenciesModuleInfo(project, key))
private val facadesForScriptDependencies: SLRUCache<ScriptModuleInfo, ProjectResolutionFacade> =
object : SLRUCache<ScriptModuleInfo, ProjectResolutionFacade>(2, 3) {
override fun createValue(scriptModuleInfo: ScriptModuleInfo?): ProjectResolutionFacade {
val dependencies = scriptModuleInfo?.externalDependencies
return createFacadeForScriptDependencies(ScriptDependenciesModuleInfo(project, dependencies, scriptModuleInfo))
}
}
private fun getFacadeForScriptDependencies(dependencies: KotlinScriptExternalDependencies?) = synchronized(facadesForScriptDependencies) {
facadesForScriptDependencies.get(dependencies)
private fun getFacadeForScriptDependencies(scriptModuleInfo: ScriptModuleInfo) = synchronized(facadesForScriptDependencies) {
facadesForScriptDependencies.get(scriptModuleInfo)
}
private fun createFacadeForScriptDependencies(
@@ -230,7 +231,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
createFacadeForScriptDependencies(syntheticFileModule, files)
}
syntheticFileModule is ScriptModuleInfo -> {
val facadeForScriptDependencies = getFacadeForScriptDependencies(syntheticFileModule.externalDependencies)
val facadeForScriptDependencies = getFacadeForScriptDependencies(syntheticFileModule)
val globalContext = facadeForScriptDependencies.globalContext.contextWithNewLockAndCompositeExceptionTracker()
ProjectResolutionFacade(
"facadeForSynthetic in ScriptModuleInfo",
@@ -55,7 +55,7 @@ data class ScriptModuleInfo(val project: Project, val scriptFile: VirtualFile,
override fun dependencies(): List<IdeaModuleInfo> {
return listOf(
this,
ScriptDependenciesModuleInfo(project, externalDependencies)
ScriptDependenciesModuleInfo(project, externalDependencies, this)
) + sdkDependencies(externalDependencies, project)
}
}
@@ -73,7 +73,11 @@ fun findJdk(dependencies: KotlinScriptExternalDependencies?, project: Project):
allJdks.firstOrNull()
}
class ScriptDependenciesModuleInfo(val project: Project, val dependencies: KotlinScriptExternalDependencies?): IdeaModuleInfo {
class ScriptDependenciesModuleInfo(
val project: Project,
val dependencies: KotlinScriptExternalDependencies?,
val scriptModuleInfo: ScriptModuleInfo?
): IdeaModuleInfo {
override fun dependencies() = (listOf(this) + sdkDependencies(dependencies, project))
override val name = Name.special("<Script dependencies>")
@@ -129,7 +129,7 @@ private fun getModuleInfoByVirtualFile(project: Project, virtualFile: VirtualFil
}
if (KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspathScope().contains(virtualFile)) {
return ScriptDependenciesModuleInfo(project, null)
return ScriptDependenciesModuleInfo(project, null, null)
}
return NotUnderContentRootModuleInfo
+1
View File
@@ -56,6 +56,7 @@
<orderEntry type="library" scope="TEST" name="native-platform-uberjar" level="project" />
<orderEntry type="module" module-name="allopen-ide" scope="TEST" />
<orderEntry type="module" module-name="noarg-ide" scope="TEST" />
<orderEntry type="module" module-name="sam-with-receiver-ide" scope="TEST" />
<orderEntry type="module" module-name="descriptors" />
</component>
</module>
+2
View File
@@ -2017,6 +2017,8 @@
<declarationAttributeAltererExtension implementation="org.jetbrains.kotlin.allopen.ide.IdeAllOpenDeclarationAttributeAltererExtension"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.samWithReceiver.ide.IdeSamWithReceiverComponentContributor"/>
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.noarg.NoArgClassBuilderInterceptorExtension"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.noarg.ide.IdeNoArgComponentContainerContributor"/>
<defaultErrorMessages implementation="org.jetbrains.kotlin.noarg.diagnostic.DefaultErrorMessagesNoArg"/>
@@ -29,12 +29,11 @@ import org.jetbrains.kotlin.resolve.BindingContext
class CliAllOpenDeclarationAttributeAltererExtension(
private val allOpenAnnotationFqNames: List<String>
) : AbstractAllOpenDeclarationAttributeAltererExtension() {
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner) = allOpenAnnotationFqNames
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?) = allOpenAnnotationFqNames
}
abstract class AbstractAllOpenDeclarationAttributeAltererExtension : DeclarationAttributeAltererExtension, AnnotationBasedExtension {
companion object {
@TestOnly
val ANNOTATIONS_FOR_TESTS = listOf("AllOpen", "AllOpen2", "test.AllOpen")
}
@@ -40,11 +40,12 @@ class IdeAllOpenDeclarationAttributeAltererExtension(val project: Project) : Abs
CachedValueProvider.Result.create(WeakHashMap<Module, List<String>>(), ProjectRootModificationTracker.getInstance(project))
}
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner): List<String> {
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List<String> {
if (ApplicationManager.getApplication().isUnitTestMode) {
return ANNOTATIONS_FOR_TESTS
}
if (modifierListOwner == null) return emptyList()
val module = ModuleUtilCore.findModuleForPsiElement(modifierListOwner) ?: return emptyList()
return cache.value.getOrPut(module) {
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
class CliNoArgDeclarationChecker(val noArgAnnotationFqNames: List<String>) : AbstractNoArgDeclarationChecker() {
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner) = noArgAnnotationFqNames
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?) = noArgAnnotationFqNames
}
abstract class AbstractNoArgDeclarationChecker : DeclarationChecker, AnnotationBasedExtension {
@@ -39,7 +39,8 @@ class IdeNoArgDeclarationChecker(val project: Project) : AbstractNoArgDeclaratio
CachedValueProvider.Result.create(WeakHashMap<Module, List<String>>(), ProjectRootModificationTracker.getInstance(project))
}
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner): List<String> {
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List<String> {
if (modifierListOwner == null) return emptyList()
val module = ModuleUtilCore.findModuleForPsiElement(modifierListOwner) ?: return emptyList()
return cache.value.getOrPut(module) {
+1
View File
@@ -37,6 +37,7 @@
<orderEntry type="module" module-name="build-common" scope="TEST" />
<orderEntry type="module" module-name="jps-tests" scope="TEST" />
<orderEntry type="module" module-name="kapt3" scope="TEST" />
<orderEntry type="module" module-name="sam-with-receiver-cli" scope="TEST" />
<orderEntry type="module" module-name="allopen-cli" scope="TEST" />
<orderEntry type="module" module-name="noarg-cli" scope="TEST" />
</component>
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2016 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.samWithReceiver
import org.jetbrains.kotlin.checkers.AbstractDiagnosticsTest
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
abstract class AbstractSamWithReceiverTest : AbstractDiagnosticsTest() {
private companion object {
private val TEST_ANNOTATIONS = listOf("SamWithReceiver")
}
override fun createEnvironment() = super.createEnvironment().apply {
StorageComponentContainerContributor.registerExtension(project, CliSamWithReceiverComponentContributor(TEST_ANNOTATIONS))
}
}
@@ -0,0 +1,92 @@
/*
* Copyright 2010-2016 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.samWithReceiver;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
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("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class SamWithReceiverTestGenerated extends AbstractSamWithReceiverTest {
public void testAllFilesPresentInDiagnostics() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("noParameters.kt")
public void testNoParameters() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics/noParameters.kt");
doTest(fileName);
}
@TestMetadata("noReturnType.kt")
public void testNoReturnType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics/noReturnType.kt");
doTest(fileName);
}
@TestMetadata("samConversionNoParameters.kt")
public void testSamConversionNoParameters() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics/samConversionNoParameters.kt");
doTest(fileName);
}
@TestMetadata("samConversionSimple.kt")
public void testSamConversionSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics/samConversionSimple.kt");
doTest(fileName);
}
@TestMetadata("samConversionSimpleWithoutAnnotation.kt")
public void testSamConversionSimpleWithoutAnnotation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics/samConversionSimpleWithoutAnnotation.kt");
doTest(fileName);
}
@TestMetadata("samWithAnnotation.kt")
public void testSamWithAnnotation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics/samWithAnnotation.kt");
doTest(fileName);
}
@TestMetadata("samWithoutAnnotation.kt")
public void testSamWithoutAnnotation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics/samWithoutAnnotation.kt");
doTest(fileName);
}
@TestMetadata("singleParameter.kt")
public void testSingleParameter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics/singleParameter.kt");
doTest(fileName);
}
@TestMetadata("singleParameterWithoutAnnotation.kt")
public void testSingleParameterWithoutAnnotation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/sam-with-receiver/sam-with-receiver-cli/testData/diagnostics/singleParameterWithoutAnnotation.kt");
doTest(fileName);
}
}
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-runtime" level="project" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="frontend.java" />
</component>
</module>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-runtime" level="project" />
<orderEntry type="module" module-name="frontend" />
</component>
</module>
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2016 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.samWithReceiver
import com.intellij.mock.MockProject
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.compiler.plugin.CliOption
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.CompilerConfigurationKey
import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.load.java.sam.SamWithReceiverResolver
object SamWithReceiverConfigurationKeys {
val ANNOTATION: CompilerConfigurationKey<List<String>> =
CompilerConfigurationKey.create("annotation qualified name")
}
class SamWithReceiverCommandLineProcessor : CommandLineProcessor {
companion object {
val ANNOTATION_OPTION = CliOption("annotation", "<fqname>", "Annotation qualified names",
required = false, allowMultipleOccurrences = true)
val PLUGIN_ID = "org.jetbrains.kotlin.samWithReceiver"
}
override val pluginId = PLUGIN_ID
override val pluginOptions = listOf(ANNOTATION_OPTION)
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) = when (option) {
ANNOTATION_OPTION -> {
val paths = configuration.getList(SamWithReceiverConfigurationKeys.ANNOTATION).toMutableList()
paths.add(value)
configuration.put(SamWithReceiverConfigurationKeys.ANNOTATION, paths)
}
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
}
}
class SamWithReceiverComponentRegistrar : ComponentRegistrar {
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
val annotations = configuration.get(SamWithReceiverConfigurationKeys.ANNOTATION) ?: return
if (annotations.isEmpty()) return
StorageComponentContainerContributor.registerExtension(project, CliSamWithReceiverComponentContributor(annotations))
}
}
class CliSamWithReceiverComponentContributor(val annotations: List<String>): StorageComponentContainerContributor {
override fun onContainerComposed(container: ComponentProvider, moduleInfo: ModuleInfo?) {
container.get<SamWithReceiverResolver>().registerExtension(SamWithReceiverResolverExtension(annotations))
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2016 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.samWithReceiver
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.extensions.AnnotationBasedExtension
import org.jetbrains.kotlin.load.java.sam.SamWithReceiverResolver
import org.jetbrains.kotlin.psi.KtModifierListOwner
class SamWithReceiverResolverExtension(val annotations: List<String>) : SamWithReceiverResolver.Extension, AnnotationBasedExtension {
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?) = annotations
override fun shouldConvertFirstSamParameterToReceiver(function: FunctionDescriptor): Boolean {
return (function.containingDeclaration as? ClassDescriptor)?.hasSpecialAnnotation(null) ?: false
}
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.samWithReceiver.SamWithReceiverCommandLineProcessor
@@ -0,0 +1 @@
org.jetbrains.kotlin.samWithReceiver.SamWithReceiverComponentRegistrar
@@ -0,0 +1,21 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// FILE: Sam.java
@SamWithReceiver
public interface Sam {
void run();
}
// FILE: test.kt
annotation class SamWithReceiver
fun test() {
Sam {
System.out.println("Hello, world!")
}
Sam {
val a: String = <!NO_THIS!>this<!>
System.out.println(a)
}
}
@@ -0,0 +1,18 @@
package
@SamWithReceiver public /*synthesized*/ fun Sam(/*0*/ function: () -> kotlin.Unit): Sam
public fun test(): kotlin.Unit
@SamWithReceiver public interface Sam {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final annotation class SamWithReceiver : kotlin.Annotation {
public constructor SamWithReceiver()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,21 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// FILE: Sam.java
@SamWithReceiver
public interface Sam {
void run(String a, String b);
}
// FILE: test.kt
annotation class SamWithReceiver
fun test() {
Sam { <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>a, <!CANNOT_INFER_PARAMETER_TYPE!>b<!><!> ->
System.out.println(a)
}
Sam { b ->
val a: String = this
System.out.println(a)
}
}
@@ -0,0 +1,18 @@
package
@SamWithReceiver public /*synthesized*/ fun Sam(/*0*/ function: kotlin.String!.(b: kotlin.String!) -> kotlin.Unit): Sam
public fun test(): kotlin.Unit
@SamWithReceiver public interface Sam {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(/*0*/ a: kotlin.String!, /*1*/ b: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final annotation class SamWithReceiver : kotlin.Annotation {
public constructor SamWithReceiver()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,28 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// FILE: Sam.java
@SamWithReceiver
public interface Sam {
void run();
}
// FILE: Exec.java
public class Exec {
void exec(Sam sam) {}
}
// FILE: test.kt
annotation class SamWithReceiver
fun test() {
val e = Exec()
e.exec {
System.out.println("Hello, world!")
}
e.exec {
val a: String = <!NO_THIS!>this<!>
System.out.println(a)
}
}
@@ -0,0 +1,26 @@
package
@SamWithReceiver public /*synthesized*/ fun Sam(/*0*/ function: () -> kotlin.Unit): Sam
public fun test(): kotlin.Unit
public open class Exec {
public constructor Exec()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun exec(/*0*/ sam: Sam!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@SamWithReceiver public interface Sam {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final annotation class SamWithReceiver : kotlin.Annotation {
public constructor SamWithReceiver()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,22 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// FILE: Sam.java
@SamWithReceiver
public interface Sam {
void run(String a);
}
// FILE: Exec.java
public class Exec {
void exec(Sam sam) {}
}
// FILE: test.kt
annotation class SamWithReceiver
fun test() {
val e = Exec()
e.exec <!TYPE_MISMATCH!>{ <!CANNOT_INFER_PARAMETER_TYPE!>a<!> -> System.out.println(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>) }<!>
e.exec { System.out.println(this) }
}
@@ -0,0 +1,26 @@
package
@SamWithReceiver public /*synthesized*/ fun Sam(/*0*/ function: kotlin.String!.() -> kotlin.Unit): Sam
public fun test(): kotlin.Unit
public open class Exec {
public constructor Exec()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun exec(/*0*/ sam: Sam!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@SamWithReceiver public interface Sam {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(/*0*/ a: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final annotation class SamWithReceiver : kotlin.Annotation {
public constructor SamWithReceiver()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,19 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// FILE: Sam.java
public interface Sam {
void run(String a);
}
// FILE: Exec.java
public class Exec {
void exec(Sam sam) {}
}
// FILE: test.kt
fun test() {
val e = Exec()
e.exec { a -> System.out.println(a) }
e.exec { System.out.println(<!NO_THIS!>this<!>) }
}
@@ -0,0 +1,19 @@
package
public /*synthesized*/ fun Sam(/*0*/ function: (a: kotlin.String!) -> kotlin.Unit): Sam
public fun test(): kotlin.Unit
public open class Exec {
public constructor Exec()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun exec(/*0*/ sam: Sam!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface Sam {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(/*0*/ a: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,23 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// FILE: Sam.java
@SamWithReceiver
public interface Sam {
String run(String a, String b);
}
// FILE: test.kt
annotation class SamWithReceiver
fun test() {
Sam { <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>a, <!CANNOT_INFER_PARAMETER_TYPE!>b<!><!> ->
System.out.println(a)
""
}
Sam { b ->
val a: String = this
System.out.println(a)
""
}
}
@@ -0,0 +1,18 @@
package
@SamWithReceiver public /*synthesized*/ fun Sam(/*0*/ function: kotlin.String!.(b: kotlin.String!) -> kotlin.String!): Sam
public fun test(): kotlin.Unit
@SamWithReceiver public interface Sam {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(/*0*/ a: kotlin.String!, /*1*/ b: kotlin.String!): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final annotation class SamWithReceiver : kotlin.Annotation {
public constructor SamWithReceiver()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,20 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// FILE: Sam.java
public interface Sam {
String run(String a, String b);
}
// FILE: test.kt
fun test() {
Sam { a, b ->
System.out.println(a)
""
}
Sam { <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>b<!> ->
val a = <!NO_THIS!>this@Sam<!>
System.out.println(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>)
""
}
}
@@ -0,0 +1,11 @@
package
public /*synthesized*/ fun Sam(/*0*/ function: (a: kotlin.String!, b: kotlin.String!) -> kotlin.String!): Sam
public fun test(): kotlin.Unit
public interface Sam {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(/*0*/ a: kotlin.String!, /*1*/ b: kotlin.String!): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,22 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// FILE: Sam.java
@SamWithReceiver
public interface Sam {
void run(String a);
}
// FILE: test.kt
annotation class SamWithReceiver
fun test() {
Sam { <!EXPECTED_PARAMETERS_NUMBER_MISMATCH, CANNOT_INFER_PARAMETER_TYPE!>a<!> ->
System.out.println(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>)
}
Sam {
val a: String = this
val a2: String = <!UNRESOLVED_REFERENCE!>it<!>
System.out.println(a)
}
}
@@ -0,0 +1,18 @@
package
@SamWithReceiver public /*synthesized*/ fun Sam(/*0*/ function: kotlin.String!.() -> kotlin.Unit): Sam
public fun test(): kotlin.Unit
@SamWithReceiver public interface Sam {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(/*0*/ a: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final annotation class SamWithReceiver : kotlin.Annotation {
public constructor SamWithReceiver()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,18 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// FILE: Sam.java
public interface Sam {
void run(String a);
}
// FILE: test.kt
fun test() {
Sam { a ->
System.out.println(a)
}
Sam {
val a = <!NO_THIS!>this<!>
System.out.println(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>)
}
}
@@ -0,0 +1,11 @@
package
public /*synthesized*/ fun Sam(/*0*/ function: (a: kotlin.String!) -> kotlin.Unit): Sam
public fun test(): kotlin.Unit
public interface Sam {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(/*0*/ a: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-runtime" level="project" />
<orderEntry type="module" module-name="sam-with-receiver-cli" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="idea-analysis" />
<orderEntry type="module" module-name="frontend.java" />
</component>
</module>
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2016 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.samWithReceiver.ide
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.idea.caches.resolve.ScriptDependenciesModuleInfo
import org.jetbrains.kotlin.idea.caches.resolve.ScriptModuleInfo
import org.jetbrains.kotlin.load.java.sam.SamWithReceiverResolver
import org.jetbrains.kotlin.samWithReceiver.SamWithReceiverResolverExtension
class IdeSamWithReceiverComponentContributor : StorageComponentContainerContributor {
override fun onContainerComposed(container: ComponentProvider, moduleInfo: ModuleInfo?) {
val annotations = when (moduleInfo) {
is ScriptModuleInfo -> moduleInfo.scriptDefinition.annotationsForSamWithReceivers
is ScriptDependenciesModuleInfo -> moduleInfo.scriptModuleInfo?.scriptDefinition?.annotationsForSamWithReceivers
else -> null
} ?: return
container.get<SamWithReceiverResolver>().registerExtension(SamWithReceiverResolverExtension(annotations))
}
}