diff options
Diffstat (limited to 'unittests/AST')
-rw-r--r-- | unittests/AST/ASTContextParentMapTest.cpp | 71 | ||||
-rw-r--r-- | unittests/AST/CMakeLists.txt | 1 | ||||
-rw-r--r-- | unittests/AST/CommentLexer.cpp | 168 | ||||
-rw-r--r-- | unittests/AST/CommentParser.cpp | 18 | ||||
-rw-r--r-- | unittests/AST/DeclPrinterTest.cpp | 47 | ||||
-rw-r--r-- | unittests/AST/Makefile | 6 | ||||
-rw-r--r-- | unittests/AST/MatchVerifier.h | 196 | ||||
-rw-r--r-- | unittests/AST/SourceLocationTest.cpp | 202 | ||||
-rw-r--r-- | unittests/AST/StmtPrinterTest.cpp | 11 |
9 files changed, 490 insertions, 230 deletions
diff --git a/unittests/AST/ASTContextParentMapTest.cpp b/unittests/AST/ASTContextParentMapTest.cpp new file mode 100644 index 0000000..c1910a8 --- /dev/null +++ b/unittests/AST/ASTContextParentMapTest.cpp @@ -0,0 +1,71 @@ +//===- unittest/AST/ASTContextParentMapTest.cpp - AST parent map test -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Tests for the getParents(...) methods of ASTContext. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" +#include "MatchVerifier.h" + +namespace clang { +namespace ast_matchers { + +using clang::tooling::newFrontendActionFactory; +using clang::tooling::runToolOnCodeWithArgs; +using clang::tooling::FrontendActionFactory; + +TEST(GetParents, ReturnsParentForDecl) { + MatchVerifier<Decl> Verifier; + EXPECT_TRUE(Verifier.match("class C { void f(); };", + methodDecl(hasParent(recordDecl(hasName("C")))))); +} + +TEST(GetParents, ReturnsParentForStmt) { + MatchVerifier<Stmt> Verifier; + EXPECT_TRUE(Verifier.match("class C { void f() { if (true) {} } };", + ifStmt(hasParent(compoundStmt())))); +} + +TEST(GetParents, ReturnsParentInsideTemplateInstantiations) { + MatchVerifier<Decl> DeclVerifier; + EXPECT_TRUE(DeclVerifier.match( + "template<typename T> struct C { void f() {} };" + "void g() { C<int> c; c.f(); }", + methodDecl(hasName("f"), + hasParent(recordDecl(isTemplateInstantiation()))))); + EXPECT_TRUE(DeclVerifier.match( + "template<typename T> struct C { void f() {} };" + "void g() { C<int> c; c.f(); }", + methodDecl(hasName("f"), + hasParent(recordDecl(unless(isTemplateInstantiation())))))); + EXPECT_FALSE(DeclVerifier.match( + "template<typename T> struct C { void f() {} };" + "void g() { C<int> c; c.f(); }", + methodDecl(hasName("f"), + allOf(hasParent(recordDecl(unless(isTemplateInstantiation()))), + hasParent(recordDecl(isTemplateInstantiation())))))); +} + +TEST(GetParents, ReturnsMultipleParentsInTemplateInstantiations) { + MatchVerifier<Stmt> TemplateVerifier; + EXPECT_TRUE(TemplateVerifier.match( + "template<typename T> struct C { void f() {} };" + "void g() { C<int> c; c.f(); }", + compoundStmt( + allOf(hasAncestor(recordDecl(isTemplateInstantiation())), + hasAncestor(recordDecl(unless(isTemplateInstantiation()))))))); +} + +} // end namespace ast_matchers +} // end namespace clang diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt index 1ea293e..ad29428 100644 --- a/unittests/AST/CMakeLists.txt +++ b/unittests/AST/CMakeLists.txt @@ -1,4 +1,5 @@ add_clang_unittest(ASTTests + ASTContextParentMapTest.cpp CommentLexer.cpp CommentParser.cpp DeclPrinterTest.cpp diff --git a/unittests/AST/CommentLexer.cpp b/unittests/AST/CommentLexer.cpp index 2723a61..507daf8 100644 --- a/unittests/AST/CommentLexer.cpp +++ b/unittests/AST/CommentLexer.cpp @@ -7,16 +7,16 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" #include "clang/AST/CommentLexer.h" #include "clang/AST/CommentCommandTraits.h" +#include "clang/Basic/CommentOptions.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/STLExtras.h" -#include <vector> - #include "gtest/gtest.h" +#include <vector> using namespace llvm; using namespace clang; @@ -32,7 +32,7 @@ protected: DiagID(new DiagnosticIDs()), Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), SourceMgr(Diags, FileMgr), - Traits(Allocator) { + Traits(Allocator, CommentOptions()) { } FileSystemOptions FileMgrOpts; @@ -301,8 +301,10 @@ TEST_F(CommentLexerTest, DoxygenCommand3) { // Doxygen escape sequences. TEST_F(CommentLexerTest, DoxygenCommand4) { - const char *Source = - "/// \\\\ \\@ \\& \\$ \\# \\< \\> \\% \\\" \\. \\::"; + const char *Sources[] = { + "/// \\\\ \\@ \\& \\$ \\# \\< \\> \\% \\\" \\. \\::", + "/// @\\ @@ @& @$ @# @< @> @% @\" @. @::" + }; const char *Text[] = { " ", "\\", " ", "@", " ", "&", " ", "$", " ", "#", " ", @@ -310,16 +312,18 @@ TEST_F(CommentLexerTest, DoxygenCommand4) { "::", "" }; - std::vector<Token> Toks; + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + std::vector<Token> Toks; - lexString(Source, Toks); + lexString(Sources[i], Toks); - ASSERT_EQ(array_lengthof(Text), Toks.size()); + ASSERT_EQ(array_lengthof(Text), Toks.size()); - for (size_t i = 0, e = Toks.size(); i != e; i++) { - if(Toks[i].is(tok::text)) - ASSERT_EQ(StringRef(Text[i]), Toks[i].getText()) - << "index " << i; + for (size_t j = 0, e = Toks.size(); j != e; j++) { + if(Toks[j].is(tok::text)) + ASSERT_EQ(StringRef(Text[j]), Toks[j].getText()) + << "index " << i; + } } } @@ -362,7 +366,7 @@ TEST_F(CommentLexerTest, DoxygenCommand6) { ASSERT_EQ(tok::text, Toks[0].getKind()); ASSERT_EQ(StringRef(" "), Toks[0].getText()); - ASSERT_EQ(tok::command, Toks[1].getKind()); + ASSERT_EQ(tok::backslash_command, Toks[1].getKind()); ASSERT_EQ(StringRef("brief"), getCommandName(Toks[1])); ASSERT_EQ(tok::text, Toks[2].getKind()); @@ -382,28 +386,60 @@ TEST_F(CommentLexerTest, DoxygenCommand7) { ASSERT_EQ(tok::text, Toks[0].getKind()); ASSERT_EQ(StringRef(" "), Toks[0].getText()); - ASSERT_EQ(tok::command, Toks[1].getKind()); + ASSERT_EQ(tok::backslash_command, Toks[1].getKind()); ASSERT_EQ(StringRef("em"), getCommandName(Toks[1])); - ASSERT_EQ(tok::command, Toks[2].getKind()); + ASSERT_EQ(tok::backslash_command, Toks[2].getKind()); ASSERT_EQ(StringRef("em"), getCommandName(Toks[2])); ASSERT_EQ(tok::text, Toks[3].getKind()); ASSERT_EQ(StringRef(" "), Toks[3].getText()); - ASSERT_EQ(tok::command, Toks[4].getKind()); + ASSERT_EQ(tok::backslash_command, Toks[4].getKind()); ASSERT_EQ(StringRef("em"), getCommandName(Toks[4])); ASSERT_EQ(tok::text, Toks[5].getKind()); ASSERT_EQ(StringRef("\t"), Toks[5].getText()); - ASSERT_EQ(tok::command, Toks[6].getKind()); + ASSERT_EQ(tok::backslash_command, Toks[6].getKind()); ASSERT_EQ(StringRef("em"), getCommandName(Toks[6])); ASSERT_EQ(tok::newline, Toks[7].getKind()); } TEST_F(CommentLexerTest, DoxygenCommand8) { + const char *Source = "/// @em@em @em\t@em\n"; + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(8U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::at_command, Toks[1].getKind()); + ASSERT_EQ(StringRef("em"), getCommandName(Toks[1])); + + ASSERT_EQ(tok::at_command, Toks[2].getKind()); + ASSERT_EQ(StringRef("em"), getCommandName(Toks[2])); + + ASSERT_EQ(tok::text, Toks[3].getKind()); + ASSERT_EQ(StringRef(" "), Toks[3].getText()); + + ASSERT_EQ(tok::at_command, Toks[4].getKind()); + ASSERT_EQ(StringRef("em"), getCommandName(Toks[4])); + + ASSERT_EQ(tok::text, Toks[5].getKind()); + ASSERT_EQ(StringRef("\t"), Toks[5].getText()); + + ASSERT_EQ(tok::at_command, Toks[6].getKind()); + ASSERT_EQ(StringRef("em"), getCommandName(Toks[6])); + + ASSERT_EQ(tok::newline, Toks[7].getKind()); +} + +TEST_F(CommentLexerTest, DoxygenCommand9) { const char *Source = "/// \\aaa\\bbb \\ccc\t\\ddd\n"; std::vector<Token> Toks; @@ -435,7 +471,7 @@ TEST_F(CommentLexerTest, DoxygenCommand8) { ASSERT_EQ(tok::newline, Toks[7].getKind()); } -TEST_F(CommentLexerTest, DoxygenCommand9) { +TEST_F(CommentLexerTest, DoxygenCommand10) { const char *Source = "// \\c\n"; std::vector<Token> Toks; @@ -446,12 +482,95 @@ TEST_F(CommentLexerTest, DoxygenCommand9) { ASSERT_EQ(tok::text, Toks[0].getKind()); ASSERT_EQ(StringRef(" "), Toks[0].getText()); - ASSERT_EQ(tok::command, Toks[1].getKind()); + ASSERT_EQ(tok::backslash_command, Toks[1].getKind()); ASSERT_EQ(StringRef("c"), getCommandName(Toks[1])); ASSERT_EQ(tok::newline, Toks[2].getKind()); } +TEST_F(CommentLexerTest, RegisterCustomBlockCommand) { + const char *Source = + "/// \\NewBlockCommand Aaa.\n" + "/// @NewBlockCommand Aaa.\n"; + + Traits.registerBlockCommand(StringRef("NewBlockCommand")); + + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(8U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::backslash_command, Toks[1].getKind()); + ASSERT_EQ(StringRef("NewBlockCommand"), getCommandName(Toks[1])); + + ASSERT_EQ(tok::text, Toks[2].getKind()); + ASSERT_EQ(StringRef(" Aaa."), Toks[2].getText()); + + ASSERT_EQ(tok::newline, Toks[3].getKind()); + + ASSERT_EQ(tok::text, Toks[4].getKind()); + ASSERT_EQ(StringRef(" "), Toks[4].getText()); + + ASSERT_EQ(tok::at_command, Toks[5].getKind()); + ASSERT_EQ(StringRef("NewBlockCommand"), getCommandName(Toks[5])); + + ASSERT_EQ(tok::text, Toks[6].getKind()); + ASSERT_EQ(StringRef(" Aaa."), Toks[6].getText()); + + ASSERT_EQ(tok::newline, Toks[7].getKind()); +} + +TEST_F(CommentLexerTest, RegisterMultipleBlockCommands) { + const char *Source = + "/// \\Foo\n" + "/// \\Bar Baz\n" + "/// \\Blech quux=corge\n"; + + Traits.registerBlockCommand(StringRef("Foo")); + Traits.registerBlockCommand(StringRef("Bar")); + Traits.registerBlockCommand(StringRef("Blech")); + + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(11U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::backslash_command, Toks[1].getKind()); + ASSERT_EQ(StringRef("Foo"), getCommandName(Toks[1])); + + ASSERT_EQ(tok::newline, Toks[2].getKind()); + + ASSERT_EQ(tok::text, Toks[3].getKind()); + ASSERT_EQ(StringRef(" "), Toks[3].getText()); + + ASSERT_EQ(tok::backslash_command, Toks[4].getKind()); + ASSERT_EQ(StringRef("Bar"), getCommandName(Toks[4])); + + ASSERT_EQ(tok::text, Toks[5].getKind()); + ASSERT_EQ(StringRef(" Baz"), Toks[5].getText()); + + ASSERT_EQ(tok::newline, Toks[6].getKind()); + + ASSERT_EQ(tok::text, Toks[7].getKind()); + ASSERT_EQ(StringRef(" "), Toks[7].getText()); + + ASSERT_EQ(tok::backslash_command, Toks[8].getKind()); + ASSERT_EQ(StringRef("Blech"), getCommandName(Toks[8])); + + ASSERT_EQ(tok::text, Toks[9].getKind()); + ASSERT_EQ(StringRef(" quux=corge"), Toks[9].getText()); + + ASSERT_EQ(tok::newline, Toks[10].getKind()); +} + // Empty verbatim block. TEST_F(CommentLexerTest, VerbatimBlock1) { const char *Sources[] = { @@ -1662,7 +1781,8 @@ TEST_F(CommentLexerTest, HTMLCharacterReferences16) { const char *Sources[] = { "// =", "// =", - "// =" + "// =", + "// =" }; for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { diff --git a/unittests/AST/CommentParser.cpp b/unittests/AST/CommentParser.cpp index 8fde247..3dce60a 100644 --- a/unittests/AST/CommentParser.cpp +++ b/unittests/AST/CommentParser.cpp @@ -7,20 +7,20 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" +#include "clang/AST/CommentParser.h" #include "clang/AST/Comment.h" +#include "clang/AST/CommentCommandTraits.h" #include "clang/AST/CommentLexer.h" -#include "clang/AST/CommentParser.h" #include "clang/AST/CommentSema.h" -#include "clang/AST/CommentCommandTraits.h" +#include "clang/Basic/CommentOptions.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Allocator.h" -#include <vector> - #include "gtest/gtest.h" +#include <vector> using namespace llvm; using namespace clang; @@ -39,7 +39,7 @@ protected: DiagID(new DiagnosticIDs()), Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), SourceMgr(Diags, FileMgr), - Traits(Allocator) { + Traits(Allocator, CommentOptions()) { } FileSystemOptions FileMgrOpts; diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp index a2fc839..44fa742 100644 --- a/unittests/AST/DeclPrinterTest.cpp +++ b/unittests/AST/DeclPrinterTest.cpp @@ -412,8 +412,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl1) { " A();" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - "")); - // WRONG; Should be: "A();" + "A()")); } TEST(DeclPrinter, TestCXXConstructorDecl2) { @@ -422,8 +421,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl2) { " A(int a);" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - "")); - // WRONG; Should be: "A(int a);" + "A(int a)")); } TEST(DeclPrinter, TestCXXConstructorDecl3) { @@ -432,8 +430,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl3) { " A(const A &a);" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - "")); - // WRONG; Should be: "A(const A &a);" + "A(const A &a)")); } TEST(DeclPrinter, TestCXXConstructorDecl4) { @@ -442,8 +439,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl4) { " A(const A &a, int = 0);" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - "")); - // WRONG; Should be: "A(const A &a, int = 0);" + "A(const A &a, int = 0)")); } TEST(DeclPrinter, TestCXXConstructorDecl5) { @@ -452,8 +448,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl5) { " A(const A &&a);" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - "")); - // WRONG; Should be: "A(const A &&a);" + "A(const A &&a)")); } TEST(DeclPrinter, TestCXXConstructorDecl6) { @@ -462,8 +457,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl6) { " explicit A(int a);" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - "")); - // WRONG; Should be: "explicit A(int a);" + "explicit A(int a)")); } TEST(DeclPrinter, TestCXXConstructorDecl7) { @@ -472,7 +466,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl7) { " constexpr A();" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - "")); + "A()")); // WRONG; Should be: "constexpr A();" } @@ -482,8 +476,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl8) { " A() = default;" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - "")); - // WRONG; Should be: "A() = default;" + "A() = default")); } TEST(DeclPrinter, TestCXXConstructorDecl9) { @@ -492,8 +485,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl9) { " A() = delete;" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - " = delete")); - // WRONG; Should be: "A() = delete;" + "A() = delete")); } TEST(DeclPrinter, TestCXXConstructorDecl10) { @@ -503,8 +495,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl10) { " A(const A &a);" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - "")); - // WRONG; Should be: "A(const A &a);" + "A<T...>(const A<T...> &a)")); } #if !defined(_MSC_VER) @@ -1246,3 +1237,21 @@ TEST(DeclPrinter, TestObjCMethod1) { "- (int) A:(id)anObject inRange:(long)range")); } +TEST(DeclPrinter, TestObjCProtocol1) { + ASSERT_TRUE(PrintedDeclObjCMatches( + "@protocol P1, P2;", + namedDecl(hasName("P1")).bind("id"), + "@protocol P1;\n")); + ASSERT_TRUE(PrintedDeclObjCMatches( + "@protocol P1, P2;", + namedDecl(hasName("P2")).bind("id"), + "@protocol P2;\n")); +} + +TEST(DeclPrinter, TestObjCProtocol2) { + ASSERT_TRUE(PrintedDeclObjCMatches( + "@protocol P2 @end" + "@protocol P1<P2> @end", + namedDecl(hasName("P1")).bind("id"), + "@protocol P1<P2>\n@end")); +} diff --git a/unittests/AST/Makefile b/unittests/AST/Makefile index e07fc45..4fb2f5b 100644 --- a/unittests/AST/Makefile +++ b/unittests/AST/Makefile @@ -10,10 +10,10 @@ CLANG_LEVEL = ../.. TESTNAME = AST include $(CLANG_LEVEL)/../../Makefile.config -LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc +LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \ clangRewriteCore.a clangRewriteFrontend.a \ - clangParse.a clangSema.a clangAnalysis.a \ - clangAST.a clangASTMatchers.a clangLex.a clangBasic.a clangEdit.a + clangParse.a clangSema.a clangAnalysis.a \ + clangEdit.a clangAST.a clangASTMatchers.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/AST/MatchVerifier.h b/unittests/AST/MatchVerifier.h new file mode 100644 index 0000000..7aa7886 --- /dev/null +++ b/unittests/AST/MatchVerifier.h @@ -0,0 +1,196 @@ +//===- unittest/AST/MatchVerifier.h - AST unit test support ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Provides MatchVerifier, a base class to implement gtest matchers that +// verify things that can be matched on the AST. +// +// Also implements matchers based on MatchVerifier: +// LocationVerifier and RangeVerifier to verify whether a matched node has +// the expected source location or source range. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +namespace clang { +namespace ast_matchers { + +enum Language { Lang_C, Lang_C89, Lang_CXX, Lang_OpenCL }; + +/// \brief Base class for verifying some property of nodes found by a matcher. +template <typename NodeType> +class MatchVerifier : public MatchFinder::MatchCallback { +public: + template <typename MatcherType> + testing::AssertionResult match(const std::string &Code, + const MatcherType &AMatcher) { + return match(Code, AMatcher, Lang_CXX); + } + + template <typename MatcherType> + testing::AssertionResult match(const std::string &Code, + const MatcherType &AMatcher, Language L); + +protected: + virtual void run(const MatchFinder::MatchResult &Result); + virtual void verify(const MatchFinder::MatchResult &Result, + const NodeType &Node) {} + + void setFailure(const Twine &Result) { + Verified = false; + VerifyResult = Result.str(); + } + + void setSuccess() { + Verified = true; + } + +private: + bool Verified; + std::string VerifyResult; +}; + +/// \brief Runs a matcher over some code, and returns the result of the +/// verifier for the matched node. +template <typename NodeType> template <typename MatcherType> +testing::AssertionResult MatchVerifier<NodeType>::match( + const std::string &Code, const MatcherType &AMatcher, Language L) { + MatchFinder Finder; + Finder.addMatcher(AMatcher.bind(""), this); + OwningPtr<tooling::FrontendActionFactory> Factory( + tooling::newFrontendActionFactory(&Finder)); + + std::vector<std::string> Args; + StringRef FileName; + switch (L) { + case Lang_C: + Args.push_back("-std=c99"); + FileName = "input.c"; + break; + case Lang_C89: + Args.push_back("-std=c89"); + FileName = "input.c"; + break; + case Lang_CXX: + Args.push_back("-std=c++98"); + FileName = "input.cc"; + break; + case Lang_OpenCL: + FileName = "input.cl"; + } + + // Default to failure in case callback is never called + setFailure("Could not find match"); + if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName)) + return testing::AssertionFailure() << "Parsing error"; + if (!Verified) + return testing::AssertionFailure() << VerifyResult; + return testing::AssertionSuccess(); +} + +template <typename NodeType> +void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) { + const NodeType *Node = Result.Nodes.getNodeAs<NodeType>(""); + if (!Node) { + setFailure("Matched node has wrong type"); + } else { + // Callback has been called, default to success. + setSuccess(); + verify(Result, *Node); + } +} + +/// \brief Verify whether a node has the correct source location. +/// +/// By default, Node.getSourceLocation() is checked. This can be changed +/// by overriding getLocation(). +template <typename NodeType> +class LocationVerifier : public MatchVerifier<NodeType> { +public: + void expectLocation(unsigned Line, unsigned Column) { + ExpectLine = Line; + ExpectColumn = Column; + } + +protected: + void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) { + SourceLocation Loc = getLocation(Node); + unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc); + unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc); + if (Line != ExpectLine || Column != ExpectColumn) { + std::string MsgStr; + llvm::raw_string_ostream Msg(MsgStr); + Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn + << ">, found <"; + Loc.print(Msg, *Result.SourceManager); + Msg << '>'; + this->setFailure(Msg.str()); + } + } + + virtual SourceLocation getLocation(const NodeType &Node) { + return Node.getLocation(); + } + +private: + unsigned ExpectLine, ExpectColumn; +}; + +/// \brief Verify whether a node has the correct source range. +/// +/// By default, Node.getSourceRange() is checked. This can be changed +/// by overriding getRange(). +template <typename NodeType> +class RangeVerifier : public MatchVerifier<NodeType> { +public: + void expectRange(unsigned BeginLine, unsigned BeginColumn, + unsigned EndLine, unsigned EndColumn) { + ExpectBeginLine = BeginLine; + ExpectBeginColumn = BeginColumn; + ExpectEndLine = EndLine; + ExpectEndColumn = EndColumn; + } + +protected: + void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) { + SourceRange R = getRange(Node); + SourceLocation Begin = R.getBegin(); + SourceLocation End = R.getEnd(); + unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin); + unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin); + unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End); + unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End); + if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn || + EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) { + std::string MsgStr; + llvm::raw_string_ostream Msg(MsgStr); + Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn + << '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <"; + Begin.print(Msg, *Result.SourceManager); + Msg << '-'; + End.print(Msg, *Result.SourceManager); + Msg << '>'; + this->setFailure(Msg.str()); + } + } + + virtual SourceRange getRange(const NodeType &Node) { + return Node.getSourceRange(); + } + +private: + unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn; +}; + +} // end namespace ast_matchers +} // end namespace clang diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp index dec833d..b8d8b02 100644 --- a/unittests/AST/SourceLocationTest.cpp +++ b/unittests/AST/SourceLocationTest.cpp @@ -17,179 +17,16 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/Tooling.h" #include "gtest/gtest.h" +#include "MatchVerifier.h" namespace clang { namespace ast_matchers { -using clang::tooling::newFrontendActionFactory; -using clang::tooling::runToolOnCodeWithArgs; -using clang::tooling::FrontendActionFactory; - -enum Language { Lang_C, Lang_C89, Lang_CXX }; - -/// \brief Base class for verifying some property of nodes found by a matcher. -/// -/// FIXME: This class should be shared with other AST tests. -template <typename NodeType> -class MatchVerifier : public MatchFinder::MatchCallback { -public: - template <typename MatcherType> - testing::AssertionResult match(const std::string &Code, - const MatcherType &AMatcher) { - return match(Code, AMatcher, Lang_CXX); - } - - template <typename MatcherType> - testing::AssertionResult match(const std::string &Code, - const MatcherType &AMatcher, Language L); - -protected: - virtual void run(const MatchFinder::MatchResult &Result); - virtual void verify(const MatchFinder::MatchResult &Result, - const NodeType &Node) = 0; - - void setFailure(const Twine &Result) { - Verified = false; - VerifyResult = Result.str(); - } - -private: - bool Verified; - std::string VerifyResult; -}; - -/// \brief Runs a matcher over some code, and returns the result of the -/// verifier for the matched node. -template <typename NodeType> template <typename MatcherType> -testing::AssertionResult MatchVerifier<NodeType>::match( - const std::string &Code, const MatcherType &AMatcher, Language L) { - MatchFinder Finder; - Finder.addMatcher(AMatcher.bind(""), this); - OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder)); - - std::vector<std::string> Args; - StringRef FileName; - switch (L) { - case Lang_C: - Args.push_back("-std=c99"); - FileName = "input.c"; - break; - case Lang_C89: - Args.push_back("-std=c89"); - FileName = "input.c"; - break; - case Lang_CXX: - Args.push_back("-std=c++98"); - FileName = "input.cc"; - break; - } - - // Default to failure in case callback is never called - setFailure("Could not find match"); - if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName)) - return testing::AssertionFailure() << "Parsing error"; - if (!Verified) - return testing::AssertionFailure() << VerifyResult; - return testing::AssertionSuccess(); -} - -template <typename NodeType> -void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) { - const NodeType *Node = Result.Nodes.getNodeAs<NodeType>(""); - if (!Node) { - setFailure("Matched node has wrong type"); - } else { - // Callback has been called, default to success - Verified = true; - verify(Result, *Node); - } -} - -/// \brief Verify whether a node has the correct source location. -/// -/// By default, Node.getSourceLocation() is checked. This can be changed -/// by overriding getLocation(). -template <typename NodeType> -class LocationVerifier : public MatchVerifier<NodeType> { -public: - void expectLocation(unsigned Line, unsigned Column) { - ExpectLine = Line; - ExpectColumn = Column; - } - -protected: - void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) { - SourceLocation Loc = getLocation(Node); - unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc); - unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc); - if (Line != ExpectLine || Column != ExpectColumn) { - std::string MsgStr; - llvm::raw_string_ostream Msg(MsgStr); - Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn - << ">, found <"; - Loc.print(Msg, *Result.SourceManager); - Msg << '>'; - this->setFailure(Msg.str()); - } - } - - virtual SourceLocation getLocation(const NodeType &Node) { - return Node.getLocation(); - } - -private: - unsigned ExpectLine, ExpectColumn; -}; - -/// \brief Verify whether a node has the correct source range. -/// -/// By default, Node.getSourceRange() is checked. This can be changed -/// by overriding getRange(). -template <typename NodeType> -class RangeVerifier : public MatchVerifier<NodeType> { -public: - void expectRange(unsigned BeginLine, unsigned BeginColumn, - unsigned EndLine, unsigned EndColumn) { - ExpectBeginLine = BeginLine; - ExpectBeginColumn = BeginColumn; - ExpectEndLine = EndLine; - ExpectEndColumn = EndColumn; - } - -protected: - void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) { - SourceRange R = getRange(Node); - SourceLocation Begin = R.getBegin(); - SourceLocation End = R.getEnd(); - unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin); - unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin); - unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End); - unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End); - if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn || - EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) { - std::string MsgStr; - llvm::raw_string_ostream Msg(MsgStr); - Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn - << '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <"; - Begin.print(Msg, *Result.SourceManager); - Msg << '-'; - End.print(Msg, *Result.SourceManager); - Msg << '>'; - this->setFailure(Msg.str()); - } - } - - virtual SourceRange getRange(const NodeType &Node) { - return Node.getSourceRange(); - } - -private: - unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn; -}; +// FIXME: Pull the *Verifier tests into their own test file. TEST(MatchVerifier, ParseError) { LocationVerifier<VarDecl> Verifier; @@ -285,5 +122,38 @@ TEST(CXXConstructorDecl, NoRetFunTypeLocRange) { EXPECT_TRUE(Verifier.match("class C { C(); };", functionDecl())); } +TEST(CompoundLiteralExpr, CompoundVectorLiteralRange) { + RangeVerifier<CompoundLiteralExpr> Verifier; + Verifier.expectRange(2, 11, 2, 22); + EXPECT_TRUE(Verifier.match( + "typedef int int2 __attribute__((ext_vector_type(2)));\n" + "int2 i2 = (int2){1, 2};", compoundLiteralExpr())); +} + +TEST(CompoundLiteralExpr, ParensCompoundVectorLiteralRange) { + RangeVerifier<CompoundLiteralExpr> Verifier; + Verifier.expectRange(2, 11, 2, 22); + EXPECT_TRUE(Verifier.match( + "typedef int int2 __attribute__((ext_vector_type(2)));\n" + "int2 i2 = (int2)(1, 2);", + compoundLiteralExpr(), Lang_OpenCL)); +} + +TEST(InitListExpr, VectorLiteralListBraceRange) { + RangeVerifier<InitListExpr> Verifier; + Verifier.expectRange(2, 17, 2, 22); + EXPECT_TRUE(Verifier.match( + "typedef int int2 __attribute__((ext_vector_type(2)));\n" + "int2 i2 = (int2){1, 2};", initListExpr())); +} + +TEST(InitListExpr, VectorLiteralInitListParens) { + RangeVerifier<InitListExpr> Verifier; + Verifier.expectRange(2, 17, 2, 22); + EXPECT_TRUE(Verifier.match( + "typedef int int2 __attribute__((ext_vector_type(2)));\n" + "int2 i2 = (int2)(1, 2);", initListExpr(), Lang_OpenCL)); +} + } // end namespace ast_matchers } // end namespace clang diff --git a/unittests/AST/StmtPrinterTest.cpp b/unittests/AST/StmtPrinterTest.cpp index 0fd1b2e..473ee13 100644 --- a/unittests/AST/StmtPrinterTest.cpp +++ b/unittests/AST/StmtPrinterTest.cpp @@ -146,20 +146,14 @@ TEST(StmtPrinter, TestMSIntegerLiteral) { " 1i8, -1i8, 1ui8, " " 1i16, -1i16, 1ui16, " " 1i32, -1i32, 1ui32, " - " 1i64, -1i64, 1ui64, " - " 1i128, -1i128, 1ui128, 1Ui128," - " 0x10000000000000000i128;" + " 1i64, -1i64, 1ui64;" "}", "A", "1 , -1 , 1U , " "1 , -1 , 1U , " "1L , -1L , 1UL , " - "1LL , -1LL , 1ULL , " - "1 , -1 , 1U , 1U , " - "18446744073709551616i128")); + "1LL , -1LL , 1ULL")); // Should be: with semicolon - // WRONG; all 128-bit literals should be printed as 128-bit. - // (This is because currently we do semantic analysis incorrectly.) } TEST(StmtPrinter, TestFloatingPointLiteral) { @@ -169,4 +163,3 @@ TEST(StmtPrinter, TestFloatingPointLiteral) { "1.F , -1.F , 1. , -1. , 1.L , -1.L")); // Should be: with semicolon } - |