|
9 | 9 | #include <string> |
10 | 10 |
|
11 | 11 | #include "absl/base/attributes.h" |
| 12 | +#include "absl/base/nullability.h" |
12 | 13 | #include "absl/status/status.h" |
13 | 14 | #include "absl/status/statusor.h" |
14 | 15 | #include "absl/strings/str_cat.h" |
|
23 | 24 | #include "clang/AST/DeclBase.h" |
24 | 25 | #include "clang/AST/DeclTemplate.h" |
25 | 26 | #include "clang/AST/Expr.h" |
| 27 | +#include "clang/AST/TypeBase.h" |
| 28 | +#include "clang/Basic/AttrKinds.h" |
26 | 29 | #include "clang/Basic/LLVM.h" |
27 | 30 | #include "llvm/ADT/APSInt.h" |
28 | 31 | #include "llvm/ADT/StringRef.h" |
@@ -167,9 +170,10 @@ static absl::Status CheckAnnotationsConsistent( |
167 | 170 |
|
168 | 171 | // Returns the `clang::Decl` that should be used for reading annotations. |
169 | 172 | // |
170 | | -// Template declarations technically do not have annotations-- the *templated* |
171 | | -// decl has annotations. So, if we're searching for annotations on a template |
172 | | -// decl, we should search for annotations on the templated decl instead. |
| 173 | +// Template declarations technically do not have annotations-- the |
| 174 | +// *templated* decl has annotations. So, if we're searching for annotations |
| 175 | +// on a template decl, we should search for annotations on the templated |
| 176 | +// decl instead. |
173 | 177 | static const clang::Decl& DeclForAnnotations(const clang::Decl& decl) { |
174 | 178 | auto* template_decl = clang::dyn_cast<clang::TemplateDecl>(&decl); |
175 | 179 | if (template_decl == nullptr) { |
@@ -290,4 +294,29 @@ absl::StatusOr<std::optional<std::string>> GetAnnotationWithStringArg( |
290 | 294 | return std::string(*arg); |
291 | 295 | } |
292 | 296 |
|
| 297 | +absl::StatusOr<const clang::AnnotateTypeAttr* absl_nullable> |
| 298 | +GetTypeAnnotationSingleDecl(const clang::Type* absl_nonnull type |
| 299 | + ABSL_ATTRIBUTE_LIFETIME_BOUND, |
| 300 | + absl::string_view annotation_name) { |
| 301 | + const clang::Type* current_type = type; |
| 302 | + const clang::AnnotateTypeAttr* found_attr = nullptr; |
| 303 | + while (const auto* attributed_type = |
| 304 | + current_type->getAs<clang::AttributedType>()) { |
| 305 | + if (attributed_type->getAttrKind() == clang::attr::AnnotateType) { |
| 306 | + const clang::AnnotateTypeAttr* annotateAttr = |
| 307 | + clang::cast<clang::AnnotateTypeAttr>(attributed_type->getAttr()); |
| 308 | + if (annotateAttr->getAnnotation() == llvm::StringRef(annotation_name)) { |
| 309 | + if (found_attr != nullptr) { |
| 310 | + return absl::InvalidArgumentError( |
| 311 | + absl::StrCat("Only one `", annotation_name, |
| 312 | + "` annotation may be placed on a type.")); |
| 313 | + } |
| 314 | + found_attr = annotateAttr; |
| 315 | + } |
| 316 | + } |
| 317 | + current_type = attributed_type->getEquivalentType().getTypePtr(); |
| 318 | + } |
| 319 | + return found_attr; |
| 320 | +} |
| 321 | + |
293 | 322 | } // namespace crubit |
0 commit comments