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