diff --git a/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp b/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp index 17c1407f71b..9eed06ddc8f 100644 --- a/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp +++ b/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include template @@ -258,4 +259,65 @@ void LibJSGCASTConsumer::HandleTranslationUnit(clang::ASTContext& context) visitor.TraverseDecl(context.getTranslationUnitDecl()); } +char const* LibJSCellMacro::type_name(Type type) +{ + switch (type) { + case Type::JSCell: + return "JS_CELL"; + case Type::JSObject: + return "JS_OBJECT"; + case Type::JSEnvironment: + return "JS_ENVIRONMENT"; + case Type::JSPrototypeObject: + return "JS_PROTOTYPE_OBJECT"; + case Type::WebPlatformObject: + return "WEB_PLATFORM_OBJECT"; + default: + __builtin_unreachable(); + } +} + +void LibJSPPCallbacks::LexedFileChanged(clang::FileID curr_fid, LexedFileChangeReason reason, clang::SrcMgr::CharacteristicKind, clang::FileID, clang::SourceLocation) +{ + if (reason == LexedFileChangeReason::EnterFile) { + m_curr_fid_hash_stack.push_back(curr_fid.getHashValue()); + } else { + assert(!m_curr_fid_hash_stack.empty()); + m_curr_fid_hash_stack.pop_back(); + } +} + +void LibJSPPCallbacks::MacroExpands(clang::Token const& name_token, clang::MacroDefinition const&, clang::SourceRange range, clang::MacroArgs const* args) +{ + if (auto* ident_info = name_token.getIdentifierInfo()) { + static llvm::StringMap libjs_macro_types { + { "JS_CELL", LibJSCellMacro::Type::JSCell }, + { "JS_OBJECT", LibJSCellMacro::Type::JSObject }, + { "JS_ENVIRONMENT", LibJSCellMacro::Type::JSEnvironment }, + { "JS_PROTOTYPE_OBJECT", LibJSCellMacro::Type::JSPrototypeObject }, + { "WEB_PLATFORM_OBJECT", LibJSCellMacro::Type::WebPlatformObject }, + }; + + auto name = ident_info->getName(); + if (auto it = libjs_macro_types.find(name); it != libjs_macro_types.end()) { + LibJSCellMacro macro { range, it->second, {} }; + + for (size_t arg_index = 0; arg_index < args->getNumMacroArguments(); arg_index++) { + auto const* first_token = args->getUnexpArgument(arg_index); + auto stringified_token = clang::MacroArgs::StringifyArgument(first_token, m_preprocessor, false, range.getBegin(), range.getEnd()); + // The token includes leading and trailing quotes + auto len = strlen(stringified_token.getLiteralData()); + std::string arg_text { stringified_token.getLiteralData() + 1, len - 2 }; + macro.args.push_back({ arg_text, first_token->getLocation() }); + } + + assert(!m_curr_fid_hash_stack.empty()); + auto curr_fid_hash = m_curr_fid_hash_stack.back(); + if (m_macro_map.find(curr_fid_hash) == m_macro_map.end()) + m_macro_map[curr_fid_hash] = {}; + m_macro_map[curr_fid_hash].push_back(macro); + } + } +} + static clang::FrontendPluginRegistry::Add X("libjs_gc_scanner", "analyze LibJS GC usage"); diff --git a/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.h b/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.h index 0a7b6a62a2d..71e80cc3b39 100644 --- a/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.h +++ b/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.h @@ -10,6 +10,47 @@ #include #include +struct LibJSCellMacro { + enum class Type { + JSCell, + JSObject, + JSEnvironment, + JSPrototypeObject, + WebPlatformObject, + }; + + struct Arg { + std::string text; + clang::SourceLocation location; + }; + + clang::SourceRange range; + Type type; + std::vector args; + + static char const* type_name(Type); +}; + +using LibJSCellMacroMap = std::unordered_map>; + +class LibJSPPCallbacks : public clang::PPCallbacks { +public: + LibJSPPCallbacks(clang::Preprocessor& preprocessor, LibJSCellMacroMap& macro_map) + : m_preprocessor(preprocessor) + , m_macro_map(macro_map) + { + } + + virtual void LexedFileChanged(clang::FileID curr_fid, LexedFileChangeReason, clang::SrcMgr::CharacteristicKind, clang::FileID, clang::SourceLocation) override; + + virtual void MacroExpands(clang::Token const& name_token, clang::MacroDefinition const& definition, clang::SourceRange range, clang::MacroArgs const* args) override; + +private: + clang::Preprocessor& m_preprocessor; + std::vector m_curr_fid_hash_stack; + LibJSCellMacroMap& m_macro_map; +}; + class LibJSGCVisitor : public clang::RecursiveASTVisitor { public: explicit LibJSGCVisitor(clang::ASTContext& context)