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 // This file defines the MultipleIncludeOpt interface. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H 15 #define LLVM_CLANG_MULTIPLEINCLUDEOPT_H 16 17 namespace clang { 18 class IdentifierInfo; 19 20 /// MultipleIncludeOpt - This class implements the simple state machine that the 21 /// Lexer class uses to detect files subject to the 'multiple-include' 22 /// optimization. The public methods in this class are triggered by various 23 /// events that occur when a file is lexed, and after the entire file is lexed, 24 /// information about which macro (if any) controls the header is returned. 25 class MultipleIncludeOpt { 26 /// ReadAnyTokens - This is set to false when a file is first opened and true 27 /// any time a token is returned to the client or a (non-multiple-include) 28 /// directive is parsed. When the final #endif is parsed this is reset back 29 /// to false, that way any tokens before the first #ifdef or after the last 30 /// #endif can be easily detected. 31 bool ReadAnyTokens; 32 33 /// ReadAnyTokens - This is set to false when a file is first opened and true 34 /// any time a token is returned to the client or a (non-multiple-include) 35 /// directive is parsed. When the final #endif is parsed this is reset back 36 /// to false, that way any tokens before the first #ifdef or after the last 37 /// #endif can be easily detected. 38 bool DidMacroExpansion; 39 40 /// TheMacro - The controlling macro for a file, if valid. 41 /// 42 const IdentifierInfo *TheMacro; 43 public: MultipleIncludeOpt()44 MultipleIncludeOpt() { 45 ReadAnyTokens = false; 46 DidMacroExpansion = false; 47 TheMacro = 0; 48 } 49 50 /// Invalidate - Permanently mark this file as not being suitable for the 51 /// include-file optimization. Invalidate()52 void Invalidate() { 53 // If we have read tokens but have no controlling macro, the state-machine 54 // below can never "accept". 55 ReadAnyTokens = true; 56 TheMacro = 0; 57 } 58 59 /// getHasReadAnyTokensVal - This is used for the #ifndef hande-shake at the 60 /// top of the file when reading preprocessor directives. Otherwise, reading 61 /// the "ifndef x" would count as reading tokens. getHasReadAnyTokensVal()62 bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } 63 64 // If a token is read, remember that we have seen a side-effect in this file. ReadToken()65 void ReadToken() { ReadAnyTokens = true; } 66 67 /// ExpandedMacro - When a macro is expanded with this lexer as the current 68 /// buffer, this method is called to disable the MIOpt if needed. ExpandedMacro()69 void ExpandedMacro() { DidMacroExpansion = true; } 70 71 /// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the 72 /// "#if !defined" equivalent) without any preceding tokens, this method is 73 /// called. 74 /// 75 /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller 76 /// ensures that this is only called if there are no tokens read before the 77 /// #ifndef. The caller is required to do this, because reading the #if line 78 /// obviously reads in in tokens. EnterTopLevelIFNDEF(const IdentifierInfo * M)79 void EnterTopLevelIFNDEF(const IdentifierInfo *M) { 80 // If the macro is already set, this is after the top-level #endif. 81 if (TheMacro) 82 return Invalidate(); 83 84 // If we have already expanded a macro by the end of the #ifndef line, then 85 // there is a macro expansion *in* the #ifndef line. This means that the 86 // condition could evaluate differently when subsequently #included. Reject 87 // this. 88 if (DidMacroExpansion) 89 return Invalidate(); 90 91 // Remember that we're in the #if and that we have the macro. 92 ReadAnyTokens = true; 93 TheMacro = M; 94 } 95 96 /// EnterTopLevelConditional - This is invoked when a top level conditional 97 /// (except #ifndef) is found. EnterTopLevelConditional()98 void EnterTopLevelConditional() { 99 /// If a conditional directive (except #ifndef) is found at the top level, 100 /// there is a chunk of the file not guarded by the controlling macro. 101 Invalidate(); 102 } 103 104 /// ExitTopLevelConditional - This method is called when the lexer exits the 105 /// top-level conditional. ExitTopLevelConditional()106 void ExitTopLevelConditional() { 107 // If we have a macro, that means the top of the file was ok. Set our state 108 // back to "not having read any tokens" so we can detect anything after the 109 // #endif. 110 if (!TheMacro) return Invalidate(); 111 112 // At this point, we haven't "read any tokens" but we do have a controlling 113 // macro. 114 ReadAnyTokens = false; 115 } 116 117 /// GetControllingMacroAtEndOfFile - Once the entire file has been lexed, if 118 /// there is a controlling macro, return it. GetControllingMacroAtEndOfFile()119 const IdentifierInfo *GetControllingMacroAtEndOfFile() const { 120 // If we haven't read any tokens after the #endif, return the controlling 121 // macro if it's valid (if it isn't, it will be null). 122 if (!ReadAnyTokens) 123 return TheMacro; 124 return 0; 125 } 126 }; 127 128 } // end namespace clang 129 130 #endif 131