brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.4 KiB · 990689c Raw
593 lines · cpp
1//===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks tests ------===//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/Lex/Preprocessor.h"10#include "clang/AST/ASTConsumer.h"11#include "clang/AST/ASTContext.h"12#include "clang/Basic/Diagnostic.h"13#include "clang/Basic/DiagnosticOptions.h"14#include "clang/Basic/FileManager.h"15#include "clang/Basic/LangOptions.h"16#include "clang/Basic/SourceManager.h"17#include "clang/Basic/TargetInfo.h"18#include "clang/Basic/TargetOptions.h"19#include "clang/Lex/HeaderSearch.h"20#include "clang/Lex/HeaderSearchOptions.h"21#include "clang/Lex/ModuleLoader.h"22#include "clang/Lex/PreprocessorOptions.h"23#include "clang/Parse/Parser.h"24#include "clang/Sema/Sema.h"25#include "llvm/ADT/SmallString.h"26#include "llvm/Support/Path.h"27#include "gtest/gtest.h"28 29using namespace clang;30 31namespace {32 33// Stub to collect data from InclusionDirective callbacks.34class InclusionDirectiveCallbacks : public PPCallbacks {35public:36  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,37                          StringRef FileName, bool IsAngled,38                          CharSourceRange FilenameRange,39                          OptionalFileEntryRef File, StringRef SearchPath,40                          StringRef RelativePath, const Module *SuggestedModule,41                          bool ModuleImported,42                          SrcMgr::CharacteristicKind FileType) override {43    this->HashLoc = HashLoc;44    this->IncludeTok = IncludeTok;45    this->FileName = FileName.str();46    this->IsAngled = IsAngled;47    this->FilenameRange = FilenameRange;48    this->File = File;49    this->SearchPath = SearchPath.str();50    this->RelativePath = RelativePath.str();51    this->SuggestedModule = SuggestedModule;52    this->ModuleImported = ModuleImported;53    this->FileType = FileType;54  }55 56  SourceLocation HashLoc;57  Token IncludeTok;58  SmallString<16> FileName;59  bool IsAngled;60  CharSourceRange FilenameRange;61  OptionalFileEntryRef File;62  SmallString<16> SearchPath;63  SmallString<16> RelativePath;64  const Module *SuggestedModule;65  bool ModuleImported;66  SrcMgr::CharacteristicKind FileType;67};68 69class CondDirectiveCallbacks : public PPCallbacks {70public:71  struct Result {72    SourceRange ConditionRange;73    ConditionValueKind ConditionValue;74 75    Result(SourceRange R, ConditionValueKind K)76        : ConditionRange(R), ConditionValue(K) {}77  };78 79  std::vector<Result> Results;80 81  void If(SourceLocation Loc, SourceRange ConditionRange,82          ConditionValueKind ConditionValue) override {83    Results.emplace_back(ConditionRange, ConditionValue);84  }85 86  void Elif(SourceLocation Loc, SourceRange ConditionRange,87            ConditionValueKind ConditionValue, SourceLocation IfLoc) override {88    Results.emplace_back(ConditionRange, ConditionValue);89  }90};91 92// Stub to collect data from PragmaOpenCLExtension callbacks.93class PragmaOpenCLExtensionCallbacks : public PPCallbacks {94public:95  typedef struct {96    SmallString<16> Name;97    unsigned State;98  } CallbackParameters;99 100  PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}101 102  void PragmaOpenCLExtension(clang::SourceLocation NameLoc,103                             const clang::IdentifierInfo *Name,104                             clang::SourceLocation StateLoc,105                             unsigned State) override {106      this->NameLoc = NameLoc;107      this->Name = Name->getName();108      this->StateLoc = StateLoc;109      this->State = State;110  }111 112  SourceLocation NameLoc;113  SmallString<16> Name;114  SourceLocation StateLoc;115  unsigned State;116};117 118class PragmaMarkCallbacks : public PPCallbacks {119public:120  struct Mark {121    SourceLocation Location;122    std::string Trivia;123  };124 125  std::vector<Mark> Marks;126 127  void PragmaMark(SourceLocation Loc, StringRef Trivia) override {128    Marks.emplace_back(Mark{Loc, Trivia.str()});129  }130};131 132// PPCallbacks test fixture.133class PPCallbacksTest : public ::testing::Test {134protected:135  PPCallbacksTest()136      : InMemoryFileSystem(137            llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>()),138        FileMgr(FileSystemOptions(), InMemoryFileSystem),139        DiagID(DiagnosticIDs::create()),140        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),141        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {142    TargetOpts->Triple = "x86_64-apple-darwin11.1.0";143    Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);144  }145 146  IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;147  FileManager FileMgr;148  IntrusiveRefCntPtr<DiagnosticIDs> DiagID;149  DiagnosticOptions DiagOpts;150  DiagnosticsEngine Diags;151  SourceManager SourceMgr;152  LangOptions LangOpts;153  std::shared_ptr<TargetOptions> TargetOpts;154  IntrusiveRefCntPtr<TargetInfo> Target;155 156  // Register a header path as a known file and add its location157  // to search path.158  void AddFakeHeader(HeaderSearch &HeaderInfo, const char *HeaderPath,159                     bool IsSystemHeader) {160    // Tell FileMgr about header.161    InMemoryFileSystem->addFile(HeaderPath, 0,162                                llvm::MemoryBuffer::getMemBuffer("\n"));163 164    // Add header's parent path to search path.165    StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);166    auto DE = FileMgr.getOptionalDirectoryRef(SearchPath);167    DirectoryLookup DL(*DE, SrcMgr::C_User, false);168    HeaderInfo.AddSearchPath(DL, IsSystemHeader);169  }170 171  // Get the raw source string of the range.172  StringRef GetSourceString(CharSourceRange Range) {173    const char* B = SourceMgr.getCharacterData(Range.getBegin());174    const char* E = SourceMgr.getCharacterData(Range.getEnd());175 176    return StringRef(B, E - B);177  }178 179  StringRef GetSourceStringToEnd(CharSourceRange Range) {180    const char *B = SourceMgr.getCharacterData(Range.getBegin());181    const char *E = SourceMgr.getCharacterData(Range.getEnd());182 183    return StringRef(184        B,185        E - B + Lexer::MeasureTokenLength(Range.getEnd(), SourceMgr, LangOpts));186  }187 188  // Run lexer over SourceText and collect FilenameRange from189  // the InclusionDirective callback.190  CharSourceRange InclusionDirectiveFilenameRange(const char *SourceText,191                                                  const char *HeaderPath,192                                                  bool SystemHeader) {193    std::unique_ptr<llvm::MemoryBuffer> Buf =194        llvm::MemoryBuffer::getMemBuffer(SourceText);195    SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));196 197    HeaderSearchOptions HSOpts;198    TrivialModuleLoader ModLoader;199 200    HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());201    AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);202 203    PreprocessorOptions PPOpts;204    Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,205                    /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);206    return InclusionDirectiveCallback(PP)->FilenameRange;207  }208 209  SrcMgr::CharacteristicKind InclusionDirectiveCharacteristicKind(210      const char *SourceText, const char *HeaderPath, bool SystemHeader) {211    std::unique_ptr<llvm::MemoryBuffer> Buf =212        llvm::MemoryBuffer::getMemBuffer(SourceText);213    SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));214 215    HeaderSearchOptions HSOpts;216    TrivialModuleLoader ModLoader;217 218    HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());219    AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);220 221    PreprocessorOptions PPOpts;222    Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,223                    /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);224    return InclusionDirectiveCallback(PP)->FileType;225  }226 227  InclusionDirectiveCallbacks *InclusionDirectiveCallback(Preprocessor &PP) {228    PP.Initialize(*Target);229    InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;230    PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));231 232    // Lex source text.233    PP.EnterMainSourceFile();234    PP.LexTokensUntilEOF();235 236    // Callbacks have been executed at this point -- return filename range.237    return Callbacks;238  }239 240  std::vector<CondDirectiveCallbacks::Result>241  DirectiveExprRange(StringRef SourceText, PreprocessorOptions PPOpts = {}) {242    HeaderSearchOptions HSOpts;243    TrivialModuleLoader ModLoader;244    std::unique_ptr<llvm::MemoryBuffer> Buf =245        llvm::MemoryBuffer::getMemBuffer(SourceText);246    SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));247    HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());248    Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,249                    /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);250    PP.Initialize(*Target);251    auto *Callbacks = new CondDirectiveCallbacks;252    PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));253 254    // Lex source text.255    PP.EnterMainSourceFile();256    PP.LexTokensUntilEOF();257 258    return Callbacks->Results;259  }260 261  std::vector<PragmaMarkCallbacks::Mark>262  PragmaMarkCall(const char *SourceText) {263    std::unique_ptr<llvm::MemoryBuffer> SourceBuf =264        llvm::MemoryBuffer::getMemBuffer(SourceText, "test.c");265    SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));266 267    HeaderSearchOptions HSOpts;268    TrivialModuleLoader ModLoader;269    PreprocessorOptions PPOpts;270 271    HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());272 273    Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,274                    /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);275    PP.Initialize(*Target);276 277    auto *Callbacks = new PragmaMarkCallbacks;278    PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));279 280    // Lex source text.281    PP.EnterMainSourceFile();282    PP.LexTokensUntilEOF();283 284    return Callbacks->Marks;285  }286 287  PragmaOpenCLExtensionCallbacks::CallbackParameters288  PragmaOpenCLExtensionCall(const char *SourceText) {289    LangOptions OpenCLLangOpts;290    OpenCLLangOpts.OpenCL = 1;291 292    std::unique_ptr<llvm::MemoryBuffer> SourceBuf =293        llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");294    SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));295 296    HeaderSearchOptions HSOpts;297    TrivialModuleLoader ModLoader;298    PreprocessorOptions PPOpts;299 300    HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, OpenCLLangOpts,301                            Target.get());302 303    Preprocessor PP(PPOpts, Diags, OpenCLLangOpts, SourceMgr, HeaderInfo,304                    ModLoader, /*IILookup=*/nullptr,305                    /*OwnsHeaderSearch=*/false);306    PP.Initialize(*Target);307 308    // parser actually sets correct pragma handlers for preprocessor309    // according to LangOptions, so we init Parser to register opencl310    // pragma handlers311    ASTContext Context(OpenCLLangOpts, SourceMgr, PP.getIdentifierTable(),312                       PP.getSelectorTable(), PP.getBuiltinInfo(), PP.TUKind);313    Context.InitBuiltinTypes(*Target);314 315    ASTConsumer Consumer;316    Sema S(PP, Context, Consumer);317    Parser P(PP, S, false);318    PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;319    PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));320 321    // Lex source text.322    PP.EnterMainSourceFile();323    PP.LexTokensUntilEOF();324 325    PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {326      Callbacks->Name,327      Callbacks->State328    };329    return RetVal;330  }331};332 333TEST_F(PPCallbacksTest, UserFileCharacteristics) {334  const char *Source = "#include \"quoted.h\"\n";335 336  SrcMgr::CharacteristicKind Kind =337      InclusionDirectiveCharacteristicKind(Source, "/quoted.h", false);338 339  ASSERT_EQ(SrcMgr::CharacteristicKind::C_User, Kind);340}341 342TEST_F(PPCallbacksTest, QuotedFilename) {343  const char* Source =344    "#include \"quoted.h\"\n";345 346  CharSourceRange Range =347    InclusionDirectiveFilenameRange(Source, "/quoted.h", false);348 349  ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));350}351 352TEST_F(PPCallbacksTest, AngledFilename) {353  const char* Source =354    "#include <angled.h>\n";355 356  CharSourceRange Range =357    InclusionDirectiveFilenameRange(Source, "/angled.h", true);358 359  ASSERT_EQ("<angled.h>", GetSourceString(Range));360}361 362TEST_F(PPCallbacksTest, QuotedInMacro) {363  const char* Source =364    "#define MACRO_QUOTED \"quoted.h\"\n"365    "#include MACRO_QUOTED\n";366 367  CharSourceRange Range =368    InclusionDirectiveFilenameRange(Source, "/quoted.h", false);369 370  ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));371}372 373TEST_F(PPCallbacksTest, AngledInMacro) {374  const char* Source =375    "#define MACRO_ANGLED <angled.h>\n"376    "#include MACRO_ANGLED\n";377 378  CharSourceRange Range =379    InclusionDirectiveFilenameRange(Source, "/angled.h", true);380 381  ASSERT_EQ("<angled.h>", GetSourceString(Range));382}383 384TEST_F(PPCallbacksTest, StringizedMacroArgument) {385  const char* Source =386    "#define MACRO_STRINGIZED(x) #x\n"387    "#include MACRO_STRINGIZED(quoted.h)\n";388 389  CharSourceRange Range =390    InclusionDirectiveFilenameRange(Source, "/quoted.h", false);391 392  ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));393}394 395TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {396  const char* Source =397    "#define MACRO_ANGLED <angled.h>\n"398    "#define MACRO_CONCAT(x, y) x ## _ ## y\n"399    "#include MACRO_CONCAT(MACRO, ANGLED)\n";400 401  CharSourceRange Range =402    InclusionDirectiveFilenameRange(Source, "/angled.h", false);403 404  ASSERT_EQ("<angled.h>", GetSourceString(Range));405}406 407TEST_F(PPCallbacksTest, TrigraphFilename) {408  const char* Source =409    "#include \"tri\?\?-graph.h\"\n";410 411  CharSourceRange Range =412    InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);413 414  ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));415}416 417TEST_F(PPCallbacksTest, TrigraphInMacro) {418  const char* Source =419    "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"420    "#include MACRO_TRIGRAPH\n";421 422  CharSourceRange Range =423    InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);424 425  ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));426}427 428TEST_F(PPCallbacksTest, FileNotFoundSkipped) {429  const char *SourceText = "#include \"skipped.h\"\n";430 431  std::unique_ptr<llvm::MemoryBuffer> SourceBuf =432      llvm::MemoryBuffer::getMemBuffer(SourceText);433  SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));434 435  HeaderSearchOptions HSOpts;436  TrivialModuleLoader ModLoader;437  PreprocessorOptions PPOpts;438  HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());439 440  DiagnosticConsumer *DiagConsumer = new DiagnosticConsumer;441  DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts, DiagConsumer);442  Preprocessor PP(PPOpts, FileNotFoundDiags, LangOpts, SourceMgr, HeaderInfo,443                  ModLoader, /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);444  PP.Initialize(*Target);445 446  class FileNotFoundCallbacks : public PPCallbacks {447  public:448    unsigned int NumCalls = 0;449    bool FileNotFound(StringRef FileName) override {450      NumCalls++;451      return FileName == "skipped.h";452    }453  };454 455  auto *Callbacks = new FileNotFoundCallbacks;456  PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));457 458  // Lex source text.459  PP.EnterMainSourceFile();460  PP.LexTokensUntilEOF();461 462  ASSERT_EQ(1u, Callbacks->NumCalls);463  ASSERT_EQ(0u, DiagConsumer->getNumErrors());464}465 466TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {467  const char* Source =468    "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";469 470  PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =471    PragmaOpenCLExtensionCall(Source);472 473  ASSERT_EQ("cl_khr_fp64", Parameters.Name);474  unsigned ExpectedState = 1;475  ASSERT_EQ(ExpectedState, Parameters.State);476}477 478TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {479  const char* Source =480    "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";481 482  PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =483    PragmaOpenCLExtensionCall(Source);484 485  ASSERT_EQ("cl_khr_fp16", Parameters.Name);486  unsigned ExpectedState = 0;487  ASSERT_EQ(ExpectedState, Parameters.State);488}489 490TEST_F(PPCallbacksTest, CollectMarks) {491  const char *Source =492    "#pragma mark\n"493    "#pragma mark\r\n"494    "#pragma mark - trivia\n"495    "#pragma mark - trivia\r\n";496 497  auto Marks = PragmaMarkCall(Source);498 499  ASSERT_EQ(4u, Marks.size());500  ASSERT_TRUE(Marks[0].Trivia.empty());501  ASSERT_TRUE(Marks[1].Trivia.empty());502  ASSERT_FALSE(Marks[2].Trivia.empty());503  ASSERT_FALSE(Marks[3].Trivia.empty());504  ASSERT_EQ(" - trivia", Marks[2].Trivia);505  ASSERT_EQ(" - trivia", Marks[3].Trivia);506}507 508TEST_F(PPCallbacksTest, DirectiveExprRanges) {509  const auto &Results1 = DirectiveExprRange("#if FLUZZY_FLOOF\n#endif\n");510  EXPECT_EQ(Results1.size(), 1U);511  EXPECT_EQ(512      GetSourceStringToEnd(CharSourceRange(Results1[0].ConditionRange, false)),513      "FLUZZY_FLOOF");514 515  const auto &Results2 = DirectiveExprRange("#if 1 + 4 < 7\n#endif\n");516  EXPECT_EQ(Results2.size(), 1U);517  EXPECT_EQ(518      GetSourceStringToEnd(CharSourceRange(Results2[0].ConditionRange, false)),519      "1 + 4 < 7");520 521  const auto &Results3 = DirectiveExprRange("#if 1 + \\\n  2\n#endif\n");522  EXPECT_EQ(Results3.size(), 1U);523  EXPECT_EQ(524      GetSourceStringToEnd(CharSourceRange(Results3[0].ConditionRange, false)),525      "1 + \\\n  2");526 527  const auto &Results4 = DirectiveExprRange("#if 0\n#elif FLOOFY\n#endif\n");528  EXPECT_EQ(Results4.size(), 2U);529  EXPECT_EQ(530      GetSourceStringToEnd(CharSourceRange(Results4[0].ConditionRange, false)),531      "0");532  EXPECT_EQ(533      GetSourceStringToEnd(CharSourceRange(Results4[1].ConditionRange, false)),534      "FLOOFY");535 536  const auto &Results5 = DirectiveExprRange("#if 1\n#elif FLOOFY\n#endif\n");537  EXPECT_EQ(Results5.size(), 2U);538  EXPECT_EQ(539      GetSourceStringToEnd(CharSourceRange(Results5[0].ConditionRange, false)),540      "1");541  EXPECT_EQ(542      GetSourceStringToEnd(CharSourceRange(Results5[1].ConditionRange, false)),543      "FLOOFY");544 545  const auto &Results6 =546      DirectiveExprRange("#if defined(FLUZZY_FLOOF)\n#endif\n");547  EXPECT_EQ(Results6.size(), 1U);548  EXPECT_EQ(549      GetSourceStringToEnd(CharSourceRange(Results6[0].ConditionRange, false)),550      "defined(FLUZZY_FLOOF)");551 552  const auto &Results7 =553      DirectiveExprRange("#if 1\n#elif defined(FLOOFY)\n#endif\n");554  EXPECT_EQ(Results7.size(), 2U);555  EXPECT_EQ(556      GetSourceStringToEnd(CharSourceRange(Results7[0].ConditionRange, false)),557      "1");558  EXPECT_EQ(559      GetSourceStringToEnd(CharSourceRange(Results7[1].ConditionRange, false)),560      "defined(FLOOFY)");561 562  const auto &Results8 =563      DirectiveExprRange("#define FLOOFY 0\n#if __FILE__ > FLOOFY\n#endif\n");564  EXPECT_EQ(Results8.size(), 1U);565  EXPECT_EQ(566      GetSourceStringToEnd(CharSourceRange(Results8[0].ConditionRange, false)),567      "__FILE__ > FLOOFY");568  EXPECT_EQ(569      Lexer::getSourceText(CharSourceRange(Results8[0].ConditionRange, false),570                           SourceMgr, LangOpts),571      "__FILE__ > FLOOFY");572 573  const char *MultiExprIf = "#if defined(FLOOFY) || defined(FLUZZY)\n#endif\n";574  const auto &Results9 = DirectiveExprRange(MultiExprIf);575  EXPECT_EQ(Results9.size(), 1U);576  EXPECT_EQ(577      Lexer::getSourceText(CharSourceRange(Results9[0].ConditionRange, false),578                           SourceMgr, LangOpts),579      "defined(FLOOFY) || defined(FLUZZY)");580 581  PreprocessorOptions PPOptsSingleFileParse;582  PPOptsSingleFileParse.SingleFileParseMode = true;583  const auto &Results10 =584      DirectiveExprRange(MultiExprIf, PPOptsSingleFileParse);585  EXPECT_EQ(Results10.size(), 1U);586  EXPECT_EQ(587      Lexer::getSourceText(CharSourceRange(Results10[0].ConditionRange, false),588                           SourceMgr, LangOpts),589      "defined(FLOOFY) || defined(FLUZZY)");590}591 592} // namespace593