Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -22,6 +22,7 @@ ReadabilityTidyModule.cpp RedundantControlFlowCheck.cpp RedundantDeclarationCheck.cpp + RedundantExternCheck.cpp RedundantFunctionPtrDereferenceCheck.cpp RedundantMemberInitCheck.cpp RedundantPreprocessorCheck.cpp Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -29,6 +29,7 @@ #include "RedundantControlFlowCheck.h" #include "RedundantDeclarationCheck.h" #include "RedundantFunctionPtrDereferenceCheck.h" +#include "RedundantExternCheck.h" #include "RedundantMemberInitCheck.h" #include "RedundantPreprocessorCheck.h" #include "RedundantSmartptrGetCheck.h" @@ -79,6 +80,8 @@ "readability-misleading-indentation"); CheckFactories.registerCheck( "readability-misplaced-array-index"); + CheckFactories.registerCheck( + "readability-redundant-extern"); CheckFactories.registerCheck( "readability-redundant-function-ptr-dereference"); CheckFactories.registerCheck( Index: clang-tidy/readability/RedundantExternCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantExternCheck.h @@ -0,0 +1,34 @@ +//===--- RedundantExternCheck.h - clang-tidy --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_EXTERN_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_EXTERN_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// Finds redundant 'extern' keywords +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-extern.html +class RedundantExternCheck : public ClangTidyCheck { +public: + RedundantExternCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_EXTERN_H Index: clang-tidy/readability/RedundantExternCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantExternCheck.cpp @@ -0,0 +1,70 @@ +//===--- RedundantExternCheck.cpp - clang-tidy ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "RedundantExternCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +AST_MATCHER(clang::FunctionDecl, hasExternStorageClass) { + return Node.getStorageClass() == clang::SC_Extern; +} + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace readability { + +void RedundantExternCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(functionDecl(hasExternStorageClass(), unless(isExternC())) + .bind("redundant_extern"), + this); +} + +void RedundantExternCheck::check(const MatchFinder::MatchResult &Result) { + auto *FD = Result.Nodes.getNodeAs("redundant_extern"); + SourceLocation BeginLoc = FD->getBeginLoc(); + SourceLocation EndLoc = FD->getEndLoc(); + + StringRef Message; + + if (FD->getLinkageInternal() == InternalLinkage) { + Message = "'extern' keyword has no effect"; + } else { + Message = "redundant 'extern' keyword"; + } + + auto Diag = diag(FD->getBeginLoc(), Message); + + if (FD->getBeginLoc().isMacroID()) + return; + + StringRef Text = + Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), + *Result.SourceManager, getLangOpts()); + + llvm::StringLiteral Extern = llvm::StringLiteral("extern"); + int Offset = Text.find(Extern); + + SourceRange ExternRange(BeginLoc.getLocWithOffset(Offset), + BeginLoc.getLocWithOffset(Offset + Extern.size())); + + StringRef ExternText = + Lexer::getSourceText(CharSourceRange::getTokenRange(ExternRange), + *Result.SourceManager, getLangOpts()); + + if (!ExternText.equals(Extern)) // Final check: typedefs, etc. + return; + + Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(ExternRange)); +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -240,6 +240,11 @@ but either don't specify it or the clause is specified but with the kind other than ``none``, and suggests to use the ``default(none)`` clause. +- New :doc:`readability-redundant-extern + ` check. + + Removes the redundant ``extern`` keywords. + Improvements to clang-include-fixer ----------------------------------- Index: docs/clang-tidy/checks/readability-redundant-extern.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/readability-redundant-extern.rst @@ -0,0 +1,30 @@ +.. title:: clang-tidy - readability-redundant-extern + +readability-redundant-extern +============================ + +Removes the redundant or unnecessary ``extern`` keywords from code. + +``extern`` is redundant in function declarations, and has no effect in +namespaces + +The default language linkage is C++, so without any additional parameters +it is redundant (extern "C++" can also be redundant, but it depends on +the context). In C context (extern "C") the situation is the same, extern +keyword is redundant for function declarations + +.. code-block:: c++ + + extern void h(); + + namespace { + extern void namespace_1(); + } + + #define FOO_EXTERN extern + FOO_EXTERN void foo_macro_1(); + + #define FOO_EXTERN extern + typedef int extern_int; + extern_int FOO_EXTERN typedef_extern_foo(); + Index: test/clang-tidy/readability-redundant-extern.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-extern.cpp @@ -0,0 +1,74 @@ +// RUN: %check_clang_tidy %s readability-redundant-extern %t + +extern int f(); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: redundant 'extern' keyword [readability-redundant-extern] +// CHECK-FIXES: int f(); + +int extern f() { return 0; } +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: redundant 'extern' keyword [readability-redundant-extern] +// CHECK-FIXES: int f() { return 0; } + +extern "C" int g(); +// CHECK-FIXES: extern "C" int g(); + +extern "C" int g() { return 0; } +// CHECK-FIXES: extern "C" int g() { return 0; } + +extern "C++" int h(); +// CHECK-FIXES: extern "C++" int h(); + +extern "C++" int h() { return 0; } +// CHECK-FIXES: extern "C++" int h() { return 0; } + +inline extern void foo_inline(); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: redundant 'extern' keyword [readability-redundant-extern] +// CHECK-FIXES: inline void foo_inline(); + +#define FOO_EXTERN extern +FOO_EXTERN void foo_macro_1(); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: redundant 'extern' keyword [readability-redundant-extern] +// CHECK-FIXES: FOO_EXTERN void foo_macro_1(); + +#define FOO_INLINE inline +FOO_INLINE extern void foo_macro_2(); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: redundant 'extern' keyword [readability-redundant-extern] +// CHECK-FIXES: FOO_INLINE extern void foo_macro_2(); + +#define FOO_EXTERN_INLINE inline extern +FOO_EXTERN_INLINE void foo_macro_3(); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: redundant 'extern' keyword [readability-redundant-extern] +// CHECK-FIXES: FOO_EXTERN_INLINE void foo_macro_3(); + +void file_scope(); +// CHECK-FIXES: void file_scope(); + +void another_file_scope(int _extern); +// CHECK-FIXES: void another_file_scope(int _extern); + +namespace { +extern void namespace_1(); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: 'extern' keyword has no effect [readability-redundant-extern] +// CHECK-FIXES: void namespace_1(); +} + +namespace a { +namespace { +namespace b { +extern void namespace_2(); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: 'extern' keyword has no effect [readability-redundant-extern] +// CHECK-FIXES: void namespace_2(); +} +} +} + +namespace { +extern "C" void namespace_3(); +// CHECK-FIXES: extern "C" void namespace_3(); +} + +#define FOO_EXTERN extern +typedef int extern_int; + +extern_int FOO_EXTERN typedef_extern_foo(); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: redundant 'extern' keyword [readability-redundant-extern] +// CHECK-FIXES: extern_int FOO_EXTERN typedef_extern_foo();