[cfe-commits] r167470 - in /cfe/trunk/unittests/AST: CMakeLists.txt SourceLocationTest.cpp

Manuel Klimek klimek at google.com
Tue Nov 6 09:31:40 PST 2012


Author: klimek
Date: Tue Nov  6 11:31:40 2012
New Revision: 167470

URL: http://llvm.org/viewvc/llvm-project?rev=167470&view=rev
Log:
Add unit tests for source locations of AST nodes.

Patch by Philip Craig.

Added:
    cfe/trunk/unittests/AST/SourceLocationTest.cpp
Modified:
    cfe/trunk/unittests/AST/CMakeLists.txt

Modified: cfe/trunk/unittests/AST/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CMakeLists.txt?rev=167470&r1=167469&r2=167470&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/CMakeLists.txt (original)
+++ cfe/trunk/unittests/AST/CMakeLists.txt Tue Nov  6 11:31:40 2012
@@ -2,6 +2,7 @@
   CommentLexer.cpp
   CommentParser.cpp
   DeclPrinterTest.cpp
+  SourceLocationTest.cpp
   StmtPrinterTest.cpp
   )
 

Added: cfe/trunk/unittests/AST/SourceLocationTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/SourceLocationTest.cpp?rev=167470&view=auto
==============================================================================
--- cfe/trunk/unittests/AST/SourceLocationTest.cpp (added)
+++ cfe/trunk/unittests/AST/SourceLocationTest.cpp Tue Nov  6 11:31:40 2012
@@ -0,0 +1,252 @@
+//===- unittest/AST/SourceLocationTest.cpp - AST source loc unit tests ----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for SourceLocation and SourceRange fields
+// in AST nodes.
+//
+// FIXME: In the long-term, when we test more than source locations, we may
+// want to have a unit test file for an AST node (or group of related nodes),
+// rather than a unit test file for source locations for all AST nodes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using clang::tooling::newFrontendActionFactory;
+using clang::tooling::runToolOnCodeWithArgs;
+using clang::tooling::FrontendActionFactory;
+
+enum Language { Lang_C, 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_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;
+};
+
+TEST(MatchVerifier, ParseError) {
+  LocationVerifier<VarDecl> Verifier;
+  Verifier.expectLocation(1, 1);
+  EXPECT_FALSE(Verifier.match("int i", varDecl()));
+}
+
+TEST(MatchVerifier, NoMatch) {
+  LocationVerifier<VarDecl> Verifier;
+  Verifier.expectLocation(1, 1);
+  EXPECT_FALSE(Verifier.match("int i;", recordDecl()));
+}
+
+TEST(MatchVerifier, WrongType) {
+  LocationVerifier<RecordDecl> Verifier;
+  Verifier.expectLocation(1, 1);
+  EXPECT_FALSE(Verifier.match("int i;", varDecl()));
+}
+
+TEST(LocationVerifier, WrongLocation) {
+  LocationVerifier<VarDecl> Verifier;
+  Verifier.expectLocation(1, 1);
+  EXPECT_FALSE(Verifier.match("int i;", varDecl()));
+}
+
+TEST(RangeVerifier, WrongRange) {
+  RangeVerifier<VarDecl> Verifier;
+  Verifier.expectRange(1, 1, 1, 1);
+  EXPECT_FALSE(Verifier.match("int i;", varDecl()));
+}
+
+class LabelDeclRangeVerifier : public RangeVerifier<LabelStmt> {
+protected:
+  virtual SourceRange getRange(const LabelStmt &Node) {
+    return Node.getDecl()->getSourceRange();
+  }
+};
+
+TEST(LabelDecl, Range) {
+  LabelDeclRangeVerifier Verifier;
+  Verifier.expectRange(1, 12, 1, 12);
+  EXPECT_TRUE(Verifier.match("void f() { l: return; }", labelStmt()));
+}
+
+TEST(LabelStmt, Range) {
+  RangeVerifier<LabelStmt> Verifier;
+  Verifier.expectRange(1, 12, 1, 15);
+  EXPECT_TRUE(Verifier.match("void f() { l: return; }", labelStmt()));
+}
+
+TEST(ParmVarDecl, KNRLocation) {
+  LocationVerifier<ParmVarDecl> Verifier;
+  Verifier.expectLocation(1, 8);
+  EXPECT_TRUE(Verifier.match("void f(i) {}", varDecl(), Lang_C));
+}
+
+TEST(ParmVarDecl, KNRRange) {
+  RangeVerifier<ParmVarDecl> Verifier;
+  Verifier.expectRange(1, 8, 1, 8);
+  EXPECT_TRUE(Verifier.match("void f(i) {}", varDecl(), Lang_C));
+}
+
+} // end namespace ast_matchers
+} // end namespace clang





More information about the cfe-commits mailing list