void AvoidGotoCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus)
    return;

  // TODO: This check does not recognize `IndirectGotoStmt` which is a
  // GNU extension. These must be matched separately and an AST matcher
  // is currently missing for them.

  // Check if the 'goto' is used for control flow other than jumping
  // out of a nested loop.
  auto Loop = stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt()));
  auto NestedLoop =
      stmt(anyOf(forStmt(hasAncestor(Loop)), cxxForRangeStmt(hasAncestor(Loop)),
                 whileStmt(hasAncestor(Loop)), doStmt(hasAncestor(Loop))));

  Finder->addMatcher(gotoStmt(anyOf(unless(hasAncestor(NestedLoop)),
                                    unless(isForwardJumping())))
                         .bind("goto"),
                     this);
}
void InefficientStringConcatenationCheck::registerMatchers(
    MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus)
    return;

  const auto BasicStringType =
      hasType(qualType(hasUnqualifiedDesugaredType(recordType(
          hasDeclaration(cxxRecordDecl(hasName("::std::basic_string")))))));

  const auto BasicStringPlusOperator = cxxOperatorCallExpr(
      hasOverloadedOperatorName("+"),
      hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))));

  const auto PlusOperator =
      cxxOperatorCallExpr(
          hasOverloadedOperatorName("+"),
          hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))),
          hasDescendant(BasicStringPlusOperator))
          .bind("plusOperator");

  const auto AssignOperator = cxxOperatorCallExpr(
      hasOverloadedOperatorName("="),
      hasArgument(0, declRefExpr(BasicStringType,
                                 hasDeclaration(decl().bind("lhsStrT")))
                         .bind("lhsStr")),
      hasArgument(1, stmt(hasDescendant(declRefExpr(
                         hasDeclaration(decl(equalsBoundNode("lhsStrT"))))))),
      hasDescendant(BasicStringPlusOperator));

  if (StrictMode) {
    Finder->addMatcher(cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator)),
                       this);
  } else {
    Finder->addMatcher(
        cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator),
                            hasAncestor(stmt(anyOf(cxxForRangeStmt(),
                                                   whileStmt(), forStmt())))),
        this);
  }
}
AST_MATCHER(Stmt, isInsideOfRangeBeginEndStmt) {
  return stmt(hasAncestor(cxxForRangeStmt(
                  hasRangeBeginEndStmt(hasDescendant(equalsNode(&Node))))))
      .matches(Node, Finder, Builder);
}