/* * Copyright 2010-2015 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.codegen; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.backend.common.output.OutputFile; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.test.ConfigurationKind; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.List; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.*; public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase { public static final FqName PACKAGE_NAME = new FqName("test"); @Override protected void setUp() throws Exception { super.setUp(); createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL); } public void testTraitImpl() { doTestKotlinSyntheticClass( "interface A { fun foo() = 42 }", JvmAbi.DEFAULT_IMPLS_SUFFIX ); } public void testSamWrapper() { doTestKotlinSyntheticClass( "val f = {}\nval foo = Thread(f)", "$sam" ); } public void testSamLambda() { doTestKotlinSyntheticClass( "val foo = Thread { }", "$1" ); } public void testCallableReferenceWrapper() { doTestKotlinSyntheticClass( "val f = String::get", "$1" ); } public void testLocalFunction() { doTestKotlinSyntheticClass( "fun foo() { fun bar() {} }", "$1" ); } public void testAnonymousFunction() { doTestKotlinSyntheticClass( "val f = {}", "$1" ); } public void testLocalClass() { doTestKotlinClass( "fun foo() { class Local }", "Local" ); } public void testInnerClassOfLocalClass() { doTestKotlinClass( "fun foo() { class Local { inner class Inner } }", "Inner" ); } public void testAnonymousObject() { doTestKotlinClass( "val o = object {}", "$1" ); } public void testWhenMappings() { doTestKotlinSyntheticClass( "enum class E { A }\n" + "val x = when (E.A) { E.A -> 1; else -> 0; }", "WhenMappings" ); } private void doTestKotlinSyntheticClass(@NotNull String code, @NotNull String classFilePart) { doTest(code, classFilePart, KOTLIN_SYNTHETIC_CLASS); } private void doTestKotlinClass(@NotNull String code, @NotNull String classFilePart) { doTest(code, classFilePart, KOTLIN_CLASS); } private void doTest(@NotNull String code, @NotNull final String classFilePart, @NotNull FqName annotationFqName) { loadText("package " + PACKAGE_NAME + "\n\n" + code); List output = generateClassesInFile().asList(); Collection files = Collections2.filter(output, new Predicate() { @Override public boolean apply(OutputFile file) { return file.getRelativePath().contains(classFilePart); } }); assertFalse("No files with \"" + classFilePart + "\" in the name are found: " + output, files.isEmpty()); assertTrue("Exactly one file with \"" + classFilePart + "\" in the name should be found: " + files, files.size() == 1); String path = files.iterator().next().getRelativePath(); String fqName = path.substring(0, path.length() - ".class".length()).replace('/', '.'); Class aClass = generateClass(fqName); assertAnnotatedWith(aClass, annotationFqName.asString()); } private void assertAnnotatedWith(@NotNull Class aClass, @NotNull String annotationFqName) { Class annotationClass = loadAnnotationClassQuietly(annotationFqName); assertTrue("No annotation " + annotationFqName + " found in " + aClass, aClass.isAnnotationPresent(annotationClass)); Annotation annotation = aClass.getAnnotation(annotationClass); int[] version = (int[]) CodegenTestUtil.getAnnotationAttribute(annotation, VERSION_FIELD_NAME); assertNotNull(version); assertTrue("Annotation " + annotationFqName + " is written with an unsupported format", JvmBytecodeBinaryVersion.create(version).isCompatible()); } }