1 //===--- PPCallbacks.h - Callbacks for Preprocessor actions -----*- C++ -*-===// 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 /// \file 10 /// Defines the PPCallbacks interface. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_LEX_PPCALLBACKS_H 15 #define LLVM_CLANG_LEX_PPCALLBACKS_H 16 17 #include "clang/Basic/DiagnosticIDs.h" 18 #include "clang/Basic/SourceLocation.h" 19 #include "clang/Basic/SourceManager.h" 20 #include "clang/Lex/ModuleLoader.h" 21 #include "clang/Lex/Pragma.h" 22 #include "llvm/ADT/StringRef.h" 23 24 namespace clang { 25 class Token; 26 class IdentifierInfo; 27 class MacroDefinition; 28 class MacroDirective; 29 class MacroArgs; 30 31 /// This interface provides a way to observe the actions of the 32 /// preprocessor as it does its thing. 33 /// 34 /// Clients can define their hooks here to implement preprocessor level tools. 35 class PPCallbacks { 36 public: 37 virtual ~PPCallbacks(); 38 39 enum FileChangeReason { 40 EnterFile, ExitFile, SystemHeaderPragma, RenameFile 41 }; 42 43 /// Callback invoked whenever a source file is entered or exited. 44 /// 45 /// \param Loc Indicates the new location. 46 /// \param PrevFID the file that was exited if \p Reason is ExitFile. 47 virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, 48 SrcMgr::CharacteristicKind FileType, 49 FileID PrevFID = FileID()) { 50 } 51 52 /// Callback invoked whenever a source file is skipped as the result 53 /// of header guard optimization. 54 /// 55 /// \param SkippedFile The file that is skipped instead of entering \#include 56 /// 57 /// \param FilenameTok The file name token in \#include "FileName" directive 58 /// or macro expanded file name token from \#include MACRO(PARAMS) directive. 59 /// Note that FilenameTok contains corresponding quotes/angles symbols. 60 virtual void FileSkipped(const FileEntryRef &SkippedFile, 61 const Token &FilenameTok, 62 SrcMgr::CharacteristicKind FileType) {} 63 64 /// Callback invoked whenever an inclusion directive results in a 65 /// file-not-found error. 66 /// 67 /// \param FileName The name of the file being included, as written in the 68 /// source code. 69 /// 70 /// \param RecoveryPath If this client indicates that it can recover from 71 /// this missing file, the client should set this as an additional header 72 /// search patch. 73 /// 74 /// \returns true to indicate that the preprocessor should attempt to recover 75 /// by adding \p RecoveryPath as a header search path. 76 virtual bool FileNotFound(StringRef FileName, 77 SmallVectorImpl<char> &RecoveryPath) { 78 return false; 79 } 80 81 /// Callback invoked whenever an inclusion directive of 82 /// any kind (\c \#include, \c \#import, etc.) has been processed, regardless 83 /// of whether the inclusion will actually result in an inclusion. 84 /// 85 /// \param HashLoc The location of the '#' that starts the inclusion 86 /// directive. 87 /// 88 /// \param IncludeTok The token that indicates the kind of inclusion 89 /// directive, e.g., 'include' or 'import'. 90 /// 91 /// \param FileName The name of the file being included, as written in the 92 /// source code. 93 /// 94 /// \param IsAngled Whether the file name was enclosed in angle brackets; 95 /// otherwise, it was enclosed in quotes. 96 /// 97 /// \param FilenameRange The character range of the quotes or angle brackets 98 /// for the written file name. 99 /// 100 /// \param File The actual file that may be included by this inclusion 101 /// directive. 102 /// 103 /// \param SearchPath Contains the search path which was used to find the file 104 /// in the file system. If the file was found via an absolute include path, 105 /// SearchPath will be empty. For framework includes, the SearchPath and 106 /// RelativePath will be split up. For example, if an include of "Some/Some.h" 107 /// is found via the framework path 108 /// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be 109 /// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be 110 /// "Some.h". 111 /// 112 /// \param RelativePath The path relative to SearchPath, at which the include 113 /// file was found. This is equal to FileName except for framework includes. 114 /// 115 /// \param Imported The module, whenever an inclusion directive was 116 /// automatically turned into a module import or null otherwise. 117 /// 118 /// \param FileType The characteristic kind, indicates whether a file or 119 /// directory holds normal user code, system code, or system code which is 120 /// implicitly 'extern "C"' in C++ mode. 121 /// 122 virtual void InclusionDirective(SourceLocation HashLoc, 123 const Token &IncludeTok, 124 StringRef FileName, 125 bool IsAngled, 126 CharSourceRange FilenameRange, 127 const FileEntry *File, 128 StringRef SearchPath, 129 StringRef RelativePath, 130 const Module *Imported, 131 SrcMgr::CharacteristicKind FileType) { 132 } 133 134 /// Callback invoked whenever a submodule was entered. 135 /// 136 /// \param M The submodule we have entered. 137 /// 138 /// \param ImportLoc The location of import directive token. 139 /// 140 /// \param ForPragma If entering from pragma directive. 141 /// 142 virtual void EnteredSubmodule(Module *M, SourceLocation ImportLoc, 143 bool ForPragma) { } 144 145 /// Callback invoked whenever a submodule was left. 146 /// 147 /// \param M The submodule we have left. 148 /// 149 /// \param ImportLoc The location of import directive token. 150 /// 151 /// \param ForPragma If entering from pragma directive. 152 /// 153 virtual void LeftSubmodule(Module *M, SourceLocation ImportLoc, 154 bool ForPragma) { } 155 156 /// Callback invoked whenever there was an explicit module-import 157 /// syntax. 158 /// 159 /// \param ImportLoc The location of import directive token. 160 /// 161 /// \param Path The identifiers (and their locations) of the module 162 /// "path", e.g., "std.vector" would be split into "std" and "vector". 163 /// 164 /// \param Imported The imported module; can be null if importing failed. 165 /// 166 virtual void moduleImport(SourceLocation ImportLoc, 167 ModuleIdPath Path, 168 const Module *Imported) { 169 } 170 171 /// Callback invoked when the end of the main file is reached. 172 /// 173 /// No subsequent callbacks will be made. 174 virtual void EndOfMainFile() { 175 } 176 177 /// Callback invoked when a \#ident or \#sccs directive is read. 178 /// \param Loc The location of the directive. 179 /// \param str The text of the directive. 180 /// 181 virtual void Ident(SourceLocation Loc, StringRef str) { 182 } 183 184 /// Callback invoked when start reading any pragma directive. 185 virtual void PragmaDirective(SourceLocation Loc, 186 PragmaIntroducerKind Introducer) { 187 } 188 189 /// Callback invoked when a \#pragma comment directive is read. 190 virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, 191 StringRef Str) { 192 } 193 194 /// Callback invoked when a \#pragma detect_mismatch directive is 195 /// read. 196 virtual void PragmaDetectMismatch(SourceLocation Loc, StringRef Name, 197 StringRef Value) { 198 } 199 200 /// Callback invoked when a \#pragma clang __debug directive is read. 201 /// \param Loc The location of the debug directive. 202 /// \param DebugType The identifier following __debug. 203 virtual void PragmaDebug(SourceLocation Loc, StringRef DebugType) { 204 } 205 206 /// Determines the kind of \#pragma invoking a call to PragmaMessage. 207 enum PragmaMessageKind { 208 /// \#pragma message has been invoked. 209 PMK_Message, 210 211 /// \#pragma GCC warning has been invoked. 212 PMK_Warning, 213 214 /// \#pragma GCC error has been invoked. 215 PMK_Error 216 }; 217 218 /// Callback invoked when a \#pragma message directive is read. 219 /// \param Loc The location of the message directive. 220 /// \param Namespace The namespace of the message directive. 221 /// \param Kind The type of the message directive. 222 /// \param Str The text of the message directive. 223 virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace, 224 PragmaMessageKind Kind, StringRef Str) { 225 } 226 227 /// Callback invoked when a \#pragma gcc diagnostic push directive 228 /// is read. 229 virtual void PragmaDiagnosticPush(SourceLocation Loc, 230 StringRef Namespace) { 231 } 232 233 /// Callback invoked when a \#pragma gcc diagnostic pop directive 234 /// is read. 235 virtual void PragmaDiagnosticPop(SourceLocation Loc, 236 StringRef Namespace) { 237 } 238 239 /// Callback invoked when a \#pragma gcc diagnostic directive is read. 240 virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, 241 diag::Severity mapping, StringRef Str) {} 242 243 /// Called when an OpenCL extension is either disabled or 244 /// enabled with a pragma. 245 virtual void PragmaOpenCLExtension(SourceLocation NameLoc, 246 const IdentifierInfo *Name, 247 SourceLocation StateLoc, unsigned State) { 248 } 249 250 /// Callback invoked when a \#pragma warning directive is read. 251 virtual void PragmaWarning(SourceLocation Loc, StringRef WarningSpec, 252 ArrayRef<int> Ids) { 253 } 254 255 /// Callback invoked when a \#pragma warning(push) directive is read. 256 virtual void PragmaWarningPush(SourceLocation Loc, int Level) { 257 } 258 259 /// Callback invoked when a \#pragma warning(pop) directive is read. 260 virtual void PragmaWarningPop(SourceLocation Loc) { 261 } 262 263 /// Callback invoked when a \#pragma execution_character_set(push) directive 264 /// is read. 265 virtual void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) {} 266 267 /// Callback invoked when a \#pragma execution_character_set(pop) directive 268 /// is read. 269 virtual void PragmaExecCharsetPop(SourceLocation Loc) {} 270 271 /// Callback invoked when a \#pragma clang assume_nonnull begin directive 272 /// is read. 273 virtual void PragmaAssumeNonNullBegin(SourceLocation Loc) {} 274 275 /// Callback invoked when a \#pragma clang assume_nonnull end directive 276 /// is read. 277 virtual void PragmaAssumeNonNullEnd(SourceLocation Loc) {} 278 279 /// Called by Preprocessor::HandleMacroExpandedIdentifier when a 280 /// macro invocation is found. 281 virtual void MacroExpands(const Token &MacroNameTok, 282 const MacroDefinition &MD, SourceRange Range, 283 const MacroArgs *Args) {} 284 285 /// Hook called whenever a macro definition is seen. 286 virtual void MacroDefined(const Token &MacroNameTok, 287 const MacroDirective *MD) { 288 } 289 290 /// Hook called whenever a macro \#undef is seen. 291 /// \param MacroNameTok The active Token 292 /// \param MD A MacroDefinition for the named macro. 293 /// \param Undef New MacroDirective if the macro was defined, null otherwise. 294 /// 295 /// MD is released immediately following this callback. 296 virtual void MacroUndefined(const Token &MacroNameTok, 297 const MacroDefinition &MD, 298 const MacroDirective *Undef) { 299 } 300 301 /// Hook called whenever the 'defined' operator is seen. 302 /// \param MD The MacroDirective if the name was a macro, null otherwise. 303 virtual void Defined(const Token &MacroNameTok, const MacroDefinition &MD, 304 SourceRange Range) { 305 } 306 307 /// Hook called when a '__has_include' or '__has_include_next' directive is 308 /// read. 309 virtual void HasInclude(SourceLocation Loc, StringRef FileName, bool IsAngled, 310 Optional<FileEntryRef> File, 311 SrcMgr::CharacteristicKind FileType); 312 313 /// Hook called when a source range is skipped. 314 /// \param Range The SourceRange that was skipped. The range begins at the 315 /// \#if/\#else directive and ends after the \#endif/\#else directive. 316 /// \param EndifLoc The end location of the 'endif' token, which may precede 317 /// the range skipped by the directive (e.g excluding comments after an 318 /// 'endif'). 319 virtual void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) { 320 } 321 322 enum ConditionValueKind { 323 CVK_NotEvaluated, CVK_False, CVK_True 324 }; 325 326 /// Hook called whenever an \#if is seen. 327 /// \param Loc the source location of the directive. 328 /// \param ConditionRange The SourceRange of the expression being tested. 329 /// \param ConditionValue The evaluated value of the condition. 330 /// 331 // FIXME: better to pass in a list (or tree!) of Tokens. 332 virtual void If(SourceLocation Loc, SourceRange ConditionRange, 333 ConditionValueKind ConditionValue) { 334 } 335 336 /// Hook called whenever an \#elif is seen. 337 /// \param Loc the source location of the directive. 338 /// \param ConditionRange The SourceRange of the expression being tested. 339 /// \param ConditionValue The evaluated value of the condition. 340 /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. 341 // FIXME: better to pass in a list (or tree!) of Tokens. 342 virtual void Elif(SourceLocation Loc, SourceRange ConditionRange, 343 ConditionValueKind ConditionValue, SourceLocation IfLoc) { 344 } 345 346 /// Hook called whenever an \#ifdef is seen. 347 /// \param Loc the source location of the directive. 348 /// \param MacroNameTok Information on the token being tested. 349 /// \param MD The MacroDefinition if the name was a macro, null otherwise. 350 virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok, 351 const MacroDefinition &MD) { 352 } 353 354 /// Hook called whenever an \#ifndef is seen. 355 /// \param Loc the source location of the directive. 356 /// \param MacroNameTok Information on the token being tested. 357 /// \param MD The MacroDefiniton if the name was a macro, null otherwise. 358 virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok, 359 const MacroDefinition &MD) { 360 } 361 362 /// Hook called whenever an \#else is seen. 363 /// \param Loc the source location of the directive. 364 /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. 365 virtual void Else(SourceLocation Loc, SourceLocation IfLoc) { 366 } 367 368 /// Hook called whenever an \#endif is seen. 369 /// \param Loc the source location of the directive. 370 /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. 371 virtual void Endif(SourceLocation Loc, SourceLocation IfLoc) { 372 } 373 }; 374 375 /// Simple wrapper class for chaining callbacks. 376 class PPChainedCallbacks : public PPCallbacks { 377 std::unique_ptr<PPCallbacks> First, Second; 378 379 public: 380 PPChainedCallbacks(std::unique_ptr<PPCallbacks> _First, 381 std::unique_ptr<PPCallbacks> _Second) 382 : First(std::move(_First)), Second(std::move(_Second)) {} 383 384 ~PPChainedCallbacks() override; 385 386 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 387 SrcMgr::CharacteristicKind FileType, 388 FileID PrevFID) override { 389 First->FileChanged(Loc, Reason, FileType, PrevFID); 390 Second->FileChanged(Loc, Reason, FileType, PrevFID); 391 } 392 393 void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok, 394 SrcMgr::CharacteristicKind FileType) override { 395 First->FileSkipped(SkippedFile, FilenameTok, FileType); 396 Second->FileSkipped(SkippedFile, FilenameTok, FileType); 397 } 398 399 bool FileNotFound(StringRef FileName, 400 SmallVectorImpl<char> &RecoveryPath) override { 401 return First->FileNotFound(FileName, RecoveryPath) || 402 Second->FileNotFound(FileName, RecoveryPath); 403 } 404 405 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 406 StringRef FileName, bool IsAngled, 407 CharSourceRange FilenameRange, const FileEntry *File, 408 StringRef SearchPath, StringRef RelativePath, 409 const Module *Imported, 410 SrcMgr::CharacteristicKind FileType) override { 411 First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, 412 FilenameRange, File, SearchPath, RelativePath, 413 Imported, FileType); 414 Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, 415 FilenameRange, File, SearchPath, RelativePath, 416 Imported, FileType); 417 } 418 419 void EnteredSubmodule(Module *M, SourceLocation ImportLoc, 420 bool ForPragma) override { 421 First->EnteredSubmodule(M, ImportLoc, ForPragma); 422 Second->EnteredSubmodule(M, ImportLoc, ForPragma); 423 } 424 425 void LeftSubmodule(Module *M, SourceLocation ImportLoc, 426 bool ForPragma) override { 427 First->LeftSubmodule(M, ImportLoc, ForPragma); 428 Second->LeftSubmodule(M, ImportLoc, ForPragma); 429 } 430 431 void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, 432 const Module *Imported) override { 433 First->moduleImport(ImportLoc, Path, Imported); 434 Second->moduleImport(ImportLoc, Path, Imported); 435 } 436 437 void EndOfMainFile() override { 438 First->EndOfMainFile(); 439 Second->EndOfMainFile(); 440 } 441 442 void Ident(SourceLocation Loc, StringRef str) override { 443 First->Ident(Loc, str); 444 Second->Ident(Loc, str); 445 } 446 447 void PragmaDirective(SourceLocation Loc, 448 PragmaIntroducerKind Introducer) override { 449 First->PragmaDirective(Loc, Introducer); 450 Second->PragmaDirective(Loc, Introducer); 451 } 452 453 void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, 454 StringRef Str) override { 455 First->PragmaComment(Loc, Kind, Str); 456 Second->PragmaComment(Loc, Kind, Str); 457 } 458 459 void PragmaDetectMismatch(SourceLocation Loc, StringRef Name, 460 StringRef Value) override { 461 First->PragmaDetectMismatch(Loc, Name, Value); 462 Second->PragmaDetectMismatch(Loc, Name, Value); 463 } 464 465 void PragmaDebug(SourceLocation Loc, StringRef DebugType) override { 466 First->PragmaDebug(Loc, DebugType); 467 Second->PragmaDebug(Loc, DebugType); 468 } 469 470 void PragmaMessage(SourceLocation Loc, StringRef Namespace, 471 PragmaMessageKind Kind, StringRef Str) override { 472 First->PragmaMessage(Loc, Namespace, Kind, Str); 473 Second->PragmaMessage(Loc, Namespace, Kind, Str); 474 } 475 476 void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) override { 477 First->PragmaDiagnosticPush(Loc, Namespace); 478 Second->PragmaDiagnosticPush(Loc, Namespace); 479 } 480 481 void PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) override { 482 First->PragmaDiagnosticPop(Loc, Namespace); 483 Second->PragmaDiagnosticPop(Loc, Namespace); 484 } 485 486 void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, 487 diag::Severity mapping, StringRef Str) override { 488 First->PragmaDiagnostic(Loc, Namespace, mapping, Str); 489 Second->PragmaDiagnostic(Loc, Namespace, mapping, Str); 490 } 491 492 void HasInclude(SourceLocation Loc, StringRef FileName, bool IsAngled, 493 Optional<FileEntryRef> File, 494 SrcMgr::CharacteristicKind FileType) override; 495 496 void PragmaOpenCLExtension(SourceLocation NameLoc, const IdentifierInfo *Name, 497 SourceLocation StateLoc, unsigned State) override { 498 First->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State); 499 Second->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State); 500 } 501 502 void PragmaWarning(SourceLocation Loc, StringRef WarningSpec, 503 ArrayRef<int> Ids) override { 504 First->PragmaWarning(Loc, WarningSpec, Ids); 505 Second->PragmaWarning(Loc, WarningSpec, Ids); 506 } 507 508 void PragmaWarningPush(SourceLocation Loc, int Level) override { 509 First->PragmaWarningPush(Loc, Level); 510 Second->PragmaWarningPush(Loc, Level); 511 } 512 513 void PragmaWarningPop(SourceLocation Loc) override { 514 First->PragmaWarningPop(Loc); 515 Second->PragmaWarningPop(Loc); 516 } 517 518 void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) override { 519 First->PragmaExecCharsetPush(Loc, Str); 520 Second->PragmaExecCharsetPush(Loc, Str); 521 } 522 523 void PragmaExecCharsetPop(SourceLocation Loc) override { 524 First->PragmaExecCharsetPop(Loc); 525 Second->PragmaExecCharsetPop(Loc); 526 } 527 528 void PragmaAssumeNonNullBegin(SourceLocation Loc) override { 529 First->PragmaAssumeNonNullBegin(Loc); 530 Second->PragmaAssumeNonNullBegin(Loc); 531 } 532 533 void PragmaAssumeNonNullEnd(SourceLocation Loc) override { 534 First->PragmaAssumeNonNullEnd(Loc); 535 Second->PragmaAssumeNonNullEnd(Loc); 536 } 537 538 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, 539 SourceRange Range, const MacroArgs *Args) override { 540 First->MacroExpands(MacroNameTok, MD, Range, Args); 541 Second->MacroExpands(MacroNameTok, MD, Range, Args); 542 } 543 544 void MacroDefined(const Token &MacroNameTok, 545 const MacroDirective *MD) override { 546 First->MacroDefined(MacroNameTok, MD); 547 Second->MacroDefined(MacroNameTok, MD); 548 } 549 550 void MacroUndefined(const Token &MacroNameTok, 551 const MacroDefinition &MD, 552 const MacroDirective *Undef) override { 553 First->MacroUndefined(MacroNameTok, MD, Undef); 554 Second->MacroUndefined(MacroNameTok, MD, Undef); 555 } 556 557 void Defined(const Token &MacroNameTok, const MacroDefinition &MD, 558 SourceRange Range) override { 559 First->Defined(MacroNameTok, MD, Range); 560 Second->Defined(MacroNameTok, MD, Range); 561 } 562 563 void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override { 564 First->SourceRangeSkipped(Range, EndifLoc); 565 Second->SourceRangeSkipped(Range, EndifLoc); 566 } 567 568 /// Hook called whenever an \#if is seen. 569 void If(SourceLocation Loc, SourceRange ConditionRange, 570 ConditionValueKind ConditionValue) override { 571 First->If(Loc, ConditionRange, ConditionValue); 572 Second->If(Loc, ConditionRange, ConditionValue); 573 } 574 575 /// Hook called whenever an \#elif is seen. 576 void Elif(SourceLocation Loc, SourceRange ConditionRange, 577 ConditionValueKind ConditionValue, SourceLocation IfLoc) override { 578 First->Elif(Loc, ConditionRange, ConditionValue, IfLoc); 579 Second->Elif(Loc, ConditionRange, ConditionValue, IfLoc); 580 } 581 582 /// Hook called whenever an \#ifdef is seen. 583 void Ifdef(SourceLocation Loc, const Token &MacroNameTok, 584 const MacroDefinition &MD) override { 585 First->Ifdef(Loc, MacroNameTok, MD); 586 Second->Ifdef(Loc, MacroNameTok, MD); 587 } 588 589 /// Hook called whenever an \#ifndef is seen. 590 void Ifndef(SourceLocation Loc, const Token &MacroNameTok, 591 const MacroDefinition &MD) override { 592 First->Ifndef(Loc, MacroNameTok, MD); 593 Second->Ifndef(Loc, MacroNameTok, MD); 594 } 595 596 /// Hook called whenever an \#else is seen. 597 void Else(SourceLocation Loc, SourceLocation IfLoc) override { 598 First->Else(Loc, IfLoc); 599 Second->Else(Loc, IfLoc); 600 } 601 602 /// Hook called whenever an \#endif is seen. 603 void Endif(SourceLocation Loc, SourceLocation IfLoc) override { 604 First->Endif(Loc, IfLoc); 605 Second->Endif(Loc, IfLoc); 606 } 607 }; 608 609 } // end namespace clang 610 611 #endif 612