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:
Form(Syntax SyntaxUsed,unsigned SpellingIndex,bool IsAlignas,bool IsRegularKeywordAttribute)97 constexpr Form(Syntax SyntaxUsed, unsigned SpellingIndex, bool IsAlignas,
98 bool IsRegularKeywordAttribute)
99 : SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingIndex),
100 IsAlignas(IsAlignas),
101 IsRegularKeywordAttribute(IsRegularKeywordAttribute) {}
Form(tok::TokenKind Tok)102 constexpr Form(tok::TokenKind Tok)
103 : SyntaxUsed(AS_Keyword), SpellingIndex(SpellingNotCalculated),
104 IsAlignas(Tok == tok::kw_alignas),
105 IsRegularKeywordAttribute(tok::isRegularKeywordAttribute(Tok)) {}
106
getSyntax()107 Syntax getSyntax() const { return Syntax(SyntaxUsed); }
getSpellingIndex()108 unsigned getSpellingIndex() const { return SpellingIndex; }
isAlignas()109 bool isAlignas() const { return IsAlignas; }
isRegularKeywordAttribute()110 bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; }
111
GNU()112 static Form GNU() { return AS_GNU; }
CXX11()113 static Form CXX11() { return AS_CXX11; }
C23()114 static Form C23() { return AS_C23; }
Declspec()115 static Form Declspec() { return AS_Declspec; }
Microsoft()116 static Form Microsoft() { return AS_Microsoft; }
Keyword(bool IsAlignas,bool IsRegularKeywordAttribute)117 static Form Keyword(bool IsAlignas, bool IsRegularKeywordAttribute) {
118 return Form(AS_Keyword, SpellingNotCalculated, IsAlignas,
119 IsRegularKeywordAttribute);
120 }
Pragma()121 static Form Pragma() { return AS_Pragma; }
ContextSensitiveKeyword()122 static Form ContextSensitiveKeyword() { return AS_ContextSensitiveKeyword; }
HLSLAnnotation()123 static Form HLSLAnnotation() { return AS_HLSLAnnotation; }
Implicit()124 static Form Implicit() { return AS_Implicit; }
125
126 private:
Form(Syntax SyntaxUsed)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
AttributeCommonInfo(const IdentifierInfo * AttrName,const IdentifierInfo * ScopeName,SourceRange AttrRange,SourceLocation ScopeLoc,Kind AttrKind,Form FormUsed)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
AttributeCommonInfo(const IdentifierInfo * AttrName,const IdentifierInfo * ScopeName,SourceRange AttrRange,SourceLocation ScopeLoc,Form FormUsed)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(AttrName, ScopeName, FormUsed.getSyntax()),
159 FormUsed) {}
160
AttributeCommonInfo(const IdentifierInfo * AttrName,SourceRange AttrRange,Form FormUsed)161 AttributeCommonInfo(const IdentifierInfo *AttrName, SourceRange AttrRange,
162 Form FormUsed)
163 : AttributeCommonInfo(AttrName, nullptr, AttrRange, SourceLocation(),
164 FormUsed) {}
165
AttributeCommonInfo(SourceRange AttrRange,Kind K,Form FormUsed)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
getParsedKind()173 Kind getParsedKind() const { return Kind(AttrKind); }
getSyntax()174 Syntax getSyntax() const { return Syntax(SyntaxUsed); }
getForm()175 Form getForm() const {
176 return Form(getSyntax(), SpellingIndex, IsAlignas,
177 IsRegularKeywordAttribute);
178 }
getAttrName()179 const IdentifierInfo *getAttrName() const { return AttrName; }
setAttrName(const IdentifierInfo * AttrNameII)180 void setAttrName(const IdentifierInfo *AttrNameII) { AttrName = AttrNameII; }
getLoc()181 SourceLocation getLoc() const { return AttrRange.getBegin(); }
getRange()182 SourceRange getRange() const { return AttrRange; }
setRange(SourceRange R)183 void setRange(SourceRange R) { AttrRange = R; }
184
hasScope()185 bool hasScope() const { return ScopeName; }
getScopeName()186 const IdentifierInfo *getScopeName() const { return ScopeName; }
getScopeLoc()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
isDeclspecAttribute()194 bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
isMicrosoftAttribute()195 bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
196
197 bool isGNUScope() const;
198 bool isClangScope() const;
199
isCXX11Attribute()200 bool isCXX11Attribute() const { return SyntaxUsed == AS_CXX11 || IsAlignas; }
201
isC23Attribute()202 bool isC23Attribute() const { return SyntaxUsed == AS_C23; }
203
isAlignas()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.
isStandardAttributeSyntax()215 bool isStandardAttributeSyntax() const {
216 return isCXX11Attribute() || isC23Attribute();
217 }
218
isGNUAttribute()219 bool isGNUAttribute() const { return SyntaxUsed == AS_GNU; }
220
isKeywordAttribute()221 bool isKeywordAttribute() const {
222 return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
223 }
224
isRegularKeywordAttribute()225 bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; }
226
isContextSensitiveKeywordAttribute()227 bool isContextSensitiveKeywordAttribute() const {
228 return SyntaxUsed == AS_ContextSensitiveKeyword;
229 }
230
getAttributeSpellingListIndex()231 unsigned getAttributeSpellingListIndex() const {
232 assert((isAttributeSpellingListCalculated() || AttrName) &&
233 "Spelling cannot be found");
234 return isAttributeSpellingListCalculated()
235 ? SpellingIndex
236 : calculateAttributeSpellingListIndex();
237 }
setAttributeSpellingListIndex(unsigned V)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.
getAttributeSpellingListIndexRaw()251 unsigned getAttributeSpellingListIndexRaw() const { return SpellingIndex; }
252
253 protected:
isAttributeSpellingListCalculated()254 bool isAttributeSpellingListCalculated() const {
255 return SpellingIndex != SpellingNotCalculated;
256 }
257 };
258
doesKeywordAttributeTakeArgs(tok::TokenKind Kind)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