hintonda created this revision.
hintonda added a reviewer: alexfh.
hintonda added a subscriber: cfe-commits.

This checker allows users to replace deprecated throw()
specifications with noexcept.

It also allows users to replace an arbitrary list of macros with
either noexcept or a user defined macro -- which is useful when
supporting older compilers.

http://reviews.llvm.org/D18575

Files:
  clang-tidy/modernize/CMakeLists.txt
  clang-tidy/modernize/ModernizeTidyModule.cpp
  clang-tidy/modernize/UseNoexceptCheck.cpp
  clang-tidy/modernize/UseNoexceptCheck.h
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/modernize-use-noexcept.rst
  test/clang-tidy/modernize-use-noexcept-macro.cpp
  test/clang-tidy/modernize-use-noexcept.cpp

Index: test/clang-tidy/modernize-use-noexcept.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/modernize-use-noexcept.cpp
@@ -0,0 +1,16 @@
+// RUN: %check_clang_tidy %s modernize-use-noexcept %t -- \
+// RUN:   -config="{CheckOptions: [{key: modernize-use-noexcept.CandidateStrings, value: 'NOTHROW,,,'}]}" \
+// RUN:   -- -std=c++11
+
+void foo() throw();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'foo': replacing noexcept specification 'throw()' with 'noexcept' [modernize-use-noexcept]
+// CHECK-FIXES: void foo() noexcept;
+
+void bar() throw() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'bar': replacing noexcept specification 'throw()' with 'noexcept' [modernize-use-noexcept]
+// CHECK-FIXES: void bar() noexcept {}
+
+#define NOTHROW throw()
+void foobar() NOTHROW {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'foobar': replacing noexcept specification 'NOTHROW' with 'noexcept' [modernize-use-noexcept]
+// CHECK-FIXES: void foobar() noexcept {}
Index: test/clang-tidy/modernize-use-noexcept-macro.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/modernize-use-noexcept-macro.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy %s modernize-use-noexcept %t -- \
+// RUN:   -config="{CheckOptions: [{key: modernize-use-noexcept.CandidateStrings, value: ' NOTHROW , , ,'}, \
+// RUN:                            {key: modernize-use-noexcept.ReplacementString, value: 'NOEXCEPT'}]}" \
+// RUN:   -- -std=c++11
+
+#define NOEXCEPT noexcept
+
+void foo() noexcept(true);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'foo': replacing noexcept specification 'noexcept(true)' with 'NOEXCEPT' [modernize-use-noexcept]
+// CHECK-FIXES: void foo() NOEXCEPT;
+
+void bar() throw() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'bar': replacing noexcept specification 'throw()' with 'NOEXCEPT' [modernize-use-noexcept]
+// CHECK-FIXES: void bar() NOEXCEPT {}
+
+#define NOTHROW throw()
+void foobar() NOTHROW {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'foobar': replacing noexcept specification 'NOTHROW' with 'NOEXCEPT' [modernize-use-noexcept]
+// CHECK-FIXES: void foobar() NOEXCEPT {}
Index: docs/clang-tidy/checks/modernize-use-noexcept.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/modernize-use-noexcept.rst
@@ -0,0 +1,51 @@
+.. title:: clang-tidy - modernize-use-noexcept
+
+modernize-use-noexcept
+======================
+
+The check converts exception specifications, e.g., throw(), to either
+noexcept, or a user defined macro.
+
+Example
+-------
+
+.. code-block:: c++
+
+  void foo() throw();
+
+transforms to:
+
+.. code-block:: c++
+
+  void foo() noexcept;
+
+
+User defined macros
+-------------------
+
+By default this check will only replace the ``throw()`` and
+``noexcept(true)`` with ``noexcept``.  However, the user can use
+:option:``CandidateStrings" to specify a comma-separated list of macro
+names that will be transformed along with ``throw()`` and
+``noexcept(true)``.
+
+Users can also use :option:``ReplacementString`` to specify a macro to
+use instead of ``noexcept``.  This is useful when maintaining source
+code that must compile on older compilers that don't support the
+``noexcept`` keyword.
+
+Example
+^^^^^^^
+
+.. code-block:: c++
+
+  void foo() NOTHROW {}
+
+transforms to:
+
+.. code-block:: c++
+
+  void foo() NOEXCEPT {}
+
+if the ``CandidateStrings`` option is set to ``NOTHROW``, and the
+``ReplacementString`` option is set to ``NOEXCEPT``.
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -83,6 +83,7 @@
    modernize-shrink-to-fit
    modernize-use-auto
    modernize-use-default
+   modernize-use-noexcept
    modernize-use-nullptr
    modernize-use-override
    performance-faster-string-find
Index: clang-tidy/modernize/UseNoexceptCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/modernize/UseNoexceptCheck.h
@@ -0,0 +1,49 @@
+//===--- UseNoexceptCheck.h - clang-tidy-------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NOEXCEPT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NOEXCEPT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+using CandidateSet = llvm::StringSet<llvm::MallocAllocator>;
+
+/// \brief Replace noexcept specifications, or macros, with noexcept or a user defined macro. 
+/// \code
+///   void foo() throw();
+/// \endcode
+/// Is converted to:
+/// \code
+///   void foo() noexcept;
+/// \endcode
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-noexcept.html
+class UseNoexceptCheck : public ClangTidyCheck {
+public:
+  UseNoexceptCheck(StringRef Name, ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  const std::string ReplacementStr;
+  std::string RawCandidateStrings;
+  CandidateSet Candidates;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NOEXCEPT_H
Index: clang-tidy/modernize/UseNoexceptCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/modernize/UseNoexceptCheck.cpp
@@ -0,0 +1,133 @@
+//===--- UseNoexceptCheck.cpp - clang-tidy---------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseNoexceptCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+namespace {
+void parseCandidateStrings(StringRef AllStrings, CandidateSet &ResultSet,
+                           char delimiter) {
+  SmallVector<StringRef, 5> Candidates;
+  AllStrings.split(Candidates, ',');
+  for (StringRef &RawString : Candidates) {
+    StringRef Candidate = RawString.trim();
+    if (!Candidate.empty())
+      ResultSet.insert(Candidate);
+  }
+}
+
+using namespace lexer_utils;
+
+static StringRef GetText(const Token &Tok, const SourceManager &SM) {
+  return StringRef(SM.getCharacterData(Tok.getLocation()), Tok.getLength());
+}
+} // namespace
+
+UseNoexceptCheck::UseNoexceptCheck(StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      ReplacementStr(Options.get("ReplacementString", "noexcept")),
+      RawCandidateStrings(
+          Options.get("CandidateStrings", "")) {
+  // Always append the defaults, even if the user provides their own.
+  RawCandidateStrings.append(",throw(),noexcept(true)");
+  parseCandidateStrings(RawCandidateStrings, Candidates, ',');
+}
+
+void UseNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "ReplacementString", ReplacementStr);
+  Options.store(Opts, "CandidateStrings", RawCandidateStrings);
+}
+
+void UseNoexceptCheck::registerMatchers(MatchFinder *Finder) {
+  if (!getLangOpts().CPlusPlus)
+    return;
+  Finder->addMatcher(functionDecl(isNoThrow()).bind("functionDecl"), this);
+}
+
+void UseNoexceptCheck::check(const MatchFinder::MatchResult &Result) {
+  SourceManager &SM = *Result.SourceManager;
+  const ASTContext &Context = *Result.Context;
+
+  if (const FunctionDecl *FuncDecl =
+          Result.Nodes.getNodeAs<clang::FunctionDecl>("functionDecl")) {
+
+    SourceRange Range = FuncDecl->getSourceRange();
+    if (!Range.isValid())
+      return;
+
+    SourceLocation BeginLoc = Range.getBegin();
+    SourceLocation CurrentLoc = Range.getEnd();
+
+    SourceLocation ReplaceStart;
+    SourceLocation ReplaceEnd;
+
+    Token Tok =
+        getPreviousNonCommentToken(Context, CurrentLoc.getLocWithOffset(1));
+
+    std::string found;
+    BeforeThanCompare<SourceLocation> isBefore(SM);
+    while (isBefore(BeginLoc, CurrentLoc)) {
+      SourceLocation Loc = Tok.getLocation();
+
+      if (Tok.is(tok::r_paren)) {
+        Tok = getPreviousNonCommentToken(Context, Tok.getLocation());
+        if (Tok.is(tok::l_paren)) {
+          Tok = getPreviousNonCommentToken(Context, Tok.getLocation());
+          found = std::string(GetText(Tok, SM)) + "()";
+          if (Candidates.find(found) != Candidates.end()) {
+            ReplaceEnd = Loc;
+            ReplaceStart = Tok.getLocation();
+            break;
+          }
+        } else if (GetText(Tok, SM) == "true") {
+          Tok = getPreviousNonCommentToken(Context, Tok.getLocation());
+          if (Tok.is(tok::l_paren)) {
+            Tok = getPreviousNonCommentToken(Context, Tok.getLocation());
+            found = std::string(GetText(Tok, SM)) + "(true)";
+            if (Candidates.find(found) != Candidates.end()) {
+              ReplaceEnd = Loc;
+              ReplaceStart = Tok.getLocation();
+              break;
+            }
+          }
+        }
+      } else {
+        found = GetText(Tok, SM);
+        if (Candidates.find(found) != Candidates.end()) {
+          ReplaceEnd = Loc;
+          ReplaceStart = Tok.getLocation();
+          break;
+        }
+        Tok = getPreviousNonCommentToken(Context, Tok.getLocation());
+      }
+      CurrentLoc = Tok.getLocation();
+    }
+
+    if (ReplaceStart.isValid() && ReplaceEnd.isValid()) {
+      diag(FuncDecl->getLocation(),
+           "function '%0': replacing noexcept specification '%1' with '%2'")
+          << FuncDecl->getNameInfo().getAsString() << found << ReplacementStr
+          << FixItHint::CreateReplacement(
+                 CharSourceRange::getTokenRange(ReplaceStart, ReplaceEnd),
+                 ReplacementStr);
+    }
+  }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/modernize/ModernizeTidyModule.cpp
===================================================================
--- clang-tidy/modernize/ModernizeTidyModule.cpp
+++ clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -19,6 +19,7 @@
 #include "ShrinkToFitCheck.h"
 #include "UseAutoCheck.h"
 #include "UseDefaultCheck.h"
+#include "UseNoexceptCheck.h"
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 
@@ -43,6 +44,7 @@
     CheckFactories.registerCheck<ShrinkToFitCheck>("modernize-shrink-to-fit");
     CheckFactories.registerCheck<UseAutoCheck>("modernize-use-auto");
     CheckFactories.registerCheck<UseDefaultCheck>("modernize-use-default");
+    CheckFactories.registerCheck<UseNoexceptCheck>("modernize-use-noexcept");
     CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
     CheckFactories.registerCheck<UseOverrideCheck>("modernize-use-override");
   }
Index: clang-tidy/modernize/CMakeLists.txt
===================================================================
--- clang-tidy/modernize/CMakeLists.txt
+++ clang-tidy/modernize/CMakeLists.txt
@@ -12,6 +12,7 @@
   ShrinkToFitCheck.cpp
   UseAutoCheck.cpp
   UseDefaultCheck.cpp
+  UseNoexceptCheck.cpp
   UseNullptrCheck.cpp
   UseOverrideCheck.cpp
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to