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#include

31

32using namespace clang;

33

34

35

36

37

40 IsVirtBaseAndNumberNonVirtBases Subobjects = ClassSubobjects[BaseType];

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

42}

43

44

46 Paths.clear();

47 ClassSubobjects.clear();

48 VisitedDependentRecords.clear();

49 ScratchPath.clear();

50 DetectedVirtual = nullptr;

51}

52

53

54

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

57 Paths.swap(Other.Paths);

58 ClassSubobjects.swap(Other.ClassSubobjects);

59 VisitedDependentRecords.swap(Other.VisitedDependentRecords);

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

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

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

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

64}

65

67 CXXBasePaths Paths(false, false,

68 false);

70}

71

75 return false;

76

77 Paths.setOrigin(const_cast<CXXRecordDecl*>(this));

78

84 },

85 Paths);

86}

87

90 return false;

91

92 CXXBasePaths Paths(false, false,

93 false);

94

96 return false;

97

98 Paths.setOrigin(const_cast<CXXRecordDecl*>(this));

99

104 },

105 Paths);

106}

107

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

112 });

113}

114

115bool

118

120 if (CurContext->Equals(this))

121 return true;

122

123 return false;

124}

125

128

130 while (true) {

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

133 if (!Ty)

134 return false;

135

139 (Base->isDependentContext() &&

140 Base->isCurrentInstantiation(Record))) {

141 return false;

142 }

143

144 Queue.push_back(Base);

145 if (!BaseMatches(Base))

146 return false;

147 }

148

149 if (Queue.empty())

150 break;

151 Record = Queue.pop_back_val();

152 }

153

154 return true;

155}

156

157bool CXXBasePaths::lookupInBases(ASTContext &Context,

160 bool LookupInDependent) {

161 bool FoundPath = false;

162

163

165 bool IsFirstStep = ScratchPath.empty();

166

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

168

171

172 bool isCurrentInstantiation = isa(BaseType);

173 if (!isCurrentInstantiation) {

174 if (auto *BaseRecord = cast_if_present(

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

176 isCurrentInstantiation = BaseRecord->isDependentContext() &&

177 BaseRecord->isCurrentInstantiation(Record);

178 }

179

180

181

182

183

184

185 if (!LookupInDependent &&

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

187 continue;

188

189

190

191 IsVirtBaseAndNumberNonVirtBases &Subobjects = ClassSubobjects[BaseType];

192 bool VisitBase = true;

193 bool SetVirtual = false;

194 if (BaseSpec.isVirtual()) {

195 VisitBase = !Subobjects.IsVirtBase;

196 Subobjects.IsVirtBase = true;

198

199

201 SetVirtual = true;

202 }

203 } else {

204 ++Subobjects.NumberOfNonVirtBases;

205 }

207

209 Element.Base = &BaseSpec;

210 Element.Class = Record;

211 if (BaseSpec.isVirtual())

212 Element.SubobjectNumber = 0;

213 else

214 Element.SubobjectNumber = Subobjects.NumberOfNonVirtBases;

215 ScratchPath.push_back(Element);

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232 if (IsFirstStep)

233 ScratchPath.Access = BaseSpec.getAccessSpecifier();

234 else

236 BaseSpec.getAccessSpecifier());

237 }

238

239

240 bool FoundPathThroughBase = false;

241

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

243

244 FoundPath = FoundPathThroughBase = true;

246

247 Paths.push_back(ScratchPath);

249

250

251 return FoundPath;

252 }

253 } else if (VisitBase) {

255 if (LookupInDependent) {

258 if (!TST) {

259 if (auto *RT = BaseSpec.getType()->getAs<RecordType>())

260 BaseRecord = cast(RT->getDecl());

261 } else {

263 if (auto *TD =

265 BaseRecord = TD->getTemplatedDecl();

266 }

267 if (BaseRecord) {

269 BaseRecord = nullptr;

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

271 BaseRecord = nullptr;

272 }

273 } else {

274 BaseRecord = cast(BaseSpec.getType()->getAsRecordDecl());

275 }

276 if (BaseRecord &&

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

278

279

280

281

282

283

284

285

286 FoundPath = FoundPathThroughBase = true;

288 return FoundPath;

289 }

290 }

291

292

293

295 ScratchPath.pop_back();

296 }

297

298

299 if (SetVirtual && !FoundPathThroughBase) {

300 DetectedVirtual = nullptr;

301 }

302 }

303

304

305 ScratchPath.Access = AccessToHere;

306

307 return FoundPath;

308}

309

312 bool LookupInDependent) const {

313

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

315 LookupInDependent))

316 return false;

317

318

319

320 if (!Paths.isRecordingPaths() || !Paths.isFindingAmbiguities())

321 return true;

322

323

324

325

326

327

328

329

330

331

332

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

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

336 continue;

337

340 VBase = cast(Record->getDecl());

341 if (!VBase)

342 break;

343

344

345

346

347

348 for (const CXXBasePath &HidingP : Paths) {

352 HidingClass = cast(Record->getDecl());

353 if (!HidingClass)

354 break;

355

357 return true;

358 }

359 }

360 return false;

361 });

362

363 return true;

364}

365

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

372 ->getCanonicalDecl() == BaseRecord;

373}

374

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

382 ->getCanonicalDecl() == BaseRecord;

383}

384

388}

389

395 return true;

396

397 return false;

398}

399

403 return true;

404

410 },

411 Paths);

412}

413

414static bool

419 if (!TST) {

421 if (!RT)

422 return false;

424 }

426 const auto *TD = dyn_cast_or_null(TN.getAsTemplateDecl());

427 if (!TD)

428 return false;

430 if (!RD)

431 return false;

433}

434

437 llvm::function_ref<bool(const NamedDecl *ND)> Filter) {

438 std::vector<const NamedDecl *> Results;

439

440 bool AnyOrdinaryMembers = false;

443 AnyOrdinaryMembers = true;

444 if (Filter(ND))

445 Results.push_back(ND);

446 }

447 if (AnyOrdinaryMembers)

448 return Results;

449

450

452 Paths.setOrigin(this);

456 },

457 Paths, true))

458 return Results;

460 I != E; ++I) {

462 Results.push_back(*I);

463 }

464 return Results;

465}

466

470 = Overrides[OverriddenSubobject];

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

472 SubobjectOverrides.push_back(Overriding);

473}

474

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

479 M != MEnd;

480 ++M)

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

482 }

483}

484

487 I->second.clear();

488 I->second.push_back(Overriding);

489 }

490}

491

492namespace {

493

494class FinalOverriderCollector {

495

496

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

498

499

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

501

503

504public:

505 ~FinalOverriderCollector();

506

510};

511

512}

513

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

518 unsigned SubobjectNumber = 0;

520 SubobjectNumber

521 = ++SubobjectCount[cast(RD->getCanonicalDecl())];

522

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

525 const CXXRecordDecl *BaseDecl = cast(RT->getDecl());

527 continue;

528

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

530

531

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

533 continue;

534 }

535

536

537

538

539

540

543 if (Base.isVirtual()) {

545 BaseOverriders = MyVirtualOverriders;

546 if (!MyVirtualOverriders) {

548

549

550

551

552 BaseOverriders = MyVirtualOverriders;

553

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

555 }

556 } else

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

558

559

560

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

562 OMEnd = BaseOverriders->end();

563 OM != OMEnd;

564 ++OM) {

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

567 }

568 }

569 }

570

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

572

573 if (!M->isVirtual())

574 continue;

575

577 using OverriddenMethodsRange =

578 llvm::iterator_rangeCXXMethodDecl::method\_iterator;

579 OverriddenMethodsRange OverriddenMethods = CanonM->overridden_methods();

580

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

582

583

584

585

586

587

588 Overriders[CanonM].add(SubobjectNumber,

590 InVirtualSubobject));

591 continue;

592 }

593

594

595

596

597

598

599

601 while (!Stack.empty()) {

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

604

605

606

607

608

609

610

611

612

613

614 Overriders[CanonOM].replaceAll(

616 InVirtualSubobject));

617

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

620 continue;

621

622

623

624 Stack.push_back(OverriddenMethods);

625 }

626 }

627

628

629

630 Overriders[CanonM].add(SubobjectNumber,

632 InVirtualSubobject));

633 }

634}

635

636FinalOverriderCollector::~FinalOverriderCollector() {

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

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

639 VO != VOEnd;

640 ++VO)

641 delete VO->second;

642}

643

644void

646 FinalOverriderCollector Collector;

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

648

649

650

651

652 for (auto &OM : FinalOverriders) {

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

655 if (Overriding.size() < 2)

656 continue;

657

659 if (!M.InVirtualSubobject)

660 return false;

661

662

663

664

665

666

668 if (&M != &OP &&

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

670 M.InVirtualSubobject))

671 return true;

672 return false;

673 };

674

675

676

677 llvm::erase_if(Overriding, IsHidden);

678 }

679 }

680}

681

682static void

685

689

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

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

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

693

695 cast(I.getType()->getAsRecordDecl());

696

697

698

701 }

702

703}

704

705void

708

710 return;

711

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

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

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

715

717 cast(I.getType()->getAsRecordDecl());

718

719

720

723 }

724}

Defines the clang::ASTContext interface.

static bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name)

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

static bool isOrdinaryMember(const NamedDecl *ND)

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

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

static RecordDecl * getAsRecordDecl(QualType BaseType)

C Language Family Type Representation.

const NestedNameSpecifier * Specifier

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

const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const

Get or compute information about the layout of the specified record (struct/union/class) D,...

CanQualType getCanonicalType(QualType T) const

Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...

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...

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...

bool isRecordingPaths() const

Whether we are recording paths.

bool isDetectingVirtual() const

Whether we are detecting virtual bases.

bool isAmbiguous(CanQualType BaseType)

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

void clear()

Clear the base-paths results.

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.

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.

void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet &Bases) const

Get the indirect primary bases for this class.

bool isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const

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

method_range methods() const

static AccessSpecifier MergeAccess(AccessSpecifier PathAccess, AccessSpecifier DeclAccess)

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

bool isPolymorphic() const

Whether this class is polymorphic (C++ [class.virtual]), which means that the class contains or inher...

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...

bool hasDefinition() const

void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const

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

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...

bool isCurrentInstantiation(const DeclContext *CurContext) const

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

bool hasMemberName(DeclarationName N) const

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

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

Function type used by forallBases() as a callback.

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...

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...

bool isVirtuallyDerivedFrom(const CXXRecordDecl *Base) const

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

bool forallBases(ForallBasesCallback BaseMatches) const

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

std::vector< const NamedDecl * > lookupDependentName(DeclarationName Name, llvm::function_ref< bool(const NamedDecl *ND)> Filter)

Performs an imprecise lookup of a dependent name in this class.

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.

CanQual< T > getUnqualifiedType() const

Retrieve the unqualified form of this type.

DeclContext - This is used only as base class of specific decl types that can act as declaration cont...

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.

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.

CXXRecordDecl * getAsRecordDecl() const

Retrieve the record declaration stored in this nested name specifier.

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

void replaceAll(UniqueVirtualMethod Overriding)

MapType::iterator iterator

SmallVectorImpl< UniqueVirtualMethod >::const_iterator overriding_const_iterator

MapType::const_iterator const_iterator

void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding)

A (possibly-)qualified type.

RecordDecl * getDefinition() const

Returns the RecordDecl that actually defines this struct/union/class.

A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...

RecordDecl * getDecl() const

Represents a C++ template name within the type system.

TemplateDecl * getAsTemplateDecl(bool IgnoreDeduced=false) const

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

Represents a type template specialization; the template must be a class template, a type alias templa...

TemplateName getTemplateName() const

Retrieve the name of the template that we are specializing.

bool isDependentType() const

Whether this type is a dependent type, meaning that its definition somehow depends on a template para...

const T * getAs() const

Member-template getAs'.

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

if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))

@ Other

Other implicit parameter.

AccessSpecifier

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

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

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