Support [throws] annotation
This commit is contained in:
@@ -19,6 +19,8 @@ package org.jetbrains.jet.codegen;
|
|||||||
import com.intellij.openapi.util.Condition;
|
import com.intellij.openapi.util.Condition;
|
||||||
import com.intellij.openapi.util.io.FileUtil;
|
import com.intellij.openapi.util.io.FileUtil;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import com.intellij.util.ArrayUtil;
|
||||||
|
import com.intellij.util.Function;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import com.intellij.util.containers.Stack;
|
import com.intellij.util.containers.Stack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -28,11 +30,15 @@ import org.jetbrains.jet.codegen.context.CodegenContext;
|
|||||||
import org.jetbrains.jet.codegen.context.PackageContext;
|
import org.jetbrains.jet.codegen.context.PackageContext;
|
||||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
||||||
import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
|
import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||||
import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
|
import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
|
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
|
||||||
|
import org.jetbrains.jet.lang.resolve.constants.*;
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||||
@@ -253,4 +259,34 @@ public class CodegenUtil {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static String[] getExceptions(@NotNull Annotated annotatedDescriptor, @NotNull final JetTypeMapper mapper) {
|
||||||
|
// Can't say 'throws.class', because 'throws' is a reserved work in Java
|
||||||
|
AnnotationDescriptor annotation = annotatedDescriptor.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
|
||||||
|
if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY;
|
||||||
|
|
||||||
|
Collection<CompileTimeConstant<?>> values = annotation.getAllValueArguments().values();
|
||||||
|
if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY;
|
||||||
|
|
||||||
|
Object value = values.iterator().next();
|
||||||
|
if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY;
|
||||||
|
ArrayValue arrayValue = (ArrayValue) value;
|
||||||
|
|
||||||
|
List<String> strings = ContainerUtil.mapNotNull(
|
||||||
|
arrayValue.getValue(),
|
||||||
|
new Function<CompileTimeConstant<?>, String>() {
|
||||||
|
@Override
|
||||||
|
public String fun(CompileTimeConstant<?> constant) {
|
||||||
|
if (constant instanceof JavaClassValue) {
|
||||||
|
JavaClassValue classValue = (JavaClassValue) constant;
|
||||||
|
ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue());
|
||||||
|
return mapper.mapClass(classDescriptor).getInternalName();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return strings.toArray(new String[strings.size()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
|||||||
asmMethod.getName(),
|
asmMethod.getName(),
|
||||||
asmMethod.getDescriptor(),
|
asmMethod.getDescriptor(),
|
||||||
jvmSignature.getGenericsSignature(),
|
jvmSignature.getGenericsSignature(),
|
||||||
null);
|
CodegenUtil.getExceptions(functionDescriptor, typeMapper));
|
||||||
|
|
||||||
if (owner instanceof PackageFacadeContext) {
|
if (owner instanceof PackageFacadeContext) {
|
||||||
Type ownerType = ((PackageFacadeContext) owner).getDelegateToClassType();
|
Type ownerType = ((PackageFacadeContext) owner).getDelegateToClassType();
|
||||||
@@ -462,7 +462,8 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int flags = getVisibilityAccessFlag(constructorDescriptor);
|
int flags = getVisibilityAccessFlag(constructorDescriptor);
|
||||||
MethodVisitor mv = classBuilder.newMethod(null, flags, "<init>", "()V", null, null);
|
MethodVisitor mv = classBuilder.newMethod(null, flags, "<init>", "()V", null,
|
||||||
|
CodegenUtil.getExceptions(constructorDescriptor, state.getTypeMapper()));
|
||||||
|
|
||||||
if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
|
if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
|
||||||
|
|
||||||
@@ -531,7 +532,8 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
|||||||
}
|
}
|
||||||
MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC),
|
MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC),
|
||||||
isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX,
|
isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX,
|
||||||
descriptor, null, null);
|
descriptor, null,
|
||||||
|
CodegenUtil.getExceptions(functionDescriptor, typeMapper));
|
||||||
|
|
||||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||||
generateDefaultImpl(owner, signature, functionDescriptor, isStatic, mv, loadStrategy);
|
generateDefaultImpl(owner, signature, functionDescriptor, isStatic, mv, loadStrategy);
|
||||||
@@ -739,7 +741,8 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
|||||||
|
|
||||||
int flags = ACC_PUBLIC;
|
int flags = ACC_PUBLIC;
|
||||||
|
|
||||||
MethodVisitor mv = v.newMethod(null, flags, delegateMethod.getName(), delegateMethod.getDescriptor(), null, null);
|
MethodVisitor mv = v.newMethod(null, flags, delegateMethod.getName(), delegateMethod.getDescriptor(), null,
|
||||||
|
CodegenUtil.getExceptions(functionDescriptor, typeMapper));
|
||||||
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
|
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
|
||||||
|
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
|
|||||||
@@ -1425,7 +1425,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
Method methodInTrait = typeMapper.mapSignature(fun.getOriginal()).getAsmMethod();
|
Method methodInTrait = typeMapper.mapSignature(fun.getOriginal()).getAsmMethod();
|
||||||
|
|
||||||
PsiElement origin = descriptorToDeclaration(bindingContext, fun);
|
PsiElement origin = descriptorToDeclaration(bindingContext, fun);
|
||||||
MethodVisitor mv = v.newMethod(origin, flags, methodToGenerate.getName(), methodToGenerate.getDescriptor(), null, null);
|
MethodVisitor mv = v.newMethod(origin, flags, methodToGenerate.getName(), methodToGenerate.getDescriptor(), null,
|
||||||
|
CodegenUtil.getExceptions(fun, typeMapper));
|
||||||
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(fun);
|
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(fun);
|
||||||
|
|
||||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
class JavaClass {
|
||||||
|
void testMethod() {
|
||||||
|
Test test = new Test();
|
||||||
|
test.none();
|
||||||
|
|
||||||
|
try {
|
||||||
|
test.one();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
test.two();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
catch (E2 e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class E1: Exception()
|
||||||
|
class E2: Exception()
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
throws()
|
||||||
|
fun none() {}
|
||||||
|
|
||||||
|
throws(javaClass<E1>())
|
||||||
|
fun one() {}
|
||||||
|
|
||||||
|
throws(javaClass<E1>(), javaClass<E2>())
|
||||||
|
fun two() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
class JavaClass {
|
||||||
|
void testMethod() {
|
||||||
|
new None();
|
||||||
|
|
||||||
|
try {
|
||||||
|
new One();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new OneWithParam(1);
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Two();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
catch (E2 e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class E1: Exception()
|
||||||
|
class E2: Exception()
|
||||||
|
|
||||||
|
class None [throws()]() {}
|
||||||
|
class One [throws(javaClass<E1>())]()
|
||||||
|
class Two [throws(javaClass<E1>(), javaClass<E2>())]()
|
||||||
|
|
||||||
|
class OneWithParam [throws(javaClass<E1>())](a: Int)
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
class JavaClass {
|
||||||
|
void testMethod(One instance) {
|
||||||
|
try {
|
||||||
|
new One(1);
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new One(1, 0);
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new One();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
One.one$default(instance, 1, 1);
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_DefaultPackage.one(1);
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_DefaultPackage.one$default(1, 0);
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class E1: Exception()
|
||||||
|
|
||||||
|
throws(javaClass<E1>())
|
||||||
|
fun one(a: Int = 1) {}
|
||||||
|
|
||||||
|
class One [throws(javaClass<E1>())] (a: Int = 1) {
|
||||||
|
throws(javaClass<E1>())
|
||||||
|
fun one(a: Int = 1) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
class JavaClass {
|
||||||
|
void testMethod() {
|
||||||
|
Test test = new Test();
|
||||||
|
test.none();
|
||||||
|
|
||||||
|
try {
|
||||||
|
test.one();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
test.two();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
catch (E2 e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
class E1: Exception()
|
||||||
|
class E2: Exception()
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
throws()
|
||||||
|
fun none()
|
||||||
|
|
||||||
|
throws(javaClass<E1>())
|
||||||
|
fun one()
|
||||||
|
|
||||||
|
throws(javaClass<E1>(), javaClass<E2>())
|
||||||
|
fun two()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Impl: Trait {
|
||||||
|
override fun none() {}
|
||||||
|
override fun one() {}
|
||||||
|
override fun two() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test: Trait by Impl()
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
class JavaClass {
|
||||||
|
void testMethod() {
|
||||||
|
_DefaultPackage.none();
|
||||||
|
|
||||||
|
try {
|
||||||
|
_DefaultPackage.one();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_DefaultPackage.two();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
catch (E2 e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
class E1: Exception()
|
||||||
|
class E2: Exception()
|
||||||
|
|
||||||
|
throws()
|
||||||
|
fun none() {}
|
||||||
|
|
||||||
|
throws(javaClass<E1>())
|
||||||
|
fun one() {}
|
||||||
|
|
||||||
|
throws(javaClass<E1>(), javaClass<E2>())
|
||||||
|
fun two() {}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
class JavaClass {
|
||||||
|
void testMethod() {
|
||||||
|
Test test = new Test();
|
||||||
|
test.none();
|
||||||
|
|
||||||
|
try {
|
||||||
|
test.one();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
test.two();
|
||||||
|
}
|
||||||
|
catch (E1 e) {}
|
||||||
|
catch (E2 e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
class E1: Exception()
|
||||||
|
class E2: Exception()
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
throws()
|
||||||
|
fun none() {}
|
||||||
|
|
||||||
|
throws(javaClass<E1>())
|
||||||
|
fun one() {}
|
||||||
|
|
||||||
|
throws(javaClass<E1>(), javaClass<E2>())
|
||||||
|
fun two() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test: Trait
|
||||||
+1
-1
@@ -35,7 +35,7 @@ public abstract class AbstractCompileJavaAgainstKotlinTest extends TestCaseWithT
|
|||||||
Assert.assertTrue(ktFilePath.endsWith(".kt"));
|
Assert.assertTrue(ktFilePath.endsWith(".kt"));
|
||||||
File ktFile = new File(ktFilePath);
|
File ktFile = new File(ktFilePath);
|
||||||
File javaFile = new File(ktFilePath.replaceFirst("\\.kt", ".java"));
|
File javaFile = new File(ktFilePath.replaceFirst("\\.kt", ".java"));
|
||||||
compileKotlinToDirAndGetAnalyzeExhaust(Collections.singletonList(ktFile), tmpdir, getTestRootDisposable(), ConfigurationKind.JDK_ONLY);
|
compileKotlinToDirAndGetAnalyzeExhaust(Collections.singletonList(ktFile), tmpdir, getTestRootDisposable(), ConfigurationKind.ALL);
|
||||||
|
|
||||||
List<String> options = Arrays.asList(
|
List<String> options = Arrays.asList(
|
||||||
"-classpath", tmpdir.getPath() + System.getProperty("path.separator") + ForTestCompileRuntime.runtimeJarForTests(),
|
"-classpath", tmpdir.getPath() + System.getProperty("path.separator") + ForTestCompileRuntime.runtimeJarForTests(),
|
||||||
|
|||||||
+40
-1
@@ -91,7 +91,7 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method")
|
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method")
|
||||||
@InnerTestClasses({Method.PrimitiveOverride.class})
|
@InnerTestClasses({Method.PrimitiveOverride.class, Method.Throws.class})
|
||||||
public static class Method extends AbstractCompileJavaAgainstKotlinTest {
|
public static class Method extends AbstractCompileJavaAgainstKotlinTest {
|
||||||
public void testAllFilesPresentInMethod() throws Exception {
|
public void testAllFilesPresentInMethod() throws Exception {
|
||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/compileJavaAgainstKotlin/method"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/compileJavaAgainstKotlin/method"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
@@ -260,10 +260,49 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method/throws")
|
||||||
|
public static class Throws extends AbstractCompileJavaAgainstKotlinTest {
|
||||||
|
public void testAllFilesPresentInThrows() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/compileJavaAgainstKotlin/method/throws"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassMembers.kt")
|
||||||
|
public void testClassMembers() throws Exception {
|
||||||
|
doTest("compiler/testData/compileJavaAgainstKotlin/method/throws/ClassMembers.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Constructor.kt")
|
||||||
|
public void testConstructor() throws Exception {
|
||||||
|
doTest("compiler/testData/compileJavaAgainstKotlin/method/throws/Constructor.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("DefaultArgs.kt")
|
||||||
|
public void testDefaultArgs() throws Exception {
|
||||||
|
doTest("compiler/testData/compileJavaAgainstKotlin/method/throws/DefaultArgs.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Delegation.kt")
|
||||||
|
public void testDelegation() throws Exception {
|
||||||
|
doTest("compiler/testData/compileJavaAgainstKotlin/method/throws/Delegation.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("TopLevel.kt")
|
||||||
|
public void testTopLevel() throws Exception {
|
||||||
|
doTest("compiler/testData/compileJavaAgainstKotlin/method/throws/TopLevel.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("TraitMembers.kt")
|
||||||
|
public void testTraitMembers() throws Exception {
|
||||||
|
doTest("compiler/testData/compileJavaAgainstKotlin/method/throws/TraitMembers.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static Test innerSuite() {
|
public static Test innerSuite() {
|
||||||
TestSuite suite = new TestSuite("Method");
|
TestSuite suite = new TestSuite("Method");
|
||||||
suite.addTestSuite(Method.class);
|
suite.addTestSuite(Method.class);
|
||||||
suite.addTestSuite(PrimitiveOverride.class);
|
suite.addTestSuite(PrimitiveOverride.class);
|
||||||
|
suite.addTestSuite(Throws.class);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user