|
|
|
@@ -20,23 +20,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __cpp_lib_optional
|
|
|
|
#ifdef __cpp_lib_optional
|
|
|
|
#include <optional>
|
|
|
|
#include <optional>
|
|
|
|
template<typename T> using optional = std::optional<T>;
|
|
|
|
template <typename T> using optional = std::optional<T>;
|
|
|
|
#else
|
|
|
|
#else
|
|
|
|
#include <llvm/ADT/Optional.h>
|
|
|
|
#include <llvm/ADT/Optional.h>
|
|
|
|
template<typename T> using optional = clang::Optional<T>;
|
|
|
|
template <typename T> using optional = clang::Optional<T>;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
|
|
template<typename InputIt>
|
|
|
|
template <typename InputIt>
|
|
|
|
bool hasReverseQualifiedName(InputIt first, InputIt last, const NamedDecl &tag)
|
|
|
|
bool hasReverseQualifiedName(InputIt first, InputIt last,
|
|
|
|
{
|
|
|
|
const NamedDecl &tag) {
|
|
|
|
const NamedDecl *currentDecl = &tag;
|
|
|
|
const NamedDecl *currentDecl = &tag;
|
|
|
|
InputIt currentName;
|
|
|
|
InputIt currentName;
|
|
|
|
for (currentName = first; currentName != last; currentName++) {
|
|
|
|
for (currentName = first; currentName != last; currentName++) {
|
|
|
|
if (!currentDecl || !currentDecl->getIdentifier() || currentDecl->getName() != *currentName)
|
|
|
|
if (!currentDecl || !currentDecl->getIdentifier() ||
|
|
|
|
|
|
|
|
currentDecl->getName() != *currentName)
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
currentDecl = dyn_cast<NamedDecl>(currentDecl->getDeclContext());
|
|
|
|
currentDecl = dyn_cast<NamedDecl>(currentDecl->getDeclContext());
|
|
|
|
@@ -50,20 +51,21 @@ bool hasReverseQualifiedName(InputIt first, InputIt last, const NamedDecl &tag)
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool isMozillaJniObjectBase(const CXXRecordDecl &klass)
|
|
|
|
bool isMozillaJniObjectBase(const CXXRecordDecl &klass) {
|
|
|
|
{
|
|
|
|
const auto qualifiedName =
|
|
|
|
const auto qualifiedName = std::array<StringRef, 3>{"mozilla", "jni", "ObjectBase"};
|
|
|
|
std::array<StringRef, 3>{"mozilla", "jni", "ObjectBase"};
|
|
|
|
return hasReverseQualifiedName(qualifiedName.crbegin(), qualifiedName.crend(), klass);
|
|
|
|
return hasReverseQualifiedName(qualifiedName.crbegin(), qualifiedName.crend(),
|
|
|
|
|
|
|
|
klass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool isMozillaJniNativeImpl(const CXXRecordDecl &klass)
|
|
|
|
bool isMozillaJniNativeImpl(const CXXRecordDecl &klass) {
|
|
|
|
{
|
|
|
|
const auto qualifiedName =
|
|
|
|
const auto qualifiedName = std::array<StringRef, 3>{"mozilla", "jni", "NativeImpl"};
|
|
|
|
std::array<StringRef, 3>{"mozilla", "jni", "NativeImpl"};
|
|
|
|
return hasReverseQualifiedName(qualifiedName.crbegin(), qualifiedName.crend(), klass);
|
|
|
|
return hasReverseQualifiedName(qualifiedName.crbegin(), qualifiedName.crend(),
|
|
|
|
|
|
|
|
klass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const NamedDecl *fieldNamed(StringRef name, const RecordDecl &strukt)
|
|
|
|
const NamedDecl *fieldNamed(StringRef name, const RecordDecl &strukt) {
|
|
|
|
{
|
|
|
|
|
|
|
|
for (const auto *decl : strukt.decls()) {
|
|
|
|
for (const auto *decl : strukt.decls()) {
|
|
|
|
const auto *namedDecl = dyn_cast<VarDecl>(decl);
|
|
|
|
const auto *namedDecl = dyn_cast<VarDecl>(decl);
|
|
|
|
if (!namedDecl)
|
|
|
|
if (!namedDecl)
|
|
|
|
@@ -78,8 +80,7 @@ const NamedDecl *fieldNamed(StringRef name, const RecordDecl &strukt)
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
optional<StringRef> nameFieldValue(const RecordDecl &strukt)
|
|
|
|
optional<StringRef> nameFieldValue(const RecordDecl &strukt) {
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto *nameField = dyn_cast_or_null<VarDecl>(fieldNamed("name", strukt));
|
|
|
|
const auto *nameField = dyn_cast_or_null<VarDecl>(fieldNamed("name", strukt));
|
|
|
|
if (!nameField)
|
|
|
|
if (!nameField)
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
@@ -103,22 +104,18 @@ struct AbstractBinding {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
static constexpr size_t LangLength = 2;
|
|
|
|
static constexpr size_t LangLength = 2;
|
|
|
|
static constexpr std::array<StringRef, LangLength> langNames = {
|
|
|
|
static constexpr std::array<StringRef, LangLength> langNames = {
|
|
|
|
"cpp",
|
|
|
|
"cpp",
|
|
|
|
"jvm",
|
|
|
|
"jvm",
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static optional<Lang> langFromString(StringRef langName)
|
|
|
|
static optional<Lang> langFromString(StringRef langName) {
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto it = std::find(langNames.begin(), langNames.end(), langName);
|
|
|
|
const auto it = std::find(langNames.begin(), langNames.end(), langName);
|
|
|
|
if (it == langNames.end())
|
|
|
|
if (it == langNames.end())
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
return Lang(it - langNames.begin());
|
|
|
|
return Lang(it - langNames.begin());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static StringRef stringFromLang(Lang lang)
|
|
|
|
static StringRef stringFromLang(Lang lang) { return langNames[size_t(lang)]; }
|
|
|
|
{
|
|
|
|
|
|
|
|
return langNames[size_t(lang)];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Subset of tools/analysis/BindingSlotKind
|
|
|
|
// Subset of tools/analysis/BindingSlotKind
|
|
|
|
enum class Kind {
|
|
|
|
enum class Kind {
|
|
|
|
@@ -130,34 +127,28 @@ struct AbstractBinding {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
static constexpr size_t KindLength = 5;
|
|
|
|
static constexpr size_t KindLength = 5;
|
|
|
|
static constexpr std::array<StringRef, KindLength> kindNames = {
|
|
|
|
static constexpr std::array<StringRef, KindLength> kindNames = {
|
|
|
|
"class",
|
|
|
|
"class", "method", "getter", "setter", "const",
|
|
|
|
"method",
|
|
|
|
|
|
|
|
"getter",
|
|
|
|
|
|
|
|
"setter",
|
|
|
|
|
|
|
|
"const",
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static optional<Kind> kindFromString(StringRef kindName)
|
|
|
|
static optional<Kind> kindFromString(StringRef kindName) {
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto it = std::find(kindNames.begin(), kindNames.end(), kindName);
|
|
|
|
const auto it = std::find(kindNames.begin(), kindNames.end(), kindName);
|
|
|
|
if (it == kindNames.end())
|
|
|
|
if (it == kindNames.end())
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
return Kind(it - kindNames.begin());
|
|
|
|
return Kind(it - kindNames.begin());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static StringRef stringFromKind(Kind kind)
|
|
|
|
static StringRef stringFromKind(Kind kind) { return kindNames[size_t(kind)]; }
|
|
|
|
{
|
|
|
|
|
|
|
|
return kindNames[size_t(kind)];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lang lang;
|
|
|
|
Lang lang;
|
|
|
|
Kind kind;
|
|
|
|
Kind kind;
|
|
|
|
StringRef symbol;
|
|
|
|
StringRef symbol;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
constexpr size_t AbstractBinding::KindLength;
|
|
|
|
constexpr size_t AbstractBinding::KindLength;
|
|
|
|
constexpr std::array<StringRef, AbstractBinding::KindLength> AbstractBinding::kindNames;
|
|
|
|
constexpr std::array<StringRef, AbstractBinding::KindLength>
|
|
|
|
|
|
|
|
AbstractBinding::kindNames;
|
|
|
|
constexpr size_t AbstractBinding::LangLength;
|
|
|
|
constexpr size_t AbstractBinding::LangLength;
|
|
|
|
constexpr std::array<StringRef, AbstractBinding::LangLength> AbstractBinding::langNames;
|
|
|
|
constexpr std::array<StringRef, AbstractBinding::LangLength>
|
|
|
|
|
|
|
|
AbstractBinding::langNames;
|
|
|
|
|
|
|
|
|
|
|
|
struct BindingTo : public AbstractBinding {
|
|
|
|
struct BindingTo : public AbstractBinding {
|
|
|
|
BindingTo(AbstractBinding b) : AbstractBinding(std::move(b)) {}
|
|
|
|
BindingTo(AbstractBinding b) : AbstractBinding(std::move(b)) {}
|
|
|
|
@@ -171,25 +162,26 @@ struct BoundAs : public AbstractBinding {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
constexpr StringRef BoundAs::ANNOTATION;
|
|
|
|
constexpr StringRef BoundAs::ANNOTATION;
|
|
|
|
|
|
|
|
|
|
|
|
template<typename B>
|
|
|
|
template <typename B>
|
|
|
|
void setBindingAttr(ASTContext &C, Decl &decl, B binding)
|
|
|
|
void setBindingAttr(ASTContext &C, Decl &decl, B binding) {
|
|
|
|
{
|
|
|
|
|
|
|
|
#if CLANG_VERSION_MAJOR >= 18
|
|
|
|
#if CLANG_VERSION_MAJOR >= 18
|
|
|
|
auto utf8 = StringLiteralKind::UTF8;
|
|
|
|
auto utf8 = StringLiteralKind::UTF8;
|
|
|
|
#else
|
|
|
|
#else
|
|
|
|
auto utf8 = StringLiteral::UTF8;
|
|
|
|
auto utf8 = StringLiteral::UTF8;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
// recent LLVM: CreateImplicit then setDelayedArgs
|
|
|
|
// recent LLVM: CreateImplicit then setDelayedArgs
|
|
|
|
Expr *langExpr = StringLiteral::Create(C, AbstractBinding::stringFromLang(binding.lang), utf8, false, {}, {});
|
|
|
|
Expr *langExpr = StringLiteral::Create(
|
|
|
|
Expr *kindExpr = StringLiteral::Create(C, AbstractBinding::stringFromKind(binding.kind), utf8, false, {}, {});
|
|
|
|
C, AbstractBinding::stringFromLang(binding.lang), utf8, false, {}, {});
|
|
|
|
Expr *symbolExpr = StringLiteral::Create(C, binding.symbol, utf8, false, {}, {});
|
|
|
|
Expr *kindExpr = StringLiteral::Create(
|
|
|
|
|
|
|
|
C, AbstractBinding::stringFromKind(binding.kind), utf8, false, {}, {});
|
|
|
|
|
|
|
|
Expr *symbolExpr =
|
|
|
|
|
|
|
|
StringLiteral::Create(C, binding.symbol, utf8, false, {}, {});
|
|
|
|
auto **args = new (C, 16) Expr *[3]{langExpr, kindExpr, symbolExpr};
|
|
|
|
auto **args = new (C, 16) Expr *[3]{langExpr, kindExpr, symbolExpr};
|
|
|
|
auto *attr = AnnotateAttr::CreateImplicit(C, B::ANNOTATION, args, 3);
|
|
|
|
auto *attr = AnnotateAttr::CreateImplicit(C, B::ANNOTATION, args, 3);
|
|
|
|
decl.addAttr(attr);
|
|
|
|
decl.addAttr(attr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
optional<AbstractBinding> readBinding(const AnnotateAttr &attr)
|
|
|
|
optional<AbstractBinding> readBinding(const AnnotateAttr &attr) {
|
|
|
|
{
|
|
|
|
|
|
|
|
if (attr.args_size() != 3)
|
|
|
|
if (attr.args_size() != 3)
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
@@ -199,9 +191,12 @@ optional<AbstractBinding> readBinding(const AnnotateAttr &attr)
|
|
|
|
if (!langExpr || !kindExpr || !symbolExpr)
|
|
|
|
if (!langExpr || !kindExpr || !symbolExpr)
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
const auto *langName = dyn_cast<StringLiteral>(langExpr->IgnoreUnlessSpelledInSource());
|
|
|
|
const auto *langName =
|
|
|
|
const auto *kindName = dyn_cast<StringLiteral>(kindExpr->IgnoreUnlessSpelledInSource());
|
|
|
|
dyn_cast<StringLiteral>(langExpr->IgnoreUnlessSpelledInSource());
|
|
|
|
const auto *symbol = dyn_cast<StringLiteral>(symbolExpr->IgnoreUnlessSpelledInSource());
|
|
|
|
const auto *kindName =
|
|
|
|
|
|
|
|
dyn_cast<StringLiteral>(kindExpr->IgnoreUnlessSpelledInSource());
|
|
|
|
|
|
|
|
const auto *symbol =
|
|
|
|
|
|
|
|
dyn_cast<StringLiteral>(symbolExpr->IgnoreUnlessSpelledInSource());
|
|
|
|
if (!langName || !kindName || !symbol)
|
|
|
|
if (!langName || !kindName || !symbol)
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
@@ -211,15 +206,14 @@ optional<AbstractBinding> readBinding(const AnnotateAttr &attr)
|
|
|
|
if (!lang || !kind)
|
|
|
|
if (!lang || !kind)
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
return AbstractBinding {
|
|
|
|
return AbstractBinding{
|
|
|
|
.lang = *lang,
|
|
|
|
.lang = *lang,
|
|
|
|
.kind = *kind,
|
|
|
|
.kind = *kind,
|
|
|
|
.symbol = symbol->getString(),
|
|
|
|
.symbol = symbol->getString(),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
optional<BindingTo> getBindingTo(const Decl &decl)
|
|
|
|
optional<BindingTo> getBindingTo(const Decl &decl) {
|
|
|
|
{
|
|
|
|
|
|
|
|
for (const auto *attr : decl.specific_attrs<AnnotateAttr>()) {
|
|
|
|
for (const auto *attr : decl.specific_attrs<AnnotateAttr>()) {
|
|
|
|
if (attr->getAnnotation() != BindingTo::ANNOTATION)
|
|
|
|
if (attr->getAnnotation() != BindingTo::ANNOTATION)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
@@ -234,8 +228,7 @@ optional<BindingTo> getBindingTo(const Decl &decl)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// C++23: turn into generator
|
|
|
|
// C++23: turn into generator
|
|
|
|
std::vector<BoundAs> getBoundAs(const Decl &decl)
|
|
|
|
std::vector<BoundAs> getBoundAs(const Decl &decl) {
|
|
|
|
{
|
|
|
|
|
|
|
|
std::vector<BoundAs> found;
|
|
|
|
std::vector<BoundAs> found;
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto *attr : decl.specific_attrs<AnnotateAttr>()) {
|
|
|
|
for (const auto *attr : decl.specific_attrs<AnnotateAttr>()) {
|
|
|
|
@@ -252,8 +245,7 @@ std::vector<BoundAs> getBoundAs(const Decl &decl)
|
|
|
|
return found;
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class FindCallCall : private RecursiveASTVisitor<FindCallCall>
|
|
|
|
class FindCallCall : private RecursiveASTVisitor<FindCallCall> {
|
|
|
|
{
|
|
|
|
|
|
|
|
public:
|
|
|
|
public:
|
|
|
|
struct Result {
|
|
|
|
struct Result {
|
|
|
|
using Kind = AbstractBinding::Kind;
|
|
|
|
using Kind = AbstractBinding::Kind;
|
|
|
|
@@ -262,8 +254,7 @@ public:
|
|
|
|
StringRef name;
|
|
|
|
StringRef name;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static optional<Result> search(Stmt *statement)
|
|
|
|
static optional<Result> search(Stmt *statement) {
|
|
|
|
{
|
|
|
|
|
|
|
|
FindCallCall finder;
|
|
|
|
FindCallCall finder;
|
|
|
|
finder.TraverseStmt(statement);
|
|
|
|
finder.TraverseStmt(statement);
|
|
|
|
return finder.result;
|
|
|
|
return finder.result;
|
|
|
|
@@ -274,8 +265,9 @@ private:
|
|
|
|
|
|
|
|
|
|
|
|
friend RecursiveASTVisitor<FindCallCall>;
|
|
|
|
friend RecursiveASTVisitor<FindCallCall>;
|
|
|
|
|
|
|
|
|
|
|
|
optional<Result> tryParseCallCall(CallExpr *callExpr){
|
|
|
|
optional<Result> tryParseCallCall(CallExpr *callExpr) {
|
|
|
|
const auto *callee = dyn_cast_or_null<CXXMethodDecl>(callExpr->getDirectCallee());
|
|
|
|
const auto *callee =
|
|
|
|
|
|
|
|
dyn_cast_or_null<CXXMethodDecl>(callExpr->getDirectCallee());
|
|
|
|
if (!callee)
|
|
|
|
if (!callee)
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
@@ -287,7 +279,8 @@ private:
|
|
|
|
if (action != "Call" && action != "Get" && action != "Set")
|
|
|
|
if (action != "Call" && action != "Get" && action != "Set")
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
const auto *parentClass = dyn_cast_or_null<ClassTemplateSpecializationDecl>(callee->getParent());
|
|
|
|
const auto *parentClass =
|
|
|
|
|
|
|
|
dyn_cast_or_null<ClassTemplateSpecializationDecl>(callee->getParent());
|
|
|
|
|
|
|
|
|
|
|
|
if (!parentClass)
|
|
|
|
if (!parentClass)
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
@@ -318,7 +311,8 @@ private:
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const auto *templateArg = parentClass->getTemplateArgs().get(0).getAsType()->getAsRecordDecl();
|
|
|
|
const auto *templateArg =
|
|
|
|
|
|
|
|
parentClass->getTemplateArgs().get(0).getAsType()->getAsRecordDecl();
|
|
|
|
|
|
|
|
|
|
|
|
if (!templateArg)
|
|
|
|
if (!templateArg)
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
@@ -327,23 +321,22 @@ private:
|
|
|
|
if (!name)
|
|
|
|
if (!name)
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
return Result {
|
|
|
|
return Result{
|
|
|
|
.kind = kind,
|
|
|
|
.kind = kind,
|
|
|
|
.name = *name,
|
|
|
|
.name = *name,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool VisitCallExpr(CallExpr *callExpr)
|
|
|
|
bool VisitCallExpr(CallExpr *callExpr) {
|
|
|
|
{
|
|
|
|
|
|
|
|
return !(result = tryParseCallCall(callExpr));
|
|
|
|
return !(result = tryParseCallCall(callExpr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
constexpr StringRef JVM_SCIP_SYMBOL_PREFIX = "S_jvm_";
|
|
|
|
constexpr StringRef JVM_SCIP_SYMBOL_PREFIX = "S_jvm_";
|
|
|
|
|
|
|
|
|
|
|
|
std::string javaScipSymbol(StringRef prefix, StringRef name, AbstractBinding::Kind kind)
|
|
|
|
std::string javaScipSymbol(StringRef prefix, StringRef name,
|
|
|
|
{
|
|
|
|
AbstractBinding::Kind kind) {
|
|
|
|
auto symbol = (prefix + name).str();
|
|
|
|
auto symbol = (prefix + name).str();
|
|
|
|
|
|
|
|
|
|
|
|
switch (kind) {
|
|
|
|
switch (kind) {
|
|
|
|
@@ -364,8 +357,7 @@ std::string javaScipSymbol(StringRef prefix, StringRef name, AbstractBinding::Ki
|
|
|
|
return symbol;
|
|
|
|
return symbol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void addSlotOwnerAttribute(llvm::json::OStream &J, const Decl &decl)
|
|
|
|
void addSlotOwnerAttribute(llvm::json::OStream &J, const Decl &decl) {
|
|
|
|
{
|
|
|
|
|
|
|
|
if (const auto bindingTo = getBindingTo(decl)) {
|
|
|
|
if (const auto bindingTo = getBindingTo(decl)) {
|
|
|
|
J.attributeBegin("slotOwner");
|
|
|
|
J.attributeBegin("slotOwner");
|
|
|
|
J.objectBegin();
|
|
|
|
J.objectBegin();
|
|
|
|
@@ -377,8 +369,7 @@ void addSlotOwnerAttribute(llvm::json::OStream &J, const Decl &decl)
|
|
|
|
J.attributeEnd();
|
|
|
|
J.attributeEnd();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void addBindingSlotsAttribute(llvm::json::OStream &J, const Decl &decl)
|
|
|
|
void addBindingSlotsAttribute(llvm::json::OStream &J, const Decl &decl) {
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto allBoundAs = getBoundAs(decl);
|
|
|
|
const auto allBoundAs = getBoundAs(decl);
|
|
|
|
if (!allBoundAs.empty()) {
|
|
|
|
if (!allBoundAs.empty()) {
|
|
|
|
J.attributeBegin("bindingSlots");
|
|
|
|
J.attributeBegin("bindingSlots");
|
|
|
|
@@ -396,7 +387,8 @@ void addBindingSlotsAttribute(llvm::json::OStream &J, const Decl &decl)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// The mangling scheme is documented at https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html
|
|
|
|
// The mangling scheme is documented at
|
|
|
|
|
|
|
|
// https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html
|
|
|
|
// The main takeaways are:
|
|
|
|
// The main takeaways are:
|
|
|
|
// - _0xxxx is the utf16 code unit xxxx
|
|
|
|
// - _0xxxx is the utf16 code unit xxxx
|
|
|
|
// - _1 is _
|
|
|
|
// - _1 is _
|
|
|
|
@@ -405,75 +397,77 @@ void addBindingSlotsAttribute(llvm::json::OStream &J, const Decl &decl)
|
|
|
|
// - __ is the separator between function name and overload specification
|
|
|
|
// - __ is the separator between function name and overload specification
|
|
|
|
// - _ is otherwise the separator between packages/classes/methods
|
|
|
|
// - _ is otherwise the separator between packages/classes/methods
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// This method takes a StringRef & and mutates it and can be called twice on a Jnicall function name to get
|
|
|
|
// This method takes a StringRef & and mutates it and can be called twice on a
|
|
|
|
|
|
|
|
// Jnicall function name to get
|
|
|
|
// first the demangled name
|
|
|
|
// first the demangled name
|
|
|
|
// second the demangled overload specification
|
|
|
|
// second the demangled overload specification
|
|
|
|
// But we don't use the later for now because we have no way to map that to how SCIP resolves overloads.
|
|
|
|
// But we don't use the later for now because we have no way to map that to how
|
|
|
|
optional<std::string> demangleJnicallPart(StringRef &remainder)
|
|
|
|
// SCIP resolves overloads.
|
|
|
|
{
|
|
|
|
optional<std::string> demangleJnicallPart(StringRef &remainder) {
|
|
|
|
std::string demangled;
|
|
|
|
std::string demangled;
|
|
|
|
|
|
|
|
|
|
|
|
std::mbstate_t ps = {};
|
|
|
|
std::mbstate_t ps = {};
|
|
|
|
|
|
|
|
|
|
|
|
while (!remainder.empty()) {
|
|
|
|
while (!remainder.empty()) {
|
|
|
|
switch (remainder[0]) {
|
|
|
|
switch (remainder[0]) {
|
|
|
|
case '0': {
|
|
|
|
case '0': {
|
|
|
|
remainder = remainder.drop_front(1);
|
|
|
|
remainder = remainder.drop_front(1);
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t codeUnit;
|
|
|
|
uint16_t codeUnit;
|
|
|
|
const auto ok = remainder.substr(1, 4).getAsInteger(16, codeUnit);
|
|
|
|
const auto ok = remainder.substr(1, 4).getAsInteger(16, codeUnit);
|
|
|
|
remainder = remainder.drop_front(4);
|
|
|
|
remainder = remainder.drop_front(4);
|
|
|
|
|
|
|
|
|
|
|
|
if (!ok) // failed reading xxxx as hexadecimal from _0xxxx
|
|
|
|
if (!ok) // failed reading xxxx as hexadecimal from _0xxxx
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
std::array<char, MB_LEN_MAX> codePoint;
|
|
|
|
std::array<char, MB_LEN_MAX> codePoint;
|
|
|
|
const auto mbLen = std::c16rtomb(codePoint.data(), codeUnit, &ps);
|
|
|
|
const auto mbLen = std::c16rtomb(codePoint.data(), codeUnit, &ps);
|
|
|
|
|
|
|
|
|
|
|
|
if (mbLen == -1) // failed converting utf16 to utf8
|
|
|
|
if (mbLen == -1) // failed converting utf16 to utf8
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
demangled += StringRef(codePoint.begin(), mbLen);
|
|
|
|
demangled += StringRef(codePoint.begin(), mbLen);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case '1':
|
|
|
|
|
|
|
|
remainder = remainder.drop_front(1);
|
|
|
|
|
|
|
|
ps = {};
|
|
|
|
|
|
|
|
demangled += '_';
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '2':
|
|
|
|
|
|
|
|
remainder = remainder.drop_front(1);
|
|
|
|
|
|
|
|
ps = {};
|
|
|
|
|
|
|
|
demangled += ';';
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '3':
|
|
|
|
|
|
|
|
remainder = remainder.drop_front(1);
|
|
|
|
|
|
|
|
ps = {};
|
|
|
|
|
|
|
|
demangled += '[';
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '_':
|
|
|
|
|
|
|
|
remainder = remainder.drop_front(1);
|
|
|
|
|
|
|
|
ps = {};
|
|
|
|
|
|
|
|
if (remainder.empty()) // the string ends with _
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (remainder[0]) {
|
|
|
|
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '1':
|
|
|
|
remainder = remainder.drop_front(1);
|
|
|
|
|
|
|
|
ps = {};
|
|
|
|
|
|
|
|
demangled += '_';
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '2':
|
|
|
|
case '2':
|
|
|
|
remainder = remainder.drop_front(1);
|
|
|
|
|
|
|
|
ps = {};
|
|
|
|
|
|
|
|
demangled += ';';
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '3':
|
|
|
|
case '3':
|
|
|
|
remainder = remainder.drop_front(1);
|
|
|
|
|
|
|
|
ps = {};
|
|
|
|
|
|
|
|
demangled += '[';
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '_':
|
|
|
|
|
|
|
|
remainder = remainder.drop_front(1);
|
|
|
|
|
|
|
|
ps = {};
|
|
|
|
|
|
|
|
if (remainder.empty()) // the string ends with _
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (remainder[0]) {
|
|
|
|
|
|
|
|
case '0':
|
|
|
|
|
|
|
|
case '1':
|
|
|
|
|
|
|
|
case '2':
|
|
|
|
|
|
|
|
case '3':
|
|
|
|
|
|
|
|
demangled += '.';
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
// either:
|
|
|
|
|
|
|
|
// * the string began with _[^0-3], which is not supposed to happen; or
|
|
|
|
|
|
|
|
// * we reached __[^0-3] meaning we finished the first part of the name and remainder holds the overload specification
|
|
|
|
|
|
|
|
return demangled;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
ps = {};
|
|
|
|
|
|
|
|
demangled += '.';
|
|
|
|
demangled += '.';
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
// either:
|
|
|
|
|
|
|
|
// * the string began with _[^0-3], which is not supposed to happen; or
|
|
|
|
|
|
|
|
// * we reached __[^0-3] meaning we finished the first part of the name
|
|
|
|
|
|
|
|
// and remainder holds the overload specification
|
|
|
|
|
|
|
|
return demangled;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
ps = {};
|
|
|
|
|
|
|
|
demangled += '.';
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
StringRef token;
|
|
|
|
StringRef token;
|
|
|
|
std::tie(token, remainder) = remainder.split('_');
|
|
|
|
std::tie(token, remainder) = remainder.split('_');
|
|
|
|
@@ -483,8 +477,8 @@ optional<std::string> demangleJnicallPart(StringRef &remainder)
|
|
|
|
return demangled;
|
|
|
|
return demangled;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
optional<std::string> scipSymbolFromJnicallFunctionName(StringRef functionName)
|
|
|
|
optional<std::string>
|
|
|
|
{
|
|
|
|
scipSymbolFromJnicallFunctionName(StringRef functionName) {
|
|
|
|
if (!functionName.consume_front("Java_"))
|
|
|
|
if (!functionName.consume_front("Java_"))
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
@@ -493,7 +487,8 @@ optional<std::string> scipSymbolFromJnicallFunctionName(StringRef functionName)
|
|
|
|
if (!demangledName || demangledName->empty())
|
|
|
|
if (!demangledName || demangledName->empty())
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
|
|
// demangleJavaName returns something like .some.package.Class$InnerClass.method
|
|
|
|
// demangleJavaName returns something like
|
|
|
|
|
|
|
|
// .some.package.Class$InnerClass.method
|
|
|
|
// - prepend S_jvm_
|
|
|
|
// - prepend S_jvm_
|
|
|
|
// - remove the leading dot
|
|
|
|
// - remove the leading dot
|
|
|
|
// - replace the last dot with a #
|
|
|
|
// - replace the last dot with a #
|
|
|
|
@@ -508,8 +503,10 @@ optional<std::string> scipSymbolFromJnicallFunctionName(StringRef functionName)
|
|
|
|
std::replace(symbol.begin(), symbol.end(), '.', '/');
|
|
|
|
std::replace(symbol.begin(), symbol.end(), '.', '/');
|
|
|
|
std::replace(symbol.begin(), symbol.end(), '$', '#');
|
|
|
|
std::replace(symbol.begin(), symbol.end(), '$', '#');
|
|
|
|
|
|
|
|
|
|
|
|
// Keep track of how many times we have seen this method, to build the ([+overloadNumber]). suffix.
|
|
|
|
// Keep track of how many times we have seen this method, to build the
|
|
|
|
// This assumes this function is called on C function definitions in the same order the matching overloads are declared in Java.
|
|
|
|
// ([+overloadNumber]). suffix. This assumes this function is called on C
|
|
|
|
|
|
|
|
// function definitions in the same order the matching overloads are declared
|
|
|
|
|
|
|
|
// in Java.
|
|
|
|
static std::unordered_map<std::string, uint> jnicallFunctions;
|
|
|
|
static std::unordered_map<std::string, uint> jnicallFunctions;
|
|
|
|
auto &overloadNumber = jnicallFunctions[symbol];
|
|
|
|
auto &overloadNumber = jnicallFunctions[symbol];
|
|
|
|
|
|
|
|
|
|
|
|
@@ -530,8 +527,7 @@ optional<std::string> scipSymbolFromJnicallFunctionName(StringRef functionName)
|
|
|
|
// {
|
|
|
|
// {
|
|
|
|
// static constexpr char name[] = "[nameFieldValue]";
|
|
|
|
// static constexpr char name[] = "[nameFieldValue]";
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
void findBindingToJavaClass(ASTContext &C, CXXRecordDecl &klass)
|
|
|
|
void findBindingToJavaClass(ASTContext &C, CXXRecordDecl &klass) {
|
|
|
|
{
|
|
|
|
|
|
|
|
for (const auto &baseSpecifier : klass.bases()) {
|
|
|
|
for (const auto &baseSpecifier : klass.bases()) {
|
|
|
|
const auto *base = baseSpecifier.getType()->getAsCXXRecordDecl();
|
|
|
|
const auto *base = baseSpecifier.getType()->getAsCXXRecordDecl();
|
|
|
|
if (!base)
|
|
|
|
if (!base)
|
|
|
|
@@ -544,11 +540,12 @@ void findBindingToJavaClass(ASTContext &C, CXXRecordDecl &klass)
|
|
|
|
if (!name)
|
|
|
|
if (!name)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
const auto symbol = javaScipSymbol(JVM_SCIP_SYMBOL_PREFIX, *name, BindingTo::Kind::Class);
|
|
|
|
const auto symbol =
|
|
|
|
const auto binding = BindingTo {{
|
|
|
|
javaScipSymbol(JVM_SCIP_SYMBOL_PREFIX, *name, BindingTo::Kind::Class);
|
|
|
|
.lang = BindingTo::Lang::Jvm,
|
|
|
|
const auto binding = BindingTo{{
|
|
|
|
.kind = BindingTo::Kind::Class,
|
|
|
|
.lang = BindingTo::Lang::Jvm,
|
|
|
|
.symbol = symbol,
|
|
|
|
.kind = BindingTo::Kind::Class,
|
|
|
|
|
|
|
|
.symbol = symbol,
|
|
|
|
}};
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
|
|
setBindingAttr(C, klass, binding);
|
|
|
|
setBindingAttr(C, klass, binding);
|
|
|
|
@@ -556,10 +553,10 @@ void findBindingToJavaClass(ASTContext &C, CXXRecordDecl &klass)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// When a Java method is marked as native, the JRE looks by default for a function
|
|
|
|
// When a Java method is marked as native, the JRE looks by default for a
|
|
|
|
// named Java_<mangled method name>[__<mangled overload specification>].
|
|
|
|
// function named Java_<mangled method name>[__<mangled overload
|
|
|
|
void findBindingToJavaFunction(ASTContext &C, FunctionDecl &function)
|
|
|
|
// specification>].
|
|
|
|
{
|
|
|
|
void findBindingToJavaFunction(ASTContext &C, FunctionDecl &function) {
|
|
|
|
const auto *identifier = function.getIdentifier();
|
|
|
|
const auto *identifier = function.getIdentifier();
|
|
|
|
if (!identifier)
|
|
|
|
if (!identifier)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
@@ -569,10 +566,10 @@ void findBindingToJavaFunction(ASTContext &C, FunctionDecl &function)
|
|
|
|
if (!symbol)
|
|
|
|
if (!symbol)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
const auto binding = BoundAs {{
|
|
|
|
const auto binding = BoundAs{{
|
|
|
|
.lang = BindingTo::Lang::Jvm,
|
|
|
|
.lang = BindingTo::Lang::Jvm,
|
|
|
|
.kind = BindingTo::Kind::Method,
|
|
|
|
.kind = BindingTo::Kind::Method,
|
|
|
|
.symbol = *symbol,
|
|
|
|
.symbol = *symbol,
|
|
|
|
}};
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
|
|
setBindingAttr(C, function, binding);
|
|
|
|
setBindingAttr(C, function, binding);
|
|
|
|
@@ -590,8 +587,7 @@ void findBindingToJavaFunction(ASTContext &C, FunctionDecl &function)
|
|
|
|
// ...
|
|
|
|
// ...
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
void findBindingToJavaMember(ASTContext &C, CXXMethodDecl &method)
|
|
|
|
void findBindingToJavaMember(ASTContext &C, CXXMethodDecl &method) {
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto *parent = method.getParent();
|
|
|
|
const auto *parent = method.getParent();
|
|
|
|
if (!parent)
|
|
|
|
if (!parent)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
@@ -607,11 +603,12 @@ void findBindingToJavaMember(ASTContext &C, CXXMethodDecl &method)
|
|
|
|
if (!found)
|
|
|
|
if (!found)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
const auto symbol = javaScipSymbol(classBinding->symbol, found->name, found->kind);
|
|
|
|
const auto symbol =
|
|
|
|
const auto binding = BindingTo {{
|
|
|
|
javaScipSymbol(classBinding->symbol, found->name, found->kind);
|
|
|
|
.lang = BindingTo::Lang::Jvm,
|
|
|
|
const auto binding = BindingTo{{
|
|
|
|
.kind = found->kind,
|
|
|
|
.lang = BindingTo::Lang::Jvm,
|
|
|
|
.symbol = symbol,
|
|
|
|
.kind = found->kind,
|
|
|
|
|
|
|
|
.symbol = symbol,
|
|
|
|
}};
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
|
|
setBindingAttr(C, method, binding);
|
|
|
|
setBindingAttr(C, method, binding);
|
|
|
|
@@ -629,8 +626,7 @@ void findBindingToJavaMember(ASTContext &C, CXXMethodDecl &method)
|
|
|
|
// ...
|
|
|
|
// ...
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
void findBindingToJavaConstant(ASTContext &C, VarDecl &field)
|
|
|
|
void findBindingToJavaConstant(ASTContext &C, VarDecl &field) {
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto *parent = dyn_cast_or_null<CXXRecordDecl>(field.getDeclContext());
|
|
|
|
const auto *parent = dyn_cast_or_null<CXXRecordDecl>(field.getDeclContext());
|
|
|
|
if (!parent)
|
|
|
|
if (!parent)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
@@ -639,11 +635,12 @@ void findBindingToJavaConstant(ASTContext &C, VarDecl &field)
|
|
|
|
if (!classBinding)
|
|
|
|
if (!classBinding)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
const auto symbol = javaScipSymbol(classBinding->symbol, field.getName(), BindingTo::Kind::Const);
|
|
|
|
const auto symbol = javaScipSymbol(classBinding->symbol, field.getName(),
|
|
|
|
const auto binding = BindingTo {{
|
|
|
|
BindingTo::Kind::Const);
|
|
|
|
.lang = BindingTo::Lang::Jvm,
|
|
|
|
const auto binding = BindingTo{{
|
|
|
|
.kind = BindingTo::Kind::Const,
|
|
|
|
.lang = BindingTo::Lang::Jvm,
|
|
|
|
.symbol = symbol,
|
|
|
|
.kind = BindingTo::Kind::Const,
|
|
|
|
|
|
|
|
.symbol = symbol,
|
|
|
|
}};
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
|
|
setBindingAttr(C, field, binding);
|
|
|
|
setBindingAttr(C, field, binding);
|
|
|
|
@@ -667,22 +664,23 @@ void findBindingToJavaConstant(ASTContext &C, VarDecl &field)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
void findBoundAsJavaClasses(ASTContext &C, CXXRecordDecl &klass)
|
|
|
|
void findBoundAsJavaClasses(ASTContext &C, CXXRecordDecl &klass) {
|
|
|
|
{
|
|
|
|
|
|
|
|
for (const auto &baseSpecifier : klass.bases()) {
|
|
|
|
for (const auto &baseSpecifier : klass.bases()) {
|
|
|
|
const auto *base = baseSpecifier.getType()->getAsCXXRecordDecl();
|
|
|
|
const auto *base = baseSpecifier.getType()->getAsCXXRecordDecl();
|
|
|
|
if (!base)
|
|
|
|
if (!base)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto &baseBaseSpecifier : base->bases()) {
|
|
|
|
for (const auto &baseBaseSpecifier : base->bases()) {
|
|
|
|
const auto *baseBase = dyn_cast_or_null<ClassTemplateSpecializationDecl>(baseBaseSpecifier.getType()->getAsCXXRecordDecl());
|
|
|
|
const auto *baseBase = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
|
|
|
|
|
|
|
|
baseBaseSpecifier.getType()->getAsCXXRecordDecl());
|
|
|
|
if (!baseBase)
|
|
|
|
if (!baseBase)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (!isMozillaJniNativeImpl(*baseBase))
|
|
|
|
if (!isMozillaJniNativeImpl(*baseBase))
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
const auto *wrapper = baseBase->getTemplateArgs().get(0).getAsType()->getAsCXXRecordDecl();
|
|
|
|
const auto *wrapper =
|
|
|
|
|
|
|
|
baseBase->getTemplateArgs().get(0).getAsType()->getAsCXXRecordDecl();
|
|
|
|
|
|
|
|
|
|
|
|
if (!wrapper)
|
|
|
|
if (!wrapper)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
@@ -691,15 +689,17 @@ void findBoundAsJavaClasses(ASTContext &C, CXXRecordDecl &klass)
|
|
|
|
if (!name)
|
|
|
|
if (!name)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
const auto javaClassSymbol = javaScipSymbol(JVM_SCIP_SYMBOL_PREFIX, *name, BoundAs::Kind::Class);
|
|
|
|
const auto javaClassSymbol =
|
|
|
|
const auto classBinding = BoundAs {{
|
|
|
|
javaScipSymbol(JVM_SCIP_SYMBOL_PREFIX, *name, BoundAs::Kind::Class);
|
|
|
|
.lang = BoundAs::Lang::Jvm,
|
|
|
|
const auto classBinding = BoundAs{{
|
|
|
|
.kind = BoundAs::Kind::Class,
|
|
|
|
.lang = BoundAs::Lang::Jvm,
|
|
|
|
.symbol = javaClassSymbol,
|
|
|
|
.kind = BoundAs::Kind::Class,
|
|
|
|
|
|
|
|
.symbol = javaClassSymbol,
|
|
|
|
}};
|
|
|
|
}};
|
|
|
|
setBindingAttr(C, klass, classBinding);
|
|
|
|
setBindingAttr(C, klass, classBinding);
|
|
|
|
|
|
|
|
|
|
|
|
const auto *methodsDecl = dyn_cast_or_null<VarDecl>(fieldNamed("methods", *base));
|
|
|
|
const auto *methodsDecl =
|
|
|
|
|
|
|
|
dyn_cast_or_null<VarDecl>(fieldNamed("methods", *base));
|
|
|
|
if (!methodsDecl)
|
|
|
|
if (!methodsDecl)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -714,7 +714,8 @@ void findBoundAsJavaClasses(ASTContext &C, CXXRecordDecl &klass)
|
|
|
|
std::set<const CXXMethodDecl *> alreadyBound;
|
|
|
|
std::set<const CXXMethodDecl *> alreadyBound;
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto *init : inits->inits()) {
|
|
|
|
for (const auto *init : inits->inits()) {
|
|
|
|
const auto *call = dyn_cast<CallExpr>(init->IgnoreUnlessSpelledInSource());
|
|
|
|
const auto *call =
|
|
|
|
|
|
|
|
dyn_cast<CallExpr>(init->IgnoreUnlessSpelledInSource());
|
|
|
|
if (!call)
|
|
|
|
if (!call)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -726,15 +727,18 @@ void findBoundAsJavaClasses(ASTContext &C, CXXRecordDecl &klass)
|
|
|
|
if (!templateArgs)
|
|
|
|
if (!templateArgs)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
const auto *strukt = dyn_cast_or_null<RecordDecl>(templateArgs->get(0).getAsType()->getAsRecordDecl());
|
|
|
|
const auto *strukt = dyn_cast_or_null<RecordDecl>(
|
|
|
|
|
|
|
|
templateArgs->get(0).getAsType()->getAsRecordDecl());
|
|
|
|
if (!strukt)
|
|
|
|
if (!strukt)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
const auto *wrapperRef = dyn_cast_or_null<DeclRefExpr>(call->getArg(0)->IgnoreUnlessSpelledInSource());
|
|
|
|
const auto *wrapperRef = dyn_cast_or_null<DeclRefExpr>(
|
|
|
|
|
|
|
|
call->getArg(0)->IgnoreUnlessSpelledInSource());
|
|
|
|
if (!wrapperRef)
|
|
|
|
if (!wrapperRef)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
const auto *boundRef = dyn_cast_or_null<UnaryOperator>(wrapperRef->template_arguments().front().getArgument().getAsExpr());
|
|
|
|
const auto *boundRef = dyn_cast_or_null<UnaryOperator>(
|
|
|
|
|
|
|
|
wrapperRef->template_arguments().front().getArgument().getAsExpr());
|
|
|
|
if (!boundRef)
|
|
|
|
if (!boundRef)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -752,25 +756,30 @@ void findBoundAsJavaClasses(ASTContext &C, CXXRecordDecl &klass)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
javaMethodSymbol += ").";
|
|
|
|
javaMethodSymbol += ").";
|
|
|
|
|
|
|
|
|
|
|
|
const auto binding = BoundAs {{
|
|
|
|
const auto binding = BoundAs{{
|
|
|
|
.lang = BoundAs::Lang::Jvm,
|
|
|
|
.lang = BoundAs::Lang::Jvm,
|
|
|
|
.kind = BoundAs::Kind::Method,
|
|
|
|
.kind = BoundAs::Kind::Method,
|
|
|
|
.symbol = javaMethodSymbol,
|
|
|
|
.symbol = javaMethodSymbol,
|
|
|
|
}};
|
|
|
|
}};
|
|
|
|
setBindingAttr(C, boundDecl, binding);
|
|
|
|
setBindingAttr(C, boundDecl, binding);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (auto *bound = dyn_cast_or_null<DeclRefExpr>(boundRef->getSubExpr())) {
|
|
|
|
if (auto *bound =
|
|
|
|
|
|
|
|
dyn_cast_or_null<DeclRefExpr>(boundRef->getSubExpr())) {
|
|
|
|
auto *method = dyn_cast_or_null<CXXMethodDecl>(bound->getDecl());
|
|
|
|
auto *method = dyn_cast_or_null<CXXMethodDecl>(bound->getDecl());
|
|
|
|
if (!method)
|
|
|
|
if (!method)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
addToBound(*method, 0);
|
|
|
|
addToBound(*method, 0);
|
|
|
|
} else if (const auto *bound = dyn_cast_or_null<UnresolvedLookupExpr>(boundRef->getSubExpr())) {
|
|
|
|
} else if (const auto *bound = dyn_cast_or_null<UnresolvedLookupExpr>(
|
|
|
|
|
|
|
|
boundRef->getSubExpr())) {
|
|
|
|
// XXX This is hackish
|
|
|
|
// XXX This is hackish
|
|
|
|
// In case of overloads it's not obvious which one we should use
|
|
|
|
// In case of overloads it's not obvious which one we should use
|
|
|
|
// this expects the declaration order between C++ and Java to match
|
|
|
|
// this expects the declaration order between C++ and Java to match
|
|
|
|
auto declarations = std::vector<Decl*>(bound->decls_begin(), bound->decls_end());
|
|
|
|
auto declarations =
|
|
|
|
auto byLocation = [](Decl *a, Decl *b){ return a->getLocation() < b->getLocation(); };
|
|
|
|
std::vector<Decl *>(bound->decls_begin(), bound->decls_end());
|
|
|
|
|
|
|
|
auto byLocation = [](Decl *a, Decl *b) {
|
|
|
|
|
|
|
|
return a->getLocation() < b->getLocation();
|
|
|
|
|
|
|
|
};
|
|
|
|
std::sort(declarations.begin(), declarations.end(), byLocation);
|
|
|
|
std::sort(declarations.begin(), declarations.end(), byLocation);
|
|
|
|
|
|
|
|
|
|
|
|
uint i = 0;
|
|
|
|
uint i = 0;
|
|
|
|
@@ -791,8 +800,7 @@ void findBoundAsJavaClasses(ASTContext &C, CXXRecordDecl &klass)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void emitBindingAttributes(llvm::json::OStream &J, const Decl &decl)
|
|
|
|
void emitBindingAttributes(llvm::json::OStream &J, const Decl &decl) {
|
|
|
|
{
|
|
|
|
|
|
|
|
addSlotOwnerAttribute(J, decl);
|
|
|
|
addSlotOwnerAttribute(J, decl);
|
|
|
|
addBindingSlotsAttribute(J, decl);
|
|
|
|
addBindingSlotsAttribute(J, decl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|