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