1//===- unittests/Lex/PPDependencyDirectivesTest.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/DependencyDirectivesScanner.h"
17#include "clang/Lex/HeaderSearch.h"
18#include "clang/Lex/HeaderSearchOptions.h"
19#include "clang/Lex/ModuleLoader.h"
20#include "clang/Lex/Preprocessor.h"
21#include "clang/Lex/PreprocessorOptions.h"
22#include "llvm/Testing/Support/Error.h"
23#include "gtest/gtest.h"
24#include <optional>
25
26using namespace clang;
27
28namespace {
29
30// The test fixture.
31class PPDependencyDirectivesTest : public ::testing::Test {
32protected:
33 PPDependencyDirectivesTest()
34 : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
35 Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
36 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
37 TargetOpts->Triple = "x86_64-apple-macos12";
38 Target = TargetInfo::CreateTargetInfo(Diags, Opts&: *TargetOpts);
39 }
40
41 FileSystemOptions FileMgrOpts;
42 FileManager FileMgr;
43 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
44 DiagnosticOptions DiagOpts;
45 DiagnosticsEngine Diags;
46 SourceManager SourceMgr;
47 LangOptions LangOpts;
48 std::shared_ptr<TargetOptions> TargetOpts;
49 IntrusiveRefCntPtr<TargetInfo> Target;
50};
51
52class IncludeCollector : public PPCallbacks {
53public:
54 Preprocessor &PP;
55 SmallVectorImpl<StringRef> &IncludedFiles;
56
57 IncludeCollector(Preprocessor &PP, SmallVectorImpl<StringRef> &IncludedFiles)
58 : PP(PP), IncludedFiles(IncludedFiles) {}
59
60 void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
61 SrcMgr::CharacteristicKind FileType, FileID PrevFID,
62 SourceLocation Loc) override {
63 if (Reason != LexedFileChangeReason::EnterFile)
64 return;
65 if (FID == PP.getPredefinesFileID())
66 return;
67 StringRef Filename =
68 PP.getSourceManager().getSLocEntry(FID).getFile().getName();
69 IncludedFiles.push_back(Elt: Filename);
70 }
71};
72
73TEST_F(PPDependencyDirectivesTest, MacroGuard) {
74 // "head1.h" has a macro guard and should only be included once.
75 // "head2.h" and "head3.h" have tokens following the macro check, they should
76 // be included multiple times.
77
78 auto VFS = new llvm::vfs::InMemoryFileSystem();
79 VFS->addFile(
80 Path: "head1.h", ModificationTime: 0,
81 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "#ifndef H1_H\n#define H1_H\n#endif\n"));
82 VFS->addFile(
83 Path: "head2.h", ModificationTime: 0,
84 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "#ifndef H2_H\n#define H2_H\n#endif\n\n"
85 "extern int foo;\n"));
86 VFS->addFile(Path: "head3.h", ModificationTime: 0,
87 Buffer: llvm::MemoryBuffer::getMemBuffer(
88 InputData: "#ifndef H3_H\n#define H3_H\n#endif\n\n"
89 "#ifdef SOMEMAC\nextern int foo;\n#endif\n"));
90 VFS->addFile(Path: "main.c", ModificationTime: 0,
91 Buffer: llvm::MemoryBuffer::getMemBuffer(
92 InputData: "#include \"head1.h\"\n#include \"head1.h\"\n"
93 "#include \"head2.h\"\n#include \"head2.h\"\n"
94 "#include \"head3.h\"\n#include \"head3.h\"\n"));
95 FileMgr.setVirtualFileSystem(VFS);
96
97 OptionalFileEntryRef FE;
98 ASSERT_THAT_ERROR(FileMgr.getFileRef("main.c").moveInto(FE),
99 llvm::Succeeded());
100 SourceMgr.setMainFileID(
101 SourceMgr.createFileID(SourceFile: *FE, IncludePos: SourceLocation(), FileCharacter: SrcMgr::C_User));
102
103 struct DepDirectives {
104 SmallVector<dependency_directives_scan::Token> Tokens;
105 SmallVector<dependency_directives_scan::Directive> Directives;
106 };
107
108 class TestDependencyDirectivesGetter : public DependencyDirectivesGetter {
109 FileManager &FileMgr;
110 SmallVector<std::unique_ptr<DepDirectives>> DepDirectivesObjects;
111
112 public:
113 TestDependencyDirectivesGetter(FileManager &FileMgr) : FileMgr(FileMgr) {}
114
115 std::unique_ptr<DependencyDirectivesGetter>
116 cloneFor(FileManager &FileMgr) override {
117 return std::make_unique<TestDependencyDirectivesGetter>(args&: FileMgr);
118 }
119
120 std::optional<ArrayRef<dependency_directives_scan::Directive>>
121 operator()(FileEntryRef File) override {
122 DepDirectivesObjects.push_back(Elt: std::make_unique<DepDirectives>());
123 StringRef Input = (*FileMgr.getBufferForFile(Entry: File))->getBuffer();
124 bool Err = scanSourceForDependencyDirectives(
125 Input, Tokens&: DepDirectivesObjects.back()->Tokens,
126 Directives&: DepDirectivesObjects.back()->Directives);
127 EXPECT_FALSE(Err);
128 return DepDirectivesObjects.back()->Directives;
129 }
130 };
131 TestDependencyDirectivesGetter GetDependencyDirectives(FileMgr);
132
133 PreprocessorOptions PPOpts;
134 HeaderSearchOptions HSOpts;
135 TrivialModuleLoader ModLoader;
136 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
137 Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
138 /*IILookup =*/nullptr,
139 /*OwnsHeaderSearch =*/false);
140 PP.Initialize(Target: *Target);
141
142 PP.setDependencyDirectivesGetter(GetDependencyDirectives);
143
144 SmallVector<StringRef> IncludedFiles;
145 PP.addPPCallbacks(C: std::make_unique<IncludeCollector>(args&: PP, args&: IncludedFiles));
146 PP.EnterMainSourceFile();
147 PP.LexTokensUntilEOF();
148
149 SmallVector<std::string> IncludedFilesSlash;
150 for (StringRef IncludedFile : IncludedFiles)
151 IncludedFilesSlash.push_back(
152 Elt: llvm::sys::path::convert_to_slash(path: IncludedFile));
153 SmallVector<std::string> ExpectedIncludes{
154 "main.c", "./head1.h", "./head2.h", "./head2.h", "./head3.h", "./head3.h",
155 };
156 EXPECT_EQ(IncludedFilesSlash, ExpectedIncludes);
157}
158
159} // anonymous namespace
160

Provided by KDAB

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

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