All Downloads are FREE. Search and download functionalities are using the official Maven repository.

au.com.integradev.delphi.checks.AssignedAndFreeCheck Maven / Gradle / Ivy

The newest version!
/*
 * Sonar Delphi Plugin
 * Copyright (C) 2011 Sabre Airline Solutions and Fabricio Colombo
 * Author(s):
 * Przemyslaw Kociolek ([email protected])
 * Michal Wojcik ([email protected])
 * Fabricio Colombo ([email protected])
 *
 * 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 javax.annotation.Nullable;
import org.sonar.check.Rule;
import org.sonar.plugins.communitydelphi.api.ast.ArgumentListNode;
import org.sonar.plugins.communitydelphi.api.ast.BinaryExpressionNode;
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.IfStatementNode;
import org.sonar.plugins.communitydelphi.api.ast.Node;
import org.sonar.plugins.communitydelphi.api.ast.PrimaryExpressionNode;
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.operator.BinaryOperator;
import org.sonar.plugins.communitydelphi.api.reporting.DelphiIssueBuilder;
import org.sonar.plugins.communitydelphi.api.reporting.QuickFix;
import org.sonar.plugins.communitydelphi.api.reporting.QuickFixEdit;
import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey;

@DeprecatedRuleKey(ruleKey = "AssignedAndFreeRule", repositoryKey = "delph")
@Rule(key = "AssignedAndFree")
public class AssignedAndFreeCheck extends DelphiCheck {
  private static final String MESSAGE = "Remove this unnecessary assignment check.";

  @Override
  public DelphiCheckContext visit(IfStatementNode statement, DelphiCheckContext context) {
    DelphiNode violation = findViolation(statement);
    if (violation != null) {
      DelphiIssueBuilder newIssue = context.newIssue().onNode(violation).withMessage(MESSAGE);

      if (!statement.hasElseBranch()) {
        newIssue.withQuickFixes(buildQuickFix(statement));
      }

      newIssue.report();
    }
    return super.visit(statement, context);
  }

  private QuickFix buildQuickFix(IfStatementNode ifStatement) {
    StatementNode thenStatement = ifStatement.getThenStatement();

    if (thenStatement instanceof CompoundStatementNode) {
      thenStatement = ((CompoundStatementNode) thenStatement).getStatements().get(0);
    }

    return QuickFix.newFix("Remove redundant assignment check")
        .withEdits(QuickFixEdit.copyReplacing(thenStatement, ifStatement));
  }

  private static DelphiNode findViolation(IfStatementNode ifStatement) {
    ExpressionNode guard = ifStatement.getGuardExpression().skipParentheses();
    String variableName = findVariableName(guard);

    if (variableName == null) {
      return null;
    }

    return findFreeStatement(ifStatement.getThenStatement(), variableName);
  }

  private static String findVariableName(ExpressionNode guard) {
    if (guard instanceof PrimaryExpressionNode) {
      return findVariableNameForAssigned(guard);
    } else if (guard instanceof BinaryExpressionNode) {
      return findVariableNameForNilComparison(guard);
    }

    return null;
  }

  private static String findVariableNameForAssigned(ExpressionNode guard) {
    Node routine = guard.getChild(0);
    if (guard.getChildren().size() < 2 || !routine.getImage().equalsIgnoreCase("Assigned")) {
      return null;
    }

    Node sibling = guard.getChild(1);
    if (sibling instanceof ArgumentListNode) {
      ArgumentListNode argumentList = (ArgumentListNode) sibling;
      if (!argumentList.isEmpty()) {
        return argumentList.getArgumentNodes().get(0).getExpression().getImage();
      }
    }

    return null;
  }

  private static String findVariableNameForNilComparison(ExpressionNode guard) {
    BinaryExpressionNode expr = (BinaryExpressionNode) guard;
    if (expr.getOperator() == BinaryOperator.NOT_EQUAL) {
      if (ExpressionNodeUtils.isNilLiteral(expr.getLeft())) {
        return expr.getRight().getImage();
      }

      if (ExpressionNodeUtils.isNilLiteral(expr.getRight())) {
        return expr.getLeft().getImage();
      }
    }

    return null;
  }

  private static DelphiNode findFreeStatement(
      @Nullable StatementNode statement, String variableName) {
    if (statement instanceof CompoundStatementNode) {
      CompoundStatementNode beginStatement = (CompoundStatementNode) statement;
      if (!beginStatement.isEmpty()) {
        return findFreeStatement(beginStatement.getStatements().get(0), variableName);
      }
    } else if (statement instanceof ExpressionStatementNode) {
      ExpressionNode expr = ((ExpressionStatementNode) statement).getExpression();
      if (isFreeExpression(expr, variableName)) {
        return statement;
      }
    }
    return null;
  }

  private static boolean isFreeExpression(ExpressionNode expr, String variableName) {
    return expr.getImage().equalsIgnoreCase("FreeAndNil(" + variableName + ")")
        || expr.getImage().equalsIgnoreCase(variableName + ".Free")
        || expr.getImage().equalsIgnoreCase(variableName + ".Free()");
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy