1 //===- Attribute.cpp ------------------------------------------------------===// 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 // Example clang plugin which adds an an annotation to file-scope declarations 10 // with the 'example' attribute. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/AST/ASTContext.h" 15 #include "clang/AST/Attr.h" 16 #include "clang/Sema/ParsedAttr.h" 17 #include "clang/Sema/Sema.h" 18 #include "clang/Sema/SemaDiagnostic.h" 19 #include "llvm/IR/Attributes.h" 20 using namespace clang; 21 22 namespace { 23 24 struct ExampleAttrInfo : public ParsedAttrInfo { 25 ExampleAttrInfo() { 26 // Can take up to 15 optional arguments, to emulate accepting a variadic 27 // number of arguments. This just illustrates how many arguments a 28 // `ParsedAttrInfo` can hold, we will not use that much in this example. 29 OptArgs = 15; 30 // GNU-style __attribute__(("example")) and C++-style [[example]] and 31 // [[plugin::example]] supported. 32 static constexpr Spelling S[] = {{ParsedAttr::AS_GNU, "example"}, 33 {ParsedAttr::AS_CXX11, "example"}, 34 {ParsedAttr::AS_CXX11, "plugin::example"}}; 35 Spellings = S; 36 } 37 38 bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr, 39 const Decl *D) const override { 40 // This attribute appertains to functions only. 41 if (!isa<FunctionDecl>(D)) { 42 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str) 43 << Attr << "functions"; 44 return false; 45 } 46 return true; 47 } 48 49 AttrHandling handleDeclAttribute(Sema &S, Decl *D, 50 const ParsedAttr &Attr) const override { 51 // Check if the decl is at file scope. 52 if (!D->getDeclContext()->isFileContext()) { 53 unsigned ID = S.getDiagnostics().getCustomDiagID( 54 DiagnosticsEngine::Error, 55 "'example' attribute only allowed at file scope"); 56 S.Diag(Attr.getLoc(), ID); 57 return AttributeNotApplied; 58 } 59 // We make some rules here: 60 // 1. Only accept at most 3 arguments here. 61 // 2. The first argument must be a string literal if it exists. 62 if (Attr.getNumArgs() > 3) { 63 unsigned ID = S.getDiagnostics().getCustomDiagID( 64 DiagnosticsEngine::Error, 65 "'example' attribute only accepts at most three arguments"); 66 S.Diag(Attr.getLoc(), ID); 67 return AttributeNotApplied; 68 } 69 // If there are arguments, the first argument should be a string literal. 70 if (Attr.getNumArgs() > 0) { 71 auto *Arg0 = Attr.getArgAsExpr(0); 72 StringLiteral *Literal = 73 dyn_cast<StringLiteral>(Arg0->IgnoreParenCasts()); 74 if (!Literal) { 75 unsigned ID = S.getDiagnostics().getCustomDiagID( 76 DiagnosticsEngine::Error, "first argument to the 'example' " 77 "attribute must be a string literal"); 78 S.Diag(Attr.getLoc(), ID); 79 return AttributeNotApplied; 80 } 81 SmallVector<Expr *, 16> ArgsBuf; 82 for (unsigned i = 0; i < Attr.getNumArgs(); i++) { 83 ArgsBuf.push_back(Attr.getArgAsExpr(i)); 84 } 85 D->addAttr(AnnotateAttr::Create(S.Context, "example", ArgsBuf.data(), 86 ArgsBuf.size(), Attr.getRange())); 87 } else { 88 // Attach an annotate attribute to the Decl. 89 D->addAttr(AnnotateAttr::Create(S.Context, "example", nullptr, 0, 90 Attr.getRange())); 91 } 92 return AttributeApplied; 93 } 94 }; 95 96 } // namespace 97 98 static ParsedAttrInfoRegistry::Add<ExampleAttrInfo> X("example", ""); 99