11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "llvm/ADT/StringSet.h"
20 FunctionsThatShouldNotThrow) {
21 return FunctionsThatShouldNotThrow.contains(Node.getNameAsString());
25 return isExplicitThrowExceptionSpec(Node.getExceptionSpecType()) &&
26 Node.getExceptionSpecSourceRange().isValid();
30 return Node.getNumParams() > 0;
37 :
ClangTidyCheck(Name, Context), RawFunctionsThatShouldNotThrow(Options.get(
38 "FunctionsThatShouldNotThrow",
"")),
39 RawIgnoredExceptions(Options.get(
"IgnoredExceptions",
"")) {
40 llvm::SmallVector<StringRef, 8> FunctionsThatShouldNotThrowVec,
42 StringRef(RawFunctionsThatShouldNotThrow)
43 .split(FunctionsThatShouldNotThrowVec,
",", -1,
false);
44 FunctionsThatShouldNotThrow.insert_range(FunctionsThatShouldNotThrowVec);
46 llvm::StringSet<> IgnoredExceptions;
47 StringRef(RawIgnoredExceptions).split(IgnoredExceptionsVec,
",", -1,
false);
48 IgnoredExceptions.insert_range(IgnoredExceptionsVec);
49 Tracer.ignoreExceptions(std::move(IgnoredExceptions));
50 Tracer.ignoreBadAlloc(
true);
54 Options.store(Opts,
"FunctionsThatShouldNotThrow",
55 RawFunctionsThatShouldNotThrow);
56 Options.store(Opts,
"IgnoredExceptions", RawIgnoredExceptions);
64 allOf(anyOf(cxxDestructorDecl(),
65 cxxConstructorDecl(isMoveConstructor()),
66 cxxMethodDecl(isMoveAssignmentOperator()), isMain(),
67 allOf(hasAnyName(
"swap",
"iter_swap",
"iter_move"),
68 hasAtLeastOneParameter())),
69 unless(isExplicitThrow())),
70 isEnabled(FunctionsThatShouldNotThrow)))
76 const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>(
"thrower");
87 diag(MatchedDecl->getLocation(),
"an exception may be thrown in function "
88 "%0 which should not throw exceptions")
91 const auto &[ThrowType, ThrowInfo] = *Info.getExceptions().begin();
93 if (ThrowInfo.Loc.isInvalid())
98 "frame #0: unhandled exception of type %0 may be thrown in function %1 "
101 << QualType(ThrowType, 0U) << Stack.back().first;
104 for (
auto CurrIt = ++Stack.rbegin(), PrevIt = Stack.rbegin();
105 CurrIt != Stack.rend(); ++CurrIt, ++PrevIt) {
106 const FunctionDecl *CurrFunction = CurrIt->first;
107 const FunctionDecl *PrevFunction = PrevIt->first;
108 const SourceLocation PrevLocation = PrevIt->second;
109 if (PrevLocation.isValid()) {
110 diag(PrevLocation,
"frame #%0: function %1 calls function %2 here",
112 << FrameNo << CurrFunction << PrevFunction;
114 diag(CurrFunction->getLocation(),
115 "frame #%0: function %1 calls function %2", DiagnosticIDs::Note)
116 << FrameNo << CurrFunction << PrevFunction;
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
ExceptionEscapeCheck(StringRef Name, ClangTidyContext *Context)
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Bundle the gathered information about an entity like a function regarding it's exception behaviour.
@ Throwing
The function can definitely throw given an AST.
llvm::MapVector< const FunctionDecl *, SourceLocation > CallStack
We use a MapVector to preserve the order of the functions in the call stack as well as have fast look...
ExceptionInfo analyze(const FunctionDecl *Func)
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)
AST_MATCHER(BinaryOperator, isRelationalOperator)
llvm::StringMap< ClangTidyValue > OptionMap