clang API Documentation

MultipleIncludeOpt.h
Go to the documentation of this file.
00001 //===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines the MultipleIncludeOpt interface.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H
00015 #define LLVM_CLANG_MULTIPLEINCLUDEOPT_H
00016 
00017 namespace clang {
00018 class IdentifierInfo;
00019 
00020 /// MultipleIncludeOpt - This class implements the simple state machine that the
00021 /// Lexer class uses to detect files subject to the 'multiple-include'
00022 /// optimization.  The public methods in this class are triggered by various
00023 /// events that occur when a file is lexed, and after the entire file is lexed,
00024 /// information about which macro (if any) controls the header is returned.
00025 class MultipleIncludeOpt {
00026   /// ReadAnyTokens - This is set to false when a file is first opened and true
00027   /// any time a token is returned to the client or a (non-multiple-include)
00028   /// directive is parsed.  When the final #endif is parsed this is reset back
00029   /// to false, that way any tokens before the first #ifdef or after the last
00030   /// #endif can be easily detected.
00031   bool ReadAnyTokens;
00032 
00033   /// ReadAnyTokens - This is set to false when a file is first opened and true
00034   /// any time a token is returned to the client or a (non-multiple-include)
00035   /// directive is parsed.  When the final #endif is parsed this is reset back
00036   /// to false, that way any tokens before the first #ifdef or after the last
00037   /// #endif can be easily detected.
00038   bool DidMacroExpansion;
00039 
00040   /// TheMacro - The controlling macro for a file, if valid.
00041   ///
00042   const IdentifierInfo *TheMacro;
00043 public:
00044   MultipleIncludeOpt() {
00045     ReadAnyTokens = false;
00046     DidMacroExpansion = false;
00047     TheMacro = 0;
00048   }
00049 
00050   /// Invalidate - Permanently mark this file as not being suitable for the
00051   /// include-file optimization.
00052   void Invalidate() {
00053     // If we have read tokens but have no controlling macro, the state-machine
00054     // below can never "accept".
00055     ReadAnyTokens = true;
00056     TheMacro = 0;
00057   }
00058 
00059   /// getHasReadAnyTokensVal - This is used for the #ifndef hande-shake at the
00060   /// top of the file when reading preprocessor directives.  Otherwise, reading
00061   /// the "ifndef x" would count as reading tokens.
00062   bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
00063 
00064   // If a token is read, remember that we have seen a side-effect in this file.
00065   void ReadToken() { ReadAnyTokens = true; }
00066 
00067   /// ExpandedMacro - When a macro is expanded with this lexer as the current
00068   /// buffer, this method is called to disable the MIOpt if needed.
00069   void ExpandedMacro() { DidMacroExpansion = true; }
00070 
00071   /// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the
00072   /// "#if !defined" equivalent) without any preceding tokens, this method is
00073   /// called.
00074   ///
00075   /// Note, we don't care about the input value of 'ReadAnyTokens'.  The caller
00076   /// ensures that this is only called if there are no tokens read before the
00077   /// #ifndef.  The caller is required to do this, because reading the #if line
00078   /// obviously reads in in tokens.
00079   void EnterTopLevelIFNDEF(const IdentifierInfo *M) {
00080     // If the macro is already set, this is after the top-level #endif.
00081     if (TheMacro)
00082       return Invalidate();
00083 
00084     // If we have already expanded a macro by the end of the #ifndef line, then
00085     // there is a macro expansion *in* the #ifndef line.  This means that the
00086     // condition could evaluate differently when subsequently #included.  Reject
00087     // this.
00088     if (DidMacroExpansion)
00089       return Invalidate();
00090 
00091     // Remember that we're in the #if and that we have the macro.
00092     ReadAnyTokens = true;
00093     TheMacro = M;
00094   }
00095 
00096   /// EnterTopLevelConditional - This is invoked when a top level conditional
00097   /// (except #ifndef) is found.
00098   void EnterTopLevelConditional() {
00099     /// If a conditional directive (except #ifndef) is found at the top level,
00100     /// there is a chunk of the file not guarded by the controlling macro.
00101     Invalidate();
00102   }
00103 
00104   /// ExitTopLevelConditional - This method is called when the lexer exits the
00105   /// top-level conditional.
00106   void ExitTopLevelConditional() {
00107     // If we have a macro, that means the top of the file was ok.  Set our state
00108     // back to "not having read any tokens" so we can detect anything after the
00109     // #endif.
00110     if (!TheMacro) return Invalidate();
00111 
00112     // At this point, we haven't "read any tokens" but we do have a controlling
00113     // macro.
00114     ReadAnyTokens = false;
00115   }
00116 
00117   /// GetControllingMacroAtEndOfFile - Once the entire file has been lexed, if
00118   /// there is a controlling macro, return it.
00119   const IdentifierInfo *GetControllingMacroAtEndOfFile() const {
00120     // If we haven't read any tokens after the #endif, return the controlling
00121     // macro if it's valid (if it isn't, it will be null).
00122     if (!ReadAnyTokens)
00123       return TheMacro;
00124     return 0;
00125   }
00126 };
00127 
00128 }  // end namespace clang
00129 
00130 #endif