From 3de97578e4720f837c348ba48d8e50599ad937d1 Mon Sep 17 00:00:00 2001 From: Stephan Bergmann Date: Tue, 28 Jan 2014 20:18:11 +0100 Subject: Clang plugin to warn about implicit conversion of literals to bool ...which warns about apparent errors like n == KIND_FOO || KIND_BAR that should have read n == KIND_FOO || n == KIND_BAR It also warns about trivial (mis-)uses of 0/1 and sal_False/True like while (1) { ... } instead of while (true) { ... } which it can automatically rewrite. It does not warn if the relevant code is inside a macro in a .h (i.e., C) include file, nor when a string literal is used in the assert macro like assert(!"this cannot happen"); Change-Id: If8c305a25e5da15e78f6139b5b0c0e868f06d4f3 --- compilerplugins/clang/literaltoboolconversion.cxx | 140 ++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 compilerplugins/clang/literaltoboolconversion.cxx (limited to 'compilerplugins') diff --git a/compilerplugins/clang/literaltoboolconversion.cxx b/compilerplugins/clang/literaltoboolconversion.cxx new file mode 100644 index 000000000000..a3779e24c38b --- /dev/null +++ b/compilerplugins/clang/literaltoboolconversion.cxx @@ -0,0 +1,140 @@ +/* -*- 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 "clang/Lex/Lexer.h" + +#include "plugin.hxx" + +namespace { + +class LiteralToBoolConversion: + public RecursiveASTVisitor, + public loplugin::RewritePlugin +{ +public: + explicit LiteralToBoolConversion(InstantiationData const & data): + RewritePlugin(data) {} + + virtual void run() override + { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); } + + bool VisitImplicitCastExpr(ImplicitCastExpr const * expr); +}; + +bool LiteralToBoolConversion::VisitImplicitCastExpr( + ImplicitCastExpr const * expr) +{ + if (ignoreLocation(expr)) { + return true; + } + if (!expr->getType()->isBooleanType()) { + return true; + } + Expr const * sub = expr->getSubExpr()->IgnoreParenCasts(); + if (sub->getType()->isBooleanType()) { + return true; + } + IntegerLiteral const * lit = dyn_cast(sub); + if (lit != nullptr && lit->getValue().getLimitedValue() <= 1) { + SourceLocation loc { sub->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 = compiler.getSourceManager().getImmediateExpansionRange( + loc).first; + } + SourceLocation spl { compiler.getSourceManager().getSpellingLoc( + loc) }; + if (!compiler.getSourceManager().isInMainFile(spl) + && compiler.getSourceManager().getFilename(spl).endswith(".h")) + { + return true; + } + } + + } + if (isa(sub)) { + SourceLocation loc { sub->getLocStart() }; + if (compiler.getSourceManager().isMacroArgExpansion(loc) + && (Lexer::getImmediateMacroName( + loc, compiler.getSourceManager(), compiler.getLangOpts()) + == "assert")) + { + return true; + } + } + if (isa(sub) || isa(sub) + || isa(sub) || isa(sub) + || isa(sub)) + { + bool rewritten = false; + if (rewriter != nullptr) { + SourceLocation loc { compiler.getSourceManager().getExpansionLoc( + expr->getLocStart()) }; + if (compiler.getSourceManager().getExpansionLoc(expr->getLocEnd()) + == loc) + { + char const * s = compiler.getSourceManager().getCharacterData( + loc); + unsigned n = Lexer::MeasureTokenLength( + expr->getLocEnd(), compiler.getSourceManager(), + compiler.getLangOpts()); + std::string tok { s, n }; + if (tok == "sal_False" || tok == "0") { + rewritten = replaceText( + compiler.getSourceManager().getExpansionLoc( + expr->getLocStart()), + n, "false"); + } else if (tok == "sal_True" || tok == "1") { + rewritten = replaceText( + compiler.getSourceManager().getExpansionLoc( + expr->getLocStart()), + n, "true"); + } + } + } + if (!rewritten) { + report( + DiagnosticsEngine::Warning, + "implicit conversion (%0) of literal of type %1 to %2", + expr->getLocStart()) + << expr->getCastKindName() << expr->getSubExpr()->getType() + << expr->getType() << expr->getSourceRange(); + } + } else if (sub->isNullPointerConstant( + compiler.getASTContext(), Expr::NPC_ValueDependentIsNull) + != Expr::NPCK_NotNull) + { + report( + DiagnosticsEngine::Warning, + ("implicit conversion (%0) of null pointer constant of type %1 to" + " %2"), + expr->getLocStart()) + << expr->getCastKindName() << expr->getSubExpr()->getType() + << expr->getType() << expr->getSourceRange(); + } else if (sub->isIntegerConstantExpr(compiler.getASTContext())) { + report( + DiagnosticsEngine::Warning, + ("implicit conversion (%0) of integer constant expression of type" + " %1 to %2"), + expr->getLocStart()) + << expr->getCastKindName() << expr->getSubExpr()->getType() + << expr->getType() << expr->getSourceRange(); + } + return true; +} + +loplugin::Plugin::Registration X( + "literaltoboolconversion", true); + +} -- cgit v1.2.3