void addSubNodes(CXXRecordDecl* RD) { addSubNodes(cast<RecordDecl>(RD)); if (RD->isDefinition()) { // FIXME: This breaks XML generation //Doc.addAttribute("num_bases", RD->getNumBases()); for (CXXRecordDecl::base_class_iterator base = RD->bases_begin(), bend = RD->bases_end(); base != bend; ++base) { Doc.addSubNode("Base"); Doc.addAttribute("id", base->getType()); AccessSpecifier as = base->getAccessSpecifierAsWritten(); const char* as_name = ""; switch(as) { case AS_none: as_name = ""; break; case AS_public: as_name = "public"; break; case AS_protected: as_name = "protected"; break; case AS_private: as_name = "private"; break; } Doc.addAttributeOptional("access", as_name); Doc.addAttribute("is_virtual", base->isVirtual()); Doc.toParent(); } } }
/// Collect the visible conversions of a base class. /// /// \param Base a base class of the class we're considering /// \param InVirtual whether this base class is a virtual base (or a base /// of a virtual base) /// \param Access the access along the inheritance path to this base /// \param ParentHiddenTypes the conversions provided by the inheritors /// of this base /// \param Output the set to which to add conversions from non-virtual bases /// \param VOutput the set to which to add conversions from virtual bases /// \param HiddenVBaseCs the set of conversions which were hidden in a /// virtual base along some inheritance path static void CollectVisibleConversions(ASTContext &Context, CXXRecordDecl *Record, bool InVirtual, AccessSpecifier Access, const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes, UnresolvedSetImpl &Output, UnresolvedSetImpl &VOutput, llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) { // The set of types which have conversions in this class or its // subclasses. As an optimization, we don't copy the derived set // unless it might change. const llvm::SmallPtrSet<CanQualType, 8> *HiddenTypes = &ParentHiddenTypes; llvm::SmallPtrSet<CanQualType, 8> HiddenTypesBuffer; // Collect the direct conversions and figure out which conversions // will be hidden in the subclasses. UnresolvedSetImpl &Cs = *Record->getConversionFunctions(); if (!Cs.empty()) { HiddenTypesBuffer = ParentHiddenTypes; HiddenTypes = &HiddenTypesBuffer; for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) { bool Hidden = !HiddenTypesBuffer.insert(GetConversionType(Context, I.getDecl())); // If this conversion is hidden and we're in a virtual base, // remember that it's hidden along some inheritance path. if (Hidden && InVirtual) HiddenVBaseCs.insert(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())); // If this conversion isn't hidden, add it to the appropriate output. else if (!Hidden) { AccessSpecifier IAccess = CXXRecordDecl::MergeAccess(Access, I.getAccess()); if (InVirtual) VOutput.addDecl(I.getDecl(), IAccess); else Output.addDecl(I.getDecl(), IAccess); } } } // Collect information recursively from any base classes. for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { const RecordType *RT = I->getType()->getAs<RecordType>(); if (!RT) continue; AccessSpecifier BaseAccess = CXXRecordDecl::MergeAccess(Access, I->getAccessSpecifier()); bool BaseInVirtual = InVirtual || I->isVirtual(); CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl()); CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, *HiddenTypes, Output, VOutput, HiddenVBaseCs); } }
void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { // FIXME: add printing of pragma attributes if required. if (!Policy.SuppressSpecifiers && D->isModulePrivate()) Out << "__module_private__ "; Out << D->getKindName(); prettyPrintAttributes(D); if (D->getIdentifier()) { Out << ' ' << *D; if (auto S = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) printTemplateArguments(S->getTemplateArgs(), S->getTemplateParameters()); else if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D)) printTemplateArguments(S->getTemplateArgs()); } if (D->isCompleteDefinition()) { // Print the base classes if (D->getNumBases()) { Out << " : "; for (CXXRecordDecl::base_class_iterator Base = D->bases_begin(), BaseEnd = D->bases_end(); Base != BaseEnd; ++Base) { if (Base != D->bases_begin()) Out << ", "; if (Base->isVirtual()) Out << "virtual "; AccessSpecifier AS = Base->getAccessSpecifierAsWritten(); if (AS != AS_none) { Print(AS); Out << " "; } Out << Base->getType().getAsString(Policy); if (Base->isPackExpansion()) Out << "..."; } } // Print the class definition // FIXME: Doesn't print access specifiers, e.g., "public:" if (Policy.TerseOutput) { Out << " {}"; } else { Out << " {\n"; VisitDeclContext(D); Indent() << "}"; } } }
void ASTDumper::VisitCXXRecordDecl(CXXRecordDecl *D) { VisitRecordDecl(D); if (!D->isCompleteDefinition()) return; for (CXXRecordDecl::base_class_iterator I = D->bases_begin(), E = D->bases_end(); I != E; ++I) { IndentScope Indent(*this); if (I->isVirtual()) OS << "virtual "; dumpAccessSpecifier(I->getAccessSpecifier()); dumpType(I->getType()); if (I->isPackExpansion()) OS << "..."; } }
/// Collect the visible conversions of a class. /// /// This would be extremely straightforward if it weren't for virtual /// bases. It might be worth special-casing that, really. static void CollectVisibleConversions(ASTContext &Context, CXXRecordDecl *Record, UnresolvedSetImpl &Output) { // The collection of all conversions in virtual bases that we've // found. These will be added to the output as long as they don't // appear in the hidden-conversions set. UnresolvedSet<8> VBaseCs; // The set of conversions in virtual bases that we've determined to // be hidden. llvm::SmallPtrSet<NamedDecl*, 8> HiddenVBaseCs; // The set of types hidden by classes derived from this one. llvm::SmallPtrSet<CanQualType, 8> HiddenTypes; // Go ahead and collect the direct conversions and add them to the // hidden-types set. UnresolvedSetImpl &Cs = *Record->getConversionFunctions(); Output.append(Cs.begin(), Cs.end()); for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) HiddenTypes.insert(GetConversionType(Context, I.getDecl())); // Recursively collect conversions from base classes. for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { const RecordType *RT = I->getType()->getAs<RecordType>(); if (!RT) continue; CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()), I->isVirtual(), I->getAccessSpecifier(), HiddenTypes, Output, VBaseCs, HiddenVBaseCs); } // Add any unhidden conversions provided by virtual bases. for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end(); I != E; ++I) { if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl()))) Output.addDecl(I.getDecl(), I.getAccess()); } }
/// getNestedVisibleConversionFunctions - imports unique conversion /// functions from base classes into the visible conversion function /// list of the class 'RD'. This is a private helper method. /// TopConversionsTypeSet is the set of conversion functions of the class /// we are interested in. HiddenConversionTypes is set of conversion functions /// of the immediate derived class which hides the conversion functions found /// in current class. void CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet, const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes) { bool inTopClass = (RD == this); QualType ClassType = getASTContext().getTypeDeclType(this); if (const RecordType *Record = ClassType->getAs<RecordType>()) { const UnresolvedSetImpl *Cs = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { NamedDecl *Conv = *I; // Only those conversions not exact match of conversions in current // class are candidateconversion routines. CanQualType ConvType; if (FunctionTemplateDecl *ConversionTemplate = dyn_cast<FunctionTemplateDecl>(Conv)) ConvType = getASTContext().getCanonicalType( ConversionTemplate->getTemplatedDecl()->getResultType()); else ConvType = getASTContext().getCanonicalType( cast<CXXConversionDecl>(Conv)->getConversionType()); // We only add conversion functions found in the base class if they // are not hidden by those found in HiddenConversionTypes which are // the conversion functions in its derived class. if (inTopClass || (!TopConversionsTypeSet.count(ConvType) && !HiddenConversionTypes.count(ConvType)) ) { if (FunctionTemplateDecl *ConversionTemplate = dyn_cast<FunctionTemplateDecl>(Conv)) RD->addVisibleConversionFunction(ConversionTemplate); else RD->addVisibleConversionFunction(cast<CXXConversionDecl>(Conv)); } } } if (getNumBases() == 0 && getNumVBases() == 0) return; llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions; if (!inTopClass) collectConversionFunctions(ConversionFunctions); for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(), E = vbases_end(); VBase != E; ++VBase) { if (const RecordType *RT = VBase->getType()->getAs<RecordType>()) { CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); VBaseClassDecl->getNestedVisibleConversionFunctions(RD, TopConversionsTypeSet, (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); } } for (CXXRecordDecl::base_class_iterator Base = bases_begin(), E = bases_end(); Base != E; ++Base) { if (Base->isVirtual()) continue; if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); BaseClassDecl->getNestedVisibleConversionFunctions(RD, TopConversionsTypeSet, (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); } } }