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

au.com.integradev.delphi.utils.RoutineUtils Maven / Gradle / Ivy

The newest version!
/*
 * 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.utils;

import static au.com.integradev.delphi.utils.StatementUtils.isRoutineInvocation;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.sonar.plugins.communitydelphi.api.ast.AssignmentStatementNode;
import org.sonar.plugins.communitydelphi.api.ast.RaiseStatementNode;
import org.sonar.plugins.communitydelphi.api.ast.RoutineBodyNode;
import org.sonar.plugins.communitydelphi.api.ast.RoutineImplementationNode;
import org.sonar.plugins.communitydelphi.api.ast.StatementNode;
import org.sonar.plugins.communitydelphi.api.ast.utils.ExpressionNodeUtils;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineKind;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineNameDeclaration;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.TypeNameDeclaration;
import org.sonar.plugins.communitydelphi.api.type.Type;
import org.sonar.plugins.communitydelphi.api.type.Type.ScopedType;

public final class RoutineUtils {
  private RoutineUtils() {
    // Utility class
  }

  public static boolean isStubRoutineWithStackUnwinding(RoutineImplementationNode routine) {
    RoutineBodyNode body = routine.getRoutineBody();
    if (body.hasStatementBlock()) {
      for (StatementNode statement : body.getStatementBlock().getStatements()) {
        if (isStackUnwindingStatement(statement)) {
          return true;
        } else if (!(statement instanceof AssignmentStatementNode)) {
          return false;
        }
      }
    }
    return false;
  }

  private static boolean isStackUnwindingStatement(StatementNode statement) {
    return statement instanceof RaiseStatementNode || isAssertFalse(statement);
  }

  private static boolean isAssertFalse(StatementNode statement) {
    return isRoutineInvocation(
        statement,
        "System.Assert",
        arguments -> ExpressionNodeUtils.isFalse(arguments.get(0).getExpression()));
  }

  private static Stream concreteParentTypesStream(Type type) {
    return type.ancestorList().stream()
        .filter(Type::isClass)
        .findFirst()
        .map(value -> Stream.concat(Stream.of(value), concreteParentTypesStream(value)))
        .orElseGet(Stream::empty);
  }

  private static boolean isOverriddenMethod(
      RoutineNameDeclaration parent, RoutineNameDeclaration child) {
    if (!(parent.getName().equalsIgnoreCase(child.getName())
        && parent.getParametersCount() == child.getParametersCount())) {
      return false;
    }

    if (!IntStream.range(0, parent.getParametersCount())
        .allMatch(
            param ->
                parent.getParameter(param).getType().is(child.getParameter(param).getType()))) {
      return false;
    }

    if (!parent.isClassInvocable()) {
      // A class invocable cannot inherit from an instance invocable
      return !child.isClassInvocable();
    }

    if (parent.getRoutineKind() == RoutineKind.CONSTRUCTOR
        || parent.getRoutineKind() == RoutineKind.DESTRUCTOR) {
      // An instance constructor or destructor cannot inherit from a class constructor or
      // destructor
      return child.isClassInvocable();
    }

    // Any other type of invocable can inherit from a class invocable
    return true;
  }

  public static List findParentMethodDeclarations(
      RoutineImplementationNode method) {
    TypeNameDeclaration typeDeclaration = method.getTypeDeclaration();
    RoutineNameDeclaration nameDeclaration = method.getRoutineNameDeclaration();
    if (typeDeclaration == null || nameDeclaration == null) {
      return Collections.emptyList();
    }

    return concreteParentTypesStream(typeDeclaration.getType())
        .map(ScopedType.class::cast)
        .flatMap(type -> type.typeScope().getRoutineDeclarations().stream())
        .filter(methodDeclaration -> isOverriddenMethod(methodDeclaration, nameDeclaration))
        .collect(Collectors.toUnmodifiableList());
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy