void DurationConversionCastCheck::registerMatchers(MatchFinder *Finder) {
  auto CallMatcher = ignoringImpCasts(callExpr(
      callee(functionDecl(DurationConversionFunction()).bind("func_decl")),
      hasArgument(0, expr().bind("arg"))));

  Finder->addMatcher(
      expr(anyOf(
          cxxStaticCastExpr(hasSourceExpression(CallMatcher)).bind("cast_expr"),
          cStyleCastExpr(hasSourceExpression(CallMatcher)).bind("cast_expr"),
          cxxFunctionalCastExpr(hasSourceExpression(CallMatcher))
              .bind("cast_expr"))),
      this);
}
void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) {
  const auto DeleteExpr =
      cxxDeleteExpr(has(castExpr(has(declRefExpr(
                        to(decl(equalsBoundNode("deletedPointer"))))))))
          .bind("deleteExpr");

  const auto DeleteMemberExpr =
      cxxDeleteExpr(has(castExpr(has(memberExpr(hasDeclaration(
                        fieldDecl(equalsBoundNode("deletedMemberPointer"))))))))
          .bind("deleteMemberExpr");

  const auto PointerExpr = ignoringImpCasts(anyOf(
      declRefExpr(to(decl().bind("deletedPointer"))),
      memberExpr(hasDeclaration(fieldDecl().bind("deletedMemberPointer")))));

  const auto PointerCondition = castExpr(hasCastKind(CK_PointerToBoolean),
                                         hasSourceExpression(PointerExpr));
  const auto BinaryPointerCheckCondition =
      binaryOperator(hasEitherOperand(castExpr(hasCastKind(CK_NullToPointer))),
                     hasEitherOperand(PointerExpr));

  Finder->addMatcher(
      ifStmt(hasCondition(anyOf(PointerCondition, BinaryPointerCheckCondition)),
             hasThen(anyOf(
                 DeleteExpr, DeleteMemberExpr,
                 compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)),
                              statementCountIs(1))
                     .bind("compound"))))
          .bind("ifWithDelete"),
      this);
}
llvm::Optional<std::string>
stripFloatCast(const ast_matchers::MatchFinder::MatchResult &Result,
               const Expr &Node) {
  if (const Expr *MaybeCastArg = selectFirst<const Expr>(
          "cast_arg",
          match(expr(anyOf(cxxStaticCastExpr(
                               hasDestinationType(realFloatingPointType()),
                               hasSourceExpression(expr().bind("cast_arg"))),
                           cStyleCastExpr(
                               hasDestinationType(realFloatingPointType()),
                               hasSourceExpression(expr().bind("cast_arg"))),
                           cxxFunctionalCastExpr(
                               hasDestinationType(realFloatingPointType()),
                               hasSourceExpression(expr().bind("cast_arg"))))),
                Node, *Result.Context)))
    return tooling::fixit::getText(*MaybeCastArg, *Result.Context).str();

  return llvm::None;
}
void ParentVirtualCallCheck::registerMatchers(MatchFinder *Finder) {
  Finder->addMatcher(
      cxxMemberCallExpr(
          callee(memberExpr(hasDescendant(implicitCastExpr(
                                hasImplicitDestinationType(pointsTo(
                                    type(anything()).bind("castToType"))),
                                hasSourceExpression(cxxThisExpr(hasType(
                                    type(anything()).bind("thisType")))))))
                     .bind("member")),
          callee(cxxMethodDecl(isVirtual()))),
      this);
}
void ProBoundsArrayToPointerDecayCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus)
    return;

  // The only allowed array to pointer decay
  // 1) just before array subscription
  // 2) inside a range-for over an array
  // 3) if it converts a string literal to a pointer
  Finder->addMatcher(
      implicitCastExpr(unless(hasParent(arraySubscriptExpr())),
                       unless(hasParentIgnoringImpCasts(explicitCastExpr())),
                       unless(isInsideOfRangeBeginEndStmt()),
                       unless(hasSourceExpression(stringLiteral())))
          .bind("cast"),
      this);
}
/// Returns `true` if `Node` is a value which evaluates to a literal `0`.
bool IsLiteralZero(const MatchFinder::MatchResult &Result, const Expr &Node) {
  auto ZeroMatcher =
      anyOf(integerLiteral(equals(0)), floatLiteral(equals(0.0)));

  // Check to see if we're using a zero directly.
  if (selectFirst<const clang::Expr>(
          "val", match(expr(ignoringImpCasts(ZeroMatcher)).bind("val"), Node,
                       *Result.Context)) != nullptr)
    return true;

  // Now check to see if we're using a functional cast with a scalar
  // initializer expression, e.g. `int{0}`.
  if (selectFirst<const clang::Expr>(
          "val", match(cxxFunctionalCastExpr(
                           hasDestinationType(
                               anyOf(isInteger(), realFloatingPointType())),
                           hasSourceExpression(initListExpr(
                               hasInit(0, ignoringParenImpCasts(ZeroMatcher)))))
                           .bind("val"),
                       Node, *Result.Context)) != nullptr)
    return true;

  return false;
}
void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) {
  // Match relational operators.
  const auto ComparisonUnaryOperator = unaryOperator(hasOperatorName("!"));
  const auto ComparisonBinaryOperator =
      binaryOperator(matchers::isComparisonOperator());
  const auto ComparisonOperator =
      expr(anyOf(ComparisonUnaryOperator, ComparisonBinaryOperator));

  // Add the list of known string compare-like functions and add user-defined
  // functions.
  std::vector<std::string> FunctionNames = utils::options::parseStringList(
      (llvm::Twine(KnownStringCompareFunctions) + StringCompareLikeFunctions)
          .str());

  // Match a call to a string compare functions.
  const auto FunctionCompareDecl =
      functionDecl(hasAnyName(std::vector<StringRef>(FunctionNames.begin(),
                                                     FunctionNames.end())))
          .bind("decl");
  const auto DirectStringCompareCallExpr =
      callExpr(hasDeclaration(FunctionCompareDecl)).bind("call");
  const auto MacroStringCompareCallExpr = conditionalOperator(anyOf(
      hasTrueExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)),
      hasFalseExpression(ignoringParenImpCasts(DirectStringCompareCallExpr))));
  // The implicit cast is not present in C.
  const auto StringCompareCallExpr = ignoringParenImpCasts(
      anyOf(DirectStringCompareCallExpr, MacroStringCompareCallExpr));

  if (WarnOnImplicitComparison) {
    // Detect suspicious calls to string compare:
    //     'if (strcmp())'  ->  'if (strcmp() != 0)'
    Finder->addMatcher(
        stmt(anyOf(ifStmt(hasCondition(StringCompareCallExpr)),
                   whileStmt(hasCondition(StringCompareCallExpr)),
                   doStmt(hasCondition(StringCompareCallExpr)),
                   forStmt(hasCondition(StringCompareCallExpr)),
                   binaryOperator(
                       anyOf(hasOperatorName("&&"), hasOperatorName("||")),
                       hasEitherOperand(StringCompareCallExpr))))
            .bind("missing-comparison"),
        this);
  }

  if (WarnOnLogicalNotComparison) {
    // Detect suspicious calls to string compared with '!' operator:
    //     'if (!strcmp())'  ->  'if (strcmp() == 0)'
    Finder->addMatcher(unaryOperator(hasOperatorName("!"),
                                     hasUnaryOperand(ignoringParenImpCasts(
                                         StringCompareCallExpr)))
                           .bind("logical-not-comparison"),
                       this);
  }

  // Detect suspicious cast to an inconsistant type (i.e. not integer type).
  Finder->addMatcher(
      implicitCastExpr(unless(hasType(isInteger())),
                       hasSourceExpression(StringCompareCallExpr))
          .bind("invalid-conversion"),
      this);

  // Detect suspicious operator with string compare function as operand.
  Finder->addMatcher(
      binaryOperator(
          unless(anyOf(matchers::isComparisonOperator(), hasOperatorName("&&"),
                       hasOperatorName("||"), hasOperatorName("="))),
          hasEitherOperand(StringCompareCallExpr))
          .bind("suspicious-operator"),
      this);

  // Detect comparison to invalid constant: 'strcmp() == -1'.
  const auto InvalidLiteral = ignoringParenImpCasts(
      anyOf(integerLiteral(unless(equals(0))),
            unaryOperator(
                hasOperatorName("-"),
                has(ignoringParenImpCasts(integerLiteral(unless(equals(0)))))),
            characterLiteral(), cxxBoolLiteral()));

  Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(),
                                    hasEitherOperand(StringCompareCallExpr),
                                    hasEitherOperand(InvalidLiteral))
                         .bind("invalid-comparison"),
                     this);
}