Skip to content
On this page

Core Classes

Decl 声明系列

  • CXXRecordDecl 类,struct
  • VarDecl
  • UnresolvedUsingTypenameDecl
cpp
 template \  class A : public Base  {
   using typename Base ::foo;
 };

Stmt

  • CompoundStmt
  • CXXTryStmt
  • BinaryOperator

Type

  • PointerType
  • ParentType
  • SubstTemplateTypeParmType

Glue Classes

  • DeclContext

  • TemplateArgument

  • NestedNameSpecifier

  • QualType Qualifier

    • 比如const int x中的const
  • IfStmt: getThen,getElse,getCond

  • CXXRecordDecl:

    • getDescribedClassTemplate
  • Type: getAsCXXRecordDecl

Type 也很复杂

cpp
int x;
const int x;
int * const * x;

Location

SourceLocation 只有一个ID字段,因为真正的Location是被SourceManager管理的,避免重复.

Call Expressions

image-20230408201217925

image-20230408201754187

image-20230408201816172

image-20230408201911064

PointerTypeLoc返回的是int*的loc

PointerTypeLoc.getPointeeLoc返回的是int的loc

loc to Text?

  • makeFileCharRange
  • measureTokenLength

Template tree transformations

说的就是c++中的模板

  • Nodes are shared 这点很关键

RecuisiveASTVisitor

  • Trigger on Types you are care about
  • Knows all the connections
  • Does not give you context information

AST Matcher

  • Trigger on Expressions
  • Bind Context
  • Get all context inside a callback

dump ast:

bash
clang-check ClangTidyToolMain.cpp  --ast-dump

即使编译不过去,也可以生成ast的,只要语法正确.

比如: 注释了iostream,cstdlib,vector,编译是肯定会失败的.

cpp
//===--- tools/extra/clang-tidy/ClangTidyToolMain.cpp - Clang tidy tool ---===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
///  \file This file contains clang-tidy tool entry point main function.
///
///  This tool uses the Clang Tooling infrastructure, see
///    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
///  for details on setting it up with LLVM source tree.
///
//===----------------------------------------------------------------------===//

#include "ClangTidyMainxx.h"
//#include <iostream>
//#include <cstdlib>
//#include <vector>

extern char **environ; // 引入全局变量environ
using namespace std;

static void testPrintEnv() {
    char **env = environ; // 将environ保存到env指针中
    vector <string> envs;
    while (*env != nullptr) { // 遍历环境变量
//        std::cout << *env << std::endl; // 打印环境变量
        envs.push_back(*env);
        env++; // 移动指针
    }
    std::sort(envs.begin(), envs.end());
    for (auto &env: envs) {
        std::cout << env << std::endl;
    }
}

int main(int argc, const char **argv) {
    testPrintEnv();
    return clang::tidy::clangTidyMain(argc, argv);
}
ast
TranslationUnitDecl 0x7fc67184a808 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x7fc67184b070 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x7fc67184add0 '__int128'
|-TypedefDecl 0x7fc67184b0e0 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x7fc67184adf0 'unsigned __int128'
|-TypedefDecl 0x7fc67184b458 <<invalid sloc>> <invalid sloc> implicit __NSConstantString '__NSConstantString_tag'
| `-RecordType 0x7fc67184b1d0 '__NSConstantString_tag'
|   `-CXXRecord 0x7fc67184b138 '__NSConstantString_tag'
|-TypedefDecl 0x7fc67184b4f0 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x7fc67184b4b0 'char *'
|   `-BuiltinType 0x7fc67184a8b0 'char'
|-TypedefDecl 0x7fc67188be58 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag[1]'
| `-ConstantArrayType 0x7fc67188be00 '__va_list_tag[1]' 1 
|   `-RecordType 0x7fc67184b5e0 '__va_list_tag'
|     `-CXXRecord 0x7fc67184b548 '__va_list_tag'
|-VarDecl 0x7fc67188bf20 </Volumes/dev/tmp/clang-tidy-standalone/tool/ClangTidyToolMain.cpp:22:1, col:15> col:15 used environ 'char **' extern
|-UsingDirectiveDecl 0x7fc67188c040 <line:23:1, col:17> col:17 Namespace 0x7fc67188bfd0 'std'
|-FunctionDecl 0x7fc67188c0e8 <line:25:1, line:37:1> line:25:13 used testPrintEnv 'void ()' static
| `-CompoundStmt 0x7fc67188c5b0 <col:28, line:37:1>
|   |-DeclStmt 0x7fc67188c240 <line:26:5, col:25>
|   | `-VarDecl 0x7fc67188c1a0 <col:5, col:18> col:12 used env 'char **' cinit
|   |   `-ImplicitCastExpr 0x7fc67188c228 <col:18> 'char **' <LValueToRValue>
|   |     `-DeclRefExpr 0x7fc67188c208 <col:18> 'char **' lvalue Var 0x7fc67188bf20 'environ' 'char **'
|   |-DeclStmt 0x7fc67188c2f8 <line:27:5, col:25>
|   | `-VarDecl 0x7fc67188c290 <col:5, col:21> col:21 invalid envs 'int'
|   `-WhileStmt 0x7fc67188c460 <line:28:5, line:32:5>
|     |-BinaryOperator 0x7fc67188c3a0 <line:28:12, col:20> 'bool' '!='
|     | |-ImplicitCastExpr 0x7fc67188c370 <col:12, col:13> 'char *' <LValueToRValue>
|     | | `-UnaryOperator 0x7fc67188c348 <col:12, col:13> 'char *' lvalue prefix '*' cannot overflow
|     | |   `-ImplicitCastExpr 0x7fc67188c330 <col:13> 'char **' <LValueToRValue>
|     | |     `-DeclRefExpr 0x7fc67188c310 <col:13> 'char **' lvalue Var 0x7fc67188c1a0 'env' 'char **'
|     | `-ImplicitCastExpr 0x7fc67188c388 <col:20> 'char *' <NullToPointer>
|     |   `-CXXNullPtrLiteralExpr 0x7fc67188c360 <col:20> 'std::nullptr_t'
|     `-CompoundStmt 0x7fc67188c448 <col:29, line:32:5>
|       `-UnaryOperator 0x7fc67188c430 <line:31:9, col:12> 'char **' postfix '++'
|         `-DeclRefExpr 0x7fc67188c410 <col:9> 'char **' lvalue Var 0x7fc67188c1a0 'env' 'char **'
`-FunctionDecl 0x7fc67188c780 <line:39:1, line:42:1> line:39:5 main 'int (int, const char **)'
  |-ParmVarDecl 0x7fc67188c5f0 <col:10, col:14> col:14 used argc 'int'
  |-ParmVarDecl 0x7fc67188c6a0 <col:20, col:33> col:33 used argv 'const char **'
  `-CompoundStmt 0x7fc67188c940 <col:39, line:42:1>
    `-CallExpr 0x7fc67188c8e0 <line:40:5, col:18> 'void'
      `-ImplicitCastExpr 0x7fc67188c8c8 <col:5> 'void (*)()' <FunctionToPointerDecay>
        `-DeclRefExpr 0x7fc67188c878 <col:5> 'void ()' lvalue Function 0x7fc67188c0e8 'testPrintEnv' 'void ()'

image-20230408204553188

如何修改源代码

简单的是Fix,

Replacement