summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2014-09-25 17:31:38 +0200
committerStephan Bergmann <sbergman@redhat.com>2014-09-25 17:43:23 +0200
commit5a9a3da719b65c53980e85940595f17c2f84f3c2 (patch)
treea1b9b9e229aa7ce3e045786dc45e7503eaf26ca1 /compilerplugins
parent48e1675ca204b6ad68f5844e21de1f7485cfd306 (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.cxx211
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: */