[flang][OpenMP] Rename some `Type` members in OpenMP clauses (#117784)
[llvm-project.git] / clang / unittests / Lex / PPCallbacksTest.cpp
blobf3cdb1dfb28742fc92e0179eaa17118f15a7bdd0
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 //===--------------------------------------------------------------===//
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"
29 using namespace clang;
31 namespace {
33 // Stub to collect data from InclusionDirective callbacks.
34 class InclusionDirectiveCallbacks : public PPCallbacks {
35 public:
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;
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;
69 class CondDirectiveCallbacks : public PPCallbacks {
70 public:
71 struct Result {
72 SourceRange ConditionRange;
73 ConditionValueKind ConditionValue;
75 Result(SourceRange R, ConditionValueKind K)
76 : ConditionRange(R), ConditionValue(K) {}
79 std::vector<Result> Results;
81 void If(SourceLocation Loc, SourceRange ConditionRange,
82 ConditionValueKind ConditionValue) override {
83 Results.emplace_back(ConditionRange, ConditionValue);
86 void Elif(SourceLocation Loc, SourceRange ConditionRange,
87 ConditionValueKind ConditionValue, SourceLocation IfLoc) override {
88 Results.emplace_back(ConditionRange, ConditionValue);
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;
100 PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}
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;
112 SourceLocation NameLoc;
113 SmallString<16> Name;
114 SourceLocation StateLoc;
115 unsigned State;
118 class PragmaMarkCallbacks : public PPCallbacks {
119 public:
120 struct Mark {
121 SourceLocation Location;
122 std::string Trivia;
125 std::vector<Mark> Marks;
127 void PragmaMark(SourceLocation Loc, StringRef Trivia) override {
128 Marks.emplace_back(Mark{Loc, Trivia.str()});
132 // PPCallbacks test fixture.
133 class PPCallbacksTest : public ::testing::Test {
134 protected:
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);
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;
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(HeaderPath, 0,
161 llvm::MemoryBuffer::getMemBuffer("\n"));
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);
170 // Get the raw source string of the range.
171 StringRef GetSourceString(CharSourceRange Range) {
172 const char* B = SourceMgr.getCharacterData(Range.getBegin());
173 const char* E = SourceMgr.getCharacterData(Range.getEnd());
175 return StringRef(B, E - B);
178 StringRef GetSourceStringToEnd(CharSourceRange Range) {
179 const char *B = SourceMgr.getCharacterData(Range.getBegin());
180 const char *E = SourceMgr.getCharacterData(Range.getEnd());
182 return StringRef(
184 E - B + Lexer::MeasureTokenLength(Range.getEnd(), SourceMgr, LangOpts));
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(SourceText);
194 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
196 TrivialModuleLoader ModLoader;
198 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
199 Diags, LangOpts, Target.get());
200 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
202 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
203 SourceMgr, HeaderInfo, ModLoader,
204 /*IILookup =*/nullptr,
205 /*OwnsHeaderSearch =*/false);
206 return InclusionDirectiveCallback(PP)->FilenameRange;
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)));
215 TrivialModuleLoader ModLoader;
217 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
218 Diags, LangOpts, Target.get());
219 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
221 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
222 SourceMgr, HeaderInfo, ModLoader,
223 /*IILookup =*/nullptr,
224 /*OwnsHeaderSearch =*/false);
225 return InclusionDirectiveCallback(PP)->FileType;
228 InclusionDirectiveCallbacks *InclusionDirectiveCallback(Preprocessor &PP) {
229 PP.Initialize(*Target);
230 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
231 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
233 // Lex source text.
234 PP.EnterMainSourceFile();
235 PP.LexTokensUntilEOF();
237 // Callbacks have been executed at this point -- return filename range.
238 return Callbacks;
241 std::vector<CondDirectiveCallbacks::Result>
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));
257 // Lex source text.
258 PP.EnterMainSourceFile();
259 PP.LexTokensUntilEOF();
261 return Callbacks->Results;
264 std::vector<PragmaMarkCallbacks::Mark>
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)));
270 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
271 Diags, LangOpts, Target.get());
272 TrivialModuleLoader ModLoader;
274 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
275 SourceMgr, HeaderInfo, ModLoader, /*IILookup=*/nullptr,
276 /*OwnsHeaderSearch=*/false);
277 PP.Initialize(*Target);
279 auto *Callbacks = new PragmaMarkCallbacks;
280 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
282 // Lex source text.
283 PP.EnterMainSourceFile();
284 PP.LexTokensUntilEOF();
286 return Callbacks->Marks;
289 PragmaOpenCLExtensionCallbacks::CallbackParameters
290 PragmaOpenCLExtensionCall(const char *SourceText) {
291 LangOptions OpenCLLangOpts;
292 OpenCLLangOpts.OpenCL = 1;
294 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
295 llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
296 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
298 TrivialModuleLoader ModLoader;
299 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
300 Diags, OpenCLLangOpts, Target.get());
302 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags,
303 OpenCLLangOpts, SourceMgr, HeaderInfo, ModLoader,
304 /*IILookup =*/nullptr,
305 /*OwnsHeaderSearch =*/false);
306 PP.Initialize(*Target);
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);
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));
321 // Lex source text.
322 PP.EnterMainSourceFile();
323 PP.LexTokensUntilEOF();
325 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
326 Callbacks->Name,
327 Callbacks->State
329 return RetVal;
333 TEST_F(PPCallbacksTest, UserFileCharacteristics) {
334 const char *Source = "#include \"quoted.h\"\n";
336 SrcMgr::CharacteristicKind Kind =
337 InclusionDirectiveCharacteristicKind(Source, "/quoted.h", false);
339 ASSERT_EQ(SrcMgr::CharacteristicKind::C_User, Kind);
342 TEST_F(PPCallbacksTest, QuotedFilename) {
343 const char* Source =
344 "#include \"quoted.h\"\n";
346 CharSourceRange Range =
347 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
349 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
352 TEST_F(PPCallbacksTest, AngledFilename) {
353 const char* Source =
354 "#include <angled.h>\n";
356 CharSourceRange Range =
357 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
359 ASSERT_EQ("<angled.h>", GetSourceString(Range));
362 TEST_F(PPCallbacksTest, QuotedInMacro) {
363 const char* Source =
364 "#define MACRO_QUOTED \"quoted.h\"\n"
365 "#include MACRO_QUOTED\n";
367 CharSourceRange Range =
368 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
370 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
373 TEST_F(PPCallbacksTest, AngledInMacro) {
374 const char* Source =
375 "#define MACRO_ANGLED <angled.h>\n"
376 "#include MACRO_ANGLED\n";
378 CharSourceRange Range =
379 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
381 ASSERT_EQ("<angled.h>", GetSourceString(Range));
384 TEST_F(PPCallbacksTest, StringizedMacroArgument) {
385 const char* Source =
386 "#define MACRO_STRINGIZED(x) #x\n"
387 "#include MACRO_STRINGIZED(quoted.h)\n";
389 CharSourceRange Range =
390 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
392 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
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";
401 CharSourceRange Range =
402 InclusionDirectiveFilenameRange(Source, "/angled.h", false);
404 ASSERT_EQ("<angled.h>", GetSourceString(Range));
407 TEST_F(PPCallbacksTest, TrigraphFilename) {
408 const char* Source =
409 "#include \"tri\?\?-graph.h\"\n";
411 CharSourceRange Range =
412 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
414 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
417 TEST_F(PPCallbacksTest, TrigraphInMacro) {
418 const char* Source =
419 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
420 "#include MACRO_TRIGRAPH\n";
422 CharSourceRange Range =
423 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
425 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
428 TEST_F(PPCallbacksTest, FileNotFoundSkipped) {
429 const char *SourceText = "#include \"skipped.h\"\n";
431 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
432 llvm::MemoryBuffer::getMemBuffer(SourceText);
433 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
435 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
436 Diags, LangOpts, Target.get());
437 TrivialModuleLoader ModLoader;
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);
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";
456 auto *Callbacks = new FileNotFoundCallbacks;
457 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
459 // Lex source text.
460 PP.EnterMainSourceFile();
461 PP.LexTokensUntilEOF();
463 ASSERT_EQ(1u, Callbacks->NumCalls);
464 ASSERT_EQ(0u, DiagConsumer->getNumErrors());
467 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
468 const char* Source =
469 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
471 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
472 PragmaOpenCLExtensionCall(Source);
474 ASSERT_EQ("cl_khr_fp64", Parameters.Name);
475 unsigned ExpectedState = 1;
476 ASSERT_EQ(ExpectedState, Parameters.State);
479 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
480 const char* Source =
481 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
483 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
484 PragmaOpenCLExtensionCall(Source);
486 ASSERT_EQ("cl_khr_fp16", Parameters.Name);
487 unsigned ExpectedState = 0;
488 ASSERT_EQ(ExpectedState, Parameters.State);
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";
498 auto Marks = PragmaMarkCall(Source);
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);
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");
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");
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");
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");
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");
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)");
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)");
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");
575 } // namespace