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