Index: clang-tidy/abseil/AbseilMatcher.h =================================================================== --- clang-tidy/abseil/AbseilMatcher.h +++ clang-tidy/abseil/AbseilMatcher.h @@ -0,0 +1,51 @@ +//===- AbseilMatcher.h - clang-tidy ---------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +namespace clang { +namespace ast_matchers { + +/// Matches AST nodes that were found within Abseil files. +/// +/// Example matches Y but not X +/// (matcher = cxxRecordDecl(isInAbseilFile()) +/// \code +/// #include "absl/strings/internal-file.h" +/// class X {}; +/// \endcode +/// absl/strings/internal-file.h: +/// \code +/// class Y {}; +/// \endcode +/// +/// Usable as: Matcher, Matcher, Matcher, +/// Matcher + +AST_POLYMORPHIC_MATCHER(isInAbseilFile, + AST_POLYMORPHIC_SUPPORTED_TYPES( + Decl, Stmt, TypeLoc, NestedNameSpecifierLoc)) { + auto &SourceManager = Finder->getASTContext().getSourceManager(); + SourceLocation Loc = Node.getBeginLoc(); + if (Loc.isInvalid()) + return false; + const FileEntry *FileEntry = + SourceManager.getFileEntryForID(SourceManager.getFileID(Loc)); + if (!FileEntry) + return false; + StringRef Filename = FileEntry->getName(); + llvm::Regex RE( + "absl/(algorithm|base|container|debugging|memory|meta|numeric|strings|" + "synchronization|time|types|utility)"); + return RE.match(Filename); +} + +} // namespace ast_matchers +} // namespace clang Index: clang-tidy/abseil/AbseilTidyModule.cpp =================================================================== --- clang-tidy/abseil/AbseilTidyModule.cpp +++ clang-tidy/abseil/AbseilTidyModule.cpp @@ -11,6 +11,7 @@ #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" #include "DurationDivisionCheck.h" +#include "NoNamespaceCheck.h" #include "StringFindStartswithCheck.h" namespace clang { @@ -22,6 +23,7 @@ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck( "abseil-duration-division"); + CheckFactories.registerCheck("abseil-no-namespace"); CheckFactories.registerCheck( "abseil-string-find-startswith"); } Index: clang-tidy/abseil/CMakeLists.txt =================================================================== --- clang-tidy/abseil/CMakeLists.txt +++ clang-tidy/abseil/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyAbseilModule AbseilTidyModule.cpp DurationDivisionCheck.cpp + NoNamespaceCheck.cpp StringFindStartswithCheck.cpp LINK_LIBS Index: clang-tidy/abseil/NoNamespaceCheck.h =================================================================== --- clang-tidy/abseil/NoNamespaceCheck.h +++ clang-tidy/abseil/NoNamespaceCheck.h @@ -0,0 +1,36 @@ +//===--- NoNamespaceCheck.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_NONAMESPACECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_NONAMESPACECHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace abseil { + +/// This check ensures users don't open namespace absl, as that violates +/// Abseil's compatibility guidelines. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-no-namespace.html +class NoNamespaceCheck : public ClangTidyCheck { +public: + NoNamespaceCheck(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_NONAMESPACECHECK_H Index: clang-tidy/abseil/NoNamespaceCheck.cpp =================================================================== --- clang-tidy/abseil/NoNamespaceCheck.cpp +++ clang-tidy/abseil/NoNamespaceCheck.cpp @@ -0,0 +1,42 @@ +//===--- NoNamespaceCheck.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 "NoNamespaceCheck.h" +#include "AbseilMatcher.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace abseil { + +void NoNamespaceCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + + Finder->addMatcher( + namespaceDecl(hasName("::absl"), unless(isInAbseilFile())) + .bind("abslNamespace"), + this); +} + +void NoNamespaceCheck::check(const MatchFinder::MatchResult &Result) { + const auto *abslNamespaceDecl = + Result.Nodes.getNodeAs("abslNamespace"); + + diag(abslNamespaceDecl->getLocation(), + "namespace 'absl' is reserved for implementation of the Abseil library " + "and should not be opened in user code"); +} + +} // namespace abseil +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -64,6 +64,12 @@ floating-point context, and recommends the use of a function that returns a floating-point value. +- New :doc:`abseil-no-namespace + ` check. + + Ensures code does not open ``namespace absl`` as that violates Abseil's + compatibility guidelines. + - New :doc:`readability-magic-numbers ` check. Index: docs/clang-tidy/checks/abseil-no-namespace.rst =================================================================== --- docs/clang-tidy/checks/abseil-no-namespace.rst +++ docs/clang-tidy/checks/abseil-no-namespace.rst @@ -0,0 +1,21 @@ +.. title:: clang-tidy - abseil-no-namespace + +abseil-no-namespace +=================== + +Ensures code does not open ``namespace absl`` as that violates Abseil's +compatibility guidelines. Code should not open ``namespace absl`` as that +conflicts with Abseil's compatibility guidelines and may result in breakage. + +Any code that uses: + +.. code-block:: c++ + + namespace absl { + ... + } + +will be prompted with a warning. + +See `the full Abseil compatibility guidelines `_ for more information. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -5,6 +5,7 @@ .. toctree:: abseil-duration-division + abseil-no-namespace abseil-string-find-startswith android-cloexec-accept android-cloexec-accept4 Index: test/clang-tidy/Inputs/absl/external-file.h =================================================================== --- test/clang-tidy/Inputs/absl/external-file.h +++ test/clang-tidy/Inputs/absl/external-file.h @@ -0,0 +1 @@ +namespace absl {} Index: test/clang-tidy/Inputs/absl/strings/internal-file.h =================================================================== --- test/clang-tidy/Inputs/absl/strings/internal-file.h +++ test/clang-tidy/Inputs/absl/strings/internal-file.h @@ -0,0 +1 @@ +namespace absl {} Index: test/clang-tidy/abseil-no-namespace.cpp =================================================================== --- test/clang-tidy/abseil-no-namespace.cpp +++ test/clang-tidy/abseil-no-namespace.cpp @@ -0,0 +1,28 @@ +// RUN: %check_clang_tidy %s abseil-no-namespace %t -- -- -I %S/Inputs +// RUN: clang-tidy -checks='-*, abseil-no-namespace' -header-filter='.*' %s -- -I %S/Inputs 2>&1 | FileCheck %s + +/// Warning will not be triggered on internal Abseil code that is included. +#include "absl/strings/internal-file.h" +// CHECK-NOT: warning: + +/// Warning will be triggered on code that is not internal that is included. +#include "absl/external-file.h" +// CHECK: absl/external-file.h:1:11: warning: namespace 'absl' is reserved +// for implementation of the Abseil library and should not be opened in user +// code [abseil-no-namespace] + +namespace absl {} +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: namespace 'absl' is reserved for +// implementation of the Abseil library and should not be opened in the user +// code [abseil-no-namespace] + +namespace absl { +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: namespace 'absl' +namespace std { +int i = 5; +} +} + +// Things that shouldn't trigger the check +int i = 5; +namespace std {}