Skip to content

Commit ceaf09c

Browse files
authored
[alpha.webkit.UncountedCallArgsChecker] Detect more trivial functions (#81829)
Allow address-of operator (&), enum constant, and a reference to constant as well as materializing temporqary expression and an expression with cleanups to appear within a trivial function.
1 parent 3af5c98 commit ceaf09c

File tree

3 files changed

+114
-2
lines changed

3 files changed

+114
-2
lines changed

clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,8 @@ class TrivialFunctionAnalysisVisitor
285285

286286
bool VisitUnaryOperator(const UnaryOperator *UO) {
287287
// Operator '*' and '!' are allowed as long as the operand is trivial.
288-
if (UO->getOpcode() == UO_Deref || UO->getOpcode() == UO_LNot)
288+
if (UO->getOpcode() == UO_Deref || UO->getOpcode() == UO_AddrOf ||
289+
UO->getOpcode() == UO_LNot)
289290
return Visit(UO->getSubExpr());
290291

291292
// Other operators are non-trivial.
@@ -306,6 +307,10 @@ class TrivialFunctionAnalysisVisitor
306307
if (auto *decl = DRE->getDecl()) {
307308
if (isa<ParmVarDecl>(decl))
308309
return true;
310+
if (isa<EnumConstantDecl>(decl))
311+
return true;
312+
if (auto *VD = dyn_cast<VarDecl>(decl))
313+
return VD->hasConstantInitialization() && VD->getEvaluatedValue();
309314
}
310315
return false;
311316
}
@@ -377,6 +382,14 @@ class TrivialFunctionAnalysisVisitor
377382
return Visit(ECE->getSubExpr());
378383
}
379384

385+
bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT) {
386+
return Visit(VMT->getSubExpr());
387+
}
388+
389+
bool VisitExprWithCleanups(const ExprWithCleanups *EWC) {
390+
return Visit(EWC->getSubExpr());
391+
}
392+
380393
bool VisitParenExpr(const ParenExpr *PE) { return Visit(PE->getSubExpr()); }
381394

382395
bool VisitInitListExpr(const InitListExpr *ILE) {
@@ -397,6 +410,11 @@ class TrivialFunctionAnalysisVisitor
397410
return true;
398411
}
399412

413+
bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
414+
// nullptr is trivial.
415+
return true;
416+
}
417+
400418
// Constant literal expressions are always trivial
401419
bool VisitIntegerLiteral(const IntegerLiteral *E) { return true; }
402420
bool VisitFloatingLiteral(const FloatingLiteral *E) { return true; }

clang/test/Analysis/Checkers/WebKit/mock-types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ template <typename T> struct RefPtr {
1919
RefPtr(T *t) : t(t) {}
2020
T *get() { return t; }
2121
T *operator->() { return t; }
22+
const T *operator->() const { return t; }
2223
T &operator*() { return *t; }
2324
RefPtr &operator=(T *) { return *this; }
2425
operator bool() { return t; }

clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
22

33
#include "mock-types.h"
4-
//#include <type_traits>
54

65
void WTFBreakpointTrap();
76
void WTFCrashWithInfo(int, const char*, const char*, int);
@@ -60,11 +59,86 @@ NO_RETURN_DUE_TO_CRASH ALWAYS_INLINE void WTFCrashWithInfo(int line, const char*
6059
WTFCrashWithInfoImpl(line, file, function, counter, wtfCrashArg(reason));
6160
}
6261

62+
enum class Flags : unsigned short {
63+
Flag1 = 1 << 0,
64+
Flag2 = 1 << 1,
65+
Flag3 = 1 << 2,
66+
};
67+
68+
template<typename E> class OptionSet {
69+
public:
70+
using StorageType = unsigned short;
71+
72+
static constexpr OptionSet fromRaw(StorageType rawValue) {
73+
return OptionSet(static_cast<E>(rawValue), FromRawValue);
74+
}
75+
76+
constexpr OptionSet() = default;
77+
78+
constexpr OptionSet(E e)
79+
: m_storage(static_cast<StorageType>(e)) {
80+
}
81+
82+
constexpr StorageType toRaw() const { return m_storage; }
83+
84+
constexpr bool isEmpty() const { return !m_storage; }
85+
86+
constexpr explicit operator bool() const { return !isEmpty(); }
87+
88+
constexpr bool contains(E option) const { return containsAny(option); }
89+
constexpr bool containsAny(OptionSet optionSet) const {
90+
return !!(*this & optionSet);
91+
}
92+
93+
constexpr bool containsAll(OptionSet optionSet) const {
94+
return (*this & optionSet) == optionSet;
95+
}
96+
97+
constexpr void add(OptionSet optionSet) { m_storage |= optionSet.m_storage; }
98+
99+
constexpr void remove(OptionSet optionSet)
100+
{
101+
m_storage &= ~optionSet.m_storage;
102+
}
103+
104+
constexpr void set(OptionSet optionSet, bool value)
105+
{
106+
if (value)
107+
add(optionSet);
108+
else
109+
remove(optionSet);
110+
}
111+
112+
constexpr friend OptionSet operator|(OptionSet lhs, OptionSet rhs) {
113+
return fromRaw(lhs.m_storage | rhs.m_storage);
114+
}
115+
116+
constexpr friend OptionSet operator&(OptionSet lhs, OptionSet rhs) {
117+
return fromRaw(lhs.m_storage & rhs.m_storage);
118+
}
119+
120+
constexpr friend OptionSet operator-(OptionSet lhs, OptionSet rhs) {
121+
return fromRaw(lhs.m_storage & ~rhs.m_storage);
122+
}
123+
124+
constexpr friend OptionSet operator^(OptionSet lhs, OptionSet rhs) {
125+
return fromRaw(lhs.m_storage ^ rhs.m_storage);
126+
}
127+
128+
private:
129+
enum InitializationTag { FromRawValue };
130+
constexpr OptionSet(E e, InitializationTag)
131+
: m_storage(static_cast<StorageType>(e)) {
132+
}
133+
StorageType m_storage { 0 };
134+
};
135+
63136
class Number {
64137
public:
65138
Number(int v) : v(v) { }
66139
Number(double);
67140
Number operator+(const Number&);
141+
const int& value() const { return v; }
68142
private:
69143
int v;
70144
};
@@ -112,6 +186,19 @@ class RefCounted {
112186
RefCounted& trivial18() const { RELEASE_ASSERT(this, "this must be not null"); return const_cast<RefCounted&>(*this); }
113187
void trivial19() const { return; }
114188

189+
static constexpr unsigned numBits = 4;
190+
int trivial20() { return v >> numBits; }
191+
192+
const int* trivial21() { return number ? &number->value() : nullptr; }
193+
194+
enum class Enum : unsigned short {
195+
Value1 = 1,
196+
Value2 = 2,
197+
};
198+
bool trivial22() { return enumValue == Enum::Value1; }
199+
200+
bool trivial23() const { return OptionSet<Flags>::fromRaw(v).contains(Flags::Flag1); }
201+
115202
static RefCounted& singleton() {
116203
static RefCounted s_RefCounted;
117204
s_RefCounted.ref();
@@ -170,6 +257,8 @@ class RefCounted {
170257
}
171258

172259
unsigned v { 0 };
260+
Number* number { nullptr };
261+
Enum enumValue { Enum::Value1 };
173262
};
174263

175264
RefCounted* refCountedObj();
@@ -208,6 +297,10 @@ class UnrelatedClass {
208297
getFieldTrivial().trivial17(); // no-warning
209298
getFieldTrivial().trivial18(); // no-warning
210299
getFieldTrivial().trivial19(); // no-warning
300+
getFieldTrivial().trivial20(); // no-warning
301+
getFieldTrivial().trivial21(); // no-warning
302+
getFieldTrivial().trivial22(); // no-warning
303+
getFieldTrivial().trivial23(); // no-warning
211304
RefCounted::singleton().trivial18(); // no-warning
212305
RefCounted::singleton().someFunction(); // no-warning
213306

0 commit comments

Comments
 (0)