PPCallbacksTest.cpp 11 KB

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