10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/AST/Type.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
22 const llvm::StringRef &MacroId) {
25 if (MacroId.startswith(
"[[") || MacroId.startswith(
"__attribute__"))
29 return Context.Idents.get(MacroId).hasMacroDefinition();
35 return Node.isOverloadedOperator();
40 return isa<CXXConversionDecl>(Node);
45 return Node.getParent()->hasMutableFields();
49 return Node.isParameterPack();
54 return Node.getReturnType()->isTemplateTypeParmType() ||
55 Node.getReturnType()->isInstantiationDependentType();
59 return !(Node.isThisDeclarationADefinition() && Node.isOutOfLine());
61 AST_MATCHER(QualType, isInstantiationDependentType) {
62 return Node->isInstantiationDependentType();
64 AST_MATCHER(QualType, isNonConstReferenceOrPointer) {
71 return (Node->isTemplateTypeParmType() || Node->isPointerType() ||
72 (Node->isReferenceType() &&
73 !Node.getNonReferenceType().isConstQualified()) ||
74 Node->isInstantiationDependentType());
78 UseNodiscardCheck::UseNodiscardCheck(StringRef
Name, ClangTidyContext *Context)
79 : ClangTidyCheck(
Name, Context),
80 NoDiscardMacro(Options.get(
"ReplacementString",
"[[nodiscard]]")) {}
83 Options.store(Opts,
"ReplacementString", NoDiscardMacro);
86 void UseNodiscardCheck::registerMatchers(MatchFinder *Finder) {
88 cxxRecordDecl(hasAnyName(
"::std::function",
"::boost::function"));
94 allOf(isConst(), isDefinitionOrInline(),
97 returns(hasDeclaration(decl(hasAttr(clang::attr::WarnUnusedResult)))),
98 isNoReturn(), isOverloadedOperator(),
99 isVariadic(), hasTemplateReturnType(),
100 hasClassMutableFields(), isConversionOperator(),
101 hasAttr(clang::attr::WarnUnusedResult),
102 hasType(isInstantiationDependentType()),
103 hasAnyParameter(anyOf(
104 parmVarDecl(anyOf(hasType(FunctionObj),
105 hasType(references(FunctionObj)))),
106 hasType(isNonConstReferenceOrPointer()),
107 hasParameterPack()))))))
112 void UseNodiscardCheck::check(
const MatchFinder::MatchResult &Result) {
113 const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXMethodDecl>(
"no_discard");
115 SourceLocation
Loc = MatchedDecl->getLocation();
116 if (
Loc.isInvalid() ||
Loc.isMacroID())
119 SourceLocation RetLoc = MatchedDecl->getInnerLocStart();
121 ASTContext &Context = *Result.Context;
123 auto Diag = diag(RetLoc,
"function %0 should be marked " + NoDiscardMacro)
134 Diag << FixItHint::CreateInsertion(RetLoc, NoDiscardMacro +
" ");
137 bool UseNodiscardCheck::isLanguageVersionSupported(
138 const LangOptions &LangOpts)
const {
143 if (NoDiscardMacro ==
"[[nodiscard]]")
144 return LangOpts.CPlusPlus17;
146 return LangOpts.CPlusPlus;