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: |
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; |
17 | virtual ~AbstractBase() {} |
18 | }; |
19 | |
20 | class AbstractInherited : public AbstractBase {}; |
21 | |
22 | class AbstractOverride : public AbstractInherited { |
23 | public: |
24 | void f() override {} |
25 | }; |
26 | |
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 | |
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 | |
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> |
101 | void templateWarning(T *t) { |
102 | // FIXME: Tidy doesn't support template instantiation locations properly. |
103 | t += 1; |
104 | // no-warning |
105 | } |
106 | |
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(t: 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 | |
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 | |