Introduce DynTypedNode::print, dump and getSourceRange.

These functions can generally be applied to multiple kinds of AST node,
so it makes sense to add them to DynTypedNode.

Differential Revision: http://llvm-reviews.chandlerc.com/D2096

llvm-svn: 194113
This commit is contained in:
Peter Collingbourne 2013-11-06 00:27:12 +00:00
parent 093a729e03
commit b23b39da21
4 changed files with 186 additions and 0 deletions

View File

@ -25,7 +25,16 @@
#include "clang/Basic/LLVM.h"
#include "llvm/Support/AlignOf.h"
namespace llvm {
class raw_ostream;
}
namespace clang {
struct PrintingPolicy;
namespace ast_type_traits {
/// \brief Kind identifier.
@ -168,6 +177,16 @@ public:
/// method returns NULL.
const void *getMemoizationData() const;
/// \brief Prints the node to the given output stream.
void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const;
/// \brief Dumps the node to the given output stream.
void dump(llvm::raw_ostream &OS, SourceManager &SM) const;
/// \brief For nodes which represent textual entities in the source code,
/// return their SourceRange. For all other nodes, return SourceRange().
SourceRange getSourceRange() const;
/// @{
/// \brief Imposes an order on \c DynTypedNode.
///

View File

@ -14,6 +14,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
namespace clang {
namespace ast_type_traits {
@ -54,5 +56,50 @@ bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived) {
StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; }
void DynTypedNode::print(llvm::raw_ostream &OS,
const PrintingPolicy &PP) const {
if (const TemplateArgument *TA = get<TemplateArgument>())
TA->print(PP, OS);
else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
NNS->print(OS, PP);
else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
NNSL->getNestedNameSpecifier()->print(OS, PP);
else if (const QualType *QT = get<QualType>())
QT->print(OS, PP);
else if (const TypeLoc *TL = get<TypeLoc>())
TL->getType().print(OS, PP);
else if (const Decl *D = get<Decl>())
D->print(OS, PP);
else if (const Stmt *S = get<Stmt>())
S->printPretty(OS, 0, PP);
else if (const Type *T = get<Type>())
QualType(T, 0).print(OS, PP);
else
OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n";
}
void DynTypedNode::dump(llvm::raw_ostream &OS, SourceManager &SM) const {
if (const Decl *D = get<Decl>())
D->dump(OS);
else if (const Stmt *S = get<Stmt>())
S->dump(OS, SM);
else
OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";
}
SourceRange DynTypedNode::getSourceRange() const {
if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>())
return CCI->getSourceRange();
if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
return NNSL->getSourceRange();
if (const TypeLoc *TL = get<TypeLoc>())
return TL->getSourceRange();
if (const Decl *D = get<Decl>())
return D->getSourceRange();
if (const Stmt *S = get<Stmt>())
return S->getSourceRange();
return SourceRange();
}
} // end namespace ast_type_traits
} // end namespace clang

View File

@ -10,6 +10,9 @@
#include "clang/AST/ASTTypeTraits.h"
#include "gtest/gtest.h"
#include "MatchVerifier.h"
using namespace clang::ast_matchers;
namespace clang {
namespace ast_type_traits {
@ -58,5 +61,54 @@ TEST(ASTNodeKind, Name) {
EXPECT_EQ("<None>", ASTNodeKind().asStringRef());
}
TEST(DynTypedNode, DeclSourceRange) {
RangeVerifier<DynTypedNode> Verifier;
Verifier.expectRange(1, 1, 1, 11);
EXPECT_TRUE(Verifier.match("void f() {}", decl()));
}
TEST(DynTypedNode, StmtSourceRange) {
RangeVerifier<DynTypedNode> Verifier;
Verifier.expectRange(1, 10, 1, 11);
EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
}
TEST(DynTypedNode, TypeLocSourceRange) {
RangeVerifier<DynTypedNode> Verifier;
Verifier.expectRange(1, 1, 1, 8);
EXPECT_TRUE(Verifier.match("void f() {}", typeLoc(loc(functionType()))));
}
TEST(DynTypedNode, NNSLocSourceRange) {
RangeVerifier<DynTypedNode> Verifier;
Verifier.expectRange(1, 33, 1, 34);
EXPECT_TRUE(Verifier.match("namespace N { typedef void T; } N::T f() {}",
nestedNameSpecifierLoc()));
}
TEST(DynTypedNode, DeclDump) {
DumpVerifier Verifier;
Verifier.expectSubstring("FunctionDecl");
EXPECT_TRUE(Verifier.match("void f() {}", functionDecl()));
}
TEST(DynTypedNode, StmtDump) {
DumpVerifier Verifier;
Verifier.expectSubstring("CompoundStmt");
EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
}
TEST(DynTypedNode, DeclPrint) {
PrintVerifier Verifier;
Verifier.expectString("void f() {\n}\n\n");
EXPECT_TRUE(Verifier.match("void f() {}", functionDecl()));
}
TEST(DynTypedNode, StmtPrint) {
PrintVerifier Verifier;
Verifier.expectString("{\n}\n");
EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
}
} // namespace ast_type_traits
} // namespace clang

View File

@ -125,6 +125,20 @@ void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
}
}
template <>
inline void MatchVerifier<ast_type_traits::DynTypedNode>::run(
const MatchFinder::MatchResult &Result) {
BoundNodes::IDToNodeMap M = Result.Nodes.getMap();
BoundNodes::IDToNodeMap::const_iterator I = M.find("");
if (I == M.end()) {
setFailure("Node was not bound");
} else {
// Callback has been called, default to success.
setSuccess();
verify(Result, I->second);
}
}
/// \brief Verify whether a node has the correct source location.
///
/// By default, Node.getSourceLocation() is checked. This can be changed
@ -207,5 +221,59 @@ private:
unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn;
};
/// \brief Verify whether a node's dump contains a given substring.
class DumpVerifier : public MatchVerifier<ast_type_traits::DynTypedNode> {
public:
void expectSubstring(const std::string &Str) {
ExpectSubstring = Str;
}
protected:
void verify(const MatchFinder::MatchResult &Result,
const ast_type_traits::DynTypedNode &Node) {
std::string DumpStr;
llvm::raw_string_ostream Dump(DumpStr);
Node.dump(Dump, *Result.SourceManager);
if (Dump.str().find(ExpectSubstring) == std::string::npos) {
std::string MsgStr;
llvm::raw_string_ostream Msg(MsgStr);
Msg << "Expected dump substring <" << ExpectSubstring << ">, found <"
<< Dump.str() << '>';
this->setFailure(Msg.str());
}
}
private:
std::string ExpectSubstring;
};
/// \brief Verify whether a node's pretty print matches a given string.
class PrintVerifier : public MatchVerifier<ast_type_traits::DynTypedNode> {
public:
void expectString(const std::string &Str) {
ExpectString = Str;
}
protected:
void verify(const MatchFinder::MatchResult &Result,
const ast_type_traits::DynTypedNode &Node) {
std::string PrintStr;
llvm::raw_string_ostream Print(PrintStr);
Node.print(Print, Result.Context->getPrintingPolicy());
if (Print.str() != ExpectString) {
std::string MsgStr;
llvm::raw_string_ostream Msg(MsgStr);
Msg << "Expected pretty print <" << ExpectString << ">, found <"
<< Print.str() << '>';
this->setFailure(Msg.str());
}
}
private:
std::string ExpectString;
};
} // end namespace ast_matchers
} // end namespace clang