void StrCatAppendCheck::registerMatchers(MatchFinder *Finder) {
  if (!getLangOpts().CPlusPlus)
  	return;
  const auto StrCat = functionDecl(hasName("::absl::StrCat"));
  // The arguments of absl::StrCat are implicitly converted to AlphaNum. This 
  // matches to the arguments because of that behavior. 
  const auto AlphaNum = IgnoringTemporaries(cxxConstructExpr(
      argumentCountIs(1), hasType(cxxRecordDecl(hasName("::absl::AlphaNum"))),
      hasArgument(0, ignoringImpCasts(declRefExpr(to(equalsBoundNode("LHS")),
                                                  expr().bind("Arg0"))))));

  const auto HasAnotherReferenceToLhs =
      callExpr(hasAnyArgument(expr(hasDescendant(declRefExpr(
          to(equalsBoundNode("LHS")), unless(equalsBoundNode("Arg0")))))));

  // Now look for calls to operator= with an object on the LHS and a call to
  // StrCat on the RHS. The first argument of the StrCat call should be the same
  // as the LHS. Ignore calls from template instantiations.
  Finder->addMatcher(
      cxxOperatorCallExpr(
          unless(isInTemplateInstantiation()), hasOverloadedOperatorName("="),
          hasArgument(0, declRefExpr(to(decl().bind("LHS")))),
          hasArgument(1, IgnoringTemporaries(
                             callExpr(callee(StrCat), hasArgument(0, AlphaNum),
                                      unless(HasAnotherReferenceToLhs))
                                 .bind("Call"))))
          .bind("Op"),
      this);
}
namespace EffectiveCPP {

    StatementMatcher ctorCallVtlMatcherEC = compoundStmt(
            hasParent(constructorDecl().bind("cDecl")),
            hasDescendant(callExpr(callee(methodDecl(isVirtual()))))
            );
    
    StatementMatcher dtorCallVtlMatcherEC = compoundStmt(
            hasParent(destructorDecl().bind("dDecl")),
            hasDescendant(callExpr(callee(methodDecl(isVirtual()))))
            );
}
void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) {
  // Swap as a function need not to be considered, because rvalue can not
  // be bound to a non-const reference.
  const auto ShrinkableAsMember =
      memberExpr(member(valueDecl().bind("ContainerDecl")));
  const auto ShrinkableAsDecl =
      declRefExpr(hasDeclaration(valueDecl().bind("ContainerDecl")));
  const auto CopyCtorCall = constructExpr(
      hasArgument(0, anyOf(ShrinkableAsMember, ShrinkableAsDecl,
                           unaryOperator(has(ShrinkableAsMember)),
                           unaryOperator(has(ShrinkableAsDecl)))));
  const auto SwapParam = expr(anyOf(
      memberExpr(member(equalsBoundNode("ContainerDecl"))),
      declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))),
      unaryOperator(has(memberExpr(member(equalsBoundNode("ContainerDecl"))))),
      unaryOperator(
          has(declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl")))))));

  Finder->addMatcher(
      memberCallExpr(on(hasType(namedDecl(stlShrinkableContainer()))),
                     callee(methodDecl(hasName("swap"))),
                     has(memberExpr(hasDescendant(CopyCtorCall))),
                     hasArgument(0, SwapParam.bind("ContainerToShrink")),
                     unless(isInTemplateInstantiation()))
          .bind("CopyAndSwapTrick"),
      this);
}
void AssertSideEffectCheck::registerMatchers(MatchFinder *Finder) {
  auto ConditionWithSideEffect =
      hasCondition(hasDescendant(expr(hasSideEffect(CheckFunctionCalls))));
  Finder->addMatcher(
      stmt(anyOf(conditionalOperator(ConditionWithSideEffect),
                 ifStmt(ConditionWithSideEffect))).bind("condStmt"),
      this);
}
void StaticObjectExceptionCheck::registerMatchers(MatchFinder *Finder) {
  if ((!getLangOpts().CPlusPlus) || (!getLangOpts().CXXExceptions))
    return;

  // Match any static or thread_local variable declaration that has an
  // initializer that can throw.
  Finder->addMatcher(
      varDecl(anyOf(hasThreadStorageDuration(), hasStaticStorageDuration()),
              unless(anyOf(isConstexpr(), hasType(cxxRecordDecl(isLambda())),
                           hasAncestor(functionDecl()))),
              anyOf(hasDescendant(cxxConstructExpr(hasDeclaration(
                        cxxConstructorDecl(unless(isNoThrow())).bind("func")))),
                    hasDescendant(cxxNewExpr(hasDeclaration(
                        functionDecl(unless(isNoThrow())).bind("func")))),
                    hasDescendant(callExpr(hasDeclaration(
                        functionDecl(unless(isNoThrow())).bind("func"))))))
          .bind("var"),
      this);
}
bool KMFolder::hasDescendant( KMFolder *fld ) const
{
  if ( !fld )
    return false;
  KMFolderDir * pdir = fld->parent();
  if ( !pdir )
    return false;
  fld = pdir->owner();
  if ( fld == this )
    return true;
  return hasDescendant( fld );
}
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 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);
  }
}
void MisplacedOperatorInStrlenInAllocCheck::registerMatchers(
    MatchFinder *Finder) {
  const auto StrLenFunc = functionDecl(anyOf(
      hasName("::strlen"), hasName("::std::strlen"), hasName("::strnlen"),
      hasName("::std::strnlen"), hasName("::strnlen_s"),
      hasName("::std::strnlen_s"), hasName("::wcslen"),
      hasName("::std::wcslen"), hasName("::wcsnlen"), hasName("::std::wcsnlen"),
      hasName("::wcsnlen_s"), hasName("std::wcsnlen_s")));

  const auto BadUse =
      callExpr(callee(StrLenFunc),
               hasAnyArgument(ignoringImpCasts(
                   binaryOperator(
                       hasOperatorName("+"),
                       hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))
                       .bind("BinOp"))))
          .bind("StrLen");

  const auto BadArg = anyOf(
      allOf(unless(binaryOperator(
                hasOperatorName("+"), hasLHS(BadUse),
                hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))),
            hasDescendant(BadUse)),
      BadUse);

  const auto Alloc0Func =
      functionDecl(anyOf(hasName("::malloc"), hasName("std::malloc"),
                         hasName("::alloca"), hasName("std::alloca")));
  const auto Alloc1Func =
      functionDecl(anyOf(hasName("::calloc"), hasName("std::calloc"),
                         hasName("::realloc"), hasName("std::realloc")));

  const auto Alloc0FuncPtr =
      varDecl(hasType(isConstQualified()),
              hasInitializer(ignoringParenImpCasts(
                  declRefExpr(hasDeclaration(Alloc0Func)))));
  const auto Alloc1FuncPtr =
      varDecl(hasType(isConstQualified()),
              hasInitializer(ignoringParenImpCasts(
                  declRefExpr(hasDeclaration(Alloc1Func)))));

  Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))),
                              hasArgument(0, BadArg))
                         .bind("Alloc"),
                     this);
  Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))),
                              hasArgument(1, BadArg))
                         .bind("Alloc"),
                     this);
  Finder->addMatcher(
      cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this);
}
void ReturnBracedInitListCheck::registerMatchers(MatchFinder *Finder) {
  // Only register the matchers for C++.
  if (!getLangOpts().CPlusPlus11)
    return;

  // Skip list initialization and constructors with an initializer list.
  auto ConstructExpr =
      cxxConstructExpr(
          unless(anyOf(hasDeclaration(cxxConstructorDecl(isExplicit())),
                       isListInitialization(), hasDescendant(initListExpr()),
                       isInTemplateInstantiation())))
          .bind("ctor");

  auto CtorAsArgument = materializeTemporaryExpr(anyOf(
      has(ConstructExpr), has(cxxFunctionalCastExpr(has(ConstructExpr)))));

  Finder->addMatcher(
      functionDecl(isDefinition(), // Declarations don't have return statements.
                   returns(unless(anyOf(builtinType(), autoType()))),
                   hasDescendant(returnStmt(hasReturnValue(
                       has(cxxConstructExpr(has(CtorAsArgument)))))))
          .bind("fn"),
      this);
}
void InterfacesGlobalInitCheck::registerMatchers(MatchFinder *Finder) {
  const auto IsGlobal =
      allOf(hasGlobalStorage(),
            hasDeclContext(anyOf(translationUnitDecl(), // Global scope.
                                 namespaceDecl(),       // Namespace scope.
                                 recordDecl())),        // Class scope.
            unless(isConstexpr()));

  const auto ReferencesUndefinedGlobalVar = declRefExpr(hasDeclaration(
      varDecl(IsGlobal, unless(isDefinition())).bind("referencee")));

  Finder->addMatcher(
      varDecl(IsGlobal, isDefinition(),
              hasInitializer(expr(hasDescendant(ReferencesUndefinedGlobalVar))))
          .bind("var"),
      this);
}
void UniqueptrDeleteReleaseCheck::registerMatchers(MatchFinder *Finder) {
  auto IsSusbstituted = qualType(anyOf(
      substTemplateTypeParmType(), hasDescendant(substTemplateTypeParmType())));

  auto UniquePtrWithDefaultDelete = classTemplateSpecializationDecl(
      hasName("std::unique_ptr"),
      hasTemplateArgument(1, refersToType(qualType(hasDeclaration(cxxRecordDecl(
                                 hasName("std::default_delete")))))));

  Finder->addMatcher(
      cxxDeleteExpr(has(ignoringParenImpCasts(cxxMemberCallExpr(
                        on(expr(hasType(UniquePtrWithDefaultDelete),
                                unless(hasType(IsSusbstituted)))
                               .bind("uptr")),
                        callee(cxxMethodDecl(hasName("release")))))))
          .bind("delete"),
      this);
}
void ProperlySeededRandomGeneratorCheck::registerMatchers(MatchFinder *Finder) {
  auto RandomGeneratorEngineDecl = cxxRecordDecl(hasAnyName(
      "::std::linear_congruential_engine", "::std::mersenne_twister_engine",
      "::std::subtract_with_carry_engine", "::std::discard_block_engine",
      "::std::independent_bits_engine", "::std::shuffle_order_engine"));
  auto RandomGeneratorEngineTypeMatcher = hasType(hasUnqualifiedDesugaredType(
      recordType(hasDeclaration(RandomGeneratorEngineDecl))));

  // std::mt19937 engine;
  // engine.seed();
  //        ^
  // engine.seed(1);
  //        ^
  // const int x = 1;
  // engine.seed(x);
  //        ^
  Finder->addMatcher(
      cxxMemberCallExpr(
          has(memberExpr(has(declRefExpr(RandomGeneratorEngineTypeMatcher)),
                         member(hasName("seed")),
                         unless(hasDescendant(cxxThisExpr())))))
          .bind("seed"),
      this);

  // std::mt19937 engine;
  //              ^
  // std::mt19937 engine(1);
  //              ^
  // const int x = 1;
  // std::mt19937 engine(x);
  //              ^
  Finder->addMatcher(
      cxxConstructExpr(RandomGeneratorEngineTypeMatcher).bind("ctor"), this);

  // srand();
  // ^
  // const int x = 1;
  // srand(x);
  // ^
  Finder->addMatcher(
      callExpr(callee(functionDecl(hasAnyName("::srand", "::std::srand"))))
          .bind("srand"),
      this);
}
void UnusedParametersCheck::warnOnUnusedParameter(
    const MatchFinder::MatchResult &Result, const FunctionDecl *Function,
    unsigned ParamIndex) {
  const auto *Param = Function->getParamDecl(ParamIndex);
  auto MyDiag = diag(Param->getLocation(), "parameter '%0' is unused")
                << Param->getName();

  auto UsedByRef = [&] {
    return !ast_matchers::match(
                decl(hasDescendant(
                    declRefExpr(to(equalsNode(Function)),
                                unless(hasAncestor(
                                    callExpr(callee(equalsNode(Function)))))))),
                *Result.Context->getTranslationUnitDecl(), *Result.Context)
                .empty();
  };

  // Comment out parameter name for non-local functions.
  if (Function->isExternallyVisible() ||
      !Result.SourceManager->isInMainFile(Function->getLocation()) ||
      UsedByRef()) {
    SourceRange RemovalRange(Param->getLocation(), Param->getLocEnd());
    // Note: We always add a space before the '/*' to not accidentally create a
    // '*/*' for pointer types, which doesn't start a comment. clang-format will
    // clean this up afterwards.
    MyDiag << FixItHint::CreateReplacement(
        RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
    return;
  }

  // Fix all redeclarations.
  for (const FunctionDecl *FD : Function->redecls())
    if (FD->param_size())
      MyDiag << removeParameter(FD, ParamIndex);

  // Fix all call sites.
  auto CallMatches = ast_matchers::match(
      decl(forEachDescendant(
          callExpr(callee(functionDecl(equalsNode(Function)))).bind("x"))),
      *Result.Context->getTranslationUnitDecl(), *Result.Context);
  for (const auto &Match : CallMatches)
    MyDiag << removeArgument(Match.getNodeAs<CallExpr>("x"), ParamIndex);
}
void StaticallyConstructedObjectsCheck::registerMatchers(MatchFinder *Finder) {
  // Constructing global, non-trivial objects with static storage is
  // disallowed, unless the object is statically initialized with a constexpr 
  // constructor or has no explicit constructor.

  // Constexpr requires C++11 or later.
  if (!getLangOpts().CPlusPlus11)
    return;

  Finder->addMatcher(varDecl(
                         // Match global, statically stored objects...
                         isGlobalStatic(),
                         // ... that have C++ constructors...
                         hasDescendant(cxxConstructExpr(unless(allOf(
                             // ... unless it is constexpr ...
                             hasDeclaration(cxxConstructorDecl(isConstexpr())),
                             // ... and is statically initialized.
                             isConstantInitializer())))))
                         .bind("decl"),
                     this);
}
void UnusedParametersCheck::warnOnUnusedParameter(
    const MatchFinder::MatchResult &Result, const FunctionDecl *Function,
    unsigned ParamIndex) {
  const auto *Param = Function->getParamDecl(ParamIndex);
  auto MyDiag = diag(Param->getLocation(), "parameter '%0' is unused")
                << Param->getName();

  auto UsedByRef = [&] {
    return !ast_matchers::match(
                decl(hasDescendant(
                    declRefExpr(to(equalsNode(Function)),
                                unless(hasAncestor(
                                    callExpr(callee(equalsNode(Function)))))))),
                *Result.Context->getTranslationUnitDecl(), *Result.Context)
                .empty();
  };

  // Comment out parameter name for non-local functions.
  if ((Function->isExternallyVisible() &&
       Function->getStorageClass() != StorageClass::SC_Static) ||
      UsedByRef()) {
    SourceRange RemovalRange(Param->getLocation(), Param->getLocEnd());
    MyDiag << FixItHint::CreateReplacement(
        RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
    return;
  }

  // Fix all redeclarations.
  for (const FunctionDecl *FD : Function->redecls())
    MyDiag << removeParameter(FD, ParamIndex);

  // Fix all call sites.
  auto CallMatches = ast_matchers::match(
      decl(forEachDescendant(
          callExpr(callee(functionDecl(equalsNode(Function)))).bind("x"))),
      *Result.Context->getTranslationUnitDecl(), *Result.Context);
  for (const auto &Match : CallMatches)
    MyDiag << removeArgument(Match.getNodeAs<CallExpr>("x"), ParamIndex);
}
AST_MATCHER(Stmt, isInsideOfRangeBeginEndStmt) {
  return stmt(hasAncestor(cxxForRangeStmt(
                  hasRangeBeginEndStmt(hasDescendant(equalsNode(&Node))))))
      .matches(Node, Finder, Builder);
}
#include "ASTUtility.h"

StatementMatcher FuncStmtMatcher = compoundStmt(
				hasParent(functionDecl(returns(pointerType())).bind("functiondecl")),
                hasDescendant(returnStmt(
                        hasDescendant(declRefExpr().bind("decl"))))
                ).bind("funcstmt");

class ReturnChecker : public MatchFinder::MatchCallback {
public:
	virtual void run(const MatchFinder::MatchResult &Result)
    {
		clang::ASTContext *Context = Result.Context;
		const clang::CompoundStmt *cs = Result.Nodes.getNodeAs<clang::CompoundStmt>("funcstmt");
		const clang::FunctionDecl *fd = Result.Nodes.getNodeAs<clang::FunctionDecl>("functiondecl");
        const clang::DeclRefExpr *decl = Result.Nodes.getNodeAs<clang::DeclRefExpr>("decl");

		if(!cs || !fd || !decl || ASTUtility::IsStmtInSTDFile(cs, Context)) return;

        if (!clang::VarDecl::classof(decl -> getDecl())) return; 
        
        const clang::VarDecl *var = static_cast<const clang::VarDecl*>(decl -> getDecl());


        if (var -> hasLocalStorage()) 
            ASTUtility::Print(decl, Context, "Rule65");
	}
};

//@TestNeed
static llvm::cl::OptionCategory MyToolCategory("options");