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