Skip to content

Instantly share code, notes, and snippets.

@colin-daniels
Created June 29, 2020 19:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save colin-daniels/b94b3d30c164d8f3b2c945028eeeaac9 to your computer and use it in GitHub Desktop.
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
#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