1//===- unittests/Lex/NoTrivialPPDirectiveTracerTest.cpp -------------------===//
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/Basic/Diagnostic.h"
10#include "clang/Basic/DiagnosticOptions.h"
11#include "clang/Basic/FileManager.h"
12#include "clang/Basic/LangOptions.h"
13#include "clang/Basic/SourceManager.h"
14#include "clang/Basic/TargetInfo.h"
15#include "clang/Basic/TargetOptions.h"
16#include "clang/Lex/HeaderSearch.h"
17#include "clang/Lex/HeaderSearchOptions.h"
18#include "clang/Lex/ModuleLoader.h"
19#include "clang/Lex/Preprocessor.h"
20#include "clang/Lex/PreprocessorOptions.h"
21#include "gtest/gtest.h"
22#include <cstddef>
23#include <initializer_list>
24
25using namespace clang;
26
27namespace {
28class NoTrivialPPDirectiveTracerTest : public ::testing::Test {
29protected:
30 NoTrivialPPDirectiveTracerTest()
31 : VFS(llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>()),
32 FileMgr(FileMgrOpts, VFS), DiagID(new DiagnosticIDs()),
33 Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
34 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
35 TargetOpts->Triple = "x86_64-unknown-linux-gnu";
36 Target = TargetInfo::CreateTargetInfo(Diags, Opts&: *TargetOpts);
37 }
38
39 void addFile(const char *source, StringRef Filename) {
40 VFS->addFile(Path: Filename, ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: source),
41 /*User=*/std::nullopt,
42 /*Group=*/std::nullopt,
43 Type: llvm::sys::fs::file_type::regular_file);
44 }
45
46 std::unique_ptr<Preprocessor> getPreprocessor(const char *source,
47 Language Lang) {
48 std::unique_ptr<llvm::MemoryBuffer> Buf =
49 llvm::MemoryBuffer::getMemBuffer(InputData: source);
50 SourceMgr.setMainFileID(SourceMgr.createFileID(Buffer: std::move(Buf)));
51
52 std::vector<std::string> Includes;
53 LangOptions::setLangDefaults(Opts&: LangOpts, Lang, T: Target->getTriple(), Includes,
54 LangStd: LangStandard::lang_cxx20);
55 LangOpts.CPlusPlusModules = true;
56 if (Lang != Language::CXX) {
57 LangOpts.Modules = true;
58 LangOpts.ImplicitModules = true;
59 }
60
61 HeaderInfo.emplace(args&: HSOpts, args&: SourceMgr, args&: Diags, args&: LangOpts, args: Target.get());
62
63 auto DE = FileMgr.getOptionalDirectoryRef(DirName: ".");
64 assert(DE);
65 auto DL = DirectoryLookup(*DE, SrcMgr::C_User, /*isFramework=*/false);
66 HeaderInfo->AddSearchPath(dir: DL, /*isAngled=*/false);
67
68 return std::make_unique<Preprocessor>(args&: PPOpts, args&: Diags, args&: LangOpts, args&: SourceMgr,
69 args&: *HeaderInfo, args&: ModLoader,
70 /*IILookup=*/args: nullptr,
71 /*OwnsHeaderSearch=*/args: false);
72 }
73
74 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
75 FileSystemOptions FileMgrOpts;
76 FileManager FileMgr;
77 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
78 DiagnosticOptions DiagOpts;
79 DiagnosticsEngine Diags;
80 SourceManager SourceMgr;
81 std::shared_ptr<TargetOptions> TargetOpts;
82 IntrusiveRefCntPtr<TargetInfo> Target;
83 LangOptions LangOpts;
84 TrivialModuleLoader ModLoader;
85 HeaderSearchOptions HSOpts;
86 std::optional<HeaderSearch> HeaderInfo;
87 PreprocessorOptions PPOpts;
88};
89
90TEST_F(NoTrivialPPDirectiveTracerTest, TrivialDirective) {
91 const char *source = R"(
92 #line 7
93 # 1 __FILE__ 1 3
94 #ident "$Header:$"
95 #pragma comment(lib, "msvcrt.lib")
96 #pragma mark LLVM's world
97 #pragma detect_mismatch("test", "1")
98 #pragma clang __debug dump Test
99 #pragma message "test"
100 #pragma GCC warning "Foo"
101 #pragma GCC error "Foo"
102 #pragma gcc diagnostic push
103 #pragma gcc diagnostic pop
104 #pragma GCC diagnostic ignored "-Wframe-larger-than"
105 #pragma OPENCL EXTENSION __cl_clang_variadic_functions : enable
106 #pragma warning(push)
107 #pragma warning(pop)
108 #pragma execution_character_set(push, "UTF-8")
109 #pragma execution_character_set(pop)
110 #pragma clang assume_nonnull begin
111 #pragma clang assume_nonnull end
112 int foo;
113 )";
114 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
115 PP->Initialize(Target: *Target);
116 PP->EnterMainSourceFile();
117 Token Tok;
118 PP->Lex(Result&: Tok);
119 EXPECT_FALSE(PP->hasSeenNoTrivialPPDirective());
120}
121
122TEST_F(NoTrivialPPDirectiveTracerTest, IncludeDirective) {
123 const char *source = R"(
124 #include "header.h"
125 int foo;
126 )";
127 const char *header = R"(
128 #ifndef HEADER_H
129 #define HEADER_H
130 #endif // HEADER_H
131 )";
132 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
133 addFile(source: header, Filename: "header.h");
134 PP->Initialize(Target: *Target);
135 PP->EnterMainSourceFile();
136 Token Tok;
137 PP->Lex(Result&: Tok);
138 EXPECT_TRUE(PP->hasSeenNoTrivialPPDirective());
139}
140
141TEST_F(NoTrivialPPDirectiveTracerTest, DefineDirective) {
142 const char *source = R"(
143 #define FOO
144 int foo;
145 )";
146 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
147 PP->Initialize(Target: *Target);
148 PP->EnterMainSourceFile();
149 Token Tok;
150 PP->Lex(Result&: Tok);
151 EXPECT_TRUE(PP->hasSeenNoTrivialPPDirective());
152}
153
154TEST_F(NoTrivialPPDirectiveTracerTest, UnDefineDirective) {
155 const char *source = R"(
156 #undef FOO
157 int foo;
158 )";
159 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
160 PP->Initialize(Target: *Target);
161 PP->setPredefines("#define FOO");
162 PP->EnterMainSourceFile();
163 Token Tok;
164 PP->Lex(Result&: Tok);
165 EXPECT_TRUE(PP->hasSeenNoTrivialPPDirective());
166}
167
168TEST_F(NoTrivialPPDirectiveTracerTest, IfDefinedDirective) {
169 const char *source = R"(
170 #if defined(FOO)
171 #endif
172 int foo;
173 )";
174 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Lang: Language::CXX);
175 PP->Initialize(Target: *Target);
176 PP->setPredefines("#define FOO");
177 PP->EnterMainSourceFile();
178 Token Tok;
179 PP->Lex(Result&: Tok);
180 EXPECT_TRUE(PP->hasSeenNoTrivialPPDirective());
181}
182
183} // namespace
184

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