clang  14.0.0git
MultipleIncludeOpt.h
Go to the documentation of this file.
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 
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.
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:
59  ReadAnyTokens = false;
60  ImmediatelyAfterTopLevelIfndef = false;
61  DidMacroExpansion = false;
62  TheMacro = nullptr;
63  DefinedMacro = nullptr;
64  }
65 
67  return MacroLoc;
68  }
69 
71  return DefinedLoc;
72  }
73 
75  ImmediatelyAfterTopLevelIfndef = false;
76  }
77 
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.
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.
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.
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.
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.
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.
174  return DefinedMacro;
175  }
176 };
177 
178 } // end namespace clang
179 
180 #endif
clang::MultipleIncludeOpt::getImmediatelyAfterTopLevelIfndef
bool getImmediatelyAfterTopLevelIfndef() const
getImmediatelyAfterTopLevelIfndef - returns true if the last directive was an #ifndef at the beginnin...
Definition: MultipleIncludeOpt.h:101
clang::MultipleIncludeOpt::EnterTopLevelConditional
void EnterTopLevelConditional()
Invoked when a top level conditional (except #ifndef) is found.
Definition: MultipleIncludeOpt.h:142
clang::MultipleIncludeOpt::ReadToken
void ReadToken()
Definition: MultipleIncludeOpt.h:106
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:88
clang::MultipleIncludeOpt::SetDefinedMacro
void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc)
Definition: MultipleIncludeOpt.h:78
clang::MultipleIncludeOpt::ExpandedMacro
void ExpandedMacro()
ExpandedMacro - When a macro is expanded with this lexer as the current buffer, this method is called...
Definition: MultipleIncludeOpt.h:113
clang::MultipleIncludeOpt
Implements the simple state machine that the Lexer class uses to detect files subject to the 'multipl...
Definition: MultipleIncludeOpt.h:28
clang::MultipleIncludeOpt::Invalidate
void Invalidate()
Invalidate - Permanently mark this file as not being suitable for the include-file optimization.
Definition: MultipleIncludeOpt.h:85
clang::MultipleIncludeOpt::getHasReadAnyTokensVal
bool getHasReadAnyTokensVal() const
getHasReadAnyTokensVal - This is used for the #ifndef handshake at the top of the file when reading p...
Definition: MultipleIncludeOpt.h:97
clang::MultipleIncludeOpt::GetDefinedMacro
const IdentifierInfo * GetDefinedMacro() const
If the ControllingMacro is followed by a macro definition, return the macro that was defined.
Definition: MultipleIncludeOpt.h:173
clang::MultipleIncludeOpt::MultipleIncludeOpt
MultipleIncludeOpt()
Definition: MultipleIncludeOpt.h:58
clang::MultipleIncludeOpt::EnterTopLevelIfndef
void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc)
Called when entering a top-level #ifndef directive (or the "\#if !defined" equivalent) without any pr...
Definition: MultipleIncludeOpt.h:122
SourceLocation.h
clang::MultipleIncludeOpt::GetDefinedLocation
SourceLocation GetDefinedLocation() const
Definition: MultipleIncludeOpt.h:70
clang::MultipleIncludeOpt::GetControllingMacroAtEndOfFile
const IdentifierInfo * GetControllingMacroAtEndOfFile() const
Once the entire file has been lexed, if there is a controlling macro, return it.
Definition: MultipleIncludeOpt.h:163
clang::IdentifierInfo
One of these records is kept for each identifier that is lexed.
Definition: IdentifierTable.h:84
clang
Definition: CalledOnceCheck.h:17
clang::MultipleIncludeOpt::GetMacroLocation
SourceLocation GetMacroLocation() const
Definition: MultipleIncludeOpt.h:66
clang::MultipleIncludeOpt::ExitTopLevelConditional
void ExitTopLevelConditional()
Called when the lexer exits the top-level conditional.
Definition: MultipleIncludeOpt.h:149
clang::MultipleIncludeOpt::resetImmediatelyAfterTopLevelIfndef
void resetImmediatelyAfterTopLevelIfndef()
Definition: MultipleIncludeOpt.h:74