au.com.integradev.delphi.checks.InheritedMethodWithNoCodeCheck Maven / Gradle / Ivy
/*
* Sonar Delphi Plugin
* Copyright (C) 2019 Integrated Application Development
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* 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 GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package au.com.integradev.delphi.checks;
import au.com.integradev.delphi.utils.RoutineUtils;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.sonar.check.Rule;
import org.sonar.plugins.communitydelphi.api.ast.ArgumentListNode;
import org.sonar.plugins.communitydelphi.api.ast.ArgumentNode;
import org.sonar.plugins.communitydelphi.api.ast.AssignmentStatementNode;
import org.sonar.plugins.communitydelphi.api.ast.CompoundStatementNode;
import org.sonar.plugins.communitydelphi.api.ast.DelphiNode;
import org.sonar.plugins.communitydelphi.api.ast.ExpressionNode;
import org.sonar.plugins.communitydelphi.api.ast.ExpressionStatementNode;
import org.sonar.plugins.communitydelphi.api.ast.FormalParameterNode.FormalParameterData;
import org.sonar.plugins.communitydelphi.api.ast.NameReferenceNode;
import org.sonar.plugins.communitydelphi.api.ast.Node;
import org.sonar.plugins.communitydelphi.api.ast.PrimaryExpressionNode;
import org.sonar.plugins.communitydelphi.api.ast.RoutineImplementationNode;
import org.sonar.plugins.communitydelphi.api.ast.RoutineNode;
import org.sonar.plugins.communitydelphi.api.ast.StatementNode;
import org.sonar.plugins.communitydelphi.api.ast.utils.ExpressionNodeUtils;
import org.sonar.plugins.communitydelphi.api.check.DelphiCheck;
import org.sonar.plugins.communitydelphi.api.check.DelphiCheckContext;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineDirective;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineNameDeclaration;
import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey;
@DeprecatedRuleKey(ruleKey = "InheritedMethodWithNoCodeRule", repositoryKey = "delph")
@Rule(key = "InheritedMethodWithNoCode")
public class InheritedMethodWithNoCodeCheck extends DelphiCheck {
private static final String MESSAGE = "Remove this useless method override.";
@Override
public DelphiCheckContext visit(RoutineImplementationNode routine, DelphiCheckContext context) {
DelphiNode violationNode = findViolation(routine);
if (violationNode != null) {
reportIssue(context, violationNode, MESSAGE);
}
return super.visit(routine, context);
}
private static DelphiNode findViolation(RoutineImplementationNode routine) {
CompoundStatementNode block = routine.getStatementBlock();
if (block == null) {
return null;
}
List statements = block.getStatements();
if (statements.size() != 1) {
return null;
}
StatementNode statement = statements.get(0);
ExpressionNode expr = null;
if (statement instanceof ExpressionStatementNode) {
expr = ((ExpressionStatementNode) statement).getExpression();
} else if (statement instanceof AssignmentStatementNode) {
AssignmentStatementNode assignment = (AssignmentStatementNode) statement;
if (ExpressionNodeUtils.isResult(assignment.getAssignee())) {
expr = assignment.getValue();
}
}
if (isInheritedCall(routine, expr)
&& !isVisibilityChanged(routine)
&& !isAddingMeaningfulDirectives(routine)) {
return statement;
}
return null;
}
private static boolean isVisibilityChanged(RoutineImplementationNode method) {
List parentMethods = RoutineUtils.findParentMethodDeclarations(method);
if (parentMethods.isEmpty() || method.getRoutineNameDeclaration() == null) {
return true;
}
RoutineNameDeclaration parentMethod = parentMethods.get(0);
return parentMethod.getVisibility().ordinal()
!= method.getRoutineNameDeclaration().getVisibility().ordinal();
}
private static boolean isAddingMeaningfulDirectives(RoutineImplementationNode method) {
List parentMethods = RoutineUtils.findParentMethodDeclarations(method);
if (parentMethods.isEmpty() || method.getRoutineNameDeclaration() == null) {
return false;
}
RoutineNameDeclaration parentMethod = parentMethods.get(0);
Set newDirectives =
method.getRoutineNameDeclaration().getDirectives().stream()
.filter(Predicate.not(parentMethod.getDirectives()::contains))
.collect(Collectors.toSet());
return newDirectives.contains(RoutineDirective.REINTRODUCE)
|| newDirectives.contains(RoutineDirective.VIRTUAL);
}
private static boolean isInheritedCall(RoutineImplementationNode method, ExpressionNode expr) {
if (!(expr instanceof PrimaryExpressionNode)) {
return false;
}
PrimaryExpressionNode expression = (PrimaryExpressionNode) expr;
if (ExpressionNodeUtils.isBareInherited(expression)) {
return true;
}
if (!ExpressionNodeUtils.isInherited(expression)) {
return false;
}
Node reference = expression.getChild(1);
String methodName = method.simpleName();
if (!(reference instanceof NameReferenceNode
&& reference.getImage().equalsIgnoreCase(methodName))) {
return false;
}
Node argumentList = expression.getChild(2);
if (argumentList != null && !(argumentList instanceof ArgumentListNode)) {
return false;
}
return argumentSignaturesMatch(method, (ArgumentListNode) argumentList);
}
private static boolean argumentSignaturesMatch(
RoutineNode routine, ArgumentListNode argumentList) {
List parameters = routine.getParameters();
List arguments =
(argumentList == null) ? Collections.emptyList() : argumentList.getArgumentNodes();
if (arguments.size() != parameters.size()) {
return false;
}
for (int i = 0; i < arguments.size(); ++i) {
if (!arguments
.get(i)
.getExpression()
.getImage()
.equalsIgnoreCase(parameters.get(i).getImage())) {
return false;
}
}
return true;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy