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()),
139 Diags(DiagID, DiagOpts, 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 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 HeaderSearchOptions HSOpts;
197 TrivialModuleLoader ModLoader;
198
199 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
200 AddFakeHeader(HeaderInfo, HeaderPath, IsSystemHeader: SystemHeader);
201
202 PreprocessorOptions PPOpts;
203 Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
204 /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);
205 return InclusionDirectiveCallback(PP)->FilenameRange;
206 }
207
208 SrcMgr::CharacteristicKind InclusionDirectiveCharacteristicKind(
209 const char *SourceText, const char *HeaderPath, bool SystemHeader) {
210 std::unique_ptr<llvm::MemoryBuffer> Buf =
211 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText);
212 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: std::move(Buf)));
213
214 HeaderSearchOptions HSOpts;
215 TrivialModuleLoader ModLoader;
216
217 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
218 AddFakeHeader(HeaderInfo, HeaderPath, IsSystemHeader: SystemHeader);
219
220 PreprocessorOptions PPOpts;
221 Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
222 /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);
223 return InclusionDirectiveCallback(PP)->FileType;
224 }
225
226 InclusionDirectiveCallbacks *InclusionDirectiveCallback(Preprocessor &PP) {
227 PP.Initialize(Target: *Target);
228 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
229 PP.addPPCallbacks(C: std::unique_ptr<PPCallbacks>(Callbacks));
230
231 // Lex source text.
232 PP.EnterMainSourceFile();
233 PP.LexTokensUntilEOF();
234
235 // Callbacks have been executed at this point -- return filename range.
236 return Callbacks;
237 }
238
239 std::vector<CondDirectiveCallbacks::Result>
240 DirectiveExprRange(StringRef SourceText, PreprocessorOptions PPOpts = {}) {
241 HeaderSearchOptions HSOpts;
242 TrivialModuleLoader ModLoader;
243 std::unique_ptr<llvm::MemoryBuffer> Buf =
244 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText);
245 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: std::move(Buf)));
246 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
247 Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
248 /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);
249 PP.Initialize(Target: *Target);
250 auto *Callbacks = new CondDirectiveCallbacks;
251 PP.addPPCallbacks(C: std::unique_ptr<PPCallbacks>(Callbacks));
252
253 // Lex source text.
254 PP.EnterMainSourceFile();
255 PP.LexTokensUntilEOF();
256
257 return Callbacks->Results;
258 }
259
260 std::vector<PragmaMarkCallbacks::Mark>
261 PragmaMarkCall(const char *SourceText) {
262 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
263 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText, BufferName: "test.c");
264 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: std::move(SourceBuf)));
265
266 HeaderSearchOptions HSOpts;
267 TrivialModuleLoader ModLoader;
268 PreprocessorOptions PPOpts;
269
270 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
271
272 Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
273 /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);
274 PP.Initialize(Target: *Target);
275
276 auto *Callbacks = new PragmaMarkCallbacks;
277 PP.addPPCallbacks(C: std::unique_ptr<PPCallbacks>(Callbacks));
278
279 // Lex source text.
280 PP.EnterMainSourceFile();
281 PP.LexTokensUntilEOF();
282
283 return Callbacks->Marks;
284 }
285
286 PragmaOpenCLExtensionCallbacks::CallbackParameters
287 PragmaOpenCLExtensionCall(const char *SourceText) {
288 LangOptions OpenCLLangOpts;
289 OpenCLLangOpts.OpenCL = 1;
290
291 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
292 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText, BufferName: "test.cl");
293 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: std::move(SourceBuf)));
294
295 HeaderSearchOptions HSOpts;
296 TrivialModuleLoader ModLoader;
297 PreprocessorOptions PPOpts;
298
299 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, OpenCLLangOpts,
300 Target.get());
301
302 Preprocessor PP(PPOpts, Diags, OpenCLLangOpts, SourceMgr, HeaderInfo,
303 ModLoader, /*IILookup=*/nullptr,
304 /*OwnsHeaderSearch=*/false);
305 PP.Initialize(Target: *Target);
306
307 // parser actually sets correct pragma handlers for preprocessor
308 // according to LangOptions, so we init Parser to register opencl
309 // pragma handlers
310 ASTContext Context(OpenCLLangOpts, SourceMgr, PP.getIdentifierTable(),
311 PP.getSelectorTable(), PP.getBuiltinInfo(), PP.TUKind);
312 Context.InitBuiltinTypes(Target: *Target);
313
314 ASTConsumer Consumer;
315 Sema S(PP, Context, Consumer);
316 Parser P(PP, S, false);
317 PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
318 PP.addPPCallbacks(C: std::unique_ptr<PPCallbacks>(Callbacks));
319
320 // Lex source text.
321 PP.EnterMainSourceFile();
322 PP.LexTokensUntilEOF();
323
324 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
325 .Name: Callbacks->Name,
326 .State: Callbacks->State
327 };
328 return RetVal;
329 }
330};
331
332TEST_F(PPCallbacksTest, UserFileCharacteristics) {
333 const char *Source = "#include \"quoted.h\"\n";
334
335 SrcMgr::CharacteristicKind Kind =
336 InclusionDirectiveCharacteristicKind(SourceText: Source, HeaderPath: "/quoted.h", SystemHeader: false);
337
338 ASSERT_EQ(SrcMgr::CharacteristicKind::C_User, Kind);
339}
340
341TEST_F(PPCallbacksTest, QuotedFilename) {
342 const char* Source =
343 "#include \"quoted.h\"\n";
344
345 CharSourceRange Range =
346 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/quoted.h", SystemHeader: false);
347
348 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
349}
350
351TEST_F(PPCallbacksTest, AngledFilename) {
352 const char* Source =
353 "#include <angled.h>\n";
354
355 CharSourceRange Range =
356 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/angled.h", SystemHeader: true);
357
358 ASSERT_EQ("<angled.h>", GetSourceString(Range));
359}
360
361TEST_F(PPCallbacksTest, QuotedInMacro) {
362 const char* Source =
363 "#define MACRO_QUOTED \"quoted.h\"\n"
364 "#include MACRO_QUOTED\n";
365
366 CharSourceRange Range =
367 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/quoted.h", SystemHeader: false);
368
369 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
370}
371
372TEST_F(PPCallbacksTest, AngledInMacro) {
373 const char* Source =
374 "#define MACRO_ANGLED <angled.h>\n"
375 "#include MACRO_ANGLED\n";
376
377 CharSourceRange Range =
378 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/angled.h", SystemHeader: true);
379
380 ASSERT_EQ("<angled.h>", GetSourceString(Range));
381}
382
383TEST_F(PPCallbacksTest, StringizedMacroArgument) {
384 const char* Source =
385 "#define MACRO_STRINGIZED(x) #x\n"
386 "#include MACRO_STRINGIZED(quoted.h)\n";
387
388 CharSourceRange Range =
389 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/quoted.h", SystemHeader: false);
390
391 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
392}
393
394TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
395 const char* Source =
396 "#define MACRO_ANGLED <angled.h>\n"
397 "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
398 "#include MACRO_CONCAT(MACRO, ANGLED)\n";
399
400 CharSourceRange Range =
401 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/angled.h", SystemHeader: false);
402
403 ASSERT_EQ("<angled.h>", GetSourceString(Range));
404}
405
406TEST_F(PPCallbacksTest, TrigraphFilename) {
407 const char* Source =
408 "#include \"tri\?\?-graph.h\"\n";
409
410 CharSourceRange Range =
411 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/tri~graph.h", SystemHeader: false);
412
413 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
414}
415
416TEST_F(PPCallbacksTest, TrigraphInMacro) {
417 const char* Source =
418 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
419 "#include MACRO_TRIGRAPH\n";
420
421 CharSourceRange Range =
422 InclusionDirectiveFilenameRange(SourceText: Source, HeaderPath: "/tri~graph.h", SystemHeader: false);
423
424 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
425}
426
427TEST_F(PPCallbacksTest, FileNotFoundSkipped) {
428 const char *SourceText = "#include \"skipped.h\"\n";
429
430 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
431 llvm::MemoryBuffer::getMemBuffer(InputData: SourceText);
432 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: std::move(SourceBuf)));
433
434 HeaderSearchOptions HSOpts;
435 TrivialModuleLoader ModLoader;
436 PreprocessorOptions PPOpts;
437 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
438
439 DiagnosticConsumer *DiagConsumer = new DiagnosticConsumer;
440 DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts, DiagConsumer);
441 Preprocessor PP(PPOpts, FileNotFoundDiags, LangOpts, SourceMgr, HeaderInfo,
442 ModLoader, /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);
443 PP.Initialize(Target: *Target);
444
445 class FileNotFoundCallbacks : public PPCallbacks {
446 public:
447 unsigned int NumCalls = 0;
448 bool FileNotFound(StringRef FileName) override {
449 NumCalls++;
450 return FileName == "skipped.h";
451 }
452 };
453
454 auto *Callbacks = new FileNotFoundCallbacks;
455 PP.addPPCallbacks(C: std::unique_ptr<PPCallbacks>(Callbacks));
456
457 // Lex source text.
458 PP.EnterMainSourceFile();
459 PP.LexTokensUntilEOF();
460
461 ASSERT_EQ(1u, Callbacks->NumCalls);
462 ASSERT_EQ(0u, DiagConsumer->getNumErrors());
463}
464
465TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
466 const char* Source =
467 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
468
469 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
470 PragmaOpenCLExtensionCall(SourceText: Source);
471
472 ASSERT_EQ("cl_khr_fp64", Parameters.Name);
473 unsigned ExpectedState = 1;
474 ASSERT_EQ(ExpectedState, Parameters.State);
475}
476
477TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
478 const char* Source =
479 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
480
481 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
482 PragmaOpenCLExtensionCall(SourceText: Source);
483
484 ASSERT_EQ("cl_khr_fp16", Parameters.Name);
485 unsigned ExpectedState = 0;
486 ASSERT_EQ(ExpectedState, Parameters.State);
487}
488
489TEST_F(PPCallbacksTest, CollectMarks) {
490 const char *Source =
491 "#pragma mark\n"
492 "#pragma mark\r\n"
493 "#pragma mark - trivia\n"
494 "#pragma mark - trivia\r\n";
495
496 auto Marks = PragmaMarkCall(SourceText: Source);
497
498 ASSERT_EQ(4u, Marks.size());
499 ASSERT_TRUE(Marks[0].Trivia.empty());
500 ASSERT_TRUE(Marks[1].Trivia.empty());
501 ASSERT_FALSE(Marks[2].Trivia.empty());
502 ASSERT_FALSE(Marks[3].Trivia.empty());
503 ASSERT_EQ(" - trivia", Marks[2].Trivia);
504 ASSERT_EQ(" - trivia", Marks[3].Trivia);
505}
506
507TEST_F(PPCallbacksTest, DirectiveExprRanges) {
508 const auto &Results1 = DirectiveExprRange(SourceText: "#if FLUZZY_FLOOF\n#endif\n");
509 EXPECT_EQ(Results1.size(), 1U);
510 EXPECT_EQ(
511 GetSourceStringToEnd(CharSourceRange(Results1[0].ConditionRange, false)),
512 "FLUZZY_FLOOF");
513
514 const auto &Results2 = DirectiveExprRange(SourceText: "#if 1 + 4 < 7\n#endif\n");
515 EXPECT_EQ(Results2.size(), 1U);
516 EXPECT_EQ(
517 GetSourceStringToEnd(CharSourceRange(Results2[0].ConditionRange, false)),
518 "1 + 4 < 7");
519
520 const auto &Results3 = DirectiveExprRange(SourceText: "#if 1 + \\\n 2\n#endif\n");
521 EXPECT_EQ(Results3.size(), 1U);
522 EXPECT_EQ(
523 GetSourceStringToEnd(CharSourceRange(Results3[0].ConditionRange, false)),
524 "1 + \\\n 2");
525
526 const auto &Results4 = DirectiveExprRange(SourceText: "#if 0\n#elif FLOOFY\n#endif\n");
527 EXPECT_EQ(Results4.size(), 2U);
528 EXPECT_EQ(
529 GetSourceStringToEnd(CharSourceRange(Results4[0].ConditionRange, false)),
530 "0");
531 EXPECT_EQ(
532 GetSourceStringToEnd(CharSourceRange(Results4[1].ConditionRange, false)),
533 "FLOOFY");
534
535 const auto &Results5 = DirectiveExprRange(SourceText: "#if 1\n#elif FLOOFY\n#endif\n");
536 EXPECT_EQ(Results5.size(), 2U);
537 EXPECT_EQ(
538 GetSourceStringToEnd(CharSourceRange(Results5[0].ConditionRange, false)),
539 "1");
540 EXPECT_EQ(
541 GetSourceStringToEnd(CharSourceRange(Results5[1].ConditionRange, false)),
542 "FLOOFY");
543
544 const auto &Results6 =
545 DirectiveExprRange(SourceText: "#if defined(FLUZZY_FLOOF)\n#endif\n");
546 EXPECT_EQ(Results6.size(), 1U);
547 EXPECT_EQ(
548 GetSourceStringToEnd(CharSourceRange(Results6[0].ConditionRange, false)),
549 "defined(FLUZZY_FLOOF)");
550
551 const auto &Results7 =
552 DirectiveExprRange(SourceText: "#if 1\n#elif defined(FLOOFY)\n#endif\n");
553 EXPECT_EQ(Results7.size(), 2U);
554 EXPECT_EQ(
555 GetSourceStringToEnd(CharSourceRange(Results7[0].ConditionRange, false)),
556 "1");
557 EXPECT_EQ(
558 GetSourceStringToEnd(CharSourceRange(Results7[1].ConditionRange, false)),
559 "defined(FLOOFY)");
560
561 const auto &Results8 =
562 DirectiveExprRange(SourceText: "#define FLOOFY 0\n#if __FILE__ > FLOOFY\n#endif\n");
563 EXPECT_EQ(Results8.size(), 1U);
564 EXPECT_EQ(
565 GetSourceStringToEnd(CharSourceRange(Results8[0].ConditionRange, false)),
566 "__FILE__ > FLOOFY");
567 EXPECT_EQ(
568 Lexer::getSourceText(CharSourceRange(Results8[0].ConditionRange, false),
569 SourceMgr, LangOpts),
570 "__FILE__ > FLOOFY");
571
572 const char *MultiExprIf = "#if defined(FLOOFY) || defined(FLUZZY)\n#endif\n";
573 const auto &Results9 = DirectiveExprRange(SourceText: MultiExprIf);
574 EXPECT_EQ(Results9.size(), 1U);
575 EXPECT_EQ(
576 Lexer::getSourceText(CharSourceRange(Results9[0].ConditionRange, false),
577 SourceMgr, LangOpts),
578 "defined(FLOOFY) || defined(FLUZZY)");
579
580 PreprocessorOptions PPOptsSingleFileParse;
581 PPOptsSingleFileParse.SingleFileParseMode = true;
582 const auto &Results10 =
583 DirectiveExprRange(SourceText: MultiExprIf, PPOpts: PPOptsSingleFileParse);
584 EXPECT_EQ(Results10.size(), 1U);
585 EXPECT_EQ(
586 Lexer::getSourceText(CharSourceRange(Results10[0].ConditionRange, false),
587 SourceMgr, LangOpts),
588 "defined(FLOOFY) || defined(FLUZZY)");
589}
590
591} // namespace
592

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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