diff options
Diffstat (limited to 'unittests')
-rw-r--r-- | unittests/AST/APValueTest.cpp | 83 | ||||
-rw-r--r-- | unittests/Basic/Makefile | 2 | ||||
-rw-r--r-- | unittests/Basic/SourceManagerTest.cpp | 296 | ||||
-rw-r--r-- | unittests/CMakeLists.txt | 19 | ||||
-rw-r--r-- | unittests/Frontend/FrontendActionTest.cpp | 4 | ||||
-rw-r--r-- | unittests/Frontend/Makefile | 2 | ||||
-rw-r--r-- | unittests/Lex/LexerTest.cpp | 177 | ||||
-rw-r--r-- | unittests/Lex/Makefile (renamed from unittests/AST/Makefile) | 6 | ||||
-rw-r--r-- | unittests/Lex/PreprocessingRecordTest.cpp | 139 | ||||
-rw-r--r-- | unittests/Makefile | 2 | ||||
-rw-r--r-- | unittests/Tooling/CompilationDatabaseTest.cpp | 223 | ||||
-rw-r--r-- | unittests/Tooling/Makefile | 17 | ||||
-rw-r--r-- | unittests/Tooling/ToolingTest.cpp | 113 |
13 files changed, 986 insertions, 97 deletions
diff --git a/unittests/AST/APValueTest.cpp b/unittests/AST/APValueTest.cpp deleted file mode 100644 index 5ac454de5f13f..0000000000000 --- a/unittests/AST/APValueTest.cpp +++ /dev/null @@ -1,83 +0,0 @@ -//===- unittests/AST/APValueTest.cpp - APValue tests ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/APValue.h" - -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" - -#include "gtest/gtest.h" - -using namespace llvm; -using namespace clang; - -namespace { - -class DiagnosticOutputGetter { - class LastDiagnosticString : public DiagnosticConsumer { - SmallString<64> LastDiagnostic; - public: - virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, - const Diagnostic &Info) { - LastDiagnostic.clear(); - Info.FormatDiagnostic(LastDiagnostic); - } - - StringRef get() const { return LastDiagnostic; } - - virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - return new LastDiagnosticString(); - } - }; - - const IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs; - const unsigned diag_just_format; - LastDiagnosticString LastDiagnostic; - DiagnosticsEngine Diag; - -public: - DiagnosticOutputGetter() - : DiagIDs(new DiagnosticIDs), - diag_just_format(DiagIDs->getCustomDiagID(DiagnosticIDs::Error, "%0")), - Diag(DiagIDs, &LastDiagnostic, false) { - } - - template<typename T> - std::string operator()(const T& value) { - Diag.Report(diag_just_format) << value; - return LastDiagnostic.get().str(); - } -}; - -TEST(APValue, Diagnostics) { - DiagnosticOutputGetter GetDiagnosticOutput; - - EXPECT_EQ("Uninitialized", GetDiagnosticOutput(APValue())); - EXPECT_EQ("5", GetDiagnosticOutput(APValue(APSInt(APInt(16, 5))))); - EXPECT_EQ("3.141590e+00", - GetDiagnosticOutput(APValue(APFloat(APFloat::IEEEdouble, - "3.14159")))); - EXPECT_EQ("3+4i", - GetDiagnosticOutput(APValue(APSInt(APInt(16, 3)), - APSInt(APInt(16, 4))))); - EXPECT_EQ("3.200000e+00+5.700000e+00i", - GetDiagnosticOutput(APValue( - APFloat(APFloat::IEEEdouble, "3.2"), - APFloat(APFloat::IEEEdouble, "5.7")))); - APValue V[] = { - APValue(APSInt(APInt(16, 3))), - APValue(APSInt(APInt(16, 4))), - APValue(APSInt(APInt(16, 5))) - }; - EXPECT_EQ("[3, 4, 5]", - GetDiagnosticOutput(APValue(V, array_lengthof(V)))); -} - -} // anonymous namespace diff --git a/unittests/Basic/Makefile b/unittests/Basic/Makefile index 4bac50c12ab30..82de790598f69 100644 --- a/unittests/Basic/Makefile +++ b/unittests/Basic/Makefile @@ -10,6 +10,6 @@ CLANG_LEVEL = ../.. TESTNAME = Basic LINK_COMPONENTS := support mc -USEDLIBS = clangBasic.a +USEDLIBS = clangLex.a clangBasic.a include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp new file mode 100644 index 0000000000000..429b58d7ea452 --- /dev/null +++ b/unittests/Basic/SourceManagerTest.cpp @@ -0,0 +1,296 @@ +//===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager tests ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Config/config.h" + +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +// The test fixture. +class SourceManagerTest : public ::testing::Test { +protected: + SourceManagerTest() + : FileMgr(FileMgrOpts), + DiagID(new DiagnosticIDs()), + Diags(DiagID, new IgnoringDiagConsumer()), + SourceMgr(Diags, FileMgr) { + TargetOpts.Triple = "x86_64-apple-darwin11.1.0"; + Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); + } + + FileSystemOptions FileMgrOpts; + FileManager FileMgr; + IntrusiveRefCntPtr<DiagnosticIDs> DiagID; + DiagnosticsEngine Diags; + SourceManager SourceMgr; + LangOptions LangOpts; + TargetOptions TargetOpts; + IntrusiveRefCntPtr<TargetInfo> Target; +}; + +class VoidModuleLoader : public ModuleLoader { + virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) { + return 0; + } +}; + +TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { + const char *source = + "#define M(x) [x]\n" + "M(foo)"; + MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source); + FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf); + + VoidModuleLoader ModLoader; + HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target); + Preprocessor PP(Diags, LangOpts, + Target.getPtr(), + SourceMgr, HeaderInfo, ModLoader, + /*IILookup =*/ 0, + /*OwnsHeaderSearch =*/false, + /*DelayInitialization =*/ false); + PP.EnterMainSourceFile(); + + std::vector<Token> toks; + while (1) { + Token tok; + PP.Lex(tok); + if (tok.is(tok::eof)) + break; + toks.push_back(tok); + } + + // Make sure we got the tokens that we expected. + ASSERT_EQ(3U, toks.size()); + ASSERT_EQ(tok::l_square, toks[0].getKind()); + ASSERT_EQ(tok::identifier, toks[1].getKind()); + ASSERT_EQ(tok::r_square, toks[2].getKind()); + + SourceLocation lsqrLoc = toks[0].getLocation(); + SourceLocation idLoc = toks[1].getLocation(); + SourceLocation rsqrLoc = toks[2].getLocation(); + + SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1); + SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6); + ASSERT_TRUE(macroExpStartLoc.isFileID()); + ASSERT_TRUE(macroExpEndLoc.isFileID()); + + SmallString<32> str; + ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str)); + ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str)); + + EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc)); + EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc)); + EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc)); + EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc)); +} + +#if defined(LLVM_ON_UNIX) + +TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { + const char *header = + "#define FM(x,y) x\n"; + + const char *main = + "#include \"/test-header.h\"\n" + "#define VAL 0\n" + "FM(VAL,0)\n" + "FM(0,VAL)\n" + "FM(FM(0,VAL),0)\n" + "#define CONCAT(X, Y) X##Y\n" + "CONCAT(1,1)\n"; + + MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header); + MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main); + FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(mainBuf); + + const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", + headerBuf->getBufferSize(), 0); + SourceMgr.overrideFileContents(headerFile, headerBuf); + + VoidModuleLoader ModLoader; + HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target); + Preprocessor PP(Diags, LangOpts, + Target.getPtr(), + SourceMgr, HeaderInfo, ModLoader, + /*IILookup =*/ 0, + /*OwnsHeaderSearch =*/false, + /*DelayInitialization =*/ false); + PP.EnterMainSourceFile(); + + std::vector<Token> toks; + while (1) { + Token tok; + PP.Lex(tok); + if (tok.is(tok::eof)) + break; + toks.push_back(tok); + } + + // Make sure we got the tokens that we expected. + ASSERT_EQ(4U, toks.size()); + ASSERT_EQ(tok::numeric_constant, toks[0].getKind()); + ASSERT_EQ(tok::numeric_constant, toks[1].getKind()); + ASSERT_EQ(tok::numeric_constant, toks[2].getKind()); + ASSERT_EQ(tok::numeric_constant, toks[3].getKind()); + + SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13); + SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8); + SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4); + SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7); + SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22); + defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc); + loc1 = SourceMgr.getMacroArgExpandedLocation(loc1); + loc2 = SourceMgr.getMacroArgExpandedLocation(loc2); + loc3 = SourceMgr.getMacroArgExpandedLocation(loc3); + defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2); + + EXPECT_TRUE(defLoc.isFileID()); + EXPECT_TRUE(loc1.isFileID()); + EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2)); + EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3)); + EXPECT_EQ(loc2, toks[1].getLocation()); + EXPECT_EQ(loc3, toks[2].getLocation()); + EXPECT_TRUE(defLoc2.isFileID()); +} + +namespace { + +struct MacroAction { + SourceLocation Loc; + std::string Name; + bool isDefinition; // if false, it is expansion. + + MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition) + : Loc(Loc), Name(Name), isDefinition(isDefinition) { } +}; + +class MacroTracker : public PPCallbacks { + std::vector<MacroAction> &Macros; + +public: + explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { } + + virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { + Macros.push_back(MacroAction(MI->getDefinitionLoc(), + MacroNameTok.getIdentifierInfo()->getName(), + true)); + } + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI, + SourceRange Range) { + Macros.push_back(MacroAction(MacroNameTok.getLocation(), + MacroNameTok.getIdentifierInfo()->getName(), + false)); + } +}; + +} + +TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { + const char *header = + "#define MACRO_IN_INCLUDE 0\n"; + + const char *main = + "#define M(x) x\n" + "#define INC \"/test-header.h\"\n" + "#include M(INC)\n" + "#define INC2 </test-header.h>\n" + "#include M(INC2)\n"; + + MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header); + MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main); + SourceMgr.createMainFileIDForMemBuffer(mainBuf); + + const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", + headerBuf->getBufferSize(), 0); + SourceMgr.overrideFileContents(headerFile, headerBuf); + + VoidModuleLoader ModLoader; + HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target); + Preprocessor PP(Diags, LangOpts, + Target.getPtr(), + SourceMgr, HeaderInfo, ModLoader, + /*IILookup =*/ 0, + /*OwnsHeaderSearch =*/false, + /*DelayInitialization =*/ false); + + std::vector<MacroAction> Macros; + PP.addPPCallbacks(new MacroTracker(Macros)); + + PP.EnterMainSourceFile(); + + std::vector<Token> toks; + while (1) { + Token tok; + PP.Lex(tok); + if (tok.is(tok::eof)) + break; + toks.push_back(tok); + } + + // Make sure we got the tokens that we expected. + ASSERT_EQ(0U, toks.size()); + + ASSERT_EQ(9U, Macros.size()); + // #define M(x) x + ASSERT_TRUE(Macros[0].isDefinition); + ASSERT_EQ("M", Macros[0].Name); + // #define INC "/test-header.h" + ASSERT_TRUE(Macros[1].isDefinition); + ASSERT_EQ("INC", Macros[1].Name); + // M expansion in #include M(INC) + ASSERT_FALSE(Macros[2].isDefinition); + ASSERT_EQ("M", Macros[2].Name); + // INC expansion in #include M(INC) + ASSERT_FALSE(Macros[3].isDefinition); + ASSERT_EQ("INC", Macros[3].Name); + // #define MACRO_IN_INCLUDE 0 + ASSERT_TRUE(Macros[4].isDefinition); + ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name); + // #define INC2 </test-header.h> + ASSERT_TRUE(Macros[5].isDefinition); + ASSERT_EQ("INC2", Macros[5].Name); + // M expansion in #include M(INC2) + ASSERT_FALSE(Macros[6].isDefinition); + ASSERT_EQ("M", Macros[6].Name); + // INC2 expansion in #include M(INC2) + ASSERT_FALSE(Macros[7].isDefinition); + ASSERT_EQ("INC2", Macros[7].Name); + // #define MACRO_IN_INCLUDE 0 + ASSERT_TRUE(Macros[8].isDefinition); + ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name); + + // The INC expansion in #include M(INC) comes before the first + // MACRO_IN_INCLUDE definition of the included file. + EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc)); + + // The INC2 expansion in #include M(INC2) comes before the second + // MACRO_IN_INCLUDE definition of the included file. + EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc)); +} + +#endif + +} // anonymous namespace diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 901f167f35636..0b3eac95d4ee5 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -50,17 +50,24 @@ if(SUPPORTS_NO_VARIADIC_MACROS_FLAG) add_definitions("-Wno-variadic-macros") endif() -add_clang_unittest(AST - AST/APValueTest.cpp - USED_LIBS gtest gtest_main clangAST - ) - add_clang_unittest(Basic Basic/FileManagerTest.cpp - USED_LIBS gtest gtest_main clangBasic + Basic/SourceManagerTest.cpp + USED_LIBS gtest gtest_main clangLex + ) + +add_clang_unittest(Lex + Lex/LexerTest.cpp + USED_LIBS gtest gtest_main clangLex ) add_clang_unittest(Frontend Frontend/FrontendActionTest.cpp USED_LIBS gtest gtest_main clangFrontend ) + +add_clang_unittest(Tooling + Tooling/CompilationDatabaseTest.cpp + Tooling/ToolingTest.cpp + USED_LIBS gtest gtest_main clangTooling + ) diff --git a/unittests/Frontend/FrontendActionTest.cpp b/unittests/Frontend/FrontendActionTest.cpp index a32388a062e96..2d4befc1f4d38 100644 --- a/unittests/Frontend/FrontendActionTest.cpp +++ b/unittests/Frontend/FrontendActionTest.cpp @@ -55,8 +55,8 @@ TEST(ASTFrontendAction, Sanity) { CompilerInvocation *invocation = new CompilerInvocation; invocation->getPreprocessorOpts().addRemappedFile( "test.cc", MemoryBuffer::getMemBuffer("int main() { float x; }")); - invocation->getFrontendOpts().Inputs.push_back( - std::make_pair(IK_CXX, "test.cc")); + invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc", + IK_CXX)); invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance compiler; diff --git a/unittests/Frontend/Makefile b/unittests/Frontend/Makefile index 7ec2b894a04b8..7c282d6b47f1a 100644 --- a/unittests/Frontend/Makefile +++ b/unittests/Frontend/Makefile @@ -13,7 +13,7 @@ LINK_COMPONENTS := support mc USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \ clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \ clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \ - clangIndex.a clangARCMigrate.a clangRewrite.a \ + clangIndex.a clangARCMigrate.a clangRewrite.a clangEdit.a \ clangAnalysis.a clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp new file mode 100644 index 0000000000000..e43ad86ff597d --- /dev/null +++ b/unittests/Lex/LexerTest.cpp @@ -0,0 +1,177 @@ +//===- unittests/Basic/LexerTest.cpp ------ Lexer tests -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/Config/config.h" + +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +// The test fixture. +class LexerTest : public ::testing::Test { +protected: + LexerTest() + : FileMgr(FileMgrOpts), + DiagID(new DiagnosticIDs()), + Diags(DiagID, new IgnoringDiagConsumer()), + SourceMgr(Diags, FileMgr) { + TargetOpts.Triple = "x86_64-apple-darwin11.1.0"; + Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); + } + + FileSystemOptions FileMgrOpts; + FileManager FileMgr; + IntrusiveRefCntPtr<DiagnosticIDs> DiagID; + DiagnosticsEngine Diags; + SourceManager SourceMgr; + LangOptions LangOpts; + TargetOptions TargetOpts; + IntrusiveRefCntPtr<TargetInfo> Target; +}; + +class VoidModuleLoader : public ModuleLoader { + virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) { + return 0; + } +}; + +TEST_F(LexerTest, LexAPI) { + const char *source = + "#define M(x) [x]\n" + "#define N(x) x\n" + "#define INN(x) x\n" + "#define NOF1 INN(val)\n" + "#define NOF2 val\n" + "M(foo) N([bar])\n" + "N(INN(val)) N(NOF1) N(NOF2) N(val)"; + + MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source); + (void)SourceMgr.createMainFileIDForMemBuffer(buf); + + VoidModuleLoader ModLoader; + HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr()); + Preprocessor PP(Diags, LangOpts, + Target.getPtr(), + SourceMgr, HeaderInfo, ModLoader, + /*IILookup =*/ 0, + /*OwnsHeaderSearch =*/false, + /*DelayInitialization =*/ false); + PP.EnterMainSourceFile(); + + std::vector<Token> toks; + while (1) { + Token tok; + PP.Lex(tok); + if (tok.is(tok::eof)) + break; + toks.push_back(tok); + } + + // Make sure we got the tokens that we expected. + ASSERT_EQ(10U, toks.size()); + ASSERT_EQ(tok::l_square, toks[0].getKind()); + ASSERT_EQ(tok::identifier, toks[1].getKind()); + ASSERT_EQ(tok::r_square, toks[2].getKind()); + ASSERT_EQ(tok::l_square, toks[3].getKind()); + ASSERT_EQ(tok::identifier, toks[4].getKind()); + ASSERT_EQ(tok::r_square, toks[5].getKind()); + ASSERT_EQ(tok::identifier, toks[6].getKind()); + ASSERT_EQ(tok::identifier, toks[7].getKind()); + ASSERT_EQ(tok::identifier, toks[8].getKind()); + ASSERT_EQ(tok::identifier, toks[9].getKind()); + + SourceLocation lsqrLoc = toks[0].getLocation(); + SourceLocation idLoc = toks[1].getLocation(); + SourceLocation rsqrLoc = toks[2].getLocation(); + std::pair<SourceLocation,SourceLocation> + macroPair = SourceMgr.getExpansionRange(lsqrLoc); + SourceRange macroRange = SourceRange(macroPair.first, macroPair.second); + + SourceLocation Loc; + EXPECT_TRUE(Lexer::isAtStartOfMacroExpansion(lsqrLoc, SourceMgr, LangOpts, &Loc)); + EXPECT_EQ(Loc, macroRange.getBegin()); + EXPECT_FALSE(Lexer::isAtStartOfMacroExpansion(idLoc, SourceMgr, LangOpts)); + EXPECT_FALSE(Lexer::isAtEndOfMacroExpansion(idLoc, SourceMgr, LangOpts)); + EXPECT_TRUE(Lexer::isAtEndOfMacroExpansion(rsqrLoc, SourceMgr, LangOpts, &Loc)); + EXPECT_EQ(Loc, macroRange.getEnd()); + + CharSourceRange range = Lexer::makeFileCharRange( + CharSourceRange::getTokenRange(lsqrLoc, idLoc), SourceMgr, LangOpts); + EXPECT_TRUE(range.isInvalid()); + range = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(idLoc, rsqrLoc), + SourceMgr, LangOpts); + EXPECT_TRUE(range.isInvalid()); + range = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(lsqrLoc, rsqrLoc), + SourceMgr, LangOpts); + EXPECT_TRUE(!range.isTokenRange()); + EXPECT_EQ(range.getAsRange(), + SourceRange(macroRange.getBegin(), + macroRange.getEnd().getLocWithOffset(1))); + + StringRef text = Lexer::getSourceText( + CharSourceRange::getTokenRange(lsqrLoc, rsqrLoc), + SourceMgr, LangOpts); + EXPECT_EQ(text, "M(foo)"); + + SourceLocation macroLsqrLoc = toks[3].getLocation(); + SourceLocation macroIdLoc = toks[4].getLocation(); + SourceLocation macroRsqrLoc = toks[5].getLocation(); + SourceLocation fileLsqrLoc = SourceMgr.getSpellingLoc(macroLsqrLoc); + SourceLocation fileIdLoc = SourceMgr.getSpellingLoc(macroIdLoc); + SourceLocation fileRsqrLoc = SourceMgr.getSpellingLoc(macroRsqrLoc); + + range = Lexer::makeFileCharRange( + CharSourceRange::getTokenRange(macroLsqrLoc, macroIdLoc), + SourceMgr, LangOpts); + EXPECT_EQ(SourceRange(fileLsqrLoc, fileIdLoc.getLocWithOffset(3)), + range.getAsRange()); + + range = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(macroIdLoc, macroRsqrLoc), + SourceMgr, LangOpts); + EXPECT_EQ(SourceRange(fileIdLoc, fileRsqrLoc.getLocWithOffset(1)), + range.getAsRange()); + + macroPair = SourceMgr.getExpansionRange(macroLsqrLoc); + range = Lexer::makeFileCharRange( + CharSourceRange::getTokenRange(macroLsqrLoc, macroRsqrLoc), + SourceMgr, LangOpts); + EXPECT_EQ(SourceRange(macroPair.first, macroPair.second.getLocWithOffset(1)), + range.getAsRange()); + + text = Lexer::getSourceText( + CharSourceRange::getTokenRange(SourceRange(macroLsqrLoc, macroIdLoc)), + SourceMgr, LangOpts); + EXPECT_EQ(text, "[bar"); + + + SourceLocation idLoc1 = toks[6].getLocation(); + SourceLocation idLoc2 = toks[7].getLocation(); + SourceLocation idLoc3 = toks[8].getLocation(); + SourceLocation idLoc4 = toks[9].getLocation(); + EXPECT_EQ("INN", Lexer::getImmediateMacroName(idLoc1, SourceMgr, LangOpts)); + EXPECT_EQ("INN", Lexer::getImmediateMacroName(idLoc2, SourceMgr, LangOpts)); + EXPECT_EQ("NOF2", Lexer::getImmediateMacroName(idLoc3, SourceMgr, LangOpts)); + EXPECT_EQ("N", Lexer::getImmediateMacroName(idLoc4, SourceMgr, LangOpts)); +} + +} // anonymous namespace diff --git a/unittests/AST/Makefile b/unittests/Lex/Makefile index 74191d037f51f..bb9c6bc3901db 100644 --- a/unittests/AST/Makefile +++ b/unittests/Lex/Makefile @@ -1,4 +1,4 @@ -##===- unittests/Frontend/Makefile -------------------------*- Makefile -*-===## +##===- unittests/Lex/Makefile ------------------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -8,8 +8,8 @@ ##===----------------------------------------------------------------------===## CLANG_LEVEL = ../.. -TESTNAME = AST +TESTNAME = Lex LINK_COMPONENTS := support mc -USEDLIBS = clangAST.a clangBasic.a +USEDLIBS = clangLex.a clangBasic.a include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/Lex/PreprocessingRecordTest.cpp b/unittests/Lex/PreprocessingRecordTest.cpp new file mode 100644 index 0000000000000..5b5d933d1b1da --- /dev/null +++ b/unittests/Lex/PreprocessingRecordTest.cpp @@ -0,0 +1,139 @@ +//===- unittests/Lex/PreprocessingRecordTest.cpp - PreprocessingRecord tests =// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "llvm/Config/config.h" + +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +// The test fixture. +class PreprocessingRecordTest : public ::testing::Test { +protected: + PreprocessingRecordTest() + : FileMgr(FileMgrOpts), + DiagID(new DiagnosticIDs()), + Diags(DiagID, new IgnoringDiagConsumer()), + SourceMgr(Diags, FileMgr) { + TargetOpts.Triple = "x86_64-apple-darwin11.1.0"; + Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); + } + + FileSystemOptions FileMgrOpts; + FileManager FileMgr; + IntrusiveRefCntPtr<DiagnosticIDs> DiagID; + DiagnosticsEngine Diags; + SourceManager SourceMgr; + LangOptions LangOpts; + TargetOptions TargetOpts; + IntrusiveRefCntPtr<TargetInfo> Target; +}; + +class VoidModuleLoader : public ModuleLoader { + virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) { + return 0; + } +}; + +TEST_F(PreprocessingRecordTest, PPRecAPI) { + const char *source = + "0 1\n" + "#if 1\n" + "2\n" + "#ifndef BB\n" + "3 4\n" + "#else\n" + "#endif\n" + "5\n" + "#endif\n" + "6\n" + "#if 1\n" + "7\n" + "#if 1\n" + "#endif\n" + "8\n" + "#endif\n" + "9\n"; + + MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source); + SourceMgr.createMainFileIDForMemBuffer(buf); + + VoidModuleLoader ModLoader; + HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr()); + Preprocessor PP(Diags, LangOpts, + Target.getPtr(), + SourceMgr, HeaderInfo, ModLoader, + /*IILookup =*/ 0, + /*OwnsHeaderSearch =*/false, + /*DelayInitialization =*/ false); + PP.createPreprocessingRecord(true); + PP.EnterMainSourceFile(); + + std::vector<Token> toks; + while (1) { + Token tok; + PP.Lex(tok); + if (tok.is(tok::eof)) + break; + toks.push_back(tok); + } + + // Make sure we got the tokens that we expected. + ASSERT_EQ(10U, toks.size()); + + PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); + EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective( + SourceRange(toks[0].getLocation(), toks[1].getLocation()))); + EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective( + SourceRange(toks[0].getLocation(), toks[2].getLocation()))); + EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective( + SourceRange(toks[3].getLocation(), toks[4].getLocation()))); + EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective( + SourceRange(toks[1].getLocation(), toks[5].getLocation()))); + EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective( + SourceRange(toks[2].getLocation(), toks[6].getLocation()))); + EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective( + SourceRange(toks[2].getLocation(), toks[5].getLocation()))); + EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective( + SourceRange(toks[0].getLocation(), toks[6].getLocation()))); + EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective( + SourceRange(toks[2].getLocation(), toks[8].getLocation()))); + EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective( + SourceRange(toks[0].getLocation(), toks[9].getLocation()))); + + EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion( + toks[0].getLocation(), toks[2].getLocation())); + EXPECT_FALSE(PPRec.areInDifferentConditionalDirectiveRegion( + toks[3].getLocation(), toks[4].getLocation())); + EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion( + toks[1].getLocation(), toks[5].getLocation())); + EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion( + toks[2].getLocation(), toks[0].getLocation())); + EXPECT_FALSE(PPRec.areInDifferentConditionalDirectiveRegion( + toks[4].getLocation(), toks[3].getLocation())); + EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion( + toks[5].getLocation(), toks[1].getLocation())); +} + +} // anonymous namespace diff --git a/unittests/Makefile b/unittests/Makefile index f4ce6adaa7251..05449d8ccf157 100644 --- a/unittests/Makefile +++ b/unittests/Makefile @@ -14,7 +14,7 @@ ifndef CLANG_LEVEL IS_UNITTEST_LEVEL := 1 CLANG_LEVEL := .. -PARALLEL_DIRS = AST Basic Frontend +PARALLEL_DIRS = Basic Frontend Lex Tooling endif # CLANG_LEVEL diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp new file mode 100644 index 0000000000000..9747de25548c4 --- /dev/null +++ b/unittests/Tooling/CompilationDatabaseTest.cpp @@ -0,0 +1,223 @@ +//===- unittest/Tooling/CompilationDatabaseTest.cpp -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +namespace clang { +namespace tooling { + +static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName, + StringRef JSONDatabase, + std::string &ErrorMessage) { + llvm::OwningPtr<CompilationDatabase> Database( + JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage)); + if (!Database) + return CompileCommand(); + std::vector<CompileCommand> Commands = Database->getCompileCommands(FileName); + EXPECT_LE(Commands.size(), 1u); + if (Commands.empty()) + return CompileCommand(); + return Commands[0]; +} + +TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) { + std::string ErrorMessage; + CompileCommand NotFound = findCompileArgsInJsonDatabase( + "a-file.cpp", "", ErrorMessage); + EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage; + EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage; +} + +TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) { + StringRef Directory("/some/directory"); + StringRef FileName("/path/to/a-file.cpp"); + StringRef Command("/path/to/compiler and some arguments"); + std::string ErrorMessage; + CompileCommand FoundCommand = findCompileArgsInJsonDatabase( + FileName, + ("[{\"directory\":\"" + Directory + "\"," + + "\"command\":\"" + Command + "\"," + "\"file\":\"" + FileName + "\"}]").str(), + ErrorMessage); + EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage; + ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage; + EXPECT_EQ("/path/to/compiler", FoundCommand.CommandLine[0]) << ErrorMessage; + EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage; + EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage; + EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage; + + CompileCommand NotFound = findCompileArgsInJsonDatabase( + "a-file.cpp", + ("[{\"directory\":\"" + Directory + "\"," + + "\"command\":\"" + Command + "\"," + "\"file\":\"" + FileName + "\"}]").str(), + ErrorMessage); + EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage; + EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage; +} + +TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) { + StringRef Directory("/some/directory"); + StringRef FileName("/path/to/a-file.cpp"); + StringRef Command("\\\"/path to compiler\\\" \\\"and an argument\\\""); + std::string ErrorMessage; + CompileCommand FoundCommand = findCompileArgsInJsonDatabase( + FileName, + ("[{\"directory\":\"" + Directory + "\"," + + "\"command\":\"" + Command + "\"," + "\"file\":\"" + FileName + "\"}]").str(), + ErrorMessage); + ASSERT_EQ(2u, FoundCommand.CommandLine.size()); + EXPECT_EQ("/path to compiler", FoundCommand.CommandLine[0]) << ErrorMessage; + EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage; +} + +TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) { + StringRef Directory("/some directory / with spaces"); + StringRef FileName("/path/to/a-file.cpp"); + StringRef Command("a command"); + std::string ErrorMessage; + CompileCommand FoundCommand = findCompileArgsInJsonDatabase( + FileName, + ("[{\"directory\":\"" + Directory + "\"," + + "\"command\":\"" + Command + "\"," + "\"file\":\"" + FileName + "\"}]").str(), + ErrorMessage); + EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage; +} + +TEST(findCompileArgsInJsonDatabase, FindsEntry) { + StringRef Directory("directory"); + StringRef FileName("file"); + StringRef Command("command"); + std::string JsonDatabase = "["; + for (int I = 0; I < 10; ++I) { + if (I > 0) JsonDatabase += ","; + JsonDatabase += + ("{\"directory\":\"" + Directory + Twine(I) + "\"," + + "\"command\":\"" + Command + Twine(I) + "\"," + "\"file\":\"" + FileName + Twine(I) + "\"}").str(); + } + JsonDatabase += "]"; + std::string ErrorMessage; + CompileCommand FoundCommand = findCompileArgsInJsonDatabase( + "file4", JsonDatabase, ErrorMessage); + EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage; + ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage; + EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage; +} + +static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) { + std::string JsonDatabase = + ("[{\"directory\":\"\", \"file\":\"test\", \"command\": \"" + + Command + "\"}]").str(); + std::string ErrorMessage; + CompileCommand FoundCommand = findCompileArgsInJsonDatabase( + "test", JsonDatabase, ErrorMessage); + EXPECT_TRUE(ErrorMessage.empty()) << ErrorMessage; + return FoundCommand.CommandLine; +} + +TEST(unescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) { + std::vector<std::string> Result = unescapeJsonCommandLine(""); + EXPECT_TRUE(Result.empty()); +} + +TEST(unescapeJsonCommandLine, SplitsOnSpaces) { + std::vector<std::string> Result = unescapeJsonCommandLine("a b c"); + ASSERT_EQ(3ul, Result.size()); + EXPECT_EQ("a", Result[0]); + EXPECT_EQ("b", Result[1]); + EXPECT_EQ("c", Result[2]); +} + +TEST(unescapeJsonCommandLine, MungesMultipleSpaces) { + std::vector<std::string> Result = unescapeJsonCommandLine(" a b "); + ASSERT_EQ(2ul, Result.size()); + EXPECT_EQ("a", Result[0]); + EXPECT_EQ("b", Result[1]); +} + +TEST(unescapeJsonCommandLine, UnescapesBackslashCharacters) { + std::vector<std::string> Backslash = unescapeJsonCommandLine("a\\\\\\\\"); + ASSERT_EQ(1ul, Backslash.size()); + EXPECT_EQ("a\\", Backslash[0]); + std::vector<std::string> Quote = unescapeJsonCommandLine("a\\\\\\\""); + ASSERT_EQ(1ul, Quote.size()); + EXPECT_EQ("a\"", Quote[0]); +} + +TEST(unescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) { + std::vector<std::string> Result = unescapeJsonCommandLine("\\\" a b \\\""); + ASSERT_EQ(1ul, Result.size()); + EXPECT_EQ(" a b ", Result[0]); +} + +TEST(unescapeJsonCommandLine, AllowsMultipleQuotedArguments) { + std::vector<std::string> Result = unescapeJsonCommandLine( + " \\\" a \\\" \\\" b \\\" "); + ASSERT_EQ(2ul, Result.size()); + EXPECT_EQ(" a ", Result[0]); + EXPECT_EQ(" b ", Result[1]); +} + +TEST(unescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) { + std::vector<std::string> Result = unescapeJsonCommandLine( + "\\\"\\\"\\\"\\\""); + ASSERT_EQ(1ul, Result.size()); + EXPECT_TRUE(Result[0].empty()) << Result[0]; +} + +TEST(unescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) { + std::vector<std::string> Result = unescapeJsonCommandLine( + "\\\"\\\\\\\"\\\""); + ASSERT_EQ(1ul, Result.size()); + EXPECT_EQ("\"", Result[0]); +} + +TEST(unescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) { + std::vector<std::string> Result = unescapeJsonCommandLine( + " \\\\\\\" \\\"a \\\\\\\" b \\\" \\\"and\\\\\\\\c\\\" \\\\\\\""); + ASSERT_EQ(4ul, Result.size()); + EXPECT_EQ("\"", Result[0]); + EXPECT_EQ("a \" b ", Result[1]); + EXPECT_EQ("and\\c", Result[2]); + EXPECT_EQ("\"", Result[3]); +} + +TEST(unescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) { + std::vector<std::string> QuotedNoSpaces = unescapeJsonCommandLine( + "\\\"a\\\"\\\"b\\\""); + ASSERT_EQ(1ul, QuotedNoSpaces.size()); + EXPECT_EQ("ab", QuotedNoSpaces[0]); + + std::vector<std::string> MixedNoSpaces = unescapeJsonCommandLine( + "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\""); + ASSERT_EQ(1ul, MixedNoSpaces.size()); + EXPECT_EQ("abcdefg", MixedNoSpaces[0]); +} + +TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) { + std::vector<std::string> Unclosed = unescapeJsonCommandLine("\\\"abc"); + ASSERT_EQ(1ul, Unclosed.size()); + EXPECT_EQ("abc", Unclosed[0]); + + std::vector<std::string> Empty = unescapeJsonCommandLine("\\\""); + ASSERT_EQ(1ul, Empty.size()); + EXPECT_EQ("", Empty[0]); +} + +} // end namespace tooling +} // end namespace clang diff --git a/unittests/Tooling/Makefile b/unittests/Tooling/Makefile new file mode 100644 index 0000000000000..0829da543d0b0 --- /dev/null +++ b/unittests/Tooling/Makefile @@ -0,0 +1,17 @@ +##===- unittests/Tooling/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL = ../.. +TESTNAME = Tooling +LINK_COMPONENTS := support mc +USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \ + clangParse.a clangSema.a clangAnalysis.a clangEdit.a clangAST.a \ + clangLex.a clangBasic.a + +include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp new file mode 100644 index 0000000000000..c7b2210a754ea --- /dev/null +++ b/unittests/Tooling/ToolingTest.cpp @@ -0,0 +1,113 @@ +//===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +namespace clang { +namespace tooling { + +namespace { +/// Takes an ast consumer and returns it from CreateASTConsumer. This only +/// works with single translation unit compilations. +class TestAction : public clang::ASTFrontendAction { + public: + /// Takes ownership of TestConsumer. + explicit TestAction(clang::ASTConsumer *TestConsumer) + : TestConsumer(TestConsumer) {} + + protected: + virtual clang::ASTConsumer* CreateASTConsumer( + clang::CompilerInstance& compiler, StringRef dummy) { + /// TestConsumer will be deleted by the framework calling us. + return TestConsumer; + } + + private: + clang::ASTConsumer * const TestConsumer; +}; + +class FindTopLevelDeclConsumer : public clang::ASTConsumer { + public: + explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl) + : FoundTopLevelDecl(FoundTopLevelDecl) {} + virtual bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) { + *FoundTopLevelDecl = true; + return true; + } + private: + bool * const FoundTopLevelDecl; +}; +} // end namespace + +TEST(runToolOnCode, FindsTopLevelDeclOnEmptyCode) { + bool FoundTopLevelDecl = false; + EXPECT_TRUE(runToolOnCode( + new TestAction(new FindTopLevelDeclConsumer(&FoundTopLevelDecl)), "")); + EXPECT_TRUE(FoundTopLevelDecl); +} + +namespace { +class FindClassDeclXConsumer : public clang::ASTConsumer { + public: + FindClassDeclXConsumer(bool *FoundClassDeclX) + : FoundClassDeclX(FoundClassDeclX) {} + virtual bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) { + if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>( + *GroupRef.begin())) { + if (Record->getName() == "X") { + *FoundClassDeclX = true; + } + } + return true; + } + private: + bool *FoundClassDeclX; +}; +} // end namespace + +TEST(runToolOnCode, FindsClassDecl) { + bool FoundClassDeclX = false; + EXPECT_TRUE(runToolOnCode(new TestAction( + new FindClassDeclXConsumer(&FoundClassDeclX)), "class X;")); + EXPECT_TRUE(FoundClassDeclX); + + FoundClassDeclX = false; + EXPECT_TRUE(runToolOnCode(new TestAction( + new FindClassDeclXConsumer(&FoundClassDeclX)), "class Y;")); + EXPECT_FALSE(FoundClassDeclX); +} + +TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) { + llvm::OwningPtr<FrontendActionFactory> Factory( + newFrontendActionFactory<SyntaxOnlyAction>()); + llvm::OwningPtr<FrontendAction> Action(Factory->create()); + EXPECT_TRUE(Action.get() != NULL); +} + +struct IndependentFrontendActionCreator { + FrontendAction *newFrontendAction() { return new SyntaxOnlyAction; } +}; + +TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) { + IndependentFrontendActionCreator Creator; + llvm::OwningPtr<FrontendActionFactory> Factory( + newFrontendActionFactory(&Creator)); + llvm::OwningPtr<FrontendAction> Action(Factory->create()); + EXPECT_TRUE(Action.get() != NULL); +} + +} // end namespace tooling +} // end namespace clang |