Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@ -0,0 +1,19 @@
set(LLVM_LINK_COMPONENTS
Support
)
add_clang_unittest(LexTests
HeaderMapTest.cpp
LexerTest.cpp
PPCallbacksTest.cpp
PPConditionalDirectiveRecordTest.cpp
)
target_link_libraries(LexTests
PRIVATE
clangAST
clangBasic
clangLex
clangParse
clangSema
)

View File

@ -0,0 +1,258 @@
//===- unittests/Lex/HeaderMapTest.cpp - HeaderMap tests ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===--------------------------------------------------------------===//
#include "clang/Basic/CharInfo.h"
#include "clang/Lex/HeaderMap.h"
#include "clang/Lex/HeaderMapTypes.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/SwapByteOrder.h"
#include "gtest/gtest.h"
#include <cassert>
#include <type_traits>
using namespace clang;
using namespace llvm;
namespace {
// Lay out a header file for testing.
template <unsigned NumBuckets, unsigned NumBytes> struct MapFile {
HMapHeader Header;
HMapBucket Buckets[NumBuckets];
unsigned char Bytes[NumBytes];
void init() {
memset(this, 0, sizeof(MapFile));
Header.Magic = HMAP_HeaderMagicNumber;
Header.Version = HMAP_HeaderVersion;
Header.NumBuckets = NumBuckets;
Header.StringsOffset = sizeof(Header) + sizeof(Buckets);
}
void swapBytes() {
using llvm::sys::getSwappedBytes;
Header.Magic = getSwappedBytes(Header.Magic);
Header.Version = getSwappedBytes(Header.Version);
Header.NumBuckets = getSwappedBytes(Header.NumBuckets);
Header.StringsOffset = getSwappedBytes(Header.StringsOffset);
}
std::unique_ptr<const MemoryBuffer> getBuffer() const {
return MemoryBuffer::getMemBuffer(
StringRef(reinterpret_cast<const char *>(this), sizeof(MapFile)),
"header",
/* RequresNullTerminator */ false);
}
};
// The header map hash function.
static inline unsigned getHash(StringRef Str) {
unsigned Result = 0;
for (char C : Str)
Result += toLowercase(C) * 13;
return Result;
}
template <class FileTy> struct FileMaker {
FileTy &File;
unsigned SI = 1;
unsigned BI = 0;
FileMaker(FileTy &File) : File(File) {}
unsigned addString(StringRef S) {
assert(SI + S.size() + 1 <= sizeof(File.Bytes));
std::copy(S.begin(), S.end(), File.Bytes + SI);
auto OldSI = SI;
SI += S.size() + 1;
return OldSI;
}
void addBucket(unsigned Hash, unsigned Key, unsigned Prefix, unsigned Suffix) {
assert(!(File.Header.NumBuckets & (File.Header.NumBuckets - 1)));
unsigned I = Hash & (File.Header.NumBuckets - 1);
do {
if (!File.Buckets[I].Key) {
File.Buckets[I].Key = Key;
File.Buckets[I].Prefix = Prefix;
File.Buckets[I].Suffix = Suffix;
++File.Header.NumEntries;
return;
}
++I;
I &= File.Header.NumBuckets - 1;
} while (I != (Hash & (File.Header.NumBuckets - 1)));
llvm_unreachable("no empty buckets");
}
};
TEST(HeaderMapTest, checkHeaderEmpty) {
bool NeedsSwap;
ASSERT_FALSE(HeaderMapImpl::checkHeader(
*MemoryBuffer::getMemBufferCopy("", "empty"), NeedsSwap));
ASSERT_FALSE(HeaderMapImpl::checkHeader(
*MemoryBuffer::getMemBufferCopy("", "empty"), NeedsSwap));
}
TEST(HeaderMapTest, checkHeaderMagic) {
MapFile<1, 1> File;
File.init();
File.Header.Magic = 0;
bool NeedsSwap;
ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
}
TEST(HeaderMapTest, checkHeaderReserved) {
MapFile<1, 1> File;
File.init();
File.Header.Reserved = 1;
bool NeedsSwap;
ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
}
TEST(HeaderMapTest, checkHeaderVersion) {
MapFile<1, 1> File;
File.init();
++File.Header.Version;
bool NeedsSwap;
ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
}
TEST(HeaderMapTest, checkHeaderValidButEmpty) {
MapFile<1, 1> File;
File.init();
bool NeedsSwap;
ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
ASSERT_FALSE(NeedsSwap);
File.swapBytes();
ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
ASSERT_TRUE(NeedsSwap);
}
TEST(HeaderMapTest, checkHeader3Buckets) {
MapFile<3, 1> File;
ASSERT_EQ(3 * sizeof(HMapBucket), sizeof(File.Buckets));
File.init();
bool NeedsSwap;
ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
}
TEST(HeaderMapTest, checkHeader0Buckets) {
// Create with 1 bucket to avoid 0-sized arrays.
MapFile<1, 1> File;
File.init();
File.Header.NumBuckets = 0;
bool NeedsSwap;
ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
}
TEST(HeaderMapTest, checkHeaderNotEnoughBuckets) {
MapFile<1, 1> File;
File.init();
File.Header.NumBuckets = 8;
bool NeedsSwap;
ASSERT_FALSE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
}
TEST(HeaderMapTest, lookupFilename) {
typedef MapFile<2, 7> FileTy;
FileTy File;
File.init();
FileMaker<FileTy> Maker(File);
auto a = Maker.addString("a");
auto b = Maker.addString("b");
auto c = Maker.addString("c");
Maker.addBucket(getHash("a"), a, b, c);
bool NeedsSwap;
ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
ASSERT_FALSE(NeedsSwap);
HeaderMapImpl Map(File.getBuffer(), NeedsSwap);
SmallString<8> DestPath;
ASSERT_EQ("bc", Map.lookupFilename("a", DestPath));
}
template <class FileTy, class PaddingTy> struct PaddedFile {
FileTy File;
PaddingTy Padding;
};
TEST(HeaderMapTest, lookupFilenameTruncatedSuffix) {
typedef MapFile<2, 64 - sizeof(HMapHeader) - 2 * sizeof(HMapBucket)> FileTy;
static_assert(std::is_standard_layout<FileTy>::value,
"Expected standard layout");
static_assert(sizeof(FileTy) == 64, "check the math");
PaddedFile<FileTy, uint64_t> P;
auto &File = P.File;
auto &Padding = P.Padding;
File.init();
FileMaker<FileTy> Maker(File);
auto a = Maker.addString("a");
auto b = Maker.addString("b");
auto c = Maker.addString("c");
Maker.addBucket(getHash("a"), a, b, c);
// Add 'x' characters to cause an overflow into Padding.
ASSERT_EQ('c', File.Bytes[5]);
for (unsigned I = 6; I < sizeof(File.Bytes); ++I) {
ASSERT_EQ(0, File.Bytes[I]);
File.Bytes[I] = 'x';
}
Padding = 0xffffffff; // Padding won't stop it either.
bool NeedsSwap;
ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
ASSERT_FALSE(NeedsSwap);
HeaderMapImpl Map(File.getBuffer(), NeedsSwap);
// The string for "c" runs to the end of File. Check that the suffix
// ("cxxxx...") is detected as truncated, and an empty string is returned.
SmallString<24> DestPath;
ASSERT_EQ("", Map.lookupFilename("a", DestPath));
}
TEST(HeaderMapTest, lookupFilenameTruncatedPrefix) {
typedef MapFile<2, 64 - sizeof(HMapHeader) - 2 * sizeof(HMapBucket)> FileTy;
static_assert(std::is_standard_layout<FileTy>::value,
"Expected standard layout");
static_assert(sizeof(FileTy) == 64, "check the math");
PaddedFile<FileTy, uint64_t> P;
auto &File = P.File;
auto &Padding = P.Padding;
File.init();
FileMaker<FileTy> Maker(File);
auto a = Maker.addString("a");
auto c = Maker.addString("c");
auto b = Maker.addString("b"); // Store the prefix last.
Maker.addBucket(getHash("a"), a, b, c);
// Add 'x' characters to cause an overflow into Padding.
ASSERT_EQ('b', File.Bytes[5]);
for (unsigned I = 6; I < sizeof(File.Bytes); ++I) {
ASSERT_EQ(0, File.Bytes[I]);
File.Bytes[I] = 'x';
}
Padding = 0xffffffff; // Padding won't stop it either.
bool NeedsSwap;
ASSERT_TRUE(HeaderMapImpl::checkHeader(*File.getBuffer(), NeedsSwap));
ASSERT_FALSE(NeedsSwap);
HeaderMapImpl Map(File.getBuffer(), NeedsSwap);
// The string for "b" runs to the end of File. Check that the prefix
// ("bxxxx...") is detected as truncated, and an empty string is returned.
SmallString<24> DestPath;
ASSERT_EQ("", Map.lookupFilename("a", DestPath));
}
} // end namespace

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,335 @@
//===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks tests ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===--------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
#include "gtest/gtest.h"
using namespace clang;
namespace {
// Stub to collect data from InclusionDirective callbacks.
class InclusionDirectiveCallbacks : public PPCallbacks {
public:
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange, const FileEntry *File,
StringRef SearchPath, StringRef RelativePath,
const Module *Imported) override {
this->HashLoc = HashLoc;
this->IncludeTok = IncludeTok;
this->FileName = FileName.str();
this->IsAngled = IsAngled;
this->FilenameRange = FilenameRange;
this->File = File;
this->SearchPath = SearchPath.str();
this->RelativePath = RelativePath.str();
this->Imported = Imported;
}
SourceLocation HashLoc;
Token IncludeTok;
SmallString<16> FileName;
bool IsAngled;
CharSourceRange FilenameRange;
const FileEntry* File;
SmallString<16> SearchPath;
SmallString<16> RelativePath;
const Module* Imported;
};
// Stub to collect data from PragmaOpenCLExtension callbacks.
class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
public:
typedef struct {
SmallString<16> Name;
unsigned State;
} CallbackParameters;
PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}
void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
const clang::IdentifierInfo *Name,
clang::SourceLocation StateLoc,
unsigned State) override {
this->NameLoc = NameLoc;
this->Name = Name->getName();
this->StateLoc = StateLoc;
this->State = State;
}
SourceLocation NameLoc;
SmallString<16> Name;
SourceLocation StateLoc;
unsigned State;
};
// PPCallbacks test fixture.
class PPCallbacksTest : public ::testing::Test {
protected:
PPCallbacksTest()
: InMemoryFileSystem(new vfs::InMemoryFileSystem),
FileMgr(FileSystemOptions(), InMemoryFileSystem),
DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
}
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem;
FileManager FileMgr;
IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticsEngine Diags;
SourceManager SourceMgr;
LangOptions LangOpts;
std::shared_ptr<TargetOptions> TargetOpts;
IntrusiveRefCntPtr<TargetInfo> Target;
// Register a header path as a known file and add its location
// to search path.
void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath,
bool IsSystemHeader) {
// Tell FileMgr about header.
InMemoryFileSystem->addFile(HeaderPath, 0,
llvm::MemoryBuffer::getMemBuffer("\n"));
// Add header's parent path to search path.
StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
DirectoryLookup DL(DE, SrcMgr::C_User, false);
HeaderInfo.AddSearchPath(DL, IsSystemHeader);
}
// Get the raw source string of the range.
StringRef GetSourceString(CharSourceRange Range) {
const char* B = SourceMgr.getCharacterData(Range.getBegin());
const char* E = SourceMgr.getCharacterData(Range.getEnd());
return StringRef(B, E - B);
}
// Run lexer over SourceText and collect FilenameRange from
// the InclusionDirective callback.
CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
const char* HeaderPath, bool SystemHeader) {
std::unique_ptr<llvm::MemoryBuffer> Buf =
llvm::MemoryBuffer::getMemBuffer(SourceText);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
SourceMgr, PCMCache, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
// Lex source text.
PP.EnterMainSourceFile();
while (true) {
Token Tok;
PP.Lex(Tok);
if (Tok.is(tok::eof))
break;
}
// Callbacks have been executed at this point -- return filename range.
return Callbacks->FilenameRange;
}
PragmaOpenCLExtensionCallbacks::CallbackParameters
PragmaOpenCLExtensionCall(const char* SourceText) {
LangOptions OpenCLLangOpts;
OpenCLLangOpts.OpenCL = 1;
std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, OpenCLLangOpts, Target.get());
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags,
OpenCLLangOpts, SourceMgr, PCMCache, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
// parser actually sets correct pragma handlers for preprocessor
// according to LangOptions, so we init Parser to register opencl
// pragma handlers
ASTContext Context(OpenCLLangOpts, SourceMgr,
PP.getIdentifierTable(), PP.getSelectorTable(),
PP.getBuiltinInfo());
Context.InitBuiltinTypes(*Target);
ASTConsumer Consumer;
Sema S(PP, Context, Consumer);
Parser P(PP, S, false);
PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
// Lex source text.
PP.EnterMainSourceFile();
while (true) {
Token Tok;
PP.Lex(Tok);
if (Tok.is(tok::eof))
break;
}
PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
Callbacks->Name,
Callbacks->State
};
return RetVal;
}
};
TEST_F(PPCallbacksTest, QuotedFilename) {
const char* Source =
"#include \"quoted.h\"\n";
CharSourceRange Range =
InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
}
TEST_F(PPCallbacksTest, AngledFilename) {
const char* Source =
"#include <angled.h>\n";
CharSourceRange Range =
InclusionDirectiveFilenameRange(Source, "/angled.h", true);
ASSERT_EQ("<angled.h>", GetSourceString(Range));
}
TEST_F(PPCallbacksTest, QuotedInMacro) {
const char* Source =
"#define MACRO_QUOTED \"quoted.h\"\n"
"#include MACRO_QUOTED\n";
CharSourceRange Range =
InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
}
TEST_F(PPCallbacksTest, AngledInMacro) {
const char* Source =
"#define MACRO_ANGLED <angled.h>\n"
"#include MACRO_ANGLED\n";
CharSourceRange Range =
InclusionDirectiveFilenameRange(Source, "/angled.h", true);
ASSERT_EQ("<angled.h>", GetSourceString(Range));
}
TEST_F(PPCallbacksTest, StringizedMacroArgument) {
const char* Source =
"#define MACRO_STRINGIZED(x) #x\n"
"#include MACRO_STRINGIZED(quoted.h)\n";
CharSourceRange Range =
InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
}
TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
const char* Source =
"#define MACRO_ANGLED <angled.h>\n"
"#define MACRO_CONCAT(x, y) x ## _ ## y\n"
"#include MACRO_CONCAT(MACRO, ANGLED)\n";
CharSourceRange Range =
InclusionDirectiveFilenameRange(Source, "/angled.h", false);
ASSERT_EQ("<angled.h>", GetSourceString(Range));
}
TEST_F(PPCallbacksTest, TrigraphFilename) {
const char* Source =
"#include \"tri\?\?-graph.h\"\n";
CharSourceRange Range =
InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
}
TEST_F(PPCallbacksTest, TrigraphInMacro) {
const char* Source =
"#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
"#include MACRO_TRIGRAPH\n";
CharSourceRange Range =
InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
}
TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
const char* Source =
"#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
PragmaOpenCLExtensionCall(Source);
ASSERT_EQ("cl_khr_fp64", Parameters.Name);
unsigned ExpectedState = 1;
ASSERT_EQ(ExpectedState, Parameters.State);
}
TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
const char* Source =
"#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
PragmaOpenCLExtensionCall(Source);
ASSERT_EQ("cl_khr_fp16", Parameters.Name);
unsigned ExpectedState = 0;
ASSERT_EQ(ExpectedState, Parameters.State);
}
} // anonoymous namespace

View File

@ -0,0 +1,137 @@
//===- unittests/Lex/PPConditionalDirectiveRecordTest.cpp-PP directive tests =//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Lex/PPConditionalDirectiveRecord.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.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 "gtest/gtest.h"
using namespace clang;
namespace {
// The test fixture.
class PPConditionalDirectiveRecordTest : public ::testing::Test {
protected:
PPConditionalDirectiveRecordTest()
: FileMgr(FileMgrOpts),
DiagID(new DiagnosticIDs()),
Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr),
TargetOpts(new TargetOptions)
{
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
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;
};
TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
const char *source =
"0 1\n"
"#if 1\n"
"2\n"
"#ifndef BB\n"
"3 4\n"
"#else\n"
"#endif\n"
"5\n"
"#endif\n"
"6\n"
"#if 1\n"
"7\n"
"#if 1\n"
"#endif\n"
"8\n"
"#endif\n"
"9\n";
std::unique_ptr<llvm::MemoryBuffer> Buf =
llvm::MemoryBuffer::getMemBuffer(source);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
SourceMgr, PCMCache, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
PPConditionalDirectiveRecord *
PPRec = new PPConditionalDirectiveRecord(SourceMgr);
PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
PP.EnterMainSourceFile();
std::vector<Token> toks;
while (1) {
Token tok;
PP.Lex(tok);
if (tok.is(tok::eof))
break;
toks.push_back(tok);
}
// Make sure we got the tokens that we expected.
ASSERT_EQ(10U, toks.size());
EXPECT_FALSE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[0].getLocation(), toks[1].getLocation())));
EXPECT_TRUE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[0].getLocation(), toks[2].getLocation())));
EXPECT_FALSE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[3].getLocation(), toks[4].getLocation())));
EXPECT_TRUE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[1].getLocation(), toks[5].getLocation())));
EXPECT_TRUE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[2].getLocation(), toks[6].getLocation())));
EXPECT_FALSE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[2].getLocation(), toks[5].getLocation())));
EXPECT_FALSE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[0].getLocation(), toks[6].getLocation())));
EXPECT_TRUE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[2].getLocation(), toks[8].getLocation())));
EXPECT_FALSE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[0].getLocation(), toks[9].getLocation())));
EXPECT_TRUE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[0].getLocation(), toks[2].getLocation()));
EXPECT_FALSE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[3].getLocation(), toks[4].getLocation()));
EXPECT_TRUE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[1].getLocation(), toks[5].getLocation()));
EXPECT_TRUE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[2].getLocation(), toks[0].getLocation()));
EXPECT_FALSE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[4].getLocation(), toks[3].getLocation()));
EXPECT_TRUE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[5].getLocation(), toks[1].getLocation()));
}
} // anonymous namespace