Quelle constantfunction.cxx
Sprache: C
/* -*- 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/.
*/
#include "plugin.hxx"
#include <iostream>
/*
Look for member functions that merely return a compile - time constant , or they are empty , and can thus
be either removed , or converted into a constant .
This mostly tends to happen as a side - effect of other cleanups .
*/
namespace {
class ConstantFunction:
public loplugin::FilteringPlugin<ConstantFunction>
{
StringRef getFilename(const FunctionDecl* functionDecl);
public :
explicit ConstantFunction(InstantiationData const & data): FilteringRewritePlugin(data) {}
void run() override
{
// these files crash clang-3.5 somewhere in the isEvaluatable/EvaluateAsXXX stuff
/* FileID mainFileID = compiler.getSourceManager().getMainFileID();
if ( strstr ( compiler . getSourceManager ( ) . getFileEntryForID ( mainFileID ) - > getName ( ) , " bootstrapfixture . cxx " ) ! = 0 ) {
return ;
}
if ( strstr ( compiler . getSourceManager ( ) . getFileEntryForID ( mainFileID ) - > getName ( ) , " gtkinst . cxx " ) ! = 0 ) {
return ;
}*/
TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
}
bool VisitFunctionDecl(const FunctionDecl *);
};
StringRef ConstantFunction::getFilename(const FunctionDecl* functionDecl)
{
SourceLocation spellingLocation = compiler.getSourceManager().getSpellingLoc(functionDecl->getCanonicalDecl()->getNameInfo().getLoc());
StringRef name { getFilenameOfLocation(spellingLocation) };
return name;
}
static bool startsWith(const std::string& rStr, const char * pSubStr) {
return rStr.compare(0 , strlen(pSubStr), pSubStr) == 0 ;
}
bool ConstantFunction::VisitFunctionDecl(const FunctionDecl * pFunctionDecl) {
if (ignoreLocation(pFunctionDecl)) {
return true ;
}
if (!pFunctionDecl->hasBody()) {
return true ;
}
if (!pFunctionDecl->isThisDeclarationADefinition()) {
return true ;
}
// stuff declared extern-C is almost always used as a some kind of callback
if (pFunctionDecl->isExternC()) {
return true ;
}
if (pFunctionDecl->isConstexpr()) {
return true ;
}
if (pFunctionDecl->isMain()) {
return true ;
}
StringRef aFileName = getFilename(pFunctionDecl);
// various tests in here are empty stubs under Linux
if (aFileName.startswith(SRCDIR "/sal/qa/" )) {
return true ;
}
// lots of empty stuff here where it looks like someone is still going to "fill in the blanks"
if (aFileName.startswith(SRCDIR "/basegfx/test/" )) {
return true ;
}
// bridges has some weird stuff in it...
if (aFileName.startswith(SRCDIR "/bridges/" )) {
return true ;
}
// dummy implementation of DDE, since it is only active on Windows
if (aFileName == SRCDIR "/svl/unx/source/svdde/ddedummy.cxx"
|| aFileName == SRCDIR "/include/svl/svdde.hxx" ) {
return true ;
}
// fancy templates at work here
if (aFileName == SRCDIR "/vcl/source/gdi/bmpfast.cxx" ) {
return true ;
}
// bunch of stuff used as callbacks here
if (aFileName == SRCDIR "/vcl/generic/glyphs/gcach_layout.cxx" ) {
return true ;
}
// salplug runtime-loading mechanism at work
if (aFileName == SRCDIR "/vcl/inc/salinst.hxx" ) {
return true ;
}
// lots of callbacks here
if (aFileName == SRCDIR "/extensions/source/plugin/unx/npnapi.cxx" ) {
return true ;
}
// vcl/unx/gtk3 re-using vcl/unx/gtk:
if (aFileName.find("/../../gtk/" ) != std::string::npos) {
return true ;
}
// used by code generated by python
if (aFileName == SRCDIR "/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx" ) {
return true ;
}
// this test just test the include of some headers
if (aFileName == SRCDIR "/officecfg/qa/cppheader.cxx" ) {
return true ;
}
// just ignore this for now, people furiously hacking in there
if (startsWith(aFileName, SRCDIR "/libreofficekit" )) {
return true ;
}
const CXXMethodDecl *pCXXMethodDecl = dyn_cast<CXXMethodDecl>(pFunctionDecl);
if (pCXXMethodDecl) {
if (pCXXMethodDecl->isVirtual()) {
return true ;
}
// static with inline body will be optimised at compile-time to a constant anyway
if (pCXXMethodDecl->isStatic() && (pCXXMethodDecl->hasInlineBody() || pCXXMethodDecl->isInlineSpecified())) {
return true ;
}
// this catches some stuff in templates
if (pFunctionDecl->hasAttr<OverrideAttr>()) {
return true ;
}
}
// a free function with an inline body will be optimised at compile-time to a constant anyway
if (!pCXXMethodDecl && pFunctionDecl->isInlineSpecified()) {
return true ;
}
if (isa<CXXConstructorDecl>(pFunctionDecl) || isa<CXXDestructorDecl>(pFunctionDecl) || isa<CXXConversionDecl>(pFunctionDecl)) {
return true ;
}
if (isInUnoIncludeFile(pFunctionDecl)) {
return true ;
}
switch (pFunctionDecl->getOverloadedOperator()) {
case OO_Delete:
case OO_EqualEqual:
case OO_Call:
return true ;
default :
break ;
}
std::string aFunctionName = pFunctionDecl->getQualifiedNameAsString();
// something to do with dynamic loading in sal/textenc/textenc.cxx
if (aFunctionName == "thisModule" ) {
return true ;
}
// an empty stub under certain conditions, sal/osl/unx/thread.cxx
if (aFunctionName == "osl_thread_priority_init_Impl" ) {
return true ;
}
// a pointer to this function is taken and passed to an underlying API, cppu/source/uno/lbenv.cxx
if (aFunctionName == "defenv_dispose" ) {
return true ;
}
// a pointer to this function is taken and passed to an underlying API, cppuhelper/source/exc_thrower.cxx
if (aFunctionName == "ExceptionThrower_acquire_release_nop" ) {
return true ;
}
// used as a callback, /vcl/source/filter/jpeg/JpegReader.cxx
if (aFunctionName == "term_source" ) {
return true ;
}
// only valid for windows, extensions/source/update/check/updatecheck.cxx
if (aFunctionName == "(anonymous namespace)::UpdateCheckThread::hasInternetConnection" ) {
return true ;
}
// used as callback, extensions/source/plugin/unx/npwrap.cxx
if (aFunctionName == "plugin_x_error_handler" || aFunctionName == "noClosure" ) {
return true ;
}
// used as callback, sax/source/expatwrap/sax_expat.cxx
if (aFunctionName == "(anonymous namespace)::SaxExpatParser_Impl::callbackUnknownEncoding" ) {
return true ;
}
// used as callback, i18npool/source/textconversion/textconversion.cxx
if (aFunctionName == "com::sun::star::i18n::nullFunc" ) {
return true ;
}
// used as callback, xmloff/source/text/txtparae.cxx
if (aFunctionName == "(anonymous namespace)::lcl_TextContentsUnfiltered" ) {
return true ;
}
// template magic, include/canvas/verifyinput.hxx
if (aFunctionName == "canvas::tools::verifyInput" ) {
return true ;
}
// template magic, cppcanvas/source/mtfrenderer/implrenderer.cxx
if (aFunctionName == "cppcanvas::internal::(anonymous namespace)::AreaQuery::result" ) {
return true ;
}
// callback, drawinglayer/source/dumper/XShapeDumper.
if (aFunctionName == "(anonymous namespace)::closeCallback" ) {
return true ;
}
// callback, basic/source/runtime/runtime.cxx
if (aFunctionName == "SbiRuntime::StepNOP" ) {
return true ;
}
// DLL stuff, only used on windows, basic/source/runtime/dllmgr.hxx
if (aFunctionName == "SbiDllMgr::FreeDll" ) {
return true ;
}
// only used on Windows, basic/source/sbx/sbxdec.cxx
if (aFunctionName == "SbxDecimal::neg" || aFunctionName == "SbxDecimal::isZero" ) {
return true ;
}
// used as a callback, include/sfx2/shell.hxx
if (aFunctionName == "SfxShell::EmptyExecStub" || aFunctionName == "SfxShell::EmptyStateStub"
|| aFunctionName == "SfxShell::VerbState" ) {
return true ;
}
// SFX_IMPL_POS_CHILDWINDOW_WITHID macro
if (aFunctionName.find("GetChildWindowId" ) != std::string::npos) {
return true ;
}
// SFX_IMPL_SUPERCLASS_INTERFACE macro
if (aFunctionName.find("InitInterface_Impl" ) != std::string::npos) {
return true ;
}
// callback, vcl/unx/generic/app/sm.cxx
if (aFunctionName == "IgnoreIceIOErrors" || aFunctionName == "IgnoreIceErrors" ) {
return true ;
}
// callback, vcl/unx/gtk/a11y/atkcomponent.cxx
if (aFunctionName == "component_wrapper_get_mdi_zorder" ) {
return true ;
}
// callback, vcl/unx/gtk/a11y/atkaction.cxx
if (aFunctionName == "action_wrapper_set_description" ) {
return true ;
}
// callback, vcl/unx/gtk/a11y/atkutil.cxx
if (aFunctionName == "ooo_atk_util_get_toolkit_version" || aFunctionName == "ooo_atk_util_get_toolkit_name" ) {
return true ;
}
// callback, vcl/unx/gtk/a11y/atktextattributes.cxx
if (aFunctionName == "InvalidValue" ) {
return true ;
}
// callback, vcl/unx/gtk/a11y/atktable.cxx
if (aFunctionName == "table_wrapper_set_summary" || aFunctionName == "table_wrapper_set_row_header"
|| aFunctionName == "table_wrapper_set_row_description"
|| aFunctionName == "table_wrapper_set_column_header"
|| aFunctionName == "table_wrapper_set_column_description"
|| aFunctionName == "table_wrapper_set_caption" ) {
return true ;
}
// callbacks, vcl/unx/gtk/window/gtksalframe.cxx
if (startsWith(aFunctionName, "GtkSalFrame::IMHandler::signal" )) {
return true ;
}
// callbacks, vcl/unx/gtk/window/glomenu.cxx
if (startsWith(aFunctionName, "g_lo_menu_is_mutable" )) {
return true ;
}
// only contains code for certain versions of GTK, /vcl/unx/gtk/window/gtksalframe.cx
if (aFunctionName == "GtkSalFrame::AllocateFrame" ) {
return true ;
}
// only valid for Windows, embeddedobj/source/msole/olemisc.cxx
if (aFunctionName == "OleEmbeddedObject::GetRidOfComponent" ) {
return true ;
}
// callback, svx/source/accessibility/ShapeTypeHandler.cxx
if (aFunctionName == "accessibility::CreateEmptyShapeReference" ) {
return true ;
}
// chart2/source/view/main/AbstractShapeFactory.cxx
if (aFunctionName == "chart::(anonymous namespace)::thisModule" ) {
return true ;
}
// chart2/source/tools/InternalData.cxx
if (aFunctionName == "chart::InternalData::dump" ) {
return true ;
}
// hwpfilter/
if (aFunctionName == "debug" || aFunctionName == "token_debug" ) {
return true ;
}
// callback, sdext/source/presenter/PresenterFrameworkObserver.cxx
if (aFunctionName == "sdext::presenter::PresenterFrameworkObserver::True" ) {
return true ;
}
// callback, sw/source/core/doc/tblrwcl.cxx
if (aFunctionName == "lcl_DelOtherBox" ) {
return true ;
}
// callback, sw/source/filter/ww8/ww8par.cxx
if (aFunctionName == "SwWW8ImplReader::Read_Majority" ) {
return true ;
}
// callback, sw/source/filter/ww8/ww8par5.cxx
if (aFunctionName == "SwWW8ImplReader::Read_F_Shape" ) {
return true ;
}
// called from SDI file, I don't know what that stuff is about, sd/source/ui/slidesorter/shell/SlideSorterViewShell.cx
if (aFunctionName == "sd::slidesorter::SlideSorterViewShell::ExecStatusBar"
|| aFunctionName == "sd::OutlineViewShell::ExecStatusBar" ) {
return true ;
}
// only used in debug mode, sd/source/filter/ppt/pptinanimations.cxx
if (startsWith(aFunctionName, "ppt::AnimationImporter::dump" )) {
return true ;
}
// only used in ENABLE_SDREMOTE_BLUETOOTH mode, sd/source/ui/dlg/tpoption.cx
if (aFunctionName == "SdTpOptionsMisc::SetImpressMode" ) {
return true ;
}
// template magic, sc/source/ui/docshell/datastream.cxx
if (startsWith(aFunctionName, "sc::(anonymous namespace)::CSVHandler::" )) {
return true ;
}
// called from SDI file, I don't know what that stuff is about, sc/source/ui/view/cellsh4.cxx
if (aFunctionName == "ScCellShell::GetStateCursor" ) {
return true ;
}
// template magic, sc/source/filter/excel/xepivot.cxx
if (aFunctionName == "XclExpPivotCache::SaveXml" ) {
return true ;
}
// template magic, sc/source/filter/html/htmlpars.cxx
if (startsWith(aFunctionName, "(anonymous namespace)::CSSHandler::" )) {
return true ;
}
// callbacks, sc/source/filter/oox/formulaparser.cxx
if (startsWith(aFunctionName, "oox::xls::BiffFormulaParserImpl::import" )) {
return true ;
}
// template magic, sc/qa/unit/helper/csv_handler.hxx
if (startsWith(aFunctionName, "csv_handler::" ) || startsWith(aFunctionName, "conditional_format_handler::" )) {
return true ;
}
// template magic, slideshow/source/inc/listenercontainer.hxx
if (startsWith(aFunctionName, "slideshow::internal::EmptyBase::EmptyClearableGuard::" )) {
return true ;
}
// callback, scripting/source/vbaevents/eventhelper.cxx
if (aFunctionName == "ApproveAll" ) {
return true ;
}
// only on WNT, basic/qa/cppunit/test_vba.cx
if (aFunctionName == "(anonymous namespace)::VBATest::testMiscOLEStuff" ) {
return true ;
}
// GtkSalFrame::TriggerPaintEvent() is only compiled under certain versions of GTK
if (aFunctionName == "GtkSalFrame::TriggerPaintEvent" ) {
return true ;
}
if (aFunctionName == "SwVectorModifyBase::dumpAsXml" ) {
return true ;
}
// vcl/unx/gtk3 re-using vcl/unx/gtk:
if (aFunctionName == "DeInitAtkBridge"
|| aFunctionName == "GtkData::initNWF"
|| aFunctionName == "GtkSalFrame::EnsureAppMenuWatch"
|| aFunctionName == "InitAtkBridge" )
{
return true ;
}
if (aFunctionName == "sc::AlignedAllocator::operator!=" ) {
return true ;
}
if (aFunctionName == "clipboard_owner_init" ) {
return true ;
}
// returns sizeof(struct) vcl/source/gdi/dibtools.cxx
if (aFunctionName == "getDIBV5HeaderSize" ) {
return true ;
}
// windows only
if (aFunctionName == "InitAccessBridge" ) {
return true ;
}
// callbacks
if (aFunctionName == "disabled_initSystray" || aFunctionName == "disabled_deInitSystray" ) {
return true ;
}
// behind a BREAKPAD option
if (aFunctionName == "desktop::(anonymous namespace)::crashReportInfoExists" ) {
return true ;
}
// LOK stuff
if (aFunctionName == "doc_getTileMode" ) {
return true ;
}
// apparently this will be useful at sometime in the future
if (aFunctionName == "LocaleDataWrapper::getCurrZeroChar" ) {
return true ;
}
// marked with TODO
if (aFunctionName == "oglcanvas::TextLayout::draw" ) {
return true ;
}
// called from the .sdi files
if (aFunctionName == "SfxObjectShell::StateView_Impl" ) {
return true ;
}
// gtk callback
if (aFunctionName == "GtkSalFrame::signalVisibility" ) {
return true ;
}
// platform-version-dependent code
if (aFunctionName == "(anonymous namespace)::ACTIVE_TAB" ) {
return true ;
}
// SMIL callbacks
if (aFunctionName == "boost::sp_scalar_constructor_hook" || aFunctionName == "boost::sp_scalar_destructor_hook" ) {
return true ;
}
std::string aImmediateMacro = "" ;
if (compiler.getSourceManager().isMacroBodyExpansion(pFunctionDecl->getLocStart()) ) {
StringRef name { Lexer::getImmediateMacroName(
pFunctionDecl->getLocStart(), compiler.getSourceManager(), compiler.getLangOpts()) };
aImmediateMacro = name;
if (name.startswith("IMPL_LINK_" ) )
{
return true ;
}
}
const CompoundStmt *pCompoundStmt = dyn_cast<CompoundStmt>(pFunctionDecl->getBody());
bool bEmptyBody = false ;
if (pCompoundStmt) {
if (pCompoundStmt->size() > 1 ) {
return true ;
}
if (pCompoundStmt->size() > 0 ) {
const ReturnStmt *pReturnStmt = dyn_cast<ReturnStmt>(*pCompoundStmt->body_begin());
if (!pReturnStmt) {
return true ;
}
if (const UnaryOperator* unaryOp = dyn_cast<UnaryOperator>(pReturnStmt->getRetValue())) {
if (unaryOp->getOpcode() == UO_AddrOf) {
return true ;
}
}
if (pReturnStmt->getRetValue() != nullptr) {
// && !pReturnStmt->getRetValue()->isEvaluatable(compiler.getASTContext())) {
bool aBoolResult;
llvm::APSInt aIntResult;
if (pReturnStmt->getRetValue()->isTypeDependent()
|| (!pReturnStmt->getRetValue()->EvaluateAsBooleanCondition(aBoolResult, compiler.getASTContext())
&& !pReturnStmt->getRetValue()->EvaluateAsInt(aIntResult, compiler.getASTContext())))
{
return true ;
}
}
} else {
bEmptyBody = true ;
}
}
std::string aMessage = "this " ;
aMessage += pCXXMethodDecl ? "method" : "function" ;
if (bEmptyBody) {
aMessage += " is empty and should be removed, " + aFunctionName;
} else {
aMessage += " returns a constant value and should be converted to a constant "
"or to static inline, " + aFunctionName + ", " + aImmediateMacro;
}
report(
DiagnosticsEngine::Warning,
aMessage,
pFunctionDecl->getLocStart())
<< pFunctionDecl->getSourceRange();
if (pFunctionDecl != pFunctionDecl->getCanonicalDecl())
report(
DiagnosticsEngine::Note,
aMessage,
pFunctionDecl->getCanonicalDecl()->getLocStart())
<< pFunctionDecl->getCanonicalDecl()->getSourceRange();
return true ;
}
loplugin::Plugin::Registration<ConstantFunction> X("constantfunction" );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=84 H=100 G=92
¤ Dauer der Verarbeitung: 0.26 Sekunden
(vorverarbeitet am 2026-09-30)
¤
*© Formatika GbR, Deutschland
2026-10-10
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1126864
#Domains=1897691