<div dir="ltr"><div dir="ltr"><div>I'm trying to write a "use [[nodiscard]]" clang-tidy checker/fix-it to advise when a function might benefit from having [[nodiscard]] added </div><div><br></div><div>Mostly this is working working except I'm finding the wrong location for the place to put the [[nodiscard]] for functions which have const,inline or virtual kewords infront of the return type. </div><div><br></div><div>e.g. </div><div><br></div><div>test.cxx:18:5: warning: function '

empty ' should be made [[nodiscard]] [modernize-use-nodiscard] </div><div>    bool empty() const </div><div>    ^ </div><div>    [[nodiscard]] </div><div>test.cxx:26:5: warning: function '

empty' should be made [[nodiscard]] [modernize-use-nodiscard] </div><div>    bool 

empty(const A &val) const </div><div>    ^ </div><div>    [[nodiscard]] </div><div>test.cxx:50:11: warning: function '

empty' should be made [[nodiscard]] [modernize-use-nodiscard] </div><div>    const bool 

empty() const </div><div>          ^ </div><div>          [[nodiscard]] </div><div>test.cxx:55:18: warning: function '

empty ' should be made [[nodiscard]] [modernize-use-nodiscard] </div><div>    inline const bool 

empty() const </div><div>                 ^ </div><div>                 [[nodiscard]] </div><div><br></div><div>And some compilers don't like the [[nodiscard] being placed in between those keywords and the return type (preferring them to be at the front of the function) </div><div><br></div><div>I'm currently using (following a series of trail and errors) to find the location just before the return type</div><div>MatchedDecl->getReturnTypeSourceRange().getBegin()</div><div><br></div><div>e.g. </div><div><br></div><div>// This function could be marked [[nodiscard]] </div><div>  diag(MatchedDecl->getReturnTypeSourceRange().getBegin(), </div><div>       "function %0 should be marked [[nodiscard]]") </div><div>      << MatchedDecl </div><div>      << FixItHint::CreateInsertion( </div><div>             MatchedDecl->getReturnTypeSourceRange().getBegin(), </div><div>             "[[nodiscard]] "); </div><div><br></div><div><br></div><div>Does anyone know how I should correctly identify the position in front of all the keywords(virtual,inline,const)? </div><div><br></div><div>Especially in the case where the return type is on a different source code line </div><div><br></div><div>e.g. </div><div>virtual </div><div>const bool full() </div><div><br></div><div>Many thanks in advance, feel free to point out any other "errors of my ways" as this is my first ever checker.</div><div><br></div><div>MyDeveloperDay </div><div><br></div><div>a current copy of the current checker code is presented here for completeness </div><div>------------------------------------------------------------------------------ </div><div>namespace clang { </div><div>namespace tidy { </div><div>namespace modernize { </div><div><br></div><div>void UseNodiscardCheck::registerMatchers(MatchFinder *Finder) { </div><div><br></div><div>  Finder->addMatcher( </div><div>      cxxMethodDecl(eachOf(unless(returns(voidType())), (isConst()))) </div><div>          .bind("noDiscardCandidate"), </div><div>      this); </div><div>} </div><div><br></div><div>static bool isNonConstReferenceType(QualType ParamType) { </div><div>  return ParamType->isReferenceType() && </div><div>         !ParamType.getNonReferenceType().isConstQualified(); </div><div>} </div><div><br></div><div>static bool isOperator(const FunctionDecl *D) { </div><div>  return D->getNameAsString().find("operator") != std::string::npos; </div><div>} </div><div><br></div><div>static bool isInternalFunction(const FunctionDecl *D) { </div><div>  return D->getNameAsString().find("_") == 0; </div><div>} </div><div><br></div><div>void UseNodiscardCheck::check(const MatchFinder::MatchResult &Result) { </div><div>  const auto *MatchedDecl = </div><div>      Result.Nodes.getNodeAs<CXXMethodDecl>("noDiscardCandidate"); </div><div><br></div><div>  // if the localtion is invalid forget it </div><div>  if (!MatchedDecl->getLocation().isValid()) </div><div>    return; </div><div><br></div><div>  // does it already have [[nodiscard]] </div><div>  if (MatchedDecl->hasUnusedResultAttr()) </div><div>    return; </div><div><br></div><div>  // if the function is const it can't be modifying </div><div>  // something locally so more likely the result is important </div><div>  if (!MatchedDecl->isConst()) </div><div>    return; </div><div><br></div><div>  // if the function is a void or is marked no return then </div><div>  // its not a canidate </div><div>  if (MatchedDecl->isNoReturn() || </div><div>      MatchedDecl->getReturnType().getAsString() == "void") </div><div>    return; </div><div><br></div><div>  // don't add [[nodiscard]] to any operators </div><div>  if (isOperator(MatchedDecl)) </div><div>    return; </div><div><br></div><div>  // don't add [[nodiscard]] to anything marked as _Foo() </div><div>  if (isInternalFunction(MatchedDecl)) </div><div>    return; </div><div><br></div><div>  // if the function has any non constant reference parameters </div><div>  // e.g. foo(A &a) </div><div>  // the may not care about the return because we may be passing data </div><div>  // via the non const reference </div><div>  // functions with no arguments will fall through  foo() </div><div>  for (const auto *Par : MatchedDecl->parameters()) { </div><div>    const Type *ParType = Par->getType().getTypePtr(); </div><div><br></div><div>    if (isNonConstReferenceType(Par->getType())) { </div><div>      return; </div><div>    } </div><div>  } </div><div><br></div><div>  // This function could be marked [[nodiscard]] </div><div>  diag(MatchedDecl->getReturnTypeSourceRange().getBegin(), </div><div>       "function %0 should be marked [[nodiscard]]") </div><div>      << MatchedDecl </div><div>      << FixItHint::CreateInsertion( </div><div>             MatchedDecl->getReturnTypeSourceRange().getBegin(), </div><div>             "[[nodiscard]] "); </div><div>  return; </div><div>} </div><div><br></div><div>} // namespace modernize </div><div>} // namespace tidy </div><div>} // namespace clang </div></div></div>