From: Manuel Klimek Date: Thu, 31 Jan 2013 13:10:40 +0000 (+0000) Subject: Move commonly useful code for AST testing into MatchVerfier.h. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4d0e9f58076037d84a7da0b407c3de8f76a9d552;p=clang Move commonly useful code for AST testing into MatchVerfier.h. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174057 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/unittests/AST/MatchVerifier.h b/unittests/AST/MatchVerifier.h new file mode 100644 index 0000000000..470689987c --- /dev/null +++ b/unittests/AST/MatchVerifier.h @@ -0,0 +1,194 @@ +//===- 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 }; + +/// \brief Base class for verifying some property of nodes found by a matcher. +template +class MatchVerifier : public MatchFinder::MatchCallback { +public: + template + testing::AssertionResult match(const std::string &Code, + const MatcherType &AMatcher) { + return match(Code, AMatcher, Lang_CXX); + } + + template + 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(); + } + + 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 template +testing::AssertionResult MatchVerifier::match( + const std::string &Code, const MatcherType &AMatcher, Language L) { + MatchFinder Finder; + Finder.addMatcher(AMatcher.bind(""), this); + OwningPtr Factory( + tooling::newFrontendActionFactory(&Finder)); + + std::vector 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 (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName)) + return testing::AssertionFailure() << "Parsing error"; + if (!Verified) + return testing::AssertionFailure() << VerifyResult; + return testing::AssertionSuccess(); +} + +template +void MatchVerifier::run(const MatchFinder::MatchResult &Result) { + const NodeType *Node = Result.Nodes.getNodeAs(""); + 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 +class LocationVerifier : public MatchVerifier { +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 +class RangeVerifier : public MatchVerifier { +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 eaf9285cf4..486c82fcec 100644 --- a/unittests/AST/SourceLocationTest.cpp +++ b/unittests/AST/SourceLocationTest.cpp @@ -21,175 +21,12 @@ #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 -class MatchVerifier : public MatchFinder::MatchCallback { -public: - template - testing::AssertionResult match(const std::string &Code, - const MatcherType &AMatcher) { - return match(Code, AMatcher, Lang_CXX); - } - - template - 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 template -testing::AssertionResult MatchVerifier::match( - const std::string &Code, const MatcherType &AMatcher, Language L) { - MatchFinder Finder; - Finder.addMatcher(AMatcher.bind(""), this); - OwningPtr Factory(newFrontendActionFactory(&Finder)); - - std::vector 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 -void MatchVerifier::run(const MatchFinder::MatchResult &Result) { - const NodeType *Node = Result.Nodes.getNodeAs(""); - 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 -class LocationVerifier : public MatchVerifier { -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 -class RangeVerifier : public MatchVerifier { -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 Verifier;