When using attributes by plugins (both in clang and clang-tidy) the preprocessor functions `__has_attribute`, `__has_c_attribute`, `__has_cpp_attribute` still returned 0. That problem is fixed by having the "hasAttribute" function also check if any of the plugins provide that attribute. This also adds C2x spelling to the example plugin for attributes so that `__has_c_attribute` can be tested. Differential Revision: https://reviews.llvm.org/D144405
102 lines
3.9 KiB
C++
102 lines
3.9 KiB
C++
//===- Attribute.cpp ------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Example clang plugin which adds an an annotation to file-scope declarations
|
|
// with the 'example' attribute.
|
|
//
|
|
// This plugin is used by clang/test/Frontend/plugin-attribute tests.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/Attr.h"
|
|
#include "clang/Sema/ParsedAttr.h"
|
|
#include "clang/Sema/Sema.h"
|
|
#include "clang/Sema/SemaDiagnostic.h"
|
|
#include "llvm/IR/Attributes.h"
|
|
using namespace clang;
|
|
|
|
namespace {
|
|
|
|
struct ExampleAttrInfo : public ParsedAttrInfo {
|
|
ExampleAttrInfo() {
|
|
// Can take up to 15 optional arguments, to emulate accepting a variadic
|
|
// number of arguments. This just illustrates how many arguments a
|
|
// `ParsedAttrInfo` can hold, we will not use that much in this example.
|
|
OptArgs = 15;
|
|
// GNU-style __attribute__(("example")) and C++/C2x-style [[example]] and
|
|
// [[plugin::example]] supported.
|
|
static constexpr Spelling S[] = {{ParsedAttr::AS_GNU, "example"},
|
|
{ParsedAttr::AS_C2x, "example"},
|
|
{ParsedAttr::AS_CXX11, "example"},
|
|
{ParsedAttr::AS_CXX11, "plugin::example"}};
|
|
Spellings = S;
|
|
}
|
|
|
|
bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr,
|
|
const Decl *D) const override {
|
|
// This attribute appertains to functions only.
|
|
if (!isa<FunctionDecl>(D)) {
|
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str)
|
|
<< Attr << "functions";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
AttrHandling handleDeclAttribute(Sema &S, Decl *D,
|
|
const ParsedAttr &Attr) const override {
|
|
// Check if the decl is at file scope.
|
|
if (!D->getDeclContext()->isFileContext()) {
|
|
unsigned ID = S.getDiagnostics().getCustomDiagID(
|
|
DiagnosticsEngine::Error,
|
|
"'example' attribute only allowed at file scope");
|
|
S.Diag(Attr.getLoc(), ID);
|
|
return AttributeNotApplied;
|
|
}
|
|
// We make some rules here:
|
|
// 1. Only accept at most 3 arguments here.
|
|
// 2. The first argument must be a string literal if it exists.
|
|
if (Attr.getNumArgs() > 3) {
|
|
unsigned ID = S.getDiagnostics().getCustomDiagID(
|
|
DiagnosticsEngine::Error,
|
|
"'example' attribute only accepts at most three arguments");
|
|
S.Diag(Attr.getLoc(), ID);
|
|
return AttributeNotApplied;
|
|
}
|
|
// If there are arguments, the first argument should be a string literal.
|
|
if (Attr.getNumArgs() > 0) {
|
|
auto *Arg0 = Attr.getArgAsExpr(0);
|
|
StringLiteral *Literal =
|
|
dyn_cast<StringLiteral>(Arg0->IgnoreParenCasts());
|
|
if (!Literal) {
|
|
unsigned ID = S.getDiagnostics().getCustomDiagID(
|
|
DiagnosticsEngine::Error, "first argument to the 'example' "
|
|
"attribute must be a string literal");
|
|
S.Diag(Attr.getLoc(), ID);
|
|
return AttributeNotApplied;
|
|
}
|
|
SmallVector<Expr *, 16> ArgsBuf;
|
|
for (unsigned i = 0; i < Attr.getNumArgs(); i++) {
|
|
ArgsBuf.push_back(Attr.getArgAsExpr(i));
|
|
}
|
|
D->addAttr(AnnotateAttr::Create(S.Context, "example", ArgsBuf.data(),
|
|
ArgsBuf.size(), Attr.getRange()));
|
|
} else {
|
|
// Attach an annotate attribute to the Decl.
|
|
D->addAttr(AnnotateAttr::Create(S.Context, "example", nullptr, 0,
|
|
Attr.getRange()));
|
|
}
|
|
return AttributeApplied;
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
static ParsedAttrInfoRegistry::Add<ExampleAttrInfo> X("example", "");
|