|
16 | 16 | */ |
17 | 17 | package org.sonar.java.checks; |
18 | 18 |
|
19 | | -import java.util.Collection; |
20 | 19 | import java.util.Collections; |
21 | 20 | import java.util.HashSet; |
22 | 21 | import java.util.List; |
23 | 22 | import java.util.Optional; |
24 | 23 | import java.util.Set; |
25 | 24 | import java.util.stream.Collectors; |
26 | 25 | import org.sonar.check.Rule; |
| 26 | +import org.sonar.java.model.ExpressionUtils; |
27 | 27 | import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; |
28 | 28 | import org.sonar.plugins.java.api.semantic.Symbol; |
| 29 | +import org.sonar.plugins.java.api.tree.AssertStatementTree; |
29 | 30 | import org.sonar.plugins.java.api.tree.AssignmentExpressionTree; |
| 31 | +import org.sonar.plugins.java.api.tree.BaseTreeVisitor; |
30 | 32 | import org.sonar.plugins.java.api.tree.BlockTree; |
31 | 33 | import org.sonar.plugins.java.api.tree.ClassTree; |
32 | 34 | import org.sonar.plugins.java.api.tree.ExpressionStatementTree; |
|
37 | 39 | import org.sonar.plugins.java.api.tree.MethodTree; |
38 | 40 | import org.sonar.plugins.java.api.tree.ReturnStatementTree; |
39 | 41 | import org.sonar.plugins.java.api.tree.StatementTree; |
| 42 | +import org.sonar.plugins.java.api.tree.ThrowStatementTree; |
40 | 43 | import org.sonar.plugins.java.api.tree.Tree; |
41 | 44 | import org.sonar.plugins.java.api.tree.VariableTree; |
42 | 45 |
|
@@ -64,7 +67,7 @@ public void visitNode(Tree tree) { |
64 | 67 | if (member.is(Tree.Kind.CONSTRUCTOR)) { |
65 | 68 | checkConstructor((MethodTree) member, componentNames); |
66 | 69 | } else if (member.is(Tree.Kind.METHOD)) { |
67 | | - checkMethod((MethodTree) member, components, componentNames); |
| 70 | + checkMethod((MethodTree) member, components); |
68 | 71 | } |
69 | 72 | } |
70 | 73 | } |
@@ -95,38 +98,30 @@ private void checkConstructor(MethodTree constructor, Set<String> componentNames |
95 | 98 | } |
96 | 99 | } |
97 | 100 |
|
98 | | - private void checkMethod(MethodTree method, List<Symbol.VariableSymbol> components, Set<String> componentsByName) { |
99 | | - String methodName = method.symbol().name(); |
100 | | - if (!componentsByName.contains(methodName)) { |
| 101 | + private void checkMethod(MethodTree method, List<Symbol.VariableSymbol> components) { |
| 102 | + if (isAnnotated(method) || !method.parameters().isEmpty()) { |
101 | 103 | return; |
102 | 104 | } |
103 | | - if (onlyReturnsRawValue(method, components)) { |
104 | | - reportIssue(method.simpleName(), "Remove this redundant method which is the same as a default one."); |
| 105 | + |
| 106 | + String methodName = method.symbol().name(); |
| 107 | + Symbol accessedComponent = components.stream().filter(c -> c.name().equals(methodName)).findFirst().orElse(null); |
| 108 | + if (accessedComponent == null) { |
| 109 | + return; |
105 | 110 | } |
106 | | - } |
107 | 111 |
|
108 | | - public static boolean onlyReturnsRawValue(MethodTree method, Collection<Symbol.VariableSymbol> components) { |
109 | | - Optional<ReturnStatementTree> returnStatement = getFirstReturnStatement(method); |
110 | | - if (!returnStatement.isPresent()) { |
111 | | - return false; |
| 112 | + var accessorVisitor = new AccessorVisitor(); |
| 113 | + method.block().accept(accessorVisitor); |
| 114 | + if (accessorVisitor.containsLogic) { |
| 115 | + return; |
112 | 116 | } |
113 | | - ExpressionTree expression = returnStatement.get().expression(); |
114 | | - Symbol identifierSymbol; |
115 | | - if (expression.is(Tree.Kind.IDENTIFIER)) { |
116 | | - identifierSymbol = ((IdentifierTree) expression).symbol(); |
117 | | - } else if (expression.is(Tree.Kind.MEMBER_SELECT)) { |
118 | | - identifierSymbol = (((MemberSelectExpressionTree) expression).identifier()).symbol(); |
119 | | - } else { |
120 | | - return false; |
| 117 | + if (accessorVisitor.returnedExpressions.stream().allMatch(e -> isComponent(e, accessedComponent))) { |
| 118 | + reportIssue(method.simpleName(), "Remove this redundant method which is the same as a default one."); |
121 | 119 | } |
122 | | - return components.stream().anyMatch(identifierSymbol::equals); |
123 | 120 | } |
124 | 121 |
|
125 | | - private static Optional<ReturnStatementTree> getFirstReturnStatement(MethodTree method) { |
126 | | - return method.block().body().stream() |
127 | | - .filter(statement -> statement.is(Tree.Kind.RETURN_STATEMENT)) |
128 | | - .map(ReturnStatementTree.class::cast) |
129 | | - .findFirst(); |
| 122 | + private static boolean isComponent(ExpressionTree expression, Symbol component) { |
| 123 | + return (ExpressionUtils.skipParentheses(expression) instanceof IdentifierTree identifier && component.equals(identifier.symbol())) |
| 124 | + || (expression instanceof MemberSelectExpressionTree memberSelect && component.equals(memberSelect.identifier().symbol())); |
130 | 125 | } |
131 | 126 |
|
132 | 127 | private static boolean isAnnotated(MethodTree method) { |
@@ -259,4 +254,47 @@ private void mergeWith(ConstructorExecutionState other) { |
259 | 254 | logicAfterAssignments = logicAfterAssignments || other.logicAfterAssignments; |
260 | 255 | } |
261 | 256 | } |
| 257 | + |
| 258 | + private static class AccessorVisitor extends BaseTreeVisitor { |
| 259 | + |
| 260 | + Set<ExpressionTree> returnedExpressions = new HashSet<>(); |
| 261 | + |
| 262 | + boolean containsLogic = false; |
| 263 | + |
| 264 | + @Override |
| 265 | + public void visitReturnStatement(ReturnStatementTree tree) { |
| 266 | + returnedExpressions.add(tree.expression()); |
| 267 | + super.visitReturnStatement(tree); |
| 268 | + } |
| 269 | + |
| 270 | + @Override |
| 271 | + public void visitAssertStatement(AssertStatementTree tree) { |
| 272 | + containsLogic = true; |
| 273 | + super.visitAssertStatement(tree); |
| 274 | + } |
| 275 | + |
| 276 | + @Override |
| 277 | + public void visitThrowStatement(ThrowStatementTree tree) { |
| 278 | + containsLogic = true; |
| 279 | + super.visitThrowStatement(tree); |
| 280 | + } |
| 281 | + |
| 282 | + @Override |
| 283 | + public void visitExpressionStatement(ExpressionStatementTree tree) { |
| 284 | + containsLogic = true; |
| 285 | + super.visitExpressionStatement(tree); |
| 286 | + } |
| 287 | + |
| 288 | + @Override |
| 289 | + public void visitVariable(VariableTree tree) { |
| 290 | + containsLogic = true; |
| 291 | + super.visitVariable(tree); |
| 292 | + } |
| 293 | + |
| 294 | + @Override |
| 295 | + public void visitAssignmentExpression(AssignmentExpressionTree tree) { |
| 296 | + containsLogic = true; |
| 297 | + super.visitAssignmentExpression(tree); |
| 298 | + } |
| 299 | + } |
262 | 300 | } |
0 commit comments