clang: lib/AST/CXXInheritance.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

23#include "llvm/ADT/DenseMap.h"

24#include "llvm/ADT/STLExtras.h"

25#include "llvm/ADT/SmallVector.h"

26#include "llvm/ADT/iterator_range.h"

27#include

28#include

29#include

30

31using namespace clang;

32

33

34

35

36

38 BaseType = BaseType.getUnqualifiedType();

39 IsVirtBaseAndNumberNonVirtBases Subobjects = ClassSubobjects.lookup(BaseType);

40 return Subobjects.NumberOfNonVirtBases + (Subobjects.IsVirtBase ? 1 : 0) > 1;

41}

42

43

45 Paths.clear();

46 ClassSubobjects.clear();

47 VisitedDependentRecords.clear();

48 ScratchPath.clear();

49 DetectedVirtual = nullptr;

50}

51

52

53

55 std::swap(Origin, Other.Origin);

56 Paths.swap(Other.Paths);

57 ClassSubobjects.swap(Other.ClassSubobjects);

58 VisitedDependentRecords.swap(Other.VisitedDependentRecords);

59 std::swap(FindAmbiguities, Other.FindAmbiguities);

60 std::swap(RecordPaths, Other.RecordPaths);

61 std::swap(DetectVirtual, Other.DetectVirtual);

62 std::swap(DetectedVirtual, Other.DetectedVirtual);

63}

64

70

74 return false;

75

77

81 return Specifier->getType()->getAsRecordDecl() &&

83 },

84 Paths);

85}

86

89 return false;

90

91 CXXBasePaths Paths(false, false,

92 false);

93

95 return false;

96

98

103 },

104 Paths);

105}

106

110 return Base->getCanonicalDecl() != TargetDecl;

111 });

112}

113

114bool

117

119 if (CurContext->Equals(this))

120 return true;

121

122 return false;

123}

124

127

129 while (true) {

130 for (const auto &I : Record->bases()) {

131 const auto *Base = I.getType()->getAsCXXRecordDecl();

132 if (Base || !(Base->isBeingDefined() || Base->isCompleteDefinition()))

133 return false;

134 if (Base->isDependentContext() && Base->isCurrentInstantiation(Record))

135 return false;

136

137 Queue.push_back(Base);

138 if (!BaseMatches(Base))

139 return false;

140 }

141

142 if (Queue.empty())

143 break;

144 Record = Queue.pop_back_val();

145 }

146

147 return true;

148}

149

150bool CXXBasePaths::lookupInBases(ASTContext &Context,

153 bool LookupInDependent) {

154 bool FoundPath = false;

155

156

158 bool IsFirstStep = ScratchPath.empty();

159

160 for (const auto &BaseSpec : Record->bases()) {

161

164

166 if (!isCurrentInstantiation) {

167 if (auto *BaseRecord = cast_if_present(

168 BaseSpec.getType()->getAsRecordDecl()))

169 isCurrentInstantiation = BaseRecord->isDependentContext() &&

170 BaseRecord->isCurrentInstantiation(Record);

171 }

172

173

174

175

176

177

178 if (!LookupInDependent &&

179 (BaseType->isDependentType() && !isCurrentInstantiation))

180 continue;

181

182

183

184 IsVirtBaseAndNumberNonVirtBases &Subobjects = ClassSubobjects[BaseType];

185 bool VisitBase = true;

186 bool SetVirtual = false;

187 if (BaseSpec.isVirtual()) {

188 VisitBase = !Subobjects.IsVirtBase;

189 Subobjects.IsVirtBase = true;

191

192

193 DetectedVirtual = BaseType->getAsCanonical();

194 SetVirtual = true;

195 }

196 } else {

197 ++Subobjects.NumberOfNonVirtBases;

198 }

200

201 CXXBasePathElement Element;

202 Element.Base = &BaseSpec;

204 if (BaseSpec.isVirtual())

206 else

207 Element.SubobjectNumber = Subobjects.NumberOfNonVirtBases;

208 ScratchPath.push_back(Element);

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225 if (IsFirstStep)

226 ScratchPath.Access = BaseSpec.getAccessSpecifier();

227 else

229 BaseSpec.getAccessSpecifier());

230 }

231

232

233 bool FoundPathThroughBase = false;

234

235 if (BaseMatches(&BaseSpec, ScratchPath)) {

236

237 FoundPath = FoundPathThroughBase = true;

239

240 Paths.push_back(ScratchPath);

242

243

244 return FoundPath;

245 }

246 } else if (VisitBase) {

248 if (LookupInDependent) {

249 const TemplateSpecializationType *TST =

250 BaseSpec.getType()->getAs();

251 if (!TST) {

252 BaseRecord = BaseSpec.getType()->getAsCXXRecordDecl();

253 } else {

255 if (auto *TD =

257 BaseRecord = TD->getTemplatedDecl();

258 }

259 if (BaseRecord) {

261 BaseRecord = nullptr;

262 else if (!VisitedDependentRecords.insert(BaseRecord).second)

263 BaseRecord = nullptr;

264 }

265 } else {

266 BaseRecord = BaseSpec.getType()->castAsCXXRecordDecl();

267 }

268 if (BaseRecord &&

269 lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {

270

271

272

273

274

275

276

277

278 FoundPath = FoundPathThroughBase = true;

280 return FoundPath;

281 }

282 }

283

284

285

287 ScratchPath.pop_back();

288 }

289

290

291 if (SetVirtual && !FoundPathThroughBase) {

292 DetectedVirtual = nullptr;

293 }

294 }

295

296

297 ScratchPath.Access = AccessToHere;

298

299 return FoundPath;

300}

301

304 bool LookupInDependent) const {

305

306 if (!Paths.lookupInBases(getASTContext(), this, BaseMatches,

307 LookupInDependent))

308 return false;

309

310

311

313 return true;

314

315

316

317

318

319

320

321

322

323

324

325 Paths.Paths.remove_if([&Paths](const CXXBasePath &Path) {

327 if (!PE.Base->isVirtual())

328 continue;

329

330 auto *VBase = PE.Base->getType()->getAsCXXRecordDecl();

331 if (!VBase)

332 break;

333

334

335

336

337

338 for (const CXXBasePath &HidingP : Paths) {

339 auto *HidingClass =

340 HidingP.back().Base->getType()->getAsCXXRecordDecl();

341 if (!HidingClass)

342 break;

343

344 if (HidingClass->isVirtuallyDerivedFrom(VBase))

345 return true;

346 }

347 }

348 return false;

349 });

350

351 return true;

352}

353

358 "User data for FindBaseClass is not canonical!");

360 ->getCanonicalDecl() == BaseRecord;

361}

362

367 "User data for FindBaseClass is not canonical!");

368 return Specifier->isVirtual() &&

370 ->getCanonicalDecl() == BaseRecord;

371}

372

377

383 return true;

384

385 return false;

386}

387

391 return true;

392

396 return findOrdinaryMember(Specifier->getType()->castAsCXXRecordDecl(),

397 Path, Name);

398 },

399 Paths);

400}

401

405 = Overrides[OverriddenSubobject];

406 if (!llvm::is_contained(SubobjectOverrides, Overriding))

407 SubobjectOverrides.push_back(Overriding);

408}

409

413 MEnd = I->second.end();

414 M != MEnd;

415 ++M)

416 add(I->first, *M);

417 }

418}

419

422 I->second.clear();

423 I->second.push_back(Overriding);

424 }

425}

426

427namespace {

428

429class FinalOverriderCollector {

430

431

432 llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount;

433

434

435 llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders;

436

438

439public:

440 ~FinalOverriderCollector();

441

445};

446

447}

448

449void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,

453 unsigned SubobjectNumber = 0;

455 SubobjectNumber

457

458 for (const auto &Base : RD->bases()) {

459 if (const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl()) {

460 if (!BaseDecl->isPolymorphic())

461 continue;

462

463 if (Overriders.empty() && Base.isVirtual()) {

464

465

466 Collect(BaseDecl, false, InVirtualSubobject, Overriders);

467 continue;

468 }

469

470

471

472

473

474

477 if (Base.isVirtual()) {

479 BaseOverriders = MyVirtualOverriders;

480 if (!MyVirtualOverriders) {

482

483

484

485

486 BaseOverriders = MyVirtualOverriders;

487

488 Collect(BaseDecl, true, BaseDecl, *MyVirtualOverriders);

489 }

490 } else

491 Collect(BaseDecl, false, InVirtualSubobject, ComputedBaseOverriders);

492

493

494

495 for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(),

496 OMEnd = BaseOverriders->end();

497 OM != OMEnd;

498 ++OM) {

500 Overriders[CanonOM].add(OM->second);

501 }

502 }

503 }

504

505 for (auto *M : RD->methods()) {

506

507 if (!M->isVirtual())

508 continue;

509

511 using OverriddenMethodsRange =

512 llvm::iterator_rangeCXXMethodDecl::method\_iterator;

513 OverriddenMethodsRange OverriddenMethods = CanonM->overridden_methods();

514

515 if (OverriddenMethods.begin() == OverriddenMethods.end()) {

516

517

518

519

520

521

522 Overriders[CanonM].add(SubobjectNumber,

524 InVirtualSubobject));

525 continue;

526 }

527

528

529

530

531

532

533

535 while (!Stack.empty()) {

536 for (const CXXMethodDecl *OM : Stack.pop_back_val()) {

538

539

540

541

542

543

544

545

546

547

548 Overriders[CanonOM].replaceAll(

550 InVirtualSubobject));

551

553 if (OverriddenMethods.begin() == OverriddenMethods.end())

554 continue;

555

556

557

558 Stack.push_back(OverriddenMethods);

559 }

560 }

561

562

563

564 Overriders[CanonM].add(SubobjectNumber,

566 InVirtualSubobject));

567 }

568}

569

570FinalOverriderCollector::~FinalOverriderCollector() {

571 for (llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *>::iterator

572 VO = VirtualOverriders.begin(), VOEnd = VirtualOverriders.end();

573 VO != VOEnd;

574 ++VO)

575 delete VO->second;

576}

577

578void

580 FinalOverriderCollector Collector;

581 Collector.Collect(this, false, nullptr, FinalOverriders);

582

583

584

585

586 for (auto &OM : FinalOverriders) {

587 for (auto &SO : OM.second) {

589 if (Overriding.size() < 2)

590 continue;

591

593 if (!M.InVirtualSubobject)

594 return false;

595

596

597

598

599

600

602 if (&M != &OP &&

603 OP.Method->getParent()->isVirtuallyDerivedFrom(

604 M.InVirtualSubobject))

605 return true;

606 return false;

607 };

608

609

610

611 llvm::erase_if(Overriding, IsHidden);

612 }

613 }

614}

615

616static void

619

620 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);

623

624 for (const auto &I : RD->bases()) {

625 assert(!I.getType()->isDependentType() &&

626 "Cannot get indirect primary bases for class with dependent bases.");

627

630

631

632

635 }

636

637}

638

639void

642

644 return;

645

646 for (const auto &I : bases()) {

647 assert(!I.getType()->isDependentType() &&

648 "Cannot get indirect primary bases for class with dependent bases.");

649

652

653

654

657 }

658}

Defines the clang::ASTContext interface.

static void AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, CXXIndirectPrimaryBaseSet &Bases)

Definition CXXInheritance.cpp:617

static bool isOrdinaryMember(const NamedDecl *ND)

Definition CXXInheritance.cpp:373

static bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path, DeclarationName Name)

Definition CXXInheritance.cpp:378

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

Defines the C++ template declaration subclasses.

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

llvm::MachO::Record Record

C Language Family Type Representation.

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...

const CXXRecordDecl * getPrimaryBase() const

getPrimaryBase - Get the primary base for this record.

bool isPrimaryBaseVirtual() const

isPrimaryBaseVirtual - Get whether the primary base for this record is virtual or not.

Represents a path from a specific derived class (which is not represented as part of the path) to a p...

DeclContext::lookup_iterator Decls

The declarations found inside this base class subobject.

AccessSpecifier Access

The access along this inheritance path.

BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...

CXXBasePaths(bool FindAmbiguities=true, bool RecordPaths=true, bool DetectVirtual=true)

BasePaths - Construct a new BasePaths structure to record the paths for a derived-to-base search.

bool isRecordingPaths() const

Whether we are recording paths.

void setOrigin(const CXXRecordDecl *Rec)

bool isDetectingVirtual() const

Whether we are detecting virtual bases.

void clear()

Clear the base-paths results.

Definition CXXInheritance.cpp:44

friend class CXXRecordDecl

bool isFindingAmbiguities() const

Whether we are finding multiple paths to detect ambiguities.

void swap(CXXBasePaths &Other)

Swap this data structure's contents with another CXXBasePaths object.

Definition CXXInheritance.cpp:54

bool isAmbiguous(CanQualType BaseType) const

Determine whether the path from the most-derived type to the given base type is ambiguous (i....

Definition CXXInheritance.cpp:37

Represents a base class of a C++ class.

A mapping from each virtual member function to its set of final overriders.

A set of all the primary bases for a class.

Represents a static or instance method of a struct/union/class.

overridden_method_range overridden_methods() const

CXXMethodDecl * getCanonicalDecl() override

Retrieves the "canonical" declaration of the given declaration.

Represents a C++ struct/union/class.

llvm::function_ref< bool(const CXXBaseSpecifier *Specifier, CXXBasePath &Path)> BaseMatchesCallback

Function type used by lookupInBases() to determine whether a specific base class subobject matches th...

void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet &Bases) const

Get the indirect primary bases for this class.

Definition CXXInheritance.cpp:640

llvm::function_ref< bool(const CXXRecordDecl *BaseDefinition)> ForallBasesCallback

Function type used by forallBases() as a callback.

bool isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const

Determine whether this class is provably not derived from the type Base.

Definition CXXInheritance.cpp:107

method_range methods() const

static AccessSpecifier MergeAccess(AccessSpecifier PathAccess, AccessSpecifier DeclAccess)

Calculates the access of a decl that is reached along a path.

bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths, bool LookupInDependent=false) const

Look for entities within the base classes of this C++ class, transitively searching all base class su...

Definition CXXInheritance.cpp:302

CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, CXXRecordDecl *PrevDecl)

bool hasDefinition() const

void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const

Retrieve the final overriders for each virtual member function in the class hierarchy where this clas...

Definition CXXInheritance.cpp:579

bool isCurrentInstantiation(const DeclContext *CurContext) const

Determine whether this dependent class is a current instantiation, when viewed from within the given ...

Definition CXXInheritance.cpp:115

bool hasMemberName(DeclarationName N) const

Determine whether this class has a member with the given name, possibly in a non-dependent base class...

Definition CXXInheritance.cpp:388

static bool FindVirtualBaseClass(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, const CXXRecordDecl *BaseRecord)

Base-class lookup callback that determines whether the given base class specifier refers to a specifi...

Definition CXXInheritance.cpp:363

static bool FindBaseClass(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, const CXXRecordDecl *BaseRecord)

Base-class lookup callback that determines whether the given base class specifier refers to a specifi...

Definition CXXInheritance.cpp:354

bool isVirtuallyDerivedFrom(const CXXRecordDecl *Base) const

Determine whether this class is virtually derived from the class Base.

Definition CXXInheritance.cpp:87

bool forallBases(ForallBasesCallback BaseMatches) const

Determines if the given callback holds for all the direct or indirect base classes of this type.

Definition CXXInheritance.cpp:125

CXXRecordDecl * getCanonicalDecl() override

Retrieves the "canonical" declaration of the given declaration.

unsigned getNumVBases() const

Retrieves the number of virtual base classes of this class.

bool isDerivedFrom(const CXXRecordDecl *Base) const

Determine whether this class is derived from the class Base.

Definition CXXInheritance.cpp:65

DeclContext * getParent()

getParent - Returns the containing DeclContext.

bool Equals(const DeclContext *DC) const

Determine whether this declaration context is equivalent to the declaration context DC.

lookup_result::iterator lookup_iterator

bool isFileContext() const

bool isDependentContext() const

Determines whether this context is dependent on a template parameter.

lookup_result lookup(DeclarationName Name) const

lookup - Find the declarations (if any) with the given Name in this context.

ASTContext & getASTContext() const LLVM_READONLY

bool isInIdentifierNamespace(unsigned NS) const

@ IDNS_Ordinary

Ordinary names.

@ IDNS_Member

Members, declared with object declarations within tag definitions.

@ IDNS_Tag

Tags, declared with 'struct foo;' and referenced with 'struct foo'.

The name of a declaration.

This represents a decl that may have a name.

The set of methods that override a given virtual method in each subobject where it occurs.

void replaceAll(UniqueVirtualMethod Overriding)

Definition CXXInheritance.cpp:420

MapType::iterator iterator

MapType::const_iterator const_iterator

void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding)

Definition CXXInheritance.cpp:402

SmallVectorImpl< UniqueVirtualMethod >::const_iterator overriding_const_iterator

A (possibly-)qualified type.

QualType getCanonicalType() const

QualType getUnqualifiedType() const

Retrieve the unqualified variant of the given type, removing as little sugar as possible.

TemplateDecl * getAsTemplateDecl(bool IgnoreDeduced=false) const

Retrieve the underlying template declaration that this template name refers to, if known.

The JSON file list parser is used to communicate input to InstallAPI.

CanQual< Type > CanQualType

Represents a canonical, potentially-qualified type.

bool isa(CodeGen::Address addr)

@ TemplateName

The identifier is a template name. FIXME: Add an annotation for that.

AccessSpecifier

A C++ access specifier (public, private, protected), plus the special value "none" which means differ...

U cast(CodeGen::Address addr)

@ Other

Other implicit parameter.

Represents an element in a path from a derived class to a base class.

int SubobjectNumber

Identifies which base class subobject (of type Base->getType()) this base path element refers to.

const CXXRecordDecl * Class

The record decl of the class that the base is a base of.

const CXXBaseSpecifier * Base

The base specifier that states the link from a derived class to a base class, which will be followed ...

Uniquely identifies a virtual method within a class hierarchy by the method itself and a class subobj...