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