Better_Software_Header_MobileBetter_Software_Header_Web

Find what you need - explore our website and developer resources

Can't the Compiler Do That?

Customized C/C++ Tooling with Clang LibTooling

git clone https://github.com/llvm/llvm-project.git
cd llvm-project
mkdir build; cd build
cmake -G Ninja ../llvm -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DLLVM_BUILD_TESTS=ON  # Enable tests; default is off.
ninja
ninja check       # Test LLVM only.
ninja clang-test  # Test Clang only.
ninja install
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"

using namespace clang::tooling;
using namespace llvm;

int main(int argc, const char **argv) {
  CommonOptionsParser optionsParser(argc, argv,
    llvm::cl::GeneralCategory
  );
  ClangTool tool(optionsParser.getCompilations(),
                 optionsParser.getSourcePathList());

  return tool.run(
    newFrontendActionFactory<clang::SyntaxOnlyAction>().get()
  );
}
cmake_minimum_required(VERSION 3.11)
project(kdab-supercede-stdpow-checker)

find_package(Clang REQUIRED)

add_executable(kdab-supercede-stdpow-checker
    kdab-supercede-stdpow-checker.cpp)
target_link_libraries(kdab-supercede-stdpow-checker
    clang-cpp LLVMCore LLVMSupport)

install(TARGETS kdab-supercede-stdpow-checker
    RUNTIME DESTINATION bin)
$ cd /path/to/kdab-supercede-stdpow-checker
$ mkdir build; cd build
$ cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/usr ..
$ ninja
$ sudo ninja install
$ cd /path/to/our/embedded/project
$ kdab-supercede-stdpow-checker -p build/dir fileToCheck.cpp
auto drawMatcher
    = functionDecl(hasName("draw"), returns(voidType()));
void draw();

void MyWidget::draw(WidgetPainter *p) {
    p->drawRectangle();
}
auto m =
  callExpr(hasArgument(1, integerLiteral().bind("secondArg")));
$ clang-query -p build main.cpp
clang-query> enable output detailed-ast
clang-query> match  callExpr(callee(functionDecl(hasName("pow"), isInStdNamespace())), hasArgument(1, expr()))

Match #1:

/path/to/ClangToolingTestApp/main.cpp:27:14: note: "root" binds here
    auto x = std::pow(pi, getExp(pi));
                             ^~~~~~~~~~~~~~~~~~~~~~~~
Binding for "root":
CallExpr
|-ImplicitCastExpr <FunctionToPointerDecay>
| `-DeclRefExpr Function 'pow'  (FunctionTemplate 'pow')
|-ImplicitCastExpr 'double' <LValueToRValue>
| `-DeclRefExpr 'const double' lvalue Var 'pi'
`-CallExpr 'int'
 |-ImplicitCastExpr <FunctionToPointerDecay>
 | `-DeclRefExpr 'int (double)' lvalue Function 'getExp'
 `-ImplicitCastExpr 'double' <LValueToRValue>
   `-DeclRefExpr 'const double' lvalue Var 'pi'

1 match.
clang-query> quit
callExpr(
    callee(
        functionDecl(hasName("pow"), isInStdNamespace())
          .bind("callee")
    ),
    hasArgument(0, expr().bind("base")),
    hasArgument(1, expr().bind("exponent"))
).bind("funcCall");
class StdPowChecker : public MatchFinder::MatchCallback {
public :
    StdPowChecker() = default;

    void run(const MatchFinder::MatchResult &result) override {}
};

class SupercedeStdPowAction : public FixItAction {
public:
    SupercedeStdPowAction() {
        m_finder.addMatcher(stdPowMatcher, &m_stdPowChecker);
    }

    std::unique_ptr<ASTConsumer>
    CreateASTConsumer(CompilerInstance &, StringRef) override {
        return m_finder.newASTConsumer();
    }

public:
    MatchFinder m_finder;
    StdPowChecker m_stdPowChecker;
};https://www.kdab.com/cpp-with-clang-libtooling/

int main(int argc, const char **argv) {
  // [...]

  return tool.run(
      newFrontendActionFactory<SupercedeStdPowAction>().get()
  );
}
const CallExpr *callExpr
    = result.Nodes.getNodeAs<CallExpr>("funcCall");
const FunctionDecl *callee
    = result.Nodes.getNodeAs<FunctionDecl>("callee");
const Expr *base = result.Nodes.getNodeAs<Expr>("base");
const Expr *exponent = result.Nodes.getNodeAs<Expr>("exponent");
auto &diagEngine = result->Context->getDiagnostics();
unsigned ID = diagEngine.getDiagnosticIDs()->getCustomDiagID(
    DiagnosticIDs::Warning,
    "std::pow is called with integer constant expression. "
    "Use utils::pow instead.");
diagEngine.Report(exponent->getBeginLoc(), ID);
auto &sm = result->Context->getSourceManager();
auto &lo = result->Context->getLangOpts();
auto baseRng
    = Lexer::getAsCharRange(base->getSourceRange(), sm, lo);
auto expRng
    = Lexer::getAsCharRange(exponent->getSourceRange(), sm, lo);
auto callRng
    = Lexer::getAsCharRange(callExpr->getSourceRange(), sm, lo);

auto baseStr = Lexer::getSourceText(baseRng, sm, lo);
auto expStr = Lexer::getSourceText(callRng, sm, lo);
diagEngine.Report(exponent->getBeginLoc(), ID)
  << FixItHint::CreateReplacement(callRng,
     (llvm::Twine("utils::pow<") + expStr + ">(" + baseStr + ")"
     ).str());
#include <iostream>
#include <cmath>
#include "utils.h"

#define DIM 2
constexpr int getExp(double x) {
    return static_cast<int>(x);
}

namespace StdLib = std;
using namespace std;

int main() {
  constexpr double pi = 3.141596;

  std::cout << "(2Pi)^2 = " << std::pow(2*pi, DIM) << endl;
  std::cout << "Pi^3 = " << StdLib::pow(pi, getExp(pi)) << endl;
}
$ cd /path/to/ClangToolingTestApp/build
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
$ cd ..
$ kdab-supercede-stdpow-checker -p build main.cpp -- -std=c++17

main.cpp:16:49: warning: std::pow is called with integer constant expression. Use utils::pow instead.
   std::cout << "(2Pi)^2 = " << std::pow(2*pi, DIM) << endl;
                                ~~~~~~~~~~~~~~~^~~~
                                utils::pow<DIM>(2*pi)
main.cpp:16:49: note: FIX-IT applied suggested code changes

main.cpp:17:47: warning: std::pow is called with integer constant expression. Use utils::pow instead.
   std::cout << "Pi^3 =" << StdLib::pow(pi, getExp(pi)) << endl;
                            ~~~~~~~~~~~~~~~~^~~~~~~~~~~
                            utils::pow<getExp(pi)>(pi)
main.cpp:17:47: note: FIX-IT applied suggested code changes
2 warnings generated.

Do you need similar support?

Contact Us

About KDAB


01_NoPhoto

Kevin Funk

former KDAB employee

AntonKreuzkamp

Anton Kreuzkamp

Software Engineer

Learn Modern C++

Learn more