forked from OSchip/llvm-project
Add an attribute plugin example
Differential Revision: https://reviews.llvm.org/D31343
This commit is contained in:
parent
bc3f171090
commit
3f03c12a51
|
@ -110,6 +110,9 @@ attribute, are:
|
|||
* ``existsInTarget``, which checks if the attribute is permitted for the given
|
||||
target.
|
||||
|
||||
To see a working example of an attribute plugin, see `the Attribute.cpp example
|
||||
<https://github.com/llvm/llvm-project/blob/master/clang/examples/Attribute/Attribute.cpp>`_.
|
||||
|
||||
Putting it all together
|
||||
=======================
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
//===- 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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 an optional string argument (the check that the argument
|
||||
// actually is a string happens in handleDeclAttribute).
|
||||
OptArgs = 1;
|
||||
// GNU-style __attribute__(("example")) and C++-style [[example]] and
|
||||
// [[plugin::example]] supported.
|
||||
Spellings.push_back({ParsedAttr::AS_GNU, "example"});
|
||||
Spellings.push_back({ParsedAttr::AS_CXX11, "example"});
|
||||
Spellings.push_back({ParsedAttr::AS_CXX11, "plugin::example"});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// Check if we have an optional string argument.
|
||||
StringRef Str = "";
|
||||
if (Attr.getNumArgs() > 0) {
|
||||
Expr *ArgExpr = Attr.getArgAsExpr(0);
|
||||
StringLiteral *Literal =
|
||||
dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts());
|
||||
if (Literal) {
|
||||
Str = Literal->getString();
|
||||
} else {
|
||||
S.Diag(ArgExpr->getExprLoc(), diag::err_attribute_argument_type)
|
||||
<< Attr.getAttrName() << AANT_ArgumentString;
|
||||
return AttributeNotApplied;
|
||||
}
|
||||
}
|
||||
// Attach an annotate attribute to the Decl.
|
||||
D->addAttr(AnnotateAttr::Create(S.Context, "example(" + Str.str() + ")",
|
||||
Attr.getRange()));
|
||||
return AttributeApplied;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static ParsedAttrInfoRegistry::Add<ExampleAttrInfo> X("example", "");
|
|
@ -0,0 +1,11 @@
|
|||
add_llvm_library(Attribute MODULE Attribute.cpp PLUGIN_TOOL clang)
|
||||
|
||||
if(LLVM_ENABLE_PLUGINS AND (WIN32 OR CYGWIN))
|
||||
target_link_libraries(AnnotateFunctions ${cmake_2_8_12_PRIVATE}
|
||||
clangAST
|
||||
clangBasic
|
||||
clangFrontend
|
||||
clangLex
|
||||
LLVMSupport
|
||||
)
|
||||
endif()
|
|
@ -6,3 +6,4 @@ endif()
|
|||
add_subdirectory(clang-interpreter)
|
||||
add_subdirectory(PrintFunctionNames)
|
||||
add_subdirectory(AnnotateFunctions)
|
||||
add_subdirectory(Attribute)
|
||||
|
|
|
@ -81,6 +81,7 @@ endif ()
|
|||
|
||||
if (CLANG_BUILD_EXAMPLES)
|
||||
list(APPEND CLANG_TEST_DEPS
|
||||
Attribute
|
||||
AnnotateFunctions
|
||||
clang-interpreter
|
||||
PrintFunctionNames
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// RUN: %clang -fplugin=%llvmshlibdir/Attribute%pluginext -emit-llvm -S %s -o - 2>&1 | FileCheck %s --check-prefix=ATTRIBUTE
|
||||
// RUN: not %clang -fplugin=%llvmshlibdir/Attribute%pluginext -emit-llvm -DBAD_ATTRIBUTE -S %s -o - 2>&1 | FileCheck %s --check-prefix=BADATTRIBUTE
|
||||
// REQUIRES: plugins, examples
|
||||
|
||||
void fn1a() __attribute__((example)) { }
|
||||
[[example]] void fn1b() { }
|
||||
[[plugin::example]] void fn1c() { }
|
||||
void fn2() __attribute__((example("somestring"))) { }
|
||||
// ATTRIBUTE: warning: 'example' attribute only applies to functions
|
||||
int var1 __attribute__((example("otherstring"))) = 1;
|
||||
|
||||
// ATTRIBUTE: [[STR1_VAR:@.+]] = private unnamed_addr constant [10 x i8] c"example()\00"
|
||||
// ATTRIBUTE: [[STR2_VAR:@.+]] = private unnamed_addr constant [20 x i8] c"example(somestring)\00"
|
||||
// ATTRIBUTE: @llvm.global.annotations = {{.*}}@{{.*}}fn1a{{.*}}[[STR1_VAR]]{{.*}}@{{.*}}fn1b{{.*}}[[STR1_VAR]]{{.*}}@{{.*}}fn1c{{.*}}[[STR1_VAR]]{{.*}}@{{.*}}fn2{{.*}}[[STR2_VAR]]
|
||||
|
||||
#ifdef BAD_ATTRIBUTE
|
||||
class Example {
|
||||
// BADATTRIBUTE: error: 'example' attribute only allowed at file scope
|
||||
void __attribute__((example)) fn3();
|
||||
};
|
||||
// BADATTRIBUTE: error: 'example' attribute requires a string
|
||||
void fn4() __attribute__((example(123))) { }
|
||||
// BADATTRIBUTE: error: 'example' attribute takes no more than 1 argument
|
||||
void fn5() __attribute__((example("a","b"))) { }
|
||||
#endif
|
Loading…
Reference in New Issue