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> : <semantic>
56     AS_HLSLSemantic,
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; }
HLSLSemantic()123     static Form HLSLSemantic() { return AS_HLSLSemantic; }
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