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