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 #include "clang/Basic/SourceLocation.h"
17 
18 namespace clang {
19 class IdentifierInfo;
20 class ASTRecordWriter;
21 
22 class AttributeCommonInfo {
23 public:
24   /// The style used to specify an attribute.
25   enum Syntax {
26     /// __attribute__((...))
27     AS_GNU,
28 
29     /// [[...]]
30     AS_CXX11,
31 
32     /// [[...]]
33     AS_C2x,
34 
35     /// __declspec(...)
36     AS_Declspec,
37 
38     /// [uuid("...")] class Foo
39     AS_Microsoft,
40 
41     /// __ptr16, alignas(...), etc.
42     AS_Keyword,
43 
44     /// #pragma ...
45     AS_Pragma,
46 
47     // Note TableGen depends on the order above.  Do not add or change the order
48     // without adding related code to TableGen/ClangAttrEmitter.cpp.
49     /// Context-sensitive version of a keyword attribute.
50     AS_ContextSensitiveKeyword,
51 
52     /// <vardecl> : <semantic>
53     AS_HLSLSemantic,
54   };
55   enum Kind {
56 #define PARSED_ATTR(NAME) AT_##NAME,
57 #include "clang/Sema/AttrParsedAttrList.inc"
58 #undef PARSED_ATTR
59     NoSemaHandlerAttribute,
60     IgnoredAttribute,
61     UnknownAttribute,
62   };
63 
64 private:
65   const IdentifierInfo *AttrName = nullptr;
66   const IdentifierInfo *ScopeName = nullptr;
67   SourceRange AttrRange;
68   const SourceLocation ScopeLoc;
69   // Corresponds to the Kind enum.
70   unsigned AttrKind : 16;
71   /// Corresponds to the Syntax enum.
72   unsigned SyntaxUsed : 4;
73   unsigned SpellingIndex : 4;
74 
75 protected:
76   static constexpr unsigned SpellingNotCalculated = 0xf;
77 
78 public:
79   AttributeCommonInfo(SourceRange AttrRange)
80       : AttrRange(AttrRange), ScopeLoc(), AttrKind(0), SyntaxUsed(0),
81         SpellingIndex(SpellingNotCalculated) {}
82 
83   AttributeCommonInfo(SourceLocation AttrLoc)
84       : AttrRange(AttrLoc), ScopeLoc(), AttrKind(0), SyntaxUsed(0),
85         SpellingIndex(SpellingNotCalculated) {}
86 
87   AttributeCommonInfo(const IdentifierInfo *AttrName,
88                       const IdentifierInfo *ScopeName, SourceRange AttrRange,
89                       SourceLocation ScopeLoc, Syntax SyntaxUsed)
90       : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
91         ScopeLoc(ScopeLoc),
92         AttrKind(getParsedKind(AttrName, ScopeName, SyntaxUsed)),
93         SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated) {}
94 
95   AttributeCommonInfo(const IdentifierInfo *AttrName,
96                       const IdentifierInfo *ScopeName, SourceRange AttrRange,
97                       SourceLocation ScopeLoc, Kind AttrKind, Syntax SyntaxUsed)
98       : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
99         ScopeLoc(ScopeLoc), AttrKind(AttrKind), SyntaxUsed(SyntaxUsed),
100         SpellingIndex(SpellingNotCalculated) {}
101 
102   AttributeCommonInfo(const IdentifierInfo *AttrName,
103                       const IdentifierInfo *ScopeName, SourceRange AttrRange,
104                       SourceLocation ScopeLoc, Kind AttrKind, Syntax SyntaxUsed,
105                       unsigned Spelling)
106       : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
107         ScopeLoc(ScopeLoc), AttrKind(AttrKind), SyntaxUsed(SyntaxUsed),
108         SpellingIndex(Spelling) {}
109 
110   AttributeCommonInfo(const IdentifierInfo *AttrName, SourceRange AttrRange,
111                       Syntax SyntaxUsed)
112       : AttrName(AttrName), ScopeName(nullptr), AttrRange(AttrRange),
113         ScopeLoc(), AttrKind(getParsedKind(AttrName, ScopeName, SyntaxUsed)),
114         SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated) {}
115 
116   AttributeCommonInfo(SourceRange AttrRange, Kind K, Syntax SyntaxUsed)
117       : AttrName(nullptr), ScopeName(nullptr), AttrRange(AttrRange), ScopeLoc(),
118         AttrKind(K), SyntaxUsed(SyntaxUsed),
119         SpellingIndex(SpellingNotCalculated) {}
120 
121   AttributeCommonInfo(SourceRange AttrRange, Kind K, Syntax SyntaxUsed,
122                       unsigned Spelling)
123       : AttrName(nullptr), ScopeName(nullptr), AttrRange(AttrRange), ScopeLoc(),
124         AttrKind(K), SyntaxUsed(SyntaxUsed), SpellingIndex(Spelling) {}
125 
126   AttributeCommonInfo(AttributeCommonInfo &&) = default;
127   AttributeCommonInfo(const AttributeCommonInfo &) = default;
128 
129   Kind getParsedKind() const { return Kind(AttrKind); }
130   Syntax getSyntax() const { return Syntax(SyntaxUsed); }
131   const IdentifierInfo *getAttrName() const { return AttrName; }
132   SourceLocation getLoc() const { return AttrRange.getBegin(); }
133   SourceRange getRange() const { return AttrRange; }
134   void setRange(SourceRange R) { AttrRange = R; }
135 
136   bool hasScope() const { return ScopeName; }
137   const IdentifierInfo *getScopeName() const { return ScopeName; }
138   SourceLocation getScopeLoc() const { return ScopeLoc; }
139 
140   /// Gets the normalized full name, which consists of both scope and name and
141   /// with surrounding underscores removed as appropriate (e.g.
142   /// __gnu__::__attr__ will be normalized to gnu::attr).
143   std::string getNormalizedFullName() const;
144 
145   bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
146   bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
147 
148   bool isGNUScope() const;
149   bool isClangScope() const;
150 
151   bool isAlignasAttribute() const {
152     // FIXME: Use a better mechanism to determine this.
153     // We use this in `isCXX11Attribute` below, so it _should_ only return
154     // true for the `alignas` spelling, but it currently also returns true
155     // for the `_Alignas` spelling, which only exists in C11. Distinguishing
156     // between the two is important because they behave differently:
157     // - `alignas` may only appear in the attribute-specifier-seq before
158     //   the decl-specifier-seq and is therefore associated with the
159     //   declaration.
160     // - `_Alignas` may appear anywhere within the declaration-specifiers
161     //   and is therefore associated with the `DeclSpec`.
162     // It's not clear how best to fix this:
163     // - We have the necessary information in the form of the `SpellingIndex`,
164     //   but we would need to compare against AlignedAttr::Keyword_alignas,
165     //   and we can't depend on clang/AST/Attr.h here.
166     // - We could test `getAttrName()->getName() == "alignas"`, but this is
167     //   inefficient.
168     return getParsedKind() == AT_Aligned && isKeywordAttribute();
169   }
170 
171   bool isCXX11Attribute() const {
172     return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
173   }
174 
175   bool isC2xAttribute() const { return SyntaxUsed == AS_C2x; }
176 
177   /// The attribute is spelled [[]] in either C or C++ mode, including standard
178   /// attributes spelled with a keyword, like alignas.
179   bool isStandardAttributeSyntax() const {
180     return isCXX11Attribute() || isC2xAttribute();
181   }
182 
183   bool isGNUAttribute() const { return SyntaxUsed == AS_GNU; }
184 
185   bool isKeywordAttribute() const {
186     return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
187   }
188 
189   bool isContextSensitiveKeywordAttribute() const {
190     return SyntaxUsed == AS_ContextSensitiveKeyword;
191   }
192 
193   unsigned getAttributeSpellingListIndex() const {
194     assert((isAttributeSpellingListCalculated() || AttrName) &&
195            "Spelling cannot be found");
196     return isAttributeSpellingListCalculated()
197                ? SpellingIndex
198                : calculateAttributeSpellingListIndex();
199   }
200   void setAttributeSpellingListIndex(unsigned V) { SpellingIndex = V; }
201 
202   static Kind getParsedKind(const IdentifierInfo *Name,
203                             const IdentifierInfo *Scope, Syntax SyntaxUsed);
204 
205 private:
206   /// Get an index into the attribute spelling list
207   /// defined in Attr.td. This index is used by an attribute
208   /// to pretty print itself.
209   unsigned calculateAttributeSpellingListIndex() const;
210 
211   friend class clang::ASTRecordWriter;
212   // Used exclusively by ASTDeclWriter to get the raw spelling list state.
213   unsigned getAttributeSpellingListIndexRaw() const { return SpellingIndex; }
214 
215 protected:
216   bool isAttributeSpellingListCalculated() const {
217     return SpellingIndex != SpellingNotCalculated;
218   }
219 };
220 } // namespace clang
221 
222 #endif // LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
223