[clang-tools-extra] r323011 - [clang-tidy] Adding Fuchsia checker for multiple inheritance
Julie Hockett via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 19 16:00:00 PST 2018
Author: juliehockett
Date: Fri Jan 19 15:59:59 2018
New Revision: 323011
URL: http://llvm.org/viewvc/llvm-project?rev=323011&view=rev
Log:
[clang-tidy] Adding Fuchsia checker for multiple inheritance
Adds a check to the Fuchsia module to warn when a class
inherits from multiple classes that are not pure virtual.
See https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md
for reference.
Differential Revision: https://reviews.llvm.org/D40580
Added:
clang-tools-extra/trunk/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
clang-tools-extra/trunk/clang-tidy/fuchsia/MultipleInheritanceCheck.h
clang-tools-extra/trunk/docs/clang-tidy/checks/fuchsia-multiple-inheritance.rst
clang-tools-extra/trunk/test/clang-tidy/fuchsia-multiple-inheritance.cpp
Modified:
clang-tools-extra/trunk/clang-tidy/fuchsia/CMakeLists.txt
clang-tools-extra/trunk/clang-tidy/fuchsia/FuchsiaTidyModule.cpp
clang-tools-extra/trunk/docs/ReleaseNotes.rst
clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
Modified: clang-tools-extra/trunk/clang-tidy/fuchsia/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/fuchsia/CMakeLists.txt?rev=323011&r1=323010&r2=323011&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/fuchsia/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/fuchsia/CMakeLists.txt Fri Jan 19 15:59:59 2018
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyFuchsiaModule
DefaultArgumentsCheck.cpp
FuchsiaTidyModule.cpp
+ MultipleInheritanceCheck.cpp
OverloadedOperatorCheck.cpp
StaticallyConstructedObjectsCheck.cpp
TrailingReturnCheck.cpp
Modified: clang-tools-extra/trunk/clang-tidy/fuchsia/FuchsiaTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/fuchsia/FuchsiaTidyModule.cpp?rev=323011&r1=323010&r2=323011&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/fuchsia/FuchsiaTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/fuchsia/FuchsiaTidyModule.cpp Fri Jan 19 15:59:59 2018
@@ -11,6 +11,7 @@
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "DefaultArgumentsCheck.h"
+#include "MultipleInheritanceCheck.h"
#include "OverloadedOperatorCheck.h"
#include "StaticallyConstructedObjectsCheck.h"
#include "TrailingReturnCheck.h"
@@ -28,6 +29,8 @@ public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<DefaultArgumentsCheck>(
"fuchsia-default-arguments");
+ CheckFactories.registerCheck<MultipleInheritanceCheck>(
+ "fuchsia-multiple-inheritance");
CheckFactories.registerCheck<OverloadedOperatorCheck>(
"fuchsia-overloaded-operator");
CheckFactories.registerCheck<StaticallyConstructedObjectsCheck>(
Added: clang-tools-extra/trunk/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp?rev=323011&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp Fri Jan 19 15:59:59 2018
@@ -0,0 +1,125 @@
+//===--- MultipleInheritanceCheck.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 "MultipleInheritanceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang;
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+AST_MATCHER(CXXRecordDecl, hasBases) {
+ if (Node.hasDefinition())
+ return Node.getNumBases() > 0;
+ return false;
+}
+
+// Adds a node (by name) to the interface map, if it was not present in the map
+// previously.
+void MultipleInheritanceCheck::addNodeToInterfaceMap(const CXXRecordDecl *Node,
+ bool isInterface) {
+ StringRef Name = Node->getIdentifier()->getName();
+ InterfaceMap.insert(std::make_pair(Name, isInterface));
+}
+
+// Returns "true" if the boolean "isInterface" has been set to the
+// interface status of the current Node. Return "false" if the
+// interface status for the current node is not yet known.
+bool MultipleInheritanceCheck::getInterfaceStatus(const CXXRecordDecl *Node,
+ bool &isInterface) const {
+ StringRef Name = Node->getIdentifier()->getName();
+ llvm::StringMapConstIterator<bool> Pair = InterfaceMap.find(Name);
+ if (Pair == InterfaceMap.end())
+ return false;
+ isInterface = Pair->second;
+ return true;
+}
+
+bool MultipleInheritanceCheck::isCurrentClassInterface(
+ const CXXRecordDecl *Node) const {
+ // Interfaces should have no fields.
+ if (!Node->field_empty()) return false;
+
+ // Interfaces should have exclusively pure methods.
+ return llvm::none_of(Node->methods(), [](const CXXMethodDecl *M) {
+ return M->isUserProvided() && !M->isPure() && !M->isStatic();
+ });
+}
+
+bool MultipleInheritanceCheck::isInterface(const CXXRecordDecl *Node) {
+ // Short circuit the lookup if we have analyzed this record before.
+ bool PreviousIsInterfaceResult;
+ if (getInterfaceStatus(Node, PreviousIsInterfaceResult))
+ return PreviousIsInterfaceResult;
+
+ // To be an interface, all base classes must be interfaces as well.
+ for (const auto &I : Node->bases()) {
+ if (I.isVirtual()) continue;
+ const auto *Ty = I.getType()->getAs<RecordType>();
+ assert(Ty && "RecordType of base class is unknown");
+ const RecordDecl *D = Ty->getDecl()->getDefinition();
+ if (!D) continue;
+ const auto *Base = cast<CXXRecordDecl>(D);
+ if (!isInterface(Base)) {
+ addNodeToInterfaceMap(Node, false);
+ return false;
+ }
+ }
+
+ bool CurrentClassIsInterface = isCurrentClassInterface(Node);
+ addNodeToInterfaceMap(Node, CurrentClassIsInterface);
+ return CurrentClassIsInterface;
+}
+
+void MultipleInheritanceCheck::registerMatchers(MatchFinder *Finder) {
+ // Requires C++.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Match declarations which have bases.
+ Finder->addMatcher(cxxRecordDecl(hasBases()).bind("decl"), this);
+}
+
+void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *D = Result.Nodes.getNodeAs<CXXRecordDecl>("decl")) {
+ // Check against map to see if if the class inherits from multiple
+ // concrete classes
+ unsigned NumConcrete = 0;
+ for (const auto &I : D->bases()) {
+ if (I.isVirtual()) continue;
+ const auto *Ty = I.getType()->getAs<RecordType>();
+ assert(Ty && "RecordType of base class is unknown");
+ const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
+ if (!isInterface(Base)) NumConcrete++;
+ }
+
+ // Check virtual bases to see if there is more than one concrete
+ // non-virtual base.
+ for (const auto &V : D->vbases()) {
+ const auto *Ty = V.getType()->getAs<RecordType>();
+ assert(Ty && "RecordType of base class is unknown");
+ const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
+ if (!isInterface(Base)) NumConcrete++;
+ }
+
+ if (NumConcrete > 1) {
+ diag(D->getLocStart(),
+ "inheriting mulitple classes that aren't "
+ "pure virtual is discouraged");
+ }
+ }
+}
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
Added: clang-tools-extra/trunk/clang-tidy/fuchsia/MultipleInheritanceCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/fuchsia/MultipleInheritanceCheck.h?rev=323011&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/fuchsia/MultipleInheritanceCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/fuchsia/MultipleInheritanceCheck.h Fri Jan 19 15:59:59 2018
@@ -0,0 +1,48 @@
+//===--- MultipleInheritanceCheck.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_FUCHSIA_MULTIPLE_INHERITANCE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_MULTIPLE_INHERITANCE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+/// Mulitple implementation inheritance is discouraged.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-multiple-inheritance.html
+class MultipleInheritanceCheck : public ClangTidyCheck {
+public:
+ MultipleInheritanceCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+ void onEndOfTranslationUnit() override { InterfaceMap.clear(); }
+
+private:
+ void addNodeToInterfaceMap(const CXXRecordDecl *Node, bool isInterface);
+ bool getInterfaceStatus(const CXXRecordDecl *Node, bool &isInterface) const;
+ bool isCurrentClassInterface(const CXXRecordDecl *Node) const;
+ bool isInterface(const CXXRecordDecl *Node);
+
+ // Contains the identity of each named CXXRecord as an interface. This is
+ // used to memoize lookup speeds and improve performance from O(N^2) to O(N),
+ // where N is the number of classes.
+ llvm::StringMap<bool> InterfaceMap;
+};
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_MULTIPLE_INHERITANCE_H
Modified: clang-tools-extra/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/ReleaseNotes.rst?rev=323011&r1=323010&r2=323011&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/ReleaseNotes.rst (original)
+++ clang-tools-extra/trunk/docs/ReleaseNotes.rst Fri Jan 19 15:59:59 2018
@@ -64,6 +64,11 @@ Improvements to clang-tidy
with looping constructs. Every backward jump is rejected. Forward jumps are
only allowed in nested loops.
+- New `fuchsia-multiple-inheritance
+ <http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-multiple-inheritance.html>`_ check
+
+ Warns if a class inherits from multiple classes that are not pure virtual.
+
- New `fuchsia-statically-constructed-objects
<http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-statically-constructed-objects.html>`_ check
Added: clang-tools-extra/trunk/docs/clang-tidy/checks/fuchsia-multiple-inheritance.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/fuchsia-multiple-inheritance.rst?rev=323011&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/fuchsia-multiple-inheritance.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/fuchsia-multiple-inheritance.rst Fri Jan 19 15:59:59 2018
@@ -0,0 +1,46 @@
+.. title:: clang-tidy - fuchsia-multiple-inheritance
+
+fuchsia-multiple-inheritance
+============================
+
+Warns if a class inherits from multiple classes that are not pure virtual.
+
+For example, declaring a class that inherits from multiple concrete classes is
+disallowed:
+
+.. code-block:: c++
+
+ class Base_A {
+ public:
+ virtual int foo() { return 0; }
+ };
+
+ class Base_B {
+ public:
+ virtual int bar() { return 0; }
+ };
+
+ // Warning
+ class Bad_Child1 : public Base_A, Base_B {};
+
+A class that inherits from a pure virtual is allowed:
+
+.. code-block:: c++
+
+ class Interface_A {
+ public:
+ virtual int foo() = 0;
+ };
+
+ class Interface_B {
+ public:
+ virtual int bar() = 0;
+ };
+
+ // No warning
+ class Good_Child1 : public Interface_A, Interface_B {
+ virtual int foo() override { return 0; }
+ virtual int bar() override { return 0; }
+ };
+
+See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md
Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=323011&r1=323010&r2=323011&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Fri Jan 19 15:59:59 2018
@@ -70,6 +70,7 @@ Clang-Tidy Checks
cppcoreguidelines-slicing
cppcoreguidelines-special-member-functions
fuchsia-default-arguments
+ fuchsia-multiple-inheritance
fuchsia-overloaded-operator
fuchsia-statically-constructed-objects
fuchsia-trailing-return
Added: clang-tools-extra/trunk/test/clang-tidy/fuchsia-multiple-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/fuchsia-multiple-inheritance.cpp?rev=323011&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/fuchsia-multiple-inheritance.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/fuchsia-multiple-inheritance.cpp Fri Jan 19 15:59:59 2018
@@ -0,0 +1,131 @@
+// RUN: %check_clang_tidy %s fuchsia-multiple-inheritance %t
+
+class Base_A {
+public:
+ virtual int foo() { return 0; }
+};
+
+class Base_B {
+public:
+ virtual int bar() { return 0; }
+};
+
+class Base_A_child : public Base_A {
+public:
+ virtual int baz() { return 0; }
+};
+
+class Interface_A {
+public:
+ virtual int foo() = 0;
+};
+
+class Interface_B {
+public:
+ virtual int bar() = 0;
+};
+
+class Interface_C {
+public:
+ virtual int blat() = 0;
+};
+
+class Interface_A_with_member {
+public:
+ virtual int foo() = 0;
+ int val = 0;
+};
+
+class Interface_with_A_Parent : public Base_A {
+public:
+ virtual int baz() = 0;
+};
+
+// Inherits from multiple concrete classes.
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: class Bad_Child1 : public Base_A, Base_B {};
+class Bad_Child1 : public Base_A, Base_B {};
+
+// CHECK-MESSAGES: [[@LINE+1]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+class Bad_Child2 : public Base_A, Interface_A_with_member {
+ virtual int foo() override { return 0; }
+};
+
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: class Bad_Child3 : public Interface_with_A_Parent, Base_B {
+class Bad_Child3 : public Interface_with_A_Parent, Base_B {
+ virtual int baz() override { return 0; }
+};
+
+// Easy cases of single inheritance
+class Simple_Child1 : public Base_A {};
+class Simple_Child2 : public Interface_A {
+ virtual int foo() override { return 0; }
+};
+
+// Valid uses of multiple inheritance
+class Good_Child1 : public Interface_A, Interface_B {
+ virtual int foo() override { return 0; }
+ virtual int bar() override { return 0; }
+};
+
+class Good_Child2 : public Base_A, Interface_B {
+ virtual int bar() override { return 0; }
+};
+
+class Good_Child3 : public Base_A_child, Interface_C, Interface_B {
+ virtual int bar() override { return 0; }
+ virtual int blat() override { return 0; }
+};
+
+struct B1 { int x; };
+struct B2 { int x;};
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: struct D : B1, B2 {};
+struct D1 : B1, B2 {};
+
+struct Base1 { virtual void foo() = 0; };
+struct V1 : virtual Base1 {};
+struct V2 : virtual Base1 {};
+struct D2 : V1, V2 {};
+
+struct Base2 { virtual void foo(); };
+struct V3 : virtual Base2 {};
+struct V4 : virtual Base2 {};
+struct D3 : V3, V4 {};
+
+struct Base3 {};
+struct V5 : virtual Base3 { virtual void f(); };
+struct V6 : virtual Base3 { virtual void g(); };
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: struct D4 : V5, V6 {};
+struct D4 : V5, V6 {};
+
+struct Base4 {};
+struct V7 : virtual Base4 { virtual void f() = 0; };
+struct V8 : virtual Base4 { virtual void g() = 0; };
+struct D5 : V7, V8 {};
+
+struct Base5 { virtual void f() = 0; };
+struct V9 : virtual Base5 { virtual void f(); };
+struct V10 : virtual Base5 { virtual void g() = 0; };
+struct D6 : V9, V10 {};
+
+struct Base6 { virtual void f(); };
+struct Base7 { virtual void g(); };
+struct V15 : virtual Base6 { virtual void f() = 0; };
+struct V16 : virtual Base7 { virtual void g() = 0; };
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: struct D9 : V15, V16 {};
+struct D9 : V15, V16 {};
+
+struct Static_Base { static void foo(); };
+struct V11 : virtual Static_Base {};
+struct V12 : virtual Static_Base {};
+struct D7 : V11, V12 {};
+
+struct Static_Base_2 {};
+struct V13 : virtual Static_Base_2 { static void f(); };
+struct V14 : virtual Static_Base_2 { static void g(); };
+struct D8 : V13, V14 {};
+
More information about the cfe-commits
mailing list