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_LEX_MULTIPLEINCLUDEOPT_H
     16 #define LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H
     17 
     18 #include "clang/Basic/SourceLocation.h"
     19 
     20 namespace clang {
     21 class IdentifierInfo;
     22 
     23 /// \brief Implements the simple state machine that the Lexer class uses to
     24 /// detect files subject to the 'multiple-include' optimization.
     25 ///
     26 /// The public methods in this class are triggered by various
     27 /// events that occur when a file is lexed, and after the entire file is lexed,
     28 /// information about which macro (if any) controls the header is returned.
     29 class MultipleIncludeOpt {
     30   /// ReadAnyTokens - This is set to false when a file is first opened and true
     31   /// any time a token is returned to the client or a (non-multiple-include)
     32   /// directive is parsed.  When the final \#endif is parsed this is reset back
     33   /// to false, that way any tokens before the first \#ifdef or after the last
     34   /// \#endif can be easily detected.
     35   bool ReadAnyTokens;
     36 
     37   /// ImmediatelyAfterTopLevelIfndef - This is true when the only tokens
     38   /// processed in the file so far is an #ifndef and an identifier.  Used in
     39   /// the detection of header guards in a file.
     40   bool ImmediatelyAfterTopLevelIfndef;
     41 
     42   /// ReadAnyTokens - This is set to false when a file is first opened and true
     43   /// any time a token is returned to the client or a (non-multiple-include)
     44   /// directive is parsed.  When the final #endif is parsed this is reset back
     45   /// to false, that way any tokens before the first #ifdef or after the last
     46   /// #endif can be easily detected.
     47   bool DidMacroExpansion;
     48 
     49   /// TheMacro - The controlling macro for a file, if valid.
     50   ///
     51   const IdentifierInfo *TheMacro;
     52 
     53   /// DefinedMacro - The macro defined right after TheMacro, if any.
     54   const IdentifierInfo *DefinedMacro;
     55 
     56   SourceLocation MacroLoc;
     57   SourceLocation DefinedLoc;
     58 public:
     59   MultipleIncludeOpt() {
     60     ReadAnyTokens = false;
     61     ImmediatelyAfterTopLevelIfndef = false;
     62     DidMacroExpansion = false;
     63     TheMacro = nullptr;
     64     DefinedMacro = nullptr;
     65   }
     66 
     67   SourceLocation GetMacroLocation() const {
     68     return MacroLoc;
     69   }
     70 
     71   SourceLocation GetDefinedLocation() const {
     72     return DefinedLoc;
     73   }
     74 
     75   void resetImmediatelyAfterTopLevelIfndef() {
     76     ImmediatelyAfterTopLevelIfndef = false;
     77   }
     78 
     79   void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc) {
     80     DefinedMacro = M;
     81     DefinedLoc = Loc;
     82   }
     83 
     84   /// Invalidate - Permanently mark this file as not being suitable for the
     85   /// include-file optimization.
     86   void Invalidate() {
     87     // If we have read tokens but have no controlling macro, the state-machine
     88     // below can never "accept".
     89     ReadAnyTokens = true;
     90     ImmediatelyAfterTopLevelIfndef = false;
     91     DefinedMacro = nullptr;
     92     TheMacro = nullptr;
     93   }
     94 
     95   /// getHasReadAnyTokensVal - This is used for the \#ifndef hande-shake at the
     96   /// top of the file when reading preprocessor directives.  Otherwise, reading
     97   /// the "ifndef x" would count as reading tokens.
     98   bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
     99 
    100   /// getImmediatelyAfterTopLevelIfndef - returns true if the last directive
    101   /// was an #ifndef at the beginning of the file.
    102   bool getImmediatelyAfterTopLevelIfndef() const {
    103     return ImmediatelyAfterTopLevelIfndef;
    104   }
    105 
    106   // If a token is read, remember that we have seen a side-effect in this file.
    107   void ReadToken() {
    108     ReadAnyTokens = true;
    109     ImmediatelyAfterTopLevelIfndef = false;
    110   }
    111 
    112   /// ExpandedMacro - When a macro is expanded with this lexer as the current
    113   /// buffer, this method is called to disable the MIOpt if needed.
    114   void ExpandedMacro() { DidMacroExpansion = true; }
    115 
    116   /// \brief Called when entering a top-level \#ifndef directive (or the
    117   /// "\#if !defined" equivalent) without any preceding tokens.
    118   ///
    119   /// Note, we don't care about the input value of 'ReadAnyTokens'.  The caller
    120   /// ensures that this is only called if there are no tokens read before the
    121   /// \#ifndef.  The caller is required to do this, because reading the \#if
    122   /// line obviously reads in in tokens.
    123   void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc) {
    124     // If the macro is already set, this is after the top-level #endif.
    125     if (TheMacro)
    126       return Invalidate();
    127 
    128     // If we have already expanded a macro by the end of the #ifndef line, then
    129     // there is a macro expansion *in* the #ifndef line.  This means that the
    130     // condition could evaluate differently when subsequently #included.  Reject
    131     // this.
    132     if (DidMacroExpansion)
    133       return Invalidate();
    134 
    135     // Remember that we're in the #if and that we have the macro.
    136     ReadAnyTokens = true;
    137     ImmediatelyAfterTopLevelIfndef = true;
    138     TheMacro = M;
    139     MacroLoc = Loc;
    140   }
    141 
    142   /// \brief Invoked when a top level conditional (except \#ifndef) is found.
    143   void EnterTopLevelConditional() {
    144     // If a conditional directive (except #ifndef) is found at the top level,
    145     // there is a chunk of the file not guarded by the controlling macro.
    146     Invalidate();
    147   }
    148 
    149   /// \brief Called when the lexer exits the top-level conditional.
    150   void ExitTopLevelConditional() {
    151     // If we have a macro, that means the top of the file was ok.  Set our state
    152     // back to "not having read any tokens" so we can detect anything after the
    153     // #endif.
    154     if (!TheMacro) return Invalidate();
    155 
    156     // At this point, we haven't "read any tokens" but we do have a controlling
    157     // macro.
    158     ReadAnyTokens = false;
    159     ImmediatelyAfterTopLevelIfndef = false;
    160   }
    161 
    162   /// \brief Once the entire file has been lexed, if there is a controlling
    163   /// macro, return it.
    164   const IdentifierInfo *GetControllingMacroAtEndOfFile() const {
    165     // If we haven't read any tokens after the #endif, return the controlling
    166     // macro if it's valid (if it isn't, it will be null).
    167     if (!ReadAnyTokens)
    168       return TheMacro;
    169     return nullptr;
    170   }
    171 
    172   /// \brief If the ControllingMacro is followed by a macro definition, return
    173   /// the macro that was defined.
    174   const IdentifierInfo *GetDefinedMacro() const {
    175     return DefinedMacro;
    176   }
    177 };
    178 
    179 }  // end namespace clang
    180 
    181 #endif
    182