Skip to content

Commit ead4346

Browse files
author
dlsmith
committed
DynamicJava:
- Supports annotation declarations - Fixes parser bug for enums - Fixes implicit accessibility of interface members - Fixes checking of assignments from character literals - Improves checking of casts - getClass() is a special method with type Class<C> for all classes - Improves error messages for innner class references - Preserves location in wildcards - Catches errors that occur during static initialization of a class - Adds a classpath option for running from the command line - Misc improvements to SoureChecker git-svn-id: file:///tmp/test-svn/trunk@5213 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent be90288 commit ead4346

File tree

19 files changed

+524
-197
lines changed

19 files changed

+524
-197
lines changed

dynamicjava/lib/plt.jar

154 Bytes
Binary file not shown.

dynamicjava/src/edu/rice/cs/dynamicjava/DynamicJava.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import edu.rice.cs.plt.tuple.Option;
55
import edu.rice.cs.plt.tuple.OptionVisitor;
66
import edu.rice.cs.plt.text.TextUtil;
7+
import edu.rice.cs.plt.text.ArgumentParser;
8+
import edu.rice.cs.plt.io.IOUtil;
9+
import edu.rice.cs.plt.reflect.PathClassLoader;
710
import edu.rice.cs.dynamicjava.interpreter.Interpreter;
811
import edu.rice.cs.dynamicjava.interpreter.InterpreterException;
912

@@ -15,14 +18,29 @@ private DynamicJava() {}
1518

1619
public static void main(String... args) throws IOException {
1720
debug.log();
18-
Interpreter i = new Interpreter(Options.DEFAULT);
21+
22+
ArgumentParser argParser = new ArgumentParser();
23+
argParser.supportOption("classpath", IOUtil.WORKING_DIRECTORY.toString());
24+
argParser.supportAlias("cp", "classpath");
25+
ArgumentParser.Result parsedArgs = argParser.parse(args);
26+
Iterable<File> cp = IOUtil.parsePath(parsedArgs.getUnaryOption("classpath"));
27+
28+
Interpreter i = new Interpreter(Options.DEFAULT, new PathClassLoader(cp));
1929
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
30+
String prev = null;
31+
boolean blank = false;
2032
String input;
2133
do {
2234
System.out.print("> ");
2335
System.out.flush();
2436
input = in.readLine();
2537
if (input != null) {
38+
// two blank lines trigger a recompute
39+
if (input.equals("")) {
40+
if (blank == true) { input = prev; blank = false; }
41+
else { blank = true; }
42+
}
43+
else { prev = input; blank = false; }
2644
try {
2745
Option<Object> result = i.interpret(input);
2846
result.apply(new OptionVisitor<Object, Void>() {

dynamicjava/src/edu/rice/cs/dynamicjava/interpreter/StatementChecker.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ private Type checkTypeName(TypeName t) {
223223
return context.importMemberClass(t.ofClass(), split.second());
224224
}
225225
else {
226-
setErrorStrings(node, split.second());
227-
throw new ExecutionError("undefined.class", node);
226+
setErrorStrings(node, ts.typePrinter().print(t), split.second());
227+
throw new ExecutionError("no.such.inner.class", node);
228228
}
229229
}
230230
}
@@ -267,7 +267,7 @@ private ClassType resolveClassName(String name, Node node) {
267267
try { result = ts.lookupClass(result, piece, IterUtil.<Type>empty(), context.accessModule()); }
268268
catch (InvalidTypeArgumentException e) { throw new RuntimeException("can't create raw type"); }
269269
catch (UnmatchedLookupException e) {
270-
setErrorStrings(node, piece);
270+
setErrorStrings(node, ts.typePrinter().print(result), piece);
271271
if (e.matches() > 1) { throw new ExecutionError("ambiguous.inner.class", node); }
272272
else { throw new ExecutionError("no.such.inner.class", node); }
273273
}
@@ -572,7 +572,7 @@ else if (switchEnum) {
572572
throw new ExecutionError("invalid.constant", exp);
573573
}
574574
if (!ts.isAssignable(t, getType(exp), getValue(exp))) {
575-
setErrorStrings(node, ts.typePrinter().print(getType(exp)));
575+
setErrorStrings(exp, ts.typePrinter().print(getType(exp)));
576576
throw new ExecutionError("switch.label.type", exp);
577577
}
578578
if (values.contains(getValue(exp))) {

dynamicjava/src/edu/rice/cs/dynamicjava/sourcechecker/SourceChecker.java

Lines changed: 151 additions & 43 deletions
Large diffs are not rendered by default.
Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
package edu.rice.cs.dynamicjava.symbol;
22

3-
import static edu.rice.cs.plt.debug.DebugUtil.debug;
4-
5-
import java.lang.reflect.InvocationTargetException;
63
import java.lang.reflect.Method;
7-
84
import edu.rice.cs.plt.iter.IterUtil;
9-
import edu.rice.cs.plt.lambda.WrappedException;
10-
import edu.rice.cs.dynamicjava.Options;
11-
import edu.rice.cs.dynamicjava.interpreter.EvaluatorException;
12-
import edu.rice.cs.dynamicjava.interpreter.RuntimeBindings;
135
import edu.rice.cs.dynamicjava.symbol.type.ArrayType;
146
import edu.rice.cs.dynamicjava.symbol.type.Type;
157
import edu.rice.cs.dynamicjava.symbol.type.VariableType;
@@ -19,7 +11,7 @@
1911
* This overrides {@link Object#clone}, giving it public access, eliminating the
2012
* CloneNotSupported {@code throws} clause, and refining the return type.
2113
*/
22-
public class ArrayCloneMethod implements DJMethod {
14+
public class ArrayCloneMethod extends SpecialMethod {
2315

2416
private final ArrayType _type;
2517

@@ -39,26 +31,8 @@ public class ArrayCloneMethod implements DJMethod {
3931
public Access accessibility() { return Access.PUBLIC; }
4032
public Access.Module accessModule() { return new TopLevelAccessModule("java.lang"); }
4133

42-
public DJMethod declaredSignature() { return this; }
43-
public Object evaluate(Object receiver, Iterable<Object> args, RuntimeBindings bindings,
44-
Options options) throws EvaluatorException {
45-
if (receiver == null) {
46-
throw new WrappedException(new EvaluatorException(new NullPointerException()));
47-
}
48-
try {
49-
Method clone = Object.class.getDeclaredMethod("clone");
50-
try { clone.setAccessible(true); /* override protected access */ }
51-
catch (SecurityException e) { debug.log(e); /* ignore -- we can't relax accessibility */ }
52-
return clone.invoke(receiver, IterUtil.toArray(args, Object.class));
53-
}
54-
catch (NoSuchMethodException e) { throw new RuntimeException(e); }
55-
catch (InvocationTargetException e) { throw new EvaluatorException(e.getCause(), EXTRA_STACK); }
56-
catch (IllegalAccessException e) { throw new RuntimeException(e); }
34+
protected Method implementation() throws NoSuchMethodException {
35+
return Object.class.getDeclaredMethod("clone");
5736
}
58-
59-
private static final String[] EXTRA_STACK =
60-
new String[] { "java.lang.reflect.Method.invoke",
61-
"sun.reflect.DelegatingMethodAccessorImpl.invoke",
62-
"sun.reflect.NativeMethodAccessorImpl.invoke",
63-
"sun.reflect.NativeMethodAccessorImpl.invoke0" };
37+
6438
}

dynamicjava/src/edu/rice/cs/dynamicjava/symbol/ExtendedTypeSystem.java

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ public class ExtendedTypeSystem extends StandardTypeSystem {
3030
/** Whether the inference algorithm should attempt to pack capture variables that appear as inference results. */
3131
private final boolean _packCaptureVars;
3232

33-
public ExtendedTypeSystem(Options opt) { this(opt, true, true); }
33+
public ExtendedTypeSystem(Options opt) { this(opt, true, true, true, true); }
3434

35-
public ExtendedTypeSystem(Options opt, boolean packCaptureVars, boolean boxingInMostSpecific) {
36-
super(opt, boxingInMostSpecific);
35+
public ExtendedTypeSystem(Options opt, boolean packCaptureVars, boolean boxingInMostSpecific,
36+
boolean useExplicitTypeArgs, boolean strictClassEquality) {
37+
super(opt, boxingInMostSpecific, useExplicitTypeArgs, strictClassEquality);
3738
_packCaptureVars = packCaptureVars;
3839
}
3940

@@ -291,6 +292,9 @@ public Boolean value() {
291292
@Override public Boolean forClassType(final ClassType superT) {
292293
return recurOnClassParent(immediateSupertype(subT));
293294
}
295+
@Override public Boolean forSimpleClassType(final SimpleClassType superT) {
296+
return sameClass(subT, superT) || forClassType(superT);
297+
}
294298
});
295299
}
296300

@@ -300,8 +304,11 @@ public Boolean value() {
300304
@Override public Boolean forClassType(final ClassType superT) {
301305
return recurOnClassParent(immediateSupertype(subT));
302306
}
307+
@Override public Boolean forRawClassType(final RawClassType superT) {
308+
return sameClass(subT, superT) || forClassType(superT);
309+
}
303310
@Override public Boolean forParameterizedClassType(final ParameterizedClassType superT) {
304-
if (subT.ofClass().equals(superT.ofClass())) {
311+
if (sameClass(subT, superT)) {
305312
return recurOnClassParent(parameterize(subT)) || forClassType(superT);
306313
}
307314
else { return forClassType(superT); }
@@ -316,7 +323,7 @@ public Boolean value() {
316323
return recurOnClassParent(immediateSupertype(subT)) || recurOnClassParent(erase(subT));
317324
}
318325
@Override public Boolean forParameterizedClassType(final ParameterizedClassType superT) {
319-
if (subT.ofClass().equals(superT.ofClass())) {
326+
if (sameClass(subT, superT)) {
320327
boolean containedArgs = true;
321328
ParameterizedClassType subCapT = capture(subT);
322329
for (final Pair<Type, Type> args : IterUtil.zip(subCapT.typeArguments(),
@@ -778,15 +785,31 @@ protected Iterable<Type> inferTypeArguments(Iterable<? extends VariableType> tpa
778785

779786
//debug.logValue("constraints", constraints);
780787
if (!transConstraints.isSatisfiable()) { return null; }
788+
789+
final Set<VariableType> inputTParams = new HashSet<VariableType>();
790+
for (VariableType tparam : tparams) {
791+
for (Type t : params) {
792+
if (containsVar(t, tparam)) { inputTParams.add(tparam); break; }
793+
}
794+
}
781795

782-
// try to use packed lower bounds
796+
// try to use packed bounds
783797
if (_packCaptureVars) {
784798
for (final ConstraintScenario s : transConstraints.scenarios()) {
785799
Iterable<Type> result = IterUtil.mapSnapshot(tparams, new Lambda<VariableType, Type>() {
786800
public Type value(VariableType param) {
787801
Type result = s.lowerBound(param);
788-
while (result instanceof VariableType && ((VariableType) result).symbol().generated()) {
789-
result = ((VariableType) result).symbol().upperBound();
802+
// use upper bound for input variables with a null lower bound
803+
if (result.equals(NULL) && inputTParams.contains(param)) {
804+
result = s.upperBound(param);
805+
while (result instanceof VariableType && ((VariableType) result).symbol().generated()) {
806+
result = ((VariableType) result).symbol().lowerBound();
807+
}
808+
}
809+
else {
810+
while (result instanceof VariableType && ((VariableType) result).symbol().generated()) {
811+
result = ((VariableType) result).symbol().upperBound();
812+
}
790813
}
791814
return result;
792815
}
@@ -795,15 +818,20 @@ public Type value(VariableType param) {
795818
}
796819
}
797820

798-
// packed lower bounds don't work, try to use lower bounds
821+
// packed bounds don't work, try to use bounds
799822
for (final ConstraintScenario s : transConstraints.scenarios()) {
800823
Iterable<Type> result = IterUtil.mapSnapshot(tparams, new Lambda<VariableType, Type>() {
801-
public Type value(VariableType param) { return s.lowerBound(param); }
824+
public Type value(VariableType param) {
825+
Type result = s.lowerBound(param);
826+
// use upper bound for input variables with a null lower bound
827+
if (result.equals(NULL) && inputTParams.contains(param)) { result = s.upperBound(param); }
828+
return result;
829+
}
802830
});
803831
if (inBounds(tparams, result)) { return result; }
804832
}
805833

806-
// lower bounds don't work, try to use capture variables
834+
// bounds don't work, try to use capture variables
807835
for (ConstraintScenario s : transConstraints.scenarios()) {
808836
List<Wildcard> constraintWs = new LinkedList<Wildcard>();
809837
for (VariableType param : tparams) {
@@ -897,9 +925,14 @@ public ConstraintFormula value() {
897925
else { return subtypeNorm(argSuper, param); }
898926
}
899927

928+
@Override public ConstraintFormula forRawClassType(RawClassType arg) {
929+
if (sameClass(arg, param)) { return subtypeNorm(parameterize(arg), param); }
930+
else { return forClassType(arg); }
931+
}
932+
900933
@Override public ConstraintFormula forParameterizedClassType(final ParameterizedClassType arg) {
901934
ConstraintFormula cf = FALSE;
902-
if (param.ofClass().equals(arg.ofClass())) {
935+
if (sameClass(param, arg)) {
903936
Thunk<ConstraintFormula> recurOnTargs = new Thunk<ConstraintFormula>() {
904937
public ConstraintFormula value() {
905938
ParameterizedClassType argCap = capture(arg);
@@ -1068,9 +1101,14 @@ public ConstraintFormula value() {
10681101
else { return supertypeNorm(arg, paramSuper); }
10691102
}
10701103

1104+
@Override public ConstraintFormula forRawClassType(RawClassType arg) {
1105+
if (sameClass(arg, param)) { return TRUE; }
1106+
else { return forClassType(arg); }
1107+
}
1108+
10711109
@Override public ConstraintFormula forParameterizedClassType(final ParameterizedClassType arg) {
10721110
ConstraintFormula cf = FALSE;
1073-
if (param.ofClass().equals(arg.ofClass())) {
1111+
if (sameClass(param, arg)) {
10741112
Thunk<ConstraintFormula> recurOnTargs = new Thunk<ConstraintFormula>() {
10751113
public ConstraintFormula value() {
10761114
ParameterizedClassType paramCap = capture(param);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package edu.rice.cs.dynamicjava.symbol;
2+
3+
import java.lang.reflect.Method;
4+
import edu.rice.cs.plt.iter.IterUtil;
5+
import edu.rice.cs.dynamicjava.symbol.type.ClassType;
6+
import edu.rice.cs.dynamicjava.symbol.type.Type;
7+
import edu.rice.cs.dynamicjava.symbol.type.VariableType;
8+
import edu.rice.cs.dynamicjava.symbol.type.Wildcard;
9+
10+
/**
11+
* Provides a DJMethod interface for accessing a class's implicit "getClass()" method.
12+
* This overrides {@link Object#getClass}, refining the return type.
13+
*/
14+
public class GetClassMethod extends SpecialMethod {
15+
16+
private final DJClass CLASS = SymbolUtil.wrapClass(Class.class);
17+
18+
private final DJClass _c;
19+
private final Type _returnType;
20+
21+
public GetClassMethod(ClassType t, TypeSystem ts) {
22+
_c = t.ofClass();
23+
Wildcard w = new Wildcard(new BoundedSymbol(new Object(), ts.erase(t), TypeSystem.NULL));
24+
Type returnType;
25+
try { returnType = ts.makeClassType(CLASS, IterUtil.singleton(w)); }
26+
catch (TypeSystem.InvalidTypeArgumentException e) { returnType = ts.makeClassType(CLASS); }
27+
_returnType = returnType;
28+
}
29+
30+
public String declaredName() { return "getClass"; }
31+
public DJClass declaringClass() { return _c; }
32+
33+
public Iterable<VariableType> typeParameters() { return IterUtil.empty(); }
34+
public Iterable<LocalVariable> parameters() { return IterUtil.empty(); }
35+
public Type returnType() { return _returnType; }
36+
public Iterable<Type> thrownTypes() { return IterUtil.empty(); }
37+
38+
public boolean isStatic() { return false; }
39+
public boolean isAbstract() { return false; }
40+
public boolean isFinal() { return false; }
41+
public Access accessibility() { return Access.PUBLIC; }
42+
public Access.Module accessModule() { return _c.accessModule(); }
43+
44+
protected Method implementation() throws NoSuchMethodException {
45+
return Object.class.getDeclaredMethod("getClass");
46+
}
47+
48+
}

0 commit comments

Comments
 (0)