1 //===--- AvoidReturnWithVoidValueCheck.cpp - clang-tidy -------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 #include "AvoidReturnWithVoidValueCheck.h"
10 #include "../utils/BracesAroundStatement.h"
11 #include "../utils/LexerUtils.h"
13 using namespace clang::ast_matchers
;
15 namespace clang::tidy::readability
{
17 static constexpr char IgnoreMacrosName
[] = "IgnoreMacros";
18 static const bool IgnoreMacrosDefault
= true;
20 static constexpr char StrictModeName
[] = "StrictMode";
21 static const bool StrictModeDefault
= true;
23 AvoidReturnWithVoidValueCheck::AvoidReturnWithVoidValueCheck(
24 StringRef Name
, ClangTidyContext
*Context
)
25 : ClangTidyCheck(Name
, Context
),
27 Options
.getLocalOrGlobal(IgnoreMacrosName
, IgnoreMacrosDefault
)),
28 StrictMode(Options
.getLocalOrGlobal(StrictModeName
, StrictModeDefault
)) {}
30 void AvoidReturnWithVoidValueCheck::registerMatchers(MatchFinder
*Finder
) {
33 hasReturnValue(allOf(hasType(voidType()), unless(initListExpr()))),
36 optionally(hasParent(functionDecl().bind("function_parent"))))
37 .bind("compound_parent"))))
42 void AvoidReturnWithVoidValueCheck::check(
43 const MatchFinder::MatchResult
&Result
) {
44 const auto *VoidReturn
= Result
.Nodes
.getNodeAs
<ReturnStmt
>("void_return");
45 if (IgnoreMacros
&& VoidReturn
->getBeginLoc().isMacroID())
47 const auto *SurroundingBlock
=
48 Result
.Nodes
.getNodeAs
<CompoundStmt
>("compound_parent");
49 if (!StrictMode
&& !SurroundingBlock
)
51 DiagnosticBuilder Diag
= diag(VoidReturn
->getBeginLoc(),
52 "return statement within a void function "
53 "should not have a specified return value");
54 const SourceLocation SemicolonPos
= utils::lexer::findNextTerminator(
55 VoidReturn
->getEndLoc(), *Result
.SourceManager
, getLangOpts());
56 if (SemicolonPos
.isInvalid())
58 if (!SurroundingBlock
) {
59 const auto BraceInsertionHints
= utils::getBraceInsertionsHints(
60 VoidReturn
, getLangOpts(), *Result
.SourceManager
,
61 VoidReturn
->getBeginLoc());
62 if (BraceInsertionHints
)
63 Diag
<< BraceInsertionHints
.openingBraceFixIt()
64 << BraceInsertionHints
.closingBraceFixIt();
66 Diag
<< FixItHint::CreateRemoval(VoidReturn
->getReturnLoc());
67 const auto *FunctionParent
=
68 Result
.Nodes
.getNodeAs
<FunctionDecl
>("function_parent");
69 if (!FunctionParent
||
70 (SurroundingBlock
&& SurroundingBlock
->body_back() != VoidReturn
))
71 // If this is not the last statement in a function body, we add a `return`.
72 Diag
<< FixItHint::CreateInsertion(SemicolonPos
.getLocWithOffset(1),
76 void AvoidReturnWithVoidValueCheck::storeOptions(
77 ClangTidyOptions::OptionMap
&Opts
) {
78 Options
.store(Opts
, IgnoreMacrosName
, IgnoreMacros
);
79 Options
.store(Opts
, StrictModeName
, StrictMode
);
82 } // namespace clang::tidy::readability