...of <http://llvm.org/viewvc/llvm-project?view=revision&revision=331155> "PR37189 Fix incorrect end source location and spelling for a split '>>' token", changing (among others) the return type of getImmediateExpansionRange from a std::pair of token locations to CharSourceRange (which will typically also represent token locations, but might also represent char locations). For now, map the return value of getImmediateExpansionRange back to a std::pair (as expected by our compilerplugins code in its current form), and mark the char location case with a TODO (which will need to be addressed if any of our plugins starts to produce wrong results due to not handling that char location case). In the long run, we should instead adapt our code to use the new return type of getImmediateExpansionRange directly. Change-Id: Idc2f5dc43830af4798b55bf605976c4ab146c522 Reviewed-on: https://gerrit.libreoffice.org/53817 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
218 lines
8.0 KiB
C++
218 lines
8.0 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/.
|
|
*/
|
|
|
|
#include <cassert>
|
|
#include <limits>
|
|
|
|
#include "clang/Lex/Lexer.h"
|
|
|
|
#include "compat.hxx"
|
|
#include "plugin.hxx"
|
|
|
|
namespace {
|
|
|
|
class LiteralToBoolConversion:
|
|
public RecursiveASTVisitor<LiteralToBoolConversion>,
|
|
public loplugin::RewritePlugin
|
|
{
|
|
public:
|
|
explicit LiteralToBoolConversion(loplugin::InstantiationData const & data):
|
|
RewritePlugin(data) {}
|
|
|
|
virtual void run() override
|
|
{ TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
|
|
|
|
bool VisitImplicitCastExpr(ImplicitCastExpr const * expr);
|
|
|
|
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::TraverseLinkageSpecDecl(LinkageSpecDecl * decl) {
|
|
assert(externCContexts_ != std::numeric_limits<unsigned int>::max()); //TODO
|
|
++externCContexts_;
|
|
bool ret = RecursiveASTVisitor::TraverseLinkageSpecDecl(decl);
|
|
assert(externCContexts_ != 0);
|
|
--externCContexts_;
|
|
return ret;
|
|
}
|
|
|
|
bool LiteralToBoolConversion::isFromCIncludeFile(
|
|
SourceLocation spellingLocation) const
|
|
{
|
|
return !compiler.getSourceManager().isInMainFile(spellingLocation)
|
|
&& (StringRef(
|
|
compiler.getSourceManager().getPresumedLoc(spellingLocation)
|
|
.getFilename())
|
|
.endswith(".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;
|
|
}
|
|
APSInt res;
|
|
if (!subExpr->isValueDependent()
|
|
&& subExpr->isIntegerConstantExpr(res, compiler.getASTContext())
|
|
&& res.getLimitedValue() <= 1)
|
|
{
|
|
SourceLocation loc { subExpr->getLocStart() };
|
|
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->getLocStart() };
|
|
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->getLocStart()) };
|
|
if (compiler.getSourceManager().getExpansionLoc(expr2->getLocEnd())
|
|
== loc)
|
|
{
|
|
char const * s = compiler.getSourceManager().getCharacterData(
|
|
loc);
|
|
unsigned n = Lexer::MeasureTokenLength(
|
|
expr2->getLocEnd(), compiler.getSourceManager(),
|
|
compiler.getLangOpts());
|
|
std::string tok { s, n };
|
|
if (tok == "sal_False" || tok == "0") {
|
|
bRewritten = replaceText(
|
|
compiler.getSourceManager().getExpansionLoc(
|
|
expr2->getLocStart()),
|
|
n, "false");
|
|
} else if (tok == "sal_True" || tok == "1") {
|
|
bRewritten = replaceText(
|
|
compiler.getSourceManager().getExpansionLoc(
|
|
expr2->getLocStart()),
|
|
n, "true");
|
|
}
|
|
}
|
|
}
|
|
if (!bRewritten) {
|
|
report(
|
|
DiagnosticsEngine::Warning,
|
|
"implicit conversion (%0) of literal of type %1 to %2",
|
|
expr2->getLocStart())
|
|
<< 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->getLocStart())
|
|
<< castExpr->getCastKindName() << subExpr->getType()
|
|
<< castExpr->getType() << expr2->getSourceRange();
|
|
} else if (!subExpr->isValueDependent()
|
|
&& subExpr->isIntegerConstantExpr(res, compiler.getASTContext()))
|
|
{
|
|
report(
|
|
DiagnosticsEngine::Warning,
|
|
("implicit conversion (%0) of integer constant expression of type"
|
|
" %1 with value %2 to %3"),
|
|
expr2->getLocStart())
|
|
<< castExpr->getCastKindName() << subExpr->getType()
|
|
<< res.toString(10) << castExpr->getType()
|
|
<< expr2->getSourceRange();
|
|
}
|
|
}
|
|
|
|
loplugin::Plugin::Registration<LiteralToBoolConversion> X(
|
|
"literaltoboolconversion", true);
|
|
|
|
}
|