Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. ///
  9. /// \file
  10. /// Defines the MultipleIncludeOpt interface.
  11. //
  12. //===----------------------------------------------------------------------===//
  13.  
  14. #ifndef LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H
  15. #define LLVM_CLANG_LEX_MULTIPLEINCLUDEOPT_H
  16.  
  17. #include "clang/Basic/SourceLocation.h"
  18.  
  19. namespace clang {
  20. class IdentifierInfo;
  21.  
  22. /// Implements the simple state machine that the Lexer class uses to
  23. /// detect files subject to the 'multiple-include' optimization.
  24. ///
  25. /// The public methods in this class are triggered by various
  26. /// events that occur when a file is lexed, and after the entire file is lexed,
  27. /// information about which macro (if any) controls the header is returned.
  28. class MultipleIncludeOpt {
  29.   /// ReadAnyTokens - This is set to false when a file is first opened and true
  30.   /// any time a token is returned to the client or a (non-multiple-include)
  31.   /// directive is parsed.  When the final \#endif is parsed this is reset back
  32.   /// to false, that way any tokens before the first \#ifdef or after the last
  33.   /// \#endif can be easily detected.
  34.   bool ReadAnyTokens;
  35.  
  36.   /// ImmediatelyAfterTopLevelIfndef - This is true when the only tokens
  37.   /// processed in the file so far is an #ifndef and an identifier.  Used in
  38.   /// the detection of header guards in a file.
  39.   bool ImmediatelyAfterTopLevelIfndef;
  40.  
  41.   /// ReadAnyTokens - This is set to false when a file is first opened and true
  42.   /// any time a token is returned to the client or a (non-multiple-include)
  43.   /// directive is parsed.  When the final #endif is parsed this is reset back
  44.   /// to false, that way any tokens before the first #ifdef or after the last
  45.   /// #endif can be easily detected.
  46.   bool DidMacroExpansion;
  47.  
  48.   /// TheMacro - The controlling macro for a file, if valid.
  49.   ///
  50.   const IdentifierInfo *TheMacro;
  51.  
  52.   /// DefinedMacro - The macro defined right after TheMacro, if any.
  53.   const IdentifierInfo *DefinedMacro;
  54.  
  55.   SourceLocation MacroLoc;
  56.   SourceLocation DefinedLoc;
  57. public:
  58.   MultipleIncludeOpt() {
  59.     ReadAnyTokens = false;
  60.     ImmediatelyAfterTopLevelIfndef = false;
  61.     DidMacroExpansion = false;
  62.     TheMacro = nullptr;
  63.     DefinedMacro = nullptr;
  64.   }
  65.  
  66.   SourceLocation GetMacroLocation() const {
  67.     return MacroLoc;
  68.   }
  69.  
  70.   SourceLocation GetDefinedLocation() const {
  71.     return DefinedLoc;
  72.   }
  73.  
  74.   void resetImmediatelyAfterTopLevelIfndef() {
  75.     ImmediatelyAfterTopLevelIfndef = false;
  76.   }
  77.  
  78.   void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc) {
  79.     DefinedMacro = M;
  80.     DefinedLoc = Loc;
  81.   }
  82.  
  83.   /// Invalidate - Permanently mark this file as not being suitable for the
  84.   /// include-file optimization.
  85.   void Invalidate() {
  86.     // If we have read tokens but have no controlling macro, the state-machine
  87.     // below can never "accept".
  88.     ReadAnyTokens = true;
  89.     ImmediatelyAfterTopLevelIfndef = false;
  90.     DefinedMacro = nullptr;
  91.     TheMacro = nullptr;
  92.   }
  93.  
  94.   /// getHasReadAnyTokensVal - This is used for the \#ifndef handshake at the
  95.   /// top of the file when reading preprocessor directives.  Otherwise, reading
  96.   /// the "ifndef x" would count as reading tokens.
  97.   bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
  98.  
  99.   /// getImmediatelyAfterTopLevelIfndef - returns true if the last directive
  100.   /// was an #ifndef at the beginning of the file.
  101.   bool getImmediatelyAfterTopLevelIfndef() const {
  102.     return ImmediatelyAfterTopLevelIfndef;
  103.   }
  104.  
  105.   // If a token is read, remember that we have seen a side-effect in this file.
  106.   void ReadToken() {
  107.     ReadAnyTokens = true;
  108.     ImmediatelyAfterTopLevelIfndef = false;
  109.   }
  110.  
  111.   /// ExpandedMacro - When a macro is expanded with this lexer as the current
  112.   /// buffer, this method is called to disable the MIOpt if needed.
  113.   void ExpandedMacro() { DidMacroExpansion = true; }
  114.  
  115.   /// Called when entering a top-level \#ifndef directive (or the
  116.   /// "\#if !defined" equivalent) without any preceding tokens.
  117.   ///
  118.   /// Note, we don't care about the input value of 'ReadAnyTokens'.  The caller
  119.   /// ensures that this is only called if there are no tokens read before the
  120.   /// \#ifndef.  The caller is required to do this, because reading the \#if
  121.   /// line obviously reads in tokens.
  122.   void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc) {
  123.     // If the macro is already set, this is after the top-level #endif.
  124.     if (TheMacro)
  125.       return Invalidate();
  126.  
  127.     // If we have already expanded a macro by the end of the #ifndef line, then
  128.     // there is a macro expansion *in* the #ifndef line.  This means that the
  129.     // condition could evaluate differently when subsequently #included.  Reject
  130.     // this.
  131.     if (DidMacroExpansion)
  132.       return Invalidate();
  133.  
  134.     // Remember that we're in the #if and that we have the macro.
  135.     ReadAnyTokens = true;
  136.     ImmediatelyAfterTopLevelIfndef = true;
  137.     TheMacro = M;
  138.     MacroLoc = Loc;
  139.   }
  140.  
  141.   /// Invoked when a top level conditional (except \#ifndef) is found.
  142.   void EnterTopLevelConditional() {
  143.     // If a conditional directive (except #ifndef) is found at the top level,
  144.     // there is a chunk of the file not guarded by the controlling macro.
  145.     Invalidate();
  146.   }
  147.  
  148.   /// Called when the lexer exits the top-level conditional.
  149.   void ExitTopLevelConditional() {
  150.     // If we have a macro, that means the top of the file was ok.  Set our state
  151.     // back to "not having read any tokens" so we can detect anything after the
  152.     // #endif.
  153.     if (!TheMacro) return Invalidate();
  154.  
  155.     // At this point, we haven't "read any tokens" but we do have a controlling
  156.     // macro.
  157.     ReadAnyTokens = false;
  158.     ImmediatelyAfterTopLevelIfndef = false;
  159.   }
  160.  
  161.   /// Once the entire file has been lexed, if there is a controlling
  162.   /// macro, return it.
  163.   const IdentifierInfo *GetControllingMacroAtEndOfFile() const {
  164.     // If we haven't read any tokens after the #endif, return the controlling
  165.     // macro if it's valid (if it isn't, it will be null).
  166.     if (!ReadAnyTokens)
  167.       return TheMacro;
  168.     return nullptr;
  169.   }
  170.  
  171.   /// If the ControllingMacro is followed by a macro definition, return
  172.   /// the macro that was defined.
  173.   const IdentifierInfo *GetDefinedMacro() const {
  174.     return DefinedMacro;
  175.   }
  176. };
  177.  
  178. }  // end namespace clang
  179.  
  180. #endif
  181.