13f03c12aSJohn Brawn //===- Attribute.cpp ------------------------------------------------------===// 23f03c12aSJohn Brawn // 33f03c12aSJohn Brawn // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 43f03c12aSJohn Brawn // See https://llvm.org/LICENSE.txt for license information. 53f03c12aSJohn Brawn // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 63f03c12aSJohn Brawn // 73f03c12aSJohn Brawn //===----------------------------------------------------------------------===// 83f03c12aSJohn Brawn // 93f03c12aSJohn Brawn // Example clang plugin which adds an an annotation to file-scope declarations 103f03c12aSJohn Brawn // with the 'example' attribute. 113f03c12aSJohn Brawn // 121285a495SAnders Waldenborg // This plugin is used by clang/test/Frontend/plugin-attribute tests. 131285a495SAnders Waldenborg // 143f03c12aSJohn Brawn //===----------------------------------------------------------------------===// 153f03c12aSJohn Brawn 163f03c12aSJohn Brawn #include "clang/AST/ASTContext.h" 173f03c12aSJohn Brawn #include "clang/AST/Attr.h" 183f03c12aSJohn Brawn #include "clang/Sema/ParsedAttr.h" 193f03c12aSJohn Brawn #include "clang/Sema/Sema.h" 203f03c12aSJohn Brawn #include "clang/Sema/SemaDiagnostic.h" 213f03c12aSJohn Brawn #include "llvm/IR/Attributes.h" 223f03c12aSJohn Brawn using namespace clang; 233f03c12aSJohn Brawn 243f03c12aSJohn Brawn namespace { 253f03c12aSJohn Brawn 263f03c12aSJohn Brawn struct ExampleAttrInfo : public ParsedAttrInfo { 273f03c12aSJohn Brawn ExampleAttrInfo() { 28b2ba6867SYafei Liu // Can take up to 15 optional arguments, to emulate accepting a variadic 29b2ba6867SYafei Liu // number of arguments. This just illustrates how many arguments a 30b2ba6867SYafei Liu // `ParsedAttrInfo` can hold, we will not use that much in this example. 31b2ba6867SYafei Liu OptArgs = 15; 326e0fc888SAaron Ballman // GNU-style __attribute__(("example")) and C++/C23-style [[example]] and 333f03c12aSJohn Brawn // [[plugin::example]] supported. 34e8743c0fSBenjamin Kramer static constexpr Spelling S[] = {{ParsedAttr::AS_GNU, "example"}, 356e0fc888SAaron Ballman {ParsedAttr::AS_C23, "example"}, 36e8743c0fSBenjamin Kramer {ParsedAttr::AS_CXX11, "example"}, 37e8743c0fSBenjamin Kramer {ParsedAttr::AS_CXX11, "plugin::example"}}; 38e8743c0fSBenjamin Kramer Spellings = S; 393f03c12aSJohn Brawn } 403f03c12aSJohn Brawn 413f03c12aSJohn Brawn bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr, 423f03c12aSJohn Brawn const Decl *D) const override { 433f03c12aSJohn Brawn // This attribute appertains to functions only. 443f03c12aSJohn Brawn if (!isa<FunctionDecl>(D)) { 45*41a94de7SMaksim Ivanov S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) 46*41a94de7SMaksim Ivanov << Attr << Attr.isRegularKeywordAttribute() << ExpectedFunction; 473f03c12aSJohn Brawn return false; 483f03c12aSJohn Brawn } 493f03c12aSJohn Brawn return true; 503f03c12aSJohn Brawn } 513f03c12aSJohn Brawn 523f03c12aSJohn Brawn AttrHandling handleDeclAttribute(Sema &S, Decl *D, 533f03c12aSJohn Brawn const ParsedAttr &Attr) const override { 543f03c12aSJohn Brawn // Check if the decl is at file scope. 553f03c12aSJohn Brawn if (!D->getDeclContext()->isFileContext()) { 563f03c12aSJohn Brawn unsigned ID = S.getDiagnostics().getCustomDiagID( 573f03c12aSJohn Brawn DiagnosticsEngine::Error, 583f03c12aSJohn Brawn "'example' attribute only allowed at file scope"); 593f03c12aSJohn Brawn S.Diag(Attr.getLoc(), ID); 603f03c12aSJohn Brawn return AttributeNotApplied; 613f03c12aSJohn Brawn } 62b2ba6867SYafei Liu // We make some rules here: 63b2ba6867SYafei Liu // 1. Only accept at most 3 arguments here. 64b2ba6867SYafei Liu // 2. The first argument must be a string literal if it exists. 65b2ba6867SYafei Liu if (Attr.getNumArgs() > 3) { 66b2ba6867SYafei Liu unsigned ID = S.getDiagnostics().getCustomDiagID( 67b2ba6867SYafei Liu DiagnosticsEngine::Error, 68b2ba6867SYafei Liu "'example' attribute only accepts at most three arguments"); 69b2ba6867SYafei Liu S.Diag(Attr.getLoc(), ID); 703f03c12aSJohn Brawn return AttributeNotApplied; 713f03c12aSJohn Brawn } 72b2ba6867SYafei Liu // If there are arguments, the first argument should be a string literal. 73b2ba6867SYafei Liu if (Attr.getNumArgs() > 0) { 74b2ba6867SYafei Liu auto *Arg0 = Attr.getArgAsExpr(0); 75b2ba6867SYafei Liu StringLiteral *Literal = 76b2ba6867SYafei Liu dyn_cast<StringLiteral>(Arg0->IgnoreParenCasts()); 77b2ba6867SYafei Liu if (!Literal) { 78b2ba6867SYafei Liu unsigned ID = S.getDiagnostics().getCustomDiagID( 79b2ba6867SYafei Liu DiagnosticsEngine::Error, "first argument to the 'example' " 80b2ba6867SYafei Liu "attribute must be a string literal"); 81b2ba6867SYafei Liu S.Diag(Attr.getLoc(), ID); 82b2ba6867SYafei Liu return AttributeNotApplied; 833f03c12aSJohn Brawn } 84b2ba6867SYafei Liu SmallVector<Expr *, 16> ArgsBuf; 85b2ba6867SYafei Liu for (unsigned i = 0; i < Attr.getNumArgs(); i++) { 86b2ba6867SYafei Liu ArgsBuf.push_back(Attr.getArgAsExpr(i)); 87b2ba6867SYafei Liu } 88b2ba6867SYafei Liu D->addAttr(AnnotateAttr::Create(S.Context, "example", ArgsBuf.data(), 89b2ba6867SYafei Liu ArgsBuf.size(), Attr.getRange())); 90b2ba6867SYafei Liu } else { 913f03c12aSJohn Brawn // Attach an annotate attribute to the Decl. 92b2ba6867SYafei Liu D->addAttr(AnnotateAttr::Create(S.Context, "example", nullptr, 0, 933f03c12aSJohn Brawn Attr.getRange())); 94b2ba6867SYafei Liu } 953f03c12aSJohn Brawn return AttributeApplied; 963f03c12aSJohn Brawn } 979a97a57dSEric Astor 989a97a57dSEric Astor bool diagAppertainsToStmt(Sema &S, const ParsedAttr &Attr, 999a97a57dSEric Astor const Stmt *St) const override { 1009a97a57dSEric Astor // This attribute appertains to for loop statements only. 1019a97a57dSEric Astor if (!isa<ForStmt>(St)) { 102*41a94de7SMaksim Ivanov S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) 103*41a94de7SMaksim Ivanov << Attr << Attr.isRegularKeywordAttribute() 104*41a94de7SMaksim Ivanov << ExpectedForLoopStatement; 1059a97a57dSEric Astor return false; 1069a97a57dSEric Astor } 1079a97a57dSEric Astor return true; 1089a97a57dSEric Astor } 1099a97a57dSEric Astor 1109a97a57dSEric Astor AttrHandling handleStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &Attr, 1119a97a57dSEric Astor class Attr *&Result) const override { 1129a97a57dSEric Astor // We make some rules here: 1139a97a57dSEric Astor // 1. Only accept at most 3 arguments here. 1149a97a57dSEric Astor // 2. The first argument must be a string literal if it exists. 1159a97a57dSEric Astor if (Attr.getNumArgs() > 3) { 1169a97a57dSEric Astor unsigned ID = S.getDiagnostics().getCustomDiagID( 1179a97a57dSEric Astor DiagnosticsEngine::Error, 1189a97a57dSEric Astor "'example' attribute only accepts at most three arguments"); 1199a97a57dSEric Astor S.Diag(Attr.getLoc(), ID); 1209a97a57dSEric Astor return AttributeNotApplied; 1219a97a57dSEric Astor } 1229a97a57dSEric Astor // If there are arguments, the first argument should be a string literal. 1239a97a57dSEric Astor if (Attr.getNumArgs() > 0) { 1249a97a57dSEric Astor auto *Arg0 = Attr.getArgAsExpr(0); 1259a97a57dSEric Astor StringLiteral *Literal = 1269a97a57dSEric Astor dyn_cast<StringLiteral>(Arg0->IgnoreParenCasts()); 1279a97a57dSEric Astor if (!Literal) { 1289a97a57dSEric Astor unsigned ID = S.getDiagnostics().getCustomDiagID( 1299a97a57dSEric Astor DiagnosticsEngine::Error, "first argument to the 'example' " 1309a97a57dSEric Astor "attribute must be a string literal"); 1319a97a57dSEric Astor S.Diag(Attr.getLoc(), ID); 1329a97a57dSEric Astor return AttributeNotApplied; 1339a97a57dSEric Astor } 1349a97a57dSEric Astor SmallVector<Expr *, 16> ArgsBuf; 1359a97a57dSEric Astor for (unsigned i = 0; i < Attr.getNumArgs(); i++) { 1369a97a57dSEric Astor ArgsBuf.push_back(Attr.getArgAsExpr(i)); 1379a97a57dSEric Astor } 1389a97a57dSEric Astor Result = AnnotateAttr::Create(S.Context, "example", ArgsBuf.data(), 1399a97a57dSEric Astor ArgsBuf.size(), Attr.getRange()); 1409a97a57dSEric Astor } else { 1419a97a57dSEric Astor Result = AnnotateAttr::Create(S.Context, "example", nullptr, 0, 1429a97a57dSEric Astor Attr.getRange()); 1439a97a57dSEric Astor } 1449a97a57dSEric Astor return AttributeApplied; 1459a97a57dSEric Astor } 1463f03c12aSJohn Brawn }; 1473f03c12aSJohn Brawn 1483f03c12aSJohn Brawn } // namespace 1493f03c12aSJohn Brawn 1503f03c12aSJohn Brawn static ParsedAttrInfoRegistry::Add<ExampleAttrInfo> X("example", ""); 151