[AST] Extract Decl::printNestedNameSpecifier helper from Decl::printQualifiedName

Summary:
To be used in clangd, e.g. in D66647.
Currently the alternative to this function is doing string manipulation on results of `printQualifiedName`, which is
hard-to-impossible to get right in presence of template arguments.

Reviewers: kadircet, aaron.ballman

Reviewed By: kadircet, aaron.ballman

Subscribers: aaron.ballman, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D67825

llvm-svn: 372863
This commit is contained in:
Ilya Biryukov 2019-09-25 13:09:10 +00:00
parent d0b44dbefd
commit 1e36ed7fbc
3 changed files with 80 additions and 20 deletions

View File

@ -310,6 +310,14 @@ public:
void printQualifiedName(raw_ostream &OS) const;
void printQualifiedName(raw_ostream &OS, const PrintingPolicy &Policy) const;
/// Print only the nested name specifier part of a fully-qualified name,
/// including the '::' at the end. E.g.
/// when `printQualifiedName(D)` prints "A::B::i",
/// this function prints "A::B::".
void printNestedNameSpecifier(raw_ostream &OS) const;
void printNestedNameSpecifier(raw_ostream &OS,
const PrintingPolicy &Policy) const;
// FIXME: Remove string version.
std::string getQualifiedNameAsString() const;

View File

@ -1558,6 +1558,19 @@ void NamedDecl::printQualifiedName(raw_ostream &OS) const {
void NamedDecl::printQualifiedName(raw_ostream &OS,
const PrintingPolicy &P) const {
printNestedNameSpecifier(OS, P);
if (getDeclName() || isa<DecompositionDecl>(this))
OS << *this;
else
OS << "(anonymous)";
}
void NamedDecl::printNestedNameSpecifier(raw_ostream &OS) const {
printNestedNameSpecifier(OS, getASTContext().getPrintingPolicy());
}
void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
const PrintingPolicy &P) const {
const DeclContext *Ctx = getDeclContext();
// For ObjC methods and properties, look through categories and use the
@ -1571,10 +1584,8 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
Ctx = ID;
}
if (Ctx->isFunctionOrMethod()) {
printName(OS);
if (Ctx->isFunctionOrMethod())
return;
}
using ContextsTy = SmallVector<const DeclContext *, 8>;
ContextsTy Contexts;
@ -1644,11 +1655,6 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
}
OS << "::";
}
if (getDeclName() || isa<DecompositionDecl>(this))
OS << *this;
else
OS << "(anonymous)";
}
void NamedDecl::getNameForDiagnostic(raw_ostream &OS,

View File

@ -16,9 +16,12 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
using namespace clang;
@ -30,11 +33,12 @@ namespace {
class PrintMatch : public MatchFinder::MatchCallback {
SmallString<1024> Printed;
unsigned NumFoundDecls;
bool SuppressUnwrittenScope;
std::function<void(llvm::raw_ostream &OS, const NamedDecl *)> Printer;
public:
explicit PrintMatch(bool suppressUnwrittenScope)
: NumFoundDecls(0), SuppressUnwrittenScope(suppressUnwrittenScope) {}
explicit PrintMatch(
std::function<void(llvm::raw_ostream &OS, const NamedDecl *)> Printer)
: NumFoundDecls(0), Printer(std::move(Printer)) {}
void run(const MatchFinder::MatchResult &Result) override {
const NamedDecl *ND = Result.Nodes.getNodeAs<NamedDecl>("id");
@ -45,9 +49,7 @@ public:
return;
llvm::raw_svector_ostream Out(Printed);
PrintingPolicy Policy = Result.Context->getPrintingPolicy();
Policy.SuppressUnwrittenScope = SuppressUnwrittenScope;
ND->printQualifiedName(Out, Policy);
Printer(Out, ND);
}
StringRef getPrinted() const {
@ -59,12 +61,12 @@ public:
}
};
::testing::AssertionResult
PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
bool SuppressUnwrittenScope,
const DeclarationMatcher &NodeMatch,
StringRef ExpectedPrinted, StringRef FileName) {
PrintMatch Printer(SuppressUnwrittenScope);
::testing::AssertionResult PrintedDeclMatches(
StringRef Code, const std::vector<std::string> &Args,
const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted,
StringRef FileName,
std::function<void(llvm::raw_ostream &, const NamedDecl *)> Print) {
PrintMatch Printer(std::move(Print));
MatchFinder Finder;
Finder.addMatcher(NodeMatch, &Printer);
std::unique_ptr<FrontendActionFactory> Factory =
@ -91,6 +93,21 @@ PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
return ::testing::AssertionSuccess();
}
::testing::AssertionResult
PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
bool SuppressUnwrittenScope,
const DeclarationMatcher &NodeMatch,
StringRef ExpectedPrinted, StringRef FileName) {
return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, FileName,
[=](llvm::raw_ostream &Out, const NamedDecl *ND) {
auto Policy =
ND->getASTContext().getPrintingPolicy();
Policy.SuppressUnwrittenScope =
SuppressUnwrittenScope;
ND->printQualifiedName(Out, Policy);
});
}
::testing::AssertionResult
PrintedNamedDeclCXX98Matches(StringRef Code, StringRef DeclName,
StringRef ExpectedPrinted) {
@ -127,6 +144,17 @@ PrintedWrittenPropertyDeclObjCMatches(StringRef Code, StringRef DeclName,
"input.m");
}
::testing::AssertionResult
PrintedNestedNameSpecifierMatches(StringRef Code, StringRef DeclName,
StringRef ExpectedPrinted) {
std::vector<std::string> Args{"-std=c++11"};
return PrintedDeclMatches(Code, Args, namedDecl(hasName(DeclName)).bind("id"),
ExpectedPrinted, "input.cc",
[](llvm::raw_ostream &Out, const NamedDecl *D) {
D->printNestedNameSpecifier(Out);
});
}
} // unnamed namespace
TEST(NamedDeclPrinter, TestNamespace1) {
@ -223,3 +251,21 @@ R"(
"property",
"Obj::property"));
}
TEST(NamedDeclPrinter, NestedNameSpecifierSimple) {
const char *Code =
R"(
namespace foo { namespace bar { void func(); } }
)";
ASSERT_TRUE(PrintedNestedNameSpecifierMatches(Code, "func", "foo::bar::"));
}
TEST(NamedDeclPrinter, NestedNameSpecifierTemplateArgs) {
const char *Code =
R"(
template <class T> struct vector;
template <> struct vector<int> { int method(); };
)";
ASSERT_TRUE(
PrintedNestedNameSpecifierMatches(Code, "method", "vector<int>::"));
}