brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.2 KiB · 2b31281 Raw
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