void UseNodiscardCheck::registerMatchers(MatchFinder *Finder) {
  // If we use ``[[nodiscard]]`` attribute, we require at least C++17. Use a
  // macro or ``__attribute__`` with pre c++17 compilers by using
  // ReplacementString option.
  if ((NoDiscardMacro == "[[nodiscard]]" && !getLangOpts().CPlusPlus17) ||
      !getLangOpts().CPlusPlus)
    return;

  auto FunctionObj =
      cxxRecordDecl(hasAnyName("::std::function", "::boost::function"));

  // Find all non-void const methods which have not already been marked to
  // warn on unused result.
  Finder->addMatcher(
      cxxMethodDecl(
          allOf(isConst(), isDefinitionOrInline(),
                unless(anyOf(
                    returns(voidType()), isNoReturn(), isOverloadedOperator(),
                    isVariadic(), hasTemplateReturnType(),
                    hasClassMutableFields(), isConversionOperator(),
                    hasAttr(clang::attr::WarnUnusedResult),
                    hasType(isInstantiationDependentType()),
                    hasAnyParameter(anyOf(
                        parmVarDecl(anyOf(hasType(FunctionObj),
                                          hasType(references(FunctionObj)))),
                        hasType(isNonConstReferenceOrPointer()),
                        hasParameterPack()))))))
          .bind("no_discard"),
      this);
}
void OpDeleteExprHandler::run(const clang::ast_matchers::MatchFinder::MatchResult& result) {
  const clang::CallExpr* deleteExpr = result.Nodes.getNodeAs<clang::CallExpr>("deleteStmt");
  const clang::FunctionDecl* funDecl = result.Nodes.getNodeAs<clang::FunctionDecl>("fun");
  if (nullptr == deleteExpr) {
    llvm::errs() << "Couldn't convert MatcherResult to CallExpr!\n";
    return;
  }

  clang::SourceLocation startLoc = deleteExpr->getArg(0)->getLocStart();
  clang::SourceLocation endLoc = deleteExpr->getArg(0)->getLocEnd();

  const clang::Expr* pointerExpr = deleteExpr->getArg(0)->IgnoreCasts();

  auto deletedType = pointerExpr->getType();
  auto ptr = deletedType.getTypePtr();
  if (!ptr->isInstantiationDependentType() && !ptr->hasUnnamedOrLocalType()) {
    handleSpecializedType(pointerExpr->getType(), startLoc.getRawEncoding(), CONVERT_TO_POINTEE);
  }

  if (!processingLocation(startLoc)) return;

  MacroAdder deleteLoggerMacro(funDecl->getNameInfo().getName().getAsString() == "operator delete[]"
                                   ? "TYPEGRIND_LOG_OP_DELETE_ARRAY"
                                   : "TYPEGRIND_LOG_OP_DELETE",
                               startLoc, endLoc, mRewriter);

  // 2nd and 3rd paramter: name of the type.
  addTypeInformationParameters(deleteLoggerMacro, deletedType, startLoc.getRawEncoding(),
                               CONVERT_TO_POINTEE);

  // last parameter: the pointer expression
  // parenthesis around it, for multiple template parameters
  deleteLoggerMacro.startBuffer() << "(";
  deleteLoggerMacro.endBuffer() << ")";

  deleteLoggerMacro.commitAroundLocations();
}