/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef LO_CLANG_SHARED_PLUGINS #include #include "clang/AST/Attr.h" #include "clang/AST/CXXInheritance.h" #include "plugin.hxx" namespace { // cf. Clang's clang::AST::CXXDynamicCastExpr::isAlwaysNull // (lib/AST/ExprCXX.cpp): bool isAlwaysNull(CXXDynamicCastExpr const * expr) { QualType SrcType = expr->getSubExpr()->getType(); QualType DestType = expr->getType(); if (const clang::PointerType *SrcPTy = SrcType->getAs()) { SrcType = SrcPTy->getPointeeType(); #if 0 DestType = DestType->castAs()->getPointeeType(); #else auto DstPTy = DestType->getAs(); if (!DstPTy) return false; DestType = DstPTy->getPointeeType(); #endif } if (DestType->isVoidType()) return false; #if 0 const CXXRecordDecl *SrcRD = cast(SrcType->castAs()->getDecl()); #else auto SrcRT = SrcType->getAs(); if (!SrcRT) return false; const CXXRecordDecl *SrcRD = cast(SrcRT->getDecl()); #endif #if 0 if (!SrcRD->hasAttr()) return false; #endif #if 0 const CXXRecordDecl *DestRD = cast(DestType->castAs()->getDecl()); #else auto DestRT = DestType->getAs(); if (!DestRT) return false; const CXXRecordDecl *DestRD = cast(DestRT->getDecl()); #endif #if 1 if (!(SrcRD && DestRD)) return false; if (DestRD->hasAttr()) { CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, /*DetectVirtual=*/false); if (DestRD->isDerivedFrom(SrcRD, Paths) && std::all_of(Paths.begin(), Paths.end(), [](CXXBasePath const & Path) { return Path.Access != AS_public; })) return true; } if (!SrcRD->hasAttr()) return false; #endif #if 0 return !DestRD->isDerivedFrom(SrcRD); #else return !(DestRD->isDerivedFrom(SrcRD) || SrcRD->isDerivedFrom(DestRD) || SrcRD == DestRD); #endif } class FailedDynCast: public loplugin::FilteringPlugin { public: explicit FailedDynCast(loplugin::InstantiationData const & data): FilteringPlugin(data) {} bool shouldVisitTemplateInstantiations() const { return true; } bool preRun() override; void run() override; bool VisitCXXDynamicCastExpr(CXXDynamicCastExpr const * expr); }; bool FailedDynCast::preRun() { return compiler.getLangOpts().CPlusPlus; } void FailedDynCast::run() { if (preRun()) { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); } } bool FailedDynCast::VisitCXXDynamicCastExpr(CXXDynamicCastExpr const * expr) { if (ignoreLocation(expr)) { return true; } if (isAlwaysNull(expr)) { report( DiagnosticsEngine::Warning, "dynamic_cast from %0 to %1 always fails", compat::getBeginLoc(expr)) << expr->getSubExpr()->getType() << expr->getType() << expr->getSourceRange(); } return true; } loplugin::Plugin::Registration faileddyncast("faileddyncast"); } // namespace #endif // LO_CLANG_SHARED_PLUGINS /* vim:set shiftwidth=4 softtabstop=4 expandtab: */