update credits
[LibreOffice.git] / compilerplugins / clang / faileddyncast.cxx
blob078d5c884b27e46e3e98a2b86b2a010460657e81
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 */
9 #ifndef LO_CLANG_SHARED_PLUGINS
11 #include <algorithm>
13 #include "clang/AST/Attr.h"
14 #include "clang/AST/CXXInheritance.h"
16 #include "plugin.hxx"
18 namespace {
20 // cf. Clang's clang::AST::CXXDynamicCastExpr::isAlwaysNull
21 // (lib/AST/ExprCXX.cpp):
22 bool isAlwaysNull(CXXDynamicCastExpr const * expr) {
23 QualType SrcType = expr->getSubExpr()->getType();
24 QualType DestType = expr->getType();
26 if (const clang::PointerType *SrcPTy = SrcType->getAs<clang::PointerType>()) {
27 SrcType = SrcPTy->getPointeeType();
28 #if 0
29 DestType = DestType->castAs<PointerType>()->getPointeeType();
30 #else
31 auto DstPTy = DestType->getAs<clang::PointerType>();
32 if (!DstPTy)
33 return false;
34 DestType = DstPTy->getPointeeType();
35 #endif
38 if (DestType->isVoidType())
39 return false;
41 #if 0
42 const CXXRecordDecl *SrcRD =
43 cast<CXXRecordDecl>(SrcType->castAs<RecordType>()->getDecl());
44 #else
45 auto SrcRT = SrcType->getAs<RecordType>();
46 if (!SrcRT)
47 return false;
48 const CXXRecordDecl *SrcRD = cast<CXXRecordDecl>(SrcRT->getDecl());
49 #endif
51 #if 0
52 if (!SrcRD->hasAttr<FinalAttr>())
53 return false;
54 #endif
56 #if 0
57 const CXXRecordDecl *DestRD =
58 cast<CXXRecordDecl>(DestType->castAs<RecordType>()->getDecl());
59 #else
60 auto DestRT = DestType->getAs<RecordType>();
61 if (!DestRT)
62 return false;
63 const CXXRecordDecl *DestRD = cast<CXXRecordDecl>(DestRT->getDecl());
64 #endif
66 #if 1
67 if (!(SrcRD && DestRD))
68 return false;
70 if (DestRD->hasAttr<FinalAttr>()) {
71 CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true,
72 /*DetectVirtual=*/false);
73 if (DestRD->isDerivedFrom(SrcRD, Paths) &&
74 std::all_of(Paths.begin(), Paths.end(),
75 [](CXXBasePath const & Path) {
76 return Path.Access != AS_public; }))
77 return true;
80 if (!SrcRD->hasAttr<FinalAttr>())
81 return false;
82 #endif
84 #if 0
85 return !DestRD->isDerivedFrom(SrcRD);
86 #else
87 return !(DestRD->isDerivedFrom(SrcRD)
88 || SrcRD->isDerivedFrom(DestRD)
89 || SrcRD == DestRD);
90 #endif
93 class FailedDynCast:
94 public loplugin::FilteringPlugin<FailedDynCast>
96 public:
97 explicit FailedDynCast(loplugin::InstantiationData const & data):
98 FilteringPlugin(data) {}
100 bool shouldVisitTemplateInstantiations() const { return true; }
102 bool preRun() override;
103 void run() override;
105 bool VisitCXXDynamicCastExpr(CXXDynamicCastExpr const * expr);
108 bool FailedDynCast::preRun() {
109 return compiler.getLangOpts().CPlusPlus;
112 void FailedDynCast::run() {
113 if (preRun()) {
114 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
118 bool FailedDynCast::VisitCXXDynamicCastExpr(CXXDynamicCastExpr const * expr) {
119 if (ignoreLocation(expr)) {
120 return true;
122 if (isAlwaysNull(expr)) {
123 report(
124 DiagnosticsEngine::Warning,
125 "dynamic_cast from %0 to %1 always fails", expr->getBeginLoc())
126 << expr->getSubExpr()->getType() << expr->getType()
127 << expr->getSourceRange();
129 return true;
132 loplugin::Plugin::Registration<FailedDynCast> faileddyncast("faileddyncast");
134 } // namespace
136 #endif // LO_CLANG_SHARED_PLUGINS
138 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */