• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- PPCallbacks.h - Callbacks for Preprocessor actions -----*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Defines the PPCallbacks interface.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_LEX_PPCALLBACKS_H
16 #define LLVM_CLANG_LEX_PPCALLBACKS_H
17 
18 #include "clang/Basic/DiagnosticIDs.h"
19 #include "clang/Basic/SourceLocation.h"
20 #include "clang/Lex/DirectoryLookup.h"
21 #include "clang/Lex/ModuleLoader.h"
22 #include "llvm/ADT/StringRef.h"
23 #include <string>
24 
25 namespace clang {
26   class SourceLocation;
27   class Token;
28   class IdentifierInfo;
29   class MacroDirective;
30 
31 /// \brief 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   /// \brief 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   /// \brief Callback invoked whenever a source file is skipped as the result
53   /// of header guard optimization.
54   ///
55   /// \param ParentFile The file that \#included the skipped file.
56   ///
57   /// \param FilenameTok The token in ParentFile that indicates the
58   /// skipped file.
FileSkipped(const FileEntry & ParentFile,const Token & FilenameTok,SrcMgr::CharacteristicKind FileType)59   virtual void FileSkipped(const FileEntry &ParentFile,
60                            const Token &FilenameTok,
61                            SrcMgr::CharacteristicKind FileType) {
62   }
63 
64   /// \brief 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.
FileNotFound(StringRef FileName,SmallVectorImpl<char> & RecoveryPath)76   virtual bool FileNotFound(StringRef FileName,
77                             SmallVectorImpl<char> &RecoveryPath) {
78     return false;
79   }
80 
81   /// \brief 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   ///
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,const FileEntry * File,StringRef SearchPath,StringRef RelativePath,const Module * Imported)118   virtual void InclusionDirective(SourceLocation HashLoc,
119                                   const Token &IncludeTok,
120                                   StringRef FileName,
121                                   bool IsAngled,
122                                   CharSourceRange FilenameRange,
123                                   const FileEntry *File,
124                                   StringRef SearchPath,
125                                   StringRef RelativePath,
126                                   const Module *Imported) {
127   }
128 
129   /// \brief Callback invoked whenever there was an explicit module-import
130   /// syntax.
131   ///
132   /// \param ImportLoc The location of import directive token.
133   ///
134   /// \param Path The identifiers (and their locations) of the module
135   /// "path", e.g., "std.vector" would be split into "std" and "vector".
136   ///
137   /// \param Imported The imported module; can be null if importing failed.
138   ///
moduleImport(SourceLocation ImportLoc,ModuleIdPath Path,const Module * Imported)139   virtual void moduleImport(SourceLocation ImportLoc,
140                             ModuleIdPath Path,
141                             const Module *Imported) {
142   }
143 
144   /// \brief Callback invoked when the end of the main file is reached.
145   ///
146   /// No subsequent callbacks will be made.
EndOfMainFile()147   virtual void EndOfMainFile() {
148   }
149 
150   /// \brief Callback invoked when a \#ident or \#sccs directive is read.
151   /// \param Loc The location of the directive.
152   /// \param str The text of the directive.
153   ///
Ident(SourceLocation Loc,const std::string & str)154   virtual void Ident(SourceLocation Loc, const std::string &str) {
155   }
156 
157   /// \brief Callback invoked when a \#pragma comment directive is read.
PragmaComment(SourceLocation Loc,const IdentifierInfo * Kind,const std::string & Str)158   virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
159                              const std::string &Str) {
160   }
161 
162   /// \brief Callback invoked when a \#pragma message directive is read.
163   /// \param Loc The location of the message directive.
164   /// \param Str The text of the message directive.
PragmaMessage(SourceLocation Loc,StringRef Str)165   virtual void PragmaMessage(SourceLocation Loc, StringRef Str) {
166   }
167 
168   /// \brief Callback invoked when a \#pragma gcc dianostic push directive
169   /// is read.
PragmaDiagnosticPush(SourceLocation Loc,StringRef Namespace)170   virtual void PragmaDiagnosticPush(SourceLocation Loc,
171                                     StringRef Namespace) {
172   }
173 
174   /// \brief Callback invoked when a \#pragma gcc dianostic pop directive
175   /// is read.
PragmaDiagnosticPop(SourceLocation Loc,StringRef Namespace)176   virtual void PragmaDiagnosticPop(SourceLocation Loc,
177                                    StringRef Namespace) {
178   }
179 
180   /// \brief Callback invoked when a \#pragma gcc dianostic directive is read.
PragmaDiagnostic(SourceLocation Loc,StringRef Namespace,diag::Mapping mapping,StringRef Str)181   virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
182                                 diag::Mapping mapping, StringRef Str) {
183   }
184 
185   /// \brief Called by Preprocessor::HandleMacroExpandedIdentifier when a
186   /// macro invocation is found.
MacroExpands(const Token & MacroNameTok,const MacroDirective * MD,SourceRange Range)187   virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
188                             SourceRange Range) {
189   }
190 
191   /// \brief Hook called whenever a macro definition is seen.
MacroDefined(const Token & MacroNameTok,const MacroDirective * MD)192   virtual void MacroDefined(const Token &MacroNameTok,
193                             const MacroDirective *MD) {
194   }
195 
196   /// \brief Hook called whenever a macro \#undef is seen.
197   ///
198   /// MD is released immediately following this callback.
MacroUndefined(const Token & MacroNameTok,const MacroDirective * MD)199   virtual void MacroUndefined(const Token &MacroNameTok,
200                               const MacroDirective *MD) {
201   }
202 
203   /// \brief Hook called whenever the 'defined' operator is seen.
204   /// \param MD The MacroDirective if the name was a macro, null otherwise.
Defined(const Token & MacroNameTok,const MacroDirective * MD)205   virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD) {
206   }
207 
208   /// \brief Hook called when a source range is skipped.
209   /// \param Range The SourceRange that was skipped. The range begins at the
210   /// \#if/\#else directive and ends after the \#endif/\#else directive.
SourceRangeSkipped(SourceRange Range)211   virtual void SourceRangeSkipped(SourceRange Range) {
212   }
213 
214   /// \brief Hook called whenever an \#if is seen.
215   /// \param Loc the source location of the directive.
216   /// \param ConditionRange The SourceRange of the expression being tested.
217   ///
218   // FIXME: better to pass in a list (or tree!) of Tokens.
If(SourceLocation Loc,SourceRange ConditionRange)219   virtual void If(SourceLocation Loc, SourceRange ConditionRange) {
220   }
221 
222   /// \brief Hook called whenever an \#elif is seen.
223   /// \param Loc the source location of the directive.
224   /// \param ConditionRange The SourceRange of the expression being tested.
225   /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
226   // FIXME: better to pass in a list (or tree!) of Tokens.
Elif(SourceLocation Loc,SourceRange ConditionRange,SourceLocation IfLoc)227   virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
228                     SourceLocation IfLoc) {
229   }
230 
231   /// \brief Hook called whenever an \#ifdef is seen.
232   /// \param Loc the source location of the directive.
233   /// \param MacroNameTok Information on the token being tested.
234   /// \param MD The MacroDirective if the name was a macro, null otherwise.
Ifdef(SourceLocation Loc,const Token & MacroNameTok,const MacroDirective * MD)235   virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
236                      const MacroDirective *MD) {
237   }
238 
239   /// \brief Hook called whenever an \#ifndef is seen.
240   /// \param Loc the source location of the directive.
241   /// \param MacroNameTok Information on the token being tested.
242   /// \param MD The MacroDirective if the name was a macro, null otherwise.
Ifndef(SourceLocation Loc,const Token & MacroNameTok,const MacroDirective * MD)243   virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
244                       const MacroDirective *MD) {
245   }
246 
247   /// \brief Hook called whenever an \#else is seen.
248   /// \param Loc the source location of the directive.
249   /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
Else(SourceLocation Loc,SourceLocation IfLoc)250   virtual void Else(SourceLocation Loc, SourceLocation IfLoc) {
251   }
252 
253   /// \brief Hook called whenever an \#endif is seen.
254   /// \param Loc the source location of the directive.
255   /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
Endif(SourceLocation Loc,SourceLocation IfLoc)256   virtual void Endif(SourceLocation Loc, SourceLocation IfLoc) {
257   }
258 };
259 
260 /// \brief Simple wrapper class for chaining callbacks.
261 class PPChainedCallbacks : public PPCallbacks {
262   virtual void anchor();
263   PPCallbacks *First, *Second;
264 
265 public:
PPChainedCallbacks(PPCallbacks * _First,PPCallbacks * _Second)266   PPChainedCallbacks(PPCallbacks *_First, PPCallbacks *_Second)
267     : First(_First), Second(_Second) {}
~PPChainedCallbacks()268   ~PPChainedCallbacks() {
269     delete Second;
270     delete First;
271   }
272 
FileChanged(SourceLocation Loc,FileChangeReason Reason,SrcMgr::CharacteristicKind FileType,FileID PrevFID)273   virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
274                            SrcMgr::CharacteristicKind FileType,
275                            FileID PrevFID) {
276     First->FileChanged(Loc, Reason, FileType, PrevFID);
277     Second->FileChanged(Loc, Reason, FileType, PrevFID);
278   }
279 
FileSkipped(const FileEntry & ParentFile,const Token & FilenameTok,SrcMgr::CharacteristicKind FileType)280   virtual void FileSkipped(const FileEntry &ParentFile,
281                            const Token &FilenameTok,
282                            SrcMgr::CharacteristicKind FileType) {
283     First->FileSkipped(ParentFile, FilenameTok, FileType);
284     Second->FileSkipped(ParentFile, FilenameTok, FileType);
285   }
286 
FileNotFound(StringRef FileName,SmallVectorImpl<char> & RecoveryPath)287   virtual bool FileNotFound(StringRef FileName,
288                             SmallVectorImpl<char> &RecoveryPath) {
289     return First->FileNotFound(FileName, RecoveryPath) ||
290            Second->FileNotFound(FileName, RecoveryPath);
291   }
292 
InclusionDirective(SourceLocation HashLoc,const Token & IncludeTok,StringRef FileName,bool IsAngled,CharSourceRange FilenameRange,const FileEntry * File,StringRef SearchPath,StringRef RelativePath,const Module * Imported)293   virtual void InclusionDirective(SourceLocation HashLoc,
294                                   const Token &IncludeTok,
295                                   StringRef FileName,
296                                   bool IsAngled,
297                                   CharSourceRange FilenameRange,
298                                   const FileEntry *File,
299                                   StringRef SearchPath,
300                                   StringRef RelativePath,
301                                   const Module *Imported) {
302     First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled,
303                               FilenameRange, File, SearchPath, RelativePath,
304                               Imported);
305     Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled,
306                                FilenameRange, File, SearchPath, RelativePath,
307                                Imported);
308   }
309 
moduleImport(SourceLocation ImportLoc,ModuleIdPath Path,const Module * Imported)310   virtual void moduleImport(SourceLocation ImportLoc,
311                             ModuleIdPath Path,
312                             const Module *Imported) {
313     First->moduleImport(ImportLoc, Path, Imported);
314     Second->moduleImport(ImportLoc, Path, Imported);
315   }
316 
EndOfMainFile()317   virtual void EndOfMainFile() {
318     First->EndOfMainFile();
319     Second->EndOfMainFile();
320   }
321 
Ident(SourceLocation Loc,const std::string & str)322   virtual void Ident(SourceLocation Loc, const std::string &str) {
323     First->Ident(Loc, str);
324     Second->Ident(Loc, str);
325   }
326 
PragmaComment(SourceLocation Loc,const IdentifierInfo * Kind,const std::string & Str)327   virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
328                              const std::string &Str) {
329     First->PragmaComment(Loc, Kind, Str);
330     Second->PragmaComment(Loc, Kind, Str);
331   }
332 
PragmaMessage(SourceLocation Loc,StringRef Str)333   virtual void PragmaMessage(SourceLocation Loc, StringRef Str) {
334     First->PragmaMessage(Loc, Str);
335     Second->PragmaMessage(Loc, Str);
336   }
337 
PragmaDiagnosticPush(SourceLocation Loc,StringRef Namespace)338   virtual void PragmaDiagnosticPush(SourceLocation Loc,
339                                     StringRef Namespace) {
340     First->PragmaDiagnosticPush(Loc, Namespace);
341     Second->PragmaDiagnosticPush(Loc, Namespace);
342   }
343 
PragmaDiagnosticPop(SourceLocation Loc,StringRef Namespace)344   virtual void PragmaDiagnosticPop(SourceLocation Loc,
345                                     StringRef Namespace) {
346     First->PragmaDiagnosticPop(Loc, Namespace);
347     Second->PragmaDiagnosticPop(Loc, Namespace);
348   }
349 
PragmaDiagnostic(SourceLocation Loc,StringRef Namespace,diag::Mapping mapping,StringRef Str)350   virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
351                                 diag::Mapping mapping, StringRef Str) {
352     First->PragmaDiagnostic(Loc, Namespace, mapping, Str);
353     Second->PragmaDiagnostic(Loc, Namespace, mapping, Str);
354   }
355 
MacroExpands(const Token & MacroNameTok,const MacroDirective * MD,SourceRange Range)356   virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
357                             SourceRange Range) {
358     First->MacroExpands(MacroNameTok, MD, Range);
359     Second->MacroExpands(MacroNameTok, MD, Range);
360   }
361 
MacroDefined(const Token & MacroNameTok,const MacroDirective * MD)362   virtual void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) {
363     First->MacroDefined(MacroNameTok, MD);
364     Second->MacroDefined(MacroNameTok, MD);
365   }
366 
MacroUndefined(const Token & MacroNameTok,const MacroDirective * MD)367   virtual void MacroUndefined(const Token &MacroNameTok,
368                               const MacroDirective *MD) {
369     First->MacroUndefined(MacroNameTok, MD);
370     Second->MacroUndefined(MacroNameTok, MD);
371   }
372 
Defined(const Token & MacroNameTok,const MacroDirective * MD)373   virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD) {
374     First->Defined(MacroNameTok, MD);
375     Second->Defined(MacroNameTok, MD);
376   }
377 
SourceRangeSkipped(SourceRange Range)378   virtual void SourceRangeSkipped(SourceRange Range) {
379     First->SourceRangeSkipped(Range);
380     Second->SourceRangeSkipped(Range);
381   }
382 
383   /// \brief Hook called whenever an \#if is seen.
If(SourceLocation Loc,SourceRange ConditionRange)384   virtual void If(SourceLocation Loc, SourceRange ConditionRange) {
385     First->If(Loc, ConditionRange);
386     Second->If(Loc, ConditionRange);
387   }
388 
389   /// \brief Hook called whenever an \#if is seen.
Elif(SourceLocation Loc,SourceRange ConditionRange,SourceLocation IfLoc)390   virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
391                     SourceLocation IfLoc) {
392     First->Elif(Loc, ConditionRange, IfLoc);
393     Second->Elif(Loc, ConditionRange, IfLoc);
394   }
395 
396   /// \brief Hook called whenever an \#ifdef is seen.
Ifdef(SourceLocation Loc,const Token & MacroNameTok,const MacroDirective * MD)397   virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
398                      const MacroDirective *MD) {
399     First->Ifdef(Loc, MacroNameTok, MD);
400     Second->Ifdef(Loc, MacroNameTok, MD);
401   }
402 
403   /// \brief Hook called whenever an \#ifndef is seen.
Ifndef(SourceLocation Loc,const Token & MacroNameTok,const MacroDirective * MD)404   virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
405                       const MacroDirective *MD) {
406     First->Ifndef(Loc, MacroNameTok, MD);
407     Second->Ifndef(Loc, MacroNameTok, MD);
408   }
409 
410   /// \brief Hook called whenever an \#else is seen.
Else(SourceLocation Loc,SourceLocation IfLoc)411   virtual void Else(SourceLocation Loc, SourceLocation IfLoc) {
412     First->Else(Loc, IfLoc);
413     Second->Else(Loc, IfLoc);
414   }
415 
416   /// \brief Hook called whenever an \#endif is seen.
Endif(SourceLocation Loc,SourceLocation IfLoc)417   virtual void Endif(SourceLocation Loc, SourceLocation IfLoc) {
418     First->Endif(Loc, IfLoc);
419     Second->Endif(Loc, IfLoc);
420   }
421 };
422 
423 }  // end namespace clang
424 
425 #endif
426