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