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/.
9 #ifndef LO_CLANG_SHARED_PLUGINS
13 #include "clang/AST/Attr.h"
14 #include "clang/AST/CXXInheritance.h"
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();
29 DestType
= DestType
->castAs
<PointerType
>()->getPointeeType();
31 auto DstPTy
= DestType
->getAs
<clang::PointerType
>();
34 DestType
= DstPTy
->getPointeeType();
38 if (DestType
->isVoidType())
42 const CXXRecordDecl
*SrcRD
=
43 cast
<CXXRecordDecl
>(SrcType
->castAs
<RecordType
>()->getDecl());
45 auto SrcRT
= SrcType
->getAs
<RecordType
>();
48 const CXXRecordDecl
*SrcRD
= cast
<CXXRecordDecl
>(SrcRT
->getDecl());
52 if (!SrcRD
->hasAttr
<FinalAttr
>())
57 const CXXRecordDecl
*DestRD
=
58 cast
<CXXRecordDecl
>(DestType
->castAs
<RecordType
>()->getDecl());
60 auto DestRT
= DestType
->getAs
<RecordType
>();
63 const CXXRecordDecl
*DestRD
= cast
<CXXRecordDecl
>(DestRT
->getDecl());
67 if (!(SrcRD
&& DestRD
))
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
; }))
80 if (!SrcRD
->hasAttr
<FinalAttr
>())
85 return !DestRD
->isDerivedFrom(SrcRD
);
87 return !(DestRD
->isDerivedFrom(SrcRD
)
88 || SrcRD
->isDerivedFrom(DestRD
)
94 public loplugin::FilteringPlugin
<FailedDynCast
>
97 explicit FailedDynCast(loplugin::InstantiationData
const & data
):
98 FilteringPlugin(data
) {}
100 bool shouldVisitTemplateInstantiations() const { return true; }
102 bool preRun() override
;
105 bool VisitCXXDynamicCastExpr(CXXDynamicCastExpr
const * expr
);
108 bool FailedDynCast::preRun() {
109 return compiler
.getLangOpts().CPlusPlus
;
112 void FailedDynCast::run() {
114 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
118 bool FailedDynCast::VisitCXXDynamicCastExpr(CXXDynamicCastExpr
const * expr
) {
119 if (ignoreLocation(expr
)) {
122 if (isAlwaysNull(expr
)) {
124 DiagnosticsEngine::Warning
,
125 "dynamic_cast from %0 to %1 always fails", expr
->getBeginLoc())
126 << expr
->getSubExpr()->getType() << expr
->getType()
127 << expr
->getSourceRange();
132 loplugin::Plugin::Registration
<FailedDynCast
> faileddyncast("faileddyncast");
136 #endif // LO_CLANG_SHARED_PLUGINS
138 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */