Home | History | Annotate | Download | only in Lex
      1 //===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- 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 //  This file defines the MultipleIncludeOpt interface.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H
     15 #define LLVM_CLANG_MULTIPLEINCLUDEOPT_H
     16 
     17 namespace clang {
     18 class IdentifierInfo;
     19 
     20 /// MultipleIncludeOpt - This class implements the simple state machine that the
     21 /// Lexer class uses to detect files subject to the 'multiple-include'
     22 /// optimization.  The public methods in this class are triggered by various
     23 /// events that occur when a file is lexed, and after the entire file is lexed,
     24 /// information about which macro (if any) controls the header is returned.
     25 class MultipleIncludeOpt {
     26   /// ReadAnyTokens - This is set to false when a file is first opened and true
     27   /// any time a token is returned to the client or a (non-multiple-include)
     28   /// directive is parsed.  When the final #endif is parsed this is reset back
     29   /// to false, that way any tokens before the first #ifdef or after the last
     30   /// #endif can be easily detected.
     31   bool ReadAnyTokens;
     32 
     33   /// ReadAnyTokens - This is set to false when a file is first opened and true
     34   /// any time a token is returned to the client or a (non-multiple-include)
     35   /// directive is parsed.  When the final #endif is parsed this is reset back
     36   /// to false, that way any tokens before the first #ifdef or after the last
     37   /// #endif can be easily detected.
     38   bool DidMacroExpansion;
     39 
     40   /// TheMacro - The controlling macro for a file, if valid.
     41   ///
     42   const IdentifierInfo *TheMacro;
     43 public:
     44   MultipleIncludeOpt() {
     45     ReadAnyTokens = false;
     46     DidMacroExpansion = false;
     47     TheMacro = 0;
     48   }
     49 
     50   /// Invalidate - Permanently mark this file as not being suitable for the
     51   /// include-file optimization.
     52   void Invalidate() {
     53     // If we have read tokens but have no controlling macro, the state-machine
     54     // below can never "accept".
     55     ReadAnyTokens = true;
     56     TheMacro = 0;
     57   }
     58 
     59   /// getHasReadAnyTokensVal - This is used for the #ifndef hande-shake at the
     60   /// top of the file when reading preprocessor directives.  Otherwise, reading
     61   /// the "ifndef x" would count as reading tokens.
     62   bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
     63 
     64   // If a token is read, remember that we have seen a side-effect in this file.
     65   void ReadToken() { ReadAnyTokens = true; }
     66 
     67   /// ExpandedMacro - When a macro is expanded with this lexer as the current
     68   /// buffer, this method is called to disable the MIOpt if needed.
     69   void ExpandedMacro() { DidMacroExpansion = true; }
     70 
     71   /// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the
     72   /// "#if !defined" equivalent) without any preceding tokens, this method is
     73   /// called.
     74   ///
     75   /// Note, we don't care about the input value of 'ReadAnyTokens'.  The caller
     76   /// ensures that this is only called if there are no tokens read before the
     77   /// #ifndef.  The caller is required to do this, because reading the #if line
     78   /// obviously reads in in tokens.
     79   void EnterTopLevelIFNDEF(const IdentifierInfo *M) {
     80     // If the macro is already set, this is after the top-level #endif.
     81     if (TheMacro)
     82       return Invalidate();
     83 
     84     // If we have already expanded a macro by the end of the #ifndef line, then
     85     // there is a macro expansion *in* the #ifndef line.  This means that the
     86     // condition could evaluate differently when subsequently #included.  Reject
     87     // this.
     88     if (DidMacroExpansion)
     89       return Invalidate();
     90 
     91     // Remember that we're in the #if and that we have the macro.
     92     ReadAnyTokens = true;
     93     TheMacro = M;
     94   }
     95 
     96   /// EnterTopLevelConditional - This is invoked when a top level conditional
     97   /// (except #ifndef) is found.
     98   void EnterTopLevelConditional() {
     99     /// If a conditional directive (except #ifndef) is found at the top level,
    100     /// there is a chunk of the file not guarded by the controlling macro.
    101     Invalidate();
    102   }
    103 
    104   /// ExitTopLevelConditional - This method is called when the lexer exits the
    105   /// top-level conditional.
    106   void ExitTopLevelConditional() {
    107     // If we have a macro, that means the top of the file was ok.  Set our state
    108     // back to "not having read any tokens" so we can detect anything after the
    109     // #endif.
    110     if (!TheMacro) return Invalidate();
    111 
    112     // At this point, we haven't "read any tokens" but we do have a controlling
    113     // macro.
    114     ReadAnyTokens = false;
    115   }
    116 
    117   /// GetControllingMacroAtEndOfFile - Once the entire file has been lexed, if
    118   /// there is a controlling macro, return it.
    119   const IdentifierInfo *GetControllingMacroAtEndOfFile() const {
    120     // If we haven't read any tokens after the #endif, return the controlling
    121     // macro if it's valid (if it isn't, it will be null).
    122     if (!ReadAnyTokens)
    123       return TheMacro;
    124     return 0;
    125   }
    126 };
    127 
    128 }  // end namespace clang
    129 
    130 #endif
    131