Created
June 29, 2020 19:04
-
-
Save colin-daniels/b94b3d30c164d8f3b2c945028eeeaac9 to your computer and use it in GitHub Desktop.
Remove free/member functions from C++ source code via clang AST manipulation, leaving only types/structs/etc behind, then print the modified source
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING | |
#include <clang/AST/AST.h> | |
#include <clang/AST/ASTConsumer.h> | |
#include <clang/AST/RecursiveASTVisitor.h> | |
#include <clang/Frontend/CompilerInstance.h> | |
#include <clang/Frontend/FrontendAction.h> | |
#include <clang/Tooling/Tooling.h> | |
#undef _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING | |
#include <fstream> | |
#include <utility> | |
using namespace clang; | |
namespace { | |
class RemoveFunctionsConsumer : public ASTConsumer { | |
public: | |
void HandleTranslationUnit(ASTContext &context) override { | |
auto translation_unit = context.getTranslationUnitDecl(); | |
struct Visitor : public RecursiveASTVisitor<Visitor> { | |
static bool VisitFunctionDecl(FunctionDecl *decl) { | |
// remove any free functions (or member functions that have been defined outside the class) | |
decl->getLexicalParent()->removeDecl(decl); | |
return true; | |
} | |
static bool VisitCXXRecordDecl(CXXRecordDecl *decl) { | |
// remove all methods/constructors/etc from a class/struct | |
auto methods = std::vector(decl->method_begin(), decl->method_end()); | |
for (auto method : methods) { | |
decl->removeDecl(method); | |
} | |
return true; | |
} | |
}; | |
Visitor().TraverseDecl(translation_unit); | |
// print the modified translation unit | |
translation_unit->print(llvm::outs()); | |
} | |
}; | |
class RemoveFunctionsAction : public PluginASTAction { | |
protected: | |
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance&, llvm::StringRef) override { | |
return std::make_unique<RemoveFunctionsConsumer>(); | |
} | |
bool ParseArgs(const CompilerInstance &, const std::vector<std::string> &args) override { | |
return true; | |
} | |
}; | |
std::vector<char> read_file_bytes(const char *filename) { | |
std::ifstream infile(filename); | |
infile.seekg(0, std::ios_base::end); | |
auto file_size = static_cast<size_t>(infile.tellg()); | |
infile.seekg(0, std::ios_base::beg); | |
// note: add one to size so code.data() is a null terminated string | |
std::vector<char> code; | |
code.resize(file_size + 1, '\0'); | |
infile.read(code.data(), file_size); | |
return code; | |
} | |
} // namespace | |
int main(int argc, char *argv[]) { | |
if (argc == 2) { | |
auto code = read_file_bytes(argv[1]); | |
auto tool = std::make_unique<RemoveFunctionsAction>(); | |
if (clang::tooling::runToolOnCode(std::move(tool), code.data())) { | |
return 0; | |
} else { | |
return 2; | |
} | |
} else { | |
return 1; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment