PPCallbacksTest.cpp 11 KB

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