Version 24.2.2.2, tag libreoffice-24.2.2.2
[LibreOffice.git] / compilerplugins / clang / check.hxx
blobaf6cd355a416b8a83e133ad19eb432bee699a046
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #pragma once
12 #include <cstddef>
14 #include <clang/AST/DeclBase.h>
15 #include <clang/AST/Decl.h>
16 #include <clang/AST/Type.h>
17 #include <clang/Basic/OperatorKinds.h>
19 #include "compat.hxx"
21 namespace loplugin {
23 class ContextCheck;
24 class TerminalCheck;
26 namespace detail {
28 inline ContextCheck checkRecordDecl(
29 clang::Decl const * decl, clang::TagTypeKind tag, llvm::StringRef id);
33 class DeclCheck;
35 class TypeCheck {
36 public:
37 explicit TypeCheck(clang::QualType type): type_(type) {}
39 explicit TypeCheck(clang::Type const * type): type_(type, 0) {}
41 explicit TypeCheck(clang::TypeDecl const * decl): type_(decl->getTypeForDecl(), 0) {}
43 explicit operator bool() const { return !type_.isNull(); }
45 TypeCheck NonConst() const;
47 TypeCheck NonConstVolatile() const;
49 TypeCheck Const() const;
51 TypeCheck Volatile() const;
53 TypeCheck ConstVolatile() const;
55 TypeCheck ConstNonVolatile() const;
57 TerminalCheck Void() const;
59 TerminalCheck Char() const;
61 TerminalCheck AnyBoolean() const;
63 TypeCheck Pointer() const;
65 TerminalCheck Enum() const;
67 TypeCheck LvalueReference() const;
69 TypeCheck RvalueReference() const;
71 inline ContextCheck Class(llvm::StringRef id) const;
73 inline ContextCheck Struct(llvm::StringRef id) const;
75 inline ContextCheck ClassOrStruct(llvm::StringRef id) const;
77 TypeCheck Typedef() const;
79 inline ContextCheck Typedef(llvm::StringRef id) const;
81 DeclCheck TemplateSpecializationClass() const;
83 TypeCheck NotSubstTemplateTypeParmType() const;
85 private:
86 TypeCheck() = default;
88 clang::QualType const type_{};
91 class DeclCheck {
92 friend TypeCheck;
94 public:
95 explicit DeclCheck(clang::Decl const * decl): decl_(decl) {}
97 explicit operator bool() const { return decl_ != nullptr; }
99 inline ContextCheck Class(llvm::StringRef id) const;
101 inline ContextCheck Struct(llvm::StringRef id) const;
103 inline ContextCheck ClassOrStruct(llvm::StringRef id) const;
105 inline ContextCheck Union(llvm::StringRef id) const;
107 inline ContextCheck Function(llvm::StringRef id) const;
109 ContextCheck Operator(clang::OverloadedOperatorKind op) const;
111 inline ContextCheck Var(llvm::StringRef id) const;
113 ContextCheck MemberFunction() const;
115 private:
116 DeclCheck() = default;
118 clang::Decl const * const decl_ = nullptr;
121 class ContextCheck {
122 public:
123 explicit ContextCheck(clang::DeclContext const * context = nullptr):
124 context_(context) {}
126 explicit operator bool() const { return context_ != nullptr; }
128 TerminalCheck GlobalNamespace() const;
130 inline ContextCheck Namespace(llvm::StringRef id) const;
132 TerminalCheck StdNamespace() const;
134 TerminalCheck StdOrNestedNamespace() const;
136 ContextCheck AnonymousNamespace() const;
138 inline ContextCheck Class(llvm::StringRef id) const;
140 inline ContextCheck Struct(llvm::StringRef id) const;
142 explicit ContextCheck(const clang::NamespaceDecl * decl ) : context_( decl ) {}
144 private:
145 clang::DeclContext const * lookThroughLinkageSpec() const;
147 clang::DeclContext const * const context_;
150 class TerminalCheck {
151 public:
152 explicit operator bool() const { return satisfied_; }
154 private:
155 friend ContextCheck;
156 friend TypeCheck;
158 explicit TerminalCheck(bool satisfied): satisfied_(satisfied) {}
160 bool const satisfied_;
164 typedef std::function<bool(clang::Decl const *)> DeclChecker;
165 // Returns true if the class has a base matching the checker, or, when checkSelf is true, if the
166 // class itself matches.
167 bool isDerivedFrom(const clang::CXXRecordDecl *decl, DeclChecker base, bool checkSelf = true);
170 namespace detail {
172 ContextCheck checkRecordDecl(
173 clang::Decl const * decl, clang::TagTypeKind tag, llvm::StringRef id)
175 auto r = llvm::dyn_cast_or_null<clang::RecordDecl>(decl);
176 if (r != nullptr && r->getTagKind() == tag) {
177 auto const i = r->getIdentifier();
178 if (i != nullptr && i->getName() == id) {
179 return ContextCheck(r->getDeclContext());
182 return ContextCheck();
187 ContextCheck TypeCheck::Class(llvm::StringRef id)
188 const
190 if (!type_.isNull()) {
191 auto const t = type_->getAs<clang::RecordType>();
192 if (t != nullptr) {
193 return detail::checkRecordDecl(t->getDecl(), compat::TagTypeKind::Class, id);
196 return ContextCheck();
199 ContextCheck TypeCheck::Struct(llvm::StringRef id) const
201 if (!type_.isNull()) {
202 auto const t = type_->getAs<clang::RecordType>();
203 if (t != nullptr) {
204 return detail::checkRecordDecl(t->getDecl(), compat::TagTypeKind::Struct, id);
207 return ContextCheck();
210 ContextCheck TypeCheck::ClassOrStruct(llvm::StringRef id) const
212 auto const c1 = Class(id);
213 if (c1) {
214 return c1;
216 return Struct(id);
219 ContextCheck TypeCheck::Typedef(llvm::StringRef id) const
221 if (!type_.isNull()) {
222 if (auto const t = type_->getAs<clang::TypedefType>()) {
223 auto const d = t->getDecl();
224 auto const i = d->getIdentifier();
225 assert(i != nullptr);
226 if (i->getName() == id) {
227 return ContextCheck(d->getDeclContext());
231 return ContextCheck();
234 ContextCheck DeclCheck::Class(llvm::StringRef id) const
236 return detail::checkRecordDecl(decl_, compat::TagTypeKind::Class, id);
239 ContextCheck DeclCheck::Struct(llvm::StringRef id) const
241 return detail::checkRecordDecl(decl_, compat::TagTypeKind::Struct, id);
244 ContextCheck DeclCheck::ClassOrStruct(llvm::StringRef id) const
246 auto const c1 = Class(id);
247 if (c1) {
248 return c1;
250 return Struct(id);
253 ContextCheck DeclCheck::Union(llvm::StringRef id) const
255 return detail::checkRecordDecl(decl_, compat::TagTypeKind::Union, id);
258 ContextCheck DeclCheck::Function(llvm::StringRef id) const
260 auto f = llvm::dyn_cast_or_null<clang::FunctionDecl>(decl_);
261 if (f != nullptr) {
262 auto const i = f->getIdentifier();
263 if (i != nullptr && i->getName() == id) {
264 return ContextCheck(f->getDeclContext());
267 return ContextCheck();
270 ContextCheck DeclCheck::Var(llvm::StringRef id) const
272 auto f = llvm::dyn_cast_or_null<clang::VarDecl>(decl_);
273 if (f != nullptr) {
274 auto const i = f->getIdentifier();
275 if (i != nullptr && i->getName() == id) {
276 return ContextCheck(f->getDeclContext());
279 return ContextCheck();
282 ContextCheck ContextCheck::Namespace(llvm::StringRef id) const
284 if (context_) {
285 auto n = llvm::dyn_cast<clang::NamespaceDecl>(lookThroughLinkageSpec());
286 if (n != nullptr) {
287 auto const i = n->getIdentifier();
288 if (i != nullptr && i->getName() == id) {
289 return ContextCheck(n->getParent());
293 return ContextCheck();
296 ContextCheck ContextCheck::Class(llvm::StringRef id) const
298 return detail::checkRecordDecl(
299 llvm::dyn_cast_or_null<clang::Decl>(context_), compat::TagTypeKind::Class, id);
302 ContextCheck ContextCheck::Struct(llvm::StringRef id) const
304 return detail::checkRecordDecl(
305 llvm::dyn_cast_or_null<clang::Decl>(context_), compat::TagTypeKind::Struct, id);
308 bool isExtraWarnUnusedType(clang::QualType type);
310 bool isOkToRemoveArithmeticCast(
311 clang::ASTContext & context, clang::QualType t1, clang::QualType t2,
312 const clang::Expr* subExpr);
316 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */