office-gobmx/compilerplugins/clang/literaltoboolconversion.cxx
Stephan Bergmann d2c5490210 -Werror,-Wdeprecated-declarations
> compilerplugins/clang/casttovoid.cxx:452:18: error: 'endswith' is deprecated: Use ends_with instead [-Werror,-Wdeprecated-declarations]
>                 .endswith(".h"));
>                  ^~~~~~~~
>                  ends_with
> ~/llvm/inst/include/llvm/ADT/StringRef.h:276:19: note: 'endswith' has been explicitly marked deprecated here
>     [[nodiscard]] LLVM_DEPRECATED(
>                   ^

etc. after
<5ac12951b4>
"[ADT] Deprecate StringRef::{starts,ends}with (#75491)" on Clang 18 trunk, where
<1b97645e56>
"[ADT] Introduce StringRef::{starts,ends}_width{,_insensitive}" had been added
towards Clang 16

Change-Id: Icb3e43b7d6be6f877815285913d846f766eddebf
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160919
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
2023-12-18 17:40:26 +01:00

231 lines
8.7 KiB
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/.
*/
#ifndef LO_CLANG_SHARED_PLUGINS
#include <cassert>
#include <limits>
#include "clang/Lex/Lexer.h"
#include "compat.hxx"
#include "plugin.hxx"
namespace {
class LiteralToBoolConversion:
public loplugin::FilteringRewritePlugin<LiteralToBoolConversion>
{
public:
explicit LiteralToBoolConversion(loplugin::InstantiationData const & data):
FilteringRewritePlugin(data) {}
virtual void run() override
{ TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
bool VisitImplicitCastExpr(ImplicitCastExpr const * expr);
bool PreTraverseLinkageSpecDecl(LinkageSpecDecl * decl);
bool PostTraverseLinkageSpecDecl(LinkageSpecDecl * decl, bool);
bool TraverseLinkageSpecDecl(LinkageSpecDecl * decl);
private:
bool isFromCIncludeFile(SourceLocation spellingLocation) const;
bool isSharedCAndCppCode(SourceLocation location) const;
void handleImplicitCastSubExpr(
ImplicitCastExpr const * castExpr, Expr const * subExpr);
unsigned int externCContexts_ = 0;
};
bool LiteralToBoolConversion::VisitImplicitCastExpr(
ImplicitCastExpr const * expr)
{
if (ignoreLocation(expr)) {
return true;
}
if (!expr->getType()->isBooleanType()) {
return true;
}
handleImplicitCastSubExpr(expr, expr->getSubExpr());
return true;
}
bool LiteralToBoolConversion::PreTraverseLinkageSpecDecl(LinkageSpecDecl *) {
assert(externCContexts_ != std::numeric_limits<unsigned int>::max()); //TODO
++externCContexts_;
return true;
}
bool LiteralToBoolConversion::PostTraverseLinkageSpecDecl(LinkageSpecDecl *, bool) {
assert(externCContexts_ != 0);
--externCContexts_;
return true;
}
bool LiteralToBoolConversion::TraverseLinkageSpecDecl(LinkageSpecDecl * decl) {
PreTraverseLinkageSpecDecl(decl);
bool ret = RecursiveASTVisitor::TraverseLinkageSpecDecl(decl);
PostTraverseLinkageSpecDecl(decl, ret);
return ret;
}
bool LiteralToBoolConversion::isFromCIncludeFile(
SourceLocation spellingLocation) const
{
return !compiler.getSourceManager().isInMainFile(spellingLocation)
&& compat::ends_with(
StringRef(compiler.getSourceManager().getPresumedLoc(spellingLocation).getFilename()),
".h");
}
bool LiteralToBoolConversion::isSharedCAndCppCode(SourceLocation location) const
{
// Assume that code is intended to be shared between C and C++ if it comes
// from an include file ending in .h, and is either in an extern "C" context
// or the body of a macro definition:
return
isFromCIncludeFile(compiler.getSourceManager().getSpellingLoc(location))
&& (externCContexts_ != 0
|| compiler.getSourceManager().isMacroBodyExpansion(location));
}
void LiteralToBoolConversion::handleImplicitCastSubExpr(
ImplicitCastExpr const * castExpr, Expr const * subExpr)
{
Expr const * expr2 = subExpr;
// track sub-expr with potential parens, to e.g. rewrite all of expanded
//
// #define sal_False ((sal_Bool)0)
//
// including the parens
subExpr = expr2->IgnoreParenCasts();
for (;;) {
BinaryOperator const * op = dyn_cast<BinaryOperator>(subExpr);
if (op == nullptr || op->getOpcode() != BO_Comma) {
break;
}
expr2 = op->getRHS();
subExpr = expr2->IgnoreParenCasts();
}
if (subExpr->getType()->isBooleanType()) {
return;
}
ConditionalOperator const * op = dyn_cast<ConditionalOperator>(subExpr);
if (op != nullptr) {
handleImplicitCastSubExpr(castExpr, op->getTrueExpr());
handleImplicitCastSubExpr(castExpr, op->getFalseExpr());
return;
}
if (!subExpr->isValueDependent()) {
if (auto const res = subExpr->getIntegerConstantExpr(compiler.getASTContext())) {
if (res->getLimitedValue() <= 1)
{
SourceLocation loc { subExpr->getBeginLoc() };
while (compiler.getSourceManager().isMacroArgExpansion(loc)) {
loc = compiler.getSourceManager().getImmediateMacroCallerLoc(loc);
}
if (compiler.getSourceManager().isMacroBodyExpansion(loc)) {
StringRef name { Lexer::getImmediateMacroName(
loc, compiler.getSourceManager(), compiler.getLangOpts()) };
if (name == "sal_False" || name == "sal_True") {
loc = compat::getImmediateExpansionRange(compiler.getSourceManager(), loc)
.first;
}
if (isSharedCAndCppCode(loc)) {
return;
}
}
}
}
}
if (isa<clang::StringLiteral>(subExpr)) {
SourceLocation loc { subExpr->getBeginLoc() };
if (compiler.getSourceManager().isMacroArgExpansion(loc)
&& (Lexer::getImmediateMacroName(
loc, compiler.getSourceManager(), compiler.getLangOpts())
== "assert"))
{
return;
}
}
if (isa<IntegerLiteral>(subExpr) || isa<CharacterLiteral>(subExpr)
|| isa<FloatingLiteral>(subExpr) || isa<ImaginaryLiteral>(subExpr)
|| isa<clang::StringLiteral>(subExpr))
{
bool bRewritten = false;
if (rewriter != nullptr) {
SourceLocation loc { compiler.getSourceManager().getExpansionLoc(
expr2->getBeginLoc()) };
if (compiler.getSourceManager().getExpansionLoc(expr2->getEndLoc())
== loc)
{
char const * s = compiler.getSourceManager().getCharacterData(
loc);
unsigned n = Lexer::MeasureTokenLength(
expr2->getEndLoc(), compiler.getSourceManager(),
compiler.getLangOpts());
std::string tok { s, n };
if (tok == "sal_False" || tok == "0") {
bRewritten = replaceText(
compiler.getSourceManager().getExpansionLoc(
expr2->getBeginLoc()),
n, "false");
} else if (tok == "sal_True" || tok == "1") {
bRewritten = replaceText(
compiler.getSourceManager().getExpansionLoc(
expr2->getBeginLoc()),
n, "true");
}
}
}
if (!bRewritten) {
report(
DiagnosticsEngine::Warning,
"implicit conversion (%0) of literal of type %1 to %2",
expr2->getBeginLoc())
<< castExpr->getCastKindName() << subExpr->getType()
<< castExpr->getType() << expr2->getSourceRange();
}
} else if (subExpr->isNullPointerConstant(
compiler.getASTContext(), Expr::NPC_ValueDependentIsNull)
> Expr::NPCK_ZeroExpression)
{
// The test above originally checked for != Expr::NPCK_NotNull, but in non-C++11
// mode we can get also Expr::NPCK_ZeroExpression inside templates, even though
// the expression is actually not a null pointer. Clang bug or C++98 misfeature?
// See Clang's NPCK_ZeroExpression declaration and beginning of isNullPointerConstant().
static_assert( Expr::NPCK_NotNull == 0 && Expr::NPCK_ZeroExpression == 1, "Clang API change" );
report(
DiagnosticsEngine::Warning,
("implicit conversion (%0) of null pointer constant of type %1 to"
" %2"),
expr2->getBeginLoc())
<< castExpr->getCastKindName() << subExpr->getType()
<< castExpr->getType() << expr2->getSourceRange();
} else if (!subExpr->isValueDependent()) {
if (auto const res = subExpr->getIntegerConstantExpr(compiler.getASTContext())) {
report(
DiagnosticsEngine::Warning,
("implicit conversion (%0) of integer constant expression of type"
" %1 with value %2 to %3"),
expr2->getBeginLoc())
<< castExpr->getCastKindName() << subExpr->getType()
<< compat::toString(*res, 10) << castExpr->getType()
<< expr2->getSourceRange();
}
}
}
loplugin::Plugin::Registration<LiteralToBoolConversion> literaltoboolconversion("literaltoboolconversion");
} // namespace
#endif // LO_CLANG_SHARED_PLUGINS