Files
TheRock/compiler/amd-llvm/clang-tools-extra/clang-tidy/misc/MultipleInheritanceCheck.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

97 lines
3.7 KiB
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
//
//===----------------------------------------------------------------------===//
#include "MultipleInheritanceCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang;
using namespace clang::ast_matchers;
namespace clang::tidy::misc {
namespace {
AST_MATCHER(CXXRecordDecl, hasBases) {
return Node.hasDefinition() && Node.getNumBases() > 0;
}
} // namespace
bool MultipleInheritanceCheck::isInterface(const CXXBaseSpecifier &Base) {
const CXXRecordDecl *const Node = Base.getType()->getAsCXXRecordDecl();
if (!Node)
return true;
assert(Node->isCompleteDefinition());
// Short circuit the lookup if we have analyzed this record before.
if (const auto CachedValue = InterfaceMap.find(Node);
CachedValue != InterfaceMap.end())
return CachedValue->second;
// To be an interface, a class must have...
const bool CurrentClassIsInterface =
// ...no bases that aren't interfaces...
llvm::none_of(Node->bases(),
[&](const CXXBaseSpecifier &I) {
return !I.isVirtual() && !isInterface(I);
}) &&
// ...no fields, and...
Node->field_empty() &&
// ...no methods that aren't pure virtual.
llvm::none_of(Node->methods(), [](const CXXMethodDecl *M) {
return M->isUserProvided() && !M->isPureVirtual() && !M->isStatic();
});
InterfaceMap.try_emplace(Node, CurrentClassIsInterface);
return CurrentClassIsInterface;
}
void MultipleInheritanceCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(cxxRecordDecl(hasBases(), isDefinition()).bind("decl"),
this);
}
void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) {
const auto &D = *Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
// Collect the direct and virtual concrete bases of the class.
SmallVector<const CXXRecordDecl *> DirectConcreteBases;
for (const CXXBaseSpecifier &Base : D.bases())
if (!Base.isVirtual() && !isInterface(Base))
DirectConcreteBases.push_back(Base.getType()->getAsCXXRecordDecl());
SmallVector<const CXXRecordDecl *> VirtualConcreteBases;
for (const CXXBaseSpecifier &VBase : D.vbases())
if (!isInterface(VBase))
VirtualConcreteBases.push_back(VBase.getType()->getAsCXXRecordDecl());
unsigned NumConcrete = DirectConcreteBases.size();
// Count only virtual concrete bases that introduce an additional
// implementation base, skipping those already represented by a more derived
// concrete base.
NumConcrete += llvm::count_if(
VirtualConcreteBases, [&](const CXXRecordDecl *VirtualBase) {
const bool HiddenByMoreDerivedVirtualBase = llvm::any_of(
VirtualConcreteBases, [&](const CXXRecordDecl *OtherVirtualBase) {
return VirtualBase != OtherVirtualBase &&
OtherVirtualBase->isVirtuallyDerivedFrom(VirtualBase);
});
const bool HiddenByDirectConcreteBase = llvm::any_of(
DirectConcreteBases, [&](const CXXRecordDecl *DirectBase) {
return DirectBase->isVirtuallyDerivedFrom(VirtualBase);
});
return !HiddenByMoreDerivedVirtualBase && !HiddenByDirectConcreteBase;
});
if (NumConcrete > 1)
diag(D.getBeginLoc(), "inheriting multiple classes that aren't "
"pure virtual is discouraged");
}
} // namespace clang::tidy::misc