Index: clang-tidy/abseil/AbseilTidyModule.cpp =================================================================== --- clang-tidy/abseil/AbseilTidyModule.cpp +++ clang-tidy/abseil/AbseilTidyModule.cpp @@ -15,6 +15,7 @@ #include "FasterStrsplitDelimiterCheck.h" #include "NoInternalDependenciesCheck.h" #include "NoNamespaceCheck.h" +#include "QualifiedAliasesCheck.h" #include "RedundantStrcatCallsCheck.h" #include "StringFindStartswithCheck.h" #include "StrCatAppendCheck.h" @@ -35,6 +36,8 @@ CheckFactories.registerCheck( "abseil-no-internal-dependencies"); CheckFactories.registerCheck("abseil-no-namespace"); + CheckFactories.registerCheck( + "abseil-qualified-aliases"); CheckFactories.registerCheck( "abseil-redundant-strcat-calls"); CheckFactories.registerCheck( Index: clang-tidy/abseil/CMakeLists.txt =================================================================== --- clang-tidy/abseil/CMakeLists.txt +++ clang-tidy/abseil/CMakeLists.txt @@ -7,6 +7,7 @@ FasterStrsplitDelimiterCheck.cpp NoInternalDependenciesCheck.cpp NoNamespaceCheck.cpp + QualifiedAliasesCheck.cpp RedundantStrcatCallsCheck.cpp StrCatAppendCheck.cpp StringFindStartswithCheck.cpp Index: clang-tidy/abseil/QualifiedAliasesCheck.h =================================================================== --- /dev/null +++ clang-tidy/abseil/QualifiedAliasesCheck.h @@ -0,0 +1,35 @@ +//===--- QualifiedAliasesCheck.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_ABSEIL_QUALIFIEDALIASESCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_QUALIFIEDALIASESCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace abseil { + +/// FIXME: Write a short description. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-qualified-aliases.html +class QualifiedAliasesCheck : public ClangTidyCheck { +public: + QualifiedAliasesCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace abseil +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_QUALIFIEDALIASESCHECK_H Index: clang-tidy/abseil/QualifiedAliasesCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/abseil/QualifiedAliasesCheck.cpp @@ -0,0 +1,49 @@ +//===--- QualifiedAliasesCheck.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 "QualifiedAliasesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace abseil { + +void QualifiedAliasesCheck::registerMatchers(MatchFinder *Finder) { + // Matches all using declarations. + Finder->addMatcher(usingDecl().bind("x"), this); +} + +void QualifiedAliasesCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("x"); + + // Finds the nested-name-specifier location. + const NestedNameSpecifierLoc QualifiedLoc = MatchedDecl->getQualifierLoc(); + const SourceLocation FrontLoc = QualifiedLoc.getBeginLoc(); + + // Checks if the using declaration is fully qualified. + const SourceManager *SM = Result.SourceManager; + CharSourceRange FrontRange = CharSourceRange(); + FrontRange.setBegin(FrontLoc); + FrontRange.setEnd(FrontLoc.getLocWithOffset(2)); + llvm::StringRef Beg = Lexer::getSourceText(FrontRange, *SM, LangOptions()); + + // If the using declaration is fully qualified, don't produce a warning. + if (Beg.startswith("::")) + return; + + diag(FrontLoc, "using declaration is not fully qualified: see " + "https://abseil.io/tips/119"); +} + +} // namespace abseil +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -98,6 +98,12 @@ Ensures code does not open ``namespace absl`` as that violates Abseil's compatibility guidelines. +- New :doc:`abseil-qualified-aliases + ` check. + + Detects using declarations that are not fully qualified, and suggests + that the developer fully qualify those declarations. + - New :doc:`abseil-redundant-strcat-calls ` check. Index: docs/clang-tidy/checks/abseil-qualified-aliases.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/abseil-qualified-aliases.rst @@ -0,0 +1,23 @@ +.. title:: clang-tidy - abseil-qualified-aliases + +abseil-qualified-aliases +======================== + +Detects using declarations that are not fully qualified, and suggests +that the developer fully qualify those declarations. + +Example: +.. code-block:: c++ + + namespace foo { + void f(); + void correct(); + } + + namespace bar { + using foo::f; // The check produces a warning here. + using ::foo::correct; // The check sees no issue here. + } + +See https://abseil.io/tips/119 for a more in depth justification of this +check. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -9,9 +9,10 @@ abseil-faster-strsplit-delimiter abseil-no-internal-dependencies abseil-no-namespace + abseil-qualified-aliases abseil-redundant-strcat-calls - abseil-string-find-startswith abseil-str-cat-append + abseil-string-find-startswith android-cloexec-accept android-cloexec-accept4 android-cloexec-creat @@ -151,6 +152,7 @@ hicpp-special-member-functions (redirects to cppcoreguidelines-special-member-functions) hicpp-static-assert (redirects to misc-static-assert) hicpp-undelegated-constructor (redirects to bugprone-undelegated-constructor) + hicpp-uppercase-literal-suffix (redirects to readability-uppercase-literal-suffix) hicpp-use-auto (redirects to modernize-use-auto) hicpp-use-emplace (redirects to modernize-use-emplace) hicpp-use-equals-default (redirects to modernize-use-equals-default) @@ -159,7 +161,6 @@ hicpp-use-nullptr (redirects to modernize-use-nullptr) hicpp-use-override (redirects to modernize-use-override) hicpp-vararg (redirects to cppcoreguidelines-pro-type-vararg) - hicpp-uppercase-literal-suffix (redirects to readability-uppercase-literal-suffix) llvm-header-guard llvm-include-order llvm-namespace-comment Index: test/clang-tidy/abseil-qualified-aliases.cpp =================================================================== --- /dev/null +++ test/clang-tidy/abseil-qualified-aliases.cpp @@ -0,0 +1,26 @@ +// RUN: %check_clang_tidy %s abseil-qualified-aliases %t + +namespace foo { + void f(); + void correct(); +} + +namespace bar { + using foo::f; +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: using declaration is not fully qualified: see https://abseil.io/tips/119 [abseil-qualified-aliases] + using ::foo::correct; +} + +namespace outermost { + namespace middle { + namespace innermost { + + enum Color {Red, Blue, Yellow}; + + } // namespace innermost + + using innermost::Color; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: using declaration is not fully qualified: see https://abseil.io/tips/119 [abseil-qualified-aliases] + + } // namespace middle +} // namespace example