/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Lex/MultipleIncludeOpt.h
Line | Count | Source |
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 | | |
17 | | #include "clang/Basic/SourceLocation.h" |
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. |
28 | | class MultipleIncludeOpt { |
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: |
58 | 42.8M | MultipleIncludeOpt() { |
59 | 42.8M | ReadAnyTokens = false; |
60 | 42.8M | ImmediatelyAfterTopLevelIfndef = false; |
61 | 42.8M | DidMacroExpansion = false; |
62 | 42.8M | TheMacro = nullptr; |
63 | 42.8M | DefinedMacro = nullptr; |
64 | 42.8M | } |
65 | | |
66 | 12 | SourceLocation GetMacroLocation() const { |
67 | 12 | return MacroLoc; |
68 | 12 | } |
69 | | |
70 | 18 | SourceLocation GetDefinedLocation() const { |
71 | 18 | return DefinedLoc; |
72 | 18 | } |
73 | | |
74 | 62.4M | void resetImmediatelyAfterTopLevelIfndef() { |
75 | 62.4M | ImmediatelyAfterTopLevelIfndef = false; |
76 | 62.4M | } |
77 | | |
78 | 296k | void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc) { |
79 | 296k | DefinedMacro = M; |
80 | 296k | DefinedLoc = Loc; |
81 | 296k | } |
82 | | |
83 | | /// Invalidate - Permanently mark this file as not being suitable for the |
84 | | /// include-file optimization. |
85 | 8.38M | void Invalidate() { |
86 | | // If we have read tokens but have no controlling macro, the state-machine |
87 | | // below can never "accept". |
88 | 8.38M | ReadAnyTokens = true; |
89 | 8.38M | ImmediatelyAfterTopLevelIfndef = false; |
90 | 8.38M | DefinedMacro = nullptr; |
91 | 8.38M | TheMacro = nullptr; |
92 | 8.38M | } |
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 | 62.4M | bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } |
98 | | |
99 | | /// getImmediatelyAfterTopLevelIfndef - returns true if the last directive |
100 | | /// was an #ifndef at the beginning of the file. |
101 | 62.4M | bool getImmediatelyAfterTopLevelIfndef() const { |
102 | 62.4M | return ImmediatelyAfterTopLevelIfndef; |
103 | 62.4M | } |
104 | | |
105 | | // If a token is read, remember that we have seen a side-effect in this file. |
106 | 1.39G | void ReadToken() { |
107 | 1.39G | ReadAnyTokens = true; |
108 | 1.39G | ImmediatelyAfterTopLevelIfndef = false; |
109 | 1.39G | } |
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 | 21.4M | 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. |
122 | 336k | void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc) { |
123 | | // If the macro is already set, this is after the top-level #endif. |
124 | 336k | if (TheMacro) |
125 | 888 | 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 | 335k | if (DidMacroExpansion) |
132 | 1 | return Invalidate(); |
133 | | |
134 | | // Remember that we're in the #if and that we have the macro. |
135 | 335k | ReadAnyTokens = true; |
136 | 335k | ImmediatelyAfterTopLevelIfndef = true; |
137 | 335k | TheMacro = M; |
138 | 335k | MacroLoc = Loc; |
139 | 335k | } |
140 | | |
141 | | /// Invoked when a top level conditional (except \#ifndef) is found. |
142 | 4.34M | void EnterTopLevelConditional() { |
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 | 4.34M | Invalidate(); |
146 | 4.34M | } |
147 | | |
148 | | /// Called when the lexer exits the top-level conditional. |
149 | 4.37M | void ExitTopLevelConditional() { |
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 | 4.37M | if (!TheMacro) return Invalidate()4.03M ; |
154 | | |
155 | | // At this point, we haven't "read any tokens" but we do have a controlling |
156 | | // macro. |
157 | 335k | ReadAnyTokens = false; |
158 | 335k | ImmediatelyAfterTopLevelIfndef = false; |
159 | 335k | } |
160 | | |
161 | | /// Once the entire file has been lexed, if there is a controlling |
162 | | /// macro, return it. |
163 | 1.02M | const IdentifierInfo *GetControllingMacroAtEndOfFile() const { |
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 | 1.02M | if (!ReadAnyTokens) |
167 | 365k | return TheMacro; |
168 | 656k | return nullptr; |
169 | 656k | } |
170 | | |
171 | | /// If the ControllingMacro is followed by a macro definition, return |
172 | | /// the macro that was defined. |
173 | 334k | const IdentifierInfo *GetDefinedMacro() const { |
174 | 334k | return DefinedMacro; |
175 | 334k | } |
176 | | }; |
177 | | |
178 | | } // end namespace clang |
179 | | |
180 | | #endif |