diff --git a/clang-tools-extra/clang-tidy/bsl/BslTidyModule.cpp b/clang-tools-extra/clang-tidy/bsl/BslTidyModule.cpp index 17abc2573b2a1..f023211e34f30 100644 --- a/clang-tools-extra/clang-tidy/bsl/BslTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bsl/BslTidyModule.cpp @@ -15,6 +15,7 @@ #include "ClassMemberRedefinedCheck.h" #include "ClassVirtualBaseCheck.h" #include "DeclForbiddenCheck.h" +#include "DependentBaseNameCheck.h" #include "DestructorAccessSpecifierCheck.h" #include "EnumExplicitCheck.h" #include "EnumInitCheck.h" @@ -71,6 +72,8 @@ class BslModule : public ClangTidyModule { "bsl-class-virtual-base"); CheckFactories.registerCheck( "bsl-decl-forbidden"); + CheckFactories.registerCheck( + "bsl-dependent-base-name"); CheckFactories.registerCheck( "bsl-destructor-access-specifier"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/bsl/CMakeLists.txt b/clang-tools-extra/clang-tidy/bsl/CMakeLists.txt index 3ddfe17e5c019..bfd15ee9d74bd 100644 --- a/clang-tools-extra/clang-tidy/bsl/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bsl/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_library(clangTidyBslModule ClassMemberRedefinedCheck.cpp ClassVirtualBaseCheck.cpp DeclForbiddenCheck.cpp + DependentBaseNameCheck.cpp DestructorAccessSpecifierCheck.cpp EnumExplicitCheck.cpp EnumInitCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bsl/DependentBaseNameCheck.cpp b/clang-tools-extra/clang-tidy/bsl/DependentBaseNameCheck.cpp new file mode 100644 index 0000000000000..d2b87137e6024 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bsl/DependentBaseNameCheck.cpp @@ -0,0 +1,76 @@ +//===--- DependentBaseNameCheck.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 "DependentBaseNameCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bsl { + +AST_MATCHER(CXXRecordDecl, hasAnyDependentBases) { + return Node.hasAnyDependentBases(); +} + +AST_MATCHER(VarDecl, dependentNameType) { + return isa(Node.getType()); +} + +void DependentBaseNameCheck::registerMatchers(MatchFinder *Finder) { + // Finder->addMatcher(cxxThisExpr().bind("this"), this); + Finder->addMatcher( + varDecl(unless(anyOf(dependentNameType(), hasType(elaboratedType()))), + hasAncestor(cxxRecordDecl(hasAnyDependentBases()))) + .bind("var"), + this); + + Finder->addMatcher( + declRefExpr(hasAncestor(cxxRecordDecl(hasAnyDependentBases()))) + .bind("this"), + this); + // memberexpr +} + +void DependentBaseNameCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("var"); + if (MatchedDecl) { + // if (isa(MatchedDecl->getType())) { + diag(MatchedDecl->getLocation(), + "in a class template with a dependent base, any name that may be " + "found in that dependent base shall be referred to using a " + "qualified-id or this->."); + } + + // getBaseTypeIdentifier + + // ok + const auto *MatchedExpr = Result.Nodes.getNodeAs("this"); + if (MatchedExpr) { + if (!MatchedExpr->hasQualifier()) { + diag(MatchedExpr->getLocation(), + "in a class template with a dependent base, any name that may be " + "found in that dependent base shall be referred to using a " + "qualified-id or this->."); + } + } + + // const auto *MatchedExpr = Result.Nodes.getNodeAs("this"); + // if (MatchedExpr) { + // diag(MatchedExpr->getLocation(), "this"); + // if (!MatchedExpr->isImplicit()) { + // diag(MatchedExpr->getLocation(), "not implicit"); + // } + // } +} + +} // namespace bsl +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/bsl/DependentBaseNameCheck.h b/clang-tools-extra/clang-tidy/bsl/DependentBaseNameCheck.h new file mode 100644 index 0000000000000..896a17f534d1c --- /dev/null +++ b/clang-tools-extra/clang-tidy/bsl/DependentBaseNameCheck.h @@ -0,0 +1,35 @@ +//===--- DependentBaseNameCheck.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_BSL_DEPENDENTBASENAMECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSL_DEPENDENTBASENAMECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bsl { + +/// Checks that names in a class template found in its dependent base are +/// referred to using a qualified-id or this->. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bsl-dependent-base-name.html +class DependentBaseNameCheck : public ClangTidyCheck { +public: + DependentBaseNameCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace bsl +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BSL_DEPENDENTBASENAMECHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 46adbad5d5314..3569f6318fec4 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -111,6 +111,11 @@ New checks Warns if unions or bitfields are declared. +- New :doc:`bsl-dependent-base-name + ` check. + + FIXME: add release notes. + - New :doc:`bsl-destructor-access-specifier ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bsl-dependent-base-name.rst b/clang-tools-extra/docs/clang-tidy/checks/bsl-dependent-base-name.rst new file mode 100644 index 0000000000000..54db9e58ab306 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bsl-dependent-base-name.rst @@ -0,0 +1,6 @@ +.. title:: clang-tidy - bsl-dependent-base-name + +bsl-dependent-base-name +======================= + +FIXME: Describe what patterns does the check detect and why. Give examples. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 4f76a100775c7..7cbe56cf2abf3 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -51,14 +51,15 @@ Clang-Tidy Checks `bsl-class-member-redefined `_, `bsl-class-virtual-base `_, `bsl-decl-forbidden `_, - `bsl-destructor-access-specifier `_, "Yes" + `bsl-dependent-base-name `_, "Yes" + `bsl-destructor-access-specifier `_, `bsl-enum-explicit `_, `bsl-enum-init `_, `bsl-enum-scoped `_, `bsl-for-loop-counter `_, `bsl-friend-decl `_, `bsl-function-name-use `_, "Yes" - `bsl-identifier-typographically-unambiguous `_, "Yes" + `bsl-identifier-typographically-unambiguous `_, `bsl-lambda-implicit-capture `_, `bsl-lambda-param-list `_, `bsl-literals-ascii-only `_, @@ -67,7 +68,7 @@ Clang-Tidy Checks `bsl-literals-uppercase-suffix `_, `bsl-literals-user-defined `_, `bsl-namespace-global `_, - `bsl-non-pod-classdef `_, "Yes" + `bsl-non-pod-classdef `_, `bsl-non-pod-static `_, `bsl-op-bitwise-operands `_, "Yes" `bsl-op-conditional-subexpr `_, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bsl-dependent-base-name.cpp b/clang-tools-extra/test/clang-tidy/checkers/bsl-dependent-base-name.cpp new file mode 100644 index 0000000000000..27f82ca16ed8b --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bsl-dependent-base-name.cpp @@ -0,0 +1,80 @@ +// RUN: %check_clang_tidy %s bsl-dependent-base-name %t + +#include + +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [bsl-dependent-base-name] +typedef int32_t TYPE; +void g ( ); + +template +class B; + +int var; + +template +class A : public B +{ + void f1 ( ) + { + TYPE t = 0; // Non-compliant Example 1 + g ( ); // Non-compliant Example 2 + var = 0; // Non-compliant?? use ::var = 0? + } + + void f2 ( ) + { + ::TYPE t1 = 0; // Compliant - explicit use global TYPE + ::g ( ); // Compliant - explicit use global func + typename B::TYPE t2 = 0; // Compliant - explicit use base TYPE + this->g ( ); // Compliant - explicit use base "g" + } +}; + +// All compliant +template +class B +{ +public: + typedef T TYPE; + void g ( ); +}; + +template class A; + + +class C {}; + +template +class D : public C +{ + void f1 ( ) + { + TYPE t = 0; + g ( ); + } + void f2 ( ) + { + ::TYPE t1 = 0; + ::g ( ); + typename B::TYPE t2 = 0; + this->g ( ); + } +}; + +class E : C +{ + void f1 ( ) + { + TYPE t = 0; + g ( ); + // A a = a(); + // a->f1(); + } + void f2 ( ) + { + ::TYPE t1 = 0; + ::g ( ); + // typename B::TYPE t2 = 0; // error + // this->g ( ); // error (???) + } +}; \ No newline at end of file