hiraditya created this revision.
hiraditya requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D96685

Files:
  clang-tools-extra/clang-tidy/modernize/AddNoexceptCheck.cpp
  clang-tools-extra/clang-tidy/modernize/AddNoexceptCheck.h

Index: clang-tools-extra/clang-tidy/modernize/AddNoexceptCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/modernize/AddNoexceptCheck.h
@@ -0,0 +1,39 @@
+//===--- AddNoexceptCheck.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_ADD_NOEXCEPT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_ADD_NOEXCEPT_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Add noexcept to function delcaration and definitions. 
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-add-noexcept.html
+class AddNoexceptCheck : public ClangTidyCheck {
+public:
+  AddNoexceptCheck(StringRef Name, ClangTidyContext *Context);
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus11;
+  }
+  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 NoexceptMacro;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_ADD_NOEXCEPT_H
Index: clang-tools-extra/clang-tidy/modernize/AddNoexceptCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/modernize/AddNoexceptCheck.cpp
@@ -0,0 +1,121 @@
+//===--- AddNoexceptCheck.cpp - clang-tidy---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// TODOs:
+// - Handle const functions properly.
+// - Handle functions with attributes.
+// - Handle functions with weird qualifiers (&, &&). There may not be too many 
+//  instances of this.
+//===----------------------------------------------------------------------===//
+
+#include "AddNoexceptCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+namespace {
+AST_MATCHER(NamedDecl, isValid) { return !Node.isInvalidDecl(); }
+AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); }
+AST_MATCHER(CXXMethodDecl, hasRefQualifier) { return Node.getRefQualifier() != clang::RQ_None; }
+AST_MATCHER(CXXMethodDecl, hasTrivialBody) { return Node.hasTrivialBody(); }
+
+AST_MATCHER(CXXRecordDecl, hasAnyDependentBases) {
+  return Node.hasAnyDependentBases();
+}
+
+AST_MATCHER(CXXMethodDecl, isTemplate) {
+  return Node.getTemplatedKind() != FunctionDecl::TK_NonTemplate;
+}
+
+AST_MATCHER(CXXMethodDecl, isDependentContext) {
+  return Node.isDependentContext();
+}
+
+AST_MATCHER(CXXMethodDecl, isInsideMacroDefinition) {
+  const ASTContext &Ctxt = Finder->getASTContext();
+  return clang::Lexer::makeFileCharRange(
+             clang::CharSourceRange::getCharRange(
+                 Node.getTypeSourceInfo()->getTypeLoc().getSourceRange()),
+             Ctxt.getSourceManager(), Ctxt.getLangOpts())
+      .isInvalid();
+}
+
+// hasDynamicExceptionSpec mathes all 'throw's in the qualifier. We also skip all 'except's in the qualifier.
+AST_MATCHER(CXXMethodDecl, hasExceptSpec) { return clang::isNoexceptExceptionSpec(Node.getExceptionSpecType()); }
+
+AST_MATCHER_P(CXXMethodDecl, hasCanonicalDecl,
+              ast_matchers::internal::Matcher<CXXMethodDecl>, InnerMatcher) {
+  return InnerMatcher.matches(*Node.getCanonicalDecl(), Finder, Builder);
+}
+
+} // namespace
+
+static SourceLocation getConstInsertionPoint(const CXXMethodDecl *M) {
+  TypeSourceInfo *TSI = M->getTypeSourceInfo();
+  if (!TSI)
+    return {};
+
+  FunctionTypeLoc FTL = TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
+  if (!FTL)
+    return {};
+  if (M->isConst()) {
+    // TODO: Use a while loop to find the end of const.
+    return FTL.getRParenLoc().getLocWithOffset(7);
+  }
+  return FTL.getRParenLoc().getLocWithOffset(1);
+}
+
+AddNoexceptCheck::AddNoexceptCheck(StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      NoexceptMacro(Options.get("ReplacementString", "")) {}
+
+void AddNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "ReplacementString", NoexceptMacro);
+}
+
+void AddNoexceptCheck::registerMatchers(MatchFinder *Finder) {
+  // TODO: Handle const.
+  // Handling const is tricky as 'const' should appear before 'noexcept'
+  // i.e., `foo() noexcept const` is illegal but `foo() const noexcept` is fine'
+  const auto m = cxxMethodDecl(isUserProvided(),
+                               unless(anyOf(hasExceptSpec(), isExpansionInSystemHeader(), isVirtual(), /*isConst(), isStatic(),*/
+                                            hasRefQualifier(), isDeleted(), hasDynamicExceptionSpec(),
+                                            hasTrivialBody(), cxxConstructorDecl(), cxxDestructorDecl(), isTemplate(),
+                                            isDependentContext(), ofClass(anyOf(isLambda(), hasAnyDependentBases())),
+                                            isInsideMacroDefinition(), hasCanonicalDecl(isInsideMacroDefinition()))))
+                     .bind("cxxMethod");
+
+  finder->match(m);
+}
+
+void AddNoexceptCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *mDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("cxxMethod");
+  // check if we've already refactored this. 
+  static std::set<SourceLocation> visited;
+  auto L = getConstInsertionPoint(mDecl);
+  if (!visited.insert(L).second) {
+    return;
+  }
+
+  StringRef ReplacementStr = "noexcept";
+  FixItHint FixIt;
+  if ((NoexceptMacro.empty()) && CRange.isValid())
+    FixIt = FixItHint::CreateReplacement(CRange, ReplacementStr);
+
+  diag(Range.getBegin(), "Add %0 %1 ")
+      << Lexer::getSourceText(CRange, *Result.SourceManager,
+                              Result.Context->getLangOpts())
+      << ReplacementStr.empty() << ReplacementStr << FixIt;
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to