clang API Documentation
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