From 9e7aa69eb7718292dec6801f766b0f7e0b62598a Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 28 Aug 2013 18:51:25 +0400 Subject: [PATCH] Resurrect JetValueParameter Its name() and type() methods are still used in Kara (the latter just to check if the type is nullable, so only the first character is needed) --- .../jet/codegen/FunctionCodegen.java | 55 +++++++++ .../JetValueParameterAnnotationTest.java | 112 ++++++++++++++++++ .../runtime/typeinfo/JetValueParameter.java | 35 ++++++ 3 files changed, 202 insertions(+) create mode 100644 compiler/tests/org/jetbrains/jet/codegen/JetValueParameterAnnotationTest.java create mode 100644 runtime/src/jet/runtime/typeinfo/JetValueParameter.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index ccada71f80c..acdc117bc0c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -19,8 +19,10 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.psi.PsiElement; +import jet.runtime.typeinfo.JetValueParameter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.AnnotationVisitor; import org.jetbrains.asm4.Label; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; @@ -121,6 +123,8 @@ public class FunctionCodegen extends GenerationStateAware { generateParameterAnnotations(functionDescriptor, mv); + generateJetValueParameterAnnotations(mv, functionDescriptor, jvmSignature); + if (isAbstractMethod(functionDescriptor, methodContext.getContextKind())) return; if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { @@ -143,6 +147,57 @@ public class FunctionCodegen extends GenerationStateAware { } } + @SuppressWarnings("deprecation") + private void generateJetValueParameterAnnotations( + @NotNull MethodVisitor mv, + @NotNull FunctionDescriptor functionDescriptor, + @NotNull JvmMethodSignature jvmSignature + ) { + Iterator descriptors = functionDescriptor.getValueParameters().iterator(); + List kotlinParameterTypes = jvmSignature.getKotlinParameterTypes(); + + for (int i = 0; i < kotlinParameterTypes.size(); i++) { + JvmMethodParameterKind kind = kotlinParameterTypes.get(i).getKind(); + if (kind == JvmMethodParameterKind.ENUM_NAME || kind == JvmMethodParameterKind.ENUM_ORDINAL) { + // We shouldn't generate annotations for invisible in runtime parameters otherwise we get bad + // RuntimeInvisibleParameterAnnotations error in javac + continue; + } + + String name; + boolean nullableType; + if (kind == JvmMethodParameterKind.VALUE) { + ValueParameterDescriptor descriptor = descriptors.next(); + name = descriptor.getName().asString(); + nullableType = descriptor.getType().isNullable(); + } + else { + String lowercaseKind = kind.name().toLowerCase(); + if (needIndexForVar(kind)) { + name = "$" + lowercaseKind + "$" + i; + } + else { + name = "$" + lowercaseKind; + } + + if (kind == JvmMethodParameterKind.RECEIVER) { + ReceiverParameterDescriptor receiver = functionDescriptor.getReceiverParameter(); + nullableType = receiver == null || receiver.getType().isNullable(); + } + else { + nullableType = true; + } + } + + AnnotationVisitor av = mv.visitParameterAnnotation(i, JvmClassName.byClass(JetValueParameter.class).getDescriptor(), true); + av.visit("name", name); + if (nullableType) { + av.visit("type", "?"); + } + av.visitEnd(); + } + } + @Nullable private Type getThisTypeForFunction(@NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context) { ReceiverParameterDescriptor expectedThisObject = functionDescriptor.getExpectedThisObject(); diff --git a/compiler/tests/org/jetbrains/jet/codegen/JetValueParameterAnnotationTest.java b/compiler/tests/org/jetbrains/jet/codegen/JetValueParameterAnnotationTest.java new file mode 100644 index 00000000000..29e8434dcbf --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/codegen/JetValueParameterAnnotationTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010-2013 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.jet.codegen; + +import jet.runtime.typeinfo.JetValueParameter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.ConfigurationKind; + +import java.lang.annotation.Annotation; + +@SuppressWarnings("deprecation") +public class JetValueParameterAnnotationTest extends CodegenTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + } + + @NotNull + private static JetValueParameter valueParameter(@NotNull final String name, final boolean nullable) { + return new JetValueParameter() { + @Override + public String name() { + return name; + } + + @Override + public String type() { + return nullable ? "?" : ""; + } + + @Override + public Class annotationType() { + return JetValueParameter.class; + } + }; + } + + public void testOneNotNullParam() { + doTest( + "fun foo(byte: Byte) {}", + valueParameter("byte", false) + ); + } + + public void testTwoNotNullParams() { + doTest( + "fun foo(int: Int, string: String) {}", + valueParameter("int", false), + valueParameter("string", false) + ); + } + + public void testTwoNullableParams() { + doTest( + "fun foo(long: Long?, unit: Unit?) {}", + valueParameter("long", true), + valueParameter("unit", true) + ); + } + + public void testTwoMixedParams() { + doTest( + "fun foo(short: Short?, boolean: Boolean) {}", + valueParameter("short", true), + valueParameter("boolean", false) + ); + } + + public void testNotNullReceiver() { + doTest( + "fun Int.foo() {}", + valueParameter("$receiver", false) + ); + } + + public void testNullableReceiver() { + doTest( + "fun String?.foo() {}", + valueParameter("$receiver", true) + ); + } + + private void doTest(@NotNull String code, @NotNull JetValueParameter... expected) { + loadText(code); + + Annotation[][] annotations = generateFunction().getParameterAnnotations(); + assertSize(expected.length, annotations); + + for (int i = 0, length = annotations.length; i < length; i++) { + assertSize(1, annotations[i]); + Annotation annotation = annotations[i][0]; + assertEquals(JetValueParameter.class, annotation.annotationType()); + assertEquals(expected[i].name(), ((JetValueParameter) annotation).name()); + assertEquals(expected[i].type(), ((JetValueParameter) annotation).type()); + } + } +} diff --git a/runtime/src/jet/runtime/typeinfo/JetValueParameter.java b/runtime/src/jet/runtime/typeinfo/JetValueParameter.java new file mode 100644 index 00000000000..1cbabd700a8 --- /dev/null +++ b/runtime/src/jet/runtime/typeinfo/JetValueParameter.java @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2013 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 jet.runtime.typeinfo; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@Deprecated +public @interface JetValueParameter { + String name(); + + /** + * This is a hack for Kara + * @return "?" if the type of this parameter is nullable, an empty string otherwise + */ + String type() default ""; +}