[PATCH] D42730: Add clang-tidy check for use of types/classes/functions from <functional> header which are deprecated and removed in C++17

Alexander Kornienko via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 31 10:22:08 PST 2018


alexfh added inline comments.


================
Comment at: test/clang-tidy/modernize-avoid-functional.cpp:30
+
+// CHECK-MESSAGES: [[@LINE+1]]:25: warning: 'binary_function<int, int, bool>' is deprecated in C++11 and removed in C++17 [modernize-avoid-functional]
+class BinaryTestClass : public std::binary_function<int, int, bool> {
----------------
Template parameters in this message are not useful. binary_function is removed in C++17 regardless of the template parameters used. I played with your patch a bit and  came up with a way to remove the template parameters in a not overly hacky way (and also pulled out the common part of the message to avoid duplication):

```
void AvoidFunctionalCheck::registerMatchers(MatchFinder *Finder) {
  Finder->addMatcher(
      cxxRecordDecl(allOf(isDerivedFrom(classTemplateSpecializationDecl(
                                            hasAnyName("std::binary_function",
                                                       "std::unary_function"))
                                            .bind("base")),
                          anyOf(isClass(), ast_matchers::isStruct()),
                          ast_matchers::isDefinition()))
          .bind("un_or_binary_derived"),
      this);
  Finder->addMatcher(callExpr(callee(functionDecl(hasName("std::ptr_fun"))))
                         .bind("ptr_fun_call"),
                     this);
  Finder->addMatcher(callExpr(callee(functionDecl(hasName("std::mem_fun"))))
                         .bind("mem_fun_call"),
                     this);
}

void AvoidFunctionalCheck::check(const MatchFinder::MatchResult &Result) {
  const StringRef Message = "%0 is deprecated in C++11 and removed in C++17";
  if (const auto *const Decl =
          Result.Nodes.getNodeAs<CXXRecordDecl>("un_or_binary_derived")) {
    const auto *SpecDecl =
        Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("base");
    for (CXXBaseSpecifier Base : Decl->bases()) {
      if (SpecDecl == Base.getType()->getAsCXXRecordDecl())
        diag(Base.getLocStart(), Message) << SpecDecl->getSpecializedTemplate();
    }
  } else if (const auto *const Call =
                 Result.Nodes.getNodeAs<CallExpr>("ptr_fun_call")) {
    diag(Call->getLocStart(), Message) << "'std::ptr_fun'";
  } else if (const auto *const Call =
                 Result.Nodes.getNodeAs<CallExpr>("mem_fun_call")) {
    diag(Call->getLocStart(), Message) << "'std::mem_fun'";
  }
}
```

This could be done differently, of course, depending on which way this check is going to evolutionize (e.g. if you're going to find usages of deprecated entities on a lower level - say, TypeLocs, or if you're going to provide fixits for narrower usage patterns).


https://reviews.llvm.org/D42730





More information about the cfe-commits mailing list