diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -36,6 +36,7 @@ RedundantSmartptrGetCheck.cpp RedundantStringCStrCheck.cpp RedundantStringInitCheck.cpp + RedundantUsingCheck.cpp SimplifyBooleanExprCheck.cpp SimplifySubscriptExprCheck.cpp StaticAccessedThroughInstanceCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -39,6 +39,7 @@ #include "RedundantSmartptrGetCheck.h" #include "RedundantStringCStrCheck.h" #include "RedundantStringInitCheck.h" +#include "RedundantUsingCheck.h" #include "SimplifyBooleanExprCheck.h" #include "SimplifySubscriptExprCheck.h" #include "StaticAccessedThroughInstanceCheck.h" @@ -101,6 +102,8 @@ "readability-redundant-member-init"); CheckFactories.registerCheck( "readability-redundant-preprocessor"); + CheckFactories.registerCheck( + "readability-redundant-using"); CheckFactories.registerCheck( "readability-simplify-subscript-expr"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/readability/RedundantUsingCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantUsingCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantUsingCheck.h @@ -0,0 +1,44 @@ +//===--- RedundantUsingCheck.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_REDUNDANTUSINGCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTUSINGCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// Finds redundant using declarations and directives. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-using.html +class RedundantUsingCheck : public ClangTidyCheck { +public: + RedundantUsingCheck(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 checkUsingDecl(const UsingDecl *Declaration, + const ast_matchers::MatchFinder::MatchResult &Result); + void + checkUsingDirective(const UsingDirectiveDecl *Directive, + const ast_matchers::MatchFinder::MatchResult &Result); + void diagUsing(int Type, const Decl *Using, const NamedDecl *ND, + const NamespaceDecl *NSD, + const ast_matchers::MatchFinder::MatchResult &Result); +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTUSINGCHECK_H diff --git a/clang-tools-extra/clang-tidy/readability/RedundantUsingCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantUsingCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantUsingCheck.cpp @@ -0,0 +1,82 @@ +//===--- RedundantUsingCheck.cpp - clang-tidy -----------------------------===// +// +// 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 "RedundantUsingCheck.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 RedundantUsingCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(usingDecl().bind("using-declaration"), this); + Finder->addMatcher(usingDirectiveDecl().bind("using-directive"), this); +} + +void RedundantUsingCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *Declaration = + Result.Nodes.getNodeAs("using-declaration")) + checkUsingDecl(Declaration, Result); + + if (const auto *Directive = + Result.Nodes.getNodeAs("using-directive")) + checkUsingDirective(Directive, Result); +} + +void RedundantUsingCheck::checkUsingDecl( + const UsingDecl *Declaration, const MatchFinder::MatchResult &Result) { + const DeclContext *DC = Declaration->getDeclContext(); + + for (const UsingShadowDecl *UsingShadow : Declaration->shadows()) { + const Decl *TargetDecl = UsingShadow->getTargetDecl()->getCanonicalDecl(); + + if (TargetDecl->getDeclContext()->Encloses(DC)) { + const auto *NSD = cast(TargetDecl->getDeclContext()); + diagUsing(0, Declaration, Declaration, NSD, Result); + break; + } + } +} + +void RedundantUsingCheck::checkUsingDirective( + const UsingDirectiveDecl *Directive, + const MatchFinder::MatchResult &Result) { + const NamespaceDecl *NDNominated = Directive->getNominatedNamespace(); + const DeclContext *DC = Directive->getDeclContext(); + + if (NDNominated->Encloses(DC)) { + const NamedDecl *NDAsWritten = Directive->getNominatedNamespaceAsWritten(); + + diagUsing(1, Directive, NDAsWritten, NDNominated, Result); + } +} +void RedundantUsingCheck::diagUsing(int Type, const Decl *Using, + const NamedDecl *ND, + const NamespaceDecl *NSD, + const MatchFinder::MatchResult &Result) { + SourceLocation End = + Lexer::findLocationAfterToken(Using->getEndLoc(), tok::semi, + *Result.SourceManager, getLangOpts(), true); + CharSourceRange RemoveRange = + CharSourceRange::getCharRange(Using->getBeginLoc(), End); + + diag(Using->getLocation(), "using %select{declaration|directive}0 %1 is " + "redundant, already in namespace %2") + << Type << ND << NSD; + diag(Using->getLocation(), "remove the using %select{declaration|directive}0", + DiagnosticIDs::Note) + << Type << FixItHint::CreateRemoval(RemoveRange); +} + +} // namespace readability +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -85,6 +85,11 @@ Finds member initializations in the constructor body which can be placed into the initialization list instead. +- New :doc:`readability-redundant-using + ` check. + + Finds redundant ``using`` declarations and directives. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -304,6 +304,7 @@ `readability-redundant-smartptr-get `_, "Yes" `readability-redundant-string-cstr `_, "Yes" `readability-redundant-string-init `_, "Yes" + `readability-redundant-using `_, "Yes" `readability-simplify-boolean-expr `_, "Yes" `readability-simplify-subscript-expr `_, "Yes" `readability-static-accessed-through-instance `_, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-using.rst b/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-using.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-using.rst @@ -0,0 +1,25 @@ +.. title:: clang-tidy - readability-redundant-using + +readability-redundant-using +=========================== + +Finds redundant ``using`` declarations and directives. + +Example: + +.. code-block:: c++ + + namespace n { + void func(); + } + + namespace { + using n::func; // redundant using declaration, already in namespace 'n'. + } + +.. code-block:: c++ + + namespace n { + using namespace n; // redundant using directive, already in namespace 'n'. + } + diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-redundant-using.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-redundant-using.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-redundant-using.cpp @@ -0,0 +1,114 @@ +// RUN: %check_clang_tidy %s readability-redundant-using %t + +namespace n1 { +using namespace n1; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: using directive 'n1' is redundant, already in namespace 'n1' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:17: note: remove the using directive +// CHECK-FIXES: {{^}} +} // namespace n1 + +namespace n2 { +using namespace n1; // ok +} + +namespace n3 { +namespace n = n3; +using namespace n; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: using directive 'n' is redundant, already in namespace 'n3' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:17: note: remove the using directive +// CHECK-FIXES: {{^}} +} // namespace n3 + +namespace n4 { +namespace inner { +using namespace n4; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: using directive 'n4' is redundant, already in namespace 'n4' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:17: note: remove the using directive +// CHECK-FIXES: {{^}} + +using namespace n4::inner; +// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: using directive 'inner' is redundant, already in namespace 'inner' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:21: note: remove the using directive +// CHECK-FIXES: {{^}} + +namespace n = n4::inner; +using namespace n; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: using directive 'n' is redundant, already in namespace 'inner' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:17: note: remove the using directive +// CHECK-FIXES: {{^}} +} // namespace inner +} // namespace n4 + +namespace n5 { +namespace inner { +using namespace n4::inner; // ok +} +} // namespace n5 + +namespace n6 { +void func(); + +using n6::func; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: using declaration 'func' is redundant, already in namespace 'n6' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:11: note: remove the using declaration +// CHECK-FIXES: {{^}} +} // namespace n6 + +namespace n7 { +using n6::func; // ok +} + +namespace n8 { +void func(); + +namespace n = n8; +using n::func; +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using declaration 'func' is redundant, already in namespace 'n8' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:10: note: remove the using declaration +// CHECK-FIXES: {{^}} +} // namespace n8 + +namespace n9 { +void outerFunc(); + +namespace inner { +using n9::outerFunc; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: using declaration 'outerFunc' is redundant, already in namespace 'n9' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:11: note: remove the using declaration +// CHECK-FIXES: {{^}} + +void innerFunc(); +using inner::innerFunc; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: using declaration 'innerFunc' is redundant, already in namespace 'inner' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:14: note: remove the using declaration +// CHECK-FIXES: {{^}} + +using n9::inner::innerFunc; +// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: using declaration 'innerFunc' is redundant, already in namespace 'inner' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:18: note: remove the using declaration +// CHECK-FIXES: {{^}} + +namespace n = n9::inner; +using n::innerFunc; +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using declaration 'innerFunc' is redundant, already in namespace 'inner' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:10: note: remove the using declaration +// CHECK-FIXES: {{^}} +} // namespace inner +} // namespace n9 + +namespace n10 { +namespace inner { +using n9::inner::innerFunc; // ok +} +} // namespace n10 + +namespace n11 { +void func(); +} + +namespace n11 { +using n11::func; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: using declaration 'func' is redundant, already in namespace 'n11' [readability-redundant-using] +// CHECK-MESSAGES: :[[@LINE-2]]:12: note: remove the using declaration +// CHECK-FIXES: {{^}} +} // namespace n11