Переглянути джерело

ClangPlugin: Add a PPCallbacks instance to collect JS_CELL-like macros

Matthew Olsson 1 рік тому
батько
коміт
54fffef902

+ 62 - 0
Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp

@@ -10,6 +10,7 @@
 #include <clang/Basic/SourceManager.h>
 #include <clang/Basic/SourceManager.h>
 #include <clang/Frontend/CompilerInstance.h>
 #include <clang/Frontend/CompilerInstance.h>
 #include <clang/Frontend/FrontendPluginRegistry.h>
 #include <clang/Frontend/FrontendPluginRegistry.h>
+#include <clang/Lex/MacroArgs.h>
 #include <unordered_set>
 #include <unordered_set>
 
 
 template<typename T>
 template<typename T>
@@ -258,4 +259,65 @@ void LibJSGCASTConsumer::HandleTranslationUnit(clang::ASTContext& context)
     visitor.TraverseDecl(context.getTranslationUnitDecl());
     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<LibJSCellMacro::Type> 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<LibJSGCPluginAction> X("libjs_gc_scanner", "analyze LibJS GC usage");
 static clang::FrontendPluginRegistry::Add<LibJSGCPluginAction> X("libjs_gc_scanner", "analyze LibJS GC usage");

+ 41 - 0
Meta/Lagom/ClangPlugins/LibJSGCPluginAction.h

@@ -10,6 +10,47 @@
 #include <clang/AST/RecursiveASTVisitor.h>
 #include <clang/AST/RecursiveASTVisitor.h>
 #include <clang/Frontend/FrontendAction.h>
 #include <clang/Frontend/FrontendAction.h>
 
 
+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<Arg> args;
+
+    static char const* type_name(Type);
+};
+
+using LibJSCellMacroMap = std::unordered_map<unsigned int, std::vector<LibJSCellMacro>>;
+
+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<unsigned int> m_curr_fid_hash_stack;
+    LibJSCellMacroMap& m_macro_map;
+};
+
 class LibJSGCVisitor : public clang::RecursiveASTVisitor<LibJSGCVisitor> {
 class LibJSGCVisitor : public clang::RecursiveASTVisitor<LibJSGCVisitor> {
 public:
 public:
     explicit LibJSGCVisitor(clang::ASTContext& context)
     explicit LibJSGCVisitor(clang::ASTContext& context)