Report error on using reflection without kotlin-reflect.jar in classpath

Should be a warning because strictly speaking, the codegen doesn't need it
during the compilation. It's an error at the moment only to let all clients of
Kotlin reflection know that they must include kotlin-reflect.jar in the
classpath
This commit is contained in:
Alexander Udalov
2015-03-12 22:29:49 +03:00
parent 9d6f4e99a1
commit 094fa2f92b
9 changed files with 63 additions and 17 deletions
@@ -65,6 +65,7 @@ import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant;
import org.jetbrains.kotlin.resolve.constants.evaluate.EvaluatePackage;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.resolve.scopes.receivers.*;
import org.jetbrains.kotlin.types.Approximation;
@@ -97,6 +98,7 @@ import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin;
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.TraitImpl;
import static org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
import static org.jetbrains.kotlin.serialization.deserialization.DeserializationPackage.findClassAcrossModuleDependencies;
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implements LocalLookup {
@@ -2665,6 +2667,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Override
public StackValue visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, StackValue data) {
checkReflectionIsAvailable(expression);
JetType type = bindingContext.get(EXPRESSION_TYPE, expression);
assert type != null;
@@ -2687,25 +2691,34 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
if (variableDescriptor != null) {
VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor();
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration instanceof PackageFragmentDescriptor) {
return generateTopLevelPropertyReference(descriptor);
}
else if (containingDeclaration instanceof ClassDescriptor) {
return generateMemberPropertyReference(descriptor, (ClassDescriptor) containingDeclaration);
}
else if (containingDeclaration instanceof ScriptDescriptor) {
return generateMemberPropertyReference(descriptor, ((ScriptDescriptor) containingDeclaration).getClassDescriptor());
}
else {
throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration);
}
if (variableDescriptor == null) {
throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
}
throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
// TODO: this diagnostic should also be reported on function references once they obtain reflection
checkReflectionIsAvailable(expression);
VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor();
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration instanceof PackageFragmentDescriptor) {
return generateTopLevelPropertyReference(descriptor);
}
else if (containingDeclaration instanceof ClassDescriptor) {
return generateMemberPropertyReference(descriptor, (ClassDescriptor) containingDeclaration);
}
else if (containingDeclaration instanceof ScriptDescriptor) {
return generateMemberPropertyReference(descriptor, ((ScriptDescriptor) containingDeclaration).getClassDescriptor());
}
else {
throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration);
}
}
private void checkReflectionIsAvailable(@NotNull JetExpression expression) {
if (findClassAcrossModuleDependencies(state.getModule(), JvmAbi.REFLECTION_FACTORY_IMPL) == null) {
state.getDiagnostics().report(ErrorsJvm.NO_REFLECTION_IN_CLASS_PATH.on(expression, expression));
}
}
@NotNull
@@ -124,6 +124,8 @@ public class GenerationState {
@NotNull
private final ModuleDescriptor module;
private final DiagnosticSink diagnostics;
@NotNull
private final Collection<FqName> packagesWithObsoleteParts;
@@ -182,6 +184,7 @@ public class GenerationState {
builderFactory = new OptimizationClassBuilderFactory(builderFactory);
}
this.diagnostics = diagnostics;
this.classFileFactory = new ClassFileFactory(this, new BuilderFactoryForDuplicateSignatureDiagnostics(
builderFactory, this.bindingContext, diagnostics));
@@ -271,6 +274,11 @@ public class GenerationState {
return runtimeTypes;
}
@NotNull
public DiagnosticSink getDiagnostics() {
return diagnostics;
}
public boolean isInlineEnabled() {
return !disableInline;
}
@@ -53,6 +53,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
MAP.put(ErrorsJvm.NATIVE_DECLARATION_IN_TRAIT, "Members of traits can not be native");
MAP.put(ErrorsJvm.NATIVE_DECLARATION_CANNOT_BE_INLINED, "Members of traits can not be inlined");
MAP.put(ErrorsJvm.NO_REFLECTION_IN_CLASS_PATH, "Expression ''{0}'' uses reflection which is not found in compilation classpath. Make sure you have kotlin-reflect.jar in the classpath", Renderers.ELEMENT_TEXT);
MAP.put(ErrorsJvm.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS,
"Expected type does not accept nulls in {0}, but the value may be null in {1}", Renderers.TO_STRING, Renderers.TO_STRING);
}
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.psi.JetDeclaration;
import org.jetbrains.kotlin.psi.JetElement;
import org.jetbrains.kotlin.psi.JetExpression;
import static org.jetbrains.kotlin.diagnostics.PositioningStrategies.*;
import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
@@ -46,6 +47,9 @@ public interface ErrorsJvm {
DiagnosticFactory0<JetDeclaration> NATIVE_DECLARATION_IN_TRAIT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<JetDeclaration> NATIVE_DECLARATION_CANNOT_BE_INLINED = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
// TODO: make this a warning
DiagnosticFactory1<JetExpression, JetExpression> NO_REFLECTION_IN_CLASS_PATH = DiagnosticFactory1.create(ERROR);
enum NullabilityInformationSource {
KOTLIN {
@NotNull
@@ -0,0 +1,3 @@
$TESTDATA_DIR$/noReflectionInClasspath.kt
-d
$TEMP_DIR$
@@ -0,0 +1,4 @@
class Foo(val prop: Any)
fun t1() = Foo::prop
fun t2() = Foo::class
@@ -0,0 +1,3 @@
ERROR: compiler/testData/cli/jvm/noReflectionInClasspath.kt: (3, 12) Expression 'Foo::prop' uses reflection which is not found in compilation classpath. Make sure you have kotlin-reflect.jar in the classpath
ERROR: compiler/testData/cli/jvm/noReflectionInClasspath.kt: (4, 12) Expression 'Foo::class' uses reflection which is not found in compilation classpath. Make sure you have kotlin-reflect.jar in the classpath
COMPILATION_ERROR
@@ -90,6 +90,12 @@ public class KotlincExecutableTestGenerated extends AbstractKotlincExecutableTes
doJvmTest(fileName);
}
@TestMetadata("noReflectionInClasspath.args")
public void testNoReflectionInClasspath() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/cli/jvm/noReflectionInClasspath.args");
doJvmTest(fileName);
}
@TestMetadata("nonExistingClassPathAndAnnotationsPath.args")
public void testNonExistingClassPathAndAnnotationsPath() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/cli/jvm/nonExistingClassPathAndAnnotationsPath.args");
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.load.java;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
public final class JvmAbi {
@@ -41,6 +43,7 @@ public final class JvmAbi {
public static final String KOTLIN_CLASS_FIELD_NAME = "$kotlinClass";
public static final String KOTLIN_PACKAGE_FIELD_NAME = "$kotlinPackage";
public static final ClassId REFLECTION_FACTORY_IMPL = ClassId.topLevel(new FqName("kotlin.reflect.jvm.internal.ReflectionFactoryImpl"));
//TODO: To be removed after kotlin M11
@Deprecated