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)