/****************************************************************************** * * $Id$ * * Copyright (C) 1997-2000 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * * All output generated with Doxygen is not covered by this license. * */ #include #include #include #include "classdef.h" #include "classlist.h" #include "entry.h" #include "scanner.h" #include "doxygen.h" #include "membername.h" #include "message.h" #include "config.h" #include "util.h" #include "diagram.h" #include "language.h" #include "htmlhelp.h" #include "example.h" #include "outputlist.h" #include "dot.h" static QCString stripExtension(const char *fName) { QCString result=fName; if (result.right(5)==".html") result=result.left(result.length()-5); return result; } // constructs a new class definition ClassDef::ClassDef(const char *nm,CompoundType ct,const char *ref,const char *fName) : Definition(removeRedundantWhiteSpace(nm)) { //name=n; if (fName) fileName=stripExtension(fName); else fileName="class_"+nameToFile(nm); if (ref) { //url=(QCString)"doxygen=\""+ref+":\" href=\""+fileName; exampleList = 0; exampleDict = 0; } else { //url="href=\""+fileName; exampleList = new ExampleList; exampleDict = new ExampleDict(29); } memListFileName="class_"+nameToFile(nm)+"-members"; inherits = new BaseClassList; inherits->setAutoDelete(TRUE); inheritedBy = new BaseClassList; inheritedBy->setAutoDelete(TRUE); allMemberNameInfoList = new MemberNameInfoList; allMemberNameInfoList->setAutoDelete(TRUE); allMemberNameInfoDict = new MemberNameInfoDict(1009); visited=FALSE; setReference(ref); compType=ct; incInfo=0; tempArgs=0; prot=Public; nspace=0; fileDef=0; usesImplClassDict=0; usesIntfClassDict=0; //printf("*** New class `%s' *** \n",nm); } // destroy the class definition ClassDef::~ClassDef() { delete inherits; delete inheritedBy; delete allMemberNameInfoList; delete allMemberNameInfoDict; delete exampleList; delete exampleDict; delete usesImplClassDict; delete usesIntfClassDict; delete incInfo; } // inserts a base class in the inheritance list void ClassDef::insertBaseClass(ClassDef *cd,Protection p, Specifier s,const char *t) { //printf("*** insert base class %s into %s\n",cd->name().data(),name().data()); inherits->inSort(new BaseClassDef(cd,p,s,t)); } // inserts a super class in the inherited list void ClassDef::insertSuperClass(ClassDef *cd,Protection p, Specifier s,const char *t) { //printf("*** insert super class %s into %s\n",cd->name().data(),name().data()); inheritedBy->inSort(new BaseClassDef(cd,p,s,t)); } // adds new member definition to the class void ClassDef::insertMember(const MemberDef *md) { //printf("adding %s::%s\n",name(),md->name()); if (!isReference()) { if (md->isRelated() && (Config::extractPrivateFlag || md->protection()!=Private)) { related.append(md); if (Config::sortMembersFlag) relatedMembers.inSort(md); else relatedMembers.append(md); } else if (md->isFriend()) { friends.append(md); if (Config::sortMembersFlag) relatedMembers.inSort(md); else relatedMembers.append(md); } else { switch (md->memberType()) { case MemberDef::Signal: signals.append(md); if (Config::sortMembersFlag) functionMembers.inSort(md); else functionMembers.append(md); break; case MemberDef::Slot: switch (md->protection()) { case Protected: proSlots.append(md); if (Config::sortMembersFlag) functionMembers.inSort(md); else functionMembers.append(md); break; case Public: pubSlots.append(md); if (Config::sortMembersFlag) functionMembers.inSort(md); else functionMembers.append(md); break; case Private: priSlots.append(md); if (Config::sortMembersFlag) functionMembers.inSort(md); else functionMembers.append(md); break; } break; default: // any of the other members if (md->isStatic()) { if (md->isVariable()) { switch (md->protection()) { case Protected: proStaticAttribs.append(md); break; case Public: pubStaticAttribs.append(md); break; case Private: priStaticAttribs.append(md); break; } } else // function { switch (md->protection()) { case Protected: proStaticMembers.append(md); break; case Public: pubStaticMembers.append(md); break; case Private: priStaticMembers.append(md); break; } } } else // not static { if (md->isVariable()) { switch (md->protection()) { case Protected: proAttribs.append(md); break; case Public: pubAttribs.append(md); break; case Private: priAttribs.append(md); break; } } else if (md->isTypedef() || md->isEnumerate()) { switch (md->protection()) { case Protected: proTypes.append(md); break; case Public: pubTypes.append(md); break; case Private: priTypes.append(md); break; } } else // member function { switch (md->protection()) { case Protected: proMembers.append(md); break; case Public: pubMembers.append(md); break; case Private: priMembers.append(md); break; } } } if (md->protection()!=Private || Config::extractPrivateFlag) { switch (md->memberType()) { case MemberDef::Typedef: if (Config::sortMembersFlag) typedefMembers.inSort(md); else typedefMembers.append(md); break; case MemberDef::Enumeration: if (Config::sortMembersFlag) enumMembers.inSort(md); else enumMembers.append(md); break; case MemberDef::EnumValue: if (Config::sortMembersFlag) enumValMembers.inSort(md); else enumValMembers.append(md); break; case MemberDef::Function: if (md->name()==name() || // constructor (md->name().find('~')!=-1 && // hack to detect destructor md->name().find("operator")==-1 ) ) constructors.append(md); else { if (Config::sortMembersFlag) functionMembers.inSort(md); else functionMembers.append(md); } break; case MemberDef::Variable: if (Config::sortMembersFlag) variableMembers.inSort(md); else variableMembers.append(md); break; default: printf("Unexpected member type %d found!\n",md->memberType()); } } break; } } } // check if we should add this member in the `all members' list if (1 /*md->isFriend() || md->protection()!=Private || Config::extractPrivateFlag*/) { MemberInfo *mi = new MemberInfo((MemberDef *)md,Public,Normal); MemberNameInfo *mni=0; if ((mni=(*allMemberNameInfoDict)[md->name()])) { mni->append(mi); } else { mni = new MemberNameInfo(md->name()); mni->append(mi); allMemberNameInfoList->inSort(mni); allMemberNameInfoDict->insert(mni->memberName(),mni); } } } // compute the anchors for all members void ClassDef::computeAnchors() { setAnchors('a',&pubMembers); setAnchors('b',&proMembers); setAnchors('c',&priMembers); setAnchors('d',&pubStaticMembers); setAnchors('e',&proStaticMembers); setAnchors('f',&priStaticMembers); setAnchors('g',&pubSlots); setAnchors('h',&proSlots); setAnchors('i',&priSlots); setAnchors('j',&signals); setAnchors('k',&related); setAnchors('l',&friends); setAnchors('m',&pubAttribs); setAnchors('n',&proAttribs); setAnchors('o',&priAttribs); setAnchors('p',&pubStaticAttribs); setAnchors('q',&proStaticAttribs); setAnchors('r',&priStaticAttribs); setAnchors('s',&pubTypes); setAnchors('t',&proTypes); setAnchors('u',&priTypes); } // add a file name to the used files set void ClassDef::insertUsedFile(const char *f) { if (files.find(f)==-1) files.append(f); } static void writeInheritanceSpecifier(OutputList &ol,BaseClassDef *bcd) { if (bcd->prot!=Public || bcd->virt!=Normal) { ol.startTypewriter(); ol.docify(" ["); QStrList sl; if (bcd->prot==Protected) sl.append("protected"); else if (bcd->prot==Private) sl.append("private"); if (bcd->virt==Virtual) sl.append("virtual"); const char *s=sl.first(); while (s) { ol.docify(s); s=sl.next(); if (s) ol.docify(", "); } ol.docify("]"); ol.endTypewriter(); } } void ClassDef::setIncludeFile(FileDef *fd,const char *incName,bool local) { //printf("ClassDef::setInclude(%p,%s,%d)\n",fd,incName,local); if (!incInfo) incInfo=new IncludeInfo; if ((incName && incInfo->includeName.isEmpty()) || (fd!=0 && incInfo->fileDef==0) ) { //printf("Setting file info\n"); incInfo->fileDef = fd; incInfo->includeName = incName; incInfo->local = local; } } // write all documentation for this class void ClassDef::writeDocumentation(OutputList &ol) { // write title QCString pageTitle=name().copy(); QCString pageType; switch(compType) { case Class: pageType=" Class"; break; case Struct: pageType=" Struct"; break; case Union: pageType=" Union"; break; default: pageType=" Interface"; break; } pageTitle+=pageType+" Reference"; startFile(ol,fileName,pageTitle); startTitle(ol,getOutputFileBase()); //ol.docify(name()+" "+pageType.right(pageType.length()-1)+" "); //parseText(ol,theTranslator->trReference()); parseText(ol,theTranslator->trCompoundReference(name(),compType)); endTitle(ol,getOutputFileBase(),name()); ol.startTextBlock(); // write brief description OutputList briefOutput(&ol); if (!briefDescription().isEmpty()) { parseDoc(briefOutput,name(),0,briefDescription()); ol+=briefOutput; ol.writeString(" \n"); ol.pushGeneratorState(); ol.disableAllBut(OutputGenerator::Html); ol.startTextLink(0,"_details"); parseText(ol,theTranslator->trMore()); ol.endTextLink(); ol.popGeneratorState(); ol.disable(OutputGenerator::Man); ol.newParagraph(); ol.enable(OutputGenerator::Man); } ol.writeSynopsis(); if (incInfo) { QCString nm=incInfo->includeName.isEmpty() ? (incInfo->fileDef ? incInfo->fileDef->docName().data() : "" ) : incInfo->includeName.data(); if (!nm.isEmpty()) { ol.startTypewriter(); ol.docify("#include "); if (incInfo->local) ol.docify("\""); else ol.docify("<"); ol.pushGeneratorState(); ol.disable(OutputGenerator::Html); ol.docify(nm); ol.disableAllBut(OutputGenerator::Html); ol.enable(OutputGenerator::Html); if (incInfo->fileDef) { ol.writeObjectLink(0,incInfo->fileDef->includeName(),0,nm); } else { ol.docify(nm); } ol.popGeneratorState(); if (incInfo->local) ol.docify("\""); else ol.docify(">"); ol.endTypewriter(); ol.newParagraph(); } } if (!Config::genTagFile.isEmpty()) tagFile << ">" << name() << ":"; if (Config::classDiagramFlag) ol.disableAllBut(OutputGenerator::Man); // write superclasses int count; if ((count=inherits->count())>0) { //parseText(ol,theTranslator->trInherits()+" "); QCString inheritLine = theTranslator->trInheritsList(inherits->count()); QRegExp marker("@[0-9]+"); int index=0,newIndex,matchLen; // now replace all markers in inheritLine with links to the classes while ((newIndex=marker.match(inheritLine,index,&matchLen))!=-1) { parseText(ol,inheritLine.mid(index,newIndex-index)); bool ok; uint entryIndex = inheritLine.mid(newIndex+1,matchLen-1).toUInt(&ok); BaseClassDef *bcd=inherits->at(entryIndex); if (ok && bcd) { ClassDef *cd=bcd->classDef; if (cd->isLinkable()) { if (!Config::genTagFile.isEmpty()) tagFile << cd->getOutputFileBase() << "?"; ol.writeObjectLink(cd->getReference(),cd->getOutputFileBase(),0,cd->name()+bcd->templSpecifiers); } else { ol.docify(cd->name()); } } else { err("Error: invalid marker %d in inherits list!\n",entryIndex); } index=newIndex+matchLen; } parseText(ol,inheritLine.right(inheritLine.length()-index)); ol.newParagraph(); } if (!Config::genTagFile.isEmpty()) tagFile << " \"" << fileName << ".html\"\n"; // write subclasses if ((count=inheritedBy->count())>0) { QCString inheritLine = theTranslator->trInheritedByList(inheritedBy->count()); QRegExp marker("@[0-9]+"); int index=0,newIndex,matchLen; // now replace all markers in inheritLine with links to the classes while ((newIndex=marker.match(inheritLine,index,&matchLen))!=-1) { parseText(ol,inheritLine.mid(index,newIndex-index)); bool ok; uint entryIndex = inheritLine.mid(newIndex+1,matchLen-1).toUInt(&ok); BaseClassDef *bcd=inheritedBy->at(entryIndex); if (ok && bcd) { ClassDef *cd=bcd->classDef; if (cd->isLinkable()) { ol.writeObjectLink(cd->getReference(),cd->getOutputFileBase(),0,cd->name()); } else { ol.docify(cd->name()); } writeInheritanceSpecifier(ol,bcd); } index=newIndex+matchLen; } parseText(ol,inheritLine.right(inheritLine.length()-index)); ol.newParagraph(); } if (Config::classDiagramFlag) ol.enableAll(); count=0; BaseClassDef *ibcd; ibcd=inheritedBy->first(); while (ibcd) { ClassDef *icd=ibcd->classDef; if ( icd->isVisibleInHierarchy()) count++; ibcd=inheritedBy->next(); } ibcd=inherits->first(); while (ibcd) { ClassDef *icd=ibcd->classDef; if ( icd->isVisibleInHierarchy()) count++; ibcd=inherits->next(); } if (Config::classDiagramFlag && count>0) // write class diagram { ClassDiagram diagram(this); // create a diagram of this class. ol.startClassDiagram(); ol.disable(OutputGenerator::Man); parseText(ol,theTranslator->trClassDiagram(name())); ol.enable(OutputGenerator::Man); ol.endClassDiagram(diagram,fileName,name()); } if (Config::haveDotFlag && Config::collGraphFlag) { DotGfxUsageGraph usageImplGraph(this,TRUE); if (!usageImplGraph.isTrivial()) { ol.disable(OutputGenerator::Latex); ol.disable(OutputGenerator::Man); ol.startCollaborationDiagram(); parseText(ol,theTranslator->trCollaborationDiagram(name())); //usageImplGraph.writeGraph(Config::htmlOutputDir); //ol.writeString((QCString)"

Interface collaboration diagram for " // "here"); //ol.writeString((QCString)"

Implementation collaboration diagram for " // "here"); ol.endCollaborationDiagram(usageImplGraph); ol.enableAll(); } } // write link to list of all members (HTML only) if (allMemberNameInfoList->count()>0 /*&& compType==Class*/) { ol.disableAllBut(OutputGenerator::Html); ol.startTextLink(memListFileName,0); parseText(ol,theTranslator->trListOfAllMembers()); ol.endTextLink(); ol.enableAll(); } ol.endTextBlock(); // write member groups ol.startMemberSections(); // non static public members pubTypes.writeDeclarations(ol,this,0,0,0,theTranslator->trPublicTypes(),0); pubMembers.writeDeclarations(ol,this,0,0,0,theTranslator->trPublicMembers(),0); pubAttribs.writeDeclarations(ol,this,0,0,0,theTranslator->trPublicAttribs(),0); pubSlots.writeDeclarations(ol,this,0,0,0,theTranslator->trPublicSlots(),0); signals.writeDeclarations(ol,this,0,0,0,theTranslator->trSignals(),0); // static public members pubStaticMembers.writeDeclarations(ol,this,0,0,0,theTranslator->trStaticPublicMembers(),0); pubStaticAttribs.writeDeclarations(ol,this,0,0,0,theTranslator->trStaticPublicAttribs(),0); // protected non-static members proTypes.writeDeclarations(ol,this,0,0,0,theTranslator->trProtectedTypes(),0); proMembers.writeDeclarations(ol,this,0,0,0,theTranslator->trProtectedMembers(),0); proAttribs.writeDeclarations(ol,this,0,0,0,theTranslator->trProtectedAttribs(),0); proSlots.writeDeclarations(ol,this,0,0,0,theTranslator->trProtectedSlots(),0); // protected static members proStaticMembers.writeDeclarations(ol,this,0,0,0,theTranslator->trStaticProtectedMembers(),0); proStaticAttribs.writeDeclarations(ol,this,0,0,0,theTranslator->trStaticProtectedAttribs(),0); if (Config::extractPrivateFlag) { // private non-static members priTypes.writeDeclarations(ol,this,0,0,0,theTranslator->trPrivateTypes(),0); priMembers.writeDeclarations(ol,this,0,0,0,theTranslator->trPrivateMembers(),0); priAttribs.writeDeclarations(ol,this,0,0,0,theTranslator->trPrivateAttribs(),0); priSlots.writeDeclarations(ol,this,0,0,0,theTranslator->trPrivateSlots(),0); // private static members priStaticMembers.writeDeclarations(ol,this,0,0,0,theTranslator->trStaticPrivateMembers(),0); priStaticAttribs.writeDeclarations(ol,this,0,0,0,theTranslator->trStaticPrivateAttribs(),0); } friends.writeDeclarations(ol,this,0,0,0,theTranslator->trFriends(),0); related.writeDeclarations(ol,this,0,0,0, theTranslator->trRelatedFunctions(), theTranslator->trRelatedSubscript() ); ol.endMemberSections(); // write detailed description bool exampleFlag=hasExamples(); if (!briefDescription().isEmpty() || !documentation().isEmpty() || (startBodyLine!=-1 && bodyDef) || exampleFlag) { ol.writeRuler(); ol.pushGeneratorState(); ol.disable(OutputGenerator::Latex); ol.disable(OutputGenerator::RTF); ol.writeAnchor("_details"); ol.popGeneratorState(); ol.startGroupHeader(); parseText(ol,theTranslator->trDetailedDescription()); ol.endGroupHeader(); ol.startTextBlock(); ArgumentList *al=0; int ti; ClassDef *pcd=0; int pi=0; // find the outer most class scope while ((ti=name().find("::",pi))!=-1 && (pcd=getClass(name().left(ti)))==0 ) pi=ti+2; if (pcd) { al=pcd->templateArguments(); } else { al=tempArgs; } if (al) // class is a template { ol.startSubsubsection(); ol.docify("template<"); Argument *a=al->first(); while (a) { ol.docify(a->type); ol.docify(a->name); if (a->defval.length()!=0) { ol.docify(" = "); ol.docify(a->defval); } a=al->next(); if (a) ol.docify(", "); } ol.docify("> "+pageType.lower()+" "+name()); ol.endSubsubsection(); ol.writeString("\n"); } // repeat brief description if (!briefDescription().isEmpty()) { ol+=briefOutput; ol.newParagraph(); } // write documentation if (!documentation().isEmpty()) { ol.pushGeneratorState(); ol.disableAllBut(OutputGenerator::RTF); ol.newParagraph(); ol.popGeneratorState(); parseDoc(ol,name(),0,documentation()+"\n"); } // write examples if (exampleFlag) { ol.startDescList(); ol.startBold(); parseText(ol,theTranslator->trExamples()+": "); ol.endBold(); ol.endDescTitle(); ol.writeDescItem(); ol.newParagraph(); writeExample(ol,exampleList); //ol.endDescItem(); ol.endDescList(); } ol.newParagraph(); writeSourceRef(ol,name()); ol.endTextBlock(); } typedefMembers.countDocMembers(); if (typedefMembers.totalCount()>0) { ol.writeRuler(); ol.startGroupHeader(); parseText(ol,theTranslator->trMemberTypedefDocumentation()); ol.endGroupHeader(); typedefMembers.writeDocumentation(ol,name()); } enumMembers.countDocMembers(); if (enumMembers.totalCount()>0) { ol.writeRuler(); ol.startGroupHeader(); parseText(ol,theTranslator->trMemberEnumerationDocumentation()); ol.endGroupHeader(); enumMembers.writeDocumentation(ol,name()); } enumValMembers.countDocMembers(); if (enumValMembers.totalCount()>0) { ol.writeRuler(); ol.startGroupHeader(); parseText(ol,theTranslator->trEnumerationValueDocumentation()); ol.endGroupHeader(); enumValMembers.writeDocumentation(ol,name()); } constructors.countDocMembers(); if (constructors.totalCount()>0) { ol.writeRuler(); ol.startGroupHeader(); parseText(ol,theTranslator->trConstructorDocumentation()); ol.endGroupHeader(); constructors.writeDocumentation(ol,name()); } functionMembers.countDocMembers(); if (functionMembers.totalCount()>0) { ol.writeRuler(); ol.startGroupHeader(); parseText(ol,theTranslator->trMemberFunctionDocumentation()); ol.endGroupHeader(); functionMembers.writeDocumentation(ol,name()); } relatedMembers.countDocMembers(); if (relatedMembers.totalCount()>0) { ol.writeRuler(); ol.startGroupHeader(); parseText(ol,theTranslator->trRelatedFunctionDocumentation()); ol.endGroupHeader(); relatedMembers.writeDocumentation(ol,name()); } variableMembers.countDocMembers(); if (variableMembers.totalCount()>0) { ol.writeRuler(); ol.startGroupHeader(); parseText(ol,theTranslator->trMemberDataDocumentation()); ol.endGroupHeader(); variableMembers.writeDocumentation(ol,name()); } ol.startTextBlock(); // write the list of used files (not for man pages) ol.pushGeneratorState(); ol.disable(OutputGenerator::Man); ol.writeRuler(); parseText(ol,theTranslator->trGeneratedFromFiles(compType,files.count()==1)); bool first=TRUE; const char *file = files.first(); while (file) { bool ambig; FileDef *fd=findFileDef(&inputNameDict,file,ambig); if (fd) { if (first) { first=FALSE; ol.startItemList(); } ol.writeListItem(); QCString path=fd->getPath().copy(); if (Config::fullPathNameFlag) { ol.docify(stripFromPath(path)); } if (fd->isLinkable()) { ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0, fd->name()); } else { ol.docify(fd->name()); } } file=files.next(); } if (!first) ol.endItemList(); // write Author section (Man only) ol.enable(OutputGenerator::Man); ol.disableAllBut(OutputGenerator::Man); ol.writeString("\n"); ol.startGroupHeader(); parseText(ol,theTranslator->trAuthor()); ol.endGroupHeader(); parseText(ol,theTranslator->trGeneratedAutomatically(Config::projectName)); ol.popGeneratorState(); ol.endTextBlock(); endFile(ol); } // write the list of all (inherited) members for this class void ClassDef::writeMemberList(OutputList &ol) { if (allMemberNameInfoList->count()==0) return; // only for HTML ol.pushGeneratorState(); ol.disableAllBut(OutputGenerator::Html); startFile(ol,memListFileName,theTranslator->trMemberList()); startTitle(ol,0); parseText(ol,name()+" "+theTranslator->trMemberList()); endTitle(ol,0,0); parseText(ol,theTranslator->trThisIsTheListOfAllMembers()); ol.writeObjectLink(getReference(),fileName,0,name()); parseText(ol,theTranslator->trIncludingInheritedMembers()); ol.startItemList(); MemberNameInfo *mni=allMemberNameInfoList->first(); while (mni) { MemberInfo *mi=mni->first(); while (mi) { MemberDef *md=mi->memberDef; ClassDef *cd=md->memberClass(); // compute the protection level for this member Protection protect=md->protection(); if (mi->prot==Protected) // inherited protection { if (protect==Public) protect=Protected; else if (protect==Protected) protect=Private; } //printf("Member %s of class %s mi->prot=%d prot=%d\n", // md->name().data(),cd->name().data(),mi->prot,protect); Specifier virt=md->virtualness(); MemberDef *rmd=md->reimplements(); while (rmd && virt==Normal) { virt = rmd->virtualness()==Normal ? Normal : Virtual; rmd = rmd->reimplements(); } if (cd && !md->name().isEmpty() && md->name()[0]!='@' && ( md->isFriend() || (mi->prot!=Private && (protect!=Private || Config::extractPrivateFlag)) ) ) { bool memberWritten=FALSE; if (cd->isLinkable() && md->isLinkable()) // create a link to the documentation { QCString name=mi->ambiguityResolutionScope+md->name(); ol.writeListItem(); ol.writeObjectLink(cd->getReference(),cd->getOutputFileBase(), md->anchor(),name); if ( md->isFunction() || md->isSignal() || md->isSlot() || (md->isFriend() && md->argsString())) ol.docify(md->argsString()); else if (md->isEnumerate()) parseText(ol," "+theTranslator->trEnumName()); else if (md->isEnumValue()) parseText(ol," "+theTranslator->trEnumValue()); else if (md->isTypedef()) ol.docify(" typedef"); else if (md->isFriend() && !strcmp(md->typeString(),"friend class")) ol.docify(" class"); ol.writeString("\n"); memberWritten=TRUE; } else if (!Config::hideMemberFlag) // no documentation, // generate link to the class instead. { ol.writeListItem(); ol.writeBoldString(md->name()); if ( md->isFunction() || md->isSignal() || md->isSlot() ) ol.docify(md->argsString()); else if (md->isEnumerate()) parseText(ol," "+theTranslator->trEnumName()); else if (md->isEnumValue()) parseText(ol," "+theTranslator->trEnumValue()); else if (md->isTypedef()) ol.docify(" typedef"); ol.writeString(" ("); parseText(ol,theTranslator->trDefinedIn()+" "); if (cd->isLinkable()) { ol.writeObjectLink(cd->getReference(),cd->getOutputFileBase(),0,cd->name()); } else { ol.writeBoldString(cd->name()); } ol.writeString(")"); memberWritten=TRUE; } if ((protect!=Public || md->isStatic() || virt!=Normal || md->isFriend() || md->isRelated() || (md->isInline() && Config::inlineInfoFlag) ) && memberWritten) { ol.startTypewriter(); ol.docify(" ["); QStrList sl; if (md->isFriend()) sl.append("friend"); else if (md->isRelated()) sl.append("related"); else { if (Config::inlineInfoFlag && md->isInline()) sl.append("inline"); if (protect==Protected) sl.append("protected"); else if (protect==Private) sl.append("private"); if (virt==Virtual) sl.append("virtual"); else if (virt==Pure) sl.append("pure virtual"); if (md->isStatic()) sl.append("static"); if (md->isSignal()) sl.append("signal"); if (md->isSlot()) sl.append("slot"); } const char *s=sl.first(); while (s) { ol.docify(s); s=sl.next(); if (s) ol.docify(", "); } ol.docify("]"); ol.endTypewriter(); } } mi=mni->next(); } mni=allMemberNameInfoList->next(); } ol.endItemList(); endFile(ol); ol.popGeneratorState(); } //void ClassDef::writeIncludeFile(OutputList &ol) //{ // initParseCodeContext(); // if (!incFile) return; // //printf("incFile=%s\n",incFile->absFilePath().data()); // ol.disableAllBut(OutputGenerator::Html); // startFile(ol,fileName+"-include",name()+" Include File"); // startTitle(ol,0); // QCString n=incName.copy(); // if (incName.isEmpty()) // { // n=incFile->name(); // if (Config::fullPathNameFlag) // { // n.prepend(stripFromPath(incFile->getPath().copy())); // } // } // parseText(ol,n); // endTitle(ol,0,0); // parseText(ol,theTranslator->trVerbatimText(incFile->name())); // //ol.writeRuler(); // ol.startCodeFragment(); // parseCode(ol,n,fileToString(incFile->absFilePath()),FALSE,0); // ol.endCodeFragment(); // endFile(ol); // ol.enableAll(); //} // add a reference to an example bool ClassDef::addExample(const char *anchor,const char *nameStr, const char *file) { if (exampleDict && !exampleDict->find(nameStr)) { Example *e=new Example; e->anchor=anchor; e->name=nameStr; e->file=file; exampleDict->insert(nameStr,e); exampleList->inSort(e); return TRUE; } return FALSE; } // returns TRUE if this class is used in an example bool ClassDef::hasExamples() { if (exampleList==0) return FALSE; else return exampleList->count()>0; } #if 0 // write the list of all examples that are used in this class. void ClassDef::writeExample(OutputList &ol) { QCString exampleLine=theTranslator->trWriteList(exampleList->count()); QRegExp marker("@[0-9]+"); int index=0,newIndex,matchLen; // now replace all markers in inheritLine with links to the classes while ((newIndex=marker.match(exampleLine,index,&matchLen))!=-1) { bool ok; parseText(ol,exampleLine.mid(index,newIndex-index)); uint entryIndex = exampleLine.mid(newIndex+1,matchLen-1).toUInt(&ok); Example *e=exampleList->at(entryIndex); if (ok && e) { ol.writeObjectLink(0,e->file,e->anchor,e->name); } index=newIndex+matchLen; } parseText(ol,exampleLine.right(exampleLine.length()-index)); ol.writeString("."); #if 0 Example *e=exampleList->first(); while (e) { ol.writeObjectLink(0,e->file,e->anchor,e->name); e=exampleList->next(); if (e) { if (exampleList->at()==(int)exampleList->count()-1) parseText(ol," "+theTranslator->trAnd()+" "); else ol.writeString(", "); } } ol.writeString("."); #endif } #endif void ClassDef::setTemplateArguments(ArgumentList *al) { if (al==0) return; if (!tempArgs) delete tempArgs; // delete old list if needed tempArgs=new ArgumentList; tempArgs->setAutoDelete(TRUE); ArgumentListIterator ali(*al); Argument *a; for (;(a=ali.current());++ali) { tempArgs->append(new Argument(*a)); } } //QCString ClassDef::getTemplateNameString() //{ // QCString result; // if (!tempArgs || tempArgs->count()==0) return result; // result="<"; // Argument *a=tempArgs->first(); // while (a) // { // if (!a->name.isEmpty()) // add template argument name // { // result+=a->name; // } // else // extract name from type // { // int i=a->type.length()-1; // while (i>=0 && isId(a->type.at(i))) i--; // if (i>0) // { // result+=a->type.right(a->type.length()-i-1); // } // } // a=tempArgs->next(); // if (a) result+=", "; // } // result+=">"; // return result; //} bool ClassDef::hasNonReferenceSuperClass() { bool found=!isReference(); BaseClassListIterator bcli(*inheritedBy); for ( ; bcli.current() && !found ; ++bcli ) found=found || bcli.current()->classDef->hasNonReferenceSuperClass(); return found; } //void ClassDef::writeMembersToContents() //{ // HtmlHelp *htmlHelp = HtmlHelp::getInstance(); // // htmlHelp->incContentsDepth(); // // MemberNameInfoListIterator mnili(*allMemberNameInfoList); // MemberNameInfo *mni; // for (;(mni=mnili.current());++mnili) // { // MemberNameInfoIterator mnii(*mni); // MemberInfo *mi; // for (mnii.toLast();(mi=mnii.current());--mnii) // { // MemberDef *md=mi->memberDef; // ClassDef *cd=md->memberClass(); // if (md->isLinkable() && cd==this) // member is not inherited // { // htmlHelp->addContentsItem(md->name()+md->argsString(), // cd->getOutputFileBase(), // md->anchor()); // } // } // } // htmlHelp->decContentsDepth(); //} void ClassDef::writeDeclaration(OutputList &ol,MemberDef *md) { //ol.insertMemberAlign(); //printf("ClassName=`%s'\n",name().data()); switch(compType) { case Class: ol.docify("class"); break; case Struct: ol.docify("struct"); break; default: ol.docify("union"); break; } int ri=name().findRev("::"); if (ri==-1) ri=name().length(); QCString cn=name().right(name().length()-ri-2); if (!cn.isEmpty() && cn.at(0)!='@' && md) { ol.docify(" "); ol.writeObjectLink(0,0,md->anchor(),cn); } ol.docify(" {"); ol.endMemberItem(FALSE,0,0,FALSE); // TODO: pass correct group parameters // insert members of this class pubMembers.writePlainDeclarations(ol,this,0,0,0); pubSlots.writePlainDeclarations(ol,this,0,0,0); signals.writePlainDeclarations(ol,this,0,0,0); pubStaticMembers.writePlainDeclarations(ol,this,0,0,0); proMembers.writePlainDeclarations(ol,this,0,0,0); proSlots.writePlainDeclarations(ol,this,0,0,0); proStaticMembers.writePlainDeclarations(ol,this,0,0,0); if (Config::extractPrivateFlag) { priMembers.writePlainDeclarations(ol,this,0,0,0); priSlots.writePlainDeclarations(ol,this,0,0,0); priStaticMembers.writePlainDeclarations(ol,this,0,0,0); } friends.writePlainDeclarations(ol,this,0,0,0); related.writePlainDeclarations(ol,this,0,0,0); } /*! a link to this class is possible within this project */ bool ClassDef::isLinkableInProject() { return !name().isEmpty() && name().find('@')==-1 && (prot!=Private || Config::extractPrivateFlag) && hasDocumentation() && !isReference(); } /*! the class is visible in a class diagram, or class hierarchy */ bool ClassDef::isVisibleInHierarchy() { return // show all classes or a superclass is visible (Config::allExtFlag || hasNonReferenceSuperClass()) && // and not an annonymous compound name().find('@')==-1 && // and not privately inherited (prot!=Private || Config::extractPrivateFlag) && // documented or show anyway or documentation is external (hasDocumentation() || !Config::hideClassFlag || isReference()); } //---------------------------------------------------------------------- // recursive function: // returns TRUE iff class definition `bcd' represents an (in)direct base // class of class definition `cd'. bool ClassDef::isBaseClass(ClassDef *bcd) { bool found=FALSE; //printf("isBaseClass(cd=%s) looking for %s\n",cd->name().data(),bcd->name().data()); BaseClassListIterator bcli(*baseClasses()); for ( ; bcli.current() && !found ; ++bcli) { ClassDef *ccd=bcli.current()->classDef; //printf("isBaseClass() baseclass %s\n",ccd->name().data()); if (ccd==bcd) found=TRUE; else found=ccd->isBaseClass(bcd); } return found; } //---------------------------------------------------------------------------- /*! * recusively merges the `all members' lists of a class base * with that of this class. Must only be called for classes without * superclasses! */ void ClassDef::mergeMembers(/*ClassDef *cd,BaseClassList *bcl*/) { BaseClassListIterator bcli(*baseClasses()); BaseClassDef *bcd; for ( ; (bcd=bcli.current()) ; ++bcli ) { ClassDef *bClass=bcd->classDef; // merge the members of bClass with the onces from cd bClass->mergeMembers(); // the all member list of the branch until bClass is now complete // so we can merge it with cd MemberNameInfoList *srcMnl = bClass->memberNameInfoList(); MemberNameInfoDict *dstMnd = memberNameInfoDict(); MemberNameInfoList *dstMnl = memberNameInfoList(); MemberNameInfoListIterator srcMnili(*srcMnl); MemberNameInfo *srcMni; for ( ; (srcMni=srcMnili.current()) ; ++srcMnili) { //printf("Base member name %s\n",srcMni->memberName()); MemberNameInfo *dstMni; if ((dstMni=dstMnd->find(srcMni->memberName()))) // a member with that name is already in the class. // the member may hide or reimplement the one in the super class // or there may be another path to the base class that is already // visited via another branch in the class hierarchy. { MemberNameInfoIterator srcMnii(*srcMni); MemberInfo *srcMi; for ( ; (srcMi=srcMnii.current()) ; ++srcMnii ) { MemberDef *srcMd = srcMi->memberDef; bool found=FALSE; bool ambigue=FALSE; bool hidden=FALSE; MemberNameInfoIterator dstMnii(*dstMni); MemberInfo *dstMi; ClassDef *srcCd = srcMd->memberClass(); for ( ; (dstMi=dstMnii.current()) && !found; ++dstMnii ) { MemberDef *dstMd = dstMi->memberDef; if (srcMd!=dstMd) // different members { ClassDef *dstCd = dstMd->memberClass(); //printf("Is %s a base class of %s?\n",srcCd->name(),dstCd->name()); if (srcCd==dstCd || dstCd->isBaseClass(srcCd)) // member is in the same or a base class { found=matchArguments(srcMd->argumentList(), dstMd->argumentList() ); //ambigue = ambigue || !found; hidden = hidden || !found; } else // member is in a non base class => multiple inheritance // using the same base class. { //printf("$$ Existing member %s %s add scope %s\n", // dstMi->ambiguityResolutionScope.data(), // dstMd->name().data(), // dstMi->scopePath.left(dstMi->scopePath.find("::")+2).data()); QCString scope=dstMi->scopePath.left(dstMi->scopePath.find("::")+2); if (scope!=dstMi->ambiguityResolutionScope.left(scope.length())) dstMi->ambiguityResolutionScope.prepend(scope); ambigue=TRUE; } } else // same members { // do not add if base class is virtual or // if scope paths are equal if ((srcMi->virt==Virtual && dstMi->virt==Virtual) || bClass->name()+"::"+srcMi->scopePath == dstMi->scopePath ) { found=TRUE; } else // member can be reached via multiple paths in the // inheritance tree { //printf("$$ Existing member %s %s add scope %s\n", // dstMi->ambiguityResolutionScope.data(), // dstMd->name().data(), // dstMi->scopePath.left(dstMi->scopePath.find("::")+2).data()); QCString scope=dstMi->scopePath.left(dstMi->scopePath.find("::")+2); if (scope!=dstMi->ambiguityResolutionScope.left(scope.length())) dstMi->ambiguityResolutionScope.prepend(scope); ambigue=TRUE; } } } //printf("member %s::%s hidden %d ambigue %d srcMi->ambigClass=%p\n", // srcCd->name().data(),srcMd->name().data(),hidden,ambigue,srcMi->ambigClass); // TODO: fix the case where a member is hidden by inheritance // of a member with the same name but with another prototype, // while there is more than one path to the member in the // base class due to multiple inheritance. In this case // it seems that the member is not reachable by prefixing a // scope name either (according to my compiler). Currently, // this case is shown anyway. if (!found && srcMd->protection()!=Private) { Specifier virt=srcMi->virt; if (srcMi->virt==Normal && bcd->virt!=Normal) virt=bcd->virt; MemberInfo *newMi = new MemberInfo(srcMd,bcd->prot,virt); newMi->scopePath=bClass->name()+"::"+srcMi->scopePath; if (ambigue) { //printf("$$ New member %s %s add scope %s::\n", // srcMi->ambiguityResolutionScope.data(), // srcMd->name().data(), // bClass->name().data()); QCString scope=bClass->name()+"::"; if (scope!=srcMi->ambiguityResolutionScope.left(scope.length())) newMi->ambiguityResolutionScope= scope+srcMi->ambiguityResolutionScope.copy(); } if (hidden) { if (srcMi->ambigClass==0) { newMi->ambigClass=bClass; newMi->ambiguityResolutionScope=bClass->name()+"::"; } else { newMi->ambigClass=srcMi->ambigClass; newMi->ambiguityResolutionScope=srcMi->ambigClass->name()+"::"; } } //printf("Adding!\n"); dstMni->append(newMi); } } } else // base class has a member that is not in the super class => copy { // create a deep copy of the list (only the MemberInfo's will be // copied, not the actual MemberDef's) MemberNameInfo *newMni = new MemberNameInfo(srcMni->memberName()); // copy the member(s) from the base to the super class MemberNameInfoIterator mnii(*srcMni); MemberInfo *mi; for (;(mi=mnii.current());++mnii) { if (mi->memberDef->protection()!=Private) { Specifier virt=mi->virt; if (mi->virt==Normal && bcd->virt!=Normal) virt=bcd->virt; MemberInfo *newMi=new MemberInfo(mi->memberDef,bcd->prot,virt); //if (mi->memberDef->memberClass()!=bClass) newMi->scopePath=bClass->name()+"::"+mi->scopePath; newMi->ambigClass=mi->ambigClass; newMi->ambiguityResolutionScope=mi->ambiguityResolutionScope.copy(); newMni->append(newMi); } } // add it to the list and dictionary dstMnl->inSort(newMni); dstMnd->insert(newMni->memberName(),newMni); } } } } //---------------------------------------------------------------------------- /*! Builds up a dictionary of all classes that are used by the state of this * class (the "implementation"). * Must be called before mergeMembers() is called! */ void ClassDef::determineImplUsageRelation() { MemberNameInfoListIterator mnili(*allMemberNameInfoList); MemberNameInfo *mni; for (;(mni=mnili.current());++mnili) { MemberNameInfoIterator mnii(*mni); MemberInfo *mi; for (mnii.toFirst();(mi=mnii.current());++mnii) { MemberDef *md=mi->memberDef; if (md->isVariable()) // for each member variable in this class { QCString type=md->typeString(); static const QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*"); //printf("in class %s found var type=`%s' name=`%s'\n", // name().data(),type.data(),md->name().data()); int p=0,i,l; bool found=FALSE; while ((i=re.match(type,p,&l))!=-1 && !found) // for each class name in the type { ClassDef *cd=getClass(name()+"::"+type.mid(i,l)); if (cd==0) cd=getClass(type.mid(i,l)); // TODO: also try inbetween scopes! if (cd /*&& cd->isLinkable()*/) // class exists and is linkable { found=TRUE; if (usesImplClassDict==0) usesImplClassDict = new UsesClassDict(257); UsesClassDef *ucd=usesImplClassDict->find(cd->name()); if (ucd==0) { ucd = new UsesClassDef(cd); usesImplClassDict->insert(cd->name(),ucd); //printf("Adding used class %s to class %s\n", // cd->name().data(),name().data()); } ucd->addAccessor(md->name()); //printf("Adding accessor %s to class %s\n", // md->name().data(),ucd->classDef->name().data()); } p=i+l; } } } } #ifdef DUMP if (usesClassDict) { printf("Class %s uses the following classes:\n",name().data()); UsesClassDictIterator ucdi(*usesClassDict); UsesClassDef *ucd; for (;(ucd=ucdi.current());++ucdi) { printf(" %s via ",ucd->classDef->name().data()); QDictIterator dvi(*ucd->accessors); const char *s; for (;(s=dvi.currentKey());++dvi) { printf("%s ",s); } printf("\n"); } } #endif } //---------------------------------------------------------------------------- #if 0 // I have disabled this code because the graphs it renders quickly become // too large to be of practical use. void ClassDef::addUsedInterfaceClasses(MemberDef *md,const char *typeStr) { QCString type = typeStr; static const QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*"); int p=0,i,l; while ((i=re.match(type,p,&l))!=-1) // for each class name in the type { ClassDef *cd=getClass(name()+"::"+type.mid(i,l)); if (cd==0) cd=getClass(type.mid(i,l)); // TODO: also try inbetween scopes! if (cd && cd!=this && !isBaseClass(cd)) { if (usesIntfClassDict==0) { usesIntfClassDict = new UsesClassDict(257); } UsesClassDef *ucd=usesIntfClassDict->find(cd->name()); if (ucd==0) { ucd = new UsesClassDef(cd); usesIntfClassDict->insert(cd->name(),ucd); //printf("in class `%s' adding used intf class `%s'\n", // name().data(),cd->name().data()); } ucd->addAccessor(md->name()); printf("in class `%s' adding accessor `%s' to class `%s'\n", name().data(),md->name().data(),ucd->classDef->name().data()); } p=i+l; } } void ClassDef::determineIntfUsageRelation() { MemberNameInfoListIterator mnili(*allMemberNameInfoList); MemberNameInfo *mni; for (;(mni=mnili.current());++mnili) { MemberNameInfoIterator mnii(*mni); MemberInfo *mi; for (mnii.toFirst();(mi=mnii.current());++mnii) { MemberDef *md=mi->memberDef; // compute the protection level for this member Protection protect=md->protection(); if (mi->prot==Protected) // inherited protection { if (protect==Public) protect=Protected; else if (protect==Protected) protect=Private; } if (!md->name().isEmpty() && md->name()[0]!='@' && (mi->prot!=Private && protect!=Private) ) { // add classes found in the return type addUsedInterfaceClasses(md,md->typeString()); ArgumentList *al = md->argumentList(); if (al) // member has arguments { // add classes found in the types of the argument list ArgumentListIterator ali(*al); Argument *a; for (;(a=ali.current());++ali) { if (!a->type.isEmpty() && a->type.at(0)!='@') { addUsedInterfaceClasses(md,a->type); } } } } } } } #endif