JDevlieghere updated this revision to Diff 183584.
JDevlieghere retitled this revision from "[WIP] Tool to insert SBReproducer
macros" to "[Reproducers] Tool to insert SBReproducer macros".
JDevlieghere added a comment.
Fixed printing of booleans; the tool would show `_Bool` instead of `bool`.
I ran this on a few files and it appears to work with the prototype.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D56822/new/
https://reviews.llvm.org/D56822
Files:
tools/CMakeLists.txt
tools/sbrepro/CMakeLists.txt
tools/sbrepro/SBRepro.cpp
Index: tools/sbrepro/SBRepro.cpp
===================================================================
--- /dev/null
+++ tools/sbrepro/SBRepro.cpp
@@ -0,0 +1,249 @@
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Tooling.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+#include <sstream>
+#include <string>
+
+using namespace clang;
+using namespace clang::driver;
+using namespace clang::tooling;
+
+static llvm::cl::OptionCategory ReproCategory("SB Reproducer");
+
+static std::string Join(const std::vector<std::string> &V) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ for (std::size_t I = 0, E = V.size(); I < E; ++I) {
+ OS << V[I];
+ if (I != E - 1)
+ OS << ", ";
+ }
+ return OS.str();
+}
+
+static std::string GetRecordMethodMacroName(bool Static, bool Const,
+ bool NoArgs) {
+ std::string Macro;
+ llvm::raw_string_ostream OS(Macro);
+
+ OS << "SB_RECORD";
+ if (Static)
+ OS << "_STATIC";
+ OS << "_METHOD";
+ if (Const)
+ OS << "_CONST";
+ if (NoArgs)
+ OS << "_NO_ARGS";
+
+ return OS.str();
+}
+
+static std::string GetRegisterMethodMacroName(bool Static, bool Const) {
+ std::string Macro;
+ llvm::raw_string_ostream OS(Macro);
+
+ OS << "SB_REGISTER";
+ if (Static)
+ OS << "_STATIC";
+ OS << "_METHOD";
+ if (Const)
+ OS << "_CONST";
+
+ return OS.str();
+}
+
+static std::string GetRecordMethodMacro(StringRef Result, StringRef Class,
+ StringRef Method, StringRef Signature,
+ StringRef Values, bool Static,
+ bool Const) {
+ std::string Macro;
+ llvm::raw_string_ostream OS(Macro);
+
+ OS << GetRecordMethodMacroName(Static, Const, Values.empty());
+
+ OS << "(" << Result << ", " << Class << ", " << Method;
+
+ if (!Values.empty()) {
+ OS << ", (" << Signature << "), " << Values << ");\n";
+ } else {
+ OS << ");\n";
+ }
+
+ return OS.str();
+}
+
+static std::string GetRecordConstructorMacro(StringRef Class,
+ StringRef Signature,
+ StringRef Values) {
+ std::string Macro;
+ llvm::raw_string_ostream OS(Macro);
+ if (!Values.empty()) {
+ OS << "SB_RECORD_CONSTRUCTOR(" << Class << ", (" << Signature << "), "
+ << Values << ");\n";
+ } else {
+ OS << "SB_RECORD_CONSTRUCTOR_NO_ARGS(" << Class << ");\n";
+ }
+ return OS.str();
+}
+
+static std::string GetRegisterConstructorMacroMacro(StringRef Class,
+ StringRef Signature) {
+ std::string Macro;
+ llvm::raw_string_ostream OS(Macro);
+ OS << "SB_REGISTER_CONSTRUCTOR(" << Class << ", (" << Signature << "));\n";
+ return OS.str();
+}
+
+static std::string GetRegisterMethodMacro(StringRef Result, StringRef Class,
+ StringRef Method, StringRef Signature,
+ bool Static, bool Const) {
+ std::string Macro;
+ llvm::raw_string_ostream OS(Macro);
+ OS << GetRegisterMethodMacroName(Static, Const);
+ OS << "(" << Result << ", " << Class << ", " << Method << ", (" << Signature
+ << "));\n";
+ return OS.str();
+}
+
+class SBVisitor : public RecursiveASTVisitor<SBVisitor> {
+public:
+ SBVisitor(Rewriter &R, ASTContext &Context)
+ : MyRewriter(R), Context(Context) {}
+
+ bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {
+ SourceManager &SM = MyRewriter.getSourceMgr();
+
+ // We don't want to modify anything outside the main file.
+ if (!SM.isInMainFile(Decl->getBeginLoc()))
+ return false;
+
+ Stmt *Body = Decl->getBody();
+ if (!Body)
+ return false;
+
+ bool IsConstructor = dyn_cast<CXXConstructorDecl>(Decl) != nullptr;
+ bool IsDestructor = dyn_cast<CXXDestructorDecl>(Decl) != nullptr;
+
+ // Do nothing for private decls.
+ AccessSpecifier AS = Decl->getAccess();
+ if (AS != AccessSpecifier::AS_public)
+ return false;
+
+ // Do nothing for destructor.
+ if (IsDestructor)
+ return false;
+
+ // Print 'bool' instead of '_Bool'.
+ PrintingPolicy Policy(Context.getLangOpts());
+ Policy.Bool = true;
+
+ CXXRecordDecl *Record = Decl->getParent();
+ QualType ReturnType = Decl->getReturnType();
+
+ std::vector<std::string> ParamTypes;
+ std::vector<std::string> ParamNames;
+ for (auto *P : Decl->parameters()) {
+ QualType T = P->getType();
+
+ // Currently we don't support functions that have function pointers as an
+ // argument.
+ if (T->isFunctionPointerType())
+ return false;
+
+ // Currently we don't support functions that have void pointers as an
+ // argument.
+ if (T->isVoidPointerType())
+ return false;
+
+ ParamTypes.push_back(T.getAsString(Policy));
+ ParamNames.push_back(P->getNameAsString());
+ }
+
+ std::string Macro;
+
+ if (IsConstructor) {
+ llvm::outs() << GetRegisterConstructorMacroMacro(
+ Record->getNameAsString(), Join(ParamTypes));
+
+ Macro = GetRecordConstructorMacro(Record->getNameAsString(),
+ Join(ParamTypes), Join(ParamNames));
+ } else {
+ llvm::outs() << GetRegisterMethodMacro(
+ ReturnType.getAsString(Policy), Record->getNameAsString(),
+ Decl->getNameAsString(), Join(ParamTypes), Decl->isStatic(),
+ Decl->isConst());
+
+ Macro = GetRecordMethodMacro(
+ ReturnType.getAsString(Policy), Record->getNameAsString(),
+ Decl->getNameAsString(), Join(ParamTypes), Join(ParamNames),
+ Decl->isStatic(), Decl->isConst());
+ }
+
+ // If this CXXMethodDecl already starts with a macro we're done.
+ for (auto &C : Body->children()) {
+ if (C->getBeginLoc().isMacroID())
+ return false;
+ }
+
+ // Insert the macro at the beginning of the function.
+ SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
+ Body->getBeginLoc(), 0, SM, MyRewriter.getLangOpts());
+ MyRewriter.InsertTextAfter(InsertLoc, Macro);
+
+ return true;
+ }
+
+private:
+ Rewriter &MyRewriter;
+ ASTContext &Context;
+};
+
+// Implementation of the ASTConsumer interface for reading an AST produced
+// by the Clang parser.
+class SBConsumer : public ASTConsumer {
+public:
+ SBConsumer(Rewriter &R, ASTContext &Context) : Visitor(R, Context) {}
+
+ // Override the method that gets called for each parsed top-level
+ // declaration.
+ bool HandleTopLevelDecl(DeclGroupRef DR) override {
+ for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
+ Visitor.TraverseDecl(*b);
+ }
+ return true;
+ }
+
+private:
+ SBVisitor Visitor;
+};
+
+class SBAction : public ASTFrontendAction {
+public:
+ SBAction() = default;
+
+ void EndSourceFileAction() override { MyRewriter.overwriteChangedFiles(); }
+
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef file) override {
+ MyRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
+ return llvm::make_unique<SBConsumer>(MyRewriter, CI.getASTContext());
+ }
+
+private:
+ Rewriter MyRewriter;
+};
+
+int main(int argc, const char **argv) {
+ CommonOptionsParser OP(argc, argv, ReproCategory);
+ ClangTool T(OP.getCompilations(), OP.getSourcePathList());
+ return T.run(newFrontendActionFactory<SBAction>().get());
+}
Index: tools/sbrepro/CMakeLists.txt
===================================================================
--- /dev/null
+++ tools/sbrepro/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_lldb_tool(sbrepro
+ SBRepro.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ clangFrontend
+ clangTooling
+
+ LINK_COMPONENTS
+ Support
+ )
Index: tools/CMakeLists.txt
===================================================================
--- tools/CMakeLists.txt
+++ tools/CMakeLists.txt
@@ -4,6 +4,7 @@
add_subdirectory(lldb-mi)
add_subdirectory(lldb-test)
add_subdirectory(lldb-vscode)
+add_subdirectory(sbrepro)
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
add_subdirectory(darwin-debug)
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits