1 | //======- AttributeCommonInfo.h - Base info about Attributes-----*- 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 | // This file defines the AttributeCommonInfo type, which is the base for a |
10 | // ParsedAttr and is used by Attr as a way to share info between the two. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H |
15 | #define LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H |
16 | |
17 | #include "clang/Basic/SourceLocation.h" |
18 | #include "clang/Basic/TokenKinds.h" |
19 | |
20 | namespace clang { |
21 | |
22 | class ASTRecordWriter; |
23 | class IdentifierInfo; |
24 | |
25 | class AttributeCommonInfo { |
26 | public: |
27 | /// The style used to specify an attribute. |
28 | enum Syntax { |
29 | /// __attribute__((...)) |
30 | AS_GNU = 1, |
31 | |
32 | /// [[...]] |
33 | AS_CXX11, |
34 | |
35 | /// [[...]] |
36 | AS_C23, |
37 | |
38 | /// __declspec(...) |
39 | AS_Declspec, |
40 | |
41 | /// [uuid("...")] class Foo |
42 | AS_Microsoft, |
43 | |
44 | /// __ptr16, alignas(...), etc. |
45 | AS_Keyword, |
46 | |
47 | /// #pragma ... |
48 | AS_Pragma, |
49 | |
50 | // Note TableGen depends on the order above. Do not add or change the order |
51 | // without adding related code to TableGen/ClangAttrEmitter.cpp. |
52 | /// Context-sensitive version of a keyword attribute. |
53 | AS_ContextSensitiveKeyword, |
54 | |
55 | /// <vardecl> : <annotation> |
56 | AS_HLSLAnnotation, |
57 | |
58 | /// The attibute has no source code manifestation and is only created |
59 | /// implicitly. |
60 | AS_Implicit |
61 | }; |
62 | enum Kind { |
63 | #define PARSED_ATTR(NAME) AT_##NAME, |
64 | #include "clang/Sema/AttrParsedAttrList.inc" |
65 | #undef PARSED_ATTR |
66 | NoSemaHandlerAttribute, |
67 | IgnoredAttribute, |
68 | UnknownAttribute, |
69 | }; |
70 | |
71 | private: |
72 | const IdentifierInfo *AttrName = nullptr; |
73 | const IdentifierInfo *ScopeName = nullptr; |
74 | SourceRange AttrRange; |
75 | const SourceLocation ScopeLoc; |
76 | // Corresponds to the Kind enum. |
77 | LLVM_PREFERRED_TYPE(Kind) |
78 | unsigned AttrKind : 16; |
79 | /// Corresponds to the Syntax enum. |
80 | LLVM_PREFERRED_TYPE(Syntax) |
81 | unsigned SyntaxUsed : 4; |
82 | LLVM_PREFERRED_TYPE(bool) |
83 | unsigned SpellingIndex : 4; |
84 | LLVM_PREFERRED_TYPE(bool) |
85 | unsigned IsAlignas : 1; |
86 | LLVM_PREFERRED_TYPE(bool) |
87 | unsigned IsRegularKeywordAttribute : 1; |
88 | |
89 | protected: |
90 | static constexpr unsigned SpellingNotCalculated = 0xf; |
91 | |
92 | public: |
93 | /// Combines information about the source-code form of an attribute, |
94 | /// including its syntax and spelling. |
95 | class Form { |
96 | public: |
97 | constexpr Form(Syntax SyntaxUsed, unsigned SpellingIndex, bool IsAlignas, |
98 | bool IsRegularKeywordAttribute) |
99 | : SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingIndex), |
100 | IsAlignas(IsAlignas), |
101 | IsRegularKeywordAttribute(IsRegularKeywordAttribute) {} |
102 | constexpr Form(tok::TokenKind Tok) |
103 | : SyntaxUsed(AS_Keyword), SpellingIndex(SpellingNotCalculated), |
104 | IsAlignas(Tok == tok::kw_alignas), |
105 | IsRegularKeywordAttribute(tok::isRegularKeywordAttribute(K: Tok)) {} |
106 | |
107 | Syntax getSyntax() const { return Syntax(SyntaxUsed); } |
108 | unsigned getSpellingIndex() const { return SpellingIndex; } |
109 | bool isAlignas() const { return IsAlignas; } |
110 | bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; } |
111 | |
112 | static Form GNU() { return AS_GNU; } |
113 | static Form CXX11() { return AS_CXX11; } |
114 | static Form C23() { return AS_C23; } |
115 | static Form Declspec() { return AS_Declspec; } |
116 | static Form Microsoft() { return AS_Microsoft; } |
117 | static Form Keyword(bool IsAlignas, bool IsRegularKeywordAttribute) { |
118 | return Form(AS_Keyword, SpellingNotCalculated, IsAlignas, |
119 | IsRegularKeywordAttribute); |
120 | } |
121 | static Form Pragma() { return AS_Pragma; } |
122 | static Form ContextSensitiveKeyword() { return AS_ContextSensitiveKeyword; } |
123 | static Form HLSLAnnotation() { return AS_HLSLAnnotation; } |
124 | static Form Implicit() { return AS_Implicit; } |
125 | |
126 | private: |
127 | constexpr Form(Syntax SyntaxUsed) |
128 | : SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated), |
129 | IsAlignas(0), IsRegularKeywordAttribute(0) {} |
130 | |
131 | LLVM_PREFERRED_TYPE(Syntax) |
132 | unsigned SyntaxUsed : 4; |
133 | unsigned SpellingIndex : 4; |
134 | LLVM_PREFERRED_TYPE(bool) |
135 | unsigned IsAlignas : 1; |
136 | LLVM_PREFERRED_TYPE(bool) |
137 | unsigned IsRegularKeywordAttribute : 1; |
138 | }; |
139 | |
140 | AttributeCommonInfo(const IdentifierInfo *AttrName, |
141 | const IdentifierInfo *ScopeName, SourceRange AttrRange, |
142 | SourceLocation ScopeLoc, Kind AttrKind, Form FormUsed) |
143 | : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange), |
144 | ScopeLoc(ScopeLoc), AttrKind(AttrKind), |
145 | SyntaxUsed(FormUsed.getSyntax()), |
146 | SpellingIndex(FormUsed.getSpellingIndex()), |
147 | IsAlignas(FormUsed.isAlignas()), |
148 | IsRegularKeywordAttribute(FormUsed.isRegularKeywordAttribute()) { |
149 | assert(SyntaxUsed >= AS_GNU && SyntaxUsed <= AS_Implicit && |
150 | "Invalid syntax!" ); |
151 | } |
152 | |
153 | AttributeCommonInfo(const IdentifierInfo *AttrName, |
154 | const IdentifierInfo *ScopeName, SourceRange AttrRange, |
155 | SourceLocation ScopeLoc, Form FormUsed) |
156 | : AttributeCommonInfo( |
157 | AttrName, ScopeName, AttrRange, ScopeLoc, |
158 | getParsedKind(Name: AttrName, Scope: ScopeName, SyntaxUsed: FormUsed.getSyntax()), |
159 | FormUsed) {} |
160 | |
161 | AttributeCommonInfo(const IdentifierInfo *AttrName, SourceRange AttrRange, |
162 | Form FormUsed) |
163 | : AttributeCommonInfo(AttrName, nullptr, AttrRange, SourceLocation(), |
164 | FormUsed) {} |
165 | |
166 | AttributeCommonInfo(SourceRange AttrRange, Kind K, Form FormUsed) |
167 | : AttributeCommonInfo(nullptr, nullptr, AttrRange, SourceLocation(), K, |
168 | FormUsed) {} |
169 | |
170 | AttributeCommonInfo(AttributeCommonInfo &&) = default; |
171 | AttributeCommonInfo(const AttributeCommonInfo &) = default; |
172 | |
173 | Kind getParsedKind() const { return Kind(AttrKind); } |
174 | Syntax getSyntax() const { return Syntax(SyntaxUsed); } |
175 | Form getForm() const { |
176 | return Form(getSyntax(), SpellingIndex, IsAlignas, |
177 | IsRegularKeywordAttribute); |
178 | } |
179 | const IdentifierInfo *getAttrName() const { return AttrName; } |
180 | void setAttrName(const IdentifierInfo *AttrNameII) { AttrName = AttrNameII; } |
181 | SourceLocation getLoc() const { return AttrRange.getBegin(); } |
182 | SourceRange getRange() const { return AttrRange; } |
183 | void setRange(SourceRange R) { AttrRange = R; } |
184 | |
185 | bool hasScope() const { return ScopeName; } |
186 | const IdentifierInfo *getScopeName() const { return ScopeName; } |
187 | SourceLocation getScopeLoc() const { return ScopeLoc; } |
188 | |
189 | /// Gets the normalized full name, which consists of both scope and name and |
190 | /// with surrounding underscores removed as appropriate (e.g. |
191 | /// __gnu__::__attr__ will be normalized to gnu::attr). |
192 | std::string getNormalizedFullName() const; |
193 | |
194 | bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; } |
195 | bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; } |
196 | |
197 | bool isGNUScope() const; |
198 | bool isClangScope() const; |
199 | |
200 | bool isCXX11Attribute() const { return SyntaxUsed == AS_CXX11 || IsAlignas; } |
201 | |
202 | bool isC23Attribute() const { return SyntaxUsed == AS_C23; } |
203 | |
204 | bool isAlignas() const { |
205 | // FIXME: In the current state, the IsAlignas member variable is only true |
206 | // with the C++ `alignas` keyword but not `_Alignas`. The following |
207 | // expression works around the otherwise lost information so it will return |
208 | // true for `alignas` or `_Alignas` while still returning false for things |
209 | // like `__attribute__((aligned))`. |
210 | return (getParsedKind() == AT_Aligned && isKeywordAttribute()); |
211 | } |
212 | |
213 | /// The attribute is spelled [[]] in either C or C++ mode, including standard |
214 | /// attributes spelled with a keyword, like alignas. |
215 | bool isStandardAttributeSyntax() const { |
216 | return isCXX11Attribute() || isC23Attribute(); |
217 | } |
218 | |
219 | bool isGNUAttribute() const { return SyntaxUsed == AS_GNU; } |
220 | |
221 | bool isKeywordAttribute() const { |
222 | return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword; |
223 | } |
224 | |
225 | bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; } |
226 | |
227 | bool isContextSensitiveKeywordAttribute() const { |
228 | return SyntaxUsed == AS_ContextSensitiveKeyword; |
229 | } |
230 | |
231 | unsigned getAttributeSpellingListIndex() const { |
232 | assert((isAttributeSpellingListCalculated() || AttrName) && |
233 | "Spelling cannot be found" ); |
234 | return isAttributeSpellingListCalculated() |
235 | ? SpellingIndex |
236 | : calculateAttributeSpellingListIndex(); |
237 | } |
238 | void setAttributeSpellingListIndex(unsigned V) { SpellingIndex = V; } |
239 | |
240 | static Kind getParsedKind(const IdentifierInfo *Name, |
241 | const IdentifierInfo *Scope, Syntax SyntaxUsed); |
242 | |
243 | private: |
244 | /// Get an index into the attribute spelling list |
245 | /// defined in Attr.td. This index is used by an attribute |
246 | /// to pretty print itself. |
247 | unsigned calculateAttributeSpellingListIndex() const; |
248 | |
249 | friend class clang::ASTRecordWriter; |
250 | // Used exclusively by ASTDeclWriter to get the raw spelling list state. |
251 | unsigned getAttributeSpellingListIndexRaw() const { return SpellingIndex; } |
252 | |
253 | protected: |
254 | bool isAttributeSpellingListCalculated() const { |
255 | return SpellingIndex != SpellingNotCalculated; |
256 | } |
257 | }; |
258 | |
259 | inline bool doesKeywordAttributeTakeArgs(tok::TokenKind Kind) { |
260 | switch (Kind) { |
261 | default: |
262 | return false; |
263 | #define KEYWORD_ATTRIBUTE(NAME, HASARG, ...) \ |
264 | case tok::kw_##NAME: \ |
265 | return HASARG; |
266 | #include "clang/Basic/RegularKeywordAttrInfo.inc" |
267 | #undef KEYWORD_ATTRIBUTE |
268 | } |
269 | } |
270 | |
271 | } // namespace clang |
272 | |
273 | #endif // LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H |
274 | |