1 of 87

2 of 87

for making the NYC++ Meetup possible

THANK YOU

to our sponsors…

Monochrome Search

Silver

Bronze

3 of 87

4 of 87

4

5 of 87

5

  • Who Am I
  • Refactoring Tooling Use Cases
  • Clang Crash Course
  • Writing a Clang Tidy Check Live
  • Special Thanks & Questions

Agenda

6 of 87

6

Who Am I

01

7 of 87

7

7

Proprietary + Confidential

C++ Core Libraries

8 of 87

8

8

Proprietary + Confidential

C++ Core Libraries

9 of 87

9

9

Proprietary + Confidential

C++ Core Libraries

10 of 87

10

10

Proprietary + Confidential

C++ Core Libraries

11 of 87

11

11

Proprietary + Confidential

C++ Core Libraries

12 of 87

12

12

Proprietary + Confidential

C++ Core Libraries

13 of 87

13

13

Proprietary + Confidential

Large Scale Refactorings

& Automated Refactoring Tools

14 of 87

14

Refactoring Tool Use Cases

02

15 of 87

15

15

Proprietary + Confidential

Consistent Code

Formatting

16 of 87

16

16

Proprietary + Confidential

Migrations & Language Updates

17 of 87

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 of 87

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 of 87

19

19

Proprietary + Confidential

Saving You From Yourself

20 of 87

20

20

UB & other Bugs

Anti Patterns & Poor Style

Inefficiencies

Your Code Base

That’s How You Get Ants

21 of 87

21

21

Clang Tidies!

03

22 of 87

22

22

What is a Clang Tidy

23 of 87

23

23

Existing Clang Tidies

24 of 87

24

24

Existing Clang Tidies

25 of 87

25

25

Existing Clang Tidies

26 of 87

26

26

Existing Clang Tidies

27 of 87

27

27

Existing Clang Tidies

28 of 87

28

28

Existing Clang Tidies

29 of 87

29

29

Existing Clang Tidies

30 of 87

30

30

I Want My Own!

31 of 87

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

32 of 87

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

33 of 87

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 of 87

34

34

Compilation in C++

04

35 of 87

35

35

Lexer

Parser

Optimizer

Assembler

Compilation in C++

Front End

Back End

36 of 87

36

36

a + b

<a>, <+>, <b>

<+>

<a>

<b>

Lexer

Parser

Code

37 of 87

37

37

Let’s Just Use A Regular Expression

38 of 87

38

38

Go Ahead and Try It

39 of 87

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 of 87

40

40

Or This

class A {

public:

virtual void foo() = 0;

};

class B : public A {

public:

virtual void foo() {}

}

41 of 87

41

41

Why Clang?

42 of 87

42

42

The Clang AST

43 of 87

43

43

int main() {

int a;

int b;

int c = a + b;

}

The Clang AST

44 of 87

44

44

Field Trip!

https://bit.ly/cpp-con-a-plus-b

45 of 87

45

45

Decls

Stmts

Types

Oh My!

46 of 87

46

46

Decls

47 of 87

47

47

Decls

48 of 87

48

48

Decls

49 of 87

49

49

AST Matchers

05

50 of 87

50

AST Matchers - Three Flavors

51 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

59

AST Matcher Reference

60 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

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 of 87

71

71

Field Trip!

bit.ly/cpp-con-ast-matchers

72 of 87

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 of 87

73

73

So you have a node

SO

WHAT?

74 of 87

74

74

Be Yourself

So you have a node

75 of 87

75

75

Refactoring

06

76 of 87

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 of 87

77

77

Clang Diagnostics & Fix-It Hints

diag(function_decl->getLocation(), "Your function is insufficiently awesome")

<< FixItHint::CreateInsertion(function_decl->getLocation(), "awesome_");

78 of 87

78

78

Writing A New Clang Tidy Check

07

79 of 87

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 of 87

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 of 87

81

81

struct Expensive {

int array[128];

};

int main() {

Expensive arr[42] = {};

for (const auto& i: arr){

// analyze i

}

}

Writing Our Own Tidy Check

82 of 87

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()

83 of 87

Really Cool Stuff You Can Build

83

if (absl::GetFlag(FLAGS_Example_for_cpp_con)) {

foo();

}

else {

bar();

}

foo();

84 of 87

84

In Conclusion

07

85 of 87

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 of 87

86

Questions

07

87 of 87

https://nycpp.dev/support

Please consider supporting NYC++