diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2014-09-25 17:31:38 +0200 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2014-09-25 17:43:23 +0200 |
commit | 5a9a3da719b65c53980e85940595f17c2f84f3c2 (patch) | |
tree | a1b9b9e229aa7ce3e045786dc45e7503eaf26ca1 /compilerplugins | |
parent | 48e1675ca204b6ad68f5844e21de1f7485cfd306 (diff) |
loplugin:nullptr
A plugin to warn about and rewrite null pointer constants that are not written
as nullptr (in C++11 code) resp. NULL (in C and C++03 code). It is not
activated for the following reasons:
* At least the call to
pImpl->aFmtNms.insert(pImpl->aFmtNms.begin() + nPos, nullptr);
in svx/source/items/clipfmtitem.cxx would require
<https://svn.boost.org/trac/boost/ticket/10540> "missing std::nullptr_t
support in boost/type_traits/is_pointer.hpp" to be fixed first.
* Additions of code that violate the plugin would probably be frequent, causing
unnecessary grief for those building with plugins enabled.
* It did not find anything interesting, apart from the above Boost bug and the
mildly interesting 1da153b617b80887680be65c1854ef8080c2e1c9 "Consistently use
APP_WRITER as an integer, never as a nullptr."
Anyway,
until make -O -j4 -k check; do make -O -j1 -k check \
COMPILER_PLUGIN_TOOL=nullptr UPDATE_FILES=all; done
sucessfully executed on a recent master and resulted in
6798 files changed, 60919 insertions(+), 60919 deletions(-)
Change-Id: I1260227949868e73fcb63fda13d83e79fde685d7
Diffstat (limited to 'compilerplugins')
-rw-r--r-- | compilerplugins/clang/store/nullptr.cxx | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/compilerplugins/clang/store/nullptr.cxx b/compilerplugins/clang/store/nullptr.cxx new file mode 100644 index 000000000000..528bb6aac9bc --- /dev/null +++ b/compilerplugins/clang/store/nullptr.cxx @@ -0,0 +1,211 @@ +/* -*- 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 "compat.hxx" +#include "plugin.hxx" + +namespace { + +char const * kindName(Expr::NullPointerConstantKind kind) { + switch (kind) { + case Expr::NPCK_NotNull: + assert(false); // cannot happen + // fall through + case Expr::NPCK_ZeroExpression: + return "ZeroExpression"; + case Expr::NPCK_ZeroLiteral: + return "ZeroLiteral"; + case Expr::NPCK_CXX11_nullptr: + return "CXX11_nullptr"; + case Expr::NPCK_GNUNull: + return "GNUNull"; + } +} + +class Nullptr: + public RecursiveASTVisitor<Nullptr>, public loplugin::RewritePlugin +{ +public: + explicit Nullptr(InstantiationData const & data): RewritePlugin(data) {} + + void run() override + { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); } + + bool VisitImplicitCastExpr(CastExpr const * expr); + +private: + bool isFromCIncludeFile(SourceLocation spellingLocation) const; + + bool isMacroBodyExpansion(SourceLocation location) const; + + void rewriteOrWarn( + Expr const & expr, char const * castKind, + Expr::NullPointerConstantKind nullPointerkind, + char const * replacement); +}; + +bool Nullptr::VisitImplicitCastExpr(CastExpr const * expr) { + if (ignoreLocation(expr)) { + return true; + } + switch (expr->getCastKind()) { + case CK_NullToPointer: + case CK_NullToMemberPointer: + break; + default: + return true; + } + Expr::NullPointerConstantKind k = expr->isNullPointerConstant( + compiler.getASTContext(), Expr::NPC_ValueDependentIsNotNull); + switch (k) { + case Expr::NPCK_NotNull: + k = expr->isNullPointerConstant( + compiler.getASTContext(), Expr::NPC_ValueDependentIsNull); + switch (k) { + case Expr::NPCK_NotNull: + break; + case Expr::NPCK_ZeroExpression: + case Expr::NPCK_ZeroLiteral: + report( + DiagnosticsEngine::Warning, + "suspicious ValueDependendIsNull %0", expr->getLocStart()) + << kindName(k) << expr->getSourceRange(); + break; + default: + assert(false); // cannot happen + } + break; + case Expr::NPCK_CXX11_nullptr: + break; + default: + { + Expr const * e = expr->getSubExpr(); + SourceLocation loc; + for (;;) { + e = e->IgnoreImpCasts(); + loc = e->getLocStart(); + while (compiler.getSourceManager().isMacroArgExpansion(loc)) { + loc = compiler.getSourceManager() + .getImmediateMacroCallerLoc( + loc); + } + if (isMacroBodyExpansion(loc)) { + if (Lexer::getImmediateMacroName( + loc, compiler.getSourceManager(), + compiler.getLangOpts()) + == "NULL") + { + if (!compiler.getLangOpts().CPlusPlus) { + return true; + } + loc = compiler.getSourceManager() + .getImmediateExpansionRange(loc).first; + if (isInUnoIncludeFile( + compiler.getSourceManager().getSpellingLoc(loc)) + || isFromCIncludeFile( + compiler.getSourceManager().getSpellingLoc( + loc))) + { + return true; + } + } else if (ignoreLocation( + compiler.getSourceManager().getSpellingLoc( + loc))) + { + return true; + } + } + ParenExpr const * pe = dyn_cast<ParenExpr>(e); + if (pe == nullptr) { + break; + } + e = pe->getSubExpr(); + } + rewriteOrWarn( + *e, expr->getCastKindName(), k, + ((!compiler.getLangOpts().CPlusPlus + || isInUnoIncludeFile( + compiler.getSourceManager().getSpellingLoc(loc)) + || isFromCIncludeFile( + compiler.getSourceManager().getSpellingLoc(loc))) + ? "NULL" : "nullptr")); + } + break; + } + return true; +} + +bool Nullptr::isFromCIncludeFile(SourceLocation spellingLocation) const { + return !compat::isInMainFile(compiler.getSourceManager(), spellingLocation) + && (StringRef( + compiler.getSourceManager().getPresumedLoc(spellingLocation) + .getFilename()) + .endswith(".h")); +} + +bool Nullptr::isMacroBodyExpansion(SourceLocation location) const { +#if (__clang_major__ == 3 && __clang_minor__ >= 3) || __clang_major__ > 3 + return compiler.getSourceManager().isMacroBodyExpansion(location); +#else + return location.isMacroID() + && !compiler.getSourceManager().isMacroArgExpansion(location); +#endif +} + +void Nullptr::rewriteOrWarn( + Expr const & expr, char const * castKind, + Expr::NullPointerConstantKind nullPointerKind, char const * replacement) +{ + if (rewriter != nullptr) { + SourceLocation locStart(expr.getLocStart()); + while (compiler.getSourceManager().isMacroArgExpansion(locStart)) { + locStart = compiler.getSourceManager() + .getImmediateMacroCallerLoc(locStart); + } + if (compiler.getLangOpts().CPlusPlus && isMacroBodyExpansion(locStart) + && (Lexer::getImmediateMacroName( + locStart, compiler.getSourceManager(), + compiler.getLangOpts()) + == "NULL")) + { + locStart = compiler.getSourceManager().getImmediateExpansionRange( + locStart).first; + } + SourceLocation locEnd(expr.getLocEnd()); + while (compiler.getSourceManager().isMacroArgExpansion(locEnd)) { + locEnd = compiler.getSourceManager() + .getImmediateMacroCallerLoc(locEnd); + } + if (compiler.getLangOpts().CPlusPlus && isMacroBodyExpansion(locEnd) + && (Lexer::getImmediateMacroName( + locEnd, compiler.getSourceManager(), + compiler.getLangOpts()) + == "NULL")) + { + locEnd = compiler.getSourceManager().getImmediateExpansionRange( + locEnd).first; + } + if (replaceText(SourceRange(compiler.getSourceManager().getSpellingLoc(locStart), compiler.getSourceManager().getSpellingLoc(locEnd)), replacement)) { + return; + } + } + report( + DiagnosticsEngine::Warning, "%0 ValueDependendIsNotNull %1 -> %2", + expr.getLocStart()) + << castKind << kindName(nullPointerKind) << replacement + << expr.getSourceRange(); +} + +loplugin::Plugin::Registration<Nullptr> X("nullptr", true); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |