Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Differential Revision: https://reviews.llvm.org/D31343
- Loading branch information
1 parent
bc3f171
commit 3f03c12
Showing
6 changed files
with
121 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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", ""); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |