diff options
Diffstat (limited to 'unittests/Lex')
-rw-r--r-- | unittests/Lex/CMakeLists.txt | 2 | ||||
-rw-r--r-- | unittests/Lex/LexerTest.cpp | 280 | ||||
-rw-r--r-- | unittests/Lex/Makefile | 5 | ||||
-rw-r--r-- | unittests/Lex/PPCallbacksTest.cpp | 105 | ||||
-rw-r--r-- | unittests/Lex/PPConditionalDirectiveRecordTest.cpp | 2 |
5 files changed, 333 insertions, 61 deletions
diff --git a/unittests/Lex/CMakeLists.txt b/unittests/Lex/CMakeLists.txt index 78838c0..cb3b927 100644 --- a/unittests/Lex/CMakeLists.txt +++ b/unittests/Lex/CMakeLists.txt @@ -5,5 +5,5 @@ add_clang_unittest(LexTests ) target_link_libraries(LexTests - clangLex + clangLex clangParse clangSema ) diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp index c9b1840..40ce928 100644 --- a/unittests/Lex/LexerTest.cpp +++ b/unittests/Lex/LexerTest.cpp @@ -28,6 +28,20 @@ using namespace clang; namespace { +class VoidModuleLoader : public ModuleLoader { + virtual ModuleLoadResult loadModule(SourceLocation ImportLoc, + ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) { + return ModuleLoadResult(); + } + + virtual void makeModuleVisible(Module *Mod, + Module::NameVisibilityKind Visibility, + SourceLocation ImportLoc, + bool Complain) { } +}; + // The test fixture. class LexerTest : public ::testing::Test { protected: @@ -42,6 +56,48 @@ protected: Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts); } + std::vector<Token> CheckLex(StringRef Source, + ArrayRef<tok::TokenKind> ExpectedTokens) { + MemoryBuffer *buf = MemoryBuffer::getMemBuffer(Source); + (void) SourceMgr.createMainFileIDForMemBuffer(buf); + + VoidModuleLoader ModLoader; + HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, + Target.getPtr()); + Preprocessor PP(new PreprocessorOptions(), 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); + } + + EXPECT_EQ(ExpectedTokens.size(), toks.size()); + for (unsigned i = 0, e = ExpectedTokens.size(); i != e; ++i) { + EXPECT_EQ(ExpectedTokens[i], toks[i].getKind()); + } + + return toks; + } + + std::string getSourceText(Token Begin, Token End) { + bool Invalid; + StringRef Str = + Lexer::getSourceText(CharSourceRange::getTokenRange(SourceRange( + Begin.getLocation(), End.getLocation())), + SourceMgr, LangOpts, &Invalid); + if (Invalid) + return "<INVALID>"; + return Str; + } + FileSystemOptions FileMgrOpts; FileManager FileMgr; IntrusiveRefCntPtr<DiagnosticIDs> DiagID; @@ -52,65 +108,179 @@ protected: IntrusiveRefCntPtr<TargetInfo> Target; }; -class VoidModuleLoader : public ModuleLoader { - virtual ModuleLoadResult loadModule(SourceLocation ImportLoc, - ModuleIdPath Path, - Module::NameVisibilityKind Visibility, - bool IsInclusionDirective) { - return ModuleLoadResult(); - } +TEST_F(LexerTest, GetSourceTextExpandsToMaximumInMacroArgument) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::l_paren); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::r_paren); - virtual void makeModuleVisible(Module *Mod, - Module::NameVisibilityKind Visibility, - SourceLocation ImportLoc, - bool Complain) { } -}; + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "M(f(M(i)))", + ExpectedTokens); + + EXPECT_EQ("M(i)", getSourceText(toks[2], toks[2])); +} + +TEST_F(LexerTest, GetSourceTextExpandsToMaximumInMacroArgumentForEndOfMacro) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "M(M(i) c)", + ExpectedTokens); + + EXPECT_EQ("M(i)", getSourceText(toks[0], toks[0])); +} + +TEST_F(LexerTest, GetSourceTextExpandsInMacroArgumentForBeginOfMacro) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "M(c c M(i))", + ExpectedTokens); + + EXPECT_EQ("c M(i)", getSourceText(toks[1], toks[2])); +} + +TEST_F(LexerTest, GetSourceTextExpandsInMacroArgumentForEndOfMacro) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "M(M(i) c c)", + ExpectedTokens); + + EXPECT_EQ("M(i) c", getSourceText(toks[0], toks[1])); +} + +TEST_F(LexerTest, GetSourceTextInSeparateFnMacros) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "M(c M(i)) M(M(i) c)", + ExpectedTokens); + + EXPECT_EQ("<INVALID>", getSourceText(toks[1], toks[2])); +} + +TEST_F(LexerTest, GetSourceTextWorksAcrossTokenPastes) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::l_paren); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::r_paren); + + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "#define C(x) M(x##c)\n" + "M(f(C(i)))", + ExpectedTokens); + + EXPECT_EQ("C(i)", getSourceText(toks[2], toks[2])); +} + +TEST_F(LexerTest, GetSourceTextExpandsAcrossMultipleMacroCalls) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::l_paren); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::r_paren); + + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "f(M(M(i)))", + ExpectedTokens); + EXPECT_EQ("M(M(i))", getSourceText(toks[2], toks[2])); +} + +TEST_F(LexerTest, GetSourceTextInMiddleOfMacroArgument) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::l_paren); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::r_paren); + + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "M(f(i))", + ExpectedTokens); + EXPECT_EQ("i", getSourceText(toks[2], toks[2])); +} + +TEST_F(LexerTest, GetSourceTextExpandsAroundDifferentMacroCalls) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::l_paren); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::r_paren); + + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "#define C(x) x\n" + "f(C(M(i)))", + ExpectedTokens); + EXPECT_EQ("C(M(i))", getSourceText(toks[2], toks[2])); +} + +TEST_F(LexerTest, GetSourceTextOnlyExpandsIfFirstTokenInMacro) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::l_paren); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::r_paren); + + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "#define C(x) c x\n" + "f(C(M(i)))", + ExpectedTokens); + EXPECT_EQ("M(i)", getSourceText(toks[3], toks[3])); +} + +TEST_F(LexerTest, GetSourceTextExpandsRecursively) { + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::l_paren); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::r_paren); + + std::vector<Token> toks = CheckLex("#define M(x) x\n" + "#define C(x) c M(x)\n" + "C(f(M(i)))", + ExpectedTokens); + EXPECT_EQ("M(i)", getSourceText(toks[3], toks[3])); +} 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(new HeaderSearchOptions, FileMgr, Diags, LangOpts, - Target.getPtr()); - Preprocessor PP(new PreprocessorOptions(), 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); - } + std::vector<tok::TokenKind> ExpectedTokens; + ExpectedTokens.push_back(tok::l_square); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::r_square); + ExpectedTokens.push_back(tok::l_square); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::r_square); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::identifier); + + std::vector<Token> toks = CheckLex("#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)", + ExpectedTokens); - // 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(); diff --git a/unittests/Lex/Makefile b/unittests/Lex/Makefile index bb9c6bc..fa233ce 100644 --- a/unittests/Lex/Makefile +++ b/unittests/Lex/Makefile @@ -9,7 +9,8 @@ CLANG_LEVEL = ../.. TESTNAME = Lex -LINK_COMPONENTS := support mc -USEDLIBS = clangLex.a clangBasic.a +LINK_COMPONENTS := mcparser support mc +USEDLIBS = clangParse.a clangSema.a clangAnalysis.a clangEdit.a \ + clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp index 36bd5f9..9405a84 100644 --- a/unittests/Lex/PPCallbacksTest.cpp +++ b/unittests/Lex/PPCallbacksTest.cpp @@ -18,8 +18,12 @@ #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConsumer.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/PathV2.h" +#include "llvm/Support/Path.h" #include "gtest/gtest.h" using namespace llvm; @@ -77,6 +81,31 @@ public: const Module* Imported; }; +// Stub to collect data from PragmaOpenCLExtension callbacks. +class PragmaOpenCLExtensionCallbacks : public PPCallbacks { +public: + typedef struct { + SmallString<16> Name; + unsigned State; + } CallbackParameters; + + PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}; + + void PragmaOpenCLExtension( + clang::SourceLocation NameLoc, const clang::IdentifierInfo *Name, + clang::SourceLocation StateLoc, unsigned State) { + this->NameLoc = NameLoc; + this->Name = Name->getName(); + this->StateLoc = StateLoc; + this->State = State; + }; + + SourceLocation NameLoc; + SmallString<16> Name; + SourceLocation StateLoc; + unsigned State; +}; + // PPCallbacks test fixture. class PPCallbacksTest : public ::testing::Test { protected: @@ -133,7 +162,8 @@ protected: VoidModuleLoader ModLoader; IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions(); - HeaderSearch HeaderInfo(HSOpts, FileMgr, Diags, LangOpts, Target.getPtr()); + HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, + Target.getPtr()); AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader); IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions(); @@ -159,6 +189,53 @@ protected: // Callbacks have been executed at this point -- return filename range. return Callbacks->FilenameRange; } + + PragmaOpenCLExtensionCallbacks::CallbackParameters + PragmaOpenCLExtensionCall(const char* SourceText) { + LangOptions OpenCLLangOpts; + OpenCLLangOpts.OpenCL = 1; + + MemoryBuffer* sourceBuf = MemoryBuffer::getMemBuffer(SourceText, "test.cl"); + (void)SourceMgr.createMainFileIDForMemBuffer(sourceBuf); + + VoidModuleLoader ModLoader; + HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, + OpenCLLangOpts, Target.getPtr()); + + Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, + Target.getPtr(), + SourceMgr, HeaderInfo, ModLoader, + /*IILookup =*/ 0, + /*OwnsHeaderSearch =*/false, + /*DelayInitialization =*/ false); + + // parser actually sets correct pragma handlers for preprocessor + // according to LangOptions, so we init Parser to register opencl + // pragma handlers + ASTContext Context(OpenCLLangOpts, SourceMgr, Target.getPtr(), + PP.getIdentifierTable(), PP.getSelectorTable(), + PP.getBuiltinInfo(), 0); + ASTConsumer Consumer; + Sema S(PP, Context, Consumer); + Parser P(PP, S, false); + PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks; + PP.addPPCallbacks(Callbacks); // Takes ownership. + + // Lex source text. + PP.EnterMainSourceFile(); + while (true) { + Token Tok; + PP.Lex(Tok); + if (Tok.is(tok::eof)) + break; + } + + PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = { + Callbacks->Name, + Callbacks->State + }; + return RetVal; + } }; TEST_F(PPCallbacksTest, QuotedFilename) { @@ -247,4 +324,28 @@ TEST_F(PPCallbacksTest, TrigraphInMacro) { ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range)); } +TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) { + const char* Source = + "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n"; + + PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters = + PragmaOpenCLExtensionCall(Source); + + ASSERT_EQ("cl_khr_fp64", Parameters.Name); + unsigned ExpectedState = 1; + ASSERT_EQ(ExpectedState, Parameters.State); +} + +TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) { + const char* Source = + "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n"; + + PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters = + PragmaOpenCLExtensionCall(Source); + + ASSERT_EQ("cl_khr_fp16", Parameters.Name); + unsigned ExpectedState = 0; + ASSERT_EQ(ExpectedState, Parameters.State); +} + } // anonoymous namespace diff --git a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp index 082eced..58857fa 100644 --- a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp +++ b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp @@ -90,7 +90,7 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) { SourceMgr.createMainFileIDForMemBuffer(buf); VoidModuleLoader ModLoader; - HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, + HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, Target.getPtr()); Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts,Target.getPtr(), SourceMgr, HeaderInfo, ModLoader, |