forked from OSchip/llvm-project
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:
parent
093a729e03
commit
b23b39da21
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue