107 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "UseNoexceptCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/Lex/Lexer.h"12 13using namespace clang::ast_matchers;14 15namespace clang::tidy::modernize {16 17namespace {18AST_MATCHER(NamedDecl, isValid) { return !Node.isInvalidDecl(); }19} // namespace20 21UseNoexceptCheck::UseNoexceptCheck(StringRef Name, ClangTidyContext *Context)22 : ClangTidyCheck(Name, Context),23 NoexceptMacro(Options.get("ReplacementString", "")),24 UseNoexceptFalse(Options.get("UseNoexceptFalse", true)) {}25 26void UseNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {27 Options.store(Opts, "ReplacementString", NoexceptMacro);28 Options.store(Opts, "UseNoexceptFalse", UseNoexceptFalse);29}30 31void UseNoexceptCheck::registerMatchers(MatchFinder *Finder) {32 Finder->addMatcher(33 functionDecl(34 isValid(),35 hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))),36 optionally(cxxMethodDecl(anyOf(hasAnyOverloadedOperatorName(37 "delete[]", "delete"),38 cxxDestructorDecl()))39 .bind("del-dtor")))40 .bind("funcDecl"),41 this);42 43 Finder->addMatcher(44 parmVarDecl(anyOf(hasType(pointerType(pointee(parenType(innerType(45 functionProtoType(hasDynamicExceptionSpec())))))),46 hasType(memberPointerType(pointee(parenType(innerType(47 functionProtoType(hasDynamicExceptionSpec()))))))))48 .bind("parmVarDecl"),49 this);50}51 52void UseNoexceptCheck::check(const MatchFinder::MatchResult &Result) {53 const FunctionProtoType *FnTy = nullptr;54 bool DtorOrOperatorDel = false;55 SourceRange Range;56 57 if (const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl")) {58 DtorOrOperatorDel = Result.Nodes.getNodeAs<FunctionDecl>("del-dtor");59 FnTy = FuncDecl->getType()->getAs<FunctionProtoType>();60 if (const auto *TSI = FuncDecl->getTypeSourceInfo())61 Range =62 TSI->getTypeLoc().castAs<FunctionTypeLoc>().getExceptionSpecRange();63 } else if (const auto *ParmDecl =64 Result.Nodes.getNodeAs<ParmVarDecl>("parmVarDecl")) {65 FnTy = ParmDecl->getType()66 ->castAs<Type>()67 ->getPointeeType()68 ->getAs<FunctionProtoType>();69 70 if (const auto *TSI = ParmDecl->getTypeSourceInfo())71 Range = TSI->getTypeLoc()72 .getNextTypeLoc()73 .IgnoreParens()74 .castAs<FunctionProtoTypeLoc>()75 .getExceptionSpecRange();76 }77 78 assert(FnTy && "FunctionProtoType is null.");79 if (isUnresolvedExceptionSpec(FnTy->getExceptionSpecType()))80 return;81 82 assert(Range.isValid() && "Exception Source Range is invalid.");83 84 const CharSourceRange CRange = Lexer::makeFileCharRange(85 CharSourceRange::getTokenRange(Range), *Result.SourceManager,86 Result.Context->getLangOpts());87 88 const bool IsNoThrow = FnTy->isNothrow();89 const StringRef ReplacementStr =90 IsNoThrow ? NoexceptMacro.empty() ? "noexcept" : NoexceptMacro91 : NoexceptMacro.empty()92 ? (DtorOrOperatorDel || UseNoexceptFalse) ? "noexcept(false)" : ""93 : "";94 95 FixItHint FixIt;96 if ((IsNoThrow || NoexceptMacro.empty()) && CRange.isValid())97 FixIt = FixItHint::CreateReplacement(CRange, ReplacementStr);98 99 diag(Range.getBegin(), "dynamic exception specification '%0' is deprecated; "100 "consider %select{using '%2'|removing it}1 instead")101 << Lexer::getSourceText(CRange, *Result.SourceManager,102 Result.Context->getLangOpts())103 << ReplacementStr.empty() << ReplacementStr << FixIt;104}105 106} // namespace clang::tidy::modernize107