PPCallbacksTest.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. //===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks tests ------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===--------------------------------------------------------------===//
  9. #include "clang/Lex/Preprocessor.h"
  10. #include "clang/AST/ASTConsumer.h"
  11. #include "clang/AST/ASTContext.h"
  12. #include "clang/Basic/Diagnostic.h"
  13. #include "clang/Basic/DiagnosticOptions.h"
  14. #include "clang/Basic/FileManager.h"
  15. #include "clang/Basic/LangOptions.h"
  16. #include "clang/Basic/MemoryBufferCache.h"
  17. #include "clang/Basic/SourceManager.h"
  18. #include "clang/Basic/TargetInfo.h"
  19. #include "clang/Basic/TargetOptions.h"
  20. #include "clang/Lex/HeaderSearch.h"
  21. #include "clang/Lex/HeaderSearchOptions.h"
  22. #include "clang/Lex/ModuleLoader.h"
  23. #include "clang/Lex/PreprocessorOptions.h"
  24. #include "clang/Parse/Parser.h"
  25. #include "clang/Sema/Sema.h"
  26. #include "llvm/ADT/SmallString.h"
  27. #include "llvm/Support/Path.h"
  28. #include "gtest/gtest.h"
  29. using namespace clang;
  30. namespace {
  31. // Stub to collect data from InclusionDirective callbacks.
  32. class InclusionDirectiveCallbacks : public PPCallbacks {
  33. public:
  34. void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
  35. StringRef FileName, bool IsAngled,
  36. CharSourceRange FilenameRange, const FileEntry *File,
  37. StringRef SearchPath, StringRef RelativePath,
  38. const Module *Imported,
  39. SrcMgr::CharacteristicKind FileType) override {
  40. this->HashLoc = HashLoc;
  41. this->IncludeTok = IncludeTok;
  42. this->FileName = FileName.str();
  43. this->IsAngled = IsAngled;
  44. this->FilenameRange = FilenameRange;
  45. this->File = File;
  46. this->SearchPath = SearchPath.str();
  47. this->RelativePath = RelativePath.str();
  48. this->Imported = Imported;
  49. this->FileType = FileType;
  50. }
  51. SourceLocation HashLoc;
  52. Token IncludeTok;
  53. SmallString<16> FileName;
  54. bool IsAngled;
  55. CharSourceRange FilenameRange;
  56. const FileEntry* File;
  57. SmallString<16> SearchPath;
  58. SmallString<16> RelativePath;
  59. const Module* Imported;
  60. SrcMgr::CharacteristicKind FileType;
  61. };
  62. // Stub to collect data from PragmaOpenCLExtension callbacks.
  63. class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
  64. public:
  65. typedef struct {
  66. SmallString<16> Name;
  67. unsigned State;
  68. } CallbackParameters;
  69. PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}
  70. void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
  71. const clang::IdentifierInfo *Name,
  72. clang::SourceLocation StateLoc,
  73. unsigned State) override {
  74. this->NameLoc = NameLoc;
  75. this->Name = Name->getName();
  76. this->StateLoc = StateLoc;
  77. this->State = State;
  78. }
  79. SourceLocation NameLoc;
  80. SmallString<16> Name;
  81. SourceLocation StateLoc;
  82. unsigned State;
  83. };
  84. // PPCallbacks test fixture.
  85. class PPCallbacksTest : public ::testing::Test {
  86. protected:
  87. PPCallbacksTest()
  88. : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
  89. FileMgr(FileSystemOptions(), InMemoryFileSystem),
  90. DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
  91. Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
  92. SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
  93. TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
  94. Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
  95. }
  96. IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
  97. FileManager FileMgr;
  98. IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
  99. IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
  100. DiagnosticsEngine Diags;
  101. SourceManager SourceMgr;
  102. LangOptions LangOpts;
  103. std::shared_ptr<TargetOptions> TargetOpts;
  104. IntrusiveRefCntPtr<TargetInfo> Target;
  105. // Register a header path as a known file and add its location
  106. // to search path.
  107. void AddFakeHeader(HeaderSearch &HeaderInfo, const char *HeaderPath,
  108. bool IsSystemHeader) {
  109. // Tell FileMgr about header.
  110. InMemoryFileSystem->addFile(HeaderPath, 0,
  111. llvm::MemoryBuffer::getMemBuffer("\n"));
  112. // Add header's parent path to search path.
  113. StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
  114. const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
  115. DirectoryLookup DL(DE, SrcMgr::C_User, false);
  116. HeaderInfo.AddSearchPath(DL, IsSystemHeader);
  117. }
  118. // Get the raw source string of the range.
  119. StringRef GetSourceString(CharSourceRange Range) {
  120. const char* B = SourceMgr.getCharacterData(Range.getBegin());
  121. const char* E = SourceMgr.getCharacterData(Range.getEnd());
  122. return StringRef(B, E - B);
  123. }
  124. // Run lexer over SourceText and collect FilenameRange from
  125. // the InclusionDirective callback.
  126. CharSourceRange InclusionDirectiveFilenameRange(const char *SourceText,
  127. const char *HeaderPath,
  128. bool SystemHeader) {
  129. std::unique_ptr<llvm::MemoryBuffer> Buf =
  130. llvm::MemoryBuffer::getMemBuffer(SourceText);
  131. SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
  132. TrivialModuleLoader ModLoader;
  133. MemoryBufferCache PCMCache;
  134. HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
  135. Diags, LangOpts, Target.get());
  136. AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
  137. Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
  138. SourceMgr, PCMCache, HeaderInfo, ModLoader,
  139. /*IILookup =*/nullptr,
  140. /*OwnsHeaderSearch =*/false);
  141. return InclusionDirectiveCallback(PP)->FilenameRange;
  142. }
  143. SrcMgr::CharacteristicKind InclusionDirectiveCharacteristicKind(
  144. const char *SourceText, const char *HeaderPath, bool SystemHeader) {
  145. std::unique_ptr<llvm::MemoryBuffer> Buf =
  146. llvm::MemoryBuffer::getMemBuffer(SourceText);
  147. SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
  148. TrivialModuleLoader ModLoader;
  149. MemoryBufferCache PCMCache;
  150. HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
  151. Diags, LangOpts, Target.get());
  152. AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
  153. Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
  154. SourceMgr, PCMCache, HeaderInfo, ModLoader,
  155. /*IILookup =*/nullptr,
  156. /*OwnsHeaderSearch =*/false);
  157. return InclusionDirectiveCallback(PP)->FileType;
  158. }
  159. InclusionDirectiveCallbacks *InclusionDirectiveCallback(Preprocessor &PP) {
  160. PP.Initialize(*Target);
  161. InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
  162. PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
  163. // Lex source text.
  164. PP.EnterMainSourceFile();
  165. while (true) {
  166. Token Tok;
  167. PP.Lex(Tok);
  168. if (Tok.is(tok::eof))
  169. break;
  170. }
  171. // Callbacks have been executed at this point -- return filename range.
  172. return Callbacks;
  173. }
  174. PragmaOpenCLExtensionCallbacks::CallbackParameters
  175. PragmaOpenCLExtensionCall(const char *SourceText) {
  176. LangOptions OpenCLLangOpts;
  177. OpenCLLangOpts.OpenCL = 1;
  178. std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
  179. llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
  180. SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
  181. TrivialModuleLoader ModLoader;
  182. MemoryBufferCache PCMCache;
  183. HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
  184. Diags, OpenCLLangOpts, Target.get());
  185. Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags,
  186. OpenCLLangOpts, SourceMgr, PCMCache, HeaderInfo, ModLoader,
  187. /*IILookup =*/nullptr,
  188. /*OwnsHeaderSearch =*/false);
  189. PP.Initialize(*Target);
  190. // parser actually sets correct pragma handlers for preprocessor
  191. // according to LangOptions, so we init Parser to register opencl
  192. // pragma handlers
  193. ASTContext Context(OpenCLLangOpts, SourceMgr, PP.getIdentifierTable(),
  194. PP.getSelectorTable(), PP.getBuiltinInfo());
  195. Context.InitBuiltinTypes(*Target);
  196. ASTConsumer Consumer;
  197. Sema S(PP, Context, Consumer);
  198. Parser P(PP, S, false);
  199. PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
  200. PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
  201. // Lex source text.
  202. PP.EnterMainSourceFile();
  203. while (true) {
  204. Token Tok;
  205. PP.Lex(Tok);
  206. if (Tok.is(tok::eof))
  207. break;
  208. }
  209. PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
  210. Callbacks->Name,
  211. Callbacks->State
  212. };
  213. return RetVal;
  214. }
  215. };
  216. TEST_F(PPCallbacksTest, UserFileCharacteristics) {
  217. const char *Source = "#include \"quoted.h\"\n";
  218. SrcMgr::CharacteristicKind Kind =
  219. InclusionDirectiveCharacteristicKind(Source, "/quoted.h", false);
  220. ASSERT_EQ(SrcMgr::CharacteristicKind::C_User, Kind);
  221. }
  222. TEST_F(PPCallbacksTest, QuotedFilename) {
  223. const char* Source =
  224. "#include \"quoted.h\"\n";
  225. CharSourceRange Range =
  226. InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
  227. ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
  228. }
  229. TEST_F(PPCallbacksTest, AngledFilename) {
  230. const char* Source =
  231. "#include <angled.h>\n";
  232. CharSourceRange Range =
  233. InclusionDirectiveFilenameRange(Source, "/angled.h", true);
  234. ASSERT_EQ("<angled.h>", GetSourceString(Range));
  235. }
  236. TEST_F(PPCallbacksTest, QuotedInMacro) {
  237. const char* Source =
  238. "#define MACRO_QUOTED \"quoted.h\"\n"
  239. "#include MACRO_QUOTED\n";
  240. CharSourceRange Range =
  241. InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
  242. ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
  243. }
  244. TEST_F(PPCallbacksTest, AngledInMacro) {
  245. const char* Source =
  246. "#define MACRO_ANGLED <angled.h>\n"
  247. "#include MACRO_ANGLED\n";
  248. CharSourceRange Range =
  249. InclusionDirectiveFilenameRange(Source, "/angled.h", true);
  250. ASSERT_EQ("<angled.h>", GetSourceString(Range));
  251. }
  252. TEST_F(PPCallbacksTest, StringizedMacroArgument) {
  253. const char* Source =
  254. "#define MACRO_STRINGIZED(x) #x\n"
  255. "#include MACRO_STRINGIZED(quoted.h)\n";
  256. CharSourceRange Range =
  257. InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
  258. ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
  259. }
  260. TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
  261. const char* Source =
  262. "#define MACRO_ANGLED <angled.h>\n"
  263. "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
  264. "#include MACRO_CONCAT(MACRO, ANGLED)\n";
  265. CharSourceRange Range =
  266. InclusionDirectiveFilenameRange(Source, "/angled.h", false);
  267. ASSERT_EQ("<angled.h>", GetSourceString(Range));
  268. }
  269. TEST_F(PPCallbacksTest, TrigraphFilename) {
  270. const char* Source =
  271. "#include \"tri\?\?-graph.h\"\n";
  272. CharSourceRange Range =
  273. InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
  274. ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
  275. }
  276. TEST_F(PPCallbacksTest, TrigraphInMacro) {
  277. const char* Source =
  278. "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
  279. "#include MACRO_TRIGRAPH\n";
  280. CharSourceRange Range =
  281. InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
  282. ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
  283. }
  284. TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
  285. const char* Source =
  286. "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
  287. PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
  288. PragmaOpenCLExtensionCall(Source);
  289. ASSERT_EQ("cl_khr_fp64", Parameters.Name);
  290. unsigned ExpectedState = 1;
  291. ASSERT_EQ(ExpectedState, Parameters.State);
  292. }
  293. TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
  294. const char* Source =
  295. "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
  296. PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
  297. PragmaOpenCLExtensionCall(Source);
  298. ASSERT_EQ("cl_khr_fp16", Parameters.Name);
  299. unsigned ExpectedState = 0;
  300. ASSERT_EQ(ExpectedState, Parameters.State);
  301. }
  302. } // anonoymous namespace