1 | // RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t -- |
2 | |
3 | class Base { |
4 | public: |
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; |
15 | virtual ~AbstractBase() {} |
16 | }; |
17 | |
18 | class AbstractInherited : public AbstractBase {}; |
19 | |
20 | class AbstractOverride : public AbstractInherited { |
21 | public: |
22 | void f() override {} |
23 | }; |
24 | |
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 | |
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 | |
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> |
100 | void templateWarning(T *t) { |
101 | // FIXME: Tidy doesn't support template instantiation locations properly. |
102 | t += 1; |
103 | // no-warning |
104 | } |
105 | |
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(t: 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 | |
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 | |