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