Skip to content

Commit

Permalink
fixhalapi.cpp
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Haberler committed Sep 1, 2014
1 parent bcfd07f commit d76bbfd
Showing 1 changed file with 161 additions and 0 deletions.
161 changes: 161 additions & 0 deletions src_clang/fixhalapi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// basically mpass.cpp/hal_export_funct fixup, but using the Refactoring/Replacements API

#include <iostream>

#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"

#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Signals.h"

using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::tooling;
using namespace llvm;

typedef std::map<std::string, const FunctionDecl *> halExportsMap;
halExportsMap halexportfuncs; // hal_export_funct's discovered

// first pass matcher: collect all calls to hal_export_funct()
// and identify the exported function
//
// match sample: " hal_export_funct("name", efunct, 0, 0,0,42);"
//
// bind "declref" to the efunct DeclRefExpr:
static StatementMatcher halExportFunctMatcher =
callExpr(callee(functionDecl(hasName("hal_export_funct"))),
hasArgument(1, declRefExpr().bind("declref")));

class MatchHelper : public MatchFinder::MatchCallback
{
public:
virtual void run(const MatchFinder::MatchResult &result)
{
ASTContext *Context = result.Context;
if (const DeclRefExpr *dr = result.Nodes.getNodeAs<DeclRefExpr>("declref")) {

// skip includes
if (!Context->getSourceManager().isInMainFile(dr->getLocStart()))
return;

// access the function declaration
if (const FunctionDecl *fd = dyn_cast<FunctionDecl>(dr->getDecl())) {
printOut(result, fd,
"detect hal_export_funct() of: " + fd->getNameInfo().getAsString());

// and remember it for the rewrite pass
halexportfuncs[fd->getNameInfo().getAsString()] = fd;
}
}
}

private:
void printOut(const MatchFinder::MatchResult &result,
const FunctionDecl *fd,
const std::string message) const
{
FullSourceLoc fullLoc(fd->getLocStart(), *result.SourceManager);
const std::string &fileName = result.SourceManager->getFilename(fullLoc);
const unsigned int lineNum = fullLoc.getSpellingLineNumber();
std::cerr << fileName << ":" << lineNum << ": " << message << '\n';
}
};

// second pass matcher: visit all function declarations
static DeclarationMatcher declMatcher = functionDecl().bind("fdecl");

class ToolTemplateCallback : public MatchFinder::MatchCallback {
public:
ToolTemplateCallback(Replacements *Replace) : Replace(Replace) {}

// second pass:
void run(const MatchFinder::MatchResult &result) override {

if (const FunctionDecl *f = result.Nodes.getNodeAs<FunctionDecl>("fdecl")) {
DeclarationName DeclName = f->getNameInfo().getName();
std::string FuncName = DeclName.getAsString();

if (halexportfuncs.count(FuncName)) { // a thread function

// rewrite second argument name and type
const ParmVarDecl *p2 = f->getParamDecl(1);
std::string ParamName = p2->getName();

Replace->insert(Replacement(*result.SourceManager, p2,
"const struct threadargs * ta"));

if (f->doesThisDeclarationHaveABody()) {
// inject previous second param before the first statement,
// reusing the name in the param decl
CompoundStmt *CS = dyn_cast<CompoundStmt>(f->getBody());

// loop over Stmt's, inject code before the first one:
for (CompoundStmt::body_iterator I = CS->body_begin(),
E = CS->body_end(); I != E; ++I) {
if (I == CS->body_begin()) {
Stmt *s = (*I);
// the 4 spaces reindent is a hack,
// but Replacement doesnt have an indent param
Replace->insert(Replacement(*result.SourceManager,
s->getLocStart(),0,
"long " + ParamName +
" = ta->_period;\n "));
}
}
}
}
}
}
private:
Replacements *Replace;
};

// Set up the command line options
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::OptionCategory ToolTemplateCategory("tool-template options");

int main(int argc, const char **argv)
{
llvm::sys::PrintStackTraceOnErrorSignal();

CommonOptionsParser op(argc, argv, ToolTemplateCategory);

ClangTool collect(op.getCompilations(), op.getSourcePathList());

// first pass - collect thread functions exported by hal_export_funct()
MatchHelper helper;
MatchFinder finder;
finder.addMatcher(halExportFunctMatcher, &helper);
int rc = collect.run(newFrontendActionFactory(&finder).get());

if (halexportfuncs.size()) { // candidates found

// second pass - fixup function decls
RefactoringTool fixup(op.getCompilations(), op.getSourcePathList());
ast_matchers::MatchFinder Finder;
ToolTemplateCallback Callback(&fixup.getReplacements());
Finder.addMatcher(declMatcher, &Callback);

// int result = Tool.run(newFrontendActionFactory(&Finder).get());

// overwrites refactored files!
int result = fixup.runAndSave(newFrontendActionFactory(&Finder).get());

llvm::outs() << "Replacements:\n";
for (auto &r : fixup.getReplacements()) {
llvm::outs() << r.toString() << "\n";
}
}
return 0;

}

0 comments on commit d76bbfd

Please sign in to comment.