1 // RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
2 
3 extern int foo();
4 
5 class A {
6 public:
7   A() = default;
8   virtual ~A() = default;
9 
virt_1()10   virtual int virt_1() { return foo() + 1; }
virt_2()11   virtual int virt_2() { return foo() + 2; }
12 
non_virt()13   int non_virt() { return foo() + 3; }
stat()14   static int stat() { return foo() + 4; }
15 };
16 
17 class B : public A {
18 public:
19   B() = default;
20 
21   // Nothing to fix: calls to direct parent.
virt_1()22   int virt_1() override { return A::virt_1() + 3; }
virt_2()23   int virt_2() override { return A::virt_2() + 4; }
24 };
25 
26 class C : public B {
27 public:
virt_1()28   int virt_1() override { return A::virt_1() + B::virt_1(); }
29   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' refers to a member overridden in subclass; did you mean 'B'? [bugprone-parent-virtual-call]
30   // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1(); }
virt_2()31   int virt_2() override { return A::virt_1() + B::virt_1(); }
32   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'B'? {{.*}}
33   // CHECK-FIXES:  int virt_2() override { return B::virt_1() + B::virt_1(); }
34 
35   // Test that non-virtual and static methods are not affected by this cherker.
method_c()36   int method_c() { return A::stat() + A::non_virt(); }
37 };
38 
39 // Check aliased type names
40 using A1 = A;
41 typedef A A2;
42 #define A3 A
43 
44 class C2 : public B {
45 public:
virt_1()46   int virt_1() override { return A1::virt_1() + A2::virt_1() + A3::virt_1(); }
47   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A1::virt_1' {{.*}}; did you mean 'B'? {{.*}}
48   // CHECK-MESSAGES: :[[@LINE-2]]:49: warning: qualified name 'A2::virt_1' {{.*}}; did you mean 'B'? {{.*}}
49   // CHECK-MESSAGES: :[[@LINE-3]]:64: warning: qualified name 'A3::virt_1' {{.*}}; did you mean 'B'? {{.*}}
50   // CHECK-FIXES:  int virt_1() override { return B::virt_1() + B::virt_1() + B::virt_1(); }
51 };
52 
53 // Test that the check affects grand-grand..-parent calls too.
54 class D : public C {
55 public:
virt_1()56   int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
57   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'C'? {{.*}}
58   // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified name 'B::virt_1' {{.*}}; did you mean 'C'? {{.*}}
59   // CHECK-FIXES:  int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
virt_2()60   int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
61   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'C'? {{.*}}
62   // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified name 'B::virt_1' {{.*}}; did you mean 'C'? {{.*}}
63   // CHECK-FIXES:  int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
64 };
65 
66 // Test classes in namespaces.
67 namespace {
68 class BN : public A {
69 public:
virt_1()70   int virt_1() override { return A::virt_1() + 3; }
virt_2()71   int virt_2() override { return A::virt_2() + 4; }
72 };
73 } // namespace
74 
75 namespace N1 {
76 class A {
77 public:
78   A() = default;
virt_1()79   virtual int virt_1() { return foo() + 1; }
virt_2()80   virtual int virt_2() { return foo() + 2; }
81 };
82 } // namespace N1
83 
84 namespace N2 {
85 class BN : public N1::A {
86 public:
virt_1()87   int virt_1() override { return A::virt_1() + 3; }
virt_2()88   int virt_2() override { return A::virt_2() + 4; }
89 };
90 } // namespace N2
91 
92 class CN : public BN {
93 public:
virt_1()94   int virt_1() override { return A::virt_1() + BN::virt_1(); }
95   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BN'? {{.*}}
96   // CHECK-FIXES:  int virt_1() override { return BN::virt_1() + BN::virt_1(); }
virt_2()97   int virt_2() override { return A::virt_1() + BN::virt_1(); }
98   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BN'? {{.*}}
99   // CHECK-FIXES:  int virt_2() override { return BN::virt_1() + BN::virt_1(); }
100 };
101 
102 class CNN : public N2::BN {
103 public:
virt_1()104   int virt_1() override { return N1::A::virt_1() + N2::BN::virt_1(); }
105   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'N1::A::virt_1' {{.*}}; did you mean 'N2::BN'? {{.*}}
106   // CHECK-FIXES:  int virt_1() override { return N2::BN::virt_1() + N2::BN::virt_1(); }
virt_2()107   int virt_2() override { return N1::A::virt_1() + N2::BN::virt_1(); }
108   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'N1::A::virt_1' {{.*}}; did you mean 'N2::BN'? {{.*}}
109   // CHECK-FIXES:  int virt_2() override { return N2::BN::virt_1() + N2::BN::virt_1(); }
110 };
111 
112 // Test multiple inheritance fixes
113 class AA {
114 public:
115   AA() = default;
116   virtual ~AA() = default;
117 
virt_1()118   virtual int virt_1() { return foo() + 1; }
virt_2()119   virtual int virt_2() { return foo() + 2; }
120 
non_virt()121   int non_virt() { return foo() + 3; }
stat()122   static int stat() { return foo() + 4; }
123 };
124 
125 class BB_1 : virtual public AA {
126 public:
127   BB_1() = default;
128 
129   // Nothing to fix: calls to parent.
virt_1()130   int virt_1() override { return AA::virt_1() + 3; }
virt_2()131   int virt_2() override { return AA::virt_2() + 4; }
132 };
133 
134 class BB_2 : virtual public AA {
135 public:
136   BB_2() = default;
virt_1()137   int virt_1() override { return AA::virt_1() + 3; }
138 };
139 
140 class CC : public BB_1, public BB_2 {
141 public:
virt_1()142   int virt_1() override { return AA::virt_1() + 3; }
143   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'AA::virt_1' refers to a member overridden in subclasses; did you mean 'BB_1' or 'BB_2'? {{.*}}
144   // No fix available due to multiple choice of parent class.
145 };
146 
147 // Test that virtual method is not diagnosed as not overridden in parent.
148 class BI : public A {
149 public:
150   BI() = default;
151 };
152 
153 class CI : BI {
virt_1()154   int virt_1() override { return A::virt_1(); }
155 };
156 
157 // Test templated classes.
158 template <class F> class BF : public A {
159 public:
virt_1()160   int virt_1() override { return A::virt_1() + 3; }
161 };
162 
163 // Test templated parent class.
164 class CF : public BF<int> {
165 public:
virt_1()166   int virt_1() override { return A::virt_1(); }
167   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BF'? {{.*}}
168 };
169 
170 // Test both templated class and its parent class.
171 template <class F> class DF : public BF<F> {
172 public:
173   DF() = default;
virt_1()174   int virt_1() override { return A::virt_1(); }
175   // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BF'? {{.*}}
176 };
177 
178 // Just to instantiate DF<F>.
bar()179 int bar() { return (new DF<int>())->virt_1(); }
180