xref: /llvm-project/clang/unittests/Lex/PPCallbacksTest.cpp (revision da95d926f6fce4ed9707c77908ad96624268f134)
1 //===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks tests ------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
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 
29 using namespace clang;
30 
31 namespace {
32 
33 // Stub to collect data from InclusionDirective callbacks.
34 class InclusionDirectiveCallbacks : public PPCallbacks {
35 public:
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,OptionalFileEntryRef File,StringRef SearchPath,StringRef RelativePath,const Module * SuggestedModule,bool ModuleImported,SrcMgr::CharacteristicKind FileType)36   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
37                           StringRef FileName, bool IsAngled,
38                           CharSourceRange FilenameRange,
39                           OptionalFileEntryRef File, StringRef SearchPath,
40                           StringRef RelativePath, const Module *SuggestedModule,
41                           bool ModuleImported,
42                           SrcMgr::CharacteristicKind FileType) override {
43     this->HashLoc = HashLoc;
44     this->IncludeTok = IncludeTok;
45     this->FileName = FileName.str();
46     this->IsAngled = IsAngled;
47     this->FilenameRange = FilenameRange;
48     this->File = File;
49     this->SearchPath = SearchPath.str();
50     this->RelativePath = RelativePath.str();
51     this->SuggestedModule = SuggestedModule;
52     this->ModuleImported = ModuleImported;
53     this->FileType = FileType;
54   }
55 
56   SourceLocation HashLoc;
57   Token IncludeTok;
58   SmallString<16> FileName;
59   bool IsAngled;
60   CharSourceRange FilenameRange;
61   OptionalFileEntryRef File;
62   SmallString<16> SearchPath;
63   SmallString<16> RelativePath;
64   const Module *SuggestedModule;
65   bool ModuleImported;
66   SrcMgr::CharacteristicKind FileType;
67 };
68 
69 class CondDirectiveCallbacks : public PPCallbacks {
70 public:
71   struct Result {
72     SourceRange ConditionRange;
73     ConditionValueKind ConditionValue;
74 
Result__anon1476b0c10111::CondDirectiveCallbacks::Result75     Result(SourceRange R, ConditionValueKind K)
76         : ConditionRange(R), ConditionValue(K) {}
77   };
78 
79   std::vector<Result> Results;
80 
If(SourceLocation Loc,SourceRange ConditionRange,ConditionValueKind ConditionValue)81   void If(SourceLocation Loc, SourceRange ConditionRange,
82           ConditionValueKind ConditionValue) override {
83     Results.emplace_back(ConditionRange, ConditionValue);
84   }
85 
Elif(SourceLocation Loc,SourceRange ConditionRange,ConditionValueKind ConditionValue,SourceLocation IfLoc)86   void Elif(SourceLocation Loc, SourceRange ConditionRange,
87             ConditionValueKind ConditionValue, SourceLocation IfLoc) override {
88     Results.emplace_back(ConditionRange, ConditionValue);
89   }
90 };
91 
92 // Stub to collect data from PragmaOpenCLExtension callbacks.
93 class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
94 public:
95   typedef struct {
96     SmallString<16> Name;
97     unsigned State;
98   } CallbackParameters;
99 
PragmaOpenCLExtensionCallbacks()100   PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}
101 
PragmaOpenCLExtension(clang::SourceLocation NameLoc,const clang::IdentifierInfo * Name,clang::SourceLocation StateLoc,unsigned State)102   void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
103                              const clang::IdentifierInfo *Name,
104                              clang::SourceLocation StateLoc,
105                              unsigned State) override {
106       this->NameLoc = NameLoc;
107       this->Name = Name->getName();
108       this->StateLoc = StateLoc;
109       this->State = State;
110   }
111 
112   SourceLocation NameLoc;
113   SmallString<16> Name;
114   SourceLocation StateLoc;
115   unsigned State;
116 };
117 
118 class PragmaMarkCallbacks : public PPCallbacks {
119 public:
120   struct Mark {
121     SourceLocation Location;
122     std::string Trivia;
123   };
124 
125   std::vector<Mark> Marks;
126 
PragmaMark(SourceLocation Loc,StringRef Trivia)127   void PragmaMark(SourceLocation Loc, StringRef Trivia) override {
128     Marks.emplace_back(Mark{Loc, Trivia.str()});
129   }
130 };
131 
132 // PPCallbacks test fixture.
133 class PPCallbacksTest : public ::testing::Test {
134 protected:
PPCallbacksTest()135   PPCallbacksTest()
136       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
137         FileMgr(FileSystemOptions(), InMemoryFileSystem),
138         DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
139         Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
140         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
141     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
142     Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
143   }
144 
145   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
146   FileManager FileMgr;
147   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
148   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
149   DiagnosticsEngine Diags;
150   SourceManager SourceMgr;
151   LangOptions LangOpts;
152   std::shared_ptr<TargetOptions> TargetOpts;
153   IntrusiveRefCntPtr<TargetInfo> Target;
154 
155   // Register a header path as a known file and add its location
156   // to search path.
AddFakeHeader(HeaderSearch & HeaderInfo,const char * HeaderPath,bool IsSystemHeader)157   void AddFakeHeader(HeaderSearch &HeaderInfo, const char *HeaderPath,
158                      bool IsSystemHeader) {
159     // Tell FileMgr about header.
160     InMemoryFileSystem->addFile(HeaderPath, 0,
161                                 llvm::MemoryBuffer::getMemBuffer("\n"));
162 
163     // Add header's parent path to search path.
164     StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
165     auto DE = FileMgr.getOptionalDirectoryRef(SearchPath);
166     DirectoryLookup DL(*DE, SrcMgr::C_User, false);
167     HeaderInfo.AddSearchPath(DL, IsSystemHeader);
168   }
169 
170   // Get the raw source string of the range.
GetSourceString(CharSourceRange Range)171   StringRef GetSourceString(CharSourceRange Range) {
172     const char* B = SourceMgr.getCharacterData(Range.getBegin());
173     const char* E = SourceMgr.getCharacterData(Range.getEnd());
174 
175     return StringRef(B, E - B);
176   }
177 
GetSourceStringToEnd(CharSourceRange Range)178   StringRef GetSourceStringToEnd(CharSourceRange Range) {
179     const char *B = SourceMgr.getCharacterData(Range.getBegin());
180     const char *E = SourceMgr.getCharacterData(Range.getEnd());
181 
182     return StringRef(
183         B,
184         E - B + Lexer::MeasureTokenLength(Range.getEnd(), SourceMgr, LangOpts));
185   }
186 
187   // Run lexer over SourceText and collect FilenameRange from
188   // the InclusionDirective callback.
InclusionDirectiveFilenameRange(const char * SourceText,const char * HeaderPath,bool SystemHeader)189   CharSourceRange InclusionDirectiveFilenameRange(const char *SourceText,
190                                                   const char *HeaderPath,
191                                                   bool SystemHeader) {
192     std::unique_ptr<llvm::MemoryBuffer> Buf =
193         llvm::MemoryBuffer::getMemBuffer(SourceText);
194     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
195 
196     TrivialModuleLoader ModLoader;
197 
198     HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
199                             Diags, LangOpts, Target.get());
200     AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
201 
202     Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
203                     SourceMgr, HeaderInfo, ModLoader,
204                     /*IILookup =*/nullptr,
205                     /*OwnsHeaderSearch =*/false);
206     return InclusionDirectiveCallback(PP)->FilenameRange;
207   }
208 
InclusionDirectiveCharacteristicKind(const char * SourceText,const char * HeaderPath,bool SystemHeader)209   SrcMgr::CharacteristicKind InclusionDirectiveCharacteristicKind(
210       const char *SourceText, const char *HeaderPath, bool SystemHeader) {
211     std::unique_ptr<llvm::MemoryBuffer> Buf =
212         llvm::MemoryBuffer::getMemBuffer(SourceText);
213     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
214 
215     TrivialModuleLoader ModLoader;
216 
217     HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
218                             Diags, LangOpts, Target.get());
219     AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
220 
221     Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
222                     SourceMgr, HeaderInfo, ModLoader,
223                     /*IILookup =*/nullptr,
224                     /*OwnsHeaderSearch =*/false);
225     return InclusionDirectiveCallback(PP)->FileType;
226   }
227 
InclusionDirectiveCallback(Preprocessor & PP)228   InclusionDirectiveCallbacks *InclusionDirectiveCallback(Preprocessor &PP) {
229     PP.Initialize(*Target);
230     InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
231     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
232 
233     // Lex source text.
234     PP.EnterMainSourceFile();
235     PP.LexTokensUntilEOF();
236 
237     // Callbacks have been executed at this point -- return filename range.
238     return Callbacks;
239   }
240 
241   std::vector<CondDirectiveCallbacks::Result>
DirectiveExprRange(StringRef SourceText)242   DirectiveExprRange(StringRef SourceText) {
243     TrivialModuleLoader ModLoader;
244     std::unique_ptr<llvm::MemoryBuffer> Buf =
245         llvm::MemoryBuffer::getMemBuffer(SourceText);
246     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
247     HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
248                             Diags, LangOpts, Target.get());
249     Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
250                     SourceMgr, HeaderInfo, ModLoader,
251                     /*IILookup =*/nullptr,
252                     /*OwnsHeaderSearch =*/false);
253     PP.Initialize(*Target);
254     auto *Callbacks = new CondDirectiveCallbacks;
255     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
256 
257     // Lex source text.
258     PP.EnterMainSourceFile();
259     PP.LexTokensUntilEOF();
260 
261     return Callbacks->Results;
262   }
263 
264   std::vector<PragmaMarkCallbacks::Mark>
PragmaMarkCall(const char * SourceText)265   PragmaMarkCall(const char *SourceText) {
266     std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
267         llvm::MemoryBuffer::getMemBuffer(SourceText, "test.c");
268     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
269 
270     HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
271                             Diags, LangOpts, Target.get());
272     TrivialModuleLoader ModLoader;
273 
274     Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
275                     SourceMgr, HeaderInfo, ModLoader, /*IILookup=*/nullptr,
276                     /*OwnsHeaderSearch=*/false);
277     PP.Initialize(*Target);
278 
279     auto *Callbacks = new PragmaMarkCallbacks;
280     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
281 
282     // Lex source text.
283     PP.EnterMainSourceFile();
284     PP.LexTokensUntilEOF();
285 
286     return Callbacks->Marks;
287   }
288 
289   PragmaOpenCLExtensionCallbacks::CallbackParameters
PragmaOpenCLExtensionCall(const char * SourceText)290   PragmaOpenCLExtensionCall(const char *SourceText) {
291     LangOptions OpenCLLangOpts;
292     OpenCLLangOpts.OpenCL = 1;
293 
294     std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
295         llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
296     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
297 
298     TrivialModuleLoader ModLoader;
299     HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
300                             Diags, OpenCLLangOpts, Target.get());
301 
302     Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags,
303                     OpenCLLangOpts, SourceMgr, HeaderInfo, ModLoader,
304                     /*IILookup =*/nullptr,
305                     /*OwnsHeaderSearch =*/false);
306     PP.Initialize(*Target);
307 
308     // parser actually sets correct pragma handlers for preprocessor
309     // according to LangOptions, so we init Parser to register opencl
310     // pragma handlers
311     ASTContext Context(OpenCLLangOpts, SourceMgr, PP.getIdentifierTable(),
312                        PP.getSelectorTable(), PP.getBuiltinInfo(), PP.TUKind);
313     Context.InitBuiltinTypes(*Target);
314 
315     ASTConsumer Consumer;
316     Sema S(PP, Context, Consumer);
317     Parser P(PP, S, false);
318     PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
319     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
320 
321     // Lex source text.
322     PP.EnterMainSourceFile();
323     PP.LexTokensUntilEOF();
324 
325     PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
326       Callbacks->Name,
327       Callbacks->State
328     };
329     return RetVal;
330   }
331 };
332 
TEST_F(PPCallbacksTest,UserFileCharacteristics)333 TEST_F(PPCallbacksTest, UserFileCharacteristics) {
334   const char *Source = "#include \"quoted.h\"\n";
335 
336   SrcMgr::CharacteristicKind Kind =
337       InclusionDirectiveCharacteristicKind(Source, "/quoted.h", false);
338 
339   ASSERT_EQ(SrcMgr::CharacteristicKind::C_User, Kind);
340 }
341 
TEST_F(PPCallbacksTest,QuotedFilename)342 TEST_F(PPCallbacksTest, QuotedFilename) {
343   const char* Source =
344     "#include \"quoted.h\"\n";
345 
346   CharSourceRange Range =
347     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
348 
349   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
350 }
351 
TEST_F(PPCallbacksTest,AngledFilename)352 TEST_F(PPCallbacksTest, AngledFilename) {
353   const char* Source =
354     "#include <angled.h>\n";
355 
356   CharSourceRange Range =
357     InclusionDirectiveFilenameRange(Source, "/angled.h", true);
358 
359   ASSERT_EQ("<angled.h>", GetSourceString(Range));
360 }
361 
TEST_F(PPCallbacksTest,QuotedInMacro)362 TEST_F(PPCallbacksTest, QuotedInMacro) {
363   const char* Source =
364     "#define MACRO_QUOTED \"quoted.h\"\n"
365     "#include MACRO_QUOTED\n";
366 
367   CharSourceRange Range =
368     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
369 
370   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
371 }
372 
TEST_F(PPCallbacksTest,AngledInMacro)373 TEST_F(PPCallbacksTest, AngledInMacro) {
374   const char* Source =
375     "#define MACRO_ANGLED <angled.h>\n"
376     "#include MACRO_ANGLED\n";
377 
378   CharSourceRange Range =
379     InclusionDirectiveFilenameRange(Source, "/angled.h", true);
380 
381   ASSERT_EQ("<angled.h>", GetSourceString(Range));
382 }
383 
TEST_F(PPCallbacksTest,StringizedMacroArgument)384 TEST_F(PPCallbacksTest, StringizedMacroArgument) {
385   const char* Source =
386     "#define MACRO_STRINGIZED(x) #x\n"
387     "#include MACRO_STRINGIZED(quoted.h)\n";
388 
389   CharSourceRange Range =
390     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
391 
392   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
393 }
394 
TEST_F(PPCallbacksTest,ConcatenatedMacroArgument)395 TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
396   const char* Source =
397     "#define MACRO_ANGLED <angled.h>\n"
398     "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
399     "#include MACRO_CONCAT(MACRO, ANGLED)\n";
400 
401   CharSourceRange Range =
402     InclusionDirectiveFilenameRange(Source, "/angled.h", false);
403 
404   ASSERT_EQ("<angled.h>", GetSourceString(Range));
405 }
406 
TEST_F(PPCallbacksTest,TrigraphFilename)407 TEST_F(PPCallbacksTest, TrigraphFilename) {
408   const char* Source =
409     "#include \"tri\?\?-graph.h\"\n";
410 
411   CharSourceRange Range =
412     InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
413 
414   ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
415 }
416 
TEST_F(PPCallbacksTest,TrigraphInMacro)417 TEST_F(PPCallbacksTest, TrigraphInMacro) {
418   const char* Source =
419     "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
420     "#include MACRO_TRIGRAPH\n";
421 
422   CharSourceRange Range =
423     InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
424 
425   ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
426 }
427 
TEST_F(PPCallbacksTest,FileNotFoundSkipped)428 TEST_F(PPCallbacksTest, FileNotFoundSkipped) {
429   const char *SourceText = "#include \"skipped.h\"\n";
430 
431   std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
432       llvm::MemoryBuffer::getMemBuffer(SourceText);
433   SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
434 
435   HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
436                           Diags, LangOpts, Target.get());
437   TrivialModuleLoader ModLoader;
438 
439   DiagnosticConsumer *DiagConsumer = new DiagnosticConsumer;
440   DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts.get(), DiagConsumer);
441   Preprocessor PP(std::make_shared<PreprocessorOptions>(), FileNotFoundDiags,
442                   LangOpts, SourceMgr, HeaderInfo, ModLoader,
443                   /*IILookup=*/nullptr,
444                   /*OwnsHeaderSearch=*/false);
445   PP.Initialize(*Target);
446 
447   class FileNotFoundCallbacks : public PPCallbacks {
448   public:
449     unsigned int NumCalls = 0;
450     bool FileNotFound(StringRef FileName) override {
451       NumCalls++;
452       return FileName == "skipped.h";
453     }
454   };
455 
456   auto *Callbacks = new FileNotFoundCallbacks;
457   PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
458 
459   // Lex source text.
460   PP.EnterMainSourceFile();
461   PP.LexTokensUntilEOF();
462 
463   ASSERT_EQ(1u, Callbacks->NumCalls);
464   ASSERT_EQ(0u, DiagConsumer->getNumErrors());
465 }
466 
TEST_F(PPCallbacksTest,OpenCLExtensionPragmaEnabled)467 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
468   const char* Source =
469     "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
470 
471   PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
472     PragmaOpenCLExtensionCall(Source);
473 
474   ASSERT_EQ("cl_khr_fp64", Parameters.Name);
475   unsigned ExpectedState = 1;
476   ASSERT_EQ(ExpectedState, Parameters.State);
477 }
478 
TEST_F(PPCallbacksTest,OpenCLExtensionPragmaDisabled)479 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
480   const char* Source =
481     "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
482 
483   PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
484     PragmaOpenCLExtensionCall(Source);
485 
486   ASSERT_EQ("cl_khr_fp16", Parameters.Name);
487   unsigned ExpectedState = 0;
488   ASSERT_EQ(ExpectedState, Parameters.State);
489 }
490 
TEST_F(PPCallbacksTest,CollectMarks)491 TEST_F(PPCallbacksTest, CollectMarks) {
492   const char *Source =
493     "#pragma mark\n"
494     "#pragma mark\r\n"
495     "#pragma mark - trivia\n"
496     "#pragma mark - trivia\r\n";
497 
498   auto Marks = PragmaMarkCall(Source);
499 
500   ASSERT_EQ(4u, Marks.size());
501   ASSERT_TRUE(Marks[0].Trivia.empty());
502   ASSERT_TRUE(Marks[1].Trivia.empty());
503   ASSERT_FALSE(Marks[2].Trivia.empty());
504   ASSERT_FALSE(Marks[3].Trivia.empty());
505   ASSERT_EQ(" - trivia", Marks[2].Trivia);
506   ASSERT_EQ(" - trivia", Marks[3].Trivia);
507 }
508 
TEST_F(PPCallbacksTest,DirectiveExprRanges)509 TEST_F(PPCallbacksTest, DirectiveExprRanges) {
510   const auto &Results1 = DirectiveExprRange("#if FLUZZY_FLOOF\n#endif\n");
511   EXPECT_EQ(Results1.size(), 1U);
512   EXPECT_EQ(
513       GetSourceStringToEnd(CharSourceRange(Results1[0].ConditionRange, false)),
514       "FLUZZY_FLOOF");
515 
516   const auto &Results2 = DirectiveExprRange("#if 1 + 4 < 7\n#endif\n");
517   EXPECT_EQ(Results2.size(), 1U);
518   EXPECT_EQ(
519       GetSourceStringToEnd(CharSourceRange(Results2[0].ConditionRange, false)),
520       "1 + 4 < 7");
521 
522   const auto &Results3 = DirectiveExprRange("#if 1 + \\\n  2\n#endif\n");
523   EXPECT_EQ(Results3.size(), 1U);
524   EXPECT_EQ(
525       GetSourceStringToEnd(CharSourceRange(Results3[0].ConditionRange, false)),
526       "1 + \\\n  2");
527 
528   const auto &Results4 = DirectiveExprRange("#if 0\n#elif FLOOFY\n#endif\n");
529   EXPECT_EQ(Results4.size(), 2U);
530   EXPECT_EQ(
531       GetSourceStringToEnd(CharSourceRange(Results4[0].ConditionRange, false)),
532       "0");
533   EXPECT_EQ(
534       GetSourceStringToEnd(CharSourceRange(Results4[1].ConditionRange, false)),
535       "FLOOFY");
536 
537   const auto &Results5 = DirectiveExprRange("#if 1\n#elif FLOOFY\n#endif\n");
538   EXPECT_EQ(Results5.size(), 2U);
539   EXPECT_EQ(
540       GetSourceStringToEnd(CharSourceRange(Results5[0].ConditionRange, false)),
541       "1");
542   EXPECT_EQ(
543       GetSourceStringToEnd(CharSourceRange(Results5[1].ConditionRange, false)),
544       "FLOOFY");
545 
546   const auto &Results6 =
547       DirectiveExprRange("#if defined(FLUZZY_FLOOF)\n#endif\n");
548   EXPECT_EQ(Results6.size(), 1U);
549   EXPECT_EQ(
550       GetSourceStringToEnd(CharSourceRange(Results6[0].ConditionRange, false)),
551       "defined(FLUZZY_FLOOF)");
552 
553   const auto &Results7 =
554       DirectiveExprRange("#if 1\n#elif defined(FLOOFY)\n#endif\n");
555   EXPECT_EQ(Results7.size(), 2U);
556   EXPECT_EQ(
557       GetSourceStringToEnd(CharSourceRange(Results7[0].ConditionRange, false)),
558       "1");
559   EXPECT_EQ(
560       GetSourceStringToEnd(CharSourceRange(Results7[1].ConditionRange, false)),
561       "defined(FLOOFY)");
562 
563   const auto &Results8 =
564       DirectiveExprRange("#define FLOOFY 0\n#if __FILE__ > FLOOFY\n#endif\n");
565   EXPECT_EQ(Results8.size(), 1U);
566   EXPECT_EQ(
567       GetSourceStringToEnd(CharSourceRange(Results8[0].ConditionRange, false)),
568       "__FILE__ > FLOOFY");
569   EXPECT_EQ(
570       Lexer::getSourceText(CharSourceRange(Results8[0].ConditionRange, false),
571                            SourceMgr, LangOpts),
572       "__FILE__ > FLOOFY");
573 }
574 
575 } // namespace
576