Skip to content

Commit

Permalink
fixed for loop shadowing, fixes vshaxe/vshaxe#136
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexHaxe committed Apr 25, 2022
1 parent 547cf10 commit ae1f2f1
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## dev branch / next version (2.x.x)

## 2.1.2 (2022-04-25)

- fixed handling of loop iterator shadowing, fixes [vshaxe/vshaxe#136](https://github.com/vshaxe/vshaxe/issues/136)

## 2.1.1 (2022-04-23)

- fixed identifier collection
Expand Down
4 changes: 2 additions & 2 deletions haxelib.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"refactor"
],
"description": "A code renaming tool for Haxe",
"version": "2.1.1",
"releasenote": "fixed identifier collection",
"version": "2.1.2",
"releasenote": "fixed handling of loop iterator shadowing",
"contributors": [
"AlexHaxe"
],
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@haxecheckstyle/haxe-rename",
"version": "2.1.1",
"version": "2.1.2",
"description": "Renaming tool for Haxe",
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions src/refactor/PrintHelper.hx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class PrintHelper {
return switch (scopeType) {
case Parameter(params):
'Parameter(${params.map((i) -> '"${i.name}"')})';
case ForLoop(loopIdentifiers):
'ForLoop(${loopIdentifiers.map((i) -> '"${i.name}"')})';
case ForLoop(scopeStart, loopIdentifiers):
'ForLoop(${loopIdentifiers.map((i) -> '"${i.name}"')}) - scopeStart: $scopeStart';
default:
'$scopeType';
}
Expand Down
6 changes: 5 additions & 1 deletion src/refactor/Refactor.hx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class Refactor {
RenameEnumField.refactorEnumField(context, file, identifier);
case Call(true):
Promise.reject(RefactorResult.Unsupported(identifier.toString()).printRefactorResult());
case Call(false) | Access | ArrayAccess(_):
case Call(false) | Access | ArrayAccess(_) | ForIterator:
context.verboseLog('rename "${identifier.name}" at call/access location - trying to find definition');
findActualWhat(context, file, identifier);
case CaseLabel(_):
Expand Down Expand Up @@ -105,6 +105,10 @@ class Refactor {
if (candidate == null) {
candidate = use;
}
case ScopedLocal(scopeEnd, ForLoop(scopeStart, _)) if (!onlyFields):
if ((scopeStart < identifier.pos.start) && (identifier.pos.start < scopeEnd)) {
candidate = use;
}
case ScopedLocal(scopeEnd, _) if (!onlyFields):
if ((use.pos.start < identifier.pos.start) && (identifier.pos.start < scopeEnd)) {
candidate = use;
Expand Down
3 changes: 2 additions & 1 deletion src/refactor/discover/IdentifierType.hx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ enum IdentifierType {
Call(isNew:Bool);
ArrayAccess(posClosing:Int);
Access;
ForIterator;
ScopedLocal(scopeEnd:Int, scopeType:ScopedLocalType);
StringConst;
}
Expand All @@ -43,7 +44,7 @@ enum ScopedLocalType {
Parameter(params:Array<Identifier>);
Var;
CaseCapture;
ForLoop(loopIdentifiers:Array<Identifier>);
ForLoop(scopeStart:Int, loopIdentifiers:Array<Identifier>);
}

enum TypedefFieldType {
Expand Down
21 changes: 19 additions & 2 deletions src/refactor/discover/UsageCollector.hx
Original file line number Diff line number Diff line change
Expand Up @@ -682,20 +682,30 @@ class UsageCollector {
function readForIteration(context:UsageContext, identifier:Identifier, token:TokenTree, scopeEnd:Int) {
var loopIdentifiers:Array<Identifier> = [];

var ident:Identifier = makeIdentifier(context, token, ScopedLocal(scopeEnd, ForLoop(loopIdentifiers)), identifier);
var pClose:Null<TokenTree> = token.access().parent().firstOf(PClose).token;
var scopeStart:Int = token.pos.min;
if (pClose != null) {
scopeStart = pClose.pos.max;
}
var ident:Identifier = makeIdentifier(context, token, ScopedLocal(scopeEnd, ForLoop(scopeStart, loopIdentifiers)), identifier);
loopIdentifiers.push(ident);
if (!token.hasChildren()) {
return;
}
for (child in token.children) {
switch (child.tok) {
case Binop(OpArrow):
ident = makeIdentifier(context, child.getFirstChild(), ScopedLocal(scopeEnd, ForLoop(loopIdentifiers)), identifier);
ident = makeIdentifier(context, child.getFirstChild(), ScopedLocal(scopeEnd, ForLoop(scopeStart, loopIdentifiers)), identifier);
loopIdentifiers.push(ident);
default:
readExpression(context, ident, child);
if (ident.uses != null) {
for (use in ident.uses) {
switch (use.type) {
case Access:
use.type = ForIterator;
default:
}
loopIdentifiers.push(use);
}
}
Expand Down Expand Up @@ -880,6 +890,13 @@ class UsageCollector {
if (!parent.matches(Kwd(KwdTypedef))) {
pOpenToken = child;
}
case Binop(OpIn):
case Binop(OpArrow):
switch (type) {
case ScopedLocal(_, ForLoop(_)):
default:
pOpenToken = child;
}
case BkOpen | Binop(_):
pOpenToken = child;
case DblDot:
Expand Down
4 changes: 2 additions & 2 deletions src/refactor/rename/RenameHelper.hx
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,12 @@ class RenameHelper {

var typeHint:Null<Identifier> = candidate.getTypeHint();
switch (candidate.type) {
case ScopedLocal(_, ForLoop(loopIdent)):
case ScopedLocal(_, ForLoop(_, loopIdent)):
var index:Int = loopIdent.indexOf(candidate);
var changes:Array<Promise<TypeHintType>> = [];
for (child in loopIdent) {
switch (child.type) {
case ScopedLocal(_, ForLoop(_)):
case ScopedLocal(_, ForLoop(_, _)):
continue;
default:
changes.push(findTypeOfIdentifier(context, {
Expand Down
19 changes: 18 additions & 1 deletion src/refactor/rename/RenameScopedLocal.hx
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,23 @@ class RenameScopedLocal {
end: use.pos.start
};
changelist.addChange(use.pos.fileName, InsertText("this.", pos), use);
case ScopedLocal(scopeEnd, scopeType):
case ScopedLocal(_, _):
return Promise.reject('local var "${context.what.toName}" exists');
default:
}
}

var skipForIterator:Bool = false;
for (use in allUses) {
switch (use.type) {
case ScopedLocal(scopeEnd, ForLoop(start, _)):
if (use.pos.start == identifier.pos.start) {
scopeStart = start;
skipForIterator = true;
} else {
scopeStart = scopeEnd;
continue;
}
case ScopedLocal(scopeEnd, _):
if (use.pos.start != identifier.pos.start) {
// new parameter with identical name, so we skip its scope
Expand All @@ -69,7 +78,15 @@ class RenameScopedLocal {
}
case StructureField(_):
continue;
case ForIterator:
if (skipForIterator) {
skipForIterator = false;
continue;
}
default:
if (use.pos.start < scopeStart) {
continue;
}
}
if (use.name == identifier.name) {
// exact match
Expand Down
27 changes: 27 additions & 0 deletions test/refactor/ClassTest.hx
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,33 @@ class ClassTest extends TestBase {
failRefactor({fileName: "testcases/classes/BaseClass.hx", toName: "data", pos: 298}, 'local var "data" exists', async);
}

public function testRenameBaseClassCaseLabel(async:Async) {
var edits:Array<TestEdit> = [];
failRefactor({fileName: "testcases/classes/BaseClass.hx", toName: "data", pos: 516},
"renaming not supported for Case1 testcases/classes/BaseClass.hx@514-519 (CaseLabel(val))", async);
}

public function testRenameUseChildClassParentSubPart(async:Async) {
var edits:Array<TestEdit> = [];
failRefactor({fileName: "testcases/classes/UseChild.hx", toName: "data", pos: 233}, "could not find identifier to rename", async);
}

public function testRenameBaseClassDataToData(async:Async) {
var edits:Array<TestEdit> = [];
failRefactor({fileName: "testcases/classes/BaseClass.hx", toName: "data", pos: 43}, "could not find identifier to rename", async);
}

public function testRenameBaseClassNoIdentifier(async:Async) {
var edits:Array<TestEdit> = [];
failRefactor({fileName: "testcases/classes/BaseClass.hx", toName: "data", pos: 103}, "could not find identifier to rename", async);
}

public function testRenameStaticUsingConstructorCall(async:Async) {
var edits:Array<TestEdit> = [];
failRefactor({fileName: "testcases/classes/StaticUsing.hx", toName: "NewChildClass", pos: 359},
"renaming not supported for ChildClass testcases/classes/StaticUsing.hx@355-365 (Call(true))", async);
}

public function testRenameBaseClassParamterWithShadow2(async:Async) {
var edits:Array<TestEdit> = [
makeReplaceTestEdit("testcases/classes/BaseClass.hx", "data", 386, 387),
Expand Down
44 changes: 42 additions & 2 deletions test/refactor/ScopedLocalTest.hx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class ScopedLocalTest extends TestBase {
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "refactorContext", 1332, 1339),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "refactorContext", 1806, 1813),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "refactorContext", 2017, 2024),

];
refactorAndCheck({fileName: "testcases/scopedlocal/Refactor.hx", toName: "refactorContext", pos: 463}, edits, async);
}
Expand Down Expand Up @@ -64,7 +63,6 @@ class ScopedLocalTest extends TestBase {
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "refactorContext", 1332, 1339),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "refactorContext", 1806, 1813),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "refactorContext", 2017, 2024),

];
refactorAndCheck({fileName: "testcases/scopedlocal/Refactor.hx", toName: "refactorContext", pos: 2020}, edits, async);
}
Expand All @@ -77,4 +75,46 @@ class ScopedLocalTest extends TestBase {
];
refactorAndCheck({fileName: "testcases/scopedlocal/Structure.hx", toName: "file", pos: 102}, edits, async);
}

public function testRenameFooVar(async:Async) {
var edits:Array<TestEdit> = [
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2104, 2107),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2139, 2142),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2187, 2190),
];
refactorAndCheck({fileName: "testcases/scopedlocal/Refactor.hx", toName: "file", pos: 2105}, edits, async);
}

public function testRenameFooArray(async:Async) {
var edits:Array<TestEdit> = [
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2104, 2107),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2139, 2142),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2187, 2190),
];
refactorAndCheck({fileName: "testcases/scopedlocal/Refactor.hx", toName: "file", pos: 2140}, edits, async);
}

public function testRenameFooItem(async:Async) {
var edits:Array<TestEdit> = [
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2132, 2135),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2155, 2158),
];
refactorAndCheck({fileName: "testcases/scopedlocal/Refactor.hx", toName: "file", pos: 2133}, edits, async);
}

public function testRenameFooItem2(async:Async) {
var edits:Array<TestEdit> = [
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2173, 2176),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2203, 2206),
];
refactorAndCheck({fileName: "testcases/scopedlocal/Refactor.hx", toName: "file", pos: 2174}, edits, async);
}

public function testRenameValItem(async:Async) {
var edits:Array<TestEdit> = [
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2180, 2183),
makeReplaceTestEdit("testcases/scopedlocal/Refactor.hx", "file", 2218, 2221),
];
refactorAndCheck({fileName: "testcases/scopedlocal/Refactor.hx", toName: "file", pos: 2181}, edits, async);
}
}
10 changes: 10 additions & 0 deletions testcases/scopedlocal/Refactor.hx
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,15 @@ class Refactor {
case StringConst:
Unsupported;
}

var foo = [1, 23, 4, 5];
for (foo in foo) {
trace(foo);
}

for (foo => val in foo) {
trace(foo);
trace(val);
}
}
}

0 comments on commit ae1f2f1

Please sign in to comment.