khuttun created this revision. khuttun added reviewers: sepavloff, alexfh. Herald added a subscriber: cfe-commits.
The purpose of this addition is to be able to write AST matchers that match class template member functions by fully qualified name, without the need to explicitly specify the template arguments in the name. For example, to match the call to `S::f` here template <typename T> struct S { void f(); }; void foo() { S<int> s; s.f(); } the matcher currently needs to specify the template arguments: callExpr(callee(functionDecl(hasName("::S<int>::f")))) With the help of this change, it's possible to create a version of `hasName` that ignores the template arguments. The matcher could then be written as callExpr(callee(functionDecl(hasNameIgnoringTemplateArgs("::S::f")))) The motivation for this change is to be able to add checking of class template member functions to clang-tidy checker bugprone-unused-return-value: http://clang.llvm.org/extra/clang-tidy/checks/bugprone-unused-return-value.html The discussion about this can be found in the code review for the checker: https://reviews.llvm.org/D41655?id=130461#inline-374438 Repository: rC Clang https://reviews.llvm.org/D45161 Files: include/clang/AST/PrettyPrinter.h lib/AST/TypePrinter.cpp unittests/AST/NamedDeclPrinterTest.cpp
Index: unittests/AST/NamedDeclPrinterTest.cpp =================================================================== --- unittests/AST/NamedDeclPrinterTest.cpp +++ unittests/AST/NamedDeclPrinterTest.cpp @@ -28,14 +28,19 @@ namespace { +using PrintingPolicyModifier = void (*)(PrintingPolicy &policy); + class PrintMatch : public MatchFinder::MatchCallback { SmallString<1024> Printed; unsigned NumFoundDecls; bool SuppressUnwrittenScope; + PrintingPolicyModifier PolicyModifier; public: - explicit PrintMatch(bool suppressUnwrittenScope) - : NumFoundDecls(0), SuppressUnwrittenScope(suppressUnwrittenScope) {} + explicit PrintMatch(bool suppressUnwrittenScope, + PrintingPolicyModifier PolicyModifier) + : NumFoundDecls(0), SuppressUnwrittenScope(suppressUnwrittenScope), + PolicyModifier(PolicyModifier) {} void run(const MatchFinder::MatchResult &Result) override { const NamedDecl *ND = Result.Nodes.getNodeAs<NamedDecl>("id"); @@ -48,6 +53,8 @@ llvm::raw_svector_ostream Out(Printed); PrintingPolicy Policy = Result.Context->getPrintingPolicy(); Policy.SuppressUnwrittenScope = SuppressUnwrittenScope; + if (PolicyModifier) + PolicyModifier(Policy); ND->printQualifiedName(Out, Policy); } @@ -64,8 +71,9 @@ PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args, bool SuppressUnwrittenScope, const DeclarationMatcher &NodeMatch, - StringRef ExpectedPrinted, StringRef FileName) { - PrintMatch Printer(SuppressUnwrittenScope); + StringRef ExpectedPrinted, StringRef FileName, + PrintingPolicyModifier PolicyModifier) { + PrintMatch Printer(SuppressUnwrittenScope, PolicyModifier); MatchFinder Finder; Finder.addMatcher(NodeMatch, &Printer); std::unique_ptr<FrontendActionFactory> Factory = @@ -94,26 +102,30 @@ ::testing::AssertionResult PrintedNamedDeclCXX98Matches(StringRef Code, StringRef DeclName, - StringRef ExpectedPrinted) { + StringRef ExpectedPrinted, + PrintingPolicyModifier PolicyModifier = nullptr) { std::vector<std::string> Args(1, "-std=c++98"); return PrintedNamedDeclMatches(Code, Args, /*SuppressUnwrittenScope*/ false, namedDecl(hasName(DeclName)).bind("id"), ExpectedPrinted, - "input.cc"); + "input.cc", + PolicyModifier); } ::testing::AssertionResult -PrintedWrittenNamedDeclCXX11Matches(StringRef Code, StringRef DeclName, - StringRef ExpectedPrinted) { +PrintedWrittenNamedDeclCXX11Matches( + StringRef Code, StringRef DeclName, StringRef ExpectedPrinted, + PrintingPolicyModifier PolicyModifier = nullptr) { std::vector<std::string> Args(1, "-std=c++11"); return PrintedNamedDeclMatches(Code, Args, /*SuppressUnwrittenScope*/ true, namedDecl(hasName(DeclName)).bind("id"), ExpectedPrinted, - "input.cc"); + "input.cc", + PolicyModifier); } } // unnamed namespace @@ -180,3 +192,20 @@ "A", "X::A")); } + +TEST(NamedDeclPrinter, TestClassTemplateMemberFunction) { + ASSERT_TRUE(PrintedNamedDeclCXX98Matches( + "template <typename T> struct X { void A(); };" + "void Y() { X<int> x; x.A(); }", + "::X<int>::A", + "X<int>::A")); +} + +TEST(NamedDeclPrinter, TestClassTemplateMemberFunction_SuppressTemplateArgs) { + ASSERT_TRUE(PrintedNamedDeclCXX98Matches( + "template <typename T> struct X { void A(); };" + "void Y() { X<int> x; x.A(); }", + "::X<int>::A", + "X::A", + [](PrintingPolicy &Policy){ Policy.SuppressTemplateArgs = true; })); +} Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -1538,6 +1538,9 @@ template<typename TA> static void printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy, bool SkipBrackets) { + if (Policy.SuppressTemplateArgs) + return; + const char *Comma = Policy.MSVCFormatting ? "," : ", "; if (!SkipBrackets) OS << '<'; Index: include/clang/AST/PrettyPrinter.h =================================================================== --- include/clang/AST/PrettyPrinter.h +++ include/clang/AST/PrettyPrinter.h @@ -52,7 +52,7 @@ Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), ConstantsAsWritten(false), SuppressImplicitBase(false), - FullyQualifiedName(false) { } + FullyQualifiedName(false), SuppressTemplateArgs(false) { } /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -225,6 +225,9 @@ /// When true, print the fully qualified name of function declarations. /// This is the opposite of SuppressScope and thus overrules it. bool FullyQualifiedName : 1; + + /// When true, suppresses printing template arguments + bool SuppressTemplateArgs : 1; }; } // end namespace clang
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits