Record* HandleRecordDecl(CXXRecordDecl *D) { assert(D && "Class missing in HandleRecordDecl"); if (!D->hasDefinition()) return NULL; // skip duplication if(records.find(D->getQualifiedNameAsString()) != records.end()) return 0; Record *r = new Record; r->qualifiedname = D->getQualifiedNameAsString(); //find all base classes //we skip all the template classes or there will be Assertion failed if (!D->getDescribedClassTemplate ()) { for (CXXRecordDecl::base_class_iterator iter = D->bases_begin(); iter != D->bases_end(); ++iter) { if (iter) { QualType type = iter->getType(); std::string tmp = type.getAsString(); //remove "class " tmp.erase(0, 6); r->bases.insert(tmp); } } } return r; }
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); } }
/** * Once the recursive visitor has completed, this routine analyzes the * MostDerivedTypeMap to find errors in the structure of the OMR classes */ void VerifyTypeStructure() { trace("Starting Structure Verification"); for (std::map<CXXRecordDecl*, bool>::iterator I = Types.begin(), E=Types.end(); I != E; ++I) { CXXRecordDecl * Type = I->first; bool extensible = I->second; trace(Type << " " << extensible << " " << getAssociatedConcreteType(Type)); if (extensible && !getAssociatedConcreteType(Type)) { trace("xxxx Issue diagnostic because there's no associated concrete type"); continue; } if (extensible) { //Extnsible type . trace("xxxx Verifying " << Type->getQualifiedNameAsString() << " has no non-extensible base classes." ); for (CXXRecordDecl::base_class_iterator BI = Type->bases_begin(), BE = Type->bases_end(); BI != BE; ++BI) { CXXRecordDecl * base_class = BI->getType()->getAsCXXRecordDecl(); if (base_class && !isExtensible(base_class) // Ensure extensible parent. && !isOMRRootType(Type)) { // OMR Root type can have non-extensible parents. //Base is not extensible, but an extensible type reaches it, with no concrete class in the middle. //Issue diagnostic. std::string diagnostic("OMR_EXTENSIBLE Type "); diagnostic += Type->getQualifiedNameAsString(); diagnostic += " derives from "; diagnostic += base_class->getQualifiedNameAsString(); diagnostic += " that is not marked as OMR_EXTENSIBLE.\n"; DiagnosticsEngine &diagEngine = Context->getDiagnostics(); unsigned diagID = diagEngine.getCustomDiagID(DiagnosticsEngine::Error, "%0"); diagEngine.Report(base_class->getLocation(), diagID) << diagnostic; } } } else { trace("xxxx Verifying " << Type->getQualifiedNameAsString() << " has no non-extensible base classes." ); for (CXXRecordDecl::base_class_iterator BI = Type->bases_begin(), BE = Type->bases_end(); BI != BE; ++BI) { CXXRecordDecl * base_class = BI->getType()->getAsCXXRecordDecl(); if (base_class && isExtensible(base_class) && !isOMRConcreteType(base_class)) { //Base is not extensible, but an extensible type reaches it, with no concrete class in the middle. //Issue diagnostic. std::string diagnostic("Type "); diagnostic += Type->getQualifiedNameAsString(); diagnostic += " derives from "; diagnostic += base_class->getQualifiedNameAsString(); diagnostic += " that is marked as OMR_EXTENSIBLE.\n"; DiagnosticsEngine &diagEngine = Context->getDiagnostics(); unsigned diagID = diagEngine.getCustomDiagID(DiagnosticsEngine::Error, "%0"); diagEngine.Report(Type->getLocation(), diagID) << diagnostic; } } } } //each most derived type }
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() << "}"; } } }
CXXRecordDecl* BlinkGCPluginConsumer::GetLeftMostBase( CXXRecordDecl* left_most) { CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); while (it != left_most->bases_end()) { if (it->getType()->isDependentType()) left_most = RecordInfo::GetDependentTemplatedDecl(*it->getType()); else left_most = it->getType()->getAsCXXRecordDecl(); if (!left_most || !left_most->hasDefinition()) return 0; it = left_most->bases_begin(); } return left_most; }
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 << "..."; } }
bool FindModule::VisitCXXRecordDecl (CXXRecordDecl * d) { if (_decl->getNumBases () <= 0) { return true; } for (CXXRecordDecl::base_class_iterator bi = _decl->bases_begin (), be = _decl->bases_end (); bi != be; ++bi) { QualType q = bi->getType (); string baseName = q.getAsString (); if (baseName == "::sc_core::sc_module" || baseName == "sc_core::sc_module" || baseName == "class sc_core::sc_module") { _isSystemCModule = true; IdentifierInfo * info = _decl->getIdentifier (); if (info != NULL) { _moduleName = info->getNameStart (); } } } if (_isSystemCModule == false) { return true; } return false; }
/// 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()); } }
bool ClassTemplateToClass::hasUsedNameDecl( ClassTemplatePartialSpecializationDecl *PartialD) { if (!PartialD->isCompleteDefinition()) return false; SmallPtrSet<NamedDecl *, 8> Params; TemplateParameterList *PartialTPList = PartialD->getTemplateParameters(); for (unsigned PI = 0; PI < PartialTPList->size(); ++PI) { NamedDecl *ND = PartialTPList->getParam(PI); if (dyn_cast<NonTypeTemplateParmDecl>(ND)) continue; Params.insert(ND); } TemplateParameterTypeVisitor ParamVisitor(Context); // Skip visiting parameters and arguments for (CXXRecordDecl::base_class_iterator I = PartialD->bases_begin(), E = PartialD->bases_end(); I != E; ++I) { ParamVisitor.TraverseType(I->getType()); } DeclContext *Ctx = dyn_cast<DeclContext>(PartialD); for (DeclContext::decl_iterator DI = Ctx->decls_begin(), DE = Ctx->decls_end(); DI != DE; ++DI) { ParamVisitor.TraverseDecl(*DI); } for (SmallPtrSet<NamedDecl *, 8>::iterator I = Params.begin(), E = Params.end(); I != E; ++I) { if (ParamVisitor.isAUsedParameter(*I)) return true; } return false; }
// The GC infrastructure assumes that if the vtable of a polymorphic // base-class is not initialized for a given object (ie, it is partially // initialized) then the object does not need to be traced. Thus, we must // ensure that any polymorphic class with a trace method does not have any // tractable fields that are initialized before we are sure that the vtable // and the trace method are both defined. There are two cases that need to // hold to satisfy that assumption: // // 1. If trace is virtual, then it must be defined in the left-most base. // This ensures that if the vtable is initialized then it contains a pointer // to the trace method. // // 2. If trace is non-virtual, then the trace method is defined and we must // ensure that the left-most base defines a vtable. This ensures that the // first thing to be initialized when constructing the object is the vtable // itself. void BlinkGCPluginConsumer::CheckPolymorphicClass( RecordInfo* info, CXXMethodDecl* trace) { CXXRecordDecl* left_most = info->record(); CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); CXXRecordDecl* left_most_base = 0; while (it != left_most->bases_end()) { left_most_base = it->getType()->getAsCXXRecordDecl(); if (!left_most_base && it->getType()->isDependentType()) left_most_base = RecordInfo::GetDependentTemplatedDecl(*it->getType()); // TODO: Find a way to correctly check actual instantiations // for dependent types. The escape below will be hit, eg, when // we have a primary template with no definition and // specializations for each case (such as SupplementBase) in // which case we don't succeed in checking the required // properties. if (!left_most_base || !left_most_base->hasDefinition()) return; StringRef name = left_most_base->getName(); // We know GCMixin base defines virtual trace. if (Config::IsGCMixinBase(name)) return; // Stop with the left-most prior to a safe polymorphic base (a safe base // is non-polymorphic and contains no fields). if (Config::IsSafePolymorphicBase(name)) break; left_most = left_most_base; it = left_most->bases_begin(); } if (RecordInfo* left_most_info = cache_.Lookup(left_most)) { // Check condition (1): if (trace && trace->isVirtual()) { if (CXXMethodDecl* trace = left_most_info->GetTraceMethod()) { if (trace->isVirtual()) return; } ReportBaseClassMustDeclareVirtualTrace(info, left_most); return; } // Check condition (2): if (DeclaresVirtualMethods(left_most)) return; if (left_most_base) { // Get the base next to the "safe polymorphic base" if (it != left_most->bases_end()) ++it; if (it != left_most->bases_end()) { if (CXXRecordDecl* next_base = it->getType()->getAsCXXRecordDecl()) { if (CXXRecordDecl* next_left_most = GetLeftMostBase(next_base)) { if (DeclaresVirtualMethods(next_left_most)) return; ReportLeftMostBaseMustBePolymorphic(info, next_left_most); return; } } } } ReportLeftMostBaseMustBePolymorphic(info, left_most); } }
void CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases) { ASTContext &C = getASTContext(); // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] // no base classes [...]. data().Aggregate = false; if (data().Bases) C.Deallocate(data().Bases); // The set of seen virtual base types. llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes; // The virtual bases of this class. llvm::SmallVector<const CXXBaseSpecifier *, 8> VBases; data().Bases = new(C) CXXBaseSpecifier [NumBases]; data().NumBases = NumBases; for (unsigned i = 0; i < NumBases; ++i) { data().Bases[i] = *Bases[i]; // Keep track of inherited vbases for this base class. const CXXBaseSpecifier *Base = Bases[i]; QualType BaseType = Base->getType(); // Skip dependent types; we can't do any checking on them now. if (BaseType->isDependentType()) continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); // Now go through all virtual bases of this base and add them. for (CXXRecordDecl::base_class_iterator VBase = BaseClassDecl->vbases_begin(), E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) { // Add this base if it's not already in the list. if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType()))) VBases.push_back(VBase); } if (Base->isVirtual()) { // Add this base if it's not already in the list. if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType))) VBases.push_back(Base); } } if (VBases.empty()) return; // Create base specifier for any direct or indirect virtual bases. data().VBases = new (C) CXXBaseSpecifier[VBases.size()]; data().NumVBases = VBases.size(); for (int I = 0, E = VBases.size(); I != E; ++I) { TypeSourceInfo *VBaseTypeInfo = VBases[I]->getTypeSourceInfo(); // Skip dependent types; we can't do any checking on them now. if (VBaseTypeInfo->getType()->isDependentType()) continue; CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>( VBaseTypeInfo->getType()->getAs<RecordType>()->getDecl()); data().VBases[I] = CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, VBaseClassDecl->getTagKind() == TTK_Class, VBases[I]->getAccessSpecifier(), VBaseTypeInfo); } }
void CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases) { ASTContext &C = getASTContext(); // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] // no base classes [...]. data().Aggregate = false; if (data().Bases) C.Deallocate(data().Bases); int vbaseCount = 0; llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases; bool hasDirectVirtualBase = false; data().Bases = new(C) CXXBaseSpecifier [NumBases]; data().NumBases = NumBases; for (unsigned i = 0; i < NumBases; ++i) { data().Bases[i] = *Bases[i]; // Keep track of inherited vbases for this base class. const CXXBaseSpecifier *Base = Bases[i]; QualType BaseType = Base->getType(); // Skip dependent types; we can't do any checking on them now. if (BaseType->isDependentType()) continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); if (Base->isVirtual()) hasDirectVirtualBase = true; for (CXXRecordDecl::base_class_iterator VBase = BaseClassDecl->vbases_begin(), E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) { // Add this vbase to the array of vbases for current class if it is // not already in the list. // FIXME. Note that we do a linear search as number of such classes are // very few. int i; for (i = 0; i < vbaseCount; ++i) if (UniqueVbases[i]->getType() == VBase->getType()) break; if (i == vbaseCount) { UniqueVbases.push_back(VBase); ++vbaseCount; } } } if (hasDirectVirtualBase) { // Iterate one more time through the direct bases and add the virtual // base to the list of vritual bases for current class. for (unsigned i = 0; i < NumBases; ++i) { const CXXBaseSpecifier *VBase = Bases[i]; if (!VBase->isVirtual()) continue; int j; for (j = 0; j < vbaseCount; ++j) if (UniqueVbases[j]->getType() == VBase->getType()) break; if (j == vbaseCount) { UniqueVbases.push_back(VBase); ++vbaseCount; } } } if (vbaseCount > 0) { // build AST for inhireted, direct or indirect, virtual bases. data().VBases = new (C) CXXBaseSpecifier [vbaseCount]; data().NumVBases = vbaseCount; for (int i = 0; i < vbaseCount; i++) { QualType QT = UniqueVbases[i]->getType(); // Skip dependent types; we can't do any checking on them now. if (QT->isDependentType()) continue; CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl()); data().VBases[i] = CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, VBaseClassDecl->getTagKind() == RecordDecl::TK_class, UniqueVbases[i]->getAccessSpecifier(), QT); } } }
/// 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)); } } }
/* this helper function is called when the traversal reaches a node of type Decl */ bool DeclHelper(Decl *D){ const Stmt* parent = getStmtParent(D, Context); //const Stmt* parentsParent = getStmtParent(parent, Context); //if it is part of the (init; condition; increment) of a for loop, we don't care about it if(isFlowControl(D, Context)){ return false; } //supresses the catch stmt's arguments if(parent != NULL && strcmp(parent->getStmtClassName(), "CXXCatchStmt") == 0){ return true; } string filename; if(!isInCurFile(Context, D, filename) && filename.size() != 0){ return false; }else if(filename.size() == 0){ return true; } string output = ""; //get the name of the node type string node = D->getDeclKindName(); //calculate the current level, nextLevel, and previousLevel int intLevel = getLevelDecl(D);int intNextLevel = intLevel+1; int intNextNextLevel = intLevel+2; int intPrevLevel = intLevel-1; //create string values for the levels to use as output string level; string nextLevel; string nextNextLevel; string prevLevel; stringstream ss; stringstream ss2; stringstream ss3; stringstream ss4; ss << intLevel; level = ss.str(); ss2 << intNextLevel; nextLevel = ss2.str(); ss3 << intPrevLevel; prevLevel = ss3.str(); ss4 << intNextNextLevel; nextNextLevel = ss4.str(); if(callStackDebug && !callStack.empty()){ cerr << "decl: call stack top: " << callStack.top()->getStmtClassName() << endl; } //if top of stack is no longer a parent while(!callStack.empty() && numClosingArgsNeeded > 0 && !isParentDecl(D, callStack.top()->getStmtClassName())){ if(debugPrint){ cerr << "adding args" << endl; } numClosingArgsNeeded--; output += "</args,1>\n"; callStack.pop(); if(callStackDebug){ cerr << "poping" << endl; printCallStack(); } } //add new calls to stack if(isParentDeclInCurFile(D,"CXXConstructExpr") && isParentDecl(D, "CXXConstructExpr")){ if(debugPrint){ cerr << "setting previousConstructorCall to true" << endl; } }else if(isParentDeclInCurFile(D,"CXXTemporaryObjectExpr") && isParentDecl(D, "CXXTemporaryObjectExpr")){ if(debugPrint){ cerr << "setting previousTempConstructorCallArg" << endl; } }else if(isParentDecl(D, "CallExpr")){ if(debugPrint){ cerr << "setting previousCallArgs to true" << endl; } }else if(isParentDecl(D, "CXXMemberCallExpr")){ if(debugPrint){ cerr << "setting previousMemberCallArg to true" << endl; } } if(isParentDecl(getDeclParent(D, Context), "Var")){ previousRhsDecl = true; if(debugPrint){ cout << "setting prev var to true" << endl; } }else if(previousRhsDecl && numClosingVarsNeeded > 0){ //if the current node is not a child of a variable declaration //but the previous node was a child of a variable declation //then we know to print a </decl> output +="</variableDecl,1>\n"; numClosingVarsNeeded--; previousRhsDecl = false; } if(node == "Var"){ output += "<variableDecl, " + prevLevel + ">"; numClosingVarsNeeded++; VarDecl* VD = (VarDecl*) D; if(!VD->hasInit()){ output +="\n</variableDecl,1>\n"; numClosingVarsNeeded--; } }else if(node == "Function"){ FunctionDecl* FD = (FunctionDecl*) D; output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: " + FD->getNameInfo().getAsString() + "," + nextLevel + ">"; }else if(node == "CXXRecord"){ const Decl* parent = getDeclParent(D, Context); if(parent && strcmp(parent->getDeclKindName(), "CXXRecord") != 0){ CXXRecordDecl* CD = (CXXRecordDecl*) D; output += "<classDef," + level + ">"; output += "\n<name: " + CD->getNameAsString() + "," + nextLevel + ">"; output += "\n<bases," + nextLevel + ">"; //iterate over all bases and add them to the output CXXRecordDecl::base_class_iterator basesItr = CD->bases_begin(); while(basesItr != CD->bases_end()){ QualType qt = basesItr->getType(); output += "\n<base: " + qt.getBaseTypeIdentifier()->getName().str(); output += "," + nextNextLevel + ">"; basesItr++; } //iterate over all of the virtual bases and add them to the output auto vBasesItr = CD->vbases_begin(); while(vBasesItr != CD->vbases_end()){ QualType qt = vBasesItr->getType(); output += "\n<base: " + qt.getBaseTypeIdentifier()->getName().str(); output += "," + nextNextLevel + ">"; vBasesItr++; } } }else if(node == "CXXDestructor"){ CXXDestructorDecl* CD = (CXXDestructorDecl*) D; if(!CD->isImplicit()){ output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: ~" + CD->getNameInfo().getAsString() + "," + nextLevel + ">"; } }else if(node == "CXXConstructor"){ CXXConstructorDecl* CD = (CXXConstructorDecl*) D; if(!CD->isImplicit()){ output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: " + CD->getNameInfo().getAsString() + "," + nextLevel + ">"; } }else if(node == "CXXMethod"){ CXXMethodDecl* CM = (CXXMethodDecl*) D; if(!CM->isImplicit()){ output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: " + CM->getNameInfo().getAsString() + "," + nextLevel + ">"; } }else{ if(debugPrint){ output += "<"; output += node; output += ">"; } } if(output.size() != 0){ cout << output << endl; } return true; }