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