clang 20.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
19namespace clang {
20class 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;
57public:
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 /// SetReadToken - Set whether the value of 'ReadAnyTokens'. Called to
112 /// override when encountering tokens outside of the include guard that have
113 /// no effect if the file in question is is included multiple times (e.g. the
114 /// null directive).
115 void SetReadToken(bool Value) { ReadAnyTokens = Value; }
116
117 /// ExpandedMacro - When a macro is expanded with this lexer as the current
118 /// buffer, this method is called to disable the MIOpt if needed.
119 void ExpandedMacro() { DidMacroExpansion = true; }
120
121 /// Called when entering a top-level \#ifndef directive (or the
122 /// "\#if !defined" equivalent) without any preceding tokens.
123 ///
124 /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller
125 /// ensures that this is only called if there are no tokens read before the
126 /// \#ifndef. The caller is required to do this, because reading the \#if
127 /// line obviously reads in tokens.
129 // If the macro is already set, this is after the top-level #endif.
130 if (TheMacro)
131 return Invalidate();
132
133 // If we have already expanded a macro by the end of the #ifndef line, then
134 // there is a macro expansion *in* the #ifndef line. This means that the
135 // condition could evaluate differently when subsequently #included. Reject
136 // this.
137 if (DidMacroExpansion)
138 return Invalidate();
139
140 // Remember that we're in the #if and that we have the macro.
141 ReadAnyTokens = true;
142 ImmediatelyAfterTopLevelIfndef = true;
143 TheMacro = M;
144 MacroLoc = Loc;
145 }
146
147 /// Invoked when a top level conditional (except \#ifndef) is found.
149 // If a conditional directive (except #ifndef) is found at the top level,
150 // there is a chunk of the file not guarded by the controlling macro.
151 Invalidate();
152 }
153
154 /// Called when the lexer exits the top-level conditional.
156 // If we have a macro, that means the top of the file was ok. Set our state
157 // back to "not having read any tokens" so we can detect anything after the
158 // #endif.
159 if (!TheMacro) return Invalidate();
160
161 // At this point, we haven't "read any tokens" but we do have a controlling
162 // macro.
163 ReadAnyTokens = false;
164 ImmediatelyAfterTopLevelIfndef = false;
165 }
166
167 /// Once the entire file has been lexed, if there is a controlling
168 /// macro, return it.
170 // If we haven't read any tokens after the #endif, return the controlling
171 // macro if it's valid (if it isn't, it will be null).
172 if (!ReadAnyTokens)
173 return TheMacro;
174 return nullptr;
175 }
176
177 /// If the ControllingMacro is followed by a macro definition, return
178 /// the macro that was defined.
180 return DefinedMacro;
181 }
182};
183
184} // end namespace clang
185
186#endif
SourceLocation Loc
Definition: SemaObjC.cpp:759
Defines the clang::SourceLocation class and associated facilities.
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...
const IdentifierInfo * GetDefinedMacro() const
If the ControllingMacro is followed by a macro definition, return the macro that was defined.
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 ExitTopLevelConditional()
Called when the lexer exits the top-level conditional.
void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc)
void SetReadToken(bool Value)
SetReadToken - Set whether the value of 'ReadAnyTokens'.
bool getImmediatelyAfterTopLevelIfndef() const
getImmediatelyAfterTopLevelIfndef - returns true if the last directive was an #ifndef at the beginnin...
const IdentifierInfo * GetControllingMacroAtEndOfFile() const
Once the entire file has been lexed, if there is a controlling macro, return it.
SourceLocation GetDefinedLocation() const
void EnterTopLevelConditional()
Invoked when a top level conditional (except #ifndef) is found.
SourceLocation GetMacroLocation() const
void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc)
Called when entering a top-level #ifndef directive (or the "\#if !defined" equivalent) without any pr...
void ExpandedMacro()
ExpandedMacro - When a macro is expanded with this lexer as the current buffer, this method is called...
Encodes a location in the source.
The JSON file list parser is used to communicate input to InstallAPI.