I have a clang matcher on a FunctionDecl node to get its return type and it also matches first argument depending on the situation.
I have a class file Instrumentizer, creating the matcher and calling the callback:
#include <string>
#include <vector>
#include "clang/Tooling/Tooling.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "InstrumentizerMatchers.hpp"
using namespace clang::ast_matchers;
static llvm::cl::OptionCategory InstrumentizerAPICategory("");
class Instrumentizer {
public:
Instrumentizer(std::string source) {
this->source_file = source;
const char* argv[] = {
"instrumentizer",
source.c_str(),
"--"
};
int argc = 3;
options = new CommonOptionsParser(argc, argv, InstrumentizerAPICategory);
auto files = options->getSourcePathList();
tool = new RefactoringTool(options->getCompilations(), files);
this->Callback = new InstrumentizerCallback();
}
~Instrumentizer();
// Config
void addTypeToMatch(std::string regex){
// Base matcher
TypeMatcher NaiveTypeMatcher = instrumentizer_matchers::asUnqualifiedType(asString(regex));
// Typeloc matcher
auto NaiveTypeLocMatcher = typeLoc(loc(NaiveTypeMatcher)).bind("type");
// Checks if current node or its descendants have a float type (to detect arrays and pointers)
// Also has a typeLoc variant
TypeMatcher TypeMatcher = anyOf(hasDescendant(NaiveTypeMatcher), NaiveTypeMatcher);
auto TypeLocMatcher = anyOf(hasDescendant(NaiveTypeLocMatcher), NaiveTypeLocMatcher);
// Matches a function return type
auto FunctionReturnMatcher = functionDecl(hasTypeLoc(TypeLocMatcher)).bind("floating_function");
Matcher.addMatcher(FunctionReturnMatcher, Callback);
}
// Get infos
std::vector<variable_t>& getVariables() {
// If it has not been done yet, run the tool with
// callbacks that will obtain and save variable names/types
std::cout << "in getVariables()" << std::endl;
if(variables.size() == 0) {
tool->run(newFrontendActionFactory(&Matcher).get());
}
return variables;
}
private:
// source file
std::string source_file;
// Store all the variables and types
std::vector<variable_t> variables;
clang::tooling::CommonOptionsParser *options;
// Underlying tool used to analyse the code
// It will also be used to apply the replacements for us
clang::tooling::RefactoringTool *tool;
// Matcher to be ran on the AST
MatchFinder Matcher;
InstrumentizerCallback *Callback;
};
The callback is defined here, with its run function:
#pragma once
#include <string>
#include <sstream>
#include <cstring>
#include <iostream>
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::tooling;
using namespace clang::ast_matchers;
using namespace clang::ast_matchers::internal;
extern "C" {
typedef struct {
size_t type_idx; // index into the type list
char* name; // name of the variable/function
} variable_t;
} // extern C
namespace instrumentizer_matchers {
// Matches if Name is contained in the string description of the qualType
AST_MATCHER_P(clang::QualType, inString, std::string, Name) {
return Node.getAsString().find(Name, Node.getAsString().length() - Name.length()) != -1;
}
// Matches if the type without Qualifiers matches
AST_MATCHER_P(clang::QualType, asUnqualifiedType, Matcher<clang::QualType>, InnerMatcher) {
return InnerMatcher.matches(Node.getLocalUnqualifiedType(), Finder, Builder);
}
}
class InstrumentizerCallback : public MatchFinder::MatchCallback {
public:
InstrumentizerCallback(){}
~InstrumentizerCallback(){}
virtual void run(const MatchFinder::MatchResult &Result) {
auto SM = Result.SourceManager;
// Handle function return types
auto func_decl = Result.Nodes.getNodeAs<clang::FunctionDecl>("floating_function");
if (func_decl) {
auto beginLoc = func_decl->getBeginLoc();
std::cout << "beginLoc: " << beginLoc.printToString(*SM) << std::endl;
std::cout << "name: " << func_decl->getNameAsString() << std::endl;
auto type = Result.Nodes.getNodeAs<clang::TypeLoc>("type");
std::cout << "position: " << type->getSourceRange().printToString(*SM) << std::endl;
return;
}
}
};
The if (func_decl) and the couts inside are expected to happen when a function declaration is matched.
I use a main file:
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Tooling/Refactoring.h"
#include "FloatingTypeFindingAction.h"
#include "Instrumentizer_class.cpp"
using namespace llvm;
using namespace clang::tooling;
int main(int argc, const char **argv) {
Instrumentizer* inst = new Instrumentizer("test.cc");
inst->addTypeToMatch("double");
inst->addTypeToMatch("test");
std::vector<variable_t> var = inst->getVariables();
}
to apply my Instrumentizer object on the test.cc file:
typedef double test;
double fun(test x){
return x;
}
int main(int argc, char **argv) {
return 0;
}
when inside getVariables(), the callback matches both the double and test types, and I just want the double in this case.
beginLoc: /local/ferro/testestestestestestestestest/src/../api/test.cc:3:1
name: fun
position: </local/ferro/testestestestestestestestest/src/../api/test.cc:3:1>
beginLoc: /local/ferro/testestestestestestestestest/src/../api/test.cc:3:1
name: fun
position: </local/ferro/testestestestestestestestest/src/../api/test.cc:3:12>