Skip to content

Commit b4e1ddf

Browse files
committed
add class variable hierarchy shadowing check, fixes #175
1 parent cd7f56f commit b4e1ddf

2 files changed

Lines changed: 65 additions & 2 deletions

File tree

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/validation/WurstValidator.java

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,8 +1568,51 @@ private void checkCall(StmtCall call) {
15681568
call.attrCallSignature().checkSignatureCompatibility(call.attrFunctionSignature(), funcName, call);
15691569
}
15701570

1571+
/** Error when a field in this class hides a field from a superclass. */
1572+
private void checkFieldShadowing(ClassDef c) {
1573+
// Iterate only the fields *declared* in this class:
1574+
for (NameLink nl : c.attrNameLinks().values()) {
1575+
NameDef def = nl.getDef();
1576+
// consider only variables that are declared in this class body
1577+
if (!(def instanceof GlobalVarDef)) continue;
1578+
if (nl.getDefinedIn() != c) continue; // not declared here
1579+
1580+
String name = def.getName();
1581+
1582+
// Look up all visible declarations of the same name in this class scope:
1583+
ImmutableCollection<DefLink> all = c.attrNameLinks().get(name);
1584+
for (DefLink other : all) {
1585+
if (!(other instanceof NameLink)) continue;
1586+
if (other.getDefinedIn() == c) continue; // skip "self" (duplicates in same class handled elsewhere)
1587+
NameDef od = other.getDef();
1588+
if (!(od instanceof GlobalVarDef)) continue;
1589+
1590+
// Is the other definition a superclass' field?
1591+
StructureDef owner = od.attrNearestStructureDef();
1592+
if (owner instanceof ClassDef) {
1593+
ClassDef superOwner = (ClassDef) owner;
1594+
if (isStrictSuperclassOf(superOwner, c)) {
1595+
// produce the requested error text
1596+
def.addError("Variable " + name + " in class " + c.getName()
1597+
+ " hides variable " + name + " from superclass " + superOwner.getName());
1598+
// one error per conflicting ancestor is enough
1599+
break;
1600+
}
1601+
}
1602+
}
1603+
}
1604+
}
15711605

1572-
// crude cap to avoid unbounded growth; tune as needed
1606+
private static boolean isStrictSuperclassOf(ClassDef sup, ClassDef sub) {
1607+
WurstTypeClass t = sub.attrTypC();
1608+
WurstTypeClass cur = (t != null) ? t.extendedClass() : null;
1609+
while (cur != null) {
1610+
ClassDef cd = cur.getClassDef();
1611+
if (cd == sup) return true;
1612+
cur = cur.extendedClass();
1613+
}
1614+
return false;
1615+
}
15731616

15741617
private static boolean isSubtypeCached(WurstType actual, WurstType expected, Annotation site) {
15751618
if (actual == expected) return true;
@@ -1796,12 +1839,15 @@ private void checkReturnInFunc(StmtReturn s, FunctionImplementation func) {
17961839

17971840
private void visit(ClassDef classDef) {
17981841
checkTypeName(classDef, classDef.getName());
1799-
if (!(classDef.getExtendedClass() instanceof NoTypeExpr) && !(classDef.getExtendedClass().attrTyp() instanceof WurstTypeClass)) {
1842+
if (!(classDef.getExtendedClass() instanceof NoTypeExpr)
1843+
&& !(classDef.getExtendedClass().attrTyp() instanceof WurstTypeClass)) {
18001844
classDef.getExtendedClass().addError("Classes may only extend other classes.");
18011845
}
18021846
if (classDef.isInnerClass() && !classDef.attrIsStatic()) {
18031847
classDef.addError("At the moment only static inner classes are supported.");
18041848
}
1849+
1850+
checkFieldShadowing(classDef);
18051851
}
18061852

18071853
private void checkTypeName(Element source, String name) {

de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/BugTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,4 +1443,21 @@ public void minusRewrite() {
14431443
}
14441444

14451445

1446+
@Test
1447+
public void duplicateNameInClassHierachy() {
1448+
testAssertErrorsLines(false, "Variable x in class B hides variable x from superclass A",
1449+
"package test",
1450+
"native testSuccess()",
1451+
"class A",
1452+
" int x",
1453+
"class B extends A",
1454+
" int x",
1455+
"init",
1456+
" let b = new B()",
1457+
" if b != null",
1458+
" testSuccess()",
1459+
"endpackage");
1460+
}
1461+
1462+
14461463
}

0 commit comments

Comments
 (0)