PPCallbacksTest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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. : InMemoryFileSystem(new vfs::InMemoryFileSystem),
  101. FileMgr(FileSystemOptions(), InMemoryFileSystem),
  102. DiagID(new DiagnosticIDs()), 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. IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem;
  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. InMemoryFileSystem->addFile(HeaderPath, 0,
  123. llvm::MemoryBuffer::getMemBuffer("\n"));
  124. // Add header's parent path to search path.
  125. StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
  126. const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
  127. DirectoryLookup DL(DE, SrcMgr::C_User, false);
  128. HeaderInfo.AddSearchPath(DL, IsSystemHeader);
  129. }
  130. // Get the raw source string of the range.
  131. StringRef GetSourceString(CharSourceRange Range) {
  132. const char* B = SourceMgr.getCharacterData(Range.getBegin());
  133. const char* E = SourceMgr.getCharacterData(Range.getEnd());
  134. return StringRef(B, E - B);
  135. }
  136. // Run lexer over SourceText and collect FilenameRange from
  137. // the InclusionDirective callback.
  138. CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
  139. const char* HeaderPath, bool SystemHeader) {
  140. std::unique_ptr<llvm::MemoryBuffer> Buf =
  141. llvm::MemoryBuffer::getMemBuffer(SourceText);
  142. SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
  143. VoidModuleLoader ModLoader;
  144. HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
  145. Diags, LangOpts, Target.get());
  146. AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
  147. Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
  148. 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(std::make_shared<HeaderSearchOptions>(), SourceMgr,
  174. Diags, OpenCLLangOpts, Target.get());
  175. Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags,
  176. OpenCLLangOpts, SourceMgr, HeaderInfo, ModLoader,
  177. /*IILookup =*/nullptr,
  178. /*OwnsHeaderSearch =*/false);
  179. PP.Initialize(*Target);
  180. // parser actually sets correct pragma handlers for preprocessor
  181. // according to LangOptions, so we init Parser to register opencl
  182. // pragma handlers
  183. ASTContext Context(OpenCLLangOpts, SourceMgr,
  184. PP.getIdentifierTable(), PP.getSelectorTable(),
  185. PP.getBuiltinInfo());
  186. Context.InitBuiltinTypes(*Target);
  187. ASTConsumer Consumer;
  188. Sema S(PP, Context, Consumer);
  189. Parser P(PP, S, false);
  190. PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
  191. PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
  192. // Lex source text.
  193. PP.EnterMainSourceFile();
  194. while (true) {
  195. Token Tok;
  196. PP.Lex(Tok);
  197. if (Tok.is(tok::eof))
  198. break;
  199. }
  200. PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
  201. Callbacks->Name,
  202. Callbacks->State
  203. };
  204. return RetVal;
  205. }
  206. };
  207. TEST_F(PPCallbacksTest, QuotedFilename) {
  208. const char* Source =
  209. "#include \"quoted.h\"\n";
  210. CharSourceRange Range =
  211. InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
  212. ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
  213. }
  214. TEST_F(PPCallbacksTest, AngledFilename) {
  215. const char* Source =
  216. "#include <angled.h>\n";
  217. CharSourceRange Range =
  218. InclusionDirectiveFilenameRange(Source, "/angled.h", true);
  219. ASSERT_EQ("<angled.h>", GetSourceString(Range));
  220. }
  221. TEST_F(PPCallbacksTest, QuotedInMacro) {
  222. const char* Source =
  223. "#define MACRO_QUOTED \"quoted.h\"\n"
  224. "#include MACRO_QUOTED\n";
  225. CharSourceRange Range =
  226. InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
  227. ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
  228. }
  229. TEST_F(PPCallbacksTest, AngledInMacro) {
  230. const char* Source =
  231. "#define MACRO_ANGLED <angled.h>\n"
  232. "#include MACRO_ANGLED\n";
  233. CharSourceRange Range =
  234. InclusionDirectiveFilenameRange(Source, "/angled.h", true);
  235. ASSERT_EQ("<angled.h>", GetSourceString(Range));
  236. }
  237. TEST_F(PPCallbacksTest, StringizedMacroArgument) {
  238. const char* Source =
  239. "#define MACRO_STRINGIZED(x) #x\n"
  240. "#include MACRO_STRINGIZED(quoted.h)\n";
  241. CharSourceRange Range =
  242. InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
  243. ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
  244. }
  245. TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
  246. const char* Source =
  247. "#define MACRO_ANGLED <angled.h>\n"
  248. "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
  249. "#include MACRO_CONCAT(MACRO, ANGLED)\n";
  250. CharSourceRange Range =
  251. InclusionDirectiveFilenameRange(Source, "/angled.h", false);
  252. ASSERT_EQ("<angled.h>", GetSourceString(Range));
  253. }
  254. TEST_F(PPCallbacksTest, TrigraphFilename) {
  255. const char* Source =
  256. "#include \"tri\?\?-graph.h\"\n";
  257. CharSourceRange Range =
  258. InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
  259. ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
  260. }
  261. TEST_F(PPCallbacksTest, TrigraphInMacro) {
  262. const char* Source =
  263. "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
  264. "#include MACRO_TRIGRAPH\n";
  265. CharSourceRange Range =
  266. InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
  267. ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
  268. }
  269. TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
  270. const char* Source =
  271. "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
  272. PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
  273. PragmaOpenCLExtensionCall(Source);
  274. ASSERT_EQ("cl_khr_fp64", Parameters.Name);
  275. unsigned ExpectedState = 1;
  276. ASSERT_EQ(ExpectedState, Parameters.State);
  277. }
  278. TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
  279. const char* Source =
  280. "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
  281. PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
  282. PragmaOpenCLExtensionCall(Source);
  283. ASSERT_EQ("cl_khr_fp16", Parameters.Name);
  284. unsigned ExpectedState = 0;
  285. ASSERT_EQ(ExpectedState, Parameters.State);
  286. }
  287. } // anonoymous namespace