From 8dcd81e0b39f41bd496468b9c51dbcf90d1f90c6 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 4 Nov 2014 20:26:53 +0200 Subject: [PATCH] KT-6178 False "Overriden methods are not annotated" when using delegation #KT-6178 Fixed --- .../jet/codegen/AnnotationCodegen.java | 10 +++++ .../delegation/ExternalAnnotations.java | 6 +++ .../delegation/ExternalAnnotations.kt | 3 ++ .../delegation/WithPlatformTypes.java | 6 +++ .../delegation/WithPlatformTypes.kt | 17 ++++++++ .../tests/org/jetbrains/jet/JetTestUtils.java | 12 +++++- .../asJava/AbstractKotlinLightClassTest.java | 41 ++++++++++--------- .../asJava/KotlinLightClassTestGenerated.java | 12 ++++++ .../KotlinMultiFileTestWithWithJava.java | 16 +++++++- 9 files changed, 101 insertions(+), 22 deletions(-) create mode 100644 compiler/testData/asJava/lightClasses/delegation/ExternalAnnotations.java create mode 100644 compiler/testData/asJava/lightClasses/delegation/ExternalAnnotations.kt create mode 100644 compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.java create mode 100644 compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java index 6da5a034902..00fdb90465e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java @@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.constants.*; import org.jetbrains.jet.lang.resolve.constants.StringValue; +import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.types.Flexibility; import org.jetbrains.jet.lang.types.JetType; @@ -189,7 +190,12 @@ public abstract class AnnotationCodegen { if (TypesPackage.isFlexible(type)) { // A flexible type whose lower bound in not-null and upper bound is nullable, should not be annotated Flexibility flexibility = TypesPackage.flexibility(type); + if (!TypeUtils.isNullableType(flexibility.getLowerBound()) && TypeUtils.isNullableType(flexibility.getUpperBound())) { + AnnotationDescriptor notNull = type.getAnnotations().findAnnotation(JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION); + if (notNull != null) { + generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, NotNull.class); + } return; } } @@ -198,6 +204,10 @@ public abstract class AnnotationCodegen { Class annotationClass = isNullableType ? Nullable.class : NotNull.class; + generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationClass); + } + + private void generateAnnotationIfNotPresent(Set annotationDescriptorsAlreadyPresent, Class annotationClass) { String descriptor = Type.getType(annotationClass).getDescriptor(); if (!annotationDescriptorsAlreadyPresent.contains(descriptor)) { visitAnnotation(descriptor, false).visitEnd(); diff --git a/compiler/testData/asJava/lightClasses/delegation/ExternalAnnotations.java b/compiler/testData/asJava/lightClasses/delegation/ExternalAnnotations.java new file mode 100644 index 00000000000..79a833d5980 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/delegation/ExternalAnnotations.java @@ -0,0 +1,6 @@ +public final class WithPlatformTypes implements kotlin.jvm.internal.KObject, java.lang.Iterable { + public WithPlatformTypes(@org.jetbrains.annotations.NotNull java.lang.Iterable i) { /* compiled code */ } + + @org.jetbrains.annotations.NotNull + public java.util.Iterator iterator() { /* compiled code */ } +} diff --git a/compiler/testData/asJava/lightClasses/delegation/ExternalAnnotations.kt b/compiler/testData/asJava/lightClasses/delegation/ExternalAnnotations.kt new file mode 100644 index 00000000000..fab2aa9581b --- /dev/null +++ b/compiler/testData/asJava/lightClasses/delegation/ExternalAnnotations.kt @@ -0,0 +1,3 @@ +// WithPlatformTypes + +class WithPlatformTypes(i: java.lang.Iterable) : java.lang.Iterable by i \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.java b/compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.java new file mode 100644 index 00000000000..490ba4982a2 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.java @@ -0,0 +1,6 @@ +public final class WithPlatformTypes implements kotlin.jvm.internal.KObject, p.J { + public WithPlatformTypes(@org.jetbrains.annotations.NotNull p.J j) { /* compiled code */ } + + @org.jetbrains.annotations.NotNull + public java.lang.String foo(@org.jetbrains.annotations.NotNull java.lang.String b) { /* compiled code */ } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.kt b/compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.kt new file mode 100644 index 00000000000..00b215f286b --- /dev/null +++ b/compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.kt @@ -0,0 +1,17 @@ +// WithPlatformTypes + +// FILE: p/J.java +package p; + +import org.jetbrains.annotations.NotNull; + +public interface J { + @NotNull + String foo(@NotNull String b); +} + +// FILE: k.kt + +import p.* + +class WithPlatformTypes(j: J) : J by j \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/JetTestUtils.java b/compiler/tests/org/jetbrains/jet/JetTestUtils.java index 66e1e6767df..a7eeb56cb5c 100644 --- a/compiler/tests/org/jetbrains/jet/JetTestUtils.java +++ b/compiler/tests/org/jetbrains/jet/JetTestUtils.java @@ -426,7 +426,17 @@ public class JetTestUtils { if (paths == null) return; List jetFiles = Lists.newArrayList(); for (String path : paths) { - jetFiles.add(loadJetFile(environment.getProject(), new File(path))); + File file = new File(path); + if (file.isFile()) { + jetFiles.add(loadJetFile(environment.getProject(), file)); + } + else { + for (File childFile : file.listFiles()) { + if (childFile.getName().endsWith(".kt")) { + jetFiles.add(loadJetFile(environment.getProject(), childFile)); + } + } + } } LazyResolveTestUtil.resolveEagerly(jetFiles, environment); } diff --git a/compiler/tests/org/jetbrains/jet/asJava/AbstractKotlinLightClassTest.java b/compiler/tests/org/jetbrains/jet/asJava/AbstractKotlinLightClassTest.java index 1106ce99522..6c6060a5b12 100644 --- a/compiler/tests/org/jetbrains/jet/asJava/AbstractKotlinLightClassTest.java +++ b/compiler/tests/org/jetbrains/jet/asJava/AbstractKotlinLightClassTest.java @@ -22,30 +22,23 @@ import com.intellij.psi.impl.compiled.ClsElementImpl; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetTestUtils; -import org.jetbrains.jet.KotlinTestWithEnvironmentManagement; -import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys; +import org.jetbrains.jet.checkers.KotlinMultiFileTestWithWithJava; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; -import org.jetbrains.jet.config.CommonConfigurationKeys; -import org.jetbrains.jet.config.CompilerConfiguration; import java.io.File; import java.io.IOException; +import java.util.List; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -public abstract class AbstractKotlinLightClassTest extends KotlinTestWithEnvironmentManagement { +public abstract class AbstractKotlinLightClassTest extends KotlinMultiFileTestWithWithJava { private static final Pattern SUBJECT_FQ_NAME_PATTERN = Pattern.compile("^//\\s*(.*)$", Pattern.MULTILINE); @NotNull - private JetCoreEnvironment createEnvironment(File kotlinFile) { - CompilerConfiguration configuration = new CompilerConfiguration(); - - configuration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, kotlinFile.getPath()); - - configuration.add(JVMConfigurationKeys.CLASSPATH_KEY, JetTestUtils.getAnnotationsJar()); - configuration.add(JVMConfigurationKeys.CLASSPATH_KEY, JetTestUtils.findMockJdkRtJar()); - - return JetCoreEnvironment.createForTests(getTestRootDisposable(), configuration); + @Override + protected File getKotlinSourceRoot() { + return createTmpDir("kotlin-src"); } @NotNull @@ -56,18 +49,16 @@ public abstract class AbstractKotlinLightClassTest extends KotlinTestWithEnviron return JavaElementFinder.getInstance(environment.getProject()); } - protected void doTest(@NotNull String fileName) throws IOException { - File file = new File(fileName); - + @Override + protected void doMultiFileTest(File file, Map modules, List files) throws IOException { String text = FileUtil.loadFile(file, true); Matcher matcher = SUBJECT_FQ_NAME_PATTERN.matcher(text); assertTrue("No FqName specified. First line of the form '// f.q.Name' expected", matcher.find()); String fqName = matcher.group(1); - JetCoreEnvironment environment = createEnvironment(file); - JavaElementFinder finder = createFinder(environment); + JavaElementFinder finder = createFinder(getEnvironment()); - PsiClass psiClass = finder.findClass(fqName, GlobalSearchScope.allScope(environment.getProject())); + PsiClass psiClass = finder.findClass(fqName, GlobalSearchScope.allScope(getEnvironment().getProject())); if (!(psiClass instanceof KotlinLightClass)) { throw new IllegalStateException("Not a light class: " + psiClass + " (" + fqName + ")"); } @@ -83,4 +74,14 @@ public abstract class AbstractKotlinLightClassTest extends KotlinTestWithEnviron JetTestUtils.assertEqualsToFile(JetTestUtils.replaceExtension(file, "java"), actual); } + + @Override + protected Void createTestModule(String name) { + return null; + } + + @Override + protected Void createTestFile(Void module, String fileName, String text, Map directives) { + return null; + } } diff --git a/compiler/tests/org/jetbrains/jet/asJava/KotlinLightClassTestGenerated.java b/compiler/tests/org/jetbrains/jet/asJava/KotlinLightClassTestGenerated.java index cfe42fd6e19..09c1f896716 100644 --- a/compiler/tests/org/jetbrains/jet/asJava/KotlinLightClassTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/asJava/KotlinLightClassTestGenerated.java @@ -45,6 +45,12 @@ public class KotlinLightClassTestGenerated extends AbstractKotlinLightClassTest JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/delegation"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("ExternalAnnotations.kt") + public void testExternalAnnotations() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/delegation/ExternalAnnotations.kt"); + doTest(fileName); + } + @TestMetadata("Function.kt") public void testFunction() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/delegation/Function.kt"); @@ -56,6 +62,12 @@ public class KotlinLightClassTestGenerated extends AbstractKotlinLightClassTest String fileName = JetTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/delegation/Property.kt"); doTest(fileName); } + + @TestMetadata("WithPlatformTypes.kt") + public void testWithPlatformTypes() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/asJava/lightClasses/nullabilityAnnotations") diff --git a/compiler/tests/org/jetbrains/jet/checkers/KotlinMultiFileTestWithWithJava.java b/compiler/tests/org/jetbrains/jet/checkers/KotlinMultiFileTestWithWithJava.java index e8fc04fab4a..a560f5c29b1 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/KotlinMultiFileTestWithWithJava.java +++ b/compiler/tests/org/jetbrains/jet/checkers/KotlinMultiFileTestWithWithJava.java @@ -25,6 +25,7 @@ import org.jetbrains.jet.JetLiteFixture; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.TestJdkKind; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; +import org.jetbrains.jet.config.CommonConfigurationKeys; import org.jetbrains.jet.config.CompilerConfiguration; import org.jetbrains.jet.utils.UtilsPackage; @@ -68,11 +69,24 @@ public abstract class KotlinMultiFileTestWithWithJava extends JetLiteFixtu Arrays.asList(JetTestUtils.getAnnotationsJar()), Arrays.asList(javaFilesDir) ); + File kotlinSourceRoot = getKotlinSourceRoot(); + if (kotlinSourceRoot != null) { + configuration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, kotlinSourceRoot.getPath()); + } return JetCoreEnvironment.createForTests(getTestRootDisposable(), configuration); } + @Nullable + protected File getKotlinSourceRoot() { + return null; + } + protected File createJavaFilesDir() { - File dir = new File(FileUtil.getTempDirectory(), "java-files"); + return createTmpDir("java-files"); + } + + protected static File createTmpDir(String dirName) { + File dir = new File(FileUtil.getTempDirectory(), dirName); try { JetTestUtils.mkdirs(dir); }