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