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
29using namespace clang;
30
31namespace {
32
33// Stub to collect data from InclusionDirective callbacks.
34class InclusionDirectiveCallbacks : public PPCallbacks {
35public:
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
69class CondDirectiveCallbacks : public PPCallbacks {
70public:
71 struct Result {
72 SourceRange ConditionRange;
73 ConditionValueKind ConditionValue;
74
75 Result(SourceRange R, ConditionValueKind K)
76 : ConditionRange(R), ConditionValue(K) {}
77 };
78
79 std::vector<Result> Results;
80
81 void If(SourceLocation Loc, SourceRange ConditionRange,
82 ConditionValueKind ConditionValue) override {
83 Results.emplace_back(args&: ConditionRange, args&: ConditionValue);
84 }
85
86 void Elif(SourceLocation Loc, SourceRange ConditionRange,
87 ConditionValueKind ConditionValue, SourceLocation IfLoc) override {
88 Results.emplace_back(args&: ConditionRange, args&: ConditionValue);
89 }
90};
91
92// Stub to collect data from PragmaOpenCLExtension callbacks.
93class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
94public:
95 typedef struct {
96 SmallString<16> Name;
97 unsigned State;
98 } CallbackParameters;
99
100 PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}
101
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
118class PragmaMarkCallbacks : public PPCallbacks {
119public:
120 struct Mark {
121 SourceLocation Location;
122 std::string Trivia;
123 };
124
125 std::vector<Mark> Marks;
126
127 void PragmaMark(SourceLocation Loc, StringRef Trivia) override {
128 Marks.emplace_back(args: Mark{.Location: Loc, .Trivia: Trivia.str()});
129 }
130};
131
132// PPCallbacks test fixture.
133class PPCallbacksTest : public ::testing::Test {
134protected:
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, Opts: 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.
157 void AddFakeHeader(HeaderSearch &HeaderInfo, const char *HeaderPath,
158 bool IsSystemHeader) {
159 // Tell FileMgr about header.
160 InMemoryFileSystem->addFile(Path: HeaderPath, ModificationTime: 0,
161 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n"));
162
163 // Add header's parent path to search path.
164 StringRef SearchPath = llvm::sys::path::parent_path(path: HeaderPath);
165 auto DE = FileMgr.getOptionalDirectoryRef(DirName: SearchPath);
166 DirectoryLookup DL(*DE, SrcMgr::C_User, false);
167 HeaderInfo.AddSearchPath(dir: DL, isAngled: IsSystemHeader);
168 }
169
170 // Get the raw source string of the range.
171 StringRef GetSourceString(CharSourceRange Range) {
172 const char* B = SourceMgr.getCharacterData(SL: Range.getBegin());
173 const char* E = SourceMgr.getCharacterData(SL: Range.getEnd());
174
175 return StringRef(B, E - B);
176 }
177
178 StringRef GetSourceStringToEnd(CharSourceRange Range) {
179 const char *B = SourceMgr.getCharacterData(SL: Range.getBegin());
180 const char *E = SourceMgr.getCharacterData(SL: Range.getEnd());
181
182 return StringRef(
183 B,
184 E - B + Lexer::MeasureTokenLength(Loc: Range.getEnd(), SM: SourceMgr, LangOpts));
185 }
186
187 // Run lexer over SourceText and collect FilenameRange from
188 // the InclusionDirective callback.
189 CharSourceRange InclusionDirectiveFilenameRange(const char *SourceText,
190 const char *HeaderPath,
191 bool SystemHeader) {
192 std::unique_ptr<llvm::MemoryBuffer> Buf =
193 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText);
194 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: 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, IsSystemHeader: 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
209 SrcMgr::CharacteristicKind InclusionDirectiveCharacteristicKind(
210 const char *SourceText, const char *HeaderPath, bool SystemHeader) {
211 std::unique_ptr<llvm::MemoryBuffer> Buf =
212 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText);
213 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: 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, IsSystemHeader: 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
228 InclusionDirectiveCallbacks *InclusionDirectiveCallback(Preprocessor &PP) {
229 PP.Initialize(Target: *Target);
230 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
231 PP.addPPCallbacks(C: 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>
242 DirectiveExprRange(StringRef SourceText) {
243 TrivialModuleLoader ModLoader;
244 std::unique_ptr<llvm::MemoryBuffer> Buf =
245 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText);
246 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: 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: *Target);
254 auto *Callbacks = new CondDirectiveCallbacks;
255 PP.addPPCallbacks(C: 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>
265 PragmaMarkCall(const char *SourceText) {
266 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
267 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText, BufferName: "test.c");
268 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: 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: *Target);
278
279 auto *Callbacks = new PragmaMarkCallbacks;
280 PP.addPPCallbacks(C: 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
290 PragmaOpenCLExtensionCall(const char *SourceText) {
291 LangOptions OpenCLLangOpts;
292 OpenCLLangOpts.OpenCL = 1;
293
294 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
295 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText, BufferName: "test.cl");
296 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: 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: *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: *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(C: std::unique_ptr<PPCallbacks>(Callbacks));
320
321 // Lex source text.
322 PP.EnterMainSourceFile();
323 PP.LexTokensUntilEOF();
324
325 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
326 .Name: Callbacks->Name,
327 .State: Callbacks->State
328 };
329 return RetVal;
330 }
331};
332
333TEST_F(PPCallbacksTest, UserFileCharacteristics) {
334 const char *Source = "#include \"quoted.h\"\n";
335
336 SrcMgr::CharacteristicKind Kind =
337 InclusionDirectiveCharacteristicKind(SourceText: Source, HeaderPath: "/quoted.h", SystemHeader: false);
338
339 ASSERT_EQ(SrcMgr::CharacteristicKind::C_User, Kind);
340}
341
342TEST_F(PPCallbacksTest, QuotedFilename) {
343 const char* Source =
344 "#include \"quoted.h\"\n";
345
346 CharSourceRange Range =
347 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/quoted.h", SystemHeader: false);
348
349 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
350}
351
352TEST_F(PPCallbacksTest, AngledFilename) {
353 const char* Source =
354 "#include <angled.h>\n";
355
356 CharSourceRange Range =
357 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/angled.h", SystemHeader: true);
358
359 ASSERT_EQ("<angled.h>", GetSourceString(Range));
360}
361
362TEST_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(SourceText: Source, HeaderPath: "/quoted.h", SystemHeader: false);
369
370 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
371}
372
373TEST_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(SourceText: Source, HeaderPath: "/angled.h", SystemHeader: true);
380
381 ASSERT_EQ("<angled.h>", GetSourceString(Range));
382}
383
384TEST_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(SourceText: Source, HeaderPath: "/quoted.h", SystemHeader: false);
391
392 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
393}
394
395TEST_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(SourceText: Source, HeaderPath: "/angled.h", SystemHeader: false);
403
404 ASSERT_EQ("<angled.h>", GetSourceString(Range));
405}
406
407TEST_F(PPCallbacksTest, TrigraphFilename) {
408 const char* Source =
409 "#include \"tri\?\?-graph.h\"\n";
410
411 CharSourceRange Range =
412 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/tri~graph.h", SystemHeader: false);
413
414 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
415}
416
417TEST_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(SourceText: Source, HeaderPath: "/tri~graph.h", SystemHeader: false);
424
425 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
426}
427
428TEST_F(PPCallbacksTest, FileNotFoundSkipped) {
429 const char *SourceText = "#include \"skipped.h\"\n";
430
431 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
432 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText);
433 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: 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: *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(C: 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
467TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
468 const char* Source =
469 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
470
471 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
472 PragmaOpenCLExtensionCall(SourceText: Source);
473
474 ASSERT_EQ("cl_khr_fp64", Parameters.Name);
475 unsigned ExpectedState = 1;
476 ASSERT_EQ(ExpectedState, Parameters.State);
477}
478
479TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
480 const char* Source =
481 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
482
483 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
484 PragmaOpenCLExtensionCall(SourceText: Source);
485
486 ASSERT_EQ("cl_khr_fp16", Parameters.Name);
487 unsigned ExpectedState = 0;
488 ASSERT_EQ(ExpectedState, Parameters.State);
489}
490
491TEST_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(SourceText: 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
509TEST_F(PPCallbacksTest, DirectiveExprRanges) {
510 const auto &Results1 = DirectiveExprRange(SourceText: "#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(SourceText: "#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(SourceText: "#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(SourceText: "#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(SourceText: "#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(SourceText: "#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(SourceText: "#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(SourceText: "#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

source code of clang/unittests/Lex/PPCallbacksTest.cpp