Skip to content

Commit 4ebd259

Browse files
author
dlsmith
committed
DynamicJava: Implemented private and package-private accessibility checks. Added options to Options to turn these checks on or off. Also implemented requireSemicolon() and requireVariableType() options.
git-svn-id: file:///tmp/test-svn/trunk@4987 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent bb37c63 commit 4ebd259

32 files changed

+310
-267
lines changed

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@
55

66
public class Options {
77

8-
public static final Options DEFAULT = new Options(ExtendedTypeSystem.INSTANCE);
8+
public static final Options DEFAULT = new Options();
99

10-
private final TypeSystem _ts;
11-
12-
public Options(TypeSystem ts) { _ts = ts; }
13-
14-
public boolean semicolonIsOptional() { return true; }
15-
public TypeSystem typeSystem() { return _ts; }
10+
/** For default options, use {@link #DEFAULT}; for custom options, create a subclass. */
11+
protected Options() {}
1612

13+
public TypeSystem typeSystem() { return ExtendedTypeSystem.INSTANCE; }
14+
/** Require a semicolon at the end of statements. */
15+
public boolean requireSemicolon() { return false; }
16+
/** Require variable declarations to include an explicit type. */
17+
public boolean requireVariableType() { return false; }
18+
/** Check that all access of class members is permitted by accessibility controls. */
19+
public boolean enforceAllAccess() { return false; }
20+
/** Check that access of private class members is permitted (irrelevant if enforceAllAccess() is true). */
21+
public boolean enforcePrivateAccess() { return false; }
1722
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public Iterable<LocalFunction> getLocalFunctions(String name, TypeSystem ts, Ite
2323
return partial;
2424
}
2525
public LocalVariable getLocalVariable(String name, TypeSystem ts) { return null; }
26-
public String getPackage() { return ""; }
26+
public Access.Module accessModule() { return new TopLevelAccessModule(""); }
2727
public Type getReturnType() { return null; }
2828
public DJClass getThis() { return null; }
2929
public DJClass getThis(String className) { return null; }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ private boolean hasMethod(String name, TypeSystem ts) {
110110
return ts.containsMethod(_thisType, name);
111111
}
112112

113-
113+
114114
/** Return a full name for a class with the given name declared here. */
115115
@Override public String makeClassName(String n) {
116116
return _c.fullName() + "$" + n;

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ private VariableType declaredTypeVariable(String name) {
5454
}
5555

5656
/** Test whether {@code name} is an in-scope top-level class */
57-
public boolean topLevelClassExists(String name, TypeSystem ts) {
57+
@Override public boolean topLevelClassExists(String name, TypeSystem ts) {
5858
return matchesTopLevelClass(name) ||
5959
(!matchesMemberClass(name) && !matchesTypeVariable(name) && super.topLevelClassExists(name, ts));
6060
}
6161

6262
/** Return the top-level class with the given name, or {@code null} if it does not exist. */
63-
public DJClass getTopLevelClass(String name, TypeSystem ts) throws AmbiguousNameException {
63+
@Override public DJClass getTopLevelClass(String name, TypeSystem ts) throws AmbiguousNameException {
6464
if (matchesTopLevelClass(name)) {
6565
return _c;
6666
}
@@ -71,7 +71,7 @@ else if (!matchesMemberClass(name) && !matchesTypeVariable(name)) {
7171
}
7272

7373
/** Test whether {@code name} is an in-scope member class */
74-
public boolean memberClassExists(String name, TypeSystem ts) {
74+
@Override public boolean memberClassExists(String name, TypeSystem ts) {
7575
return matchesMemberClass(name) ||
7676
(!matchesTopLevelClass(name) && !matchesTypeVariable(name) && super.memberClassExists(name, ts));
7777
}
@@ -80,7 +80,7 @@ public boolean memberClassExists(String name, TypeSystem ts) {
8080
* Return the most inner type containing a class with the given name, or {@code null}
8181
* if there is no such type.
8282
*/
83-
public ClassType typeContainingMemberClass(String name, TypeSystem ts) throws AmbiguousNameException {
83+
@Override public ClassType typeContainingMemberClass(String name, TypeSystem ts) throws AmbiguousNameException {
8484
debug.logStart(new String[]{"class","name"}, _c, name); try {
8585

8686
if (matchesMemberClass(name)) {
@@ -95,19 +95,21 @@ else if (!matchesTopLevelClass(name) && !matchesTypeVariable(name)) {
9595
}
9696

9797
/** Test whether {@code name} is an in-scope type variable. */
98-
public boolean typeVariableExists(String name, TypeSystem ts) {
98+
@Override public boolean typeVariableExists(String name, TypeSystem ts) {
9999
return matchesTypeVariable(name) ||
100100
(!matchesClass(name) && super.typeVariableExists(name, ts));
101101
}
102102

103103
/** Return the type variable with the given name, or {@code null} if it does not exist. */
104-
public VariableType getTypeVariable(String name, TypeSystem ts) {
104+
@Override public VariableType getTypeVariable(String name, TypeSystem ts) {
105105
VariableType result = declaredTypeVariable(name);
106106
if (result != null) { return result; }
107107
else if (!matchesClass(name)) { return super.getTypeVariable(name, ts); }
108108
else { return null; }
109109
}
110110

111-
public ClassLoader getClassLoader() { return _loader; }
111+
@Override public ClassLoader getClassLoader() { return _loader; }
112+
113+
@Override public Access.Module accessModule() { return _c.accessModule(); }
112114

113115
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,8 @@ public Iterable<LocalFunction> getLocalFunctions(String name, TypeSystem ts, Ite
178178

179179
/* MISC CONTEXTUAL INFORMATION */
180180

181-
public String getPackage() {
182-
return _next.getPackage();
181+
public Access.Module accessModule() {
182+
return _next.accessModule();
183183
}
184184

185185
/** Return a full name for a class with the given name declared here. */

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

Lines changed: 75 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@
8080
import edu.rice.cs.plt.tuple.Option;
8181
import edu.rice.cs.plt.lambda.Lambda;
8282
import edu.rice.cs.plt.lambda.Lambda2;
83-
import edu.rice.cs.plt.lambda.Thunk;
8483

8584
import edu.rice.cs.dynamicjava.Options;
8685
import edu.rice.cs.dynamicjava.symbol.*;
@@ -191,13 +190,12 @@ public void checkConstructorCall(ConstructorCall node) {
191190

192191
try {
193192
ConstructorInvocation inv = ts.lookupConstructor(type, targs, args, Option.<Type>none());
194-
195-
// TODO: Check accessibility of constructor
196193
// Note that super constructor calls *have to* be accessible, even if accessibility
197194
// checking is turned off -- a call to a private constructor cannot be compiled
198195
// in a way that it will run successfully (since constructor calls are the only code
199196
// that is directly compiled rather than being interpreted, we don't have this problem
200197
// elsewhere)
198+
checkAccessibility(inv.constructor(), node, true);
201199
checkThrownExceptions(inv.thrown(), node);
202200
node.setArguments(CollectUtil.makeList(inv.args()));
203201
setConstructor(node, inv.constructor());
@@ -212,6 +210,44 @@ public void checkConstructorCall(ConstructorCall node) {
212210
}
213211
}
214212

213+
/** Verify that the given symbol is accessible. */
214+
public void checkAccessibility(Access.Limited symbol, Node node) {
215+
checkAccessibility(symbol, node, false);
216+
}
217+
218+
/**
219+
* Verify that the given symbol is accessible. If {@code alwaysCheckPrivate}, private access is
220+
* checked even when the options dictate otherwise.
221+
*/
222+
private void checkAccessibility(Access.Limited symbol, Node node, boolean alwaysCheckPrivate) {
223+
switch (symbol.accessibility()) {
224+
case PRIVATE:
225+
if (alwaysCheckPrivate || opt.enforcePrivateAccess() || opt.enforceAllAccess()) {
226+
if (!symbol.accessModule().equals(context.accessModule())) {
227+
setErrorStrings(node, symbol.declaredName());
228+
throw new ExecutionError("illegal.private.access", node);
229+
}
230+
}
231+
break;
232+
case PACKAGE:
233+
if (opt.enforceAllAccess()) {
234+
if (!symbol.accessModule().packageName().equals(context.accessModule().packageName())) {
235+
setErrorStrings(node, symbol.declaredName());
236+
throw new ExecutionError("illegal.package.access", node);
237+
}
238+
}
239+
break;
240+
case PROTECTED:
241+
if (opt.enforceAllAccess()) {
242+
// TODO: implement protected-access checks
243+
}
244+
break;
245+
case PUBLIC:
246+
// access is always valid
247+
break;
248+
}
249+
}
250+
215251
/** Verify that the thrown exceptions are expected in this context. */
216252
private void checkThrownExceptions(Iterable<? extends Type> thrownTypes, Node node) {
217253
Iterable<Type> allowed = IterUtil.compose(TypeSystem.RUNTIME_EXCEPTION,
@@ -301,7 +337,10 @@ else if (context.fieldExists(first.image(), ts)) {
301337
}
302338
try {
303339
DJClass c = context.getTopLevelClass(className, ts);
304-
if (c != null) { classType = ts.makeClassType(c); }
340+
if (c != null) {
341+
checkAccessibility(c, node);
342+
classType = ts.makeClassType(c);
343+
}
305344
else {
306345
classType = context.getTypeVariable(className, ts);
307346
if (classType == null) {
@@ -332,7 +371,9 @@ else if (ts.containsClass(classType, memberName.image())) {
332371
className += "." + last.image();
333372
classIds.add(last);
334373
try {
335-
classType = ts.lookupStaticClass(classType, memberName.image(), IterUtil.<Type>empty());
374+
ClassType memberType = ts.lookupStaticClass(classType, memberName.image(), IterUtil.<Type>empty());
375+
checkAccessibility(memberType.ofClass(), node);
376+
classType = memberType;
336377
}
337378
catch (InvalidTargetException e) { throw new RuntimeException("ts.containsClass lied"); }
338379
catch (InvalidTypeArgumentException e) { throw new ExecutionError("type.argument.arity", node); }
@@ -430,8 +471,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
430471
setType(obj, t);
431472
ref = ts.lookupField(obj, node.getFieldName());
432473
}
433-
434-
// TODO: Check accessibility of field
474+
checkAccessibility(ref.field(), node);
435475
setField(node, ref.field());
436476
setVariableType(node, ref.type());
437477
if (!ref.field().isStatic()) {
@@ -459,7 +499,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
459499
try {
460500
ObjectFieldReference ref = ts.lookupField(receiver, node.getFieldName());
461501
node.setExpression(ref.object());
462-
// TODO: Check accessibility of field
502+
checkAccessibility(ref.field(), node);
463503
setField(node, ref.field());
464504
setVariableType(node, ref.type());
465505
Type result = ts.capture(ref.type());
@@ -486,7 +526,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
486526
setType(obj, t);
487527
try {
488528
FieldReference ref = ts.lookupField(obj, node.getFieldName());
489-
// TODO: Check accessibility of field
529+
checkAccessibility(ref.field(), node);
490530
setField(node, ref.field());
491531
setDJClass(node, c);
492532
setVariableType(node, ref.type());
@@ -508,7 +548,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
508548
Type t = checkTypeName(node.getFieldType());
509549
try {
510550
FieldReference ref = ts.lookupStaticField(t, node.getFieldName());
511-
// TODO: Check accessibility of field
551+
checkAccessibility(ref.field(), node);
512552
setField(node, ref.field());
513553
setVariableType(node, ref.type());
514554
Type result = ts.capture(ref.type());
@@ -517,7 +557,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
517557
}
518558
catch (TypeSystemException e) {
519559
setErrorStrings(node, ts.userRepresentation(t), node.getFieldName());
520-
throw new ExecutionError("no.such.field", node);
560+
throw new ExecutionError("no.such.static.field", node);
521561
}
522562
}
523563

@@ -534,7 +574,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
534574
ClassType t;
535575
if (context.localFunctionExists(node.getMethodName(), ts)) {
536576
Iterable<LocalFunction> matches = context.getLocalFunctions(node.getMethodName(), ts);
537-
t = ts.makeClassType(new FunctionWrapperClass(context.getPackage(), matches));
577+
t = ts.makeClassType(new FunctionWrapperClass(context.accessModule(), matches));
538578
}
539579
else {
540580
try {
@@ -557,8 +597,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
557597
setType(obj, t);
558598
inv = ts.lookupMethod(obj, node.getMethodName(), targs, args, expected);
559599
}
560-
561-
// TODO: Check accessibility of method
600+
checkAccessibility(inv.method(), node);
562601
checkThrownExceptions(inv.thrown(), node);
563602
node.setArguments(CollectUtil.makeList(inv.args()));
564603
setMethod(node, inv.method());
@@ -620,7 +659,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
620659
try {
621660
// Note: Changes made below may also need to be made in the TypeSystem's boxing & unboxing implementations
622661
ObjectMethodInvocation inv = ts.lookupMethod(receiver, node.getMethodName(), targs, args, expected);
623-
// TODO: Check accessibility of method
662+
checkAccessibility(inv.method(), node);
624663
checkThrownExceptions(inv.thrown(), node);
625664
node.setExpression(inv.object());
626665
node.setArguments(CollectUtil.makeList(inv.args()));
@@ -662,7 +701,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
662701
setType(obj, t);
663702
try {
664703
MethodInvocation inv = ts.lookupMethod(obj, node.getMethodName(), targs, args, expected);
665-
// TODO: Check accessibility of method
704+
checkAccessibility(inv.method(), node);
666705
checkThrownExceptions(inv.thrown(), node);
667706
node.setArguments(CollectUtil.makeList(inv.args()));
668707
setMethod(node, inv.method());
@@ -699,7 +738,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
699738
try {
700739
// Note: Changes made below may also need to be made in the TypeSystem's boxing & unboxing implementations
701740
MethodInvocation inv = ts.lookupStaticMethod(t, node.getMethodName(), targs, args, expected);
702-
// TODO: Check accessibility of method
741+
checkAccessibility(inv.method(), node);
703742
checkThrownExceptions(inv.thrown(), node);
704743
node.setArguments(CollectUtil.makeList(inv.args()));
705744
setMethod(node, inv.method());
@@ -713,7 +752,7 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
713752
}
714753
catch (TypeSystemException e) {
715754
setErrorStrings(node, ts.userRepresentation(t), node.getMethodName(), nodeTypesString(args));
716-
throw new ExecutionError("no.such.method", node);
755+
throw new ExecutionError("no.such.static.method", node);
717756
}
718757
}
719758

@@ -812,7 +851,7 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
812851

813852
try {
814853
ConstructorInvocation inv = ts.lookupConstructor(t, targs, args, expected);
815-
// TODO: Check accessibility of constructor
854+
checkAccessibility(inv.constructor(), node);
816855
checkThrownExceptions(inv.thrown(), node);
817856
node.setArguments(CollectUtil.makeList(inv.args()));
818857
setConstructor(node, inv.constructor());
@@ -850,7 +889,7 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
850889
// Super constructor invocation is something besides Object()
851890
try {
852891
ConstructorInvocation inv = ts.lookupConstructor(t, targs, args, expected);
853-
// TODO: Check accessibility of constructor
892+
checkAccessibility(inv.constructor(), node);
854893
checkThrownExceptions(inv.thrown(), node);
855894
node.setArguments(CollectUtil.makeList(inv.args()));
856895
}
@@ -864,7 +903,7 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
864903
}
865904

866905
TreeClassLoader loader = new TreeClassLoader(context.getClassLoader(), opt);
867-
TreeClass c = new TreeClass(context.makeAnonymousClassName(), null, node, loader, opt);
906+
TreeClass c = new TreeClass(context.makeAnonymousClassName(), null, context.accessModule(), node, loader, opt);
868907
setDJClass(node, c);
869908
ClassChecker checker = new ClassChecker(c, loader, context, opt);
870909
checker.initializeClassSignatures(node);
@@ -888,8 +927,12 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
888927
}
889928

890929
try {
891-
Type t = ts.lookupClass(node.getExpression(), node.getClassName(), classTargs);
892-
// TODO: Check that t is not a static member of enclosing
930+
ClassType t = ts.lookupClass(node.getExpression(), node.getClassName(), classTargs);
931+
checkAccessibility(t.ofClass(), node);
932+
if (t.ofClass().isStatic()) {
933+
setErrorStrings(node, node.getClassName(), ts.userRepresentation(getType(node.getExpression())));
934+
throw new ExecutionError("static.inner.allocation", node);
935+
}
893936
if (!ts.isConcrete(t)) {
894937
throw new ExecutionError("allocation.type", node);
895938
}
@@ -904,7 +947,7 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
904947

905948
try {
906949
ConstructorInvocation inv = ts.lookupConstructor(t, targs, args, expected);
907-
// TODO: Check accessibility of constructor
950+
checkAccessibility(inv.constructor(), node);
908951
checkThrownExceptions(inv.thrown(), node);
909952
node.setArguments(CollectUtil.makeList(inv.args()));
910953
setConstructor(node, inv.constructor());
@@ -940,8 +983,12 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
940983
}
941984

942985
try {
943-
Type t = ts.lookupClass(node.getExpression(), node.getClassName(), classTargs);
944-
// TODO: Check that t is not a static member of enclosing
986+
ClassType t = ts.lookupClass(node.getExpression(), node.getClassName(), classTargs);
987+
checkAccessibility(t.ofClass(), node);
988+
if (t.ofClass().isStatic()) {
989+
setErrorStrings(node, node.getClassName(), ts.userRepresentation(getType(node.getExpression())));
990+
throw new ExecutionError("static.inner.allocation", node);
991+
}
945992
if (!ts.isExtendable(t)) {
946993
throw new ExecutionError("allocation.type", node);
947994
}
@@ -957,7 +1004,7 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
9571004

9581005
try {
9591006
ConstructorInvocation inv = ts.lookupConstructor(t, targs, args, expected);
960-
// TODO: Check accessibility of constructor
1007+
checkAccessibility(inv.constructor(), node);
9611008
checkThrownExceptions(inv.thrown(), node);
9621009
node.setArguments(CollectUtil.makeList(inv.args()));
9631010
}
@@ -978,7 +1025,7 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
9781025
}
9791026

9801027
TreeClassLoader loader = new TreeClassLoader(context.getClassLoader(), opt);
981-
TreeClass c = new TreeClass(context.makeAnonymousClassName(), null, node, loader, opt);
1028+
TreeClass c = new TreeClass(context.makeAnonymousClassName(), null, context.accessModule(), node, loader, opt);
9821029
setDJClass(node, c);
9831030
ClassChecker checker = new ClassChecker(c, loader, context, opt);
9841031
checker.initializeClassSignatures(node);

0 commit comments

Comments
 (0)