for making the NYC++ Meetup possible
THANK YOU
to our sponsors…
Monochrome Search
Silver
Bronze
4
5
Agenda
6
Who Am I
01
7
7
Proprietary + Confidential
C++ Core Libraries
8
8
Proprietary + Confidential
C++ Core Libraries
9
9
Proprietary + Confidential
C++ Core Libraries
10
10
Proprietary + Confidential
C++ Core Libraries
11
11
Proprietary + Confidential
C++ Core Libraries
12
12
Proprietary + Confidential
C++ Core Libraries
13
13
Proprietary + Confidential
Large Scale Refactorings
& Automated Refactoring Tools
14
Refactoring Tool Use Cases
02
15
15
Proprietary + Confidential
Consistent Code
Formatting
16
16
Proprietary + Confidential
Migrations & Language Updates
17
17
Proprietary + Confidential
#include <memory>
int main() {
int * c = new int(8);
delete c;
}
C++ 98 -> C++14
#include <memory>
int main() {
std::unique_ptr<int>c =
std::make_unique<int>(8);
}
18
18
Proprietary + Confidential
#include <string>
#include <string_view>
void foo(std::string_view a);
void foo(std::vector<const std::string> a);
int main() {
foo({"hello", "world!"});
}
C++ 17 -> C++20
#include <string>
#include <string_view>
void foo(std::string_view a);
void foo(std::vector<const std::string> a);
int main() {
foo(std::vector<const std::string>
{"hello", "world!"});
}
19
19
Proprietary + Confidential
Saving You From Yourself
20
20
UB & other Bugs
Anti Patterns & Poor Style
Inefficiencies
Your Code Base
That’s How You Get Ants
21
21
Clang Tidies!
03
22
22
What is a Clang Tidy
23
23
Existing Clang Tidies
24
24
Existing Clang Tidies
25
25
Existing Clang Tidies
26
26
Existing Clang Tidies
27
27
Existing Clang Tidies
28
28
Existing Clang Tidies
29
29
Existing Clang Tidies
30
30
I Want My Own!
Anatomy of a Clang Tidy
class AwesomeFunctionNamesCheck : public ClangTidyCheck {
public:
AwesomeFunctionNamesCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
Proprietary + Confidential
Anatomy of a Clang Tidy
class AwesomeFunctionNamesCheck : public ClangTidyCheck {
public:
AwesomeFunctionNamesCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
Proprietary + Confidential
Anatomy of a Clang Tidy
class AwesomeFunctionNamesCheck : public ClangTidyCheck {
public:
AwesomeFunctionNamesCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
Proprietary + Confidential
34
34
Compilation in C++
04
35
35
Lexer
Parser
Optimizer
Assembler
Compilation in C++
Front End
Back End
36
36
a + b
<a>, <+>, <b>
<+>
<a>
<b>
Lexer
Parser
Code
37
37
Let’s Just Use A Regular Expression
38
38
Go Ahead and Try It
39
39
Give Me Your Reg Ex for This
int main() {
int x{};
int z = {};
int q = 0;
auto w = int{0};
auto u = int(0);
auto f = 0 + 0;
auto e = 0;
}
40
40
Or This
class A {
public:
virtual void foo() = 0;
};
class B : public A {
public:
virtual void foo() {}
}
41
41
Why Clang?
42
42
The Clang AST
43
43
int main() {
int a;
int b;
int c = a + b;
}
The Clang AST
44
44
Field Trip!
https://bit.ly/cpp-con-a-plus-b
45
45
Decls
Stmts
Types
Oh My!
46
46
Decls
47
47
Decls
48
48
Decls
49
49
AST Matchers
05
50
AST Matchers - Three Flavors
51
AST Matchers - Node
namespace bar {
void foo();
class A {
public:
virtual void foo();
void bar();
private:
int x;
};
}
decl()
clang::Decl
namedDecl()
clang::NamedDecl
functionDecl()
clang::FunctionDecl
cxxMemberDecl()
clang::CXXMemberDecl
52
AST Matchers - Node
cxxMethodDecl().bind(“my_method_decl”)
namespace bar {
void foo();
class A {
public:
virtual void foo();
void bar();
private:
int x;
};
}
my_method_decl
my_method_decl
53
AST Matchers - Narrowing
cxxMethodDecl(isVirtual()).
bind(“my_virtual_method_decl”)
namespace bar {
void foo();
class A {
public:
virtual void foo();
void bar();
private:
int x;
};
}
my_virtual_method_decl
54
AST Matchers - Traverse
callExpr(callee(
cxxMethodDecl(hasName(“bar”))))
namespace bar {
void foo();
class A {
public:
virtual void foo();
void bar();
private:
int x;
};
}
int main() {� A a;
a.bar();
}
55
AST Matchers - Traverse
callExpr(callee(
cxxMethodDecl(hasName(“bar”))))
namespace bar {
void foo();
class A {
public:
virtual void foo();
void bar();
private:
int x;
};
}
int main() {� A a;
a.bar();
}
56
AST Matchers - Traversal Methods
struct S {
int m_i;
};
void func() {
int a = 0;
int c = 0;
auto l = [a, b = c](int d) { int e = d; };
l(43);
}
fieldDecl(
hasType(asString("int")))
57
AST Matchers - Traversal Methods
struct S {
safe_int m_i;
};
void func() {
int a = 0;
int c = 0;
auto l = [safe_a, safe_b = c](int d) { int e = d; };
l(43);
}
fieldDecl(
hasType(asString("int")))
58
AST Matchers - Traversal Methods
struct S {
int m_i;
};
void func() {
int a = 0;
int c = 0;
auto l = [a, b = c](int d) { int e = d; };
l(43);
}
traverse(
TK_IgnoreUnlessSpelledInSource, fieldDecl(
hasType(asString("int"))))
59
AST Matcher Reference
60
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
61
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
62
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
63
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
64
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
65
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
66
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
67
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
68
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
69
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
70
AST Matchers - Matcher Expressions
Looking for calls to a member function on a class named A and whose called function is named foo and whose first parameter is an integer.
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
71
71
Field Trip!
bit.ly/cpp-con-ast-matchers
72
AST Matchers - RegisterMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) {
finder->AddMatcher(
traverse(TK_IgnoreUnlessSpelledInSource,
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(hasName(“A”)))),
callee(functionDecl(
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))), this)
}
73
73
So you have a node
SO
WHAT?
74
74
Be Yourself
So you have a node
75
75
Refactoring
06
76
76
The Bound Nodes
void check(const ast_matchers::MatchFinder::MatchResult &Result) {
const auto * call_expr = Result.Nodes.getNodeAs<clang::CallExpr>("call_expr");
const auto * class_decl = Result.Nodes.getNodeAs<clang::CXXRecordDecl>("class_a");
const auto * function_decl = Result.Nodes.GetNodeAs<clang::FunctionDecl>("foo_decl");
…
}
cxxMemberCallExpr(stmt().bind(“call_expr”),
on(hasType(cxxRecordDecl(decl().bind(“class_a”), hasName(“A”)))),
callee(functionDecl(decl().bind(“foo_decl”),
hasName(“foo”),
hasParameter(0, hasType(isInteger())))))
77
77
Clang Diagnostics & Fix-It Hints
diag(function_decl->getLocation(), "Your function is insufficiently awesome")
<< FixItHint::CreateInsertion(function_decl->getLocation(), "awesome_");
78
78
Writing A New Clang Tidy Check
07
79
79
struct Expensive {
int array[128];
};
int main() {
Expensive arr[42] = {};
for (const auto i: arr){
// analyze i
}
}
Writing Our Own Tidy Check
80
80
struct Expensive {
int array[128];
};
int main() {
Expensive arr[42] = {};
for (const auto i: arr){
// analyze i
}
}
Writing Our Own Tidy Check
81
81
struct Expensive {
int array[128];
};
int main() {
Expensive arr[42] = {};
for (const auto& i: arr){
// analyze i
}
}
Writing Our Own Tidy Check
Really Cool Stuff You Can Build
82
void OldAPI(int v, int m, int d){
NewAPI(m, v);
}
void NewAPI(int m, int v);
- OldAPI(vel, mass, dist);
+ NewAPI(mass, vel);
ABSL_DEPRECATE_AND_INLINE()
Really Cool Stuff You Can Build
83
if (absl::GetFlag(FLAGS_Example_for_cpp_con)) {
foo();
}
else {
bar();
}
foo();
84
In Conclusion
07
85
85
Special Thanks
People Who Taught Me About Clang
Samuel Benzaquen
Matthew Kulukundis
Andy Soffer
Eric Li
Yitzhak Mandelbaum
Samira Bazuzi
People Who Told Me To Give This Talk Repeatedly Over and Over Again Until I Finally Wrote It
Peter Muldoon
Daisy Hollman
David Sankel
Bret Brown
Margot Leibold
86
Questions
07
https://nycpp.dev/support
Please consider supporting NYC++