PPCallbacksTest.cpp 11 KB

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