Issue #12671: kill pitest mutations in FinalLocalVariableCheck#13814
Issue #12671: kill pitest mutations in FinalLocalVariableCheck#13814romani merged 1 commit intocheckstyle:masterfrom
Conversation
9f03219 to
725c1e1
Compare
|
Github, generate report |
|
Please read https://github.com/checkstyle/contribution/tree/master/checkstyle-tester#basic-difference-report-with-label-and-custom-projects-list |
|
Github, generate report |
romani
left a comment
There was a problem hiding this comment.
ok to merge if report has no diff
Explain to me how this code is the same to the previous code, and there is no logical differences. Also, does this fix #13184 (comment) ? |
The EXPR
SLIST
I haven't checked the state of the |
|
@rdiachenko Let me know if I missed it, but what about the fact that we are switching from a double array to a single? This means we are no longer returning to a previous state when we would have pop. Now with your changes, when we call
It seems we are, as I described above. |
We are not switching from a doubly array. Instead, we are moving the second dimention into // before
private final Deque<ScopeData> scopeStack = new ArrayDeque<>();
private final Deque<Deque<DetailAST>> prevScopeUninitializedVariables = new ArrayDeque<>();
// after
private final Deque<ScopeData> scopeStack = new ArrayDeque<>();
private static final class ScopeData {
private Deque<DetailAST> prevScopeUninitializedVariables = new ArrayDeque<>();
}Because we reuse
Because we still use double array and push / pop operations are equivalent to what they used to be, we do return to the previous state. Let's check this: EXPR // before
public void visitToken(DetailAST ast) {
case TokenTypes.EXPR:
if (ast.getParent().getType() == TokenTypes.SWITCH_RULE) {
// store `Deque<DetailAST> prevScopeUninitializedVariableData`
// into `prevScopeUninitializedVariables`
storePrevScopeUninitializedVariableData();
}
}
public void leaveToken(DetailAST ast) {
case TokenTypes.EXPR:
if (parentAst.getType() == TokenTypes.SWITCH_RULE) {
// no pop happens
prevScopeUninitializedVariableData = prevScopeUninitializedVariables.peek();
if (shouldUpdateUninitializedVariables(parentAst)) {
updateAllUninitializedVariables(prevScopeUninitializedVariableData);
}
}
}
// after
public void visitToken(DetailAST ast) {
case TokenTypes.EXPR:
if (ast.getParent().getType() == TokenTypes.SWITCH_RULE) {
// store `Deque<DetailAST> prevScopeUninitializedVariableData` into `scopeStack`
storePrevScopeUninitializedVariableData();
}
}
public void leaveToken(DetailAST ast) {
case TokenTypes.EXPR:
if (parentAst.getType() == TokenTypes.SWITCH_RULE ....) {
// no pop happens, similar iteration over all scopes trying to update
// uninitialized variables as before
updateAllUninitializedVariables();
}
}SLIST // before
public void visitToken(DetailAST ast) {
case TokenTypes.SLIST:
if (ast.getParent().getType() != TokenTypes.CASE_GROUP....) {
// store `Deque<DetailAST> prevScopeUninitializedVariableData`
// into `prevScopeUninitializedVariables `
storePrevScopeUninitializedVariableData();
scopeStack.push(new ScopeData());
}
}
public void leaveToken(DetailAST ast) {
case TokenTypes.SLIST:
prevScopeUninitializedVariableData = prevScopeUninitializedVariables.peek();
if (parentAst.getType() != TokenTypes.CASE_GROUP....) {
scope = scopeStack.pop().scope;
prevScopeUninitializedVariables.pop();
}
if (containsBreak || shouldUpdateUninitializedVariables(parentAst)) {
// use the last element from `prevScopeUninitializedVariables` which was popped
updateAllUninitializedVariables(prevScopeUninitializedVariableData);
}
}
// after
public void visitToken(DetailAST ast) {
case TokenTypes.SLIST:
if (ast.getParent().getType() != TokenTypes.CASE_GROUP....) {
// store `Deque<DetailAST> prevScopeUninitializedVariableData` into `scopeStack`
storePrevScopeUninitializedVariableData();
scopeStack.push(new ScopeData());
}
}
public void leaveToken(DetailAST ast) {
case TokenTypes.SLIST:
if (parentAst.getType() != TokenTypes.CASE_GROUP......) {
// it is safe to pop because `prevScopeUninitializedVariableData` is contained
// in the next element due to the push ordering in the `visitToken`
scope = scopeStack.pop().scope;
}
if (containsBreak || shouldUpdateUninitializedVariables(parentAst)) {
// at this point `scopeStack.peek` contains `prevScopeUninitializedVariableData`
// which was stored during `visitToken`
updateAllUninitializedVariables();
}
} |
rnveach
left a comment
There was a problem hiding this comment.
I think I am good with the changes now. Enough analysis has been done that I agree with that this hopefully won't be an issue.
| scope = scopeStack.pop().scope; | ||
| prevScopeUninitializedVariables.pop(); |
There was a problem hiding this comment.
prevScopeUninitializedVariables.pop(); was only popped here. But now that prevScopeUV are stored in ScopeData, which is:
- being popped here, same as
prevScopeUninitializedVariables✅ - Being popped at 🤔
@rdiachenko Can you please confirm that this won't cause a problem?
There was a problem hiding this comment.
It shouldn't cause a problem because of the equivalent push in the visitToken. The popped value always contains empty previous data list at this point.
Issue #12671
Diff Regression config: https://gist.githubusercontent.com/Kevin222004/6e271c2ae713051c0a30111211de5627/raw/9f34341ce6c7feabbda4bc3d59fa62df427d775d/FinalLocal.xml
Diff Regression projects: https://gist.githubusercontent.com/Kevin222004/9600f179b602d4c971bdb0a050099005/raw/360a95ed7bb60d7a0956e531199d484c4d6f6617/test-projects.properties
Report label: Regression-Oct-03
Attempt to improve this PR and kill mutation without affecting performance issues mentioned in the comments.
We don't need a separate stack for
prevScopeUninitializedVariables. We can track those variables withinScopeDataand rely on the current check's logic topopfromscopeStack.