Skip to content

Commit

Permalink
[clang-tidy] Abseil: no namepsace check
Browse files Browse the repository at this point in the history
This check ensures that users of Abseil do not open namespace absl in their code, as that violates our compatibility guidelines.

AbseilMatcher.h written by Hugo Gonzalez.

Patch by Deanna Garcia!

llvm-svn: 340800
  • Loading branch information
hokein committed Aug 28, 2018
1 parent c1436db commit d2f7b04
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 0 deletions.
51 changes: 51 additions & 0 deletions clang-tools-extra/clang-tidy/abseil/AbseilMatcher.h
Original file line number Diff line number Diff line change
@@ -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<Decl>, Matcher<Stmt>, Matcher<TypeLoc>,
/// Matcher<NestedNameSpecifierLoc>

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
2 changes: 2 additions & 0 deletions clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "../ClangTidyModuleRegistry.h"
#include "DurationDivisionCheck.h"
#include "FasterStrsplitDelimiterCheck.h"
#include "NoNamespaceCheck.h"
#include "StringFindStartswithCheck.h"

namespace clang {
Expand All @@ -25,6 +26,7 @@ class AbseilModule : public ClangTidyModule {
"abseil-duration-division");
CheckFactories.registerCheck<FasterStrsplitDelimiterCheck>(
"abseil-faster-strsplit-delimiter");
CheckFactories.registerCheck<NoNamespaceCheck>("abseil-no-namespace");
CheckFactories.registerCheck<StringFindStartswithCheck>(
"abseil-string-find-startswith");
}
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/abseil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ add_clang_library(clangTidyAbseilModule
AbseilTidyModule.cpp
DurationDivisionCheck.cpp
FasterStrsplitDelimiterCheck.cpp
NoNamespaceCheck.cpp
StringFindStartswithCheck.cpp

LINK_LIBS
Expand Down
42 changes: 42 additions & 0 deletions clang-tools-extra/clang-tidy/abseil/NoNamespaceCheck.cpp
Original file line number Diff line number Diff line change
@@ -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<NamespaceDecl>("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
36 changes: 36 additions & 0 deletions clang-tools-extra/clang-tidy/abseil/NoNamespaceCheck.h
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ Improvements to clang-tidy
Finds instances of ``absl::StrSplit()`` or ``absl::MaxSplits()`` where the
delimiter is a single character string literal and replaces with a character.

- New :doc:`abseil-no-namespace
<clang-tidy/checks/abseil-no-namespace>` check.

Ensures code does not open ``namespace absl`` as that violates Abseil's
compatibility guidelines.

- New :doc:`readability-magic-numbers
<clang-tidy/checks/readability-magic-numbers>` check.

Expand Down
21 changes: 21 additions & 0 deletions clang-tools-extra/docs/clang-tidy/checks/abseil-no-namespace.rst
Original file line number Diff line number Diff line change
@@ -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 <https://
abseil.io/about/compatibility>`_ for more information.
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Clang-Tidy Checks
.. toctree::
abseil-duration-division
abseil-faster-strsplit-delimiter
abseil-no-namespace
abseil-string-find-startswith
android-cloexec-accept
android-cloexec-accept4
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
namespace absl {}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
namespace absl {}
24 changes: 24 additions & 0 deletions clang-tools-extra/test/clang-tidy/abseil-no-namespace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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

namespace absl {}
// CHECK-MESSAGES: :[[@LINE-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'
namespace std {
int i = 5;
}
}

// Things that shouldn't trigger the check
int i = 5;
namespace std {}

0 comments on commit d2f7b04

Please sign in to comment.