diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt index 10e21f38a3f..e35f34d070c 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt @@ -22,9 +22,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs -import org.jetbrains.org.objectweb.asm.AnnotationVisitor -import org.jetbrains.org.objectweb.asm.MethodVisitor -import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.* import java.lang.reflect.Array internal class AnnotationsCollectorMethodVisitor( @@ -55,6 +53,27 @@ internal class AnnotationsCollectorMethodVisitor( return BinaryJavaAnnotation.addAnnotation(annotations, desc, context, signatureParser) } + + override fun visitTypeAnnotation(typeRef: Int, typePath: TypePath?, desc: String, visible: Boolean): AnnotationVisitor? { + // TODO: support annotations on type arguments + if (typePath != null) return null + + val typeReference = TypeReference(typeRef) + + return when (typeReference.sort) { + TypeReference.METHOD_RETURN -> member.safeAs()?.returnType?.let { + BinaryJavaAnnotation.addTypeAnnotation(it, desc, context, signatureParser) + } + + TypeReference.METHOD_FORMAL_PARAMETER -> + BinaryJavaAnnotation.addTypeAnnotation( + member.valueParameters[typeReference.formalParameterIndex].type, + desc, context, signatureParser + ) + + else -> null + } + } } class BinaryJavaAnnotation private constructor( @@ -87,6 +106,20 @@ class BinaryJavaAnnotation private constructor( return annotationVisitor } + + fun addTypeAnnotation( + type: JavaType, + desc: String, + context: ClassifierResolutionContext, + signatureParser: BinaryClassSignatureParser + ): AnnotationVisitor? { + type as? PlainJavaClassifierType ?: return null + + val (javaAnnotation, annotationVisitor) = createAnnotationAndVisitor(desc, context, signatureParser) + type.addAnnotation(javaAnnotation) + + return annotationVisitor + } } private val classifierResolutionResult by lazy(LazyThreadSafetyMode.NONE) { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt index e5335c657f9..2dbcc1bb1bd 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt @@ -162,6 +162,12 @@ class BinaryJavaClass( object : FieldVisitor(ASM_API_VERSION_FOR_CLASS_READING) { override fun visitAnnotation(desc: String, visible: Boolean) = BinaryJavaAnnotation.addAnnotation(this@run.annotations, desc, context, signatureParser) + + override fun visitTypeAnnotation(typeRef: Int, typePath: TypePath?, desc: String, visible: Boolean) = + if (typePath == null) + BinaryJavaAnnotation.addTypeAnnotation(type, desc, context, signatureParser) + else + null } } } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Types.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Types.kt index 609011c2b17..47542d57c07 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Types.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Types.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.load.java.structure.impl.classFiles +import com.intellij.util.containers.ContainerUtil import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.load.java.structure.* import org.jetbrains.kotlin.name.FqName @@ -39,9 +40,18 @@ internal class PlainJavaClassifierType( get() = typeArguments.isEmpty() && classifierResolverResult.classifier?.safeAs()?.typeParameters?.isNotEmpty() == true - // TODO: support type annotations - override val annotations get() = emptyList() - override fun findAnnotation(fqName: FqName) = null + private var _annotations = emptyList() + override val annotations get() = _annotations + + override fun findAnnotation(fqName: FqName) = annotations.find { it.classId?.asSingleFqName() == fqName } + + internal fun addAnnotation(annotation: JavaAnnotation) { + if (_annotations.isEmpty()) { + _annotations = ContainerUtil.newSmartList() + } + + (_annotations as MutableList).add(annotation) + } override val isDeprecatedInJavaDoc get() = false diff --git a/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.fast.txt b/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.fast.txt new file mode 100644 index 00000000000..5e4ceb48ec3 --- /dev/null +++ b/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.fast.txt @@ -0,0 +1,14 @@ +package test + +public open class InnerClassTypeAnnotation { + public constructor InnerClassTypeAnnotation() + + @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) public final annotation class Foo : kotlin.Annotation { + public constructor Foo() + } + + public open inner class Inner { + public constructor Inner(/*0*/ p0: @test.InnerClassTypeAnnotation.Foo kotlin.String!) + public open fun bar(/*0*/ p0: kotlin.String!, /*1*/ p1: @test.InnerClassTypeAnnotation.Foo kotlin.String!): @test.InnerClassTypeAnnotation.Foo kotlin.String! + } +} diff --git a/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.java b/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.java index 0b9078dcbf8..c507c591e03 100644 --- a/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.java +++ b/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.java @@ -13,6 +13,8 @@ public class InnerClassTypeAnnotation { public class Inner { public Inner(@Foo String foo) { } + + public @Foo String bar(String x, @Foo String y) { return null; } } @Retention(RetentionPolicy.CLASS) diff --git a/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.javac.txt b/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.javac.txt index 88a9361ce8d..d4e98cddc31 100644 --- a/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.javac.txt +++ b/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.javac.txt @@ -9,5 +9,6 @@ public open class InnerClassTypeAnnotation { public open inner class Inner { public constructor Inner(/*0*/ p0: kotlin.String!) + public open fun bar(/*0*/ p0: kotlin.String!, /*1*/ p1: kotlin.String!): kotlin.String! } } diff --git a/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.txt b/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.txt index 0a331d40030..a0cb256777a 100644 --- a/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.txt +++ b/compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.txt @@ -9,5 +9,6 @@ public open class InnerClassTypeAnnotation { public open inner class Inner { public constructor Inner(/*0*/ @test.InnerClassTypeAnnotation.Foo p0: @test.InnerClassTypeAnnotation.Foo kotlin.String!) + @test.InnerClassTypeAnnotation.Foo public open fun bar(/*0*/ p0: kotlin.String!, /*1*/ @test.InnerClassTypeAnnotation.Foo p1: @test.InnerClassTypeAnnotation.Foo kotlin.String!): @test.InnerClassTypeAnnotation.Foo kotlin.String! } } diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/jvm/compiler/AbstractLoadJava8WithFastClassReadingTest.kt b/compiler/tests-java8/tests/org/jetbrains/kotlin/jvm/compiler/AbstractLoadJava8WithFastClassReadingTest.kt new file mode 100644 index 00000000000..5d46c979330 --- /dev/null +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/jvm/compiler/AbstractLoadJava8WithFastClassReadingTest.kt @@ -0,0 +1,23 @@ +/* + * 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.jvm.compiler + +import org.jetbrains.kotlin.test.TestJdkKind + +abstract class AbstractLoadJava8WithFastClassReadingTest : AbstractLoadJavaWithFastClassReadingTest() { + override fun getJdkKind() = TestJdkKind.FULL_JDK +} diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/jvm/compiler/LoadJava8WithFastClassReadingTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/jvm/compiler/LoadJava8WithFastClassReadingTestGenerated.java new file mode 100644 index 00000000000..fb492074da9 --- /dev/null +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/jvm/compiler/LoadJava8WithFastClassReadingTestGenerated.java @@ -0,0 +1,62 @@ +/* + * 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.jvm.compiler; + +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("compiler/testData/loadJava8/compiledJava") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class LoadJava8WithFastClassReadingTestGenerated extends AbstractLoadJava8WithFastClassReadingTest { + public void testAllFilesPresentInCompiledJava() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava8/compiledJava"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true); + } + + @TestMetadata("InnerClassTypeAnnotation.java") + public void testInnerClassTypeAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava8/compiledJava/InnerClassTypeAnnotation.java"); + doTestCompiledJava(fileName); + } + + @TestMetadata("MapRemove.java") + public void testMapRemove() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava8/compiledJava/MapRemove.java"); + doTestCompiledJava(fileName); + } + + @TestMetadata("TypeAnnotations.java") + public void testTypeAnnotations() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava8/compiledJava/TypeAnnotations.java"); + doTestCompiledJava(fileName); + } + + @TestMetadata("TypeParameterAnnotations.java") + public void testTypeParameterAnnotations() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava8/compiledJava/TypeParameterAnnotations.java"); + doTestCompiledJava(fileName); + } +} diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index c8ddc452674..1f8621fa212 100755 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -535,6 +535,10 @@ fun main(args: Array) { model("loadJava8/sourceJava", extension = "java", testMethod = "doTestSourceJava") } + testClass { + model("loadJava8/compiledJava", extension = "java", testMethod = "doTestCompiledJava") + } + testClass { model("resolvedCalls/enhancedSignatures") }