From e075ee967d0c030a22b7699ee54b5cbd49c07c17 Mon Sep 17 00:00:00 2001 From: Noel Grandin Date: Thu, 29 Mar 2018 13:49:19 +0200 Subject: give DBG_UNHANDLED_EXCEPTION_WHEN an area parameter and rename it to DBG_UNHANDLED_EXCEPTION, to make it more like the SAL_WARN-type macros. Use some macro magic to deal with different numbers of arguments. Update the sallogareas plugin to check the area parameter of DBG_UNHANDLED_EXCEPTION. Change-Id: Ie790223244c3484f41acb3679c043fb9b438e7c4 Reviewed-on: https://gerrit.libreoffice.org/52073 Tested-by: Jenkins Reviewed-by: Noel Grandin --- compilerplugins/clang/sallogareas.cxx | 107 +++++++++++++++++------------ compilerplugins/clang/test/sallogareas.cxx | 58 ++++++++++++++++ 2 files changed, 121 insertions(+), 44 deletions(-) create mode 100644 compilerplugins/clang/test/sallogareas.cxx (limited to 'compilerplugins/clang') diff --git a/compilerplugins/clang/sallogareas.cxx b/compilerplugins/clang/sallogareas.cxx index 98cafb596fd5..1095302d9ada 100644 --- a/compilerplugins/clang/sallogareas.cxx +++ b/compilerplugins/clang/sallogareas.cxx @@ -49,54 +49,73 @@ bool SalLogAreas::VisitCallExpr( const CallExpr* call ) { if( ignoreLocation( call )) return true; - if( const FunctionDecl* func = call->getDirectCallee()) + const FunctionDecl* func = call->getDirectCallee(); + if( !func ) + return true; + + if( !( func->getNumParams() == 5 && func->getIdentifier() != NULL + && ( func->getName() == "sal_detail_log" || func->getName() == "log" || func->getName() == "DbgUnhandledException")) ) + return true; + + auto tc = loplugin::DeclCheck(func); + enum class LogCallKind { Sal, DbgUnhandledException}; + LogCallKind kind; + int areaArgIndex; + if( tc.Function("sal_detail_log") || tc.Function("log").Namespace("detail").Namespace("sal").GlobalNamespace() ) + { + kind = LogCallKind::Sal; // fine + areaArgIndex = 1; + } + else if( tc.Function("DbgUnhandledException").GlobalNamespace() ) + { + kind = LogCallKind::DbgUnhandledException; // ok + areaArgIndex = 3; + } + else + return true; + + // The SAL_DETAIL_LOG_STREAM macro expands to two calls to sal::detail::log(), + // so do not warn repeatedly about the same macro (the area->getLocStart() of all the calls + // from the same macro should be the same). + if( kind == LogCallKind::Sal ) + { + SourceLocation expansionLocation = compiler.getSourceManager().getExpansionLoc( call->getLocStart()); + if( expansionLocation == lastSalDetailLogStreamMacro ) + return true; + lastSalDetailLogStreamMacro = expansionLocation; + }; + if( const clang::StringLiteral* area = dyn_cast< clang::StringLiteral >( call->getArg( areaArgIndex )->IgnoreParenImpCasts())) { - if( func->getNumParams() == 5 && func->getIdentifier() != NULL - && ( func->getName() == "sal_detail_log" || func->getName() == "log" )) + if( area->getKind() == clang::StringLiteral::Ascii ) + checkArea( area->getBytes(), area->getExprLoc()); + else + report( DiagnosticsEngine::Warning, "unsupported string literal kind (plugin needs fixing?)", + area->getLocStart()); + return true; + } + if( kind == LogCallKind::DbgUnhandledException ) // below checks don't apply + return true; + if( loplugin::DeclCheck(inFunction).Function("log").Namespace("detail").Namespace("sal").GlobalNamespace() + || loplugin::DeclCheck(inFunction).Function("sal_detail_logFormat").GlobalNamespace() ) + return true; // These functions only forward to sal_detail_log, so ok. + if( call->getArg( areaArgIndex )->isNullPointerConstant( compiler.getASTContext(), + Expr::NPC_ValueDependentIsNotNull ) != Expr::NPCK_NotNull ) + { // If the area argument is a null pointer, that is allowed only for SAL_DEBUG. + const SourceManager& source = compiler.getSourceManager(); + for( SourceLocation loc = call->getLocStart(); + loc.isMacroID(); + loc = source.getImmediateExpansionRange( loc ).first ) { - auto tc = loplugin::DeclCheck(func); - if( tc.Function("sal_detail_log") || tc.Function("log").Namespace("detail").Namespace("sal").GlobalNamespace() ) - { - // The SAL_DETAIL_LOG_STREAM macro expands to two calls to sal::detail::log(), - // so do not warn repeatedly about the same macro (the area->getLocStart() of all the calls - // from the same macro should be the same). - SourceLocation expansionLocation = compiler.getSourceManager().getExpansionLoc( call->getLocStart()); - if( expansionLocation == lastSalDetailLogStreamMacro ) - return true; - lastSalDetailLogStreamMacro = expansionLocation; - if( const clang::StringLiteral* area = dyn_cast< clang::StringLiteral >( call->getArg( 1 )->IgnoreParenImpCasts())) - { - if( area->getKind() == clang::StringLiteral::Ascii ) - checkArea( area->getBytes(), area->getExprLoc()); - else - report( DiagnosticsEngine::Warning, "unsupported string literal kind (plugin needs fixing?)", - area->getLocStart()); - return true; - } - if( loplugin::DeclCheck(inFunction).Function("log").Namespace("detail").Namespace("sal").GlobalNamespace() - || loplugin::DeclCheck(inFunction).Function("sal_detail_logFormat").GlobalNamespace() ) - return true; // These functions only forward to sal_detail_log, so ok. - if( call->getArg( 1 )->isNullPointerConstant( compiler.getASTContext(), - Expr::NPC_ValueDependentIsNotNull ) != Expr::NPCK_NotNull ) - { // If the area argument is a null pointer, that is allowed only for SAL_DEBUG. - const SourceManager& source = compiler.getSourceManager(); - for( SourceLocation loc = call->getLocStart(); - loc.isMacroID(); - loc = source.getImmediateExpansionRange( loc ).first ) - { - StringRef inMacro = Lexer::getImmediateMacroName( loc, source, compiler.getLangOpts()); - if( inMacro == "SAL_DEBUG" || inMacro == "SAL_DEBUG_BACKTRACE" ) - return true; // ok - } - report( DiagnosticsEngine::Warning, "missing log area", - call->getArg( 1 )->IgnoreParenImpCasts()->getLocStart()); - return true; - } - report( DiagnosticsEngine::Warning, "cannot analyse log area argument (plugin needs fixing?)", - call->getLocStart()); - } + StringRef inMacro = Lexer::getImmediateMacroName( loc, source, compiler.getLangOpts()); + if( inMacro == "SAL_DEBUG" || inMacro == "SAL_DEBUG_BACKTRACE" ) + return true; // ok } + report( DiagnosticsEngine::Warning, "missing log area", + call->getArg( 1 )->IgnoreParenImpCasts()->getLocStart()); + return true; } + report( DiagnosticsEngine::Warning, "cannot analyse log area argument (plugin needs fixing?)", + call->getLocStart()); return true; } diff --git a/compilerplugins/clang/test/sallogareas.cxx b/compilerplugins/clang/test/sallogareas.cxx new file mode 100644 index 000000000000..6a9035a05f30 --- /dev/null +++ b/compilerplugins/clang/test/sallogareas.cxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 + +void func1(); + +int main() +{ + SAL_WARN( + "bob.none", + "message"); // expected-error@-2 {{unknown log area 'bob.none' (check or extend include/sal/log-areas.dox) [loplugin:sallogareas]}} + + SAL_WARN("xmloff", "message"); + + try + { + func1(); + } + catch (std::exception const&) + { + DBG_UNHANDLED_EXCEPTION( + "bob.none", + "message"); // expected-error@-2 {{unknown log area 'bob.none' (check or extend include/sal/log-areas.dox) [loplugin:sallogareas]}} + } + try + { + func1(); + } + catch (std::exception const&) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "message"); + } + try + { + func1(); + } + catch (std::exception const&) + { + DBG_UNHANDLED_EXCEPTION("xmloff"); + } + try + { + func1(); + } + catch (std::exception const&) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ -- cgit v1.2.3