82 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//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(Options.get(IgnoreMacrosName, IgnoreMacrosDefault)),27 StrictMode(Options.get(StrictModeName, StrictModeDefault)) {}28 29void AvoidReturnWithVoidValueCheck::registerMatchers(MatchFinder *Finder) {30 Finder->addMatcher(31 returnStmt(32 hasReturnValue(allOf(hasType(voidType()), unless(initListExpr()))),33 optionally(hasParent(34 compoundStmt(35 optionally(hasParent(functionDecl().bind("function_parent"))))36 .bind("compound_parent"))))37 .bind("void_return"),38 this);39}40 41void AvoidReturnWithVoidValueCheck::check(42 const MatchFinder::MatchResult &Result) {43 const auto *VoidReturn = Result.Nodes.getNodeAs<ReturnStmt>("void_return");44 if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID())45 return;46 const auto *SurroundingBlock =47 Result.Nodes.getNodeAs<CompoundStmt>("compound_parent");48 if (!StrictMode && !SurroundingBlock)49 return;50 const DiagnosticBuilder Diag = diag(51 VoidReturn->getBeginLoc(), "return statement within a void function "52 "should not have a specified return value");53 const SourceLocation SemicolonPos = utils::lexer::findNextTerminator(54 VoidReturn->getEndLoc(), *Result.SourceManager, getLangOpts());55 if (SemicolonPos.isInvalid())56 return;57 if (!SurroundingBlock) {58 const auto BraceInsertionHints = utils::getBraceInsertionsHints(59 VoidReturn, getLangOpts(), *Result.SourceManager,60 VoidReturn->getBeginLoc());61 if (BraceInsertionHints)62 Diag << BraceInsertionHints.openingBraceFixIt()63 << BraceInsertionHints.closingBraceFixIt();64 }65 Diag << FixItHint::CreateRemoval(VoidReturn->getReturnLoc());66 const auto *FunctionParent =67 Result.Nodes.getNodeAs<FunctionDecl>("function_parent");68 if (!FunctionParent ||69 (SurroundingBlock && SurroundingBlock->body_back() != VoidReturn))70 // If this is not the last statement in a function body, we add a `return`.71 Diag << FixItHint::CreateInsertion(SemicolonPos.getLocWithOffset(1),72 " return;", true);73}74 75void AvoidReturnWithVoidValueCheck::storeOptions(76 ClangTidyOptions::OptionMap &Opts) {77 Options.store(Opts, IgnoreMacrosName, IgnoreMacros);78 Options.store(Opts, StrictModeName, StrictMode);79}80 81} // namespace clang::tidy::readability82