2016-06-22 12:08:45 +02:00
/* -*- 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/.
*/
2019-09-18 14:15:59 +02:00
# ifndef LO_CLANG_SHARED_PLUGINS
2016-06-22 12:08:45 +02:00
# include <string>
# include <iostream>
# include "plugin.hxx"
# include "compat.hxx"
# include "clang/AST/CXXInheritance.h"
// Check for calls to virtual methods from destructors. These are dangerous because intention might be to call
// a method on a subclass, while in actual fact, it only calls the method on the current or super class.
//
namespace {
class FragileDestructor :
2018-08-23 14:35:15 +02:00
public loplugin : : FilteringPlugin < FragileDestructor >
2016-06-22 12:08:45 +02:00
{
public :
2017-11-07 11:50:47 +01:00
explicit FragileDestructor ( loplugin : : InstantiationData const & data ) :
2018-08-23 14:35:15 +02:00
FilteringPlugin ( data ) { }
2016-06-22 12:08:45 +02:00
2019-09-18 14:15:59 +02:00
virtual bool preRun ( ) override
{
StringRef fn ( handler . getMainFileName ( ) ) ;
// TODO, these all need fixing
if ( loplugin : : isSamePathname ( fn , SRCDIR " /comphelper/source/misc/proxyaggregation.cxx " ) )
return false ;
if ( loplugin : : isSamePathname ( fn , SRCDIR " /svx/source/svdraw/svdpntv.cxx " ) ) // ~SdrPaintView calling ClearPageView
return false ;
if ( loplugin : : isSamePathname ( fn , SRCDIR " /svx/source/svdraw/svdobj.cxx " ) ) // ~SdrObject calling GetLastBoundRect
return false ;
if ( loplugin : : isSamePathname ( fn , SRCDIR " /svx/source/svdraw/svdedxv.cxx " ) ) // ~SdrObjEditView calling SdrEndTextEdit
return false ;
if ( loplugin : : isSamePathname ( fn , SRCDIR " /connectivity/source/drivers/file/FStatement.cxx " ) ) // ~OStatement_Base calling disposing
return false ;
if ( loplugin : : isSamePathname ( fn , SRCDIR " /sd/source/core/CustomAnimationEffect.cxx " ) ) // ~EffectSequenceHelper calling reset
return false ;
if ( loplugin : : isSamePathname ( fn , SRCDIR " /sd/source/ui/view/sdview.cxx " ) ) // ~View calling DeleteWindowFromPaintView
return false ;
if ( loplugin : : isSamePathname ( fn , SRCDIR " /sw/source/core/layout/ssfrm.cxx " ) ) // ~SwFrame calling IsDeleteForbidden
return false ;
2021-05-31 08:30:38 +02:00
if ( loplugin : : isSamePathname ( fn , SRCDIR " /chart2/source/model/template/CandleStickChartType.cxx " ) ) // to ignore <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100797> "[10/11/12 Regression] using declaration causing virtual call with wrongly adjusted this pointer" workaround
2021-05-26 14:44:02 +01:00
return false ;
2016-06-22 12:08:45 +02:00
2019-09-18 14:15:59 +02:00
return true ;
}
virtual void run ( ) override
{
if ( preRun ( ) )
TraverseDecl ( compiler . getASTContext ( ) . getTranslationUnitDecl ( ) ) ;
}
2016-06-22 12:08:45 +02:00
2019-09-18 14:15:59 +02:00
bool PreTraverseCXXDestructorDecl ( CXXDestructorDecl * ) ;
bool PostTraverseCXXDestructorDecl ( CXXDestructorDecl * , bool ) ;
bool TraverseCXXDestructorDecl ( CXXDestructorDecl * ) ;
2016-06-22 12:08:45 +02:00
bool VisitCXXMemberCallExpr ( const CXXMemberCallExpr * ) ;
private :
2019-09-18 14:15:59 +02:00
std : : vector < CXXDestructorDecl * > m_vDestructors ;
2016-06-22 12:08:45 +02:00
} ;
2019-09-18 14:15:59 +02:00
bool FragileDestructor : : PreTraverseCXXDestructorDecl ( CXXDestructorDecl * cxxDestructorDecl )
2016-06-22 12:08:45 +02:00
{
2019-09-18 14:15:59 +02:00
if ( ignoreLocation ( cxxDestructorDecl ) )
return true ;
if ( ! cxxDestructorDecl - > isThisDeclarationADefinition ( ) )
return true ;
if ( cxxDestructorDecl - > getParent ( ) - > hasAttr < FinalAttr > ( ) )
return true ;
m_vDestructors . push_back ( cxxDestructorDecl ) ;
return true ;
}
bool FragileDestructor : : PostTraverseCXXDestructorDecl ( CXXDestructorDecl * cxxDestructorDecl , bool )
{
if ( ! m_vDestructors . empty ( ) & & m_vDestructors . back ( ) = = cxxDestructorDecl )
m_vDestructors . pop_back ( ) ;
return true ;
}
bool FragileDestructor : : TraverseCXXDestructorDecl ( CXXDestructorDecl * cxxDestructorDecl )
{
PreTraverseCXXDestructorDecl ( cxxDestructorDecl ) ;
auto ret = FilteringPlugin : : TraverseCXXDestructorDecl ( cxxDestructorDecl ) ;
PostTraverseCXXDestructorDecl ( cxxDestructorDecl , ret ) ;
2016-07-12 11:31:25 +02:00
return ret ;
2016-06-22 12:08:45 +02:00
}
bool FragileDestructor : : VisitCXXMemberCallExpr ( const CXXMemberCallExpr * callExpr )
{
2019-09-18 14:15:59 +02:00
if ( m_vDestructors . empty ( ) | | ignoreLocation ( callExpr ) )
2016-06-22 12:08:45 +02:00
return true ;
const CXXMethodDecl * methodDecl = callExpr - > getMethodDecl ( ) ;
2019-09-18 14:15:59 +02:00
if ( ! methodDecl - > isVirtual ( ) | | methodDecl - > hasAttr < FinalAttr > ( ) )
2016-06-22 12:08:45 +02:00
return true ;
const CXXRecordDecl * parentRecordDecl = methodDecl - > getParent ( ) ;
2019-09-18 14:15:59 +02:00
if ( parentRecordDecl - > hasAttr < FinalAttr > ( ) )
2016-06-22 12:08:45 +02:00
return true ;
2019-09-18 14:15:59 +02:00
if ( ! callExpr - > getImplicitObjectArgument ( ) - > IgnoreImpCasts ( ) - > isImplicitCXXThis ( ) )
2016-06-22 12:08:45 +02:00
return true ;
2019-09-18 14:15:59 +02:00
2017-11-13 00:20:20 +01:00
// if we see an explicit call to its own method, that's OK
2018-08-10 12:35:21 +02:00
auto s1 = compiler . getSourceManager ( ) . getCharacterData ( compat : : getBeginLoc ( callExpr ) ) ;
auto s2 = compiler . getSourceManager ( ) . getCharacterData ( compat : : getEndLoc ( callExpr ) ) ;
2016-06-22 12:08:45 +02:00
std : : string tok ( s1 , s2 - s1 ) ;
2019-09-18 14:15:59 +02:00
if ( tok . find ( " :: " ) ! = std : : string : : npos )
2016-06-22 12:08:45 +02:00
return true ;
2019-09-18 14:15:59 +02:00
// Very common pattern that we call acquire/dispose in destructors of UNO objects
// to make sure they are cleaned up.
if ( methodDecl - > getName ( ) = = " acquire " | | methodDecl - > getName ( ) = = " dispose " )
2016-06-22 12:08:45 +02:00
return true ;
2019-09-18 14:15:59 +02:00
2016-06-22 12:08:45 +02:00
report (
DiagnosticsEngine : : Warning ,
2018-09-20 11:17:00 +02:00
" calling virtual method from destructor, either make the virtual method final, or make this class final " ,
2018-08-10 12:35:21 +02:00
compat : : getBeginLoc ( callExpr ) )
2016-06-22 12:08:45 +02:00
< < callExpr - > getSourceRange ( ) ;
report (
DiagnosticsEngine : : Note ,
" callee method here " ,
2018-08-10 12:35:21 +02:00
compat : : getBeginLoc ( methodDecl ) )
2016-06-22 12:08:45 +02:00
< < methodDecl - > getSourceRange ( ) ;
return true ;
}
2019-09-18 14:15:59 +02:00
loplugin : : Plugin : : Registration < FragileDestructor > fragiledestructor ( " fragiledestructor " ) ;
2016-06-22 12:08:45 +02:00
}
2019-09-18 14:15:59 +02:00
# endif // LO_CLANG_SHARED_PLUGINS
2016-06-22 12:08:45 +02:00
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */