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 virtual void anchor(); 378 std::unique_ptr<PPCallbacks> First, Second; 379 380 public: 381 PPChainedCallbacks(std::unique_ptr<PPCallbacks> _First, 382 std::unique_ptr<PPCallbacks> _Second) 383 : First(std::move(_First)), Second(std::move(_Second)) {} 384 385 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 386 SrcMgr::CharacteristicKind FileType, 387 FileID PrevFID) override { 388 First->FileChanged(Loc, Reason, FileType, PrevFID); 389 Second->FileChanged(Loc, Reason, FileType, PrevFID); 390 } 391 392 void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok, 393 SrcMgr::CharacteristicKind FileType) override { 394 First->FileSkipped(SkippedFile, FilenameTok, FileType); 395 Second->FileSkipped(SkippedFile, FilenameTok, FileType); 396 } 397 398 bool FileNotFound(StringRef FileName, 399 SmallVectorImpl<char> &RecoveryPath) override { 400 return First->FileNotFound(FileName, RecoveryPath) || 401 Second->FileNotFound(FileName, RecoveryPath); 402 } 403 404 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 405 StringRef FileName, bool IsAngled, 406 CharSourceRange FilenameRange, const FileEntry *File, 407 StringRef SearchPath, StringRef RelativePath, 408 const Module *Imported, 409 SrcMgr::CharacteristicKind FileType) override { 410 First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, 411 FilenameRange, File, SearchPath, RelativePath, 412 Imported, FileType); 413 Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, 414 FilenameRange, File, SearchPath, RelativePath, 415 Imported, FileType); 416 } 417 418 void EnteredSubmodule(Module *M, SourceLocation ImportLoc, 419 bool ForPragma) override { 420 First->EnteredSubmodule(M, ImportLoc, ForPragma); 421 Second->EnteredSubmodule(M, ImportLoc, ForPragma); 422 } 423 424 void LeftSubmodule(Module *M, SourceLocation ImportLoc, 425 bool ForPragma) override { 426 First->LeftSubmodule(M, ImportLoc, ForPragma); 427 Second->LeftSubmodule(M, ImportLoc, ForPragma); 428 } 429 430 void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, 431 const Module *Imported) override { 432 First->moduleImport(ImportLoc, Path, Imported); 433 Second->moduleImport(ImportLoc, Path, Imported); 434 } 435 436 void EndOfMainFile() override { 437 First->EndOfMainFile(); 438 Second->EndOfMainFile(); 439 } 440 441 void Ident(SourceLocation Loc, StringRef str) override { 442 First->Ident(Loc, str); 443 Second->Ident(Loc, str); 444 } 445 446 void PragmaDirective(SourceLocation Loc, 447 PragmaIntroducerKind Introducer) override { 448 First->PragmaDirective(Loc, Introducer); 449 Second->PragmaDirective(Loc, Introducer); 450 } 451 452 void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, 453 StringRef Str) override { 454 First->PragmaComment(Loc, Kind, Str); 455 Second->PragmaComment(Loc, Kind, Str); 456 } 457 458 void PragmaDetectMismatch(SourceLocation Loc, StringRef Name, 459 StringRef Value) override { 460 First->PragmaDetectMismatch(Loc, Name, Value); 461 Second->PragmaDetectMismatch(Loc, Name, Value); 462 } 463 464 void PragmaDebug(SourceLocation Loc, StringRef DebugType) override { 465 First->PragmaDebug(Loc, DebugType); 466 Second->PragmaDebug(Loc, DebugType); 467 } 468 469 void PragmaMessage(SourceLocation Loc, StringRef Namespace, 470 PragmaMessageKind Kind, StringRef Str) override { 471 First->PragmaMessage(Loc, Namespace, Kind, Str); 472 Second->PragmaMessage(Loc, Namespace, Kind, Str); 473 } 474 475 void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) override { 476 First->PragmaDiagnosticPush(Loc, Namespace); 477 Second->PragmaDiagnosticPush(Loc, Namespace); 478 } 479 480 void PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) override { 481 First->PragmaDiagnosticPop(Loc, Namespace); 482 Second->PragmaDiagnosticPop(Loc, Namespace); 483 } 484 485 void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, 486 diag::Severity mapping, StringRef Str) override { 487 First->PragmaDiagnostic(Loc, Namespace, mapping, Str); 488 Second->PragmaDiagnostic(Loc, Namespace, mapping, Str); 489 } 490 491 void HasInclude(SourceLocation Loc, StringRef FileName, bool IsAngled, 492 Optional<FileEntryRef> File, 493 SrcMgr::CharacteristicKind FileType) override { 494 First->HasInclude(Loc, FileName, IsAngled, File, FileType); 495 Second->HasInclude(Loc, FileName, IsAngled, File, FileType); 496 } 497 498 void PragmaOpenCLExtension(SourceLocation NameLoc, const IdentifierInfo *Name, 499 SourceLocation StateLoc, unsigned State) override { 500 First->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State); 501 Second->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State); 502 } 503 504 void PragmaWarning(SourceLocation Loc, StringRef WarningSpec, 505 ArrayRef<int> Ids) override { 506 First->PragmaWarning(Loc, WarningSpec, Ids); 507 Second->PragmaWarning(Loc, WarningSpec, Ids); 508 } 509 510 void PragmaWarningPush(SourceLocation Loc, int Level) override { 511 First->PragmaWarningPush(Loc, Level); 512 Second->PragmaWarningPush(Loc, Level); 513 } 514 515 void PragmaWarningPop(SourceLocation Loc) override { 516 First->PragmaWarningPop(Loc); 517 Second->PragmaWarningPop(Loc); 518 } 519 520 void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) override { 521 First->PragmaExecCharsetPush(Loc, Str); 522 Second->PragmaExecCharsetPush(Loc, Str); 523 } 524 525 void PragmaExecCharsetPop(SourceLocation Loc) override { 526 First->PragmaExecCharsetPop(Loc); 527 Second->PragmaExecCharsetPop(Loc); 528 } 529 530 void PragmaAssumeNonNullBegin(SourceLocation Loc) override { 531 First->PragmaAssumeNonNullBegin(Loc); 532 Second->PragmaAssumeNonNullBegin(Loc); 533 } 534 535 void PragmaAssumeNonNullEnd(SourceLocation Loc) override { 536 First->PragmaAssumeNonNullEnd(Loc); 537 Second->PragmaAssumeNonNullEnd(Loc); 538 } 539 540 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, 541 SourceRange Range, const MacroArgs *Args) override { 542 First->MacroExpands(MacroNameTok, MD, Range, Args); 543 Second->MacroExpands(MacroNameTok, MD, Range, Args); 544 } 545 546 void MacroDefined(const Token &MacroNameTok, 547 const MacroDirective *MD) override { 548 First->MacroDefined(MacroNameTok, MD); 549 Second->MacroDefined(MacroNameTok, MD); 550 } 551 552 void MacroUndefined(const Token &MacroNameTok, 553 const MacroDefinition &MD, 554 const MacroDirective *Undef) override { 555 First->MacroUndefined(MacroNameTok, MD, Undef); 556 Second->MacroUndefined(MacroNameTok, MD, Undef); 557 } 558 559 void Defined(const Token &MacroNameTok, const MacroDefinition &MD, 560 SourceRange Range) override { 561 First->Defined(MacroNameTok, MD, Range); 562 Second->Defined(MacroNameTok, MD, Range); 563 } 564 565 void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override { 566 First->SourceRangeSkipped(Range, EndifLoc); 567 Second->SourceRangeSkipped(Range, EndifLoc); 568 } 569 570 /// Hook called whenever an \#if is seen. 571 void If(SourceLocation Loc, SourceRange ConditionRange, 572 ConditionValueKind ConditionValue) override { 573 First->If(Loc, ConditionRange, ConditionValue); 574 Second->If(Loc, ConditionRange, ConditionValue); 575 } 576 577 /// Hook called whenever an \#elif is seen. 578 void Elif(SourceLocation Loc, SourceRange ConditionRange, 579 ConditionValueKind ConditionValue, SourceLocation IfLoc) override { 580 First->Elif(Loc, ConditionRange, ConditionValue, IfLoc); 581 Second->Elif(Loc, ConditionRange, ConditionValue, IfLoc); 582 } 583 584 /// Hook called whenever an \#ifdef is seen. 585 void Ifdef(SourceLocation Loc, const Token &MacroNameTok, 586 const MacroDefinition &MD) override { 587 First->Ifdef(Loc, MacroNameTok, MD); 588 Second->Ifdef(Loc, MacroNameTok, MD); 589 } 590 591 /// Hook called whenever an \#ifndef is seen. 592 void Ifndef(SourceLocation Loc, const Token &MacroNameTok, 593 const MacroDefinition &MD) override { 594 First->Ifndef(Loc, MacroNameTok, MD); 595 Second->Ifndef(Loc, MacroNameTok, MD); 596 } 597 598 /// Hook called whenever an \#else is seen. 599 void Else(SourceLocation Loc, SourceLocation IfLoc) override { 600 First->Else(Loc, IfLoc); 601 Second->Else(Loc, IfLoc); 602 } 603 604 /// Hook called whenever an \#endif is seen. 605 void Endif(SourceLocation Loc, SourceLocation IfLoc) override { 606 First->Endif(Loc, IfLoc); 607 Second->Endif(Loc, IfLoc); 608 } 609 }; 610 611 } // end namespace clang 612 613 #endif 614