brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.6 KiB · 132b7dd Raw
92 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 "RedundantControlFlowCheck.h"10#include "clang/ASTMatchers/ASTMatchFinder.h"11#include "clang/Lex/Lexer.h"12 13using namespace clang::ast_matchers;14 15namespace clang::tidy::readability {16 17static const char *const RedundantReturnDiag =18    "redundant return statement at the end "19    "of a function with a void return type";20static const char *const RedundantContinueDiag =21    "redundant continue statement at the "22    "end of loop statement";23 24static bool isLocationInMacroExpansion(const SourceManager &SM,25                                       SourceLocation Loc) {26  return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);27}28 29void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {30  Finder->addMatcher(31      functionDecl(isDefinition(), returns(voidType()),32                   hasBody(compoundStmt(hasAnySubstatement(33                                            returnStmt(unless(has(expr())))))34                               .bind("return"))),35      this);36  Finder->addMatcher(37      mapAnyOf(forStmt, cxxForRangeStmt, whileStmt, doStmt)38          .with(hasBody(compoundStmt(hasAnySubstatement(continueStmt()))39                            .bind("continue"))),40      this);41}42 43void RedundantControlFlowCheck::check(const MatchFinder::MatchResult &Result) {44  if (const auto *Return = Result.Nodes.getNodeAs<CompoundStmt>("return"))45    checkRedundantReturn(Result, Return);46  else if (const auto *Continue =47               Result.Nodes.getNodeAs<CompoundStmt>("continue"))48    checkRedundantContinue(Result, Continue);49}50 51void RedundantControlFlowCheck::checkRedundantReturn(52    const MatchFinder::MatchResult &Result, const CompoundStmt *Block) {53  const CompoundStmt::const_reverse_body_iterator Last = Block->body_rbegin();54  if (const auto *Return = dyn_cast<ReturnStmt>(*Last))55    issueDiagnostic(Result, Block, Return->getSourceRange(),56                    RedundantReturnDiag);57}58 59void RedundantControlFlowCheck::checkRedundantContinue(60    const MatchFinder::MatchResult &Result, const CompoundStmt *Block) {61  const CompoundStmt::const_reverse_body_iterator Last = Block->body_rbegin();62  if (const auto *Continue = dyn_cast<ContinueStmt>(*Last))63    issueDiagnostic(Result, Block, Continue->getSourceRange(),64                    RedundantContinueDiag);65}66 67void RedundantControlFlowCheck::issueDiagnostic(68    const MatchFinder::MatchResult &Result, const CompoundStmt *const Block,69    const SourceRange &StmtRange, const char *const Diag) {70  const SourceManager &SM = *Result.SourceManager;71  if (isLocationInMacroExpansion(SM, StmtRange.getBegin()))72    return;73 74  const CompoundStmt::const_reverse_body_iterator Previous =75      ++Block->body_rbegin();76  SourceLocation Start;77  if (Previous != Block->body_rend())78    Start = Lexer::findLocationAfterToken(79        cast<Stmt>(*Previous)->getEndLoc(), tok::semi, SM, getLangOpts(),80        /*SkipTrailingWhitespaceAndNewLine=*/true);81  if (!Start.isValid())82    Start = StmtRange.getBegin();83  auto RemovedRange = CharSourceRange::getCharRange(84      Start, Lexer::findLocationAfterToken(85                 StmtRange.getEnd(), tok::semi, SM, getLangOpts(),86                 /*SkipTrailingWhitespaceAndNewLine=*/true));87 88  diag(StmtRange.getBegin(), Diag) << FixItHint::CreateRemoval(RemovedRange);89}90 91} // namespace clang::tidy::readability92