blob: 3b8fb3f5005b6d6ae8c9a473fdb896afb7248aeb [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "rs_bindings_from_cc/ast_util.h"
#include <optional>
#include <string>
#include "absl/functional/function_ref.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Type.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/LLVM.h"
namespace crubit {
bool IsFullClassTemplateSpecializationOrChild(const clang::Decl* decl) {
if (clang::isa<clang::ClassTemplatePartialSpecializationDecl>(decl)) {
return false;
}
if (clang::isa<clang::ClassTemplateSpecializationDecl>(decl)) {
return true;
}
if (const auto* decl_context = decl->getDeclContext()) {
return IsFullClassTemplateSpecializationOrChild(
clang::dyn_cast<clang::Decl>(decl_context));
}
return false;
}
std::optional<std::string> CollectUnknownAttrs(
const clang::Decl& decl,
absl::FunctionRef<bool(const clang::Attr&)> is_known) {
std::optional<std::string> unknown_attr;
if (!decl.hasAttrs()) {
// Surprisingly, getAttrs() does not return an empty vec if there are no
// attrs, it crashes.
return unknown_attr;
}
for (clang::Attr* attr : decl.getAttrs()) {
if (is_known(*attr)) {
continue;
}
if (unknown_attr.has_value()) {
absl::StrAppend(&*unknown_attr, ", ");
} else {
unknown_attr.emplace("");
}
absl::StrAppend(&*unknown_attr, attr->getAttrName()
? attr->getNormalizedFullName()
: attr->getSpelling());
}
return unknown_attr;
}
absl::string_view DebugAttrName(clang::attr::Kind attr_kind) {
// TODO(jeanpierreda): Give some more human-readable name, e.g. using
// ParsedAttrInfo::getAllBuiltin. Unfortunately, we don't have a TypeLoc,
// so we only have access to a Kind, which doesn't specify how it is spelled.
//
// For now, we use the symbol name, and prefix it with `clang::attr` to make
// it obvious it's an internal symbol and not something the user typed.
switch (attr_kind) {
// (Yes, the X-macro is really the only way to do it. Party like it's 1969!)
#define ATTR(X) \
case clang::attr::X: \
return "clang::attr::Kind::" #X;
#include "clang/Basic/AttrList.inc"
#undef ATTR
}
}
std::optional<std::string> CollectUnknownTypeAttrs(
const clang::Type& t, absl::FunctionRef<bool(clang::attr::Kind)> is_known) {
std::optional<std::string> unknown_attr;
const clang::Type* type = &t;
while (const auto* attributed_type = type->getAs<clang::AttributedType>()) {
clang::attr::Kind attr_kind = attributed_type->getAttrKind();
if (!is_known(attr_kind)) {
if (unknown_attr.has_value()) {
absl::StrAppend(&*unknown_attr, ", ");
} else {
unknown_attr.emplace("");
}
absl::StrAppend(&*unknown_attr, DebugAttrName(attr_kind));
}
type = attributed_type->getEquivalentType().getTypePtr();
}
return unknown_attr;
}
} // namespace crubit