2022-09-05 14:28:32 -07:00
|
|
|
//===- unittests/Lex/PPDependencyDirectivesTest.cpp -------------------------=//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/Basic/Diagnostic.h"
|
|
|
|
#include "clang/Basic/DiagnosticOptions.h"
|
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
#include "clang/Basic/LangOptions.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "clang/Basic/TargetInfo.h"
|
|
|
|
#include "clang/Basic/TargetOptions.h"
|
|
|
|
#include "clang/Lex/DependencyDirectivesScanner.h"
|
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
|
|
|
#include "clang/Lex/HeaderSearchOptions.h"
|
|
|
|
#include "clang/Lex/ModuleLoader.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
|
|
|
#include "clang/Lex/PreprocessorOptions.h"
|
|
|
|
#include "llvm/Testing/Support/Error.h"
|
|
|
|
#include "gtest/gtest.h"
|
2023-01-14 11:07:21 -08:00
|
|
|
#include <optional>
|
2022-09-05 14:28:32 -07:00
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// The test fixture.
|
|
|
|
class PPDependencyDirectivesTest : public ::testing::Test {
|
|
|
|
protected:
|
|
|
|
PPDependencyDirectivesTest()
|
|
|
|
: FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
|
|
|
|
Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
|
|
|
|
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
|
|
|
|
TargetOpts->Triple = "x86_64-apple-macos12";
|
|
|
|
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSystemOptions FileMgrOpts;
|
|
|
|
FileManager FileMgr;
|
|
|
|
IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
|
|
|
|
DiagnosticsEngine Diags;
|
|
|
|
SourceManager SourceMgr;
|
|
|
|
LangOptions LangOpts;
|
|
|
|
std::shared_ptr<TargetOptions> TargetOpts;
|
|
|
|
IntrusiveRefCntPtr<TargetInfo> Target;
|
|
|
|
};
|
|
|
|
|
|
|
|
class IncludeCollector : public PPCallbacks {
|
|
|
|
public:
|
|
|
|
Preprocessor &PP;
|
|
|
|
SmallVectorImpl<StringRef> &IncludedFiles;
|
|
|
|
|
|
|
|
IncludeCollector(Preprocessor &PP, SmallVectorImpl<StringRef> &IncludedFiles)
|
|
|
|
: PP(PP), IncludedFiles(IncludedFiles) {}
|
|
|
|
|
|
|
|
void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
|
|
|
|
SrcMgr::CharacteristicKind FileType, FileID PrevFID,
|
|
|
|
SourceLocation Loc) override {
|
|
|
|
if (Reason != LexedFileChangeReason::EnterFile)
|
|
|
|
return;
|
|
|
|
if (FID == PP.getPredefinesFileID())
|
|
|
|
return;
|
|
|
|
StringRef Filename =
|
|
|
|
PP.getSourceManager().getSLocEntry(FID).getFile().getName();
|
|
|
|
IncludedFiles.push_back(Filename);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(PPDependencyDirectivesTest, MacroGuard) {
|
|
|
|
// "head1.h" has a macro guard and should only be included once.
|
|
|
|
// "head2.h" and "head3.h" have tokens following the macro check, they should
|
|
|
|
// be included multiple times.
|
|
|
|
|
|
|
|
auto VFS = new llvm::vfs::InMemoryFileSystem();
|
|
|
|
VFS->addFile(
|
|
|
|
"head1.h", 0,
|
|
|
|
llvm::MemoryBuffer::getMemBuffer("#ifndef H1_H\n#define H1_H\n#endif\n"));
|
|
|
|
VFS->addFile(
|
|
|
|
"head2.h", 0,
|
|
|
|
llvm::MemoryBuffer::getMemBuffer("#ifndef H2_H\n#define H2_H\n#endif\n\n"
|
|
|
|
"extern int foo;\n"));
|
|
|
|
VFS->addFile("head3.h", 0,
|
|
|
|
llvm::MemoryBuffer::getMemBuffer(
|
|
|
|
"#ifndef H3_H\n#define H3_H\n#endif\n\n"
|
|
|
|
"#ifdef SOMEMAC\nextern int foo;\n#endif\n"));
|
|
|
|
VFS->addFile("main.c", 0,
|
|
|
|
llvm::MemoryBuffer::getMemBuffer(
|
|
|
|
"#include \"head1.h\"\n#include \"head1.h\"\n"
|
|
|
|
"#include \"head2.h\"\n#include \"head2.h\"\n"
|
|
|
|
"#include \"head3.h\"\n#include \"head3.h\"\n"));
|
|
|
|
FileMgr.setVirtualFileSystem(VFS);
|
|
|
|
|
2022-12-20 00:15:11 +01:00
|
|
|
OptionalFileEntryRef FE;
|
2022-09-05 14:28:32 -07:00
|
|
|
ASSERT_THAT_ERROR(FileMgr.getFileRef("main.c").moveInto(FE),
|
|
|
|
llvm::Succeeded());
|
|
|
|
SourceMgr.setMainFileID(
|
|
|
|
SourceMgr.createFileID(*FE, SourceLocation(), SrcMgr::C_User));
|
|
|
|
|
|
|
|
struct DepDirectives {
|
|
|
|
SmallVector<dependency_directives_scan::Token> Tokens;
|
|
|
|
SmallVector<dependency_directives_scan::Directive> Directives;
|
|
|
|
};
|
|
|
|
SmallVector<std::unique_ptr<DepDirectives>> DepDirectivesObjects;
|
|
|
|
|
|
|
|
auto getDependencyDirectives = [&](FileEntryRef File)
|
2023-01-14 12:31:01 -08:00
|
|
|
-> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
|
2022-09-05 14:28:32 -07:00
|
|
|
DepDirectivesObjects.push_back(std::make_unique<DepDirectives>());
|
|
|
|
StringRef Input = (*FileMgr.getBufferForFile(File))->getBuffer();
|
|
|
|
bool Err = scanSourceForDependencyDirectives(
|
|
|
|
Input, DepDirectivesObjects.back()->Tokens,
|
2024-06-05 11:42:13 -07:00
|
|
|
DepDirectivesObjects.back()->Directives);
|
2022-09-05 14:28:32 -07:00
|
|
|
EXPECT_FALSE(Err);
|
2023-01-06 16:56:23 +01:00
|
|
|
return llvm::ArrayRef(DepDirectivesObjects.back()->Directives);
|
2022-09-05 14:28:32 -07:00
|
|
|
};
|
|
|
|
|
2025-04-04 10:11:14 -07:00
|
|
|
PreprocessorOptions PPOpts;
|
|
|
|
PPOpts.DependencyDirectivesForFile = [&](FileEntryRef File)
|
2024-04-09 11:28:24 -07:00
|
|
|
-> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
|
|
|
|
return getDependencyDirectives(File);
|
|
|
|
};
|
|
|
|
|
2025-03-25 12:14:06 -07:00
|
|
|
HeaderSearchOptions HSOpts;
|
2022-09-05 14:28:32 -07:00
|
|
|
TrivialModuleLoader ModLoader;
|
2025-03-25 12:14:06 -07:00
|
|
|
HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
|
2022-09-05 14:28:32 -07:00
|
|
|
Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
|
|
|
|
/*IILookup =*/nullptr,
|
|
|
|
/*OwnsHeaderSearch =*/false);
|
|
|
|
PP.Initialize(*Target);
|
|
|
|
|
|
|
|
SmallVector<StringRef> IncludedFiles;
|
|
|
|
PP.addPPCallbacks(std::make_unique<IncludeCollector>(PP, IncludedFiles));
|
|
|
|
PP.EnterMainSourceFile();
|
2023-08-21 12:41:56 +02:00
|
|
|
PP.LexTokensUntilEOF();
|
2022-09-05 14:28:32 -07:00
|
|
|
|
2023-09-08 13:13:20 -07:00
|
|
|
SmallVector<std::string> IncludedFilesSlash;
|
|
|
|
for (StringRef IncludedFile : IncludedFiles)
|
|
|
|
IncludedFilesSlash.push_back(
|
|
|
|
llvm::sys::path::convert_to_slash(IncludedFile));
|
|
|
|
SmallVector<std::string> ExpectedIncludes{
|
2022-09-05 14:28:32 -07:00
|
|
|
"main.c", "./head1.h", "./head2.h", "./head2.h", "./head3.h", "./head3.h",
|
|
|
|
};
|
2023-09-08 13:13:20 -07:00
|
|
|
EXPECT_EQ(IncludedFilesSlash, ExpectedIncludes);
|
2022-09-05 14:28:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|