151 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Example clang plugin which adds an an annotation to file-scope declarations10// with the 'example' attribute.11//12// This plugin is used by clang/test/Frontend/plugin-attribute tests.13//14//===----------------------------------------------------------------------===//15 16#include "clang/AST/ASTContext.h"17#include "clang/AST/Attr.h"18#include "clang/Sema/ParsedAttr.h"19#include "clang/Sema/Sema.h"20#include "clang/Sema/SemaDiagnostic.h"21#include "llvm/IR/Attributes.h"22using namespace clang;23 24namespace {25 26struct ExampleAttrInfo : public ParsedAttrInfo {27 ExampleAttrInfo() {28 // Can take up to 15 optional arguments, to emulate accepting a variadic29 // number of arguments. This just illustrates how many arguments a30 // `ParsedAttrInfo` can hold, we will not use that much in this example.31 OptArgs = 15;32 // GNU-style __attribute__(("example")) and C++/C23-style [[example]] and33 // [[plugin::example]] supported.34 static constexpr Spelling S[] = {{ParsedAttr::AS_GNU, "example"},35 {ParsedAttr::AS_C23, "example"},36 {ParsedAttr::AS_CXX11, "example"},37 {ParsedAttr::AS_CXX11, "plugin::example"}};38 Spellings = S;39 }40 41 bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr,42 const Decl *D) const override {43 // This attribute appertains to functions only.44 if (!isa<FunctionDecl>(D)) {45 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)46 << Attr << Attr.isRegularKeywordAttribute() << ExpectedFunction;47 return false;48 }49 return true;50 }51 52 AttrHandling handleDeclAttribute(Sema &S, Decl *D,53 const ParsedAttr &Attr) const override {54 // Check if the decl is at file scope.55 if (!D->getDeclContext()->isFileContext()) {56 unsigned ID = S.getDiagnostics().getCustomDiagID(57 DiagnosticsEngine::Error,58 "'example' attribute only allowed at file scope");59 S.Diag(Attr.getLoc(), ID);60 return AttributeNotApplied;61 }62 // We make some rules here:63 // 1. Only accept at most 3 arguments here.64 // 2. The first argument must be a string literal if it exists.65 if (Attr.getNumArgs() > 3) {66 unsigned ID = S.getDiagnostics().getCustomDiagID(67 DiagnosticsEngine::Error,68 "'example' attribute only accepts at most three arguments");69 S.Diag(Attr.getLoc(), ID);70 return AttributeNotApplied;71 }72 // If there are arguments, the first argument should be a string literal.73 if (Attr.getNumArgs() > 0) {74 auto *Arg0 = Attr.getArgAsExpr(0);75 StringLiteral *Literal =76 dyn_cast<StringLiteral>(Arg0->IgnoreParenCasts());77 if (!Literal) {78 unsigned ID = S.getDiagnostics().getCustomDiagID(79 DiagnosticsEngine::Error, "first argument to the 'example' "80 "attribute must be a string literal");81 S.Diag(Attr.getLoc(), ID);82 return AttributeNotApplied;83 }84 SmallVector<Expr *, 16> ArgsBuf;85 for (unsigned i = 0; i < Attr.getNumArgs(); i++) {86 ArgsBuf.push_back(Attr.getArgAsExpr(i));87 }88 D->addAttr(AnnotateAttr::Create(S.Context, "example", ArgsBuf.data(),89 ArgsBuf.size(), Attr.getRange()));90 } else {91 // Attach an annotate attribute to the Decl.92 D->addAttr(AnnotateAttr::Create(S.Context, "example", nullptr, 0,93 Attr.getRange()));94 }95 return AttributeApplied;96 }97 98 bool diagAppertainsToStmt(Sema &S, const ParsedAttr &Attr,99 const Stmt *St) const override {100 // This attribute appertains to for loop statements only.101 if (!isa<ForStmt>(St)) {102 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)103 << Attr << Attr.isRegularKeywordAttribute()104 << ExpectedForLoopStatement;105 return false;106 }107 return true;108 }109 110 AttrHandling handleStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &Attr,111 class Attr *&Result) const override {112 // We make some rules here:113 // 1. Only accept at most 3 arguments here.114 // 2. The first argument must be a string literal if it exists.115 if (Attr.getNumArgs() > 3) {116 unsigned ID = S.getDiagnostics().getCustomDiagID(117 DiagnosticsEngine::Error,118 "'example' attribute only accepts at most three arguments");119 S.Diag(Attr.getLoc(), ID);120 return AttributeNotApplied;121 }122 // If there are arguments, the first argument should be a string literal.123 if (Attr.getNumArgs() > 0) {124 auto *Arg0 = Attr.getArgAsExpr(0);125 StringLiteral *Literal =126 dyn_cast<StringLiteral>(Arg0->IgnoreParenCasts());127 if (!Literal) {128 unsigned ID = S.getDiagnostics().getCustomDiagID(129 DiagnosticsEngine::Error, "first argument to the 'example' "130 "attribute must be a string literal");131 S.Diag(Attr.getLoc(), ID);132 return AttributeNotApplied;133 }134 SmallVector<Expr *, 16> ArgsBuf;135 for (unsigned i = 0; i < Attr.getNumArgs(); i++) {136 ArgsBuf.push_back(Attr.getArgAsExpr(i));137 }138 Result = AnnotateAttr::Create(S.Context, "example", ArgsBuf.data(),139 ArgsBuf.size(), Attr.getRange());140 } else {141 Result = AnnotateAttr::Create(S.Context, "example", nullptr, 0,142 Attr.getRange());143 }144 return AttributeApplied;145 }146};147 148} // namespace149 150static ParsedAttrInfoRegistry::Add<ExampleAttrInfo> X("example", "");151