1 //===----- Attr.h --- Helper functions for attribute handling in Sema -----===//
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 provides helpers for Sema functions that handle attributes.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_CLANG_SEMA_ATTR_H
14 #define LLVM_CLANG_SEMA_ATTR_H
15
16 #include "clang/AST/Attr.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/DeclBase.h"
19 #include "clang/AST/DeclCXX.h"
20 #include "clang/AST/DeclObjC.h"
21 #include "clang/AST/Type.h"
22 #include "clang/Basic/AttributeCommonInfo.h"
23 #include "clang/Basic/DiagnosticSema.h"
24 #include "clang/Basic/SourceLocation.h"
25 #include "clang/Sema/ParsedAttr.h"
26 #include "clang/Sema/SemaBase.h"
27 #include "llvm/Support/Casting.h"
28
29 namespace clang {
30
31 /// isFuncOrMethodForAttrSubject - Return true if the given decl has function
32 /// type (function or function-typed variable) or an Objective-C
33 /// method.
isFuncOrMethodForAttrSubject(const Decl * D)34 inline bool isFuncOrMethodForAttrSubject(const Decl *D) {
35 return (D->getFunctionType() != nullptr) || llvm::isa<ObjCMethodDecl>(D);
36 }
37
38 /// Return true if the given decl has function type (function or
39 /// function-typed variable) or an Objective-C method or a block.
isFunctionOrMethodOrBlockForAttrSubject(const Decl * D)40 inline bool isFunctionOrMethodOrBlockForAttrSubject(const Decl *D) {
41 return isFuncOrMethodForAttrSubject(D) || llvm::isa<BlockDecl>(D);
42 }
43
44 /// Return true if the given decl has a declarator that should have
45 /// been processed by Sema::GetTypeForDeclarator.
hasDeclarator(const Decl * D)46 inline bool hasDeclarator(const Decl *D) {
47 // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
48 return isa<DeclaratorDecl>(D) || isa<BlockDecl>(D) ||
49 isa<TypedefNameDecl>(D) || isa<ObjCPropertyDecl>(D);
50 }
51
52 /// hasFunctionProto - Return true if the given decl has a argument
53 /// information. This decl should have already passed
54 /// isFuncOrMethodForAttrSubject or isFunctionOrMethodOrBlockForAttrSubject.
hasFunctionProto(const Decl * D)55 inline bool hasFunctionProto(const Decl *D) {
56 if (const FunctionType *FnTy = D->getFunctionType())
57 return isa<FunctionProtoType>(FnTy);
58 return isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D);
59 }
60
61 /// getFunctionOrMethodNumParams - Return number of function or method
62 /// parameters. It is an error to call this on a K&R function (use
63 /// hasFunctionProto first).
getFunctionOrMethodNumParams(const Decl * D)64 inline unsigned getFunctionOrMethodNumParams(const Decl *D) {
65 if (const FunctionType *FnTy = D->getFunctionType())
66 return cast<FunctionProtoType>(FnTy)->getNumParams();
67 if (const auto *BD = dyn_cast<BlockDecl>(D))
68 return BD->getNumParams();
69 return cast<ObjCMethodDecl>(D)->param_size();
70 }
71
getFunctionOrMethodParam(const Decl * D,unsigned Idx)72 inline const ParmVarDecl *getFunctionOrMethodParam(const Decl *D,
73 unsigned Idx) {
74 if (const auto *FD = dyn_cast<FunctionDecl>(D))
75 return FD->getParamDecl(Idx);
76 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
77 return MD->getParamDecl(Idx);
78 if (const auto *BD = dyn_cast<BlockDecl>(D))
79 return BD->getParamDecl(Idx);
80 return nullptr;
81 }
82
getFunctionOrMethodParamType(const Decl * D,unsigned Idx)83 inline QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) {
84 if (const FunctionType *FnTy = D->getFunctionType())
85 return cast<FunctionProtoType>(FnTy)->getParamType(Idx);
86 if (const auto *BD = dyn_cast<BlockDecl>(D))
87 return BD->getParamDecl(Idx)->getType();
88
89 return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType();
90 }
91
getFunctionOrMethodParamRange(const Decl * D,unsigned Idx)92 inline SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) {
93 if (auto *PVD = getFunctionOrMethodParam(D, Idx))
94 return PVD->getSourceRange();
95 return SourceRange();
96 }
97
getFunctionOrMethodResultType(const Decl * D)98 inline QualType getFunctionOrMethodResultType(const Decl *D) {
99 if (const FunctionType *FnTy = D->getFunctionType())
100 return FnTy->getReturnType();
101 return cast<ObjCMethodDecl>(D)->getReturnType();
102 }
103
getFunctionOrMethodResultSourceRange(const Decl * D)104 inline SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) {
105 if (const auto *FD = dyn_cast<FunctionDecl>(D))
106 return FD->getReturnTypeSourceRange();
107 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
108 return MD->getReturnTypeSourceRange();
109 return SourceRange();
110 }
111
isFunctionOrMethodVariadic(const Decl * D)112 inline bool isFunctionOrMethodVariadic(const Decl *D) {
113 if (const FunctionType *FnTy = D->getFunctionType())
114 return cast<FunctionProtoType>(FnTy)->isVariadic();
115 if (const auto *BD = dyn_cast<BlockDecl>(D))
116 return BD->isVariadic();
117 return cast<ObjCMethodDecl>(D)->isVariadic();
118 }
119
isInstanceMethod(const Decl * D)120 inline bool isInstanceMethod(const Decl *D) {
121 if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(D))
122 return MethodDecl->isInstance();
123 return false;
124 }
125
126 /// Diagnose mutually exclusive attributes when present on a given
127 /// declaration. Returns true if diagnosed.
128 template <typename AttrTy>
checkAttrMutualExclusion(SemaBase & S,Decl * D,const ParsedAttr & AL)129 bool checkAttrMutualExclusion(SemaBase &S, Decl *D, const ParsedAttr &AL) {
130 if (const auto *A = D->getAttr<AttrTy>()) {
131 S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
132 << AL << A
133 << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute());
134 S.Diag(A->getLocation(), diag::note_conflicting_attribute);
135 return true;
136 }
137 return false;
138 }
139
140 template <typename AttrTy>
checkAttrMutualExclusion(SemaBase & S,Decl * D,const Attr & AL)141 bool checkAttrMutualExclusion(SemaBase &S, Decl *D, const Attr &AL) {
142 if (const auto *A = D->getAttr<AttrTy>()) {
143 S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible)
144 << &AL << A
145 << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute());
146 Diag(A->getLocation(), diag::note_conflicting_attribute);
147 return true;
148 }
149 return false;
150 }
151
152 template <typename... DiagnosticArgs>
153 const SemaBase::SemaDiagnosticBuilder &
appendDiagnostics(const SemaBase::SemaDiagnosticBuilder & Bldr)154 appendDiagnostics(const SemaBase::SemaDiagnosticBuilder &Bldr) {
155 return Bldr;
156 }
157
158 template <typename T, typename... DiagnosticArgs>
159 const SemaBase::SemaDiagnosticBuilder &
appendDiagnostics(const SemaBase::SemaDiagnosticBuilder & Bldr,T && ExtraArg,DiagnosticArgs &&...ExtraArgs)160 appendDiagnostics(const SemaBase::SemaDiagnosticBuilder &Bldr, T &&ExtraArg,
161 DiagnosticArgs &&...ExtraArgs) {
162 return appendDiagnostics(Bldr << std::forward<T>(ExtraArg),
163 std::forward<DiagnosticArgs>(ExtraArgs)...);
164 }
165
166 /// Applies the given attribute to the Decl without performing any
167 /// additional semantic checking.
168 template <typename AttrType>
handleSimpleAttribute(SemaBase & S,Decl * D,const AttributeCommonInfo & CI)169 void handleSimpleAttribute(SemaBase &S, Decl *D,
170 const AttributeCommonInfo &CI) {
171 D->addAttr(::new (S.getASTContext()) AttrType(S.getASTContext(), CI));
172 }
173
174 /// Add an attribute @c AttrType to declaration @c D, provided that
175 /// @c PassesCheck is true.
176 /// Otherwise, emit diagnostic @c DiagID, passing in all parameters
177 /// specified in @c ExtraArgs.
178 template <typename AttrType, typename... DiagnosticArgs>
handleSimpleAttributeOrDiagnose(SemaBase & S,Decl * D,const AttributeCommonInfo & CI,bool PassesCheck,unsigned DiagID,DiagnosticArgs &&...ExtraArgs)179 void handleSimpleAttributeOrDiagnose(SemaBase &S, Decl *D,
180 const AttributeCommonInfo &CI,
181 bool PassesCheck, unsigned DiagID,
182 DiagnosticArgs &&...ExtraArgs) {
183 if (!PassesCheck) {
184 SemaBase::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID);
185 appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...);
186 return;
187 }
188 handleSimpleAttribute<AttrType>(S, D, CI);
189 }
190
191 } // namespace clang
192 #endif // LLVM_CLANG_SEMA_ATTR_H
193