Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -11,6 +11,7 @@ NamedParameterCheck.cpp NamespaceCommentCheck.cpp ReadabilityTidyModule.cpp + RedundantReturnCheck.cpp RedundantStringCStrCheck.cpp RedundantSmartptrGetCheck.cpp SimplifyBooleanExprCheck.cpp Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -18,6 +18,7 @@ #include "ImplicitBoolCastCheck.h" #include "InconsistentDeclarationParameterNameCheck.h" #include "NamedParameterCheck.h" +#include "RedundantReturnCheck.h" #include "RedundantSmartptrGetCheck.h" #include "RedundantStringCStrCheck.h" #include "SimplifyBooleanExprCheck.h" @@ -44,6 +45,8 @@ "readability-implicit-bool-cast"); CheckFactories.registerCheck( "readability-inconsistent-declaration-parameter-name"); + CheckFactories.registerCheck( + "readability-redundant-return"); CheckFactories.registerCheck( "readability-uniqueptr-delete-release"); CheckFactories.registerCheck( Index: clang-tidy/readability/RedundantReturnCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantReturnCheck.h @@ -0,0 +1,47 @@ +//===--- RedundantReturnCheck.h - clang-tidy---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_RETURN_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_RETURN_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// Eliminates redundant `return` statements at the end of a function that +/// returns `void`. +/// +/// Eliminates redundant `continue` statements at the end of a loop body. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-return.html +class RedundantReturnCheck : public ClangTidyCheck { +public: + RedundantReturnCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + void + checkRedundantReturn(const ast_matchers::MatchFinder::MatchResult &Result, + const FunctionDecl *Fn); + + void + checkRedundantContinue(const ast_matchers::MatchFinder::MatchResult &Result, + const CompoundStmt *Block); +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_RETURN_H Index: clang-tidy/readability/RedundantReturnCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantReturnCheck.cpp @@ -0,0 +1,106 @@ +//===--- RedundantReturnCheck.cpp - clang-tidy-----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RedundantReturnCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace readability { + +void RedundantReturnCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + functionDecl(isDefinition(), returns(asString("void")), + has(compoundStmt(hasAnySubstatement(returnStmt())))) + .bind("fn"), + this); + auto CompoundContinue = has(compoundStmt(hasAnySubstatement(continueStmt()))); + Finder->addMatcher(forStmt(CompoundContinue).bind("for"), this); + Finder->addMatcher(whileStmt(CompoundContinue).bind("while"), this); + Finder->addMatcher(doStmt(CompoundContinue).bind("do"), this); +} + +void RedundantReturnCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *Fn = Result.Nodes.getNodeAs("fn")) { + checkRedundantReturn(Result, Fn); + } else if (const auto *For = Result.Nodes.getNodeAs("for")) { + checkRedundantContinue(Result, dyn_cast(For->getBody())); + } else if (const auto *While = Result.Nodes.getNodeAs("while")) { + checkRedundantContinue(Result, dyn_cast(While->getBody())); + } else if (const auto *Do = Result.Nodes.getNodeAs("do")) { + checkRedundantContinue(Result, dyn_cast(Do->getBody())); + } +} + +void RedundantReturnCheck::checkRedundantReturn( + const MatchFinder::MatchResult &Result, const FunctionDecl *Fn) { + if (const auto *Block = dyn_cast(Fn->getBody())) { + CompoundStmt::const_reverse_body_iterator last = Block->body_rbegin(); + if (const auto *Return = dyn_cast(*last)) { + CompoundStmt::const_reverse_body_iterator Previous = + ++Block->body_rbegin(); + SourceLocation Start; + if (Previous != Block->body_rend()) { + Start = Lexer::findLocationAfterToken( + dyn_cast(*Previous)->getLocEnd(), tok::semi, + *Result.SourceManager, Result.Context->getLangOpts(), + /*SkipTrailingWhitespaceAndNewLine=*/true); + } else { + Start = Return->getLocStart(); + } + auto ReturnRange = CharSourceRange::getCharRange( + Start, Lexer::findLocationAfterToken( + Return->getLocEnd(), tok::semi, *Result.SourceManager, + Result.Context->getLangOpts(), + /*SkipTrailingWhitespaceAndNewLine=*/true)); + + diag(Return->getLocStart(), + "redundant return statement at the end of void function") + << FixItHint::CreateRemoval(ReturnRange); + } + } +} + +void RedundantReturnCheck::checkRedundantContinue( + const ast_matchers::MatchFinder::MatchResult &Result, + const CompoundStmt *Block) { + if (Block) { + CompoundStmt::const_reverse_body_iterator last = Block->body_rbegin(); + if (const auto *Continue = dyn_cast(*last)) { + CompoundStmt::const_reverse_body_iterator Previous = + ++Block->body_rbegin(); + SourceLocation Start; + if (Previous != Block->body_rend()) { + Start = Lexer::findLocationAfterToken( + dyn_cast(*Previous)->getLocEnd(), tok::semi, + *Result.SourceManager, Result.Context->getLangOpts(), + /*SkipTrailingWhitespaceAndNewLine=*/true); + } else { + Start = Continue->getLocStart(); + } + auto ContinueRange = CharSourceRange::getCharRange( + Start, Lexer::findLocationAfterToken( + Continue->getLocEnd(), tok::semi, *Result.SourceManager, + Result.Context->getLangOpts(), + /*SkipTrailingWhitespaceAndNewLine=*/true)); + + diag(Continue->getLocStart(), + "redundant continue statement at the end of for statement") + << FixItHint::CreateRemoval(ContinueRange); + } + } +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -76,6 +76,7 @@ readability-implicit-bool-cast readability-inconsistent-declaration-parameter-name readability-named-parameter + readability-redundant-return readability-redundant-smartptr-get readability-redundant-string-cstr readability-simplify-boolean-expr Index: docs/clang-tidy/checks/readability-redundant-return.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/readability-redundant-return.rst @@ -0,0 +1,10 @@ +.. title:: clang-tidy - readability-redundant-return + +readability-redundant-return +============================ + +This check looks for procedures (functions returning no value) with `return` +statements at the end of the function. Such `return` statements are redundant. + +Loop statements (`for`, `while`, `do while`) are checked for redundant +`continue` statements at the end of the loop body. Index: test/clang-tidy/readability-redundant-return.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-return.cpp @@ -0,0 +1,68 @@ +// RUN: %check_clang_tidy %s readability-redundant-return %t + +void g(int i); +void j(); + +void f() { + return; +} +// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: redundant return statement at the end of void function [readability-redundant-return] +// CHECK-FIXES: {{^}}void f() {{{$}} +// CHECK-FIXES-NEXT: {{^ *}$}} + +void g() { + f(); + return; +} +// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: redundant return statement +// CHECK-FIXES: {{^ }}f();{{$}} +// CHECK-FIXES-NEXT: {{^ *}$}} + +void g(int i) { + if (i < 0) { + return; + } + if (i < 10) { + f(); + } +} + +int h() { + return 1; +} + +void j() { +} + +void k() { + for (int i = 0; i < 10; ++i) { + continue; + } +} +// CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant continue statement +// CHECK-FIXES: {{^}} for (int i = 0; i < 10; ++i) {{{$}} +// CHECK-FIXES-NEXT: {{^ *}$}} + +void m() { + int i = 0; + do { + ++i; + continue; + } while (i < 10); +} +// CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant continue statement +// CHECK-FIXES: {{^ do {$}} +// CHECK-FIXES-NEXT: {{^}} ++i;{{$}} +// CHECK-FIXES-NEXT: {{^ *}}} while (i < 10);{{$}} + +void p() { + int i = 0; + while (i < 10) { + ++i; + continue; + } +} +// CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant continue statement +// CHECK-FIXES: {{^}} while (i < 10) {{{$}} +// CHECK-FIXES-NEXT: {{^}} ++i;{{$}} +// CHECK-FIXES-NEXT: {{^ *}$}}