1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
12 #include <clang/AST/DeclCXX.h>
13 #include <clang/AST/DeclTemplate.h>
19 TypeCheck
TypeCheck::NonConst() const {
20 return !type_
.isNull() && !type_
.isConstQualified()
21 ? *this : TypeCheck();
22 // returning TypeCheck(type_.getUnqualifiedType()) instead of *this
23 // may look tempting, but could remove sugar we might be interested in
27 TypeCheck
TypeCheck::NonConstVolatile() const {
29 (!type_
.isNull() && !type_
.isConstQualified()
30 && !type_
.isVolatileQualified())
31 ? *this : TypeCheck();
32 // returning TypeCheck(type_.getUnqualifiedType()) instead of *this
33 // may look tempting, but could remove sugar we might be interested in
37 TypeCheck
TypeCheck::Const() const {
39 (!type_
.isNull() && type_
.isConstQualified()
40 && !type_
.isVolatileQualified())
41 ? *this : TypeCheck();
42 // returning TypeCheck(type_.getUnqualifiedType()) instead of *this
43 // may look tempting, but could remove sugar we might be interested in
47 TypeCheck
TypeCheck::Volatile() const {
49 (!type_
.isNull() && !type_
.isConstQualified()
50 && type_
.isVolatileQualified())
51 ? *this : TypeCheck();
52 // returning TypeCheck(type_.getUnqualifiedType()) instead of *this
53 // may look tempting, but could remove sugar we might be interested in
57 TypeCheck
TypeCheck::ConstVolatile() const {
59 (!type_
.isNull() && type_
.isConstQualified()
60 && type_
.isVolatileQualified())
61 ? *this : TypeCheck();
62 // returning TypeCheck(type_.getUnqualifiedType()) instead of *this
63 // may look tempting, but could remove sugar we might be interested in
67 TerminalCheck
TypeCheck::Void() const {
70 && type_
->isSpecificBuiltinType(clang::BuiltinType::Void
));
73 TerminalCheck
TypeCheck::Char() const {
76 && (type_
->isSpecificBuiltinType(clang::BuiltinType::Char_S
)
77 || type_
->isSpecificBuiltinType(clang::BuiltinType::Char_U
)));
80 TerminalCheck
TypeCheck::AnyBoolean() const {
81 if (type_
->isBooleanType()) {
82 return TerminalCheck(true);
84 auto t
= type_
->getAs
<clang::TypedefType
>();
86 return TerminalCheck(false);
88 auto n
=t
->getDecl()->getName();
90 n
== "sal_Bool" || n
== "BOOL" || n
== "Boolean" || n
== "FT_Bool"
91 || n
== "FcBool" || n
== "GLboolean" || n
== "NPBool" || n
== "TW_BOOL"
92 || n
== "UBool" || n
== "boolean" || n
== "dbus_bool_t"
93 || n
== "gboolean" || n
== "hb_bool_t" || n
== "jboolean" || n
== "my_bool");
96 TypeCheck
TypeCheck::LvalueReference() const {
97 if (!type_
.isNull()) {
98 auto const t
= type_
->getAs
<clang::LValueReferenceType
>();
100 return TypeCheck(t
->getPointeeType());
106 TypeCheck
TypeCheck::Pointer() const {
107 if (!type_
.isNull()) {
108 auto const t
= type_
->getAs
<clang::PointerType
>();
110 return TypeCheck(t
->getPointeeType());
116 TerminalCheck
TypeCheck::Enum() const {
117 if (!type_
.isNull()) {
118 auto const t
= type_
->getAs
<clang::EnumType
>();
120 return TerminalCheck(true);
123 return TerminalCheck(false);
126 TypeCheck
TypeCheck::Typedef() const {
127 if (!type_
.isNull()) {
128 if (auto const t
= type_
->getAs
<clang::TypedefType
>()) {
129 return TypeCheck(t
->desugar());
135 DeclCheck
TypeCheck::TemplateSpecializationClass() const {
136 if (!type_
.isNull()) {
137 if (auto const t
= type_
->getAs
<clang::TemplateSpecializationType
>()) {
138 if (!t
->isTypeAlias()) {
139 if (auto const d
= llvm::dyn_cast_or_null
<clang::ClassTemplateDecl
>(
140 t
->getTemplateName().getAsTemplateDecl()))
142 return DeclCheck(d
->getTemplatedDecl());
150 TypeCheck
TypeCheck::NotSubstTemplateTypeParmType() const {
153 && type_
->getAs
<clang::SubstTemplateTypeParmType
>() == nullptr)
154 ? *this : TypeCheck();
157 ContextCheck
DeclCheck::Operator(clang::OverloadedOperatorKind op
) const {
158 assert(op
!= clang::OO_None
);
159 auto f
= llvm::dyn_cast_or_null
<clang::FunctionDecl
>(decl_
);
161 f
!= nullptr && f
->getOverloadedOperator() == op
162 ? f
->getDeclContext() : nullptr);
165 ContextCheck
DeclCheck::MemberFunction() const {
166 auto m
= llvm::dyn_cast_or_null
<clang::CXXMethodDecl
>(decl_
);
167 return ContextCheck(m
== nullptr ? nullptr : m
->getParent());
172 bool isGlobalNamespace(clang::DeclContext
const * context
) {
173 assert(context
!= nullptr);
174 return (context
->isLookupContext() ? context
: context
->getLookupParent())->isTranslationUnit();
179 TerminalCheck
ContextCheck::GlobalNamespace() const {
180 return TerminalCheck(context_
!= nullptr && isGlobalNamespace(context_
));
183 TerminalCheck
ContextCheck::StdNamespace() const {
184 return TerminalCheck(
185 context_
!= nullptr && context_
->isStdNamespace());
190 bool isStdOrNestedNamespace(clang::DeclContext
const * context
) {
191 assert(context
!= nullptr);
192 if (!context
->isNamespace()) {
195 if (isGlobalNamespace(context
)) {
198 if (context
->isStdNamespace()) {
201 return isStdOrNestedNamespace(context
->getParent());
206 TerminalCheck
ContextCheck::StdOrNestedNamespace() const {
207 return TerminalCheck(context_
!= nullptr && isStdOrNestedNamespace(context_
));
210 ContextCheck
ContextCheck::AnonymousNamespace() const {
211 auto n
= llvm::dyn_cast_or_null
<clang::NamespaceDecl
>(context_
);
213 n
!= nullptr && n
->isAnonymousNamespace() ? n
->getParent() : nullptr);
218 bool BaseCheckNotSomethingInterestingSubclass(const clang::CXXRecordDecl
*BaseDefinition
) {
219 if (BaseDefinition
) {
220 auto tc
= TypeCheck(BaseDefinition
);
221 if (tc
.Class("Dialog").GlobalNamespace() || tc
.Class("SfxPoolItem").GlobalNamespace()) {
228 bool isDerivedFromSomethingInteresting(const clang::CXXRecordDecl
*decl
) {
231 auto tc
= TypeCheck(decl
);
232 if (tc
.Class("Dialog"))
234 if (tc
.Class("SfxPoolItem"))
236 if (!decl
->hasDefinition()) {
239 if (// not sure what hasAnyDependentBases() does,
240 // but it avoids classes we don't want, e.g. WeakAggComponentImplHelper1
241 !decl
->hasAnyDependentBases() &&
242 !decl
->forallBases(BaseCheckNotSomethingInterestingSubclass
, true)) {
250 bool isExtraWarnUnusedType(clang::QualType type
) {
251 auto const rec
= type
->getAsCXXRecordDecl();
252 if (rec
== nullptr) {
255 auto const tc
= TypeCheck(rec
);
256 // Check some common non-LO types:
257 if (tc
.Class("basic_string").StdNamespace()
258 || tc
.Class("deque").StdNamespace()
259 || tc
.Class("list").StdNamespace()
260 || tc
.Class("map").StdNamespace()
261 || tc
.Class("pair").StdNamespace()
262 || tc
.Class("queue").StdNamespace()
263 || tc
.Class("set").StdNamespace()
264 || tc
.Class("stack").StdNamespace()
265 || tc
.Class("unordered_map").StdNamespace()
266 || tc
.Class("unordered_set").StdNamespace()
267 || tc
.Class("vector").StdNamespace())
271 return isDerivedFromSomethingInteresting(rec
);
276 bool isArithmeticOp(clang::Expr
const * expr
) {
277 expr
= expr
->IgnoreParenImpCasts();
278 if (auto const e
= llvm::dyn_cast
<clang::BinaryOperator
>(expr
)) {
279 switch (e
->getOpcode()) {
291 case clang::BO_Comma
:
292 return isArithmeticOp(e
->getRHS());
297 return llvm::isa
<clang::UnaryOperator
>(expr
)
298 || llvm::isa
<clang::AbstractConditionalOperator
>(expr
);
303 bool isOkToRemoveArithmeticCast(
304 clang::ASTContext
& context
, clang::QualType t1
, clang::QualType t2
, const clang::Expr
* subExpr
)
306 // Don't warn if the types are arithmetic (in the C++ meaning), and: either
307 // at least one is a typedef or decltype (and if both are, they're different),
308 // or the sub-expression involves some operation that is likely to change
309 // types through promotion, or the sub-expression is an integer literal (so
310 // its type generally depends on its value and suffix if any---even with a
311 // suffix like L it could still be either long or long long):
312 if ((t1
->isIntegralType(context
)
313 || t1
->isRealFloatingType())
314 && ((t1
.getLocalUnqualifiedType() != t2
.getLocalUnqualifiedType()
315 && (loplugin::TypeCheck(t1
).Typedef()
316 || loplugin::TypeCheck(t2
).Typedef()
317 || llvm::isa
<clang::DecltypeType
>(t1
) || llvm::isa
<clang::DecltypeType
>(t2
)))
318 || isArithmeticOp(subExpr
)
319 || llvm::isa
<clang::IntegerLiteral
>(subExpr
->IgnoreParenImpCasts())))
327 static bool BaseCheckNotSubclass(const clang::CXXRecordDecl
*BaseDefinition
, void *p
) {
330 auto const & base
= *static_cast<const DeclChecker
*>(p
);
331 if (base(BaseDefinition
)) {
337 bool isDerivedFrom(const clang::CXXRecordDecl
*decl
, DeclChecker base
) {
342 if (!decl
->hasDefinition()) {
345 if (!decl
->forallBases(
346 [&base
](const clang::CXXRecordDecl
*BaseDefinition
) -> bool
347 { return BaseCheckNotSubclass(BaseDefinition
, &base
); },
357 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */