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 #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: MultipleIncludeOpt()59 MultipleIncludeOpt() { 60 ReadAnyTokens = false; 61 ImmediatelyAfterTopLevelIfndef = false; 62 DidMacroExpansion = false; 63 TheMacro = nullptr; 64 DefinedMacro = nullptr; 65 } 66 GetMacroLocation()67 SourceLocation GetMacroLocation() const { 68 return MacroLoc; 69 } 70 GetDefinedLocation()71 SourceLocation GetDefinedLocation() const { 72 return DefinedLoc; 73 } 74 resetImmediatelyAfterTopLevelIfndef()75 void resetImmediatelyAfterTopLevelIfndef() { 76 ImmediatelyAfterTopLevelIfndef = false; 77 } 78 SetDefinedMacro(IdentifierInfo * M,SourceLocation Loc)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. Invalidate()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. getHasReadAnyTokensVal()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. getImmediatelyAfterTopLevelIfndef()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. ReadToken()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. ExpandedMacro()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. EnterTopLevelIfndef(const IdentifierInfo * M,SourceLocation Loc)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. EnterTopLevelConditional()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. ExitTopLevelConditional()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. GetControllingMacroAtEndOfFile()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. GetDefinedMacro()174 const IdentifierInfo *GetDefinedMacro() const { 175 return DefinedMacro; 176 } 177 }; 178 179 } // end namespace clang 180 181 #endif 182