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/Attr.h"
13 #include "clang/AST/CXXInheritance.h"
19 // cf. Clang's clang::AST::CXXDynamicCastExpr::isAlwaysNull
20 // (lib/AST/ExprCXX.cpp):
21 bool isAlwaysNull(CXXDynamicCastExpr
const * expr
) {
22 QualType SrcType
= expr
->getSubExpr()->getType();
23 QualType DestType
= expr
->getType();
25 if (const clang::PointerType
*SrcPTy
= SrcType
->getAs
<clang::PointerType
>()) {
26 SrcType
= SrcPTy
->getPointeeType();
28 DestType
= DestType
->castAs
<PointerType
>()->getPointeeType();
30 auto DstPTy
= DestType
->getAs
<clang::PointerType
>();
33 DestType
= DstPTy
->getPointeeType();
37 if (DestType
->isVoidType())
41 const CXXRecordDecl
*SrcRD
=
42 cast
<CXXRecordDecl
>(SrcType
->castAs
<RecordType
>()->getDecl());
44 auto SrcRT
= SrcType
->getAs
<RecordType
>();
47 const CXXRecordDecl
*SrcRD
= cast
<CXXRecordDecl
>(SrcRT
->getDecl());
51 if (!SrcRD
->hasAttr
<FinalAttr
>())
56 const CXXRecordDecl
*DestRD
=
57 cast
<CXXRecordDecl
>(DestType
->castAs
<RecordType
>()->getDecl());
59 auto DestRT
= DestType
->getAs
<RecordType
>();
62 const CXXRecordDecl
*DestRD
= cast
<CXXRecordDecl
>(DestRT
->getDecl());
66 if (!(SrcRD
&& DestRD
))
69 if (DestRD
->hasAttr
<FinalAttr
>()) {
70 CXXBasePaths
Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true,
71 /*DetectVirtual=*/false);
72 if (DestRD
->isDerivedFrom(SrcRD
, Paths
) &&
73 std::all_of(Paths
.begin(), Paths
.end(),
74 [](CXXBasePath
const & Path
) {
75 return Path
.Access
!= AS_public
; }))
79 if (!SrcRD
->hasAttr
<FinalAttr
>())
84 return !DestRD
->isDerivedFrom(SrcRD
);
86 return !(DestRD
->isDerivedFrom(SrcRD
)
87 || SrcRD
->isDerivedFrom(DestRD
)
93 public RecursiveASTVisitor
<FailedDynCast
>, public loplugin::Plugin
96 explicit FailedDynCast(loplugin::InstantiationData
const & data
):
99 bool shouldVisitTemplateInstantiations() const { return true; }
103 bool VisitCXXDynamicCastExpr(CXXDynamicCastExpr
const * expr
);
106 void FailedDynCast::run() {
107 if (compiler
.getLangOpts().CPlusPlus
) {
108 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
112 bool FailedDynCast::VisitCXXDynamicCastExpr(CXXDynamicCastExpr
const * expr
) {
113 if (ignoreLocation(expr
)) {
116 if (isAlwaysNull(expr
)) {
118 DiagnosticsEngine::Warning
,
119 "dynamic_cast from %0 to %1 always fails", expr
->getLocStart())
120 << expr
->getSubExpr()->getType() << expr
->getType()
121 << expr
->getSourceRange();
126 loplugin::Plugin::Registration
<FailedDynCast
> X("faileddyncast");
130 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */