MultipleIncludeOpt.h revision 0184cc719f06d2c5da6ae0725847ef875c6128cd
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- C++ -*-===// 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The LLVM Compiler Infrastructure 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// License. See LICENSE.TXT for details. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file defines the MultipleIncludeOpt interface. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define LLVM_CLANG_MULTIPLEINCLUDEOPT_H 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace clang { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IdentifierInfo; 197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)/// MultipleIncludeOpt - This class implements the simple state machine that the 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/// Lexer class uses to detect files subject to the 'multiple-include' 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// optimization. The public methods in this class are triggered by various 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// events that occur when a file is lexed, and after the entire file is lexed, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// information about which macro (if any) controls the header is returned. 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MultipleIncludeOpt { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// ReadAnyTokens - This is set to false when a file is first opened and true 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// any time a token is returned to the client or a (non-multiple-include) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// directive is parsed. When the final #endif is parsed this is reset back 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// to false, that way any tokens before the first #ifdef or after the last 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// #endif can be easily detected. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ReadAnyTokens; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// ReadAnyTokens - This is set to false when a file is first opened and true 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// any time a token is returned to the client or a (non-multiple-include) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// directive is parsed. When the final #endif is parsed this is reset back 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// to false, that way any tokens before the first #ifdef or after the last 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// #endif can be easily detected. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool DidMacroExpansion; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// TheMacro - The controlling macro for a file, if valid. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const IdentifierInfo *TheMacro; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public: 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MultipleIncludeOpt() { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReadAnyTokens = false; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DidMacroExpansion = false; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TheMacro = 0; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// Invalidate - Permenantly mark this file as not being suitable for the 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// include-file optimization. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Invalidate() { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have read tokens but have no controlling macro, the state-machine 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // below can never "accept". 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReadAnyTokens = true; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TheMacro = 0; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// getHasReadAnyTokensVal - This is used for the #ifndef hande-shake at the 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// top of the file when reading preprocessor directives. Otherwise, reading 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// the "ifndef x" would count as reading tokens. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a token is read, remember that we have seen a side-effect in this file. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ReadToken() { ReadAnyTokens = true; } 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// ExpandedMacro - When a macro is expanded with this lexer as the current 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// buffer, this method is called to disable the MIOpt if needed. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ExpandedMacro() { DidMacroExpansion = true; } 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the 72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /// "#if !defined" equivalent) without any preceding tokens, this method is 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /// called. 74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /// 75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller 76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /// ensures that this is only called if there are no tokens read before the 77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /// #ifndef. The caller is required to do this, because reading the #if line 78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /// obviously reads in in tokens. 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void EnterTopLevelIFNDEF(const IdentifierInfo *M) { 80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // If the macro is already set, this is after the top-level #endif. 81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (TheMacro) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Invalidate(); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have already expanded a macro by the end of the #ifndef line, then 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there is a macro expansion *in* the #ifndef line. This means that the 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // condition could evaluate differently when subsequently #included. Reject 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (DidMacroExpansion) 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return Invalidate(); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Remember that we're in the #if and that we have the macro. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReadAnyTokens = true; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TheMacro = M; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// EnterTopLevelConditional - This is invoked when a top level conditional 97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /// (except #ifndef) is found. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void EnterTopLevelConditional() { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// If a conditional directive (except #ifndef) is found at the top level, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// there is a chunk of the file not guarded by the controlling macro. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Invalidate(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// ExitTopLevelConditional - This method is called when the lexer exits the 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// top-level conditional. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ExitTopLevelConditional() { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have a macro, that means the top of the file was ok. Set our state 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // back to "not having read any tokens" so we can detect anything after the 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // #endif. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!TheMacro) return Invalidate(); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // At this point, we haven't "read any tokens" but we do have a controlling 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // macro. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReadAnyTokens = false; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// GetControllingMacroAtEndOfFile - Once the entire file has been lexed, if 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// there is a controlling macro, return it. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const IdentifierInfo *GetControllingMacroAtEndOfFile() const { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we haven't read any tokens after the #endif, return the controlling 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // macro if it's valid (if it isn't, it will be null). 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ReadAnyTokens) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TheMacro; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // end namespace clang 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)