SlideShare a Scribd company logo
Clang-tidy:
путешествие внутрь AST С++
Юрий Ефимочев
О себе
Архитектор в LogicNow
Специализация: высоконагруженные
отказоустойчивые системы на C++
Бэкап-решение
Что такое clang-tidy?
Инструмент для статического анализа кода и
поиска типичных ошибок программирования
Встроенные правила(~200)
ClangAnalyzer
Readability/Modernize/Performance
CppCoreGuidelines
LLVM/Google-style
Пример запуска
class TestClass
{
public:
TestClass() :
m_B(),
m_C()
{
}
private:
int m_A;
int m_B;
int m_C;
};
Пример запуска
$ clang-tidy -checks="cppcoreguidelines-*" ./test.cpp
1 warning generated.
/home/yury/Projects/test.cpp:4:5: warning: constructor does not initialize
these fields: m_A [cppcoreguidelines-pro-type-member-init]
TestClass() :
^
m_A(),
Code review
Цели code review
Соответствие реализации задаче
Поиск ошибок и неоптимальностей реализации
Соответствие guidelines и best practices
Clang-tidy и code review?
Платформа для построения собственных
инструментов статического анализа кода
Расширяемость
Полный доступ к AST и препроцессору
Модульная архитектура
Инфраструктура для разработки и тестирования
Что необходимо для использования?
Код должен собираться clang
Необходима compilation database
Алгоритм разработки правила
1.Подготовить пример
2.Посмотреть в AST
3.???
4.Profit
Пример: class field visibility
#include <iostream>
class TestClass
{
public:
static int const Constant = 42;
int m_public;
private:
int m_private;
};
struct TestStruct
{
int Field;
};
// style: class public field
Clang-check: визуализация AST
$ clang-check -ast-dump -ast-dump-filter="Test" ./test.cpp
Dumping TestClass:
CXXRecordDecl 0x4ed7688 <test.cpp:3:1, line:12:1> line:3:7 class TestClass definition
|-CXXRecordDecl 0x4ed77a0 <col:1, col:7> col:7 implicit class TestClass
|-AccessSpecDecl 0x4ed7830 <line:5:1, col:7> col:1 public
|-VarDecl 0x4ed7868 <line:6:5, col:33> col:22 Constant 'const int' static cinit
| `-IntegerLiteral 0x4ed78c8 <col:33> 'int' 42
|-FieldDecl 0x4ed7940 <line:8:5, col:9> col:9 m_public 'int'
|-AccessSpecDecl 0x4ed7988 <line:10:1, col:8> col:1 private
`-FieldDecl 0x4ed79c0 <line:11:5, col:9> col:9 m_private 'int'
Dumping TestStruct:
CXXRecordDecl 0x4ed7a08 <test.cpp:14:1, line:17:1> line:14:8 struct TestStruct definition
|-CXXRecordDecl 0x4ed7b20 <col:1, col:8> col:8 implicit struct TestStruct
`-FieldDecl 0x4ed7bc0 <line:16:5, col:9> col:9 Field 'int'
Из чего состоит AST?
AST Nodes
Decl
Stmt
Type
AST Nodes
Decl
CXXRecordDecl
CXXMethodDecl
VarDecl
Stmt
Type
AST Nodes
Decl
Stmt
ifStmt
CXXTryStmt
BinaryOperator
CompoundStmt
Type
AST Nodes
Decl
Stmt
Type
PointerType
ReferenceType
LValueReferenceType
RValueReferenceType
Clang-check: визуализация AST
$ clang-check -ast-dump -ast-dump-filter="Test" ./test.cpp
Dumping TestClass:
CXXRecordDecl 0x4ed7688 <test.cpp:3:1, line:12:1> line:3:7 class TestClass definition
|-CXXRecordDecl 0x4ed77a0 <col:1, col:7> col:7 implicit class TestClass
|-AccessSpecDecl 0x4ed7830 <line:5:1, col:7> col:1 public
|-VarDecl 0x4ed7868 <line:6:5, col:33> col:22 Constant 'const int' static cinit
| `-IntegerLiteral 0x4ed78c8 <col:33> 'int' 42
|-FieldDecl 0x4ed7940 <line:8:5, col:9> col:9 m_public 'int'
|-AccessSpecDecl 0x4ed7988 <line:10:1, col:8> col:1 private
`-FieldDecl 0x4ed79c0 <line:11:5, col:9> col:9 m_private 'int'
Dumping TestStruct:
CXXRecordDecl 0x4ed7a08 <test.cpp:14:1, line:17:1> line:14:8 struct TestStruct definition
|-CXXRecordDecl 0x4ed7b20 <col:1, col:8> col:8 implicit struct TestStruct
`-FieldDecl 0x4ed7bc0 <line:16:5, col:9> col:9 Field 'int'
AST Matchers
Node Matchers
cxxRecordDecl, cxxMethodDecl, namespaceDecl, ifStmt, ...
Narrowing Matchers
isConstant, isFinal, hasName, matchesName, unless, ...
Traversal Matchers
hasDescendant, hasParent, hasBody, ...
cxxMethodDecl(matchesName(“Get.*”),
hasParent(cxxRecordDecl(isStruct()))
Clang-query: поиск в AST
clang-query> match fieldDecl()
Match #1:
/home/yury/Projects/test.cpp:8:5: note: "root" binds here
int m_public;
^~~~~~~~~~~~
Match #2:
/home/yury/Projects/test.cpp:11:5: note: "root" binds here
int m_private;
^~~~~~~~~~~~~
Match #3:
/home/yury/Projects/test.cpp:16:5: note: "root" binds here
int Field;
^~~~~~~~~
3 matches.
Clang-query: поиск в AST
clang-query> match fieldDecl(isPublic())
Match #1:
/home/yury/Projects/test.cpp:8:5: note: "root" binds here
int m_public;
^~~~~~~~~~~~
Match #2:
/home/yury/Projects/test.cpp:16:5: note: "root" binds here
int Field;
^~~~~~~~~
2 matches.
Clang-query: поиск в AST
clang-query> match fieldDecl(isPublic(), hasParent(cxxRecordDecl(isClass())))
Match #1:
/home/yury/Projects/test.cpp:8:5: note: "root" binds here
int m_public;
^~~~~~~~~~~~
1 match.
Добавление правила
$ ./add_new_check.py misc field-visibility
Updating ./misc/CMakeLists.txt...
Creating ./misc/FieldVisibilityCheck.h...
Creating ./misc/FieldVisibilityCheck.cpp...
Updating ./misc/MiscTidyModule.cpp...
Creating ../test/clang-tidy/misc-field-visibility.cpp...
Creating ../docs/clang-tidy/checks/misc-field-visibility.rst...
Updating ../docs/clang-tidy/checks/list.rst...
Done. Now it's your turn!
Реализация правила
class FieldVisibilityCheck : public ClangTidyCheck
{
public:
FieldVisibilityCheck(StringRef name, ClangTidyContext* context) :
ClangTidyCheck(name, context)
{
}
private:
void registerMatchers(ast_matchers::MatchFinder* finder) override
{
}
void check(ast_matchers::MatchFinder::MatchResult const& result) override
{
}
};
Реализация правила
class FieldVisibilityCheck : public ClangTidyCheck
{
public:
FieldVisibilityCheck(StringRef name, ClangTidyContext* context) :
ClangTidyCheck(name, context)
{
}
private:
void registerMatchers(ast_matchers::MatchFinder* finder) override
{
finder->addMatcher(fieldDecl(isPublic(), hasParent(cxxRecordDecl(isClass()))).bind("field"), this);
}
void check(ast_matchers::MatchFinder::MatchResult const& result) override
{
FieldDecl const& field = *result.Nodes.getNodeAs<FieldDecl const>("field");
diag(field.getLocStart(), "Class field should be private");
}
};
Что получилось?
$ clang-tidy -checks="misc-field-visibility-check" ./test.cpp
1 warning generated.
/home/yury/Projects/test.cpp:8:5: warning: Class field should be private
[iaso-field-visibility-check]
int m_public;
^
Пример: argument immutability
int Function(int a)
{
// ...
a = something;
// ...
return a;
}
Пример: argument immutability
struct Test
{
virtual int VirtualMethod(int a) = 0;
int Method(int a, int const b, int& c, int* d)
{
a = b;
return a;
}
};
AST
Dumping Test:
CXXRecordDecl 0x46b1b20 <test.cpp:1:1, line:9:1> line:1:8 struct Test definition
|-CXXRecordDecl 0x46b1c30 <col:1, col:8> col:8 implicit struct Test
|-CXXMethodDecl 0x46b1d90 <line:3:5, col:32> col:9 VirtualMethod 'int (int)'
| `-ParmVarDecl 0x46b1cd0 <col:23, col:27> col:27 a 'int'
`-CXXMethodDecl 0x46b2140 <line:4:5, line:8:5> line:4:9 Method 'int (int, const int, int &, int *)'
|-ParmVarDecl 0x46b1e50 <col:16, col:20> col:20 used a 'int'
|-ParmVarDecl 0x46b1ec0 <col:23, col:33> col:33 used b 'const int'
|-ParmVarDecl 0x46b1f60 <col:36, col:41> col:41 c 'int &'
|-ParmVarDecl 0x46b2000 <col:44, col:49> col:49 d 'int *'
`-CompoundStmt 0x46b2320 <line:5:5, line:8:5>
|-BinaryOperator 0x46b22a0 <line:6:9, col:13> 'int' lvalue '='
| |-DeclRefExpr 0x46b2238 <col:9> 'int' lvalue ParmVar 0x46b1e50 'a' 'int'
| `-ImplicitCastExpr 0x46b2288 <col:13> 'int' <LValueToRValue>
| `-DeclRefExpr 0x46b2260 <col:13> 'const int' lvalue ParmVar 0x46b1ec0 'b' 'const int'
`-ReturnStmt 0x46b2308 <line:7:9, col:16>
`-ImplicitCastExpr 0x46b22f0 <col:16> 'int' <LValueToRValue>
`-DeclRefExpr 0x46b22c8 <col:16> 'int' lvalue ParmVar 0x46b1e50 'a' 'int'
Реализация
void ImmutableParamsCheck::registerMatchers(MatchFinder* finder)
{
finder->addMatcher(
parmVarDecl(
hasAncestor(functionDecl(hasBody(stmt()))),
unless(anyOf(
hasType(isConstQualified()),
hasType(referenceType()),
hasType(pointerType())))).bind("parameter"), this);
}
void ImmutableParamsCheck::check(MatchFinder::MatchResult const& result)
{
ParmVarDecl const& parameter = *result.Nodes.getNodeAs<ParmVarDecl const>("parameter");
SourceLocation const location = parameter.getSourceRange().getEnd();
diag(location, "Consider making constant") <<
FixItHint::CreateInsertion(location, "const ");
}
Что получилось?
$ clang-tidy -checks="misc-immutable-parameters-check" -fix ./test.cpp
2 warnings generated.
/home/yury/Projects/test.cpp:4:20: warning: Consider making constant [iaso-immutable-
params]
int Method(int a, int const b, int& c, int* d)
^
const
/home/yury/Projects/test.cpp:4:20: note: FIX-IT applied suggested code changes
int Method(int a, int const b, int& c, int* d)
^
clang-tidy applied 1 of 1 suggested fixes.
Результат
struct Test
{
virtual int VirtualMethod(int a) = 0;
int Method(int a, int const b, int& c, int* d)
{
a = b;
return a;
}
};
Результат
struct Test
{
virtual int VirtualMethod(int a) = 0;
int Method(int const a, int const b, int& c, int* d)
{
a = b;
return a;
}
};
Пример: naming guidelines
// cxxRecordDecl(unless(matchesName("::[A-Z][a-zA-Z0-9]*$")))
class TestClass
{
public:
// cxxMethodDecl(unless(matchesName("::[A-Z][a-zA-Z0-9]*$")))
// parmVarDecl(unless(matchesName("::[a-z][a-zA-Z0-9]*$")))
void Method(int arg);
private:
// fieldDecl(unless(matchesName("::m_[a-z][a-zA-Z0-9]*$")),
// hasParent(cxxRecordDecl(isClass())))
int m_field;
};
struct TestStruct
{
// fieldDecl(unless(matchesName("::[A-Z][a-zA-Z0-9]*$")),
// hasParent(cxxRecordDecl(isStruct())))
int Field;
};
Пример: naming guidelines
// varDecl(hasLocalStorage(), unless(matchesName("::[a-z][a-zA-Z0-9]*$")))
int localVariable;
// varDecl(hasGlobalStorage(),
// unless(anyOf(matchesName("::s_[a-z][a-zA-Z0-9]*$"), hasType(isConstQualified()))))
static int s_staticVariable;
// varDecl(hasGlobalStorage(),
// unless(anyOf(matchesName("::[A-Z][a-zA-Z0-9]*$"),
unless(hasType(isConstQualified())))))
static int const Constant = 42;
Clang-tidy
Clang-tidy: итоги
Простая реализация сложных проверок
Атоматизизация рутинных проверок
Отличный способ лучше узнать C++
Полезные ссылки
http://clang.llvm.org/extra/clang-tidy
http://clang.llvm.org/docs/LibASTMatchersReference.html
http://clang.llvm.org/docs/IntroductionToTheClangAST.html
?
efimyury@gmail.com
yury.efimochev@logicnow.com
Clang-tidy: путешествие внутрь AST C++

More Related Content

What's hot (20)

PDF
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Loïc Knuchel
 
PDF
Most Common JavaScript Mistakes
Yoann Gotthilf
 
PDF
Corrig Projet P L S Q L
badirh
 
PDF
Hyrje openmp
L Dr
 
KEY
Javascrpt arale
Alipay
 
PDF
Writeup ctf online idsecconf 2017
idsecconf
 
DOCX
EJEMPLOS DESARROLLADOS
Darwin Durand
 
PPTX
Java осень 2012 лекция 6
Technopark
 
PDF
JQuery
koji lin
 
DOCX
Ejercicios c#
marthaleo36
 
PPTX
Gjuha paskal
Erin Elezi
 
PDF
JUG.ua 20170225 - Java bytecode instrumentation
Anton Arhipov
 
PDF
Laporan ai modul 3-if b 2014-14102055-deprilana ego prakasa
Deprilana Ego Prakasa
 
ODP
Mikstura it2013
Adam Przybyła
 
DOCX
Danna y felix 10°
danna gabriela
 
DOCX
Simulacion - Algoritmo congruencial cuadratico
José Antonio Sandoval Acosta
 
PDF
openFrameworks基礎 動きを生みだす、アニメーション入門 - 芸大グラフィックスプログラミング演習B
Atsushi Tadokoro
 
DOCX
โปรแกรมย่อยและฟังก์ชันมาตรฐาน
knangsmiley
 
DOCX
c ++ informe Nº5 ucsm
Isaac Aquino
 
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Loïc Knuchel
 
Most Common JavaScript Mistakes
Yoann Gotthilf
 
Corrig Projet P L S Q L
badirh
 
Hyrje openmp
L Dr
 
Javascrpt arale
Alipay
 
Writeup ctf online idsecconf 2017
idsecconf
 
EJEMPLOS DESARROLLADOS
Darwin Durand
 
Java осень 2012 лекция 6
Technopark
 
JQuery
koji lin
 
Ejercicios c#
marthaleo36
 
Gjuha paskal
Erin Elezi
 
JUG.ua 20170225 - Java bytecode instrumentation
Anton Arhipov
 
Laporan ai modul 3-if b 2014-14102055-deprilana ego prakasa
Deprilana Ego Prakasa
 
Mikstura it2013
Adam Przybyła
 
Danna y felix 10°
danna gabriela
 
Simulacion - Algoritmo congruencial cuadratico
José Antonio Sandoval Acosta
 
openFrameworks基礎 動きを生みだす、アニメーション入門 - 芸大グラフィックスプログラミング演習B
Atsushi Tadokoro
 
โปรแกรมย่อยและฟังก์ชันมาตรฐาน
knangsmiley
 
c ++ informe Nº5 ucsm
Isaac Aquino
 

Viewers also liked (17)

PDF
Антон Бикинеев, Reflection in C++Next
Sergey Platonov
 
PPTX
Григорий Демченко, Универсальный адаптер
Sergey Platonov
 
PDF
Использование юнит-тестов для повышения качества разработки
victor-yastrebov
 
PPTX
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Sergey Platonov
 
PDF
Clang tidy
Yury Yafimachau
 
PPTX
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Platonov Sergey
 
PDF
Parallel STL
Evgeny Krutko
 
PDF
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Sergey Platonov
 
PDF
Догнать и перегнать boost::lexical_cast
Roman Orlov
 
PDF
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Yauheni Akhotnikau
 
PPTX
Фитнес для вашего кода: как держать его в форме
Ilia Shishkov
 
PPTX
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
Sergey Platonov
 
PPTX
C++ Core Guidelines
Sergey Zubkov
 
PPTX
Quality assurance of large c++ projects
corehard_by
 
PDF
Fuzzing: The New Unit Testing
Dmitry Vyukov
 
PPTX
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Mikhail Matrosov
 
PDF
Василий Сорокин, Простой REST сервер на Qt с рефлексией
Sergey Platonov
 
Антон Бикинеев, Reflection in C++Next
Sergey Platonov
 
Григорий Демченко, Универсальный адаптер
Sergey Platonov
 
Использование юнит-тестов для повышения качества разработки
victor-yastrebov
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Sergey Platonov
 
Clang tidy
Yury Yafimachau
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Platonov Sergey
 
Parallel STL
Evgeny Krutko
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Sergey Platonov
 
Догнать и перегнать boost::lexical_cast
Roman Orlov
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Yauheni Akhotnikau
 
Фитнес для вашего кода: как держать его в форме
Ilia Shishkov
 
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
Sergey Platonov
 
C++ Core Guidelines
Sergey Zubkov
 
Quality assurance of large c++ projects
corehard_by
 
Fuzzing: The New Unit Testing
Dmitry Vyukov
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Mikhail Matrosov
 
Василий Сорокин, Простой REST сервер на Qt с рефлексией
Sergey Platonov
 
Ad

More from corehard_by (20)

PPTX
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
corehard_by
 
PPTX
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
corehard_by
 
PPTX
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
corehard_by
 
PDF
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
corehard_by
 
PPTX
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
corehard_by
 
PDF
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
corehard_by
 
PDF
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
corehard_by
 
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
corehard_by
 
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
corehard_by
 
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
corehard_by
 
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
corehard_by
 
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
corehard_by
 
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
corehard_by
 
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
corehard_by
 
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
corehard_by
 
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
corehard_by
 
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
corehard_by
 
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
corehard_by
 
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
corehard_by
 
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
corehard_by
 
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
corehard_by
 
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
corehard_by
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
corehard_by
 
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
corehard_by
 
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
corehard_by
 
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
corehard_by
 
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
corehard_by
 
Ad

Clang-tidy: путешествие внутрь AST C++

Editor's Notes

  • #4: standalone/plugin
  • #9: standalone/plugin
  • #10: standalone/plugin
  • #14: Сколько строк в AST без фильтра? 37698
  • #15: Сколько строк в AST без фильтра? 37698
  • #21: Сколько строк в AST без фильтра? 37698
  • #39: Лучше разбираться в c++
  • #43: Лучше разбираться в c++