Load some of the TYPE_USE annotations in fast class reading mode

Only top-level types on fields, methods' return types and
value parameters are supported to catch-up how class-files are loaded
in IntelliJ (see IDEA-153093)

NB: this commit also affects
ForeignJava8AnnotationsNoAnnotationInClasspathWithFastClassReadingTestGenerated
that were failing before

 #KT-20016 Fixed
This commit is contained in:
Denis Zharkov
2017-09-11 13:15:24 +03:00
parent 08f3dbce67
commit d6ee774243
10 changed files with 162 additions and 6 deletions
@@ -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<BinaryJavaMethod>()?.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) {
@@ -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
}
}
}
@@ -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<JavaClass>()?.typeParameters?.isNotEmpty() == true
// TODO: support type annotations
override val annotations get() = emptyList<JavaAnnotation>()
override fun findAnnotation(fqName: FqName) = null
private var _annotations = emptyList<JavaAnnotation>()
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
@@ -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!
}
}
@@ -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)
@@ -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!
}
}
@@ -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!
}
}
@@ -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
}
@@ -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);
}
}
@@ -535,6 +535,10 @@ fun main(args: Array<String>) {
model("loadJava8/sourceJava", extension = "java", testMethod = "doTestSourceJava")
}
testClass<AbstractLoadJava8WithFastClassReadingTest> {
model("loadJava8/compiledJava", extension = "java", testMethod = "doTestCompiledJava")
}
testClass<AbstractEnhancedSignaturesResolvedCallsTest> {
model("resolvedCalls/enhancedSignatures")
}