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 /// \file
00011 /// \brief Defines the MultipleIncludeOpt interface.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #ifndef LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H
00016 #define LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H
00017 
00018 #include "clang/Basic/SourceLocation.h"
00019 
00020 namespace clang {
00021 class IdentifierInfo;
00022 
00023 /// \brief Implements the simple state machine that the Lexer class uses to
00024 /// detect files subject to the 'multiple-include' optimization.
00025 ///
00026 /// The public methods in this class are triggered by various
00027 /// events that occur when a file is lexed, and after the entire file is lexed,
00028 /// information about which macro (if any) controls the header is returned.
00029 class MultipleIncludeOpt {
00030   /// ReadAnyTokens - This is set to false when a file is first opened and true
00031   /// any time a token is returned to the client or a (non-multiple-include)
00032   /// directive is parsed.  When the final \#endif is parsed this is reset back
00033   /// to false, that way any tokens before the first \#ifdef or after the last
00034   /// \#endif can be easily detected.
00035   bool ReadAnyTokens;
00036 
00037   /// ImmediatelyAfterTopLevelIfndef - This is true when the only tokens
00038   /// processed in the file so far is an #ifndef and an identifier.  Used in
00039   /// the detection of header guards in a file.
00040   bool ImmediatelyAfterTopLevelIfndef;
00041 
00042   /// ReadAnyTokens - This is set to false when a file is first opened and true
00043   /// any time a token is returned to the client or a (non-multiple-include)
00044   /// directive is parsed.  When the final #endif is parsed this is reset back
00045   /// to false, that way any tokens before the first #ifdef or after the last
00046   /// #endif can be easily detected.
00047   bool DidMacroExpansion;
00048 
00049   /// TheMacro - The controlling macro for a file, if valid.
00050   ///
00051   const IdentifierInfo *TheMacro;
00052 
00053   /// DefinedMacro - The macro defined right after TheMacro, if any.
00054   const IdentifierInfo *DefinedMacro;
00055 
00056   SourceLocation MacroLoc;
00057   SourceLocation DefinedLoc;
00058 public:
00059   MultipleIncludeOpt() {
00060     ReadAnyTokens = false;
00061     ImmediatelyAfterTopLevelIfndef = false;
00062     DidMacroExpansion = false;
00063     TheMacro = nullptr;
00064     DefinedMacro = nullptr;
00065   }
00066 
00067   SourceLocation GetMacroLocation() const {
00068     return MacroLoc;
00069   }
00070 
00071   SourceLocation GetDefinedLocation() const {
00072     return DefinedLoc;
00073   }
00074 
00075   void resetImmediatelyAfterTopLevelIfndef() {
00076     ImmediatelyAfterTopLevelIfndef = false;
00077   }
00078 
00079   void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc) {
00080     DefinedMacro = M;
00081     DefinedLoc = Loc;
00082   }
00083 
00084   /// Invalidate - Permanently mark this file as not being suitable for the
00085   /// include-file optimization.
00086   void Invalidate() {
00087     // If we have read tokens but have no controlling macro, the state-machine
00088     // below can never "accept".
00089     ReadAnyTokens = true;
00090     ImmediatelyAfterTopLevelIfndef = false;
00091     DefinedMacro = nullptr;
00092     TheMacro = nullptr;
00093   }
00094 
00095   /// getHasReadAnyTokensVal - This is used for the \#ifndef hande-shake at the
00096   /// top of the file when reading preprocessor directives.  Otherwise, reading
00097   /// the "ifndef x" would count as reading tokens.
00098   bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
00099 
00100   /// getImmediatelyAfterTopLevelIfndef - returns true if the last directive
00101   /// was an #ifndef at the beginning of the file.
00102   bool getImmediatelyAfterTopLevelIfndef() const {
00103     return ImmediatelyAfterTopLevelIfndef;
00104   }
00105 
00106   // If a token is read, remember that we have seen a side-effect in this file.
00107   void ReadToken() {
00108     ReadAnyTokens = true;
00109     ImmediatelyAfterTopLevelIfndef = false;
00110   }
00111 
00112   /// ExpandedMacro - When a macro is expanded with this lexer as the current
00113   /// buffer, this method is called to disable the MIOpt if needed.
00114   void ExpandedMacro() { DidMacroExpansion = true; }
00115 
00116   /// \brief Called when entering a top-level \#ifndef directive (or the
00117   /// "\#if !defined" equivalent) without any preceding tokens.
00118   ///
00119   /// Note, we don't care about the input value of 'ReadAnyTokens'.  The caller
00120   /// ensures that this is only called if there are no tokens read before the
00121   /// \#ifndef.  The caller is required to do this, because reading the \#if
00122   /// line obviously reads in in tokens.
00123   void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc) {
00124     // If the macro is already set, this is after the top-level #endif.
00125     if (TheMacro)
00126       return Invalidate();
00127 
00128     // If we have already expanded a macro by the end of the #ifndef line, then
00129     // there is a macro expansion *in* the #ifndef line.  This means that the
00130     // condition could evaluate differently when subsequently #included.  Reject
00131     // this.
00132     if (DidMacroExpansion)
00133       return Invalidate();
00134 
00135     // Remember that we're in the #if and that we have the macro.
00136     ReadAnyTokens = true;
00137     ImmediatelyAfterTopLevelIfndef = true;
00138     TheMacro = M;
00139     MacroLoc = Loc;
00140   }
00141 
00142   /// \brief Invoked when a top level conditional (except \#ifndef) is found.
00143   void EnterTopLevelConditional() {
00144     // If a conditional directive (except #ifndef) is found at the top level,
00145     // there is a chunk of the file not guarded by the controlling macro.
00146     Invalidate();
00147   }
00148 
00149   /// \brief Called when the lexer exits the top-level conditional.
00150   void ExitTopLevelConditional() {
00151     // If we have a macro, that means the top of the file was ok.  Set our state
00152     // back to "not having read any tokens" so we can detect anything after the
00153     // #endif.
00154     if (!TheMacro) return Invalidate();
00155 
00156     // At this point, we haven't "read any tokens" but we do have a controlling
00157     // macro.
00158     ReadAnyTokens = false;
00159     ImmediatelyAfterTopLevelIfndef = false;
00160   }
00161 
00162   /// \brief Once the entire file has been lexed, if there is a controlling
00163   /// macro, return it.
00164   const IdentifierInfo *GetControllingMacroAtEndOfFile() const {
00165     // If we haven't read any tokens after the #endif, return the controlling
00166     // macro if it's valid (if it isn't, it will be null).
00167     if (!ReadAnyTokens)
00168       return TheMacro;
00169     return nullptr;
00170   }
00171 
00172   /// \brief If the ControllingMacro is followed by a macro definition, return
00173   /// the macro that was defined.
00174   const IdentifierInfo *GetDefinedMacro() const {
00175     return DefinedMacro;
00176   }
00177 };
00178 
00179 }  // end namespace clang
00180 
00181 #endif