Skip to content

Commit 18ea803

Browse files
committed
now a warning + implicit fix
1 parent 67690ca commit 18ea803

2 files changed

Lines changed: 101 additions & 10 deletions

File tree

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

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1643,14 +1643,14 @@ private void checkUninitializedVars(FunctionLike f) {
16431643
&& !f.getSource().getFile().endsWith("blizzard.j")
16441644
&& !f.getSource().getFile().endsWith("war3map.j")) {
16451645
new DataflowAnomalyAnalysis(Utils.isJassCode(f)).execute(f);
1646-
checkJassImplicitNullLocalsReadWithoutExplicitWrite(f);
16471646
}
1647+
checkJassImplicitNullLocalsReadWithoutExplicitWrite(f);
16481648
}
16491649

16501650
/**
16511651
* JASS compatibility shim: we currently synthesize "= null" for uninitialized non-primitive
16521652
* locals to avoid invalid emitted JASS. Still report likely user bugs early when such a local
1653-
* is read but never explicitly assigned in the input.
1653+
* is read before its first explicit assignment in the input.
16541654
*/
16551655
private void checkJassImplicitNullLocalsReadWithoutExplicitWrite(FunctionLike f) {
16561656
if (!Utils.isJassCode(f)) {
@@ -1671,27 +1671,84 @@ public void visit(LocalVarDef localVarDef) {
16711671
return;
16721672
}
16731673

1674-
Set<LocalVarDef> explicitWrites = new HashSet<>();
1674+
Set<LocalVarDef> implicitNullLocalSet = new HashSet<>(implicitNullLocals);
1675+
Map<LocalVarDef, StmtSet> firstExplicitWrite = new HashMap<>();
16751676
f.accept(new Element.DefaultVisitor() {
16761677
@Override
16771678
public void visit(StmtSet stmtSet) {
16781679
super.visit(stmtSet);
16791680
NameLink link = stmtSet.getUpdatedExpr().attrNameLink();
16801681
if (link != null && link.getDef() instanceof LocalVarDef) {
1681-
explicitWrites.add((LocalVarDef) link.getDef());
1682+
LocalVarDef local = (LocalVarDef) link.getDef();
1683+
if (!implicitNullLocalSet.contains(local)) {
1684+
return;
1685+
}
1686+
StmtSet previous = firstExplicitWrite.get(local);
1687+
if (previous == null
1688+
|| stmtSet.attrSource().getLeftPos() < previous.attrSource().getLeftPos()) {
1689+
firstExplicitWrite.put(local, stmtSet);
1690+
}
1691+
}
1692+
}
1693+
});
1694+
1695+
Set<LocalVarDef> readBeforeExplicitWrite = new HashSet<>();
1696+
f.accept(new Element.DefaultVisitor() {
1697+
@Override
1698+
public void visit(ExprVarAccess varAccess) {
1699+
super.visit(varAccess);
1700+
NameLink link = varAccess.attrNameLink();
1701+
if (link == null || !(link.getDef() instanceof LocalVarDef)) {
1702+
return;
1703+
}
1704+
LocalVarDef local = (LocalVarDef) link.getDef();
1705+
if (!implicitNullLocalSet.contains(local)) {
1706+
return;
1707+
}
1708+
if (isWriteTarget(varAccess)) {
1709+
return;
1710+
}
1711+
StmtSet firstWrite = firstExplicitWrite.get(local);
1712+
if (firstWrite == null) {
1713+
readBeforeExplicitWrite.add(local);
1714+
return;
1715+
}
1716+
StmtSet enclosingSet = nearestEnclosingStmtSet(varAccess);
1717+
if (enclosingSet == firstWrite) {
1718+
readBeforeExplicitWrite.add(local);
1719+
return;
1720+
}
1721+
if (varAccess.attrSource().getLeftPos() < firstWrite.attrSource().getLeftPos()) {
1722+
readBeforeExplicitWrite.add(local);
16821723
}
16831724
}
16841725
});
16851726

16861727
for (LocalVarDef local : implicitNullLocals) {
1687-
if (explicitWrites.contains(local)) {
1688-
continue;
1728+
if (readBeforeExplicitWrite.contains(local)) {
1729+
local.addWarning("Variable " + local.getName()
1730+
+ " is read before explicit initialization in input JASS; defaulting to null.");
16891731
}
1690-
if (f.attrReadVariables().contains(local)) {
1691-
local.addError("Variable " + local.getName()
1692-
+ " is read before explicit initialization in input JASS.");
1732+
}
1733+
}
1734+
1735+
private boolean isWriteTarget(ExprVarAccess varAccess) {
1736+
if (!(varAccess.getParent() instanceof StmtSet)) {
1737+
return false;
1738+
}
1739+
StmtSet set = (StmtSet) varAccess.getParent();
1740+
return set.getUpdatedExpr() == varAccess;
1741+
}
1742+
1743+
private @Nullable StmtSet nearestEnclosingStmtSet(Element e) {
1744+
Element current = e.getParent();
1745+
while (current != null) {
1746+
if (current instanceof StmtSet) {
1747+
return (StmtSet) current;
16931748
}
1749+
current = current.getParent();
16941750
}
1751+
return null;
16951752
}
16961753

16971754
private boolean isImplicitNullInit(LocalVarDef localVarDef) {

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

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void jassLocalHandleDefaultsToNull() {
5454

5555
@Test
5656
public void jassLocalHandleReadWithoutExplicitInitReportsEarly() {
57-
testAssertErrorsLinesWithStdLib(false, "read before explicit initialization in input JASS",
57+
testAssertWarningsLinesWithStdLib(false, "read before explicit initialization in input JASS",
5858
"function tiw takes nothing returns nothing",
5959
"local location uiw",
6060
"call RemoveLocation(uiw)",
@@ -66,4 +66,38 @@ public void jassLocalHandleReadWithoutExplicitInitReportsEarly() {
6666
);
6767
}
6868

69+
@Test
70+
public void war3mapJassLocalHandleReadWithoutExplicitInitReportsEarly() {
71+
test()
72+
.withStdLib()
73+
.setStopOnFirstError(false)
74+
.executeProg(false)
75+
.expectWarning("read before explicit initialization in input JASS")
76+
.compilationUnits(
77+
compilationUnit("war3map.j",
78+
"function showUnitTextAlliesWithZ takes nothing returns nothing",
79+
"local location p2",
80+
"call RemoveLocation(p2)",
81+
"endfunction"
82+
)
83+
);
84+
}
85+
86+
@Test
87+
public void jassLocalHandleReadBeforeLaterWriteStillWarns() {
88+
testAssertWarningsLinesWithStdLib(false, "read before explicit initialization in input JASS",
89+
"function tiw takes nothing returns nothing",
90+
"local location uiw",
91+
"call RemoveLocation(uiw)",
92+
"set uiw = GetRectCenter(GetPlayableMapRect())",
93+
"call RemoveLocation(uiw)",
94+
"set uiw = null",
95+
"endfunction",
96+
"package B",
97+
" init",
98+
" tiw()",
99+
"endpackage"
100+
);
101+
}
102+
69103
}

0 commit comments

Comments
 (0)