-
Notifications
You must be signed in to change notification settings - Fork 889
Conversation
42a503c
to
7a0b9b7
Compare
Don't unnecessarily use a BlockScopeAwareRuleWalker, just store a stack of for-loop scopes
7a0b9b7
to
f9d7577
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't know how to say this in a nice way ...
this code still looks pretty bad
I left some comments on the really bad parts. I will review again after these changes
src/rules/preferForOfRule.ts
Outdated
return true; | ||
} | ||
} else if (node.kind === ts.SyntaxKind.PostfixUnaryExpression) { | ||
const incrementor = node as ts.PostfixUnaryExpression; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be joined with the if block above as they do exactly the same
src/rules/preferForOfRule.ts
Outdated
} | ||
} else if (node.kind === ts.SyntaxKind.PostfixUnaryExpression) { | ||
const incrementor = node as ts.PostfixUnaryExpression; | ||
if (incrementor.operator === ts.SyntaxKind.PlusPlusToken && incrementor.operand.getText() === indexVariableName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just return, no need for an if
src/rules/preferForOfRule.ts
Outdated
// ensure variable is incremented | ||
if (node.kind === ts.SyntaxKind.PrefixUnaryExpression) { | ||
const incrementor = node as ts.PrefixUnaryExpression; | ||
if (incrementor.operator === ts.SyntaxKind.PlusPlusToken && incrementor.operand.getText() === indexVariableName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could replace incrementor.operand.getText() === indexVariableName
with isIdentifier(incrementor.operand) && incrementor.operand.text === indexVariableName
maybe make this a function because you also need it below
src/rules/preferForOfRule.ts
Outdated
if (node == null) { | ||
return false; | ||
// ensure variable is incremented | ||
if (node.kind === ts.SyntaxKind.PrefixUnaryExpression) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use typeguards?
src/rules/preferForOfRule.ts
Outdated
} | ||
} else if (node.kind === ts.SyntaxKind.BinaryExpression) { | ||
const binaryExpression = node as ts.BinaryExpression; | ||
if (binaryExpression.operatorToken.getText() === "+=" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
operatorToken.kind === ts.SyntaxKind.PlusEqualsToken
same below with EqualsToken
and PlusToken
src/rules/preferForOfRule.ts
Outdated
const binaryExpression = node as ts.BinaryExpression; | ||
if (binaryExpression.operatorToken.getText() === "+=" | ||
&& binaryExpression.left.getText() === indexVariableName | ||
&& binaryExpression.right.getText() === "1") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isNumericLiteral(binaryExpression.right) && binaryExpression.right.text === "1"
make this a function a reuse it for the 2 conditions below, too
src/rules/preferForOfRule.ts
Outdated
let indexVariable: ts.Identifier | undefined; | ||
|
||
// assign `indexVariableName` if initializer is simple and starts at 0 | ||
if (forLoop.initializer && forLoop.initializer.kind === ts.SyntaxKind.VariableDeclarationList) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (forLoop.initializer && isVariableDeclarationList(forLoop.initializer) && forLoop.initializer.declarations.length === 1) {
const declaration = forLoop.initializer.declarations[0];
if (declaration.name.kind === ts.SyntaxKind.Identifier &&
declaration.initializer !== undefined && isNumericLiteral(declaration.initializer) && declaration.initializer.text === "0") {
indexVariable = declaration.name;
indexVariableName = indexVariable.text;
}
}
src/rules/preferForOfRule.ts
Outdated
// ensure `for` condition | ||
if (!indexVariableName | ||
|| !forLoop.condition | ||
|| forLoop.condition.kind !== ts.SyntaxKind.BinaryExpression |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!isBinaryExpression(forLoop.condition) ||
!isVariable(forLoop.condition.left, indexVariableName) || // see my other comments regarding indexVariableName
forLoop.condition.operatorToken.kind !== ts.SyntaxKind.LessThanToken ||
// condition from line 159
!isPropertyAccessExpression(forLoop.condition.right) ||
forLoop.condition.right.name.text !== "length"
src/rules/preferForOfRule.ts
Outdated
// store `for` loop state | ||
const state: IncrementorState = { | ||
indexVariableName, | ||
arrayToken: arrayToken as ts.Identifier, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arrayToken
is not guaranteed to be ts.Identifier
src/rules/preferForOfRule.ts
Outdated
if (state.arrayToken.getText() !== arrayIdentifier.getText()) { | ||
// iterator used in array other than one iterated over | ||
state.onlyArrayReadAccess = false; | ||
} else if (elementAccess.parent && isAssignment(elementAccess.parent)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
elementAccess.parent
is never undefined, so you can simply assert it
AFAICT the rule will bail out if you use an identifier with the same name as the index variable somewhere inside the loop body. That's no blocker for now as the old implementation behaved the same I guess. for (let i = 0; i < arr.length; ++i) {
{
let i; // i is not used in element access, the rule bails out
}
class Foo {
private i; // same as above
constructor(i: number) {} // same as above
}
let foo: { i: number } = { i: 1 }; // same as above for both identifiers
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code looks much better now, thanks
PR checklist
Overview of change:
Don't unnecessarily use a BlockScopeAwareRuleWalker, just store a stack of for-loop scopes.