tdf#130857 qt weld: Support "Insert Breaks" dialog
[LibreOffice.git] / compilerplugins / clang / crosscast.cxx
blob293b8646d1522aabe3b97fca6732d69fdfacb114
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 // Find uses of dynamic_cast that cast between unrelated classes, which is suspicious and might
11 // indicate a bug. The heuristic used to consider two classes unrelated is that neither derives
12 // from the other (directly or indirectly) and they do not both virtually derive (directly or
13 // indirectly) from a common third class. Additionally, class definitions can be attributed with
14 // SAL_LOPLUGIN_ANNOTATE("crosscast") (from sal/types.h) to suppress false warnings about known-good
15 // cases casting from or to such a class.
17 #ifndef LO_CLANG_SHARED_PLUGINS
19 #include <cassert>
20 #include <set>
22 #include "compat.hxx"
23 #include "plugin.hxx"
25 namespace
27 void computeVirtualBases(CXXRecordDecl const* decl, std::set<CXXRecordDecl const*>* vbases)
29 assert(vbases != nullptr);
30 for (auto const& i : decl->bases())
32 auto const d = i.getType()->getAsCXXRecordDecl();
33 if (d == nullptr)
35 continue;
37 if (i.isVirtual())
39 if (!vbases->insert(d->getCanonicalDecl()).second)
41 // As we track the already computed virtual bases in vbases anyway, we can cheaply
42 // optimize the case where we see a virtual base again, even though we don't bother
43 // to optimize the case where we see a non-virtual base multiple times:
44 continue;
47 computeVirtualBases(d, vbases);
51 bool compareVirtualBases(CXXRecordDecl const* decl, std::set<CXXRecordDecl const*>& vbases)
53 for (auto const& i : decl->bases())
55 auto const d = i.getType()->getAsCXXRecordDecl();
56 if (d == nullptr)
58 continue;
60 if (i.isVirtual() && vbases.count(d->getCanonicalDecl()) == 1)
62 return true;
64 if (compareVirtualBases(d, vbases))
66 return true;
69 return false;
72 bool haveCommonVirtualBase(CXXRecordDecl const* decl1, CXXRecordDecl const* decl2)
74 std::set<CXXRecordDecl const*> vbases;
75 computeVirtualBases(decl1, &vbases);
76 return compareVirtualBases(decl2, vbases);
79 bool isAllowedInCrossCasts(CXXRecordDecl const* decl)
81 auto const def = decl->getDefinition();
82 if (def == nullptr)
84 return false;
86 for (auto const attr : def->specific_attrs<AnnotateAttr>())
88 if (attr->getAnnotation() == "loplugin:crosscast")
90 return true;
93 return false;
96 class CrossCast final : public loplugin::FilteringPlugin<CrossCast>
98 public:
99 explicit CrossCast(loplugin::InstantiationData const& data)
100 : FilteringPlugin(data)
104 bool preRun() override { return compiler.getLangOpts().CPlusPlus; }
106 void run() override
108 if (preRun())
110 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
114 bool VisitCXXDynamicCastExpr(CXXDynamicCastExpr const* expr)
116 if (ignoreLocation(expr))
118 return true;
120 auto const t2 = expr->getTypeAsWritten();
121 if (t2->isVoidPointerType())
123 return true;
125 auto const d2 = t2->getPointeeCXXRecordDecl();
126 if (d2 == nullptr)
128 return true;
130 auto const t1 = compat::getSubExprAsWritten(expr)->getType();
131 auto t1a = t1;
132 if (auto const t = t1a->getAs<clang::PointerType>())
134 t1a = t->getPointeeType();
136 auto const d1 = t1a->getAsCXXRecordDecl();
137 if (d1 == nullptr)
139 return true;
141 if (d1->getCanonicalDecl() == d2->getCanonicalDecl() || d1->isDerivedFrom(d2)
142 || d2->isDerivedFrom(d1) || haveCommonVirtualBase(d1, d2))
144 return true;
146 if (isAllowedInCrossCasts(d1) || isAllowedInCrossCasts(d2))
148 return true;
150 if (suppressWarningAt(expr->getBeginLoc()))
152 return true;
154 report(DiagnosticsEngine::Warning, "suspicious dynamic cross cast from %0 to %1",
155 expr->getExprLoc())
156 << t1 << t2 << expr->getSourceRange();
157 return true;
161 loplugin::Plugin::Registration<CrossCast> crosscast("crosscast");
164 #endif
166 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */