Index: clang-tools-extra/clang-tidy/zircon/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/zircon/CMakeLists.txt +++ clang-tools-extra/clang-tidy/zircon/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyZirconModule + NoStdNamespaceCheck.cpp TemporaryObjectsCheck.cpp ZirconTidyModule.cpp Index: clang-tools-extra/clang-tidy/zircon/NoStdNamespaceCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/zircon/NoStdNamespaceCheck.h @@ -0,0 +1,37 @@ +//===--- NoStdNamespace.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_ZIRCON_NOSTDNAMESPACECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_NOSTDNAMESPACECHECK_H + +#include "../ClangTidy.h" +#include "../utils/OptionsUtils.h" + +namespace clang { +namespace tidy { +namespace zircon { + +/// Use of the std namespace is not allowed in the Zircon kernel according to +/// its libc++ policy. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/zircon-no-std-namespace.html +class NoStdNamespaceCheck : public ClangTidyCheck { +public: + NoStdNamespaceCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace zircon +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_NOSTDNAMESPACECHECK_H Index: clang-tools-extra/clang-tidy/zircon/NoStdNamespaceCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/zircon/NoStdNamespaceCheck.cpp @@ -0,0 +1,86 @@ +//===--- NoStdNamespaceCheck.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 "NoStdNamespaceCheck.h" +#include "../utils/OptionsUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace zircon { + +namespace { + +AST_MATCHER(NamespaceDecl, isStdNamespace) { return Node.isStdNamespace(); } + +AST_MATCHER(NamespaceAliasDecl, isAliasedToStd) { + if (const NamedDecl *AN = Node.getAliasedNamespace()) { + // If this aliases to an actual namespace, check if its std. + if (const auto *N = dyn_cast(AN)) + return N->isStdNamespace(); + } + return false; +} + +AST_MATCHER_P(UsingDirectiveDecl, redirectsTo, + ast_matchers::internal::Matcher, InnerMatcher) { + if (const NamespaceDecl *N = Node.getNominatedNamespace()) + return InnerMatcher.matches(*N, Finder, Builder); + return false; +} + +} // namespace + +void NoStdNamespaceCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + + // Match all values scoped to std namespace. + Finder->addMatcher( + valueDecl(hasType(decl(hasDeclContext(namespaceDecl(isStdNamespace()))))) + .bind("stdVar"), + this); + Finder->addMatcher(namespaceDecl(isStdNamespace()).bind("stdNamespace"), + this); + Finder->addMatcher(callExpr(callee(functionDecl(hasDeclContext( + namespaceDecl(isStdNamespace()))))) + .bind("stdCall"), + this); + Finder->addMatcher(namespaceAliasDecl(isAliasedToStd()).bind("stdAlias"), + this); + Finder->addMatcher( + usingDirectiveDecl(redirectsTo(namespaceDecl(isStdNamespace()))) + .bind("stdUsing"), + this); +} + +void NoStdNamespaceCheck::check(const MatchFinder::MatchResult &Result) { + std::string Warning = + "use of the 'std' namespace is not allowed in Zircon kernel code"; + if (const auto *D = Result.Nodes.getNodeAs("stdVar")) + diag(D->getBeginLoc(), Warning); + if (const auto *D = Result.Nodes.getNodeAs("stdCall")) + diag(D->getBeginLoc(), Warning); + if (const auto *D = Result.Nodes.getNodeAs("stdAlias")) + diag(D->getTargetNameLoc(), Warning); + if (const auto *D = Result.Nodes.getNodeAs("stdUsing")) + diag(D->getLocation(), Warning); + if (const auto *D = Result.Nodes.getNodeAs("stdNamespace")) + diag(D->getLocation(), Warning); +} + +} // namespace zircon +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/zircon/ZirconTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/zircon/ZirconTidyModule.cpp +++ clang-tools-extra/clang-tidy/zircon/ZirconTidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "NoStdNamespaceCheck.h" #include "TemporaryObjectsCheck.h" using namespace clang::ast_matchers; @@ -22,6 +23,8 @@ class ZirconModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "zircon-no-std-namespace"); CheckFactories.registerCheck( "zircon-temporary-objects"); } Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -170,6 +170,12 @@ ` check does not warn about calls inside macros anymore by default. +- New :doc:`zircon-no-std-namespace + ` check. + + Warns when the `std` namespace is used, as its use is against Zircon's libc++ + policy for the kernel. + Improvements to include-fixer ----------------------------- Index: clang-tools-extra/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -252,4 +252,5 @@ readability-string-compare readability-uniqueptr-delete-release readability-uppercase-literal-suffix + zircon-no-std-namespace zircon-temporary-objects Index: clang-tools-extra/docs/clang-tidy/checks/zircon-no-std-namespace.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/zircon-no-std-namespace.rst @@ -0,0 +1,30 @@ +.. title:: clang-tidy - zircon-no-std-namespace + +zircon-no-std-namespace +======================= + +Ensures code does not use ``namespace std`` as that violates Zircon's +kernel libc++ policy. + +Any code that uses: + +.. code-block:: c++ + + namespace std { + ... + } + +or + +.. code-block:: c++ + + using namespace std; + +or uses a declaration or function from the ``std`` namespace: + +.. code-block:: c++ + + std::string foo; + std::move(foo); + +will be prompted with a warning. Index: clang-tools-extra/test/clang-tidy/zircon-no-std-namespace.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/zircon-no-std-namespace.cpp @@ -0,0 +1,50 @@ +// RUN: %check_clang_tidy %s zircon-no-std-namespace %t + +int func() { return 1; } + +namespace std { +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use of the 'std' namespace is not allowed in Zircon kernel code + +typedef int std_int; +int std_func() { return 1; } + +int a = 1; +int b = func(); +std_int c; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use of the 'std' namespace is not allowed in Zircon kernel code +int d = std_func(); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use of the 'std' namespace is not allowed in Zircon kernel code + +} + +// Warn on uses of quailfied std namespace. +int i = 1; +int j = func(); +std::std_int k; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use of the 'std' namespace is not allowed in Zircon kernel code +int l = std::std_func(); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use of the 'std' namespace is not allowed in Zircon kernel code + + +namespace foo { + +int w = 1; +int x = func(); +std::std_int y; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use of the 'std' namespace is not allowed in Zircon kernel code +int z = std::std_func(); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use of the 'std' namespace is not allowed in Zircon kernel code + +} + +// Warn on the alias declaration, and on users of it. +namespace bar = std; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use of the 'std' namespace is not allowed in Zircon kernel code +bar::std_int q; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use of the 'std' namespace is not allowed in Zircon kernel code + +// Warn on the using declaration, and on users of it. +using namespace std; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use of the 'std' namespace is not allowed in Zircon kernel code +std_int r = 1; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use of the 'std' namespace is not allowed in Zircon kernel code