-
Notifications
You must be signed in to change notification settings - Fork 724
Expand file tree
/
Copy pathAssignmentInSubExpressionCheck.java
More file actions
154 lines (135 loc) · 5.29 KB
/
Copy pathAssignmentInSubExpressionCheck.java
File metadata and controls
154 lines (135 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
* SonarQube Java
* Copyright (C) SonarSource Sàrl
* mailto:info AT sonarsource DOT com
*
* You can redistribute and/or modify this program under the terms of
* the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Sonar Source-Available License for more details.
*
* You should have received a copy of the Sonar Source-Available License
* along with this program; if not, see https://sonarsource.com/license/ssal/
*/
package org.sonar.java.checks;
import javax.annotation.Nullable;
import org.sonar.check.Rule;
import org.sonar.java.model.ExpressionUtils;
import org.sonar.plugins.java.api.JavaFileScanner;
import org.sonar.plugins.java.api.JavaFileScannerContext;
import org.sonar.plugins.java.api.tree.AnnotationTree;
import org.sonar.plugins.java.api.tree.AssignmentExpressionTree;
import org.sonar.plugins.java.api.tree.BaseTreeVisitor;
import org.sonar.plugins.java.api.tree.BinaryExpressionTree;
import org.sonar.plugins.java.api.tree.ExpressionStatementTree;
import org.sonar.plugins.java.api.tree.ExpressionTree;
import org.sonar.plugins.java.api.tree.LambdaExpressionTree;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.Tree.Kind;
import org.sonar.plugins.java.api.tree.VariableTree;
import org.sonar.plugins.java.api.tree.WhileStatementTree;
import org.sonar.plugins.java.api.tree.YieldStatementTree;
import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey;
@DeprecatedRuleKey(ruleKey = "AssignmentInSubExpressionCheck", repositoryKey = "squid")
@Rule(key = "S1121")
public class AssignmentInSubExpressionCheck extends BaseTreeVisitor implements JavaFileScanner {
private JavaFileScannerContext context;
@Override
public void scanFile(JavaFileScannerContext context) {
this.context = context;
scan(context.getTree());
}
@Override
public void visitAnnotation(AnnotationTree annotationTree) {
//skip scanning of annotation : assignment in annotation is normal behaviour
scan(annotationTree.annotationType());
}
@Override
public void visitLambdaExpression(LambdaExpressionTree lambdaExpressionTree) {
//skip lambda if body is an assignment
if(!(lambdaExpressionTree.body() instanceof AssignmentExpressionTree)) {
super.visitLambdaExpression(lambdaExpressionTree);
}
}
@Override
public void visitExpressionStatement(ExpressionStatementTree tree) {
ExpressionTree expressionTree = ExpressionUtils.skipParentheses(tree.expression());
expressionTree = skipChainedAssignments(expressionTree);
scan(expressionTree);
}
private ExpressionTree skipChainedAssignments(ExpressionTree expressionTree) {
ExpressionTree tree = ExpressionUtils.skipParentheses(expressionTree);
while (tree instanceof AssignmentExpressionTree assignmentExpressionTree) {
scan(assignmentExpressionTree.variable());
tree = ExpressionUtils.skipParentheses(assignmentExpressionTree.expression());
}
return tree;
}
@Override
public void visitBinaryExpression(BinaryExpressionTree tree) {
if (isRelationalExpression(tree)) {
visitInnerExpression(tree.leftOperand());
visitInnerExpression(tree.rightOperand());
} else {
super.visitBinaryExpression(tree);
}
}
private void visitInnerExpression(ExpressionTree tree) {
AssignmentExpressionTree assignmentExpressionTree = getInnerAssignmentExpression(tree);
if (assignmentExpressionTree != null) {
super.visitAssignmentExpression(assignmentExpressionTree);
} else {
scan(tree);
}
}
@Nullable
private static AssignmentExpressionTree getInnerAssignmentExpression(ExpressionTree tree) {
ExpressionTree expressionTree = ExpressionUtils.skipParentheses(tree);
if (expressionTree.is(Kind.ASSIGNMENT)) {
return (AssignmentExpressionTree) expressionTree;
}
return null;
}
private static boolean isRelationalExpression(Tree tree) {
return tree.is(
Kind.EQUAL_TO,
Kind.NOT_EQUAL_TO,
Kind.LESS_THAN,
Kind.LESS_THAN_OR_EQUAL_TO,
Kind.GREATER_THAN,
Kind.GREATER_THAN_OR_EQUAL_TO);
}
@Override
public void visitWhileStatement(WhileStatementTree tree) {
scan(tree.statement());
}
@Override
public void visitVariable(VariableTree tree) {
ExpressionTree initializer = tree.initializer();
if (initializer != null) {
ExpressionTree expressionTree = skipChainedAssignments(initializer);
scan(expressionTree);
}
}
@Override
public void visitYieldStatement(YieldStatementTree tree) {
if (isWithinSwitchExpression(tree)) {
super.visitYieldStatement(tree);
}
}
private static boolean isWithinSwitchExpression(YieldStatementTree tree) {
Tree parent = tree.parent();
while (!parent.is(Tree.Kind.SWITCH_EXPRESSION, Tree.Kind.SWITCH_STATEMENT, Kind.COMPILATION_UNIT)) {
parent = parent.parent();
}
return parent.is(Tree.Kind.SWITCH_EXPRESSION);
}
@Override
public void visitAssignmentExpression(AssignmentExpressionTree tree) {
super.visitAssignmentExpression(tree);
context.reportIssue(this, tree.operatorToken(), "Extract the assignment out of this expression.");
}
}