1*f329e3edSDiscookie // RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t -- \
2*f329e3edSDiscookie // RUN: -config="{CheckOptions: \
3*f329e3edSDiscookie // RUN: {bugprone-pointer-arithmetic-on-polymorphic-object.IgnoreInheritedVirtualFunctions: true}}"
4*f329e3edSDiscookie 
5*f329e3edSDiscookie class Base {
6*f329e3edSDiscookie public:
~Base()7*f329e3edSDiscookie   virtual ~Base() {}
8*f329e3edSDiscookie };
9*f329e3edSDiscookie 
10*f329e3edSDiscookie class Derived : public Base {};
11*f329e3edSDiscookie 
12*f329e3edSDiscookie class FinalDerived final : public Base {};
13*f329e3edSDiscookie 
14*f329e3edSDiscookie class AbstractBase {
15*f329e3edSDiscookie public:
16*f329e3edSDiscookie   virtual void f() = 0;
~AbstractBase()17*f329e3edSDiscookie   virtual ~AbstractBase() {}
18*f329e3edSDiscookie };
19*f329e3edSDiscookie 
20*f329e3edSDiscookie class AbstractInherited : public AbstractBase {};
21*f329e3edSDiscookie 
22*f329e3edSDiscookie class AbstractOverride : public AbstractInherited {
23*f329e3edSDiscookie public:
f()24*f329e3edSDiscookie   void f() override {}
25*f329e3edSDiscookie };
26*f329e3edSDiscookie 
operators()27*f329e3edSDiscookie void operators() {
28*f329e3edSDiscookie   Base *b = new Derived[10];
29*f329e3edSDiscookie 
30*f329e3edSDiscookie   b += 1;
31*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type differs from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object]
32*f329e3edSDiscookie 
33*f329e3edSDiscookie   b = b + 1;
34*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type differs from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object]
35*f329e3edSDiscookie 
36*f329e3edSDiscookie   b++;
37*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type differs from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object]
38*f329e3edSDiscookie 
39*f329e3edSDiscookie   --b;
40*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type differs from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object]
41*f329e3edSDiscookie 
42*f329e3edSDiscookie   b[1];
43*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type differs from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object]
44*f329e3edSDiscookie 
45*f329e3edSDiscookie   delete[] static_cast<Derived*>(b);
46*f329e3edSDiscookie }
47*f329e3edSDiscookie 
subclassWarnings()48*f329e3edSDiscookie void subclassWarnings() {
49*f329e3edSDiscookie   Base *b = new Base[10];
50*f329e3edSDiscookie 
51*f329e3edSDiscookie   // False positive that's impossible to distinguish without
52*f329e3edSDiscookie   // path-sensitive analysis, but the code is bug-prone regardless.
53*f329e3edSDiscookie   b += 1;
54*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
55*f329e3edSDiscookie 
56*f329e3edSDiscookie   delete[] b;
57*f329e3edSDiscookie 
58*f329e3edSDiscookie   // Common false positive is a class that overrides all parent functions.
59*f329e3edSDiscookie   Derived *d = new Derived[10];
60*f329e3edSDiscookie 
61*f329e3edSDiscookie   d += 1;
62*f329e3edSDiscookie   // no-warning
63*f329e3edSDiscookie 
64*f329e3edSDiscookie   delete[] d;
65*f329e3edSDiscookie 
66*f329e3edSDiscookie   // Final classes cannot have a dynamic type.
67*f329e3edSDiscookie   FinalDerived *fd = new FinalDerived[10];
68*f329e3edSDiscookie 
69*f329e3edSDiscookie   fd += 1;
70*f329e3edSDiscookie   // no-warning
71*f329e3edSDiscookie 
72*f329e3edSDiscookie   delete[] fd;
73*f329e3edSDiscookie }
74*f329e3edSDiscookie 
abstractWarnings()75*f329e3edSDiscookie void abstractWarnings() {
76*f329e3edSDiscookie   // Classes with an abstract member funtion are always matched.
77*f329e3edSDiscookie   AbstractBase *ab = new AbstractOverride[10];
78*f329e3edSDiscookie 
79*f329e3edSDiscookie   ab += 1;
80*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'AbstractBase'
81*f329e3edSDiscookie 
82*f329e3edSDiscookie   delete[] static_cast<AbstractOverride*>(ab);
83*f329e3edSDiscookie 
84*f329e3edSDiscookie   AbstractInherited *ai = new AbstractOverride[10];
85*f329e3edSDiscookie 
86*f329e3edSDiscookie   ai += 1;
87*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'AbstractInherited'
88*f329e3edSDiscookie 
89*f329e3edSDiscookie   delete[] static_cast<AbstractOverride*>(ai);
90*f329e3edSDiscookie 
91*f329e3edSDiscookie   // If all abstract member functions are overridden, the class is not matched.
92*f329e3edSDiscookie   AbstractOverride *ao = new AbstractOverride[10];
93*f329e3edSDiscookie 
94*f329e3edSDiscookie   ao += 1;
95*f329e3edSDiscookie   // no-warning
96*f329e3edSDiscookie 
97*f329e3edSDiscookie   delete[] ao;
98*f329e3edSDiscookie }
99*f329e3edSDiscookie 
100*f329e3edSDiscookie template <typename T>
templateWarning(T * t)101*f329e3edSDiscookie void templateWarning(T *t) {
102*f329e3edSDiscookie   // FIXME: Tidy doesn't support template instantiation locations properly.
103*f329e3edSDiscookie   t += 1;
104*f329e3edSDiscookie   // no-warning
105*f329e3edSDiscookie }
106*f329e3edSDiscookie 
functionArgument(Base * b)107*f329e3edSDiscookie void functionArgument(Base *b) {
108*f329e3edSDiscookie   b += 1;
109*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
110*f329e3edSDiscookie 
111*f329e3edSDiscookie   templateWarning(b);
112*f329e3edSDiscookie }
113*f329e3edSDiscookie 
114*f329e3edSDiscookie using BaseAlias = Base;
115*f329e3edSDiscookie using DerivedAlias = Derived;
116*f329e3edSDiscookie using FinalDerivedAlias = FinalDerived;
117*f329e3edSDiscookie 
118*f329e3edSDiscookie using BasePtr = Base*;
119*f329e3edSDiscookie using DerivedPtr = Derived*;
120*f329e3edSDiscookie using FinalDerivedPtr = FinalDerived*;
121*f329e3edSDiscookie 
typeAliases(BaseAlias * b,DerivedAlias * d,FinalDerivedAlias * fd,BasePtr bp,DerivedPtr dp,FinalDerivedPtr fdp)122*f329e3edSDiscookie void typeAliases(BaseAlias *b, DerivedAlias *d, FinalDerivedAlias *fd,
123*f329e3edSDiscookie                  BasePtr bp, DerivedPtr dp, FinalDerivedPtr fdp) {
124*f329e3edSDiscookie   b += 1;
125*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
126*f329e3edSDiscookie 
127*f329e3edSDiscookie   d += 1;
128*f329e3edSDiscookie   // no-warning
129*f329e3edSDiscookie 
130*f329e3edSDiscookie   fd += 1;
131*f329e3edSDiscookie   // no-warning
132*f329e3edSDiscookie 
133*f329e3edSDiscookie   bp += 1;
134*f329e3edSDiscookie   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
135*f329e3edSDiscookie 
136*f329e3edSDiscookie   dp += 1;
137*f329e3edSDiscookie   // no-warning
138*f329e3edSDiscookie 
139*f329e3edSDiscookie   fdp += 1;
140*f329e3edSDiscookie   // no-warning
141*f329e3edSDiscookie }
142