1//===--- AvoidReturnWithVoidValueCheck.cpp - clang-tidy -------------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "AvoidReturnWithVoidValueCheck.h"
10#include "../utils/BracesAroundStatement.h"
11#include "../utils/LexerUtils.h"
12
13using namespace clang::ast_matchers;
14
15namespace clang::tidy::readability {
16
17static constexpr char IgnoreMacrosName[] = "IgnoreMacros";
18static const bool IgnoreMacrosDefault = true;
19
20static constexpr char StrictModeName[] = "StrictMode";
21static const bool StrictModeDefault = true;
22
23AvoidReturnWithVoidValueCheck::AvoidReturnWithVoidValueCheck(
24 StringRef Name, ClangTidyContext *Context)
25 : ClangTidyCheck(Name, Context),
26 IgnoreMacros(
27 Options.getLocalOrGlobal(LocalName: IgnoreMacrosName, Default: IgnoreMacrosDefault)),
28 StrictMode(Options.getLocalOrGlobal(LocalName: StrictModeName, Default: StrictModeDefault)) {}
29
30void AvoidReturnWithVoidValueCheck::registerMatchers(MatchFinder *Finder) {
31 Finder->addMatcher(
32 NodeMatch: returnStmt(
33 hasReturnValue(InnerMatcher: allOf(hasType(InnerMatcher: voidType()), unless(initListExpr()))),
34 optionally(hasParent(
35 compoundStmt(
36 optionally(hasParent(functionDecl().bind(ID: "function_parent"))))
37 .bind(ID: "compound_parent"))))
38 .bind(ID: "void_return"),
39 Action: this);
40}
41
42void AvoidReturnWithVoidValueCheck::check(
43 const MatchFinder::MatchResult &Result) {
44 const auto *VoidReturn = Result.Nodes.getNodeAs<ReturnStmt>(ID: "void_return");
45 if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID())
46 return;
47 const auto *SurroundingBlock =
48 Result.Nodes.getNodeAs<CompoundStmt>(ID: "compound_parent");
49 if (!StrictMode && !SurroundingBlock)
50 return;
51 DiagnosticBuilder Diag = diag(Loc: VoidReturn->getBeginLoc(),
52 Description: "return statement within a void function "
53 "should not have a specified return value");
54 const SourceLocation SemicolonPos = utils::lexer::findNextTerminator(
55 Start: VoidReturn->getEndLoc(), SM: *Result.SourceManager, LangOpts: getLangOpts());
56 if (SemicolonPos.isInvalid())
57 return;
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();
65 }
66 Diag << FixItHint::CreateRemoval(RemoveRange: VoidReturn->getReturnLoc());
67 if (!Result.Nodes.getNodeAs<FunctionDecl>(ID: "function_parent") ||
68 SurroundingBlock->body_back() != VoidReturn)
69 Diag << FixItHint::CreateInsertion(InsertionLoc: SemicolonPos.getLocWithOffset(Offset: 1),
70 Code: " return;", BeforePreviousInsertions: true);
71}
72
73void AvoidReturnWithVoidValueCheck::storeOptions(
74 ClangTidyOptions::OptionMap &Opts) {
75 Options.store(Options&: Opts, LocalName: IgnoreMacrosName, Value: IgnoreMacros);
76 Options.store(Options&: Opts, LocalName: StrictModeName, Value: StrictMode);
77}
78
79} // namespace clang::tidy::readability
80

source code of clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp