clang  6.0.0svn
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 handshake 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
One of these records is kept for each identifier that is lexed.
Implements the simple state machine that the Lexer class uses to detect files subject to the 'multipl...
void ExpandedMacro()
ExpandedMacro - When a macro is expanded with this lexer as the current buffer, this method is called...
void Invalidate()
Invalidate - Permanently mark this file as not being suitable for the include-file optimization...
bool getHasReadAnyTokensVal() const
getHasReadAnyTokensVal - This is used for the #ifndef handshake at the top of the file when reading p...
void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc)
SourceLocation GetDefinedLocation() const
Encodes a location in the source.
SourceLocation GetMacroLocation() const
Dataflow Directional Tag Classes.
void ExitTopLevelConditional()
Called when the lexer exits the top-level conditional.
void EnterTopLevelConditional()
Invoked when a top level conditional (except #ifndef) is found.
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...
bool getImmediatelyAfterTopLevelIfndef() const
getImmediatelyAfterTopLevelIfndef - returns true if the last directive was an #ifndef at the beginnin...
const IdentifierInfo * GetDefinedMacro() const
If the ControllingMacro is followed by a macro definition, return the macro that was defined...
const IdentifierInfo * GetControllingMacroAtEndOfFile() const
Once the entire file has been lexed, if there is a controlling macro, return it.