• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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