Skip to content

Commit e58ae58

Browse files
author
rcartwright
committed
This revision adds some null checks to make syntax checking and type
checking more robust in the presence of errors. It also eliminates a ban on extending Runnable in the functional level. The following files were modified: M src/edu/rice/cs/javalanglevels/TypeChecker.java M src/edu/rice/cs/javalanglevels/VariableData.java M src/edu/rice/cs/javalanglevels/IntermediateVisitor.java M src/edu/rice/cs/javalanglevels/SymbolData.java M src/edu/rice/cs/javalanglevels/Augmentor.java M src/edu/rice/cs/javalanglevels/FullJavaVisitor.java M src/edu/rice/cs/javalanglevels/LanguageLevelVisitor.java git-svn-id: file:///tmp/test-svn/trunk@5392 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent d933be2 commit e58ae58

File tree

7 files changed

+80
-70
lines changed

7 files changed

+80
-70
lines changed

javalanglevels/src/edu/rice/cs/javalanglevels/Augmentor.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,17 +350,15 @@ public Void forInnerClassDef(InnerClassDef cd) {
350350
// return null;
351351
// }
352352

353-
/** Look up this top level interface in the symbolTable, and then visit its body.
354-
* Write any necessary extra variable definitions at the end of the file.
355-
* InterfaceDefs can only appear at the top level of a source file.
353+
/** Look up this top level interface in the symbolTable, and then visit its body. Write any necessary extra variable
354+
* definitions at the end of the file. InterfaceDefs can only appear at the top level of a source file.
356355
* @param cd The InterfaceDef being augmented.
357356
*/
358357
public Void forInterfaceDef(InterfaceDef cd) {
359358
String interfaceName = cd.getName().getText();
360359
SymbolData sd = _llv.symbolTable.get(_llv.getQualifiedClassName(interfaceName));
361360
if (sd == null) { throw new RuntimeException("Internal Program Error: Can't find SymbolData for " +
362361
cd.getName().getText() + ". Please report this bug."); }
363-
364362
ModifiersAndVisibility m = cd.getMav();
365363

366364
/* Make interfaces public by default? */

javalanglevels/src/edu/rice/cs/javalanglevels/FullJavaVisitor.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,13 @@ public Void forInterfaceDef(InterfaceDef that) {
347347

348348
String className = getQualifiedClassName(that.getName().getText());
349349
// if (className.equals("listFW.IList")) System.err.println("Attempting to define symbol " + className);
350-
SymbolData sd = defineSymbolData(that, className); //TODO: should this statement follow interface processing in 345
351-
350+
351+
SymbolData sd = defineSymbolData(that, className);
352+
// TODO: should the preceding statement follow interface processing in 345
353+
354+
// Note: sd can only be null if an error occurs in defineSymbol
355+
if (sd != null) sd.setInterface(true);
356+
352357
that.getMav().visit(this);
353358
that.getName().visit(this);
354359

javalanglevels/src/edu/rice/cs/javalanglevels/IntermediateVisitor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,11 @@ public Void forInterfaceDef(InterfaceDef that) {
452452
for (int i = 0; i < that.getInterfaces().length; i++) that.getInterfaces()[i].visit(this);
453453

454454
SymbolData sd = defineSymbolData(that, className);
455+
// Note: sd can only be null if an error occurs in defineSymbol
456+
455457
if (sd != null) {
456-
identifyInnerClasses(that); // inner interfaces??
457458
sd.setInterface(true);
459+
identifyInnerClasses(that); // inner interfaces??
458460
that.getBody().visit(new InterfaceBodyIntermediateVisitor(sd, _file, _package, _importedFiles, _importedPackages,
459461
_classesInThisFile, continuations, fixUps));
460462
}

javalanglevels/src/edu/rice/cs/javalanglevels/LanguageLevelVisitor.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ protected SymbolData getSymbolData(File file,
609609
if (sD != null) {
610610
if (resultSD == null || resultSD.equals(sD)) resultSD = sD;
611611
else { // sD is NOT the first match; flag an error
612-
if (addError) {
612+
if (addError) { // TODO: why do we suppress this error in some cases?
613613
_addAndIgnoreError("The class name " + qualClassName + " is ambiguous. It could be " + resultSD.getName()
614614
+ " or " + sD.getName(), new NullLiteral(si));
615615
return null;
@@ -713,7 +713,7 @@ protected SymbolData getQualifiedSymbolData(String qualClassName, SourceInfo si,
713713
* @param resolve Whether to return a continuation or fully parse the class.
714714
* @param fromClassFile Whether this was called from the class file reader.
715715
* @param addError Whether to add errors. We don't add errors when iterating through a qualified class name's
716-
* package.
716+
* package. (??)
717717
*/
718718
protected SymbolData getQualifiedSymbolData(String qualClassName, SourceInfo si, boolean resolve, boolean fromClassFile,
719719
boolean addError) {
@@ -856,6 +856,7 @@ protected SymbolData defineSymbolData(TypeDefBase typeDefBase, final String qual
856856
* any special inner class initialization.
857857
* @param typeDefBase The AST node for the class def, interface def, inner class def, or inner interface def.
858858
* @param qualifiedTypeName The fully qualified name of the class or interface
859+
* @return the defined SymbolData or null if the type has already been defined
859860
*/
860861
protected SymbolData defineSymbolData(final TypeDefBase typeDefBase, final String qualifiedTypeName,
861862
final String enclosingClassName /*, final HashSet<String> classesInThisFile*/) {
@@ -895,7 +896,7 @@ protected SymbolData defineSymbolData(final TypeDefBase typeDefBase, final Strin
895896
boolean forwardRef = false;
896897
SymbolData iD = _lookupTypeFromWithinClass(rt, enclosingClassName);
897898
if (iD != null && ! iD.isContinuation() && ! iD.isInterface()) {
898-
_addError("The symbol " + rtName + " is not an interface", typeDefBase);
899+
_addAndIgnoreError("The symbol " + rtName + " is not an interface", typeDefBase);
899900
}
900901
if (iD == null || iD.isContinuation()) { // create a dummy symbol pending fixUp TODO: is this necessary?
901902
iD = new SymbolData(rtName);
@@ -909,9 +910,9 @@ protected SymbolData defineSymbolData(final TypeDefBase typeDefBase, final Strin
909910
Command fixUp = new Command() {
910911
public void execute() {
911912
SymbolData newID = _lookupTypeFromWithinClass(rt, enclosingClassName);
912-
if (newID == null) _addError("The symbol " + rtName + " is not defined", typeDefBase);
913+
if (newID == null) _addAndIgnoreError("The symbol " + rtName + " is not defined", typeDefBase);
913914
else if (! newID.isInterface())
914-
_addError("The symbol " + rtName + " is not an interface", typeDefBase);
915+
_addAndIgnoreError("The symbol " + rtName + " is not an interface", typeDefBase);
915916
interfaces.set(j, newID);
916917
sd.addEnclosingData(newID);
917918
}
@@ -948,7 +949,7 @@ else if (typeDefBase instanceof ClassDef) {
948949
public void execute() {
949950
SymbolData newSuperSD = _lookupTypeFromWithinClass(rt, enclosingClassName);
950951
if (newSuperSD == null)
951-
_addError("The class " + sd + " has an undefined superclass " + rt, typeDefBase);
952+
_addAndIgnoreError("The class " + sd + " has an undefined superclass " + rt, typeDefBase);
952953
else // TODO: Does not check that newSuperSD is not an interace
953954
sd.setSuperClass(newSuperSD);
954955
}
@@ -1121,7 +1122,8 @@ protected VariableData[] formalParameters2VariableData(FormalParameter[] fps, Sy
11211122
new VariableData(name, new ModifiersAndVisibility(SourceInfo.NO_INFO, mav), sd, true, enclosing);
11221123

11231124
assert ! varData[i].isPrivate();
1124-
if (sd == null) { // TODO !!!: can this happen?
1125+
1126+
if (sd == null || sd == SymbolData.NOT_FOUND) { // a forward Type reference
11251127
// To establish a reference to a not-yet-defined type, create a fixup
11261128
final int j = i;
11271129
/* The following is a kludge to make method signature collision detection work (unless different
@@ -1131,7 +1133,7 @@ protected VariableData[] formalParameters2VariableData(FormalParameter[] fps, Sy
11311133
public void execute() {
11321134
SymbolData newSd = _identifyType(typeName, si, enclosingClassName);
11331135
assert newSd != null && newSd != SymbolData.NOT_FOUND; // TODO !!!: Expand to error message?
1134-
varData[j].setType(newSd);
1136+
if (newSd != null) varData[j].setType(newSd);
11351137
}
11361138
};
11371139
fixUps.add(fixUp);
@@ -1833,14 +1835,14 @@ public void createConstructor(SymbolData sd) {
18331835
// }
18341836
//
18351837
if (sd.isContinuation()) {
1836-
_addError("Could not generate constructor for class " + sd + " because it has no definition",
1838+
_addAndIgnoreError("Could not generate constructor for class " + sd + " because it has no definition",
18371839
new NullLiteral(SourceInfo.NO_INFO));
18381840
return;
18391841
}
18401842

18411843
SymbolData superSd = sd.getSuperClass();
18421844
if (superSd == null) {
1843-
_addError("Could not generate constructor for class " + sd + " because it has no superclass",
1845+
_addAndIgnoreError("Could not generate constructor for class " + sd + " because it has no superclass",
18441846
new NullLiteral(SourceInfo.NO_INFO));
18451847
return;
18461848
}

javalanglevels/src/edu/rice/cs/javalanglevels/SymbolData.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -860,19 +860,20 @@ public boolean hasMethod(String name) {
860860
return false;
861861
}
862862

863-
/**
864-
* Returns the method with the given name.
865-
* @param name The name of the method to return
866-
* @param paramTypes Array of the TypeDatas correpsonding to the parameters to the method.
867-
* @return The MethodData or null if it is not found
868-
*/
863+
/** Returns the method with the given name and param types.
864+
* @param name The name of the method to return
865+
* @param paramTypes Array of the TypeDatas correpsonding to the parameters to the method.
866+
* @return The matched MethodData or null if it is not found
867+
*/
869868
public MethodData getMethod(String name, TypeData[] paramTypes) {
870869
for (int i = 0; i < _methods.size(); i++) {
871870
MethodData currMd = _methods.get(i);
872871
if (currMd.getName().equals(name)) {
873872
if (paramTypes.length == currMd.getParams().length) {
874873
boolean match = true;
875-
for (int j = 0; j < paramTypes.length; j++) {
874+
for (int j = 0; j < paramTypes.length; j++) { // TODO; clean up this coding!
875+
if (paramTypes[j] == null || paramTypes[j].getSymbolData() == null || currMd.getParams()[j].getType() == null)
876+
continue; // prevents a null pointer exception
876877
if (! paramTypes[j].getSymbolData().equals(currMd.getParams()[j].getType().getSymbolData())) {
877878
match = false;
878879
break;

javalanglevels/src/edu/rice/cs/javalanglevels/TypeChecker.java

Lines changed: 43 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ private static boolean _areInSamePackage(SymbolData enclosingSD, SymbolData this
297297
}
298298

299299

300-
/**pass a default value*/
300+
/** Pass a default value*/
301301
protected MethodData _lookupMethodHelper(String methodName, SymbolData enclosingSD, InstanceData[] arguments,
302302
JExpression jexpr, boolean isConstructor, SymbolData thisSD) {
303303
return _lookupMethodHelper(methodName, enclosingSD, arguments, jexpr, isConstructor, thisSD,
@@ -654,7 +654,6 @@ public static boolean checkAccessibility(JExpression piece, ModifiersAndVisibili
654654
}
655655
}
656656

657-
658657
/** Return the field or variable with the name text inside of data. (Referenced from thisSD) */
659658
public static VariableData getFieldOrVariable(String text, Data data, SymbolData thisSD, JExpression piece) {
660659
if (data == null) return null;
@@ -1140,13 +1139,11 @@ public TypeData forClassDef(ClassDef that) {
11401139
}
11411140
}
11421141

1143-
//unassign anything that got assigned in the scope of the class def.
1144-
1142+
// Unassign anything that got assigned in the scope of the class def.
11451143
unassignVariableDatas(cbtc.thingsThatHaveBeenAssigned);
11461144

11471145
return forClassDefOnly(that, mav_result, name_result, typeParameters_result, superclass_result, interfaces_result, body_result);
11481146
}
1149-
11501147

11511148
/**Do everything necessary to handle an interface*/
11521149
public TypeData forInterfaceDef(InterfaceDef that) {
@@ -1164,18 +1161,15 @@ public TypeData forInterfaceDef(InterfaceDef that) {
11641161
}
11651162
}
11661163

1167-
1168-
11691164
// Check for cyclic inheritance
11701165
if (checkForCyclicInheritance(sd, new LinkedList<SymbolData>(), that)) {
11711166
return null;
11721167
}
11731168

1174-
//make sure that this does not extend the runnable interface
1175-
if (sd.hasInterface(getSymbolData("java.lang.Runnable", that, false, false))) {
1176-
_addError(sd.getName() + " extends the Runnable interface, which is not allowed at any language level", that);
1177-
}
1178-
1169+
// // Make sure that this does not extend the runnable interface
1170+
// if (sd.hasInterface(getSymbolData("java.lang.Runnable", that, false, false))) {
1171+
// _addError(sd.getName() + " extends the Runnable interface, which is not allowed at any language level", that);
1172+
// }
11791173

11801174
final TypeData mav_result = that.getMav().visit(this);
11811175
final TypeData name_result = that.getName().visit(this);
@@ -2214,30 +2208,30 @@ public void testForInterfaceDef() {
22142208
assertEquals("There should be 2 errors", 2, errors.size());
22152209
assertEquals("The error message should be correct", "The interface superI is private and cannot be accessed from somewhereElse.Lisa", errors.get(1).getFirst());
22162210

2217-
2218-
//Test that if the interface extends java.lang.Runnable, then an error is thrown.
2219-
InterfaceDef id3 = new InterfaceDef(SourceInfo.NO_INFO, _publicMav, new Word(SourceInfo.NO_INFO, "JimesH"),
2220-
new TypeParameter[0], new ReferenceType[] {new ClassOrInterfaceType(SourceInfo.NO_INFO, "java.lang.Runnable", new Type[0])}, new BracedBody(SourceInfo.NO_INFO, new BodyItemI[0]));
2221-
SymbolData sd = new SymbolData("JimesH");
2222-
sd.setIsContinuation(false);
2223-
sd.setInterface(true);
2224-
2225-
symbolTable.clear();
2226-
SymbolData runnableSd = new SymbolData("java.lang.Runnable");
2227-
runnableSd.setMav(_publicMav);
2228-
runnableSd.setIsContinuation(false);
2229-
runnableSd.setPackage("java.lang");
2230-
runnableSd.setInterface(true);
2231-
sd.addInterface(runnableSd);
2232-
symbolTable.put("JimesH", sd);
2233-
symbolTable.remove("java.lang.Runnable");
2234-
symbolTable.put("java.lang.Runnable", runnableSd);
2235-
2236-
id3.visit(_btc);
2237-
assertEquals("There should be 3 errors now", 3, errors.size());
2238-
assertEquals("The error message should be correct", "JimesH extends the Runnable interface, which is not allowed at any language level", errors.get(2).getFirst());
2239-
2240-
//Test that an error is thrown if you implement a class
2211+
/* The Runnable restriction has been dropped. */
2212+
// //Test that if the interface extends java.lang.Runnable, then an error is thrown.
2213+
// InterfaceDef id3 = new InterfaceDef(SourceInfo.NO_INFO, _publicMav, new Word(SourceInfo.NO_INFO, "JimesH"),
2214+
// new TypeParameter[0], new ReferenceType[] {new ClassOrInterfaceType(SourceInfo.NO_INFO, "java.lang.Runnable", new Type[0])}, new BracedBody(SourceInfo.NO_INFO, new BodyItemI[0]));
2215+
// SymbolData sd = new SymbolData("JimesH");
2216+
// sd.setIsContinuation(false);
2217+
// sd.setInterface(true);
2218+
//
2219+
// symbolTable.clear();
2220+
// SymbolData runnableSd = new SymbolData("java.lang.Runnable");
2221+
// runnableSd.setMav(_publicMav);
2222+
// runnableSd.setIsContinuation(false);
2223+
// runnableSd.setPackage("java.lang");
2224+
// runnableSd.setInterface(true);
2225+
// sd.addInterface(runnableSd);
2226+
// symbolTable.put("JimesH", sd);
2227+
// symbolTable.remove("java.lang.Runnable");
2228+
// symbolTable.put("java.lang.Runnable", runnableSd);
2229+
//
2230+
// id3.visit(_btc);
2231+
// assertEquals("There should be 3 errors now", 3, errors.size());
2232+
// assertEquals("The error message should be correct", "JimesH extends the Runnable interface, which is not allowed at any language level", errors.get(2).getFirst());
2233+
2234+
// Test that an error is thrown if you implement a class
22412235

22422236
InterfaceDef id4 = new InterfaceDef(SourceInfo.NO_INFO, _publicMav, new Word(SourceInfo.NO_INFO, "Bart"),
22432237
new TypeParameter[0], new ReferenceType[] {new ClassOrInterfaceType(SourceInfo.NO_INFO, "superC", new Type[0])}, new BracedBody(SourceInfo.NO_INFO, new BodyItemI[0]));
@@ -2257,24 +2251,28 @@ public void testForInterfaceDef() {
22572251
result = id4.visit(_btc);
22582252

22592253

2260-
assertEquals("There should be 4 errors now ", 4, errors.size());
2261-
assertEquals("The error message should be correct", "superC is not an interface and thus cannot appear after the keyword 'extends' here", errors.get(3).getFirst());
2254+
assertEquals("There should be 3 errors now ", 3, errors.size());
2255+
assertEquals("The error message should be correct",
2256+
"superC is not an interface and thus cannot appear after the keyword 'extends' here",
2257+
errors.getLast().getFirst());
22622258

2263-
//Test that no error is thrown if you implement an interface
2259+
// Test that no error is thrown if you implement an interface
22642260
superC.setInterface(true);
22652261
result = id4.visit(_btc);
2266-
assertEquals("There should still just be 4 errors", 4, errors.size());
2262+
assertEquals("There should still just be 3 errors", 3, errors.size());
22672263

2268-
//Test that if a public interface is in a file of the wrong name, an error is thrown.
2264+
// Test that if a public interface is in a file of the wrong name, an error is thrown.
22692265
me.addModifier("public");
22702266
result = id4.visit(_btc);
2271-
assertEquals("There should be 5 errorrs", 5, errors.size());
2272-
assertEquals("The error message should be correct", "Bart is public thus must be defined in a file with the same name.", errors.get(4).getFirst());
2267+
assertEquals("There should be 4 errorrs", 4, errors.size());
2268+
assertEquals("The error message should be correct",
2269+
"Bart is public thus must be defined in a file with the same name.",
2270+
errors.getLast().getFirst());
22732271

2274-
//Test that if a public interface is in a file of the right name, no error is thrown.
2272+
// Test that if a public interface is in a file of the right name, no error is thrown.
22752273
_btc._file = new File("Bart.dj1");
22762274
result = id4.visit(_btc);
2277-
assertEquals("There should still just be 5 errors", 5, errors.size());
2275+
assertEquals("There should still just be 4 errors", 4, errors.size());
22782276
}
22792277

22802278
public void testForClassImportStatement() {

javalanglevels/src/edu/rice/cs/javalanglevels/VariableData.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,11 @@ public String toString() {
196196
public void setMav(ModifiersAndVisibility mav) { _modifiersAndVisibility = mav; }
197197

198198
/** @return the SymbolData representing the type of this variable. */
199-
public SymbolData getType() { return _type; }
199+
public SymbolData getType() { return _type;
200+
/* The following appears to break the Augmentor visitor. Why? */
201+
// if (_type != null) return _type;
202+
// return SymbolData.NOT_FOUND;
203+
}
200204

201205
/** Sets the SymbolData representing the type of this variable. */
202206
public void setType(SymbolData type) { _type = type; }

0 commit comments

Comments
 (0)