xref: /llvm-project/clang/include/clang/Basic/AttributeCommonInfo.h (revision 4018317407006b2c632fbb75729de624a2426439)
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/Basic/AttrParsedAttrList.inc"
65 #undef PARSED_ATTR
66     NoSemaHandlerAttribute,
67     IgnoredAttribute,
68     UnknownAttribute,
69   };
70   enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, GSL, RISCV };
71   enum class AttrArgsInfo {
72     None,
73     Optional,
74     Required,
75   };
76 
77 private:
78   const IdentifierInfo *AttrName = nullptr;
79   const IdentifierInfo *ScopeName = nullptr;
80   SourceRange AttrRange;
81   const SourceLocation ScopeLoc;
82   // Corresponds to the Kind enum.
83   LLVM_PREFERRED_TYPE(Kind)
84   unsigned AttrKind : 16;
85   /// Corresponds to the Syntax enum.
86   LLVM_PREFERRED_TYPE(Syntax)
87   unsigned SyntaxUsed : 4;
88   LLVM_PREFERRED_TYPE(bool)
89   unsigned SpellingIndex : 4;
90   LLVM_PREFERRED_TYPE(bool)
91   unsigned IsAlignas : 1;
92   LLVM_PREFERRED_TYPE(bool)
93   unsigned IsRegularKeywordAttribute : 1;
94 
95 protected:
96   static constexpr unsigned SpellingNotCalculated = 0xf;
97 
98 public:
99   /// Combines information about the source-code form of an attribute,
100   /// including its syntax and spelling.
101   class Form {
102   public:
103     constexpr Form(Syntax SyntaxUsed, unsigned SpellingIndex, bool IsAlignas,
104                    bool IsRegularKeywordAttribute)
105         : SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingIndex),
106           IsAlignas(IsAlignas),
107           IsRegularKeywordAttribute(IsRegularKeywordAttribute) {}
108     constexpr Form(tok::TokenKind Tok)
109         : SyntaxUsed(AS_Keyword), SpellingIndex(SpellingNotCalculated),
110           IsAlignas(Tok == tok::kw_alignas),
111           IsRegularKeywordAttribute(tok::isRegularKeywordAttribute(Tok)) {}
112 
113     Syntax getSyntax() const { return Syntax(SyntaxUsed); }
114     unsigned getSpellingIndex() const { return SpellingIndex; }
115     bool isAlignas() const { return IsAlignas; }
116     bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; }
117 
118     static Form GNU() { return AS_GNU; }
119     static Form CXX11() { return AS_CXX11; }
120     static Form C23() { return AS_C23; }
121     static Form Declspec() { return AS_Declspec; }
122     static Form Microsoft() { return AS_Microsoft; }
123     static Form Keyword(bool IsAlignas, bool IsRegularKeywordAttribute) {
124       return Form(AS_Keyword, SpellingNotCalculated, IsAlignas,
125                   IsRegularKeywordAttribute);
126     }
127     static Form Pragma() { return AS_Pragma; }
128     static Form ContextSensitiveKeyword() { return AS_ContextSensitiveKeyword; }
129     static Form HLSLAnnotation() { return AS_HLSLAnnotation; }
130     static Form Implicit() { return AS_Implicit; }
131 
132   private:
133     constexpr Form(Syntax SyntaxUsed)
134         : SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated),
135           IsAlignas(0), IsRegularKeywordAttribute(0) {}
136 
137     LLVM_PREFERRED_TYPE(Syntax)
138     unsigned SyntaxUsed : 4;
139     unsigned SpellingIndex : 4;
140     LLVM_PREFERRED_TYPE(bool)
141     unsigned IsAlignas : 1;
142     LLVM_PREFERRED_TYPE(bool)
143     unsigned IsRegularKeywordAttribute : 1;
144   };
145 
146   AttributeCommonInfo(const IdentifierInfo *AttrName,
147                       const IdentifierInfo *ScopeName, SourceRange AttrRange,
148                       SourceLocation ScopeLoc, Kind AttrKind, Form FormUsed)
149       : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
150         ScopeLoc(ScopeLoc), AttrKind(AttrKind),
151         SyntaxUsed(FormUsed.getSyntax()),
152         SpellingIndex(FormUsed.getSpellingIndex()),
153         IsAlignas(FormUsed.isAlignas()),
154         IsRegularKeywordAttribute(FormUsed.isRegularKeywordAttribute()) {
155     assert(SyntaxUsed >= AS_GNU && SyntaxUsed <= AS_Implicit &&
156            "Invalid syntax!");
157   }
158 
159   AttributeCommonInfo(const IdentifierInfo *AttrName,
160                       const IdentifierInfo *ScopeName, SourceRange AttrRange,
161                       SourceLocation ScopeLoc, Form FormUsed)
162       : AttributeCommonInfo(
163             AttrName, ScopeName, AttrRange, ScopeLoc,
164             getParsedKind(AttrName, ScopeName, FormUsed.getSyntax()),
165             FormUsed) {}
166 
167   AttributeCommonInfo(const IdentifierInfo *AttrName, SourceRange AttrRange,
168                       Form FormUsed)
169       : AttributeCommonInfo(AttrName, nullptr, AttrRange, SourceLocation(),
170                             FormUsed) {}
171 
172   AttributeCommonInfo(SourceRange AttrRange, Kind K, Form FormUsed)
173       : AttributeCommonInfo(nullptr, nullptr, AttrRange, SourceLocation(), K,
174                             FormUsed) {}
175 
176   AttributeCommonInfo(AttributeCommonInfo &&) = default;
177   AttributeCommonInfo(const AttributeCommonInfo &) = default;
178 
179   Kind getParsedKind() const { return Kind(AttrKind); }
180   Syntax getSyntax() const { return Syntax(SyntaxUsed); }
181   Form getForm() const {
182     return Form(getSyntax(), SpellingIndex, IsAlignas,
183                 IsRegularKeywordAttribute);
184   }
185   const IdentifierInfo *getAttrName() const { return AttrName; }
186   void setAttrName(const IdentifierInfo *AttrNameII) { AttrName = AttrNameII; }
187   SourceLocation getLoc() const { return AttrRange.getBegin(); }
188   SourceRange getRange() const { return AttrRange; }
189   void setRange(SourceRange R) { AttrRange = R; }
190 
191   bool hasScope() const { return ScopeName; }
192   const IdentifierInfo *getScopeName() const { return ScopeName; }
193   SourceLocation getScopeLoc() const { return ScopeLoc; }
194 
195   /// Gets the normalized full name, which consists of both scope and name and
196   /// with surrounding underscores removed as appropriate (e.g.
197   /// __gnu__::__attr__ will be normalized to gnu::attr).
198   std::string getNormalizedFullName() const;
199 
200   bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
201   bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
202 
203   bool isGNUScope() const;
204   bool isClangScope() const;
205 
206   bool isCXX11Attribute() const { return SyntaxUsed == AS_CXX11 || IsAlignas; }
207 
208   bool isC23Attribute() const { return SyntaxUsed == AS_C23; }
209 
210   bool isAlignas() const {
211     // FIXME: In the current state, the IsAlignas member variable is only true
212     // with the C++  `alignas` keyword but not `_Alignas`. The following
213     // expression works around the otherwise lost information so it will return
214     // true for `alignas` or `_Alignas` while still returning false for things
215     // like  `__attribute__((aligned))`.
216     return (getParsedKind() == AT_Aligned && isKeywordAttribute());
217   }
218 
219   /// The attribute is spelled [[]] in either C or C++ mode, including standard
220   /// attributes spelled with a keyword, like alignas.
221   bool isStandardAttributeSyntax() const {
222     return isCXX11Attribute() || isC23Attribute();
223   }
224 
225   bool isGNUAttribute() const { return SyntaxUsed == AS_GNU; }
226 
227   bool isKeywordAttribute() const {
228     return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
229   }
230 
231   bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; }
232 
233   bool isContextSensitiveKeywordAttribute() const {
234     return SyntaxUsed == AS_ContextSensitiveKeyword;
235   }
236 
237   unsigned getAttributeSpellingListIndex() const {
238     assert((isAttributeSpellingListCalculated() || AttrName) &&
239            "Spelling cannot be found");
240     return isAttributeSpellingListCalculated()
241                ? SpellingIndex
242                : calculateAttributeSpellingListIndex();
243   }
244   void setAttributeSpellingListIndex(unsigned V) { SpellingIndex = V; }
245 
246   static Kind getParsedKind(const IdentifierInfo *Name,
247                             const IdentifierInfo *Scope, Syntax SyntaxUsed);
248 
249   static AttrArgsInfo getCXX11AttrArgsInfo(const IdentifierInfo *Name);
250 
251 private:
252   /// Get an index into the attribute spelling list
253   /// defined in Attr.td. This index is used by an attribute
254   /// to pretty print itself.
255   unsigned calculateAttributeSpellingListIndex() const;
256 
257   friend class clang::ASTRecordWriter;
258   // Used exclusively by ASTDeclWriter to get the raw spelling list state.
259   unsigned getAttributeSpellingListIndexRaw() const { return SpellingIndex; }
260 
261 protected:
262   bool isAttributeSpellingListCalculated() const {
263     return SpellingIndex != SpellingNotCalculated;
264   }
265 };
266 
267 inline bool doesKeywordAttributeTakeArgs(tok::TokenKind Kind) {
268   switch (Kind) {
269   default:
270     return false;
271 #define KEYWORD_ATTRIBUTE(NAME, HASARG, ...)                                   \
272   case tok::kw_##NAME:                                                         \
273     return HASARG;
274 #include "clang/Basic/RegularKeywordAttrInfo.inc"
275 #undef KEYWORD_ATTRIBUTE
276   }
277 }
278 
279 } // namespace clang
280 
281 #endif // LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
282