Bug 1833552 - Reformat mozsearch clang plugin using LLVM style. r=asuth

This is a bump of the Mozsearch clang plugin and was reviewed upstream:
https://github.com/mozsearch/mozsearch/pull/839

Differential Revision: https://phabricator.services.mozilla.com/D230454
This commit is contained in:
Nicolas Guichard
2024-11-28 00:04:18 +00:00
parent 6126601e77
commit 08d24b12c7
6 changed files with 505 additions and 443 deletions

View File

@@ -31,12 +31,13 @@ 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 {};
@@ -107,18 +108,14 @@ struct AbstractBinding {
"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)) {}
@@ -172,24 +163,25 @@ 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 {};
@@ -218,8 +213,7 @@ optional<AbstractBinding> readBinding(const AnnotateAttr &attr)
}; };
} }
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;
@@ -275,7 +266,8 @@ 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 {};
@@ -334,16 +328,15 @@ private:
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,12 +397,13 @@ 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 = {};
@@ -467,7 +460,8 @@ optional<std::string> demangleJnicallPart(StringRef &remainder)
default: default:
// either: // either:
// * the string began with _[^0-3], which is not supposed to happen; or // * 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 // * we reached __[^0-3] meaning we finished the first part of the name
// and remainder holds the overload specification
return demangled; return demangled;
} }
default: default:
@@ -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,7 +540,8 @@ 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 =
javaScipSymbol(JVM_SCIP_SYMBOL_PREFIX, *name, BindingTo::Kind::Class);
const auto binding = BindingTo{{ const auto binding = BindingTo{{
.lang = BindingTo::Lang::Jvm, .lang = BindingTo::Lang::Jvm,
.kind = BindingTo::Kind::Class, .kind = BindingTo::Kind::Class,
@@ -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;
@@ -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,7 +603,8 @@ 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 =
javaScipSymbol(classBinding->symbol, found->name, found->kind);
const auto binding = BindingTo{{ const auto binding = BindingTo{{
.lang = BindingTo::Lang::Jvm, .lang = BindingTo::Lang::Jvm,
.kind = found->kind, .kind = found->kind,
@@ -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,7 +635,8 @@ 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(),
BindingTo::Kind::Const);
const auto binding = BindingTo{{ const auto binding = BindingTo{{
.lang = BindingTo::Lang::Jvm, .lang = BindingTo::Lang::Jvm,
.kind = BindingTo::Kind::Const, .kind = BindingTo::Kind::Const,
@@ -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,7 +689,8 @@ 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 =
javaScipSymbol(JVM_SCIP_SYMBOL_PREFIX, *name, BoundAs::Kind::Class);
const auto classBinding = BoundAs{{ const auto classBinding = BoundAs{{
.lang = BoundAs::Lang::Jvm, .lang = BoundAs::Lang::Jvm,
.kind = BoundAs::Kind::Class, .kind = BoundAs::Kind::Class,
@@ -699,7 +698,8 @@ void findBoundAsJavaClasses(ASTContext &C, CXXRecordDecl &klass)
}}; }};
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;
@@ -760,17 +764,22 @@ void findBoundAsJavaClasses(ASTContext &C, CXXRecordDecl &klass)
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);
} }

View File

@@ -10,8 +10,10 @@
void findBindingToJavaClass(clang::ASTContext &C, clang::CXXRecordDecl &klass); void findBindingToJavaClass(clang::ASTContext &C, clang::CXXRecordDecl &klass);
void findBoundAsJavaClasses(clang::ASTContext &C, clang::CXXRecordDecl &klass); void findBoundAsJavaClasses(clang::ASTContext &C, clang::CXXRecordDecl &klass);
void findBindingToJavaFunction(clang::ASTContext &C, clang::FunctionDecl &function); void findBindingToJavaFunction(clang::ASTContext &C,
void findBindingToJavaMember(clang::ASTContext &C, clang::CXXMethodDecl &method); clang::FunctionDecl &function);
void findBindingToJavaMember(clang::ASTContext &C,
clang::CXXMethodDecl &method);
void findBindingToJavaConstant(clang::ASTContext &C, clang::VarDecl &field); void findBindingToJavaConstant(clang::ASTContext &C, clang::VarDecl &field);
void emitBindingAttributes(llvm::json::OStream &json, const clang::Decl &decl); void emitBindingAttributes(llvm::json::OStream &json, const clang::Decl &decl);

View File

@@ -9,10 +9,10 @@
#include <stdlib.h> #include <stdlib.h>
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#include "StringOperations.h"
#include <direct.h> #include <direct.h>
#include <io.h> #include <io.h>
#include <windows.h> #include <windows.h>
#include "StringOperations.h"
#else #else
#include <sys/file.h> #include <sys/file.h>
#include <sys/time.h> #include <sys/time.h>
@@ -50,7 +50,8 @@ void ensurePath(std::string Path) {
} }
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
AutoLockFile::AutoLockFile(const std::string &SrcFile, const std::string &DstFile) { AutoLockFile::AutoLockFile(const std::string &SrcFile,
const std::string &DstFile) {
this->Filename = DstFile; this->Filename = DstFile;
std::string Hash = hash(SrcFile); std::string Hash = hash(SrcFile);
std::string MutexName = std::string("Local\\searchfox-") + Hash; std::string MutexName = std::string("Local\\searchfox-") + Hash;
@@ -71,12 +72,11 @@ AutoLockFile::~AutoLockFile() {
CloseHandle(Handle); CloseHandle(Handle);
} }
bool AutoLockFile::success() { bool AutoLockFile::success() { return Handle != NULL; }
return Handle != NULL;
}
FILE *AutoLockFile::openTmp() { FILE *AutoLockFile::openTmp() {
int TmpDescriptor = _open((Filename + ".tmp").c_str(), _O_WRONLY | _O_APPEND | _O_CREAT | _O_BINARY, 0666); int TmpDescriptor = _open((Filename + ".tmp").c_str(),
_O_WRONLY | _O_APPEND | _O_CREAT | _O_BINARY, 0666);
return _fdopen(TmpDescriptor, "ab"); return _fdopen(TmpDescriptor, "ab");
} }
@@ -97,7 +97,8 @@ std::string getAbsolutePath(const std::string &Filename) {
return std::string(Full); return std::string(Full);
} }
#else #else
AutoLockFile::AutoLockFile(const std::string &SrcFile, const std::string &DstFile) { AutoLockFile::AutoLockFile(const std::string &SrcFile,
const std::string &DstFile) {
this->Filename = DstFile; this->Filename = DstFile;
FileDescriptor = open(SrcFile.c_str(), O_RDONLY); FileDescriptor = open(SrcFile.c_str(), O_RDONLY);
if (FileDescriptor == -1) { if (FileDescriptor == -1) {
@@ -117,7 +118,8 @@ AutoLockFile::~AutoLockFile() { close(FileDescriptor); }
bool AutoLockFile::success() { return FileDescriptor != -1; } bool AutoLockFile::success() { return FileDescriptor != -1; }
FILE *AutoLockFile::openTmp() { FILE *AutoLockFile::openTmp() {
int TmpDescriptor = open((Filename + ".tmp").c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666); int TmpDescriptor =
open((Filename + ".tmp").c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
return fdopen(TmpDescriptor, "ab"); return fdopen(TmpDescriptor, "ab");
} }

View File

@@ -96,7 +96,8 @@ FileType relativizePath(std::string& path) {
// Empty filenames can get turned into Srcdir when they are resolved as // Empty filenames can get turned into Srcdir when they are resolved as
// absolute paths, so we should exclude files that are exactly equal to // absolute paths, so we should exclude files that are exactly equal to
// Srcdir or anything outside Srcdir. // Srcdir or anything outside Srcdir.
if (path.length() > Srcdir.length() && path.compare(0, Srcdir.length(), Srcdir) == 0) { if (path.length() > Srcdir.length() &&
path.compare(0, Srcdir.length(), Srcdir) == 0) {
// Remove the trailing `/' as well. // Remove the trailing `/' as well.
path.erase(0, Srcdir.length() + 1); path.erase(0, Srcdir.length() + 1);
return FileType::Source; return FileType::Source;
@@ -142,13 +143,9 @@ static bool isASCII(const std::string& Input) {
} }
struct RAIITracer { struct RAIITracer {
RAIITracer(const char *log) : mLog(log) { RAIITracer(const char *log) : mLog(log) { printf("<%s>\n", mLog); }
printf("<%s>\n", mLog);
}
~RAIITracer() { ~RAIITracer() { printf("</%s>\n", mLog); }
printf("</%s>\n", mLog);
}
const char *mLog; const char *mLog;
}; };
@@ -157,21 +154,16 @@ struct RAIITracer {
// Sets variable to value on creation then resets variable to its original // Sets variable to value on creation then resets variable to its original
// value on destruction // value on destruction
template<typename T> template <typename T> class ValueRollback {
class ValueRollback {
public: public:
template <typename U = T> template <typename U = T>
ValueRollback(T &variable, U &&value) ValueRollback(T &variable, U &&value)
: mVariable{&variable} : mVariable{&variable},
, mSavedValue{std::exchange(variable, std::forward<U>(value))} mSavedValue{std::exchange(variable, std::forward<U>(value))} {}
{
}
ValueRollback(ValueRollback &&other) noexcept ValueRollback(ValueRollback &&other) noexcept
: mVariable{std::exchange(other.mVariable, nullptr)} : mVariable{std::exchange(other.mVariable, nullptr)},
, mSavedValue{std::move(other.mSavedValue)} mSavedValue{std::move(other.mSavedValue)} {}
{
}
ValueRollback(const ValueRollback &) = delete; ValueRollback(const ValueRollback &) = delete;
ValueRollback &operator=(ValueRollback &&) = delete; ValueRollback &operator=(ValueRollback &&) = delete;
@@ -227,7 +219,8 @@ struct FileInfo {
struct MacroExpansionState { struct MacroExpansionState {
Token MacroNameToken; Token MacroNameToken;
const MacroInfo *MacroInfo = nullptr; const MacroInfo *MacroInfo = nullptr;
std::vector<std::string> Dependencies; // other macro symbols this expansions depends on // other macro symbols this expansion depends on
std::vector<std::string> Dependencies;
std::string Expansion; std::string Expansion;
std::map<SourceLocation, unsigned> TokenLocations; std::map<SourceLocation, unsigned> TokenLocations;
SourceRange Range; SourceRange Range;
@@ -255,10 +248,8 @@ public:
FileID PrevFID) override; FileID PrevFID) override;
virtual void InclusionDirective(SourceLocation HashLoc, virtual void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok, const Token &IncludeTok, StringRef FileName,
StringRef FileName, bool IsAngled, CharSourceRange FileNameRange,
bool IsAngled,
CharSourceRange FileNameRange,
#if CLANG_VERSION_MAJOR >= 16 #if CLANG_VERSION_MAJOR >= 16
OptionalFileEntryRef File, OptionalFileEntryRef File,
#elif CLANG_VERSION_MAJOR >= 15 #elif CLANG_VERSION_MAJOR >= 15
@@ -266,8 +257,7 @@ public:
#else #else
const FileEntry *File, const FileEntry *File,
#endif #endif
StringRef SearchPath, StringRef SearchPath, StringRef RelativePath,
StringRef RelativePath,
#if CLANG_VERSION_MAJOR >= 19 #if CLANG_VERSION_MAJOR >= 19
const Module *SuggestedModule, const Module *SuggestedModule,
bool ModuleImported, bool ModuleImported,
@@ -314,9 +304,11 @@ private:
// Tracks the set of declarations that the current expression/statement is // Tracks the set of declarations that the current expression/statement is
// nested inside of. // nested inside of.
struct AutoSetContext { struct AutoSetContext {
AutoSetContext(IndexConsumer *Self, NamedDecl *Context, bool VisitImplicit = false) AutoSetContext(IndexConsumer *Self, NamedDecl *Context,
bool VisitImplicit = false)
: Self(Self), Prev(Self->CurDeclContext), Decl(Context) { : Self(Self), Prev(Self->CurDeclContext), Decl(Context) {
this->VisitImplicit = VisitImplicit || (Prev ? Prev->VisitImplicit : false); this->VisitImplicit =
VisitImplicit || (Prev ? Prev->VisitImplicit : false);
Self->CurDeclContext = this; Self->CurDeclContext = this;
} }
@@ -453,7 +445,8 @@ private:
if (IsInvalid) { if (IsInvalid) {
return ""; return "";
} }
unsigned Column1 = SM.getColumnNumber(Begin.first, Begin.second, &IsInvalid); unsigned Column1 =
SM.getColumnNumber(Begin.first, Begin.second, &IsInvalid);
if (IsInvalid) { if (IsInvalid) {
return ""; return "";
} }
@@ -496,8 +489,8 @@ private:
std::string Backing; std::string Backing;
llvm::raw_string_ostream Stream(Backing); llvm::raw_string_ostream Stream(Backing);
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
printTemplateArgumentList( printTemplateArgumentList(Stream, TemplateArgs.asArray(),
Stream, TemplateArgs.asArray(), PrintingPolicy(CI.getLangOpts())); PrintingPolicy(CI.getLangOpts()));
Result += Stream.str(); Result += Stream.str();
} }
} else if (const auto *Nd = dyn_cast<NamespaceDecl>(DC)) { } else if (const auto *Nd = dyn_cast<NamespaceDecl>(DC)) {
@@ -549,7 +542,8 @@ private:
// we can end up with hash collisions where different symbols from // we can end up with hash collisions where different symbols from
// different platforms map to the same thing. // different platforms map to the same thing.
char *Platform = getenv("MOZSEARCH_PLATFORM"); char *Platform = getenv("MOZSEARCH_PLATFORM");
Filename = std::string(Platform ? Platform : "") + std::string("@") + Filename; Filename =
std::string(Platform ? Platform : "") + std::string("@") + Filename;
} }
return hash(Filename + std::string("@") + locationToString(Loc)); return hash(Filename + std::string("@") + locationToString(Loc));
} }
@@ -569,8 +563,8 @@ private:
// The majority of path characters are letters and slashes which don't get // The majority of path characters are letters and slashes which don't get
// encoded, so that satisfies (1). Since "@" characters in the unsanitized // encoded, so that satisfies (1). Since "@" characters in the unsanitized
// path get encoded, there should be no "@" characters in the sanitized path // path get encoded, there should be no "@" characters in the sanitized path
// that got preserved from the unsanitized input, so that should satisfy (2). // that got preserved from the unsanitized input, so that should satisfy
// And (3) was done by trial-and-error. Note in particular the dot (.) // (2). And (3) was done by trial-and-error. Note in particular the dot (.)
// character needs to be encoded, or the symbol-search feature of mozsearch // character needs to be encoded, or the symbol-search feature of mozsearch
// doesn't work correctly, as all dot characters in the symbol query get // doesn't work correctly, as all dot characters in the symbol query get
// replaced by #. // replaced by #.
@@ -591,7 +585,8 @@ private:
// we can end up with hash collisions where different symbols from // we can end up with hash collisions where different symbols from
// different platforms map to the same thing. // different platforms map to the same thing.
char *Platform = getenv("MOZSEARCH_PLATFORM"); char *Platform = getenv("MOZSEARCH_PLATFORM");
Filename = std::string(Platform ? Platform : "") + std::string("@") + Filename; Filename =
std::string(Platform ? Platform : "") + std::string("@") + Filename;
} }
return Filename; return Filename;
} }
@@ -708,11 +703,11 @@ private:
public: public:
IndexConsumer(CompilerInstance &CI) IndexConsumer(CompilerInstance &CI)
: CI(CI), SM(CI.getSourceManager()), LO(CI.getLangOpts()), CurMangleContext(nullptr), : CI(CI), SM(CI.getSourceManager()), LO(CI.getLangOpts()),
AstContext(nullptr), ConcatInfo(CI.getPreprocessor()), CurDeclContext(nullptr), CurMangleContext(nullptr), AstContext(nullptr),
ConcatInfo(CI.getPreprocessor()), CurDeclContext(nullptr),
TemplateStack(nullptr) { TemplateStack(nullptr) {
CI.getPreprocessor().addPPCallbacks( CI.getPreprocessor().addPPCallbacks(make_unique<PreprocessorHook>(this));
make_unique<PreprocessorHook>(this));
CI.getPreprocessor().setTokenWatcher( CI.getPreprocessor().setTokenWatcher(
[this](const auto &token) { onTokenLexed(token); }); [this](const auto &token) { onTokenLexed(token); });
} }
@@ -757,8 +752,8 @@ public:
FileInfo &Info = *It->second; FileInfo &Info = *It->second;
std::string Filename = Outdir + Info.Realname; std::string Filename = Outdir + Info.Realname;
std::string SrcFilename = Info.Generated std::string SrcFilename =
? Objdir + Info.Realname.substr(GENERATED.length()) Info.Generated ? Objdir + Info.Realname.substr(GENERATED.length())
: Srcdir + PATHSEP_STRING + Info.Realname; : Srcdir + PATHSEP_STRING + Info.Realname;
ensurePath(Filename); ensurePath(Filename);
@@ -778,13 +773,15 @@ public:
std::ifstream Fin(Filename.c_str(), std::ios::in | std::ios::binary); std::ifstream Fin(Filename.c_str(), std::ios::in | std::ios::binary);
FILE *OutFp = Lock.openTmp(); FILE *OutFp = Lock.openTmp();
if (!OutFp) { if (!OutFp) {
fprintf(stderr, "Unable to open tmp out file for %s\n", Filename.c_str()); fprintf(stderr, "Unable to open tmp out file for %s\n",
Filename.c_str());
exit(1); exit(1);
} }
// Sort our new results and get an iterator to them // Sort our new results and get an iterator to them
std::sort(Info.Output.begin(), Info.Output.end()); std::sort(Info.Output.begin(), Info.Output.end());
std::vector<std::string>::const_iterator NewLinesIter = Info.Output.begin(); std::vector<std::string>::const_iterator NewLinesIter =
Info.Output.begin();
std::string LastNewWritten; std::string LastNewWritten;
// Loop over the existing (sorted) lines in the analysis output file. // Loop over the existing (sorted) lines in the analysis output file.
@@ -815,8 +812,10 @@ public:
// dedupe the new entries being written // dedupe the new entries being written
continue; continue;
} }
if (fwrite(NewLinesIter->c_str(), NewLinesIter->length(), 1, OutFp) != 1) { if (fwrite(NewLinesIter->c_str(), NewLinesIter->length(), 1, OutFp) !=
fprintf(stderr, "Unable to write %zu bytes[1] to tmp output file for %s\n", 1) {
fprintf(stderr,
"Unable to write %zu bytes[1] to tmp output file for %s\n",
NewLinesIter->length(), Filename.c_str()); NewLinesIter->length(), Filename.c_str());
exit(1); exit(1);
} }
@@ -825,7 +824,8 @@ public:
// Write the entry read from the existing file. // Write the entry read from the existing file.
if (fwrite(OldLine.c_str(), OldLine.length(), 1, OutFp) != 1) { if (fwrite(OldLine.c_str(), OldLine.length(), 1, OutFp) != 1) {
fprintf(stderr, "Unable to write %zu bytes[2] to tmp output file for %s\n", fprintf(stderr,
"Unable to write %zu bytes[2] to tmp output file for %s\n",
OldLine.length(), Filename.c_str()); OldLine.length(), Filename.c_str());
exit(1); exit(1);
} }
@@ -839,8 +839,10 @@ public:
if (*NewLinesIter == LastNewWritten) { if (*NewLinesIter == LastNewWritten) {
continue; continue;
} }
if (fwrite(NewLinesIter->c_str(), NewLinesIter->length(), 1, OutFp) != 1) { if (fwrite(NewLinesIter->c_str(), NewLinesIter->length(), 1, OutFp) !=
fprintf(stderr, "Unable to write %zu bytes[3] to tmp output file for %s\n", 1) {
fprintf(stderr,
"Unable to write %zu bytes[3] to tmp output file for %s\n",
NewLinesIter->length(), Filename.c_str()); NewLinesIter->length(), Filename.c_str());
exit(1); exit(1);
} }
@@ -851,7 +853,9 @@ public:
// with the new one. // with the new one.
fclose(OutFp); fclose(OutFp);
if (!Lock.moveTmp()) { if (!Lock.moveTmp()) {
fprintf(stderr, "Unable to move tmp output file into place for %s (err %d)\n", Filename.c_str(), errno); fprintf(stderr,
"Unable to move tmp output file into place for %s (err %d)\n",
Filename.c_str(), errno);
exit(1); exit(1);
} }
} }
@@ -950,7 +954,8 @@ public:
D = F->getTemplateInstantiationPattern(); D = F->getTemplateInstantiationPattern();
} }
return Context(D->getQualifiedNameAsString(), getMangledName(CurMangleContext, D)); return Context(D->getQualifiedNameAsString(),
getMangledName(CurMangleContext, D));
} }
Context getContext(SourceLocation Loc) { Context getContext(SourceLocation Loc) {
@@ -990,7 +995,8 @@ public:
return Context(); return Context();
} }
// Searches for the closest CurDeclContext parent that is a function template instantiation // Searches for the closest CurDeclContext parent that is a function template
// instantiation
const FunctionDecl *getCurrentFunctionTemplateInstantiation() { const FunctionDecl *getCurrentFunctionTemplateInstantiation() {
const auto *Ctxt = CurDeclContext; const auto *Ctxt = CurDeclContext;
while (Ctxt) { while (Ctxt) {
@@ -1033,9 +1039,9 @@ public:
// indexer to visit EVERY identifier, which is way too much data. // indexer to visit EVERY identifier, which is way too much data.
struct AutoTemplateContext { struct AutoTemplateContext {
AutoTemplateContext(IndexConsumer *Self) AutoTemplateContext(IndexConsumer *Self)
: Self(Self) : Self(Self), CurMode(Self->TemplateStack ? Self->TemplateStack->CurMode
, CurMode(Self->TemplateStack ? Self->TemplateStack->CurMode : Mode::GatherDependent) : Mode::GatherDependent),
, Parent(Self->TemplateStack) { Parent(Self->TemplateStack) {
Self->TemplateStack = this; Self->TemplateStack = this;
} }
@@ -1066,9 +1072,7 @@ public:
} }
} }
bool inGatherMode() { bool inGatherMode() { return CurMode == Mode::GatherDependent; }
return CurMode == Mode::GatherDependent;
}
// Do we need to perform the extra AnalyzeDependent passes (one per // Do we need to perform the extra AnalyzeDependent passes (one per
// instantiation)? // instantiation)?
@@ -1119,7 +1123,8 @@ public:
AutoTemplateContext *TemplateStack; AutoTemplateContext *TemplateStack;
std::unordered_multimap<const FunctionDecl *, const Stmt *> ForwardingTemplates; std::unordered_multimap<const FunctionDecl *, const Stmt *>
ForwardingTemplates;
std::unordered_set<unsigned> ForwardedTemplateLocations; std::unordered_set<unsigned> ForwardedTemplateLocations;
bool shouldVisitTemplateInstantiations() const { bool shouldVisitTemplateInstantiations() const {
@@ -1196,7 +1201,8 @@ public:
// Flag to omit the identifier from being cross-referenced across files. // Flag to omit the identifier from being cross-referenced across files.
// This is usually desired for local variables. // This is usually desired for local variables.
NoCrossref = 1 << 0, NoCrossref = 1 << 0,
// Flag to indicate the token with analysis data is not an identifier. Indicates // Flag to indicate the token with analysis data is not an identifier.
// Indicates
// we want to skip the check that tries to ensure a sane identifier token. // we want to skip the check that tries to ensure a sane identifier token.
NotIdentifierToken = 1 << 1, NotIdentifierToken = 1 << 1,
// This indicates that the end of the provided SourceRange is valid and // This indicates that the end of the provided SourceRange is valid and
@@ -1206,8 +1212,10 @@ public:
LocRangeEndValid = 1 << 2 LocRangeEndValid = 1 << 2
}; };
void emitStructuredRecordInfo(llvm::json::OStream &J, SourceLocation Loc, const RecordDecl *decl) { void emitStructuredRecordInfo(llvm::json::OStream &J, SourceLocation Loc,
J.attribute("kind", TypeWithKeyword::getTagTypeKindName(decl->getTagKind())); const RecordDecl *decl) {
J.attribute("kind",
TypeWithKeyword::getTagTypeKindName(decl->getTagKind()));
const ASTContext &C = *AstContext; const ASTContext &C = *AstContext;
const ASTRecordLayout &Layout = C.getASTRecordLayout(decl); const ASTRecordLayout &Layout = C.getASTRecordLayout(decl);
@@ -1226,7 +1234,8 @@ public:
// * the size string 4/8 is shorter than true/false in the analysis // * the size string 4/8 is shorter than true/false in the analysis
// file // file
const QualType ptrType = C.getUIntPtrType(); const QualType ptrType = C.getUIntPtrType();
J.attribute("ownVFPtrBytes", C.getTypeSizeInChars(ptrType).getQuantity()); J.attribute("ownVFPtrBytes",
C.getTypeSizeInChars(ptrType).getQuantity());
} }
J.attributeBegin("supers"); J.attributeBegin("supers");
@@ -1310,14 +1319,17 @@ public:
J.arrayBegin(); J.arrayBegin();
uint64_t iField = 0; uint64_t iField = 0;
for (RecordDecl::field_iterator It = decl->field_begin(), for (RecordDecl::field_iterator It = decl->field_begin(),
End = decl->field_end(); It != End; ++It, ++iField) { End = decl->field_end();
It != End; ++It, ++iField) {
const FieldDecl &Field = **It; const FieldDecl &Field = **It;
auto sourceRange = SM.getExpansionRange(Field.getSourceRange()).getAsRange(); auto sourceRange =
SM.getExpansionRange(Field.getSourceRange()).getAsRange();
uint64_t localOffsetBits = Layout.getFieldOffset(iField); uint64_t localOffsetBits = Layout.getFieldOffset(iField);
CharUnits localOffsetBytes = C.toCharUnitsFromBits(localOffsetBits); CharUnits localOffsetBytes = C.toCharUnitsFromBits(localOffsetBits);
J.objectBegin(); J.objectBegin();
J.attribute("lineRange", pathAndLineRangeToString(structFileID, sourceRange)); J.attribute("lineRange",
pathAndLineRangeToString(structFileID, sourceRange));
J.attribute("pretty", getQualifiedName(&Field)); J.attribute("pretty", getQualifiedName(&Field));
J.attribute("sym", getMangledName(CurMangleContext, &Field)); J.attribute("sym", getMangledName(CurMangleContext, &Field));
@@ -1346,7 +1358,8 @@ public:
J.attributeBegin("bitPositions"); J.attributeBegin("bitPositions");
J.objectBegin(); J.objectBegin();
J.attribute("begin", unsigned(localOffsetBits - C.toBits(localOffsetBytes))); J.attribute("begin",
unsigned(localOffsetBits - C.toBits(localOffsetBytes)));
J.attribute("width", Field.getBitWidthValue(C)); J.attribute("width", Field.getBitWidthValue(C));
J.objectEnd(); J.objectEnd();
@@ -1381,7 +1394,8 @@ public:
J.attribute("kind", "enumConstant"); J.attribute("kind", "enumConstant");
} }
void emitStructuredFunctionInfo(llvm::json::OStream &J, const FunctionDecl *decl) { void emitStructuredFunctionInfo(llvm::json::OStream &J,
const FunctionDecl *decl) {
emitBindingAttributes(J, *decl); emitBindingAttributes(J, *decl);
J.attributeBegin("args"); J.attributeBegin("args");
@@ -1431,7 +1445,8 @@ public:
// TODO: Make sure we're doing template traversals appropriately... // TODO: Make sure we're doing template traversals appropriately...
// findOverriddenMethods (now removed) liked to do: // findOverriddenMethods (now removed) liked to do:
// if (Decl->isTemplateInstantiation()) { // if (Decl->isTemplateInstantiation()) {
// Decl = dyn_cast<CXXMethodDecl>(Decl->getTemplateInstantiationPattern()); // Decl =
// dyn_cast<CXXMethodDecl>(Decl->getTemplateInstantiationPattern());
// } // }
// I think our pre-emptive dereferencing/avoidance of templates may // I think our pre-emptive dereferencing/avoidance of templates may
// protect us from this, but it needs more investigation. // protect us from this, but it needs more investigation.
@@ -1507,7 +1522,8 @@ public:
* Emit structured info for a variable if it is a static class member. * Emit structured info for a variable if it is a static class member.
*/ */
void emitStructuredVarInfo(llvm::json::OStream &J, const VarDecl *decl) { void emitStructuredVarInfo(llvm::json::OStream &J, const VarDecl *decl) {
const auto *parentDecl = dyn_cast_or_null<RecordDecl>(decl->getDeclContext()); const auto *parentDecl =
dyn_cast_or_null<RecordDecl>(decl->getDeclContext());
J.attribute("kind", "field"); J.attribute("kind", "field");
@@ -1572,8 +1588,7 @@ public:
// called for each identifier that corresponds to a symbol. // called for each identifier that corresponds to a symbol.
void visitIdentifier(const char *Kind, const char *SyntaxKind, void visitIdentifier(const char *Kind, const char *SyntaxKind,
llvm::StringRef QualName, SourceRange LocRange, llvm::StringRef QualName, SourceRange LocRange,
std::string Symbol, std::string Symbol, QualType MaybeType = QualType(),
QualType MaybeType = QualType(),
Context TokenContext = Context(), int Flags = 0, Context TokenContext = Context(), int Flags = 0,
SourceRange PeekRange = SourceRange(), SourceRange PeekRange = SourceRange(),
SourceRange NestingRange = SourceRange(), SourceRange NestingRange = SourceRange(),
@@ -1583,7 +1598,9 @@ public:
// Also visit the spelling site. // Also visit the spelling site.
SourceLocation SpellingLoc = SM.getSpellingLoc(Loc); SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
if (SpellingLoc != Loc) { if (SpellingLoc != Loc) {
visitIdentifier(Kind, SyntaxKind, QualName, SpellingLoc, Symbol, MaybeType, TokenContext, Flags, PeekRange, NestingRange, ArgRanges); visitIdentifier(Kind, SyntaxKind, QualName, SpellingLoc, Symbol,
MaybeType, TokenContext, Flags, PeekRange, NestingRange,
ArgRanges);
} }
SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc); SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
@@ -1598,12 +1615,16 @@ public:
// Find the file positions corresponding to the token. // Find the file positions corresponding to the token.
unsigned StartOffset = SM.getFileOffset(ExpansionLoc); unsigned StartOffset = SM.getFileOffset(ExpansionLoc);
unsigned EndOffset = (Flags & LocRangeEndValid) unsigned EndOffset =
(Flags & LocRangeEndValid)
? SM.getFileOffset(LocRange.getEnd()) ? SM.getFileOffset(LocRange.getEnd())
: StartOffset + Lexer::MeasureTokenLength(ExpansionLoc, SM, CI.getLangOpts()); : StartOffset +
Lexer::MeasureTokenLength(ExpansionLoc, SM, CI.getLangOpts());
std::string LocStr = locationToString(ExpansionLoc, EndOffset - StartOffset); std::string LocStr =
std::string RangeStr = locationToString(ExpansionLoc, EndOffset - StartOffset); locationToString(ExpansionLoc, EndOffset - StartOffset);
std::string RangeStr =
locationToString(ExpansionLoc, EndOffset - StartOffset);
std::string PeekRangeStr; std::string PeekRangeStr;
if (!(Flags & NotIdentifierToken)) { if (!(Flags & NotIdentifierToken)) {
@@ -1745,7 +1766,8 @@ public:
J.objectBegin(); J.objectBegin();
J.attributeBegin(macroInfo.Key); J.attributeBegin(macroInfo.Key);
J.objectBegin(); J.objectBegin();
J.attribute("", macroInfo.Expansion); // "" is the platform key, populated by the merge step J.attribute("", macroInfo.Expansion); // "" is the platform key,
// populated by the merge step
J.objectEnd(); J.objectEnd();
J.attributeEnd(); J.attributeEnd();
J.objectEnd(); J.objectEnd();
@@ -1757,7 +1779,8 @@ public:
J.objectBegin(); J.objectBegin();
J.attributeBegin(macroInfo.Key); J.attributeBegin(macroInfo.Key);
J.objectBegin(); J.objectBegin();
J.attributeBegin(""); // "" is the platform key, populated by the merge step J.attributeBegin(
""); // "" is the platform key, populated by the merge step
J.arrayBegin(); J.arrayBegin();
J.value(it->second); J.value(it->second);
J.arrayEnd(); J.arrayEnd();
@@ -1815,7 +1838,8 @@ public:
// But if there are parameters, we want to include those as well. // But if there are parameters, we want to include those as well.
for (ParmVarDecl *Param : D->parameters()) { for (ParmVarDecl *Param : D->parameters()) {
std::pair<FileID, unsigned> ParamLoc = SM.getDecomposedLoc(Param->getLocation()); std::pair<FileID, unsigned> ParamLoc =
SM.getDecomposedLoc(Param->getLocation());
// It's possible there are macros involved or something. We don't include // It's possible there are macros involved or something. We don't include
// the parameters in that case. // the parameters in that case.
@@ -1841,8 +1865,8 @@ public:
for (CXXBaseSpecifier &Base : D2->bases()) { for (CXXBaseSpecifier &Base : D2->bases()) {
std::pair<FileID, unsigned> Loc = SM.getDecomposedLoc(Base.getEndLoc()); std::pair<FileID, unsigned> Loc = SM.getDecomposedLoc(Base.getEndLoc());
// It's possible there are macros involved or something. We don't include // It's possible there are macros involved or something. We don't
// the parameters in that case. // include the parameters in that case.
if (Loc.first == FuncLoc.first) { if (Loc.first == FuncLoc.first) {
// Assume parameters are in order, so we always take the last one. // Assume parameters are in order, so we always take the last one.
End = Base.getEndLoc(); End = Base.getEndLoc();
@@ -1854,8 +1878,7 @@ public:
} }
SourceRange getCommentRange(NamedDecl *D) { SourceRange getCommentRange(NamedDecl *D) {
const RawComment* RC = const RawComment *RC = AstContext->getRawCommentForDeclNoCache(D);
AstContext->getRawCommentForDeclNoCache(D);
if (!RC) { if (!RC) {
return SourceRange(); return SourceRange();
} }
@@ -1944,7 +1967,8 @@ public:
D = D2->getTemplateInstantiationPattern(); D = D2->getTemplateInstantiationPattern();
} }
// We treat pure virtual declarations as definitions. // We treat pure virtual declarations as definitions.
Kind = (D2->isThisDeclarationADefinition() || isPure(D2)) ? "def" : "decl"; Kind =
(D2->isThisDeclarationADefinition() || isPure(D2)) ? "def" : "decl";
PrettyKind = "function"; PrettyKind = "function";
PeekRange = getFunctionPeekRange(D2); PeekRange = getFunctionPeekRange(D2);
@@ -1998,7 +2022,8 @@ public:
if (D2) { if (D2) {
// There's no exposure of the left brace so we have to find it. // There's no exposure of the left brace so we have to find it.
NestingRange = SourceRange( NestingRange = SourceRange(
findLeftBraceFromLoc(D2->isAnonymousNamespace() ? D2->getBeginLoc() : ExpansionLoc), findLeftBraceFromLoc(D2->isAnonymousNamespace() ? D2->getBeginLoc()
: ExpansionLoc),
D2->getRBraceLoc()); D2->getRBraceLoc());
} }
} else if (isa<FieldDecl>(D)) { } else if (isa<FieldDecl>(D)) {
@@ -2024,9 +2049,9 @@ public:
// In the case of destructors, Loc might point to the ~ character. In that // In the case of destructors, Loc might point to the ~ character. In that
// case we want to skip to the name of the class. However, Loc might also // case we want to skip to the name of the class. However, Loc might also
// point to other places that generate destructors, such as a lambda (apparently // point to other places that generate destructors, such as a lambda
// clang 8 creates a destructor declaration for at least some lambdas). In // (apparently clang 8 creates a destructor declaration for at least some
// that case we'll just drop the declaration. // lambdas). In that case we'll just drop the declaration.
if (isa<CXXDestructorDecl>(D)) { if (isa<CXXDestructorDecl>(D)) {
PrettyKind = "destructor"; PrettyKind = "destructor";
const char *P = SM.getCharacterData(Loc); const char *P = SM.getCharacterData(Loc);
@@ -2046,9 +2071,9 @@ public:
} }
} }
visitIdentifier(Kind, PrettyKind, getQualifiedName(D), SourceRange(Loc), Symbol, visitIdentifier(Kind, PrettyKind, getQualifiedName(D), SourceRange(Loc),
qtype, Symbol, qtype, getContext(D), Flags, PeekRange,
getContext(D), Flags, PeekRange, NestingRange); NestingRange);
// In-progress structured info emission. // In-progress structured info emission.
if (RecordDecl *D2 = dyn_cast<RecordDecl>(D)) { if (RecordDecl *D2 = dyn_cast<RecordDecl>(D)) {
@@ -2058,8 +2083,7 @@ public:
// dependent type or if we're in any kind of template context. This // dependent type or if we're in any kind of template context. This
// should be re-evaluated once this is working for normal classes and // should be re-evaluated once this is working for normal classes and
// we can better evaluate what is useful. // we can better evaluate what is useful.
!D2->isDependentType() && !D2->isDependentType() && !TemplateStack) {
!TemplateStack) {
if (auto *D3 = dyn_cast<CXXRecordDecl>(D2)) { if (auto *D3 = dyn_cast<CXXRecordDecl>(D2)) {
findBindingToJavaClass(*AstContext, *D3); findBindingToJavaClass(*AstContext, *D3);
findBoundAsJavaClasses(*AstContext, *D3); findBoundAsJavaClasses(*AstContext, *D3);
@@ -2082,10 +2106,8 @@ public:
if ((D2->isThisDeclarationADefinition() || isPure(D2)) && if ((D2->isThisDeclarationADefinition() || isPure(D2)) &&
// a clause at the top should have generalized and set wasTemplate so // a clause at the top should have generalized and set wasTemplate so
// it shouldn't be the case that isTemplateInstantiation() is true. // it shouldn't be the case that isTemplateInstantiation() is true.
!D2->isTemplateInstantiation() && !D2->isTemplateInstantiation() && !wasTemplate &&
!wasTemplate && !D2->isFunctionTemplateSpecialization() && !TemplateStack) {
!D2->isFunctionTemplateSpecialization() &&
!TemplateStack) {
if (auto *D3 = dyn_cast<CXXMethodDecl>(D2)) { if (auto *D3 = dyn_cast<CXXMethodDecl>(D2)) {
findBindingToJavaMember(*AstContext, *D3); findBindingToJavaMember(*AstContext, *D3);
} else { } else {
@@ -2095,14 +2117,12 @@ public:
} }
} }
if (FieldDecl *D2 = dyn_cast<FieldDecl>(D)) { if (FieldDecl *D2 = dyn_cast<FieldDecl>(D)) {
if (!D2->isTemplated() && if (!D2->isTemplated() && !TemplateStack) {
!TemplateStack) {
emitStructuredInfo(ExpansionLoc, D2); emitStructuredInfo(ExpansionLoc, D2);
} }
} }
if (VarDecl *D2 = dyn_cast<VarDecl>(D)) { if (VarDecl *D2 = dyn_cast<VarDecl>(D)) {
if (!D2->isTemplated() && if (!D2->isTemplated() && !TemplateStack &&
!TemplateStack &&
isa<CXXRecordDecl>(D2->getDeclContext())) { isa<CXXRecordDecl>(D2->getDeclContext())) {
findBindingToJavaConstant(*AstContext, *D2); findBindingToJavaConstant(*AstContext, *D2);
emitStructuredInfo(ExpansionLoc, D2); emitStructuredInfo(ExpansionLoc, D2);
@@ -2118,11 +2138,14 @@ public:
return true; return true;
} }
// If we are in a template and find a Stmt that was registed in ForwardedTemplateLocations, // If we are in a template and find a Stmt that was registed in
// convert the location to an actual Stmt* in ForwardingTemplates // ForwardedTemplateLocations, convert the location to an actual Stmt* in
// ForwardingTemplates
if (TemplateStack && !TemplateStack->inGatherMode()) { if (TemplateStack && !TemplateStack->inGatherMode()) {
if (ForwardedTemplateLocations.find(E->getBeginLoc().getRawEncoding()) != ForwardedTemplateLocations.end()) { if (ForwardedTemplateLocations.find(E->getBeginLoc().getRawEncoding()) !=
ForwardingTemplates.insert({getCurrentFunctionTemplateInstantiation(), E}); ForwardedTemplateLocations.end()) {
ForwardingTemplates.insert(
{getCurrentFunctionTemplateInstantiation(), E});
return true; return true;
} }
} }
@@ -2148,8 +2171,9 @@ public:
} }
bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
// If we are in a template and the callee is type-dependent, register it in ForwardedTemplateLocations // If we are in a template and the callee is type-dependent, register it in
// to forward its uses to the surrounding template call site // ForwardedTemplateLocations to forward its uses to the surrounding
// template call site
if (TemplateStack && TemplateStack->inGatherMode()) { if (TemplateStack && TemplateStack->inGatherMode()) {
if (E->isTypeDependent()) { if (E->isTypeDependent()) {
TemplateStack->visitDependent(E->getBeginLoc()); TemplateStack->visitDependent(E->getBeginLoc());
@@ -2210,9 +2234,10 @@ public:
argRanges.push_back(argExpr->getSourceRange()); argRanges.push_back(argExpr->getSourceRange());
} }
visitIdentifier("use", "function", getQualifiedName(NamedCallee), Loc, Mangled, visitIdentifier("use", "function", getQualifiedName(NamedCallee), Loc,
E->getCallReturnType(*AstContext), getContext(SpellingLoc), Flags, Mangled, E->getCallReturnType(*AstContext),
SourceRange(), SourceRange(), &argRanges); getContext(SpellingLoc), Flags, SourceRange(),
SourceRange(), &argRanges);
return true; return true;
} }
@@ -2300,7 +2325,8 @@ public:
} }
void VisitForwardedStatements(const Expr *E, SourceLocation Loc) { void VisitForwardedStatements(const Expr *E, SourceLocation Loc) {
// If this is a forwarding template (eg MakeUnique), visit the forwarded statements // If this is a forwarding template (eg MakeUnique), visit the forwarded
// statements
auto todo = std::stack{std::vector<const Stmt *>{E}}; auto todo = std::stack{std::vector<const Stmt *>{E}};
auto seen = std::unordered_set<const Stmt *>{}; auto seen = std::unordered_set<const Stmt *>{};
while (!todo.empty()) { while (!todo.empty()) {
@@ -2326,8 +2352,10 @@ public:
continue; continue;
if (!F->isTemplateInstantiation()) if (!F->isTemplateInstantiation())
continue; continue;
const auto [ForwardedBegin, ForwardedEnd] = ForwardingTemplates.equal_range(F); const auto [ForwardedBegin, ForwardedEnd] =
for (auto ForwardedIt = ForwardedBegin; ForwardedIt != ForwardedEnd; ++ForwardedIt) ForwardingTemplates.equal_range(F);
for (auto ForwardedIt = ForwardedBegin; ForwardedIt != ForwardedEnd;
++ForwardedIt)
if (seen.find(ForwardedIt->second) == seen.end()) if (seen.find(ForwardedIt->second) == seen.end())
todo.push(ForwardedIt->second); todo.push(ForwardedIt->second);
} }
@@ -2339,12 +2367,16 @@ public:
return true; return true;
} }
// If we are in a template and find a Stmt that was registed in ForwardedTemplateLocations, // If we are in a template and find a Stmt that was registed in
// convert the location to an actual Stmt* in ForwardingTemplates // ForwardedTemplateLocations, convert the location to an actual Stmt* in
// ForwardingTemplates
if (TemplateStack && !TemplateStack->inGatherMode()) { if (TemplateStack && !TemplateStack->inGatherMode()) {
const auto IsForwarded = ForwardedTemplateLocations.find(E->getBeginLoc().getRawEncoding()) != ForwardedTemplateLocations.end(); const auto IsForwarded =
ForwardedTemplateLocations.find(E->getBeginLoc().getRawEncoding()) !=
ForwardedTemplateLocations.end();
if (IsForwarded) { if (IsForwarded) {
ForwardingTemplates.insert({getCurrentFunctionTemplateInstantiation(), E}); ForwardingTemplates.insert(
{getCurrentFunctionTemplateInstantiation(), E});
return true; return true;
} }
} }
@@ -2513,8 +2545,9 @@ public:
return true; return true;
} }
// If we are in a template and the new is type-dependent, register it in ForwardedTemplateLocations // If we are in a template and the new is type-dependent, register it in
// to forward its uses to the surrounding template call site // ForwardedTemplateLocations to forward its uses to the surrounding
// template call site
if (TemplateStack && TemplateStack->inGatherMode()) { if (TemplateStack && TemplateStack->inGatherMode()) {
const auto *TypeInfo = N->getAllocatedTypeSourceInfo(); const auto *TypeInfo = N->getAllocatedTypeSourceInfo();
const auto ConstructExprLoc = TypeInfo->getTypeLoc().getBeginLoc(); const auto ConstructExprLoc = TypeInfo->getTypeLoc().getBeginLoc();
@@ -2544,7 +2577,8 @@ public:
// Also record the dependent NestedNameSpecifier locations // Also record the dependent NestedNameSpecifier locations
for (auto NestedNameLoc = E->getQualifierLoc(); for (auto NestedNameLoc = E->getQualifierLoc();
NestedNameLoc && NestedNameLoc.getNestedNameSpecifier()->isDependent(); NestedNameLoc &&
NestedNameLoc.getNestedNameSpecifier()->isDependent();
NestedNameLoc = NestedNameLoc.getPrefix()) { NestedNameLoc = NestedNameLoc.getPrefix()) {
TemplateStack->visitDependent(NestedNameLoc.getLocalBeginLoc()); TemplateStack->visitDependent(NestedNameLoc.getLocalBeginLoc());
} }
@@ -2575,9 +2609,8 @@ public:
std::string symbol = std::string("URL_") + mangleURL(s); std::string symbol = std::string("URL_") + mangleURL(s);
visitIdentifier("use", "file", StringRef(s), Loc, symbol, visitIdentifier("use", "file", StringRef(s), Loc, symbol, QualType(),
QualType(), Context(), Context(), NotIdentifierToken | LocRangeEndValid);
NotIdentifierToken | LocRangeEndValid);
return true; return true;
} }
@@ -2592,11 +2625,11 @@ public:
std::string symbol = std::string symbol =
std::string("FILE_") + mangleFile(newFile->Realname, type); std::string("FILE_") + mangleFile(newFile->Realname, type);
// We use an explicit zero-length source range at the start of the file. If we // We use an explicit zero-length source range at the start of the file. If
// don't set the LocRangeEndValid flag, the visitIdentifier code will use the // we don't set the LocRangeEndValid flag, the visitIdentifier code will use
// entire first token, which could be e.g. a long multiline-comment. // the entire first token, which could be e.g. a long multiline-comment.
visitIdentifier("def", "file", newFile->Realname, SourceRange(Loc), visitIdentifier("def", "file", newFile->Realname, SourceRange(Loc), symbol,
symbol, QualType(), Context(), QualType(), Context(),
NotIdentifierToken | LocRangeEndValid); NotIdentifierToken | LocRangeEndValid);
} }
@@ -2606,17 +2639,19 @@ public:
if (type == FileType::Unknown) { if (type == FileType::Unknown) {
return; return;
} }
std::string symbol = std::string symbol = std::string("FILE_") + mangleFile(includedFile, type);
std::string("FILE_") + mangleFile(includedFile, type);
// Support the #include MACRO use-case // Support the #include MACRO use-case
// When parsing #include MACRO: // When parsing #include MACRO:
// - the filename is never passed to onTokenLexed // - the filename is never passed to onTokenLexed
// - inclusionDirective is called before endMacroExpansion (which is only called when the following token is parsed) // - inclusionDirective is called before endMacroExpansion (which is only
// So add the filename here and call endMacroExpansion immediately. // called when the following token is parsed) So add the filename here and
// This ensures the macro has a correct expansion and it has been added to MacroMaps so the referenced filename knows to populate inExpansionAt. // call endMacroExpansion immediately. This ensures the macro has a correct
// expansion and it has been added to MacroMaps so the referenced filename
// knows to populate inExpansionAt.
if (MacroExpansionState) { if (MacroExpansionState) {
MacroExpansionState->TokenLocations[FileNameRange.getBegin()] = MacroExpansionState->Expansion.length(); MacroExpansionState->TokenLocations[FileNameRange.getBegin()] =
MacroExpansionState->Expansion.length();
MacroExpansionState->Expansion += '"'; MacroExpansionState->Expansion += '"';
MacroExpansionState->Expansion += includedFile; MacroExpansionState->Expansion += includedFile;
MacroExpansionState->Expansion += '"'; MacroExpansionState->Expansion += '"';
@@ -2640,8 +2675,8 @@ public:
IdentifierInfo *Ident = Tok.getIdentifierInfo(); IdentifierInfo *Ident = Tok.getIdentifierInfo();
if (Ident) { if (Ident) {
std::string Mangled = std::string Mangled = std::string("M_") +
std::string("M_") + mangleLocation(Loc, std::string(Ident->getName())); mangleLocation(Loc, std::string(Ident->getName()));
visitIdentifier("def", "macro", Ident->getName(), Loc, Mangled); visitIdentifier("def", "macro", Ident->getName(), Loc, Mangled);
} }
} }
@@ -2661,13 +2696,14 @@ public:
IdentifierInfo *Ident = Tok.getIdentifierInfo(); IdentifierInfo *Ident = Tok.getIdentifierInfo();
if (Ident) { if (Ident) {
std::string Mangled = std::string Mangled =
std::string("M_") + std::string("M_") + mangleLocation(Macro->getDefinitionLoc(),
mangleLocation(Macro->getDefinitionLoc(), std::string(Ident->getName())); std::string(Ident->getName()));
visitIdentifier("use", "macro", Ident->getName(), Loc, Mangled); visitIdentifier("use", "macro", Ident->getName(), Loc, Mangled);
} }
} }
void beginMacroExpansion(const Token &Tok, const MacroInfo *Macro, SourceRange Range) { void beginMacroExpansion(const Token &Tok, const MacroInfo *Macro,
SourceRange Range) {
if (!Macro) if (!Macro)
return; return;
@@ -2683,12 +2719,19 @@ public:
return; return;
if (MacroExpansionState) { if (MacroExpansionState) {
const auto InMacroArgs = MacroExpansionState->Range.fullyContains(SM.getExpansionRange(Range).getAsRange()); const auto InMacroArgs = MacroExpansionState->Range.fullyContains(
const auto InMacroBody = SM.getExpansionLoc(Tok.getLocation()) == SM.getExpansionLoc(MacroExpansionState->MacroNameToken.getLocation()); SM.getExpansionRange(Range).getAsRange());
const auto InMacroBody =
SM.getExpansionLoc(Tok.getLocation()) ==
SM.getExpansionLoc(MacroExpansionState->MacroNameToken.getLocation());
if (InMacroArgs || InMacroBody) { if (InMacroArgs || InMacroBody) {
if (MacroExpansionState->MacroInfo->getDefinitionLoc() != Macro->getDefinitionLoc()) { if (MacroExpansionState->MacroInfo->getDefinitionLoc() !=
Macro->getDefinitionLoc()) {
IdentifierInfo *DependencyIdent = Tok.getIdentifierInfo(); IdentifierInfo *DependencyIdent = Tok.getIdentifierInfo();
std::string DependencySymbol = std::string("M_") + mangleLocation(Macro->getDefinitionLoc(), std::string(DependencyIdent->getName())); std::string DependencySymbol =
std::string("M_") +
mangleLocation(Macro->getDefinitionLoc(),
std::string(DependencyIdent->getName()));
MacroExpansionState->Dependencies.push_back(DependencySymbol); MacroExpansionState->Dependencies.push_back(DependencySymbol);
} }
@@ -2712,31 +2755,38 @@ public:
} }
void endMacroExpansion() { void endMacroExpansion() {
// large macros are too slow to reformat, don't reformat macros larger than those arbitrary thresholds // large macros are too slow to reformat, don't reformat macros larger than
// those arbitrary thresholds
static constexpr auto includedFileExpansionReformatThreshold = 20'000; static constexpr auto includedFileExpansionReformatThreshold = 20'000;
static constexpr auto mainFileExpansionReformatThreshold = 200'000; static constexpr auto mainFileExpansionReformatThreshold = 200'000;
const auto expansionLocation = SM.getExpansionLoc(MacroExpansionState->MacroNameToken.getLocation()); const auto expansionLocation =
SM.getExpansionLoc(MacroExpansionState->MacroNameToken.getLocation());
const auto expansionFilename = SM.getFilename(expansionLocation); const auto expansionFilename = SM.getFilename(expansionLocation);
const auto includedExtensions = std::array{".h", ".hpp", ".hxx", ".inc", ".def"}; const auto includedExtensions =
const auto isIncludedFile = std::any_of(includedExtensions.begin(), includedExtensions.end(), [&](const auto *extension) { std::array{".h", ".hpp", ".hxx", ".inc", ".def"};
const auto isIncludedFile =
std::any_of(includedExtensions.begin(), includedExtensions.end(),
[&](const auto *extension) {
return expansionFilename.ends_with_insensitive(extension); return expansionFilename.ends_with_insensitive(extension);
}); });
const auto expansionReformatThreshold = isIncludedFile ? includedFileExpansionReformatThreshold : mainFileExpansionReformatThreshold; const auto expansionReformatThreshold =
isIncludedFile ? includedFileExpansionReformatThreshold
: mainFileExpansionReformatThreshold;
if (MacroExpansionState->Expansion.length() < expansionReformatThreshold) { if (MacroExpansionState->Expansion.length() < expansionReformatThreshold) {
// large macros are too memory-hungry to reformat with ColumnLimit != 0 // large macros are too memory-hungry to reformat with ColumnLimit != 0
// see https://github.com/llvm/llvm-project/issues/107434 // see https://github.com/llvm/llvm-project/issues/107434
auto style = clang::format::getMozillaStyle(); auto style = clang::format::getMozillaStyle();
if (MacroExpansionState->Expansion.length() > includedFileExpansionReformatThreshold) if (MacroExpansionState->Expansion.length() >
includedFileExpansionReformatThreshold)
style.ColumnLimit = 0; style.ColumnLimit = 0;
const auto replacements = clang::format::reformat( const auto replacements = clang::format::reformat(
style, style, MacroExpansionState->Expansion,
MacroExpansionState->Expansion, {tooling::Range(0, MacroExpansionState->Expansion.length())});
{tooling::Range(0, MacroExpansionState->Expansion.length())} auto formatted = clang::tooling::applyAllReplacements(
); MacroExpansionState->Expansion, replacements);
auto formatted = clang::tooling::applyAllReplacements(MacroExpansionState->Expansion, replacements);
if (formatted) { if (formatted) {
for (auto &[k, v] : MacroExpansionState->TokenLocations) { for (auto &[k, v] : MacroExpansionState->TokenLocations) {
v = replacements.getShiftedCodePosition(v); v = replacements.getShiftedCodePosition(v);
@@ -2745,15 +2795,18 @@ public:
} }
} }
IdentifierInfo *Ident = MacroExpansionState->MacroNameToken.getIdentifierInfo(); IdentifierInfo *Ident =
MacroExpansionState->MacroNameToken.getIdentifierInfo();
std::string Symbol = std::string Symbol =
std::string("M_") + std::string("M_") +
mangleLocation(MacroExpansionState->MacroInfo->getDefinitionLoc(), std::string(Ident->getName())); mangleLocation(MacroExpansionState->MacroInfo->getDefinitionLoc(),
std::string(Ident->getName()));
const auto dependenciesBegin = MacroExpansionState->Dependencies.begin(); const auto dependenciesBegin = MacroExpansionState->Dependencies.begin();
const auto dependenciesEnd = MacroExpansionState->Dependencies.end(); const auto dependenciesEnd = MacroExpansionState->Dependencies.end();
std::sort(dependenciesBegin, dependenciesEnd); std::sort(dependenciesBegin, dependenciesEnd);
MacroExpansionState->Dependencies.erase(std::unique(dependenciesBegin, dependenciesEnd), dependenciesEnd); MacroExpansionState->Dependencies.erase(
std::unique(dependenciesBegin, dependenciesEnd), dependenciesEnd);
auto Key = Symbol; auto Key = Symbol;
for (const auto &Dependency : MacroExpansionState->Dependencies) { for (const auto &Dependency : MacroExpansionState->Dependencies) {
@@ -2773,7 +2826,8 @@ public:
MacroExpansionState.reset(); MacroExpansionState.reset();
macroUsed(MacroExpansionState->MacroNameToken, MacroExpansionState->MacroInfo); macroUsed(MacroExpansionState->MacroNameToken,
MacroExpansionState->MacroInfo);
} }
void onTokenLexed(const Token &Tok) { void onTokenLexed(const Token &Tok) {
@@ -2787,7 +2841,8 @@ public:
return; return;
} }
if (ConcatInfo.AvoidConcat(MacroExpansionState->PrevPrevTok, MacroExpansionState->PrevTok, Tok)) { if (ConcatInfo.AvoidConcat(MacroExpansionState->PrevPrevTok,
MacroExpansionState->PrevTok, Tok)) {
MacroExpansionState->Expansion += ' '; MacroExpansionState->Expansion += ' ';
} }
@@ -2799,7 +2854,8 @@ public:
} else { } else {
const auto spelling = CI.getPreprocessor().getSpelling(Tok); const auto spelling = CI.getPreprocessor().getSpelling(Tok);
if (Tok.isAnyIdentifier()) { if (Tok.isAnyIdentifier()) {
MacroExpansionState->TokenLocations[SLoc] = MacroExpansionState->Expansion.length(); MacroExpansionState->TokenLocations[SLoc] =
MacroExpansionState->Expansion.length();
} }
MacroExpansionState->Expansion += spelling; MacroExpansionState->Expansion += spelling;
} }
@@ -2826,11 +2882,9 @@ void PreprocessorHook::FileChanged(SourceLocation Loc, FileChangeReason Reason,
} }
} }
void PreprocessorHook::InclusionDirective(SourceLocation HashLoc, void PreprocessorHook::InclusionDirective(
const Token &IncludeTok, SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
StringRef FileName, bool IsAngled, CharSourceRange FileNameRange,
bool IsAngled,
CharSourceRange FileNameRange,
#if CLANG_VERSION_MAJOR >= 16 #if CLANG_VERSION_MAJOR >= 16
OptionalFileEntryRef File, OptionalFileEntryRef File,
#elif CLANG_VERSION_MAJOR >= 15 #elif CLANG_VERSION_MAJOR >= 15
@@ -2838,11 +2892,9 @@ void PreprocessorHook::InclusionDirective(SourceLocation HashLoc,
#else #else
const FileEntry *File, const FileEntry *File,
#endif #endif
StringRef SearchPath, StringRef SearchPath, StringRef RelativePath,
StringRef RelativePath,
#if CLANG_VERSION_MAJOR >= 19 #if CLANG_VERSION_MAJOR >= 19
const Module *SuggestedModule, const Module *SuggestedModule, bool ModuleImported,
bool ModuleImported,
#else #else
const Module *Imported, const Module *Imported,
#endif #endif
@@ -2851,7 +2903,8 @@ void PreprocessorHook::InclusionDirective(SourceLocation HashLoc,
if (!File) { if (!File) {
return; return;
} }
Indexer->inclusionDirective(FileNameRange.getAsRange(), &File->getFileEntry()); Indexer->inclusionDirective(FileNameRange.getAsRange(),
&File->getFileEntry());
#else #else
Indexer->inclusionDirective(FileNameRange.getAsRange(), File); Indexer->inclusionDirective(FileNameRange.getAsRange(), File);
#endif #endif
@@ -2869,8 +2922,7 @@ void PreprocessorHook::MacroExpands(const Token &Tok, const MacroDefinition &Md,
void PreprocessorHook::MacroUndefined(const Token &Tok, void PreprocessorHook::MacroUndefined(const Token &Tok,
const MacroDefinition &Md, const MacroDefinition &Md,
const MacroDirective *Undef) const MacroDirective *Undef) {
{
Indexer->macroUsed(Tok, Md.getMacroInfo()); Indexer->macroUsed(Tok, Md.getMacroInfo());
} }

View File

@@ -37,6 +37,4 @@ std::string hash(const std::string &Str) {
return std::string(HashStr); return std::string(HashStr);
} }
std::string toString(int N) { std::string toString(int N) { return stringFormat("%d", N); }
return stringFormat("%d", N);
}

View File

@@ -7,8 +7,8 @@
#define StringOperations_h #define StringOperations_h
#include <memory> #include <memory>
#include <string>
#include <string.h> #include <string.h>
#include <string>
std::string hash(const std::string &Str); std::string hash(const std::string &Str);