/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/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 | 2.13M | MultipleIncludeOpt() { |
59 | 2.13M | ReadAnyTokens = false; |
60 | 2.13M | ImmediatelyAfterTopLevelIfndef = false; |
61 | 2.13M | DidMacroExpansion = false; |
62 | 2.13M | TheMacro = nullptr; |
63 | 2.13M | DefinedMacro = nullptr; |
64 | 2.13M | } |
65 | | |
66 | 14 | SourceLocation GetMacroLocation() const { |
67 | 14 | return MacroLoc; |
68 | 14 | } |
69 | | |
70 | 21 | SourceLocation GetDefinedLocation() const { |
71 | 21 | return DefinedLoc; |
72 | 21 | } |
73 | | |
74 | 35.9M | void resetImmediatelyAfterTopLevelIfndef() { |
75 | 35.9M | ImmediatelyAfterTopLevelIfndef = false; |
76 | 35.9M | } |
77 | | |
78 | 366k | void SetDefinedMacro(IdentifierInfo *M, SourceLocation Loc) { |
79 | 366k | DefinedMacro = M; |
80 | 366k | DefinedLoc = Loc; |
81 | 366k | } |
82 | | |
83 | | /// Invalidate - Permanently mark this file as not being suitable for the |
84 | | /// include-file optimization. |
85 | 789k | void Invalidate() { |
86 | 789k | // If we have read tokens but have no controlling macro, the state-machine |
87 | 789k | // below can never "accept". |
88 | 789k | ReadAnyTokens = true; |
89 | 789k | ImmediatelyAfterTopLevelIfndef = false; |
90 | 789k | DefinedMacro = nullptr; |
91 | 789k | TheMacro = nullptr; |
92 | 789k | } |
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 | 35.9M | 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 | 35.9M | bool getImmediatelyAfterTopLevelIfndef() const { |
102 | 35.9M | return ImmediatelyAfterTopLevelIfndef; |
103 | 35.9M | } |
104 | | |
105 | | // If a token is read, remember that we have seen a side-effect in this file. |
106 | 1.33G | void ReadToken() { |
107 | 1.33G | ReadAnyTokens = true; |
108 | 1.33G | ImmediatelyAfterTopLevelIfndef = false; |
109 | 1.33G | } |
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 | 10.0M | 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 | 393k | void EnterTopLevelIfndef(const IdentifierInfo *M, SourceLocation Loc) { |
123 | 393k | // If the macro is already set, this is after the top-level #endif. |
124 | 393k | if (TheMacro) |
125 | 231 | return Invalidate(); |
126 | 393k | |
127 | 393k | // If we have already expanded a macro by the end of the #ifndef line, then |
128 | 393k | // there is a macro expansion *in* the #ifndef line. This means that the |
129 | 393k | // condition could evaluate differently when subsequently #included. Reject |
130 | 393k | // this. |
131 | 393k | if (DidMacroExpansion) |
132 | 1 | return Invalidate(); |
133 | 393k | |
134 | 393k | // Remember that we're in the #if and that we have the macro. |
135 | 393k | ReadAnyTokens = true; |
136 | 393k | ImmediatelyAfterTopLevelIfndef = true; |
137 | 393k | TheMacro = M; |
138 | 393k | MacroLoc = Loc; |
139 | 393k | } |
140 | | |
141 | | /// Invoked when a top level conditional (except \#ifndef) is found. |
142 | 564k | void EnterTopLevelConditional() { |
143 | 564k | // If a conditional directive (except #ifndef) is found at the top level, |
144 | 564k | // there is a chunk of the file not guarded by the controlling macro. |
145 | 564k | Invalidate(); |
146 | 564k | } |
147 | | |
148 | | /// Called when the lexer exits the top-level conditional. |
149 | 617k | void ExitTopLevelConditional() { |
150 | 617k | // If we have a macro, that means the top of the file was ok. Set our state |
151 | 617k | // back to "not having read any tokens" so we can detect anything after the |
152 | 617k | // #endif. |
153 | 617k | if (!TheMacro) return Invalidate()224k ; |
154 | 392k | |
155 | 392k | // At this point, we haven't "read any tokens" but we do have a controlling |
156 | 392k | // macro. |
157 | 392k | ReadAnyTokens = false; |
158 | 392k | ImmediatelyAfterTopLevelIfndef = false; |
159 | 392k | } |
160 | | |
161 | | /// Once the entire file has been lexed, if there is a controlling |
162 | | /// macro, return it. |
163 | 582k | const IdentifierInfo *GetControllingMacroAtEndOfFile() const { |
164 | 582k | // If we haven't read any tokens after the #endif, return the controlling |
165 | 582k | // macro if it's valid (if it isn't, it will be null). |
166 | 582k | if (!ReadAnyTokens) |
167 | 396k | return TheMacro; |
168 | 185k | return nullptr; |
169 | 185k | } |
170 | | |
171 | | /// If the ControllingMacro is followed by a macro definition, return |
172 | | /// the macro that was defined. |
173 | 391k | const IdentifierInfo *GetDefinedMacro() const { |
174 | 391k | return DefinedMacro; |
175 | 391k | } |
176 | | }; |
177 | | |
178 | | } // end namespace clang |
179 | | |
180 | | #endif |