183 lines · cpp
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-exception6//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),33 Diags(DiagnosticIDs::create(), DiagOpts, new IgnoringDiagConsumer()),34 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {35 TargetOpts->Triple = "x86_64-unknown-linux-gnu";36 Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);37 }38 39 void addFile(const char *source, StringRef Filename) {40 VFS->addFile(Filename, 0, llvm::MemoryBuffer::getMemBuffer(source),41 /*User=*/std::nullopt,42 /*Group=*/std::nullopt,43 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(source);50 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));51 52 std::vector<std::string> Includes;53 LangOptions::setLangDefaults(LangOpts, Lang, Target->getTriple(), Includes,54 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(HSOpts, SourceMgr, Diags, LangOpts, Target.get());62 63 auto DE = FileMgr.getOptionalDirectoryRef(".");64 assert(DE);65 auto DL = DirectoryLookup(*DE, SrcMgr::C_User, /*isFramework=*/false);66 HeaderInfo->AddSearchPath(DL, /*isAngled=*/false);67 68 return std::make_unique<Preprocessor>(PPOpts, Diags, LangOpts, SourceMgr,69 *HeaderInfo, ModLoader,70 /*IILookup=*/nullptr,71 /*OwnsHeaderSearch=*/false);72 }73 74 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;75 FileSystemOptions FileMgrOpts;76 FileManager FileMgr;77 DiagnosticOptions DiagOpts;78 DiagnosticsEngine Diags;79 SourceManager SourceMgr;80 std::shared_ptr<TargetOptions> TargetOpts;81 IntrusiveRefCntPtr<TargetInfo> Target;82 LangOptions LangOpts;83 TrivialModuleLoader ModLoader;84 HeaderSearchOptions HSOpts;85 std::optional<HeaderSearch> HeaderInfo;86 PreprocessorOptions PPOpts;87};88 89TEST_F(NoTrivialPPDirectiveTracerTest, TrivialDirective) {90 const char *source = R"(91 #line 792 # 1 __FILE__ 1 393 #ident "$Header:$"94 #pragma comment(lib, "msvcrt.lib")95 #pragma mark LLVM's world96 #pragma detect_mismatch("test", "1")97 #pragma clang __debug dump Test98 #pragma message "test"99 #pragma GCC warning "Foo"100 #pragma GCC error "Foo"101 #pragma gcc diagnostic push102 #pragma gcc diagnostic pop103 #pragma GCC diagnostic ignored "-Wframe-larger-than"104 #pragma OPENCL EXTENSION __cl_clang_variadic_functions : enable105 #pragma warning(push)106 #pragma warning(pop)107 #pragma execution_character_set(push, "UTF-8")108 #pragma execution_character_set(pop)109 #pragma clang assume_nonnull begin110 #pragma clang assume_nonnull end111 int foo;112 )";113 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);114 PP->Initialize(*Target);115 PP->EnterMainSourceFile();116 Token Tok;117 PP->Lex(Tok);118 EXPECT_FALSE(PP->hasSeenNoTrivialPPDirective());119}120 121TEST_F(NoTrivialPPDirectiveTracerTest, IncludeDirective) {122 const char *source = R"(123 #include "header.h"124 int foo;125 )";126 const char *header = R"(127 #ifndef HEADER_H128 #define HEADER_H129 #endif // HEADER_H130 )";131 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);132 addFile(header, "header.h");133 PP->Initialize(*Target);134 PP->EnterMainSourceFile();135 Token Tok;136 PP->Lex(Tok);137 EXPECT_TRUE(PP->hasSeenNoTrivialPPDirective());138}139 140TEST_F(NoTrivialPPDirectiveTracerTest, DefineDirective) {141 const char *source = R"(142 #define FOO143 int foo;144 )";145 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);146 PP->Initialize(*Target);147 PP->EnterMainSourceFile();148 Token Tok;149 PP->Lex(Tok);150 EXPECT_TRUE(PP->hasSeenNoTrivialPPDirective());151}152 153TEST_F(NoTrivialPPDirectiveTracerTest, UnDefineDirective) {154 const char *source = R"(155 #undef FOO156 int foo;157 )";158 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);159 PP->Initialize(*Target);160 PP->setPredefines("#define FOO");161 PP->EnterMainSourceFile();162 Token Tok;163 PP->Lex(Tok);164 EXPECT_TRUE(PP->hasSeenNoTrivialPPDirective());165}166 167TEST_F(NoTrivialPPDirectiveTracerTest, IfDefinedDirective) {168 const char *source = R"(169 #if defined(FOO)170 #endif171 int foo;172 )";173 std::unique_ptr<Preprocessor> PP = getPreprocessor(source, Language::CXX);174 PP->Initialize(*Target);175 PP->setPredefines("#define FOO");176 PP->EnterMainSourceFile();177 Token Tok;178 PP->Lex(Tok);179 EXPECT_TRUE(PP->hasSeenNoTrivialPPDirective());180}181 182} // namespace183