summaryrefslogtreecommitdiffstats
path: root/unittests/Lex
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/Lex')
-rw-r--r--unittests/Lex/CMakeLists.txt2
-rw-r--r--unittests/Lex/LexerTest.cpp280
-rw-r--r--unittests/Lex/Makefile5
-rw-r--r--unittests/Lex/PPCallbacksTest.cpp105
-rw-r--r--unittests/Lex/PPConditionalDirectiveRecordTest.cpp2
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,
OpenPOWER on IntegriCloud