summaryrefslogtreecommitdiff
path: root/compilerplugins/clang
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2014-01-28 20:18:11 +0100
committerStephan Bergmann <sbergman@redhat.com>2014-01-28 20:26:31 +0100
commit3de97578e4720f837c348ba48d8e50599ad937d1 (patch)
tree8678eb61287cc85ef9ea90cddc123125fcc72ba5 /compilerplugins/clang
parentbfe54489398881bfbe569aa4d2162655ffca6ff4 (diff)
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
Diffstat (limited to 'compilerplugins/clang')
-rw-r--r--compilerplugins/clang/literaltoboolconversion.cxx140
1 files changed, 140 insertions, 0 deletions
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<LiteralToBoolConversion>,
+ 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<IntegerLiteral>(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<StringLiteral>(sub)) {
+ SourceLocation loc { sub->getLocStart() };
+ if (compiler.getSourceManager().isMacroArgExpansion(loc)
+ && (Lexer::getImmediateMacroName(
+ loc, compiler.getSourceManager(), compiler.getLangOpts())
+ == "assert"))
+ {
+ return true;
+ }
+ }
+ if (isa<IntegerLiteral>(sub) || isa<CharacterLiteral>(sub)
+ || isa<FloatingLiteral>(sub) || isa<ImaginaryLiteral>(sub)
+ || isa<StringLiteral>(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<LiteralToBoolConversion> X(
+ "literaltoboolconversion", true);
+
+}