From e03e2a29f9279deabe62d795b0db925a982d0eef Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Thu, 8 Apr 2021 21:18:07 +0200 Subject: issue #2732: Adding support for C++ concepts (Origin: bugzilla #499352) --- doc/commands.doc | 10 + src/CMakeLists.txt | 1 + src/classdef.cpp | 65 ++-- src/classdef.h | 4 +- src/code.l | 80 ++-- src/commentscan.l | 35 ++ src/conceptdef.cpp | 733 +++++++++++++++++++++++++++++++++++ src/conceptdef.h | 82 ++++ src/context.cpp | 5 +- src/definition.h | 3 +- src/dirdef.cpp | 4 + src/docbookgen.cpp | 24 ++ src/docbookgen.h | 2 + src/doxygen.cpp | 244 +++++++++++- src/doxygen.h | 2 + src/entry.h | 4 +- src/filedef.cpp | 48 ++- src/filedef.h | 10 +- src/ftvhelp.cpp | 4 + src/groupdef.cpp | 71 +++- src/groupdef.h | 5 + src/htmlgen.cpp | 13 + src/htmlgen.h | 2 + src/index.cpp | 305 ++++++++++++++- src/index.h | 5 + src/latexgen.cpp | 37 ++ src/latexgen.h | 2 + src/layout.cpp | 57 +++ src/layout.h | 12 +- src/mangen.h | 2 + src/memberdef.cpp | 4 + src/namespacedef.cpp | 58 ++- src/namespacedef.h | 6 + src/outputgen.h | 2 + src/outputlist.h | 4 + src/parserintf.h | 2 +- src/perlmodgen.cpp | 62 ++- src/rtfgen.cpp | 42 ++ src/rtfgen.h | 2 + src/scanner.l | 58 ++- src/searchindex.cpp | 18 +- src/searchindex.h | 2 +- src/sqlite3gen.cpp | 39 +- src/tagreader.cpp | 79 +++- src/translator.h | 12 + src/translator_adapter.h | 30 +- src/translator_br.h | 10 +- src/translator_en.h | 45 +++ src/translator_nl.h | 40 ++ src/translator_pt.h | 10 +- src/translator_sv.h | 2 +- src/util.cpp | 84 +++- src/util.h | 8 + src/xmlgen.cpp | 108 +++++- templates/general/layout_default.xml | 14 + templates/html/doxygen.css | 6 + templates/xml/compound.xsd | 4 + templates/xml/index.xsd | 1 + 58 files changed, 2466 insertions(+), 157 deletions(-) create mode 100644 src/conceptdef.cpp create mode 100644 src/conceptdef.h diff --git a/doc/commands.doc b/doc/commands.doc index 1465a1e..b9ffc3e 100644 --- a/doc/commands.doc +++ b/doc/commands.doc @@ -60,6 +60,7 @@ documentation: \refitem cmdcite \\cite \refitem cmdclass \\class \refitem cmdcode \\code +\refitem cmdconcept \\concept \refitem cmdcond \\cond \refitem cmdcopybrief \\copybrief \refitem cmdcopydetails \\copydetails @@ -457,6 +458,15 @@ Structural indicators \endlatexonly
+\section cmdconcept \\concept + + \addindex \\concept + Indicates that a comment block contains documentation for a + C++20 concept with name \. + See also the \ref cmdheaderfile "\\headerfile" command to specify the + header a user should be included to use the concept. + +
\section cmddef \\def \addindex \\def diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 868cd04..1840648 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -224,6 +224,7 @@ add_library(doxymain STATIC classdef.cpp classlist.cpp cmdmapper.cpp + conceptdef.cpp condparser.cpp context.cpp cppvalue.cpp diff --git a/src/classdef.cpp b/src/classdef.cpp index 6432e2a..f7af740 100644 --- a/src/classdef.cpp +++ b/src/classdef.cpp @@ -188,7 +188,7 @@ class ClassDefImpl : public DefinitionMixin virtual bool isVisibleInHierarchy() const; virtual bool visibleInParentsDeclList() const; virtual const ArgumentList &templateArguments() const; - virtual NamespaceDef *getNamespaceDef() const; + //virtual NamespaceDef *getNamespaceDef() const; virtual FileDef *getFileDef() const; virtual const MemberDef *getMemberByName(const QCString &) const; virtual bool isBaseClass(const ClassDef *bcd,bool followInstances,int level=0) const; @@ -250,7 +250,7 @@ class ClassDefImpl : public DefinitionMixin virtual void insertUsedFile(const FileDef *); virtual bool addExample(const char *anchor,const char *name, const char *file); virtual void mergeCategory(ClassDef *category); - virtual void setNamespace(NamespaceDef *nd); + //virtual void setNamespace(NamespaceDef *nd); virtual void setFileDef(FileDef *fd); virtual void setSubGrouping(bool enabled); virtual void setProtection(Protection p); @@ -355,6 +355,8 @@ class ClassDefImpl : public DefinitionMixin QCString &title,QCString &subtitle) const; QCString includeStatement() const; void addTypeConstraint(const QCString &typeConstraint,const QCString &type); + void writeTemplateSpec(OutputList &ol,const Definition *d, + const QCString &type,SrcLangExt lang) const; // PIMPL idiom class IMPL; @@ -428,8 +430,8 @@ class ClassDefAliasImpl : public DefinitionAliasMixin { return getCdAlias()->visibleInParentsDeclList(); } virtual const ArgumentList &templateArguments() const { return getCdAlias()->templateArguments(); } - virtual NamespaceDef *getNamespaceDef() const - { return getCdAlias()->getNamespaceDef(); } + //virtual NamespaceDef *getNamespaceDef() const + //{ return getCdAlias()->getNamespaceDef(); } virtual FileDef *getFileDef() const { return getCdAlias()->getFileDef(); } virtual const MemberDef *getMemberByName(const QCString &s) const @@ -551,8 +553,6 @@ class ClassDefAliasImpl : public DefinitionAliasMixin virtual void updateSubClasses(const BaseClassList &) {} }; - - ClassDef *createClassDefAlias(const Definition *newScope,const ClassDef *cd) { ClassDef *acd = new ClassDefAliasImpl(newScope,cd); @@ -605,7 +605,7 @@ class ClassDefImpl::IMPL /*! Namespace this class is part of * (this is the inner most namespace in case of nested namespaces) */ - NamespaceDef *nspace = 0; + //NamespaceDef *nspace = 0; /*! File this class is defined in */ FileDef *fileDef = 0; @@ -725,7 +725,7 @@ void ClassDefImpl::IMPL::init(const char *defFileName, const char *name, fileName=ctStr+name; } prot=Public; - nspace=0; + //nspace=0; fileDef=0; subGrouping=Config_getBool(SUBGROUPING); templateMaster =0; @@ -1296,15 +1296,15 @@ static void searchTemplateSpecs(/*in*/ const Definition *d, } } -static void writeTemplateSpec(OutputList &ol,const Definition *d, - const QCString &type,SrcLangExt lang) +void ClassDefImpl::writeTemplateSpec(OutputList &ol,const Definition *d, + const QCString &type,SrcLangExt lang) const { ArgumentLists specs; QCString name; searchTemplateSpecs(d,specs,name,lang); if (!specs.empty()) // class has template scope specifiers { - ol.startSubsubsection(); + ol.startCompoundTemplateParams(); for (const ArgumentList &al : specs) { ol.docify("template<"); @@ -1312,7 +1312,13 @@ static void writeTemplateSpec(OutputList &ol,const Definition *d, while (it!=al.end()) { Argument a = *it; - ol.docify(a.type); + linkifyText(TextGeneratorOLImpl(ol), // out + d, // scope + getFileDef(), // fileScope + this, // self + a.type, // text + FALSE // autoBreak + ); if (!a.name.isEmpty()) { ol.docify(" "); @@ -1329,9 +1335,20 @@ static void writeTemplateSpec(OutputList &ol,const Definition *d, ol.docify(">"); ol.lineBreak(); } + if (!m_impl->requiresClause.isEmpty()) + { + ol.docify("requires "); + linkifyText(TextGeneratorOLImpl(ol), // out + d, // scope + getFileDef(), // fileScope + this, // self + m_impl->requiresClause, // text + FALSE // autoBreak + ); + ol.lineBreak(); + } ol.docify(type.lower()+" "+name); - ol.endSubsubsection(); - ol.writeString("\n"); + ol.endCompoundTemplateParams(); } } @@ -2557,11 +2574,14 @@ void ClassDefImpl::writeDocumentationContents(OutputList &ol,const QCString & /* case LayoutDocEntry::NamespaceNestedNamespaces: case LayoutDocEntry::NamespaceNestedConstantGroups: case LayoutDocEntry::NamespaceClasses: + case LayoutDocEntry::NamespaceConcepts: case LayoutDocEntry::NamespaceInterfaces: case LayoutDocEntry::NamespaceStructs: case LayoutDocEntry::NamespaceExceptions: case LayoutDocEntry::NamespaceInlineClasses: + case LayoutDocEntry::ConceptDefinition: case LayoutDocEntry::FileClasses: + case LayoutDocEntry::FileConcepts: case LayoutDocEntry::FileInterfaces: case LayoutDocEntry::FileStructs: case LayoutDocEntry::FileExceptions: @@ -2573,6 +2593,7 @@ void ClassDefImpl::writeDocumentationContents(OutputList &ol,const QCString & /* case LayoutDocEntry::FileSourceLink: case LayoutDocEntry::FileInlineClasses: case LayoutDocEntry::GroupClasses: + case LayoutDocEntry::GroupConcepts: case LayoutDocEntry::GroupInlineClasses: case LayoutDocEntry::GroupNamespaces: case LayoutDocEntry::GroupDirs: @@ -4557,10 +4578,10 @@ const ArgumentList &ClassDefImpl::templateArguments() const return m_impl->tempArgs; } -NamespaceDef *ClassDefImpl::getNamespaceDef() const -{ - return m_impl->nspace; -} +//NamespaceDef *ClassDefImpl::getNamespaceDef() const +//{ +// return m_impl->nspace; +//} FileDef *ClassDefImpl::getFileDef() const { @@ -4667,10 +4688,10 @@ const MemberGroupList &ClassDefImpl::getMemberGroups() const return m_impl->memberGroups; } -void ClassDefImpl::setNamespace(NamespaceDef *nd) -{ - m_impl->nspace = nd; -} +//void ClassDefImpl::setNamespace(NamespaceDef *nd) +//{ +// m_impl->nspace = nd; +//} void ClassDefImpl::setFileDef(FileDef *fd) { diff --git a/src/classdef.h b/src/classdef.h index b3e3325..c908a70 100644 --- a/src/classdef.h +++ b/src/classdef.h @@ -211,7 +211,7 @@ class ClassDef : public Definition /** Returns the namespace this compound is in, or 0 if it has a global * scope. */ - virtual NamespaceDef *getNamespaceDef() const = 0; + //virtual NamespaceDef *getNamespaceDef() const = 0; /** Returns the file in which this compound's definition can be found. * Should not return 0 (but it might be a good idea to check anyway). @@ -389,7 +389,7 @@ class ClassDefMutable : public DefinitionMutable, public ClassDef //----------------------------------------------------------------------------------- virtual void setIncludeFile(FileDef *fd,const char *incName,bool local,bool force) = 0; - virtual void setNamespace(NamespaceDef *nd) = 0; + //virtual void setNamespace(NamespaceDef *nd) = 0; virtual void setFileDef(FileDef *fd) = 0; virtual void setSubGrouping(bool enabled) = 0; virtual void setProtection(Protection p) = 0; diff --git a/src/code.l b/src/code.l index 6632018..87cc333 100644 --- a/src/code.l +++ b/src/code.l @@ -270,7 +270,7 @@ TEMPLIST "<"[^\"\}\{\(\)\/\n\>]*">" SCOPETNAME (((({ID}{TEMPLIST}?){BN}*)?{SEP}{BN}*)*)((~{BN}*)?{ID}) SCOPEPREFIX ({ID}{TEMPLIST}?{BN}*{SEP}{BN}*)+ KEYWORD_OBJC ("@public"|"@private"|"@protected"|"@class"|"@implementation"|"@interface"|"@end"|"@selector"|"@protocol"|"@optional"|"@required"|"@throw"|"@synthesize"|"@property") -KEYWORD ("asm"|"__assume"|"auto"|"class"|"const"|"delete"|"enum"|"explicit"|"extern"|"false"|"friend"|"gcnew"|"gcroot"|"set"|"get"|"inline"|"internal"|"mutable"|"namespace"|"new"|"null"|"nullptr"|"override"|"operator"|"pin_ptr"|"private"|"protected"|"public"|"raise"|"register"|"remove"|"self"|"sizeof"|"static"|"struct"|"__super"|"function"|"template"|"generic"|"this"|"true"|"typedef"|"typeid"|"typename"|"union"|"using"|"virtual"|"volatile"|"abstract"|"final"|"import"|"synchronized"|"transient"|"alignas"|"alignof"|{KEYWORD_OBJC}) +KEYWORD ("asm"|"__assume"|"auto"|"class"|"const"|"delete"|"enum"|"explicit"|"extern"|"false"|"friend"|"gcnew"|"gcroot"|"set"|"get"|"inline"|"internal"|"mutable"|"namespace"|"new"|"null"|"nullptr"|"override"|"operator"|"pin_ptr"|"private"|"protected"|"public"|"raise"|"register"|"remove"|"self"|"sizeof"|"static"|"struct"|"__super"|"function"|"template"|"generic"|"this"|"true"|"typedef"|"typeid"|"typename"|"union"|"using"|"virtual"|"volatile"|"abstract"|"final"|"import"|"synchronized"|"transient"|"alignas"|"alignof"|"concept"|"requires"|{KEYWORD_OBJC}) FLOWKW ("break"|"catch"|"continue"|"default"|"do"|"else"|"finally"|"return"|"switch"|"throw"|"throws"|"@catch"|"@finally") FLOWCONDITION ("case"|"for"|"foreach"|"for each"|"goto"|"if"|"try"|"while"|"@try") TYPEKW ("bool"|"byte"|"char"|"double"|"float"|"int"|"long"|"object"|"short"|"signed"|"unsigned"|"void"|"wchar_t"|"size_t"|"boolean"|"id"|"SEL"|"string"|"nullptr") @@ -362,6 +362,7 @@ ENDQopt ("const"|"volatile"|"sealed"|"override")({BN}+("const"|"volatile"|"seale %x ObjCSkipStr %x ObjCCallComment %x OldStyleArgs +%x ConceptName %x UsingName %x RawString %x InlineInit @@ -908,12 +909,23 @@ ENDQopt ("const"|"volatile"|"sealed"|"override")({BN}+("const"|"volatile"|"seale yyextra->insideTemplate=TRUE; yyextra->sharpCount=0; } +"concept"{BN}+ { + startFontClass(yyscanner,"keyword"); + codifyLines(yyscanner,yytext); + endFontClass(yyscanner); + BEGIN(ConceptName); + } "using"{BN}+"namespace"{BN}+ { startFontClass(yyscanner,"keyword"); codifyLines(yyscanner,yytext); endFontClass(yyscanner); BEGIN(UsingName); } +{ID}("::"{ID})* { + addUsingDirective(yyscanner,yytext); + generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext); + } +"=" { codifyLines(yyscanner,yytext); BEGIN(Body); } {ID}("::"{ID})* { addUsingDirective(yyscanner,yytext); generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext); @@ -1295,7 +1307,7 @@ ENDQopt ("const"|"volatile"|"sealed"|"override")({BN}+("const"|"volatile"|"seale {SCOPENAME}/{B}* { if (yyextra->theCallContext.getScope().globalDef()) { - DBG_CTX((stderr,"yyextra->theCallContext.getClass()=%p\n",yyextra->theCallContext.getScope().globalDef())); + DBG_CTX((stderr,"yyextra->theCallContext.getClass()=%p\n",(void*)yyextra->theCallContext.getScope().globalDef())); if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope().globalDef(),yytext)) { yyextra->code->codify(yytext); @@ -1753,6 +1765,11 @@ ENDQopt ("const"|"volatile"|"sealed"|"override")({BN}+("const"|"volatile"|"seale endFontClass(yyscanner); yyextra->inFunctionTryBlock=TRUE; } +"requires" { // function-try-block + startFontClass(yyscanner,"keyword"); + yyextra->code->codify(yytext); + endFontClass(yyscanner); + } {ID} { if (yyextra->insideBody || !yyextra->parmType.isEmpty()) { @@ -2356,7 +2373,7 @@ static void startCodeLine(yyscan_t yyscanner) //lineAnchor.sprintf("l%05d",yyextra->yyLineNr); const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr); - DBG_CTX((stderr,"%s:startCodeLine(%d)=%p\n",yyextra->sourceFileDef->name().data(),yyextra->yyLineNr,d)); + DBG_CTX((stderr,"%s:startCodeLine(%d)=%p\n",yyextra->sourceFileDef->name().data(),yyextra->yyLineNr,(void*)d)); if (!yyextra->includeCodeFragment && d) { yyextra->currentDefinition = d; @@ -2502,13 +2519,13 @@ static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol, { yyextra->yyLineNr++; *(p-1)='\0'; - DBG_CTX((stderr,"writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp)); + DBG_CTX((stderr,"writeCodeLink(%s,%s,%s,%s)\n",ref.data(),file.data(),anchor.data(),sp)); ol.writeCodeLink(ref,file,anchor,sp,tooltip); nextCodeLine(yyscanner); } else { - DBG_CTX((stderr,"writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp)); + DBG_CTX((stderr,"writeCodeLink(%s,%s,%s,%s)\n",ref.data(),file.data(),anchor.data(),sp)); ol.writeCodeLink(ref,file,anchor,sp,tooltip); done=TRUE; } @@ -2586,7 +2603,7 @@ static const ClassDef *stripClassName(yyscan_t yyscanner,const char *s,const Def { cd=yyextra->symbolResolver.resolveClass(d,clName); } - DBG_CTX((stderr,"stripClass trying '%s' = %p\n",clName.data(),cd)); + DBG_CTX((stderr,"stripClass trying '%s' = %p\n",clName.data(),(void*)cd)); if (cd) { return cd; @@ -2767,7 +2784,7 @@ static bool getLinkInScope(yyscan_t yyscanner, { yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope()))); DBG_CTX((stderr,"yyextra->currentDefinition=%p yyextra->currentMemberDef=%p yyextra->insideBody=%d\n", - yyextra->currentDefinition,yyextra->currentMemberDef,yyextra->insideBody)); + (void*)yyextra->currentDefinition,(void*)yyextra->currentMemberDef,yyextra->insideBody)); if (yyextra->currentDefinition && yyextra->currentMemberDef && md!=yyextra->currentMemberDef && yyextra->insideBody && yyextra->collectXRefs) @@ -2858,9 +2875,11 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner, DBG_CTX((stderr,"non-local variable name=%s cd=%s md=%s!\n", className.data(),cd?cd->name().data():"", md?md->name().data():"")); - if (cd==0 && md==0 && (i=className.find('<'))!=-1) + i=className.find('<'); + QCString bareName = className; + if (i!=-1) bareName = bareName.left(i); + if (cd==0 && md==0 && i!=-1) { - QCString bareName = className.left(i); //stripTemplateSpecifiersFromScope(className); DBG_CTX((stderr,"bareName=%s\n",bareName.data())); if (bareName!=className) { @@ -2876,6 +2895,14 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner, writeMultiLineCodeLink(yyscanner,*yyextra->code,nd,clName); return; } + const ConceptDef *conceptDef = getResolvedConcept(d,bareName); + if (conceptDef && conceptDef->isLinkable()) + { + yyextra->theCallContext.setScope(ScopedTypeVariant(conceptDef)); + addToSearchIndex(yyscanner,className); + writeMultiLineCodeLink(yyscanner,*yyextra->code,conceptDef,clName); + return; + } DBG_CTX((stderr,"md=%s\n",md?md->name().data():"")); DBG_CTX((stderr,"is found as a type cd=%s nd=%s\n", cd?cd->name().data():"", @@ -2905,7 +2932,7 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner, //} } isLocal=TRUE; - DBG_CTX((stderr,"is a local variable cd=%p!\n",cd)); + DBG_CTX((stderr,"is a local variable cd=%p!\n",(void*)cd)); } yyextra->isPrefixedWithThis = FALSE; // discard the "this" prefix for the next calls @@ -2944,13 +2971,13 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner, } else // not a class, maybe a global member { - DBG_CTX((stderr,"class %s not linkable! cd=%p md=%p typeOnly=%d\n",clName,cd,md,typeOnly)); + DBG_CTX((stderr,"class %s not linkable! cd=%p md=%p typeOnly=%d\n",clName,(void*)cd,(void*)md,typeOnly)); if (!isLocal && (md!=0 || (cd==0 && !typeOnly))) // not a class, see if it is a global enum/variable/typedef. { if (md==0) // not found as a typedef { md = setCallContextForVar(yyscanner,clName); - DBG_CTX((stderr,"setCallContextForVar(%s) md=%p yyextra->currentDefinition=%p\n",clName,md,yyextra->currentDefinition)); + DBG_CTX((stderr,"setCallContextForVar(%s) md=%p yyextra->currentDefinition=%p\n",clName,(void*)md,(void*)yyextra->currentDefinition)); if (md && yyextra->currentDefinition) { DBG_CTX((stderr,"%s accessible from %s? %d md->getOuterScope=%s\n", @@ -2967,7 +2994,7 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner, } if (md && (!varOnly || md->isVariable())) { - DBG_CTX((stderr,"is a global md=%p yyextra->currentDefinition=%s linkable=%d\n",md,yyextra->currentDefinition?yyextra->currentDefinition->name().data():"",md->isLinkable())); + DBG_CTX((stderr,"is a global md=%p yyextra->currentDefinition=%s linkable=%d\n",(void*)md,yyextra->currentDefinition?yyextra->currentDefinition->name().data():"",md->isLinkable())); if (md->isLinkable()) { QCString text=clName; @@ -3019,7 +3046,7 @@ static bool generateClassMemberLink(yyscan_t yyscanner, } const ClassDef *typeClass = stripClassName(yyscanner,removeAnonymousScopes(xmd->typeString()),xmd->getOuterScope()); - DBG_CTX((stderr,"%s -> typeName=%p\n",xmd->typeString(),typeClass)); + DBG_CTX((stderr,"%s -> typeName=%p\n",xmd->typeString(),(void*)typeClass)); yyextra->theCallContext.setScope(ScopedTypeVariant(typeClass)); const Definition *xd = xmd->getOuterScope()==Doxygen::globalScope ? @@ -3028,7 +3055,8 @@ static bool generateClassMemberLink(yyscan_t yyscanner, if (xd && xd->isLinkable()) { - DBG_CTX((stderr,"yyextra->currentDefinition=%p yyextra->currentMemberDef=%p xmd=%p yyextra->insideBody=%d\n",yyextra->currentDefinition,yyextra->currentMemberDef,xmd,yyextra->insideBody)); + DBG_CTX((stderr,"yyextra->currentDefinition=%p yyextra->currentMemberDef=%p xmd=%p yyextra->insideBody=%d\n", + (void*)yyextra->currentDefinition,(void*)yyextra->currentMemberDef,(void*)xmd,yyextra->insideBody)); if (xmd->templateMaster()) xmd = xmd->templateMaster(); @@ -3062,7 +3090,7 @@ static bool generateClassMemberLink(yyscan_t yyscanner, { const ClassDef *cd = toClassDef(def); const MemberDef *xmd = cd->getMemberByName(memName); - DBG_CTX((stderr,"generateClassMemberLink(class=%s,member=%s)=%p\n",def->name().data(),memName,xmd)); + DBG_CTX((stderr,"generateClassMemberLink(class=%s,member=%s)=%p\n",def->name().data(),memName,(void*)xmd)); if (xmd) { return generateClassMemberLink(yyscanner,ol,xmd,memName); @@ -3167,7 +3195,7 @@ static void generateMemberLink(yyscan_t yyscanner, } if (vmn) { - DBG_CTX((stderr,"There is a variable with name '%s'\n",varName)); + DBG_CTX((stderr,"There is a variable with name '%s'\n",varName.data())); for (const auto &vmd : *vmn) { if (vmd->getClassDef()==vcd) @@ -3382,7 +3410,7 @@ static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx) ctx->objectType = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,ctx->objectTypeOrName); ctx->method = yyextra->symbolResolver.getTypedef(); } - DBG_CTX((stderr," object is class? %p\n",ctx->objectType)); + DBG_CTX((stderr," object is class? %p\n",(void*)ctx->objectType)); if (ctx->objectType) // found class { ctx->method = ctx->objectType->getMemberByName(ctx->methodName); @@ -3391,20 +3419,20 @@ static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx) else if (ctx->method==0) // search for class variable with the same name { DBG_CTX((stderr," no\n")); - DBG_CTX((stderr,"yyextra->currentDefinition=%p\n",yyextra->currentDefinition)); + DBG_CTX((stderr,"yyextra->currentDefinition=%p\n",(void*)yyextra->currentDefinition)); if (yyextra->currentDefinition && yyextra->currentDefinition->definitionType()==Definition::TypeClass) { ctx->objectVar = (toClassDef(yyextra->currentDefinition))->getMemberByName(ctx->objectTypeOrName); - DBG_CTX((stderr," ctx->objectVar=%p\n",ctx->objectVar)); + DBG_CTX((stderr," ctx->objectVar=%p\n",(void*)ctx->objectVar)); if (ctx->objectVar) { ctx->objectType = stripClassName(yyscanner,ctx->objectVar->typeString(),yyextra->currentDefinition); - DBG_CTX((stderr," ctx->objectType=%p\n",ctx->objectType)); + DBG_CTX((stderr," ctx->objectType=%p\n",(void*)ctx->objectType)); if (ctx->objectType && !ctx->methodName.isEmpty()) { ctx->method = ctx->objectType->getMemberByName(ctx->methodName); - DBG_CTX((stderr," ctx->method=%p\n",ctx->method)); + DBG_CTX((stderr," ctx->method=%p\n",(void*)ctx->method)); } } } @@ -3420,7 +3448,7 @@ static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx) { ctx->method = cd->getMemberByName(ctx->methodName); } - DBG_CTX((stderr," class=%p method=%p\n",cd,ctx->method)); + DBG_CTX((stderr," class=%p method=%p\n",(void*)cd,(void*)ctx->method)); } } } @@ -3595,7 +3623,7 @@ static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx) ctx->method = ctx->objectType->getMemberByName(ctx->methodName); } } - DBG_CTX((stderr," ***** method=%s -> object=%p\n",ictx->method->name().data(),ctx->objectType)); + DBG_CTX((stderr," ***** method=%s -> object=%p\n",(void*)ictx->method->name().data(),(void*)ctx->objectType)); } } else @@ -3820,7 +3848,7 @@ void CCodeParser::parseCode(CodeOutputInterface &od,const char *className,const yyscan_t yyscanner = p->yyscanner; struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; DBG_CTX((stderr,"***parseCode() exBlock=%d exName=%s fd=%p className=%s searchCtx=%s\n", - exBlock,exName,fd,className,searchCtx?searchCtx->name().data():"")); + exBlock,exName,(void*)fd,className,searchCtx?searchCtx->name().data():"")); if (s.isEmpty()) return; @@ -3873,7 +3901,7 @@ void CCodeParser::parseCode(CodeOutputInterface &od,const char *className,const { setCurrentDoc(yyscanner,"l00001"); } - yyextra->currentDefinition = 0; + yyextra->currentDefinition = getResolvedNamespace(className); yyextra->currentMemberDef = 0; yyextra->searchingForBody = exBlock; yyextra->insideBody = FALSE; diff --git a/src/commentscan.l b/src/commentscan.l index de359b6..dc16d4c 100644 --- a/src/commentscan.l +++ b/src/commentscan.l @@ -68,6 +68,7 @@ static bool handleAddToGroup(yyscan_t yyscanner,const QCString &, const StringVe static bool handleWeakGroup(yyscan_t yyscanner,const QCString &, const StringVector &); static bool handleNamespace(yyscan_t yyscanner,const QCString &, const StringVector &); static bool handlePackage(yyscan_t yyscanner,const QCString &, const StringVector &); +static bool handleConcept(yyscan_t yyscanner,const QCString &, const StringVector &); static bool handleClass(yyscan_t yyscanner,const QCString &, const StringVector &); static bool handleHeaderFile(yyscan_t yyscanner,const QCString &, const StringVector &); static bool handleProtocol(yyscan_t yyscanner,const QCString &, const StringVector &); @@ -176,6 +177,7 @@ static const std::map< std::string, DocCmdMap > docCmdMap = { "cite", { &handleCite, CommandSpacing::Inline }}, { "class", { &handleClass, CommandSpacing::Invisible }}, { "code", { &handleFormatBlock, CommandSpacing::Block }}, + { "concept", { &handleConcept, CommandSpacing::Invisible }}, { "copybrief", { &handleCopyBrief, CommandSpacing::Invisible }}, { "copydetails", { &handleCopyDetails, CommandSpacing::Block }}, { "copydoc", { &handleCopyDoc, CommandSpacing::Block }}, @@ -518,6 +520,7 @@ STopt [^\n@\\]* %x EnumDocArg1 %x NameSpaceDocArg1 %x PackageDocArg1 +%x ConceptDocArg1 %x GroupDocArg1 %x GroupDocArg2 %x SectionLabel @@ -1024,6 +1027,28 @@ STopt [^\n@\\]* . { // ignore other stuff } + /* ------------ handle argument of concept command --------------- */ + +{SCOPEID} { // handle argument + yyextra->current->name = yytext; + BEGIN( Comment ); + } +{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, + "missing argument after " + "\\concept." + ); + unput_string(yytext,yyleng); + BEGIN( Comment ); + } +. { // ignore other stuff + } + + /* ------ handle argument of class/struct/union command --------------- */ {SCOPENAME}{TMPLSPEC} { @@ -1994,6 +2019,15 @@ static bool handleClass(yyscan_t yyscanner,const QCString &cmd, const StringVect return stop; } +static bool handleConcept(yyscan_t yyscanner,const QCString &cmd, const StringVector &) +{ + struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + bool stop=makeStructuralIndicator(yyscanner,Entry::CONCEPTDOC_SEC); + yyextra->currentCmd = cmd; + BEGIN( ConceptDocArg1 ); + return stop; +} + static bool handleHeaderFile(yyscan_t yyscanner,const QCString &, const StringVector &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; @@ -2774,6 +2808,7 @@ static bool getDocSectionName(int s) case Entry::DIRDOC_SEC: case Entry::EXAMPLE_SEC: case Entry::MEMBERGRP_SEC: + case Entry::CONCEPTDOC_SEC: return TRUE; default: return FALSE; diff --git a/src/conceptdef.cpp b/src/conceptdef.cpp new file mode 100644 index 0000000..c92237f --- /dev/null +++ b/src/conceptdef.cpp @@ -0,0 +1,733 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2021 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. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +#include "conceptdef.h" +#include "definitionimpl.h" +#include "util.h" +#include "config.h" +#include "doxygen.h" +#include "language.h" +#include "outputlist.h" +#include "searchindex.h" +#include "message.h" +#include "parserintf.h" + +//------------------------------------------------------------------------------------ + +class ConceptDefImpl : public DefinitionMixin +{ + public: + ConceptDefImpl(const char *fileName,int startLine,int startColumn, + const char *name,const char *tagRef=0,const char *tagFile=0); + ~ConceptDefImpl(); + + virtual ConceptDef *resolveAlias() { return this; } + + //---------- ConceptDef + virtual DefType definitionType() const; + virtual QCString getOutputFileBase() const; + virtual bool hasDetailedDescription() const; + virtual QCString displayName(bool includeScope=true) const; + virtual const IncludeInfo *includeInfo() const; + virtual ArgumentList getTemplateParameterList() const; + virtual QCString anchor() const; + virtual bool isLinkableInProject() const; + virtual bool isLinkable() const; + virtual QCString initializer() const; + virtual void writeDeclarationLink(OutputList &ol,bool &found, + const char *header,bool localNames) const; + virtual const NamespaceDef *getNamespaceDef() const; + virtual const FileDef *getFileDef() const; + + //---------- ConceptDefMutable + virtual void setIncludeFile(FileDef *fd,const char *incName,bool local,bool force); + virtual void setTemplateArguments(const ArgumentList &al); + virtual void setNamespace(NamespaceDef *nd); + virtual void setFileDef(FileDef *fd); + virtual void writeTagFile(TextStream &); + virtual void writeDocumentation(OutputList &); + virtual void setInitializer(const char *init); + virtual void findSectionsInDocumentation(); + + //---------- Helpers + void writeBriefDescription(OutputList &) const; + void writeAuthorSection(OutputList &ol) const; + void writeIncludeFiles(OutputList &ol) const; + void writeDetailedDescription(OutputList &ol,const QCString &title) const; + void writeDefinition(OutputList &ol,const QCString &title) const; + + private: + QCString m_fileName; + std::unique_ptr m_incInfo; + NamespaceDef *m_nspace = 0; + FileDef *m_fileDef = 0; + ArgumentList m_tArgList; + QCString m_initializer; +}; + +ConceptDefMutable *createConceptDef( + const char *fileName,int startLine,int startColumn, + const char *name, const char *tagRef,const char *tagFile) +{ + return new ConceptDefImpl(fileName,startLine,startColumn,name,tagRef,tagFile); +} + +//------------------------------------------------------------------------------------ + +class ConceptDefAliasImpl : public DefinitionAliasMixin +{ + public: + ConceptDefAliasImpl(const Definition *newScope,const ConceptDef *cd) + : DefinitionAliasMixin(newScope,cd) { init(); } + virtual ~ConceptDefAliasImpl() { deinit(); } + + const ConceptDef *getCdAlias() const { return toConceptDef(getAlias()); } + virtual ConceptDef *resolveAlias() { return const_cast(getCdAlias()); } + + virtual DefType definitionType() const { return TypeConcept; } + virtual QCString getOutputFileBase() const + { return getCdAlias()->getOutputFileBase(); } + virtual QCString getReference() const + { return getCdAlias()->getReference(); } + virtual bool isReference() const + { return getCdAlias()->isReference(); } + virtual bool hasDetailedDescription() const + { return getCdAlias()->hasDetailedDescription(); } + virtual QCString displayName(bool includeScope=true) const + { return getCdAlias()->displayName(includeScope); } + virtual const IncludeInfo *includeInfo() const + { return getCdAlias()->includeInfo(); } + virtual ArgumentList getTemplateParameterList() const + { return getCdAlias()->getTemplateParameterList(); } + virtual QCString anchor() const + { return getCdAlias()->anchor(); } + virtual bool isLinkableInProject() const + { return getCdAlias()->isLinkableInProject(); } + virtual bool isLinkable() const + { return getCdAlias()->isLinkable(); } + virtual QCString initializer() const + { return getCdAlias()->initializer(); } + virtual const NamespaceDef *getNamespaceDef() const + { return getCdAlias()->getNamespaceDef(); } + virtual const FileDef *getFileDef() const + { return getCdAlias()->getFileDef(); } + virtual void writeDeclarationLink(OutputList &ol,bool &found, + const char *header,bool localNames) const + { getCdAlias()->writeDeclarationLink(ol,found,header,localNames); } +}; + +ConceptDef *createConceptDefAlias(const Definition *newScope,const ConceptDef *cd) +{ + ConceptDef *acd = new ConceptDefAliasImpl(newScope,cd); + return acd; +} + +//------------------------------------------------------------------------------------ + +ConceptDefImpl::ConceptDefImpl(const char *fileName,int startLine,int startColumn, + const char *name,const char *tagRef,const char *tagFile) : DefinitionMixin(fileName,startLine,startColumn,name) +{ + if (tagFile) + { + if (tagRef) + { + m_fileName = stripExtension(tagFile); + } + else + { + m_fileName = convertNameToFile(stripExtension(tagFile)); + } + } + else + { + m_fileName = convertNameToFile(QCString("concept")+name); + } + setReference(tagRef); +} + +ConceptDefImpl::~ConceptDefImpl() +{ +} + +Definition::DefType ConceptDefImpl::definitionType() const +{ + return TypeConcept; +} + +QCString ConceptDefImpl::getOutputFileBase() const +{ + return m_fileName; +} + +bool ConceptDefImpl::hasDetailedDescription() const +{ + bool repeatBrief = Config_getBool(REPEAT_BRIEF); + bool sourceBrowser = Config_getBool(SOURCE_BROWSER); + return ((!briefDescription().isEmpty() && repeatBrief) || + !documentation().isEmpty() || + (sourceBrowser && getStartBodyLine()!=-1 && getBodyDef())); +} + +QCString ConceptDefImpl::anchor() const +{ + return ""; +} + +QCString ConceptDefImpl::displayName(bool includeScope) const +{ + return includeScope ? name() : localName(); +} + +const IncludeInfo *ConceptDefImpl::includeInfo() const +{ + return m_incInfo.get(); +} + +ArgumentList ConceptDefImpl::getTemplateParameterList() const +{ + return m_tArgList; +} + +bool ConceptDefImpl::isLinkableInProject() const +{ + return hasDocumentation() && !isReference() && !isHidden(); +} + +bool ConceptDefImpl::isLinkable() const +{ + return isLinkableInProject() || isReference(); +} + +void ConceptDefImpl::setIncludeFile(FileDef *fd,const char *incName,bool local,bool force) +{ + if (!m_incInfo) m_incInfo = std::make_unique(); + if ((incName && m_incInfo->includeName.isEmpty()) || + (fd!=0 && m_incInfo->fileDef==0) + ) + { + m_incInfo->fileDef = fd; + m_incInfo->includeName = incName; + m_incInfo->local = local; + } + if (force && incName) + { + m_incInfo->includeName = incName; + m_incInfo->local = local; + } +} + +void ConceptDefImpl::setTemplateArguments(const ArgumentList &al) +{ + m_tArgList = al; +} + +void ConceptDefImpl::setNamespace(NamespaceDef *nd) +{ + m_nspace = nd; +} + +const NamespaceDef *ConceptDefImpl::getNamespaceDef() const +{ + return m_nspace; +} + +void ConceptDefImpl::setFileDef(FileDef *fd) +{ + m_fileDef=fd; +} + +const FileDef *ConceptDefImpl::getFileDef() const +{ + return m_fileDef; +} + +void ConceptDefImpl::setInitializer(const char *init) +{ + m_initializer = init; +} + +QCString ConceptDefImpl::initializer() const +{ + return m_initializer; +} + +void ConceptDefImpl::writeTagFile(TextStream &tagFile) +{ + tagFile << " \n"; + tagFile << " " << convertToXML(name()) << "\n"; + tagFile << " " << convertToXML(getOutputFileBase()) << Doxygen::htmlFileExtension << "\n"; + QCString idStr = id(); + if (!idStr.isEmpty()) + { + tagFile << " " << convertToXML(idStr) << "\n"; + } + writeDocAnchorsToTagFile(tagFile); + tagFile << " \n"; +} + +void ConceptDefImpl::writeBriefDescription(OutputList &ol) const +{ + if (hasBriefDescription()) + { + DocRoot *rootNode = validatingParseDoc(briefFile(),briefLine(),this,0, + briefDescription(),TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); + if (rootNode && !rootNode->isEmpty()) + { + ol.startParagraph(); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Man); + ol.writeString(" - "); + ol.popGeneratorState(); + ol.writeDoc(rootNode,this,0); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::RTF); + ol.writeString(" \n"); + ol.enable(OutputGenerator::RTF); + + if (hasDetailedDescription()) + { + ol.disableAllBut(OutputGenerator::Html); + ol.startTextLink(getOutputFileBase(),"details"); + ol.parseText(theTranslator->trMore()); + ol.endTextLink(); + } + ol.popGeneratorState(); + ol.endParagraph(); + } + delete rootNode; + } + ol.writeSynopsis(); +} + +void ConceptDefImpl::writeIncludeFiles(OutputList &ol) const +{ + if (m_incInfo) + { + QCString nm=m_incInfo->includeName.isEmpty() ? + (m_incInfo->fileDef ? + m_incInfo->fileDef->docName().data() : "" + ) : + m_incInfo->includeName.data(); + if (!nm.isEmpty()) + { + ol.startParagraph(); + ol.startTypewriter(); + ol.docify("#include "); + if (m_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 (m_incInfo->fileDef) + { + ol.writeObjectLink(0,m_incInfo->fileDef->includeName(),0,nm); + } + else + { + ol.docify(nm); + } + ol.popGeneratorState(); + if (m_incInfo->local) + ol.docify("\""); + else + ol.docify(">"); + ol.endTypewriter(); + ol.endParagraph(); + } + } +} + +static QCString templateSpec(const ArgumentList &al) +{ + TextStream t; + t << "template<"; + bool first=true; + for (const auto &a : al) + { + if (!first) t << ", "; + t << a.type; + if (!a.name.isEmpty()) + { + t << " " << a.name; + } + if (a.defval.length()!=0) + { + t << " " << a.defval; + } + first=false; + } + t << ">"; + return t.str(); +} + +void ConceptDefImpl::writeDefinition(OutputList &ol,const QCString &title) const +{ + ol.startGroupHeader(); + ol.parseText(title); + ol.endGroupHeader(); + + auto intf = Doxygen::parserManager->getCodeParser(".cpp"); + intf->resetCodeParserState(); + ol.startCodeFragment("DoxyCode"); + QCString scopeName; + if (getOuterScope()!=Doxygen::globalScope) scopeName=getOuterScope()->name(); + TextStream conceptDef; + conceptDef << templateSpec(m_tArgList); + conceptDef << "\nconcept "; + conceptDef << name(); + conceptDef << " = "; + conceptDef << m_initializer; + intf->parseCode(ol,scopeName,conceptDef.str(),SrcLangExt_Cpp,false,0, + m_fileDef, -1,-1,true,0,false,this); + ol.endCodeFragment("DoxyCode"); +} + +void ConceptDefImpl::writeDetailedDescription(OutputList &ol,const QCString &title) const +{ + static bool repeatBrief = Config_getBool(REPEAT_BRIEF); + if (hasDetailedDescription()) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + ol.writeRuler(); + ol.popGeneratorState(); + + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeAnchor(0,"details"); + ol.popGeneratorState(); + + ol.startGroupHeader(); + ol.parseText(title); + ol.endGroupHeader(); + + ol.startTextBlock(); + // repeat brief description + if (!briefDescription().isEmpty() && repeatBrief) + { + ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); + } + if (!briefDescription().isEmpty() && repeatBrief && + !documentation().isEmpty()) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + ol.writeString("\n\n"); + ol.popGeneratorState(); + } + + // write documentation + if (!documentation().isEmpty()) + { + ol.generateDoc(docFile(),docLine(),this,0,documentation(),TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); + } + + writeSourceDef(ol,name()); + ol.endTextBlock(); + } +} + +void ConceptDefImpl::writeAuthorSection(OutputList &ol) const +{ + // write Author section (Man only) + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Man); + ol.startGroupHeader(); + ol.parseText(theTranslator->trAuthor(TRUE,TRUE)); + ol.endGroupHeader(); + ol.parseText(theTranslator->trGeneratedAutomatically(Config_getString(PROJECT_NAME))); + ol.popGeneratorState(); +} + +void ConceptDefImpl::writeDocumentation(OutputList &ol) +{ + static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); + QCString pageTitle = theTranslator->trConceptReference(displayName()); + startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_ConceptVisible,!generateTreeView); + + // ---- navigation part + if (!generateTreeView) + { + if (getOuterScope()!=Doxygen::globalScope) + { + writeNavigationPath(ol); + } + ol.endQuickIndices(); + } + + // ---- title part + startTitle(ol,getOutputFileBase(),this); + ol.parseText(pageTitle); + endTitle(ol,getOutputFileBase(),displayName()); + + // ---- contents part + + ol.startContents(); + + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->setCurrentDoc(this,anchor(),FALSE); + Doxygen::searchIndex->addWord(localName(),TRUE); + } + + Doxygen::indexList->addIndexItem(this,0); + //---------------------------------------- start flexible part ------------------------------- + + for (const auto &lde : LayoutDocManager::instance().docEntries(LayoutDocManager::Concept)) + { + switch (lde->kind()) + { + case LayoutDocEntry::BriefDesc: + writeBriefDescription(ol); + break; + case LayoutDocEntry::ConceptDefinition: + { + const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get(); + writeDefinition(ol,ls->title(getLanguage())); + } + break; + case LayoutDocEntry::DetailedDesc: + { + const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get(); + writeDetailedDescription(ol,ls->title(getLanguage())); + } + break; + case LayoutDocEntry::AuthorSection: + writeAuthorSection(ol); + break; + case LayoutDocEntry::ClassIncludes: + writeIncludeFiles(ol); + break; + case LayoutDocEntry::MemberDeclStart: + case LayoutDocEntry::NamespaceClasses: + case LayoutDocEntry::NamespaceInterfaces: + case LayoutDocEntry::NamespaceStructs: + case LayoutDocEntry::NamespaceExceptions: + case LayoutDocEntry::NamespaceConcepts: + case LayoutDocEntry::NamespaceNestedNamespaces: + case LayoutDocEntry::NamespaceNestedConstantGroups: + case LayoutDocEntry::MemberGroups: + case LayoutDocEntry::MemberDecl: + case LayoutDocEntry::MemberDeclEnd: + case LayoutDocEntry::MemberDefStart: + case LayoutDocEntry::NamespaceInlineClasses: + case LayoutDocEntry::MemberDef: + case LayoutDocEntry::MemberDefEnd: + case LayoutDocEntry::ClassInheritanceGraph: + case LayoutDocEntry::ClassNestedClasses: + case LayoutDocEntry::ClassCollaborationGraph: + case LayoutDocEntry::ClassAllMembersLink: + case LayoutDocEntry::ClassUsedFiles: + case LayoutDocEntry::ClassInlineClasses: + case LayoutDocEntry::FileClasses: + case LayoutDocEntry::FileConcepts: + case LayoutDocEntry::FileInterfaces: + case LayoutDocEntry::FileStructs: + case LayoutDocEntry::FileExceptions: + case LayoutDocEntry::FileNamespaces: + case LayoutDocEntry::FileConstantGroups: + case LayoutDocEntry::FileIncludes: + case LayoutDocEntry::FileIncludeGraph: + case LayoutDocEntry::FileIncludedByGraph: + case LayoutDocEntry::FileInlineClasses: + case LayoutDocEntry::FileSourceLink: + case LayoutDocEntry::GroupClasses: + case LayoutDocEntry::GroupConcepts: + case LayoutDocEntry::GroupInlineClasses: + case LayoutDocEntry::GroupNamespaces: + case LayoutDocEntry::GroupDirs: + case LayoutDocEntry::GroupNestedGroups: + case LayoutDocEntry::GroupFiles: + case LayoutDocEntry::GroupGraph: + case LayoutDocEntry::GroupPageDocs: + case LayoutDocEntry::DirSubDirs: + case LayoutDocEntry::DirFiles: + case LayoutDocEntry::DirGraph: + err("Internal inconsistency: member %d should not be part of " + "LayoutDocManager::Namespace entry list\n",lde->kind()); + break; + } + } + + //---------------------------------------- end flexible part ------------------------------- + + ol.endContents(); + + endFileWithNavPath(this,ol); +} + +void ConceptDefImpl::writeDeclarationLink(OutputList &ol,bool &found,const char *header,bool localNames) const +{ + if (isLinkable()) + { + if (!found) // first concept + { + ol.startMemberHeader("concepts"); + if (header) + { + ol.parseText(header); + } + else + { + theTranslator->trConcept(true,false); + } + ol.endMemberHeader(); + ol.startMemberList(); + found=TRUE; + } + ol.startMemberDeclaration(); + ol.startMemberItem(anchor(),FALSE); + ol.writeString("concept "); + QCString cname = displayName(!localNames); + ol.insertMemberAlign(); + if (isLinkable()) + { + ol.writeObjectLink(getReference(), + getOutputFileBase(), + anchor(), + cname + ); + } + else + { + ol.startBold(); + ol.docify(cname); + ol.endBold(); + } + ol.endMemberItem(); + // add the brief description if available + if (!briefDescription().isEmpty() && Config_getBool(BRIEF_MEMBER_DESC)) + { + DocRoot *rootNode = validatingParseDoc(briefFile(),briefLine(),this,0, + briefDescription(),FALSE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); + if (rootNode && !rootNode->isEmpty()) + { + ol.startMemberDescription(anchor()); + ol.writeDoc(rootNode,this,0); + ol.endMemberDescription(); + } + delete rootNode; + } + ol.endMemberDeclaration(anchor(),0); + } +} + +void ConceptDefImpl::findSectionsInDocumentation() +{ + docFindSections(briefDescription(),this,docFile()); + docFindSections(documentation(),this,docFile()); +} + +//------------------------------------------------------------------------------------ + +bool ConceptLinkedRefMap::declVisible() const +{ + bool hideUndocClasses = Config_getBool(HIDE_UNDOC_CLASSES); + for (const auto &cd : *this) + { + bool isLink = cd->isLinkable(); + if (isLink || !hideUndocClasses) + { + return true; + } + } + return false; +} + +void ConceptLinkedRefMap::writeDeclaration(OutputList &ol,const char *header,bool localNames) const +{ + bool found=FALSE; + for (const auto &cd : *this) + { + cd->writeDeclarationLink(ol,found,header,localNames); + } + if (found) ol.endMemberList(); +} + +//------------------------------------------------------------------------------------ + +// --- Cast functions +// +ConceptDef *toConceptDef(Definition *d) +{ + if (d && (typeid(*d)==typeid(ConceptDefImpl) || typeid(*d)==typeid(ConceptDefAliasImpl))) + { + return static_cast(d); + } + else + { + return 0; + } +} + +ConceptDef *toConceptDef(DefinitionMutable *md) +{ + Definition *d = toDefinition(md); + if (d && typeid(*d)==typeid(ConceptDefImpl)) + { + return static_cast(d); + } + else + { + return 0; + } +} + +const ConceptDef *toConceptDef(const Definition *d) +{ + if (d && (typeid(*d)==typeid(ConceptDefImpl) || typeid(*d)==typeid(ConceptDefAliasImpl))) + { + return static_cast(d); + } + else + { + return 0; + } +} + +ConceptDefMutable *toConceptDefMutable(Definition *d) +{ + if (d && typeid(*d)==typeid(ConceptDefImpl)) + { + return static_cast(d); + } + else + { + return 0; + } +} + +ConceptDefMutable *toConceptDefMutable(const Definition *d) +{ + if (d && typeid(*d)==typeid(ConceptDefImpl)) + { + return const_cast(static_cast(d)); + } + else + { + return 0; + } +} + + + diff --git a/src/conceptdef.h b/src/conceptdef.h new file mode 100644 index 0000000..224ed57 --- /dev/null +++ b/src/conceptdef.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2021 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. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +#ifndef CONCEPTDEF_H +#define CONCEPTDEF_H + +#include "definition.h" +#include "filedef.h" + +class ConceptDef : public Definition +{ + public: + virtual DefType definitionType() const = 0; + virtual QCString getOutputFileBase() const = 0; + virtual bool hasDetailedDescription() const = 0; + virtual QCString displayName(bool includeScope=true) const = 0; + virtual const IncludeInfo *includeInfo() const = 0; + virtual ArgumentList getTemplateParameterList() const = 0; + virtual QCString anchor() const = 0; + virtual bool isLinkableInProject() const = 0; + virtual bool isLinkable() const = 0; + virtual QCString initializer() const = 0; + virtual void writeDeclarationLink(OutputList &ol,bool &found, + const char *header,bool localNames) const = 0; + virtual const NamespaceDef *getNamespaceDef() const = 0; + virtual const FileDef *getFileDef() const = 0; +}; + +class ConceptDefMutable : public DefinitionMutable, public ConceptDef +{ + public: + virtual void setIncludeFile(FileDef *fd,const char *incName,bool local,bool force) = 0; + virtual void setTemplateArguments(const ArgumentList &al) = 0; + virtual void setNamespace(NamespaceDef *nd) = 0; + virtual void setFileDef(FileDef *fd) = 0; + virtual void writeTagFile(TextStream &) = 0; + virtual void writeDocumentation(OutputList &ol) = 0; + virtual void setInitializer(const char *init) = 0; + virtual void findSectionsInDocumentation() = 0; +}; + +ConceptDefMutable *createConceptDef( + const char *fileName,int startLine,int startColumn,const char *name, + const char *tagRef=0,const char *tagFile=0); + +ConceptDef *createConceptDefAlias(const Definition *newScope,const ConceptDef *cd); + +// ---- Map + +class ConceptLinkedMap : public LinkedMap +{ +}; + +class ConceptLinkedRefMap : public LinkedRefMap +{ + public: + bool declVisible() const; + void writeDeclaration(OutputList &ol,const char *header,bool localNames) const; + void writeDocumentation(OutputList &ol,const Definition * container=0) const; +}; + +// ---- Cast functions + +ConceptDef *toConceptDef(Definition *d); +ConceptDef *toConceptDef(DefinitionMutable *d); +const ConceptDef *toConceptDef(const Definition *d); +ConceptDefMutable *toConceptDefMutable(Definition *d); +ConceptDefMutable *toConceptDefMutable(const Definition *d); + +#endif diff --git a/src/context.cpp b/src/context.cpp index 32e6720..8275130 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -1552,6 +1552,7 @@ class DefinitionContext case Definition::TypePackage: result="package"; break; case Definition::TypePage: result="page"; break; case Definition::TypeDir: result="dir"; break; + case Definition::TypeConcept: result="concept"; break; case Definition::TypeMember: break; } return result; @@ -6393,7 +6394,9 @@ class NestingContext::Private : public GenericNodeListContext if (!nd->isAnonymous() && (!rootOnly || nd->getOuterScope()==Doxygen::globalScope)) { - bool hasChildren = namespaceHasNestedNamespace(nd); + bool hasChildren = namespaceHasNestedNamespace(nd) || + namespaceHasNestedClass(nd,false,ClassDef::Class) || + namespaceHasNestedConcept(nd); bool isLinkable = nd->isLinkableInProject(); if (isLinkable || hasChildren) { diff --git a/src/definition.h b/src/definition.h index 1b1c364..66d7628 100644 --- a/src/definition.h +++ b/src/definition.h @@ -90,7 +90,8 @@ class Definition TypeGroup = 4, TypePackage = 5, TypePage = 6, - TypeDir = 7 + TypeDir = 7, + TypeConcept = 8 }; diff --git a/src/dirdef.cpp b/src/dirdef.cpp index a1363cc..39a5cb1 100644 --- a/src/dirdef.cpp +++ b/src/dirdef.cpp @@ -561,11 +561,14 @@ void DirDefImpl::writeDocumentation(OutputList &ol) case LayoutDocEntry::NamespaceNestedNamespaces: case LayoutDocEntry::NamespaceNestedConstantGroups: case LayoutDocEntry::NamespaceClasses: + case LayoutDocEntry::NamespaceConcepts: case LayoutDocEntry::NamespaceInterfaces: case LayoutDocEntry::NamespaceStructs: case LayoutDocEntry::NamespaceExceptions: case LayoutDocEntry::NamespaceInlineClasses: + case LayoutDocEntry::ConceptDefinition: case LayoutDocEntry::FileClasses: + case LayoutDocEntry::FileConcepts: case LayoutDocEntry::FileInterfaces: case LayoutDocEntry::FileStructs: case LayoutDocEntry::FileExceptions: @@ -577,6 +580,7 @@ void DirDefImpl::writeDocumentation(OutputList &ol) case LayoutDocEntry::FileSourceLink: case LayoutDocEntry::FileInlineClasses: case LayoutDocEntry::GroupClasses: + case LayoutDocEntry::GroupConcepts: case LayoutDocEntry::GroupInlineClasses: case LayoutDocEntry::GroupNamespaces: case LayoutDocEntry::GroupDirs: diff --git a/src/docbookgen.cpp b/src/docbookgen.cpp index 6e6d969..1c03c07 100644 --- a/src/docbookgen.cpp +++ b/src/docbookgen.cpp @@ -385,6 +385,9 @@ DB_GEN_C2("IndexSections " << is) case isNamespaceIndex: //Namespace Index}\n" break; + case isConceptIndex: + //Concept Index}\n" + break; case isClassHierarchyIndex: //Hierarchical Index}\n" break; @@ -409,6 +412,10 @@ DB_GEN_C2("IndexSections " << is) m_t << "\n"; m_t << " "; break; + case isConceptDocumentation: + m_t << "<chapter>\n"; + m_t << " <title>"; + break; case isClassDocumentation: m_t << "<chapter>\n"; m_t << " <title>"; @@ -456,6 +463,10 @@ DB_GEN_C2("IndexSections " << is) //m_t << "<xi:include href=\"namespaces.xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>"; //m_t << "</chapter>\n"; break; + case isConceptIndex: + //m_t << "<xi:include href=\"concepts.xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>"; + //m_t << "</chapter>\n"; + break; case isClassHierarchyIndex: //m_t << "<xi:include href=\"hierarchy.xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>"; //m_t << "</chapter>\n"; @@ -510,6 +521,19 @@ DB_GEN_C2("IndexSections " << is) } m_t << "</chapter>\n"; break; + case isConceptDocumentation: + { + m_t << "\n"; + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + if (cd->isLinkableInProject() && !cd->isAlias()) + { + m_t << "getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>\n"; + } + } + } + m_t << "\n"; + break; case isClassDocumentation: { m_t << "\n"; diff --git a/src/docbookgen.h b/src/docbookgen.h index 2de8a40..fc9d576 100644 --- a/src/docbookgen.h +++ b/src/docbookgen.h @@ -241,6 +241,8 @@ class DocbookGenerator : public OutputGenerator void endMemberItem(); void startMemberTemplateParams(); void endMemberTemplateParams(const char *,const char *); + void startCompoundTemplateParams() { startSubsubsection(); } + void endCompoundTemplateParams() { endSubsubsection(); } void startMemberGroupHeader(bool); void endMemberGroupHeader(); void startMemberGroupDocs(){DB_GEN_EMPTY}; diff --git a/src/doxygen.cpp b/src/doxygen.cpp index 9a9342b..880a3f4 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -104,6 +104,7 @@ #include "regex.h" #include "fileinfo.h" #include "dir.h" +#include "conceptdef.h" #if USE_SQLITE3 #include @@ -124,6 +125,7 @@ extern void initResources(); // globally accessible variables ClassLinkedMap *Doxygen::classLinkedMap = 0; ClassLinkedMap *Doxygen::hiddenClassLinkedMap = 0; +ConceptLinkedMap *Doxygen::conceptLinkedMap = 0; NamespaceLinkedMap *Doxygen::namespaceLinkedMap = 0; MemberNameLinkedMap *Doxygen::memberNameLinkedMap = 0; MemberNameLinkedMap *Doxygen::functionNameLinkedMap = 0; @@ -184,6 +186,7 @@ void clearAll() Doxygen::classLinkedMap->clear(); Doxygen::hiddenClassLinkedMap->clear(); + Doxygen::conceptLinkedMap->clear(); Doxygen::namespaceLinkedMap->clear(); Doxygen::pageLinkedMap->clear(); Doxygen::exampleLinkedMap->clear(); @@ -531,7 +534,8 @@ static void buildFileList(const Entry *root) for (const auto &e : root->children()) buildFileList(e.get()); } -static void addIncludeFile(ClassDefMutable *cd,FileDef *ifd,const Entry *root) +template +static void addIncludeFile(DefMutable *cd,FileDef *ifd,const Entry *root) { if ( (!root->doc.stripWhiteSpace().isEmpty() || @@ -1158,6 +1162,148 @@ static void buildClassDocList(const Entry *root) for (const auto &e : root->children()) buildClassDocList(e.get()); } +//---------------------------------------------------------------------- +// build a list of all classes mentioned in the documentation +// and all classes that have a documentation block before their definition. + +static void addConceptToContext(const Entry *root) +{ + FileDef *fd = root->fileDef(); + + QCString scName; + if (root->parent()->section&Entry::SCOPE_MASK) + { + scName=root->parent()->name; + } + + // name with scope (if not present already) + QCString qualifiedName = root->name; + if (!scName.isEmpty() && !leftScopeMatch(qualifiedName,scName)) + { + qualifiedName.prepend(scName+"::"); + } + + // see if we already found the concept before + ConceptDefMutable *cd = getConceptMutable(qualifiedName); + + Debug::print(Debug::Classes,0, " Found concept with name %s (qualifiedName=%s -> cd=%p)\n", + cd ? qPrint(cd->name()) : qPrint(root->name), qPrint(qualifiedName),cd); + + if (cd) + { + qualifiedName=cd->name(); + Debug::print(Debug::Classes,0," Existing concept %s!\n",qPrint(cd->name())); + + cd->setDocumentation(root->doc,root->docFile,root->docLine); + cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + + addIncludeFile(cd,fd,root); + } + else // new concept + { + QCString className; + QCString namespaceName; + extractNamespaceName(qualifiedName,className,namespaceName); + + //printf("New concept: fullname %s namespace '%s' name='%s' brief='%s' docs='%s'\n", + // qualifiedName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data()); + + QCString tagName; + QCString refFileName; + const TagInfo *tagInfo = root->tagInfo(); + if (tagInfo) + { + tagName = tagInfo->tagName; + refFileName = tagInfo->fileName; + if (qualifiedName.find("::")!=-1) + // symbols imported via tag files may come without the parent scope, + // so we artificially create it here + { + buildScopeFromQualifiedName(qualifiedName,root->lang,tagInfo); + } + } + std::unique_ptr tArgList = getTemplateArgumentsFromName(qualifiedName,root->tArgLists); + // add concept to the list + //printf("ClassDict.insert(%s)\n",fullName.data()); + cd = toConceptDefMutable( + Doxygen::conceptLinkedMap->add(qualifiedName, + std::unique_ptr( + createConceptDef(tagInfo?tagName:root->fileName,root->startLine,root->startColumn, + qualifiedName,tagName,refFileName)))); + if (cd) + { + Debug::print(Debug::Classes,0," New concept '%s' #tArgLists=%d tagInfo=%p\n", + qPrint(qualifiedName),root->tArgLists.size(),tagInfo); + cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition + cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + cd->setLanguage(root->lang); + cd->setId(root->id); + cd->setHidden(root->hidden); + cd->setInitializer(root->initializer.str().c_str()); + if (tArgList) + { + cd->setTemplateArguments(*tArgList); + } + // file definition containing the class cd + cd->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine); + cd->setBodyDef(fd); + addIncludeFile(cd,fd,root); + + // also add namespace to the correct structural context + Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,qualifiedName,0,tagInfo); + if (d && d->definitionType()==Definition::TypeNamespace) + { + DefinitionMutable *dm = toDefinitionMutable(d); + if (dm) + { + dm->addInnerCompound(cd); + } + cd->setOuterScope(d); + } + } + else + { + Debug::print(Debug::Classes,0," Not added concept '%s', already exists (as alias)\n", qPrint(qualifiedName)); + } + } + + if (cd) + { + cd->addSectionsToDefinition(root->anchors); + if (fd) + { + //printf(">> Inserting concept '%s' in file '%s' (root->fileName='%s')\n", + // cd->name().data(), + // fd->name().data(), + // root->fileName.data() + // ); + cd->setFileDef(fd); + fd->insertConcept(cd); + } + addConceptToGroups(root,cd); + cd->setRefItems(root->sli); + } +} +static void buildConceptList(const Entry *root) +{ + if (root->section & Entry::CONCEPT_SEC) + { + addConceptToContext(root); + } + for (const auto &e : root->children()) buildConceptList(e.get()); +} + +static void buildConceptDocList(const Entry *root) +{ + if (root->section & Entry::CONCEPTDOC_SEC) + { + addConceptToContext(root); + } + for (const auto &e : root->children()) buildConceptDocList(e.get()); +} + +//---------------------------------------------------------------------- + static void resolveClassNestingRelations() { ClassDefSet visitedClasses; @@ -3437,6 +3583,7 @@ static void buildFunctionList(const Entry *root) // functions have the same number of template parameters bool sameNumTemplateArgs = TRUE; bool matchingReturnTypes = TRUE; + bool sameRequiresClause = TRUE; if (!mdTempl.empty() && !root->tArgLists.empty()) { if (mdTempl.size()!=root->tArgLists.back().size()) @@ -3447,6 +3594,10 @@ static void buildFunctionList(const Entry *root) { matchingReturnTypes = FALSE; } + if (md->requiresClause()!=root->req) + { + sameRequiresClause = FALSE; + } } bool staticsInDifferentFiles = @@ -3458,6 +3609,7 @@ static void buildFunctionList(const Entry *root) FALSE) && sameNumTemplateArgs && matchingReturnTypes && + sameRequiresClause && !staticsInDifferentFiles ) { @@ -5245,13 +5397,14 @@ static bool findGlobalMember(const Entry *root, matching = FALSE; } - // for template member we also need to check the return type + // for template member we also need to check the return type and requires if (!md->templateArguments().empty() && !root->tArgLists.empty()) { //printf("Comparing return types '%s'<->'%s'\n", // md->typeString(),type); if (md->templateArguments().size()!=root->tArgLists.back().size() || - qstrcmp(md->typeString(),type)!=0) + qstrcmp(md->typeString(),type)!=0 || + md->requiresClause()!=root->req) { //printf(" ---> no matching\n"); matching = FALSE; @@ -7852,6 +8005,15 @@ static void addSourceReferences() fd->addSourceRef(cd->getStartDefLine(),cd.get(),0); } } + // add source references for concept definitions + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + FileDef *fd=cd->getBodyDef(); + if (fd && cd->isLinkableInProject() && cd->getStartDefLine()!=-1) + { + fd->addSourceRef(cd->getStartDefLine(),cd.get(),0); + } + } // add source references for namespace definitions for (const auto &nd : *Doxygen::namespaceLinkedMap) { @@ -8096,6 +8258,27 @@ static void generateClassDocs() //---------------------------------------------------------------------------- +static void generateConceptDocs() +{ + for (const auto &cdi : *Doxygen::conceptLinkedMap) + { + ConceptDefMutable *cd=toConceptDefMutable(cdi.get()); + + //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope); + if (cd && + (cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file + cd->getOuterScope()==Doxygen::globalScope // only look at global concepts + ) && !cd->isHidden() && cd->isLinkableInProject() + ) + { + msg("Generating docs for concept %s...\n",cd->name().data()); + cd->writeDocumentation(*g_outputList); + } + } +} + +//---------------------------------------------------------------------------- + static void inheritDocumentation() { for (const auto &mn : *Doxygen::memberNameLinkedMap) @@ -8241,6 +8424,15 @@ static void findSectionsInDocumentation() cdm->findSectionsInDocumentation(); } } + // for each concept + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + ConceptDefMutable *cdm = toConceptDefMutable(cd.get()); + if (cdm) + { + cdm->findSectionsInDocumentation(); + } + } // for each file for (const auto &fn : *Doxygen::inputNameLinkedMap) { @@ -8934,6 +9126,20 @@ static void generateNamespaceClassDocs(const ClassLinkedRefMap &classList) } } +static void generateNamespaceConceptDocs(const ConceptLinkedRefMap &conceptList) +{ + // for each concept in the namespace... + for (const auto &cd : conceptList) + { + ConceptDefMutable *cdm = toConceptDefMutable(cd); + if ( cdm && cd->isLinkableInProject() && !cd->isHidden()) + { + msg("Generating docs for concept %s...\n",cd->name().data()); + cdm->writeDocumentation(*g_outputList); + } + } +} + static void generateNamespaceDocs() { static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE); @@ -8960,6 +9166,7 @@ static void generateNamespaceDocs() generateNamespaceClassDocs(nd->getStructs()); generateNamespaceClassDocs(nd->getExceptions()); } + generateNamespaceConceptDocs(nd->getConcepts()); } } @@ -10096,6 +10303,7 @@ void initDoxygen() Doxygen::namespaceLinkedMap = new NamespaceLinkedMap; Doxygen::classLinkedMap = new ClassLinkedMap; Doxygen::hiddenClassLinkedMap = new ClassLinkedMap; + Doxygen::conceptLinkedMap = new ConceptLinkedMap; Doxygen::dirLinkedMap = new DirLinkedMap; Doxygen::pageLinkedMap = new PageLinkedMap; // all doc pages Doxygen::exampleLinkedMap = new PageLinkedMap; // all examples @@ -10715,6 +10923,15 @@ static void writeTagFile() cdm->writeTagFile(tagFile); } } + // for each concept + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + ConceptDefMutable *cdm = toConceptDefMutable(cd.get()); + if (cdm && cdm->isLinkableInProject()) + { + cdm->writeTagFile(tagFile); + } + } // for each namespace for (const auto &nd : *Doxygen::namespaceLinkedMap) { @@ -11241,6 +11458,10 @@ void parseInput() buildClassList(root.get()); g_s.end(); + g_s.begin("Building concept list...\n"); + buildConceptList(root.get()); + g_s.end(); + // build list of using declarations here (global list) buildListOfUsingDecls(root.get()); g_s.end(); @@ -11260,6 +11481,11 @@ void parseInput() g_s.begin("Associating documentation with classes...\n"); buildClassDocList(root.get()); + g_s.end(); + + g_s.begin("Associating documentation with concepts...\n"); + buildConceptDocList(root.get()); + g_s.end(); g_s.begin("Building example list...\n"); buildExampleList(root.get()); @@ -11411,6 +11637,11 @@ void parseInput() return qstricmp(n1->name(),n2->name())<0; }; + auto conceptComp = [](const ConceptLinkedMap::Ptr &c1,const ConceptLinkedMap::Ptr &c2) + { + return qstricmp(c1->name(),c2->name())<0; + }; + g_s.begin("Sorting lists...\n"); std::sort(Doxygen::memberNameLinkedMap->begin(), Doxygen::memberNameLinkedMap->end(), @@ -11424,6 +11655,9 @@ void parseInput() std::sort(Doxygen::classLinkedMap->begin(), Doxygen::classLinkedMap->end(), classComp); + std::sort(Doxygen::conceptLinkedMap->begin(), + Doxygen::conceptLinkedMap->end(), + conceptComp); std::sort(Doxygen::namespaceLinkedMap->begin(), Doxygen::namespaceLinkedMap->end(), namespaceComp); @@ -11711,6 +11945,10 @@ void generateOutput() generateClassDocs(); g_s.end(); + g_s.begin("Generating concept documentation...\n"); + generateConceptDocs(); + g_s.end(); + g_s.begin("Generating namespace index...\n"); generateNamespaceDocs(); g_s.end(); diff --git a/src/doxygen.h b/src/doxygen.h index 5b136b4..787b69e 100644 --- a/src/doxygen.h +++ b/src/doxygen.h @@ -41,6 +41,7 @@ class GroupLinkedMap; class FileDef; class ClassDef; class ClassLinkedMap; +class ConceptLinkedMap; class MemberNameLinkedMap; class FileNameLinkedMap; class NamespaceLinkedMap; @@ -76,6 +77,7 @@ class Doxygen public: static ClassLinkedMap *classLinkedMap; static ClassLinkedMap *hiddenClassLinkedMap; + static ConceptLinkedMap *conceptLinkedMap; static PageLinkedMap *exampleLinkedMap; static PageLinkedMap *pageLinkedMap; static std::unique_ptr mainPage; diff --git a/src/entry.h b/src/entry.h index 6ba88e8..95b2274 100644 --- a/src/entry.h +++ b/src/entry.h @@ -66,6 +66,7 @@ class Entry enum Sections { CLASS_SEC = 0x00000001, NAMESPACE_SEC = 0x00000010, + CONCEPT_SEC = 0x00000020, COMPOUND_MASK = CLASS_SEC, SCOPE_MASK = COMPOUND_MASK | NAMESPACE_SEC, @@ -79,6 +80,7 @@ class Entry CATEGORYDOC_SEC = 0x00040000, SERVICEDOC_SEC = 0x00080000, SINGLETONDOC_SEC = 0x00100000, + CONCEPTDOC_SEC = 0x00200000, COMPOUNDDOC_MASK = CLASSDOC_SEC | STRUCTDOC_SEC | UNIONDOC_SEC | INTERFACEDOC_SEC | EXCEPTIONDOC_SEC | PROTOCOLDOC_SEC | CATEGORYDOC_SEC | SERVICEDOC_SEC | SINGLETONDOC_SEC, @@ -256,7 +258,7 @@ class Entry QCString args; //!< member argument string QCString bitfields; //!< member's bit fields ArgumentList argList; //!< member arguments as a list - ArgumentLists tArgLists; //!< template argument declarations + ArgumentLists tArgLists; //!< template argument declarations TextStream program; //!< the program text TextStream initializer; //!< initial value (for variables) QCString includeFile; //!< include file (2 arg of \\class, must be unique) diff --git a/src/filedef.cpp b/src/filedef.cpp index a9503c5..58d38c4 100644 --- a/src/filedef.cpp +++ b/src/filedef.cpp @@ -45,6 +45,7 @@ #include "clangparser.h" #include "settings.h" #include "definitionimpl.h" +#include "conceptdef.h" //--------------------------------------------------------------------------- @@ -90,8 +91,9 @@ class FileDefImpl : public DefinitionMixin virtual MemberList *getMemberList(MemberListType lt) const; virtual const MemberLists &getMemberLists() const { return m_memberLists; } virtual const MemberGroupList &getMemberGroups() const { return m_memberGroups; } - virtual NamespaceLinkedRefMap getNamespaces() const { return m_namespaces; } - virtual ClassLinkedRefMap getClasses() const { return m_classes; } + virtual const NamespaceLinkedRefMap &getNamespaces() const { return m_namespaces; } + virtual const ConceptLinkedRefMap &getConcepts() const { return m_concepts; } + virtual const ClassLinkedRefMap &getClasses() const { return m_classes; } virtual QCString title() const; virtual bool hasDetailedDescription() const; virtual QCString fileVersion() const; @@ -112,6 +114,7 @@ class FileDefImpl : public DefinitionMixin virtual void setDiskName(const QCString &name); virtual void insertMember(MemberDef *md); virtual void insertClass(const ClassDef *cd); + virtual void insertConcept(const ConceptDef *cd); virtual void insertNamespace(const NamespaceDef *nd); virtual void computeAnchors(); virtual void setPackageDef(PackageDef *pd) { m_package=pd; } @@ -143,6 +146,7 @@ class FileDefImpl : public DefinitionMixin void writeNamespaceDeclarations(OutputList &ol,const QCString &title, bool isConstantGroup); void writeClassDeclarations(OutputList &ol,const QCString &title,const ClassLinkedRefMap &list); + void writeConcepts(OutputList &ol,const QCString &title); void writeInlineClasses(OutputList &ol); void startMemberDeclarations(OutputList &ol); void endMemberDeclarations(OutputList &ol); @@ -178,6 +182,7 @@ class FileDefImpl : public DefinitionMixin ClassLinkedRefMap m_interfaces; ClassLinkedRefMap m_structs; ClassLinkedRefMap m_exceptions; + ConceptLinkedRefMap m_concepts; bool m_subGrouping; }; @@ -356,6 +361,17 @@ void FileDefImpl::writeTagFile(TextStream &tagFile) writeClassesToTagFile(tagFile, m_exceptions); } break; + case LayoutDocEntry::FileConcepts: + { + for (const auto *nd : m_concepts) + { + if (nd->isLinkableInProject()) + { + tagFile << " " << convertToXML(nd->name()) << "\n"; + } + } + } + break; case LayoutDocEntry::FileNamespaces: { for (const auto *nd : m_namespaces) @@ -668,6 +684,12 @@ void FileDefImpl::writeClassDeclarations(OutputList &ol,const QCString &title,co list.writeDeclaration(ol,0,title,FALSE); } +void FileDefImpl::writeConcepts(OutputList &ol,const QCString &title) +{ + // write list of classes + m_concepts.writeDeclaration(ol,title,FALSE); +} + void FileDefImpl::writeInlineClasses(OutputList &ol) { // temporarily undo the disabling could be done by startMemberDocumentation() @@ -777,6 +799,13 @@ void FileDefImpl::writeSummaryLinks(OutputList &ol) const ol.writeSummaryLink(0,label,ls->title(lang),first); first=FALSE; } + else if (lde->kind()==LayoutDocEntry::FileConcepts && m_concepts.declVisible()) + { + const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get(); + QCString label = "concepts"; + ol.writeSummaryLink(0,label,ls->title(lang),first); + first=FALSE; + } else if (lde->kind()==LayoutDocEntry::MemberDecl) { const LayoutDocEntryMemberDecl *lmd = (const LayoutDocEntryMemberDecl*)lde.get(); @@ -919,6 +948,12 @@ void FileDefImpl::writeDocumentation(OutputList &ol) writeClassDeclarations(ol,ls->title(lang),m_exceptions); } break; + case LayoutDocEntry::FileConcepts: + { + const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get(); + writeConcepts(ol,ls->title(lang)); + } + break; case LayoutDocEntry::FileNamespaces: { const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get(); @@ -977,11 +1012,14 @@ void FileDefImpl::writeDocumentation(OutputList &ol) case LayoutDocEntry::NamespaceNestedNamespaces: case LayoutDocEntry::NamespaceNestedConstantGroups: case LayoutDocEntry::NamespaceClasses: + case LayoutDocEntry::NamespaceConcepts: case LayoutDocEntry::NamespaceInterfaces: case LayoutDocEntry::NamespaceStructs: case LayoutDocEntry::NamespaceExceptions: case LayoutDocEntry::NamespaceInlineClasses: + case LayoutDocEntry::ConceptDefinition: case LayoutDocEntry::GroupClasses: + case LayoutDocEntry::GroupConcepts: case LayoutDocEntry::GroupInlineClasses: case LayoutDocEntry::GroupNamespaces: case LayoutDocEntry::GroupDirs: @@ -1319,6 +1357,12 @@ void FileDefImpl::insertClass(const ClassDef *cd) list.add(cd->name(),cd); } +void FileDefImpl::insertConcept(const ConceptDef *cd) +{ + if (cd->isHidden()) return; + m_concepts.add(cd->name(),cd); +} + /*! Adds namespace definition \a nd to the list of all compounds of this file */ void FileDefImpl::insertNamespace(const NamespaceDef *nd) { diff --git a/src/filedef.h b/src/filedef.h index 3075470..02b484a 100644 --- a/src/filedef.h +++ b/src/filedef.h @@ -24,16 +24,18 @@ #include "definition.h" #include "memberlist.h" #include "containers.h" -#include "classlist.h" class MemberList; class FileDef; class FileList; class ClassDef; +class ConceptDef; class MemberDef; class OutputList; class NamespaceDef; class NamespaceLinkedRefMap; +class ConceptLinkedRefMap; +class ClassLinkedRefMap; class PackageDef; class DirDef; class ClangTUParser; @@ -133,8 +135,9 @@ class FileDef : public DefinitionMutable, public Definition /* user defined member groups */ virtual const MemberGroupList &getMemberGroups() const = 0; - virtual NamespaceLinkedRefMap getNamespaces() const = 0; - virtual ClassLinkedRefMap getClasses() const = 0; + virtual const NamespaceLinkedRefMap &getNamespaces() const = 0; + virtual const ConceptLinkedRefMap &getConcepts() const = 0; + virtual const ClassLinkedRefMap &getClasses() const = 0; virtual QCString title() const = 0; virtual bool hasDetailedDescription() const = 0; @@ -164,6 +167,7 @@ class FileDef : public DefinitionMutable, public Definition virtual void insertMember(MemberDef *md) = 0; virtual void insertClass(const ClassDef *cd) = 0; + virtual void insertConcept(const ConceptDef *cd) = 0; virtual void insertNamespace(const NamespaceDef *nd) = 0; virtual void computeAnchors() = 0; diff --git a/src/ftvhelp.cpp b/src/ftvhelp.cpp index d061325..7ef38c8 100644 --- a/src/ftvhelp.cpp +++ b/src/ftvhelp.cpp @@ -479,6 +479,10 @@ void FTVHelp::generateTree(TextStream &t, const std::vector &nl,int le char icon=compoundIcon(toClassDef(n->def)); t << "" << icon << ""; } + else if (n->def && n->def->definitionType()==Definition::TypeConcept) + { + t << "R"; + } else if (n->def && n->def->definitionType()==Definition::TypeDir) { t << ""; diff --git a/src/groupdef.cpp b/src/groupdef.cpp index 27ab775..82a550d 100644 --- a/src/groupdef.cpp +++ b/src/groupdef.cpp @@ -64,6 +64,7 @@ class GroupDefImpl : public DefinitionMixin virtual bool hasGroupTitle( ) const { return m_titleSet; } virtual void addFile(const FileDef *def); virtual bool addClass(const ClassDef *def); + virtual bool addConcept(const ConceptDef *def); virtual bool addNamespace(const NamespaceDef *def); virtual void addGroup(const GroupDef *def); virtual void addPage(const PageDef *def); @@ -102,6 +103,7 @@ class GroupDefImpl : public DefinitionMixin virtual const FileList &getFiles() const { return m_fileList; } virtual const ClassLinkedRefMap &getClasses() const { return m_classes; } + virtual const ConceptLinkedRefMap &getConcepts() const { return m_concepts; } virtual const NamespaceLinkedRefMap &getNamespaces() const { return m_namespaces; } virtual const GroupList &getSubGroups() const { return m_groups; } virtual const PageLinkedRefMap &getPages() const { return m_pages; } @@ -122,6 +124,7 @@ class GroupDefImpl : public DefinitionMixin void writeNestedGroups(OutputList &ol,const QCString &title); void writeDirs(OutputList &ol,const QCString &title); void writeClasses(OutputList &ol,const QCString &title); + void writeConcepts(OutputList &ol,const QCString &title); void writeInlineClasses(OutputList &ol); void writePageDocumentation(OutputList &ol); void writeDetailedDescription(OutputList &ol,const QCString &title); @@ -140,6 +143,7 @@ class GroupDefImpl : public DefinitionMixin QCString m_fileName; // base name of the generated file FileList m_fileList; // list of files in the group ClassLinkedRefMap m_classes; // list of classes in the group + ConceptLinkedRefMap m_concepts; // list of concepts in the group NamespaceLinkedRefMap m_namespaces; // list of namespaces in the group GroupList m_groups; // list of sub groups. PageLinkedRefMap m_pages; // list of pages in the group @@ -256,6 +260,18 @@ bool GroupDefImpl::addClass(const ClassDef *cd) return FALSE; } +bool GroupDefImpl::addConcept(const ConceptDef *cd) +{ + if (cd->isHidden()) return FALSE; + QCString qn = cd->name(); + if (m_concepts.find(qn)==0) + { + m_concepts.add(qn,cd); + return TRUE; + } + return FALSE; +} + bool GroupDefImpl::addNamespace(const NamespaceDef *def) { //printf("adding namespace hidden=%d\n",def->isHidden()); @@ -619,6 +635,18 @@ void GroupDefImpl::writeTagFile(TextStream &tagFile) } } break; + case LayoutDocEntry::GroupConcepts: + { + for (const auto &cd : m_concepts) + { + if (cd->isLinkableInProject()) + { + tagFile << " " << convertToXML(cd->name()) + << "\n"; + } + } + } + break; case LayoutDocEntry::GroupNamespaces: { for (const auto &nd : m_namespaces) @@ -936,6 +964,12 @@ void GroupDefImpl::writeClasses(OutputList &ol,const QCString &title) m_classes.writeDeclaration(ol,0,title,FALSE); } +void GroupDefImpl::writeConcepts(OutputList &ol,const QCString &title) +{ + // write list of concepts + m_concepts.writeDeclaration(ol,title,FALSE); +} + void GroupDefImpl::writeInlineClasses(OutputList &ol) { m_classes.writeDocumentation(ol); @@ -1023,15 +1057,17 @@ void GroupDefImpl::writeSummaryLinks(OutputList &ol) const SrcLangExt lang = getLanguage(); for (const auto &lde : LayoutDocManager::instance().docEntries(LayoutDocManager::Group)) { - if ((lde->kind()==LayoutDocEntry::GroupClasses && m_classes.declVisible()) || - (lde->kind()==LayoutDocEntry::GroupNamespaces && m_namespaces.declVisible()) || - (lde->kind()==LayoutDocEntry::GroupFiles && !m_fileList.empty()) || + if ((lde->kind()==LayoutDocEntry::GroupClasses && m_classes.declVisible()) || + (lde->kind()==LayoutDocEntry::GroupConcepts && m_concepts.declVisible()) || + (lde->kind()==LayoutDocEntry::GroupNamespaces && m_namespaces.declVisible()) || + (lde->kind()==LayoutDocEntry::GroupFiles && !m_fileList.empty()) || (lde->kind()==LayoutDocEntry::GroupNestedGroups && !m_groups.empty()) || - (lde->kind()==LayoutDocEntry::GroupDirs && !m_dirList.empty()) + (lde->kind()==LayoutDocEntry::GroupDirs && !m_dirList.empty()) ) { const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get(); QCString label = lde->kind()==LayoutDocEntry::GroupClasses ? "nested-classes" : + lde->kind()==LayoutDocEntry::GroupConcepts ? "concepts" : lde->kind()==LayoutDocEntry::GroupNamespaces ? "namespaces" : lde->kind()==LayoutDocEntry::GroupFiles ? "files" : lde->kind()==LayoutDocEntry::GroupNestedGroups ? "groups" : @@ -1123,6 +1159,12 @@ void GroupDefImpl::writeDocumentation(OutputList &ol) writeClasses(ol,ls->title(lang)); } break; + case LayoutDocEntry::GroupConcepts: + { + const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get(); + writeConcepts(ol,ls->title(lang)); + } + break; case LayoutDocEntry::GroupInlineClasses: { writeInlineClasses(ol); @@ -1201,11 +1243,14 @@ void GroupDefImpl::writeDocumentation(OutputList &ol) case LayoutDocEntry::NamespaceNestedNamespaces: case LayoutDocEntry::NamespaceNestedConstantGroups: case LayoutDocEntry::NamespaceClasses: + case LayoutDocEntry::NamespaceConcepts: case LayoutDocEntry::NamespaceInterfaces: case LayoutDocEntry::NamespaceStructs: case LayoutDocEntry::NamespaceExceptions: case LayoutDocEntry::NamespaceInlineClasses: + case LayoutDocEntry::ConceptDefinition: case LayoutDocEntry::FileClasses: + case LayoutDocEntry::FileConcepts: case LayoutDocEntry::FileInterfaces: case LayoutDocEntry::FileStructs: case LayoutDocEntry::FileExceptions: @@ -1312,6 +1357,24 @@ void addClassToGroups(const Entry *root,ClassDef *cd) } } +void addConceptToGroups(const Entry *root,ConceptDef *cd) +{ + for (const Grouping &g : root->groups) + { + GroupDef *gd = Doxygen::groupLinkedMap->find(g.groupname); + if (gd && gd->addConcept(cd)) + { + ConceptDefMutable *cdm = toConceptDefMutable(cd); + if (cdm) + { + cdm->makePartOfGroup(gd); + } + //printf("Compound %s: in group %s\n",cd->name().data(),gd->groupTitle()); + } + } +} + + void addNamespaceToGroups(const Entry *root,NamespaceDef *nd) { //printf("root->groups.size()=%zu\n",root->groups.size()); diff --git a/src/groupdef.h b/src/groupdef.h index 26d26ca..8d3b78e 100644 --- a/src/groupdef.h +++ b/src/groupdef.h @@ -30,9 +30,11 @@ class MemberList; class MemberLists; class FileList; class ClassLinkedRefMap; +class ConceptLinkedRefMap; class NamespaceLinkedRefMap; class FileDef; class ClassDef; +class ConceptDef; class NamespaceDef; class GroupList; class OutputList; @@ -58,6 +60,7 @@ class GroupDef : public DefinitionMutable, public Definition virtual bool hasGroupTitle( ) const = 0; virtual void addFile(const FileDef *def) = 0; virtual bool addClass(const ClassDef *def) = 0; + virtual bool addConcept(const ConceptDef *def) = 0; virtual bool addNamespace(const NamespaceDef *def) = 0; virtual void addGroup(const GroupDef *def) = 0; virtual void addPage(const PageDef *def) = 0; @@ -96,6 +99,7 @@ class GroupDef : public DefinitionMutable, public Definition virtual const FileList &getFiles() const = 0; virtual const ClassLinkedRefMap &getClasses() const = 0; + virtual const ConceptLinkedRefMap &getConcepts() const = 0; virtual const NamespaceLinkedRefMap &getNamespaces() const = 0; virtual const GroupList &getSubGroups() const = 0; virtual const PageLinkedRefMap &getPages() const = 0; @@ -125,6 +129,7 @@ class GroupList : public std::vector }; void addClassToGroups (const Entry *root,ClassDef *cd); +void addConceptToGroups (const Entry *root,ConceptDef *cd); void addNamespaceToGroups(const Entry *root,NamespaceDef *nd); void addGroupToGroups (const Entry *root,GroupDef *subGroup); void addMemberToGroups (const Entry *root,MemberDef *md); diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp index b239116..fc00b17 100644 --- a/src/htmlgen.cpp +++ b/src/htmlgen.cpp @@ -1630,6 +1630,15 @@ void HtmlGenerator::endMemberTemplateParams(const char *anchor,const char *inher m_t << "\">"; } +void HtmlGenerator::startCompoundTemplateParams() +{ + m_t << "
"; +} + +void HtmlGenerator::endCompoundTemplateParams() +{ + m_t << "
"; +} void HtmlGenerator::insertMemberAlign(bool templ) { @@ -2222,6 +2231,7 @@ static bool quickLinkVisible(LayoutNavEntry::Kind kind) case LayoutNavEntry::Namespaces: return documentedNamespaces>0 && showNamespaces; case LayoutNavEntry::NamespaceList: return documentedNamespaces>0 && showNamespaces; case LayoutNavEntry::NamespaceMembers: return documentedNamespaceMembers[NMHL_All]>0; + case LayoutNavEntry::Concepts: return documentedConcepts>0; case LayoutNavEntry::Classes: return annotatedClasses>0; case LayoutNavEntry::ClassList: return annotatedClasses>0; case LayoutNavEntry::ClassIndex: return annotatedClasses>0; @@ -2369,6 +2379,7 @@ static void writeDefaultQuickLinks(TextStream &t,bool compact, case HLI_InterfaceHierarchy: kind = LayoutNavEntry::InterfaceHierarchy; break; case HLI_ExceptionHierarchy: kind = LayoutNavEntry::ExceptionHierarchy; break; case HLI_Classes: kind = LayoutNavEntry::ClassIndex; altKind = LayoutNavEntry::Classes; break; + case HLI_Concepts: kind = LayoutNavEntry::Concepts; break; case HLI_Interfaces: kind = LayoutNavEntry::InterfaceIndex; altKind = LayoutNavEntry::Interfaces; break; case HLI_Structs: kind = LayoutNavEntry::StructIndex; altKind = LayoutNavEntry::Structs; break; case HLI_Exceptions: kind = LayoutNavEntry::ExceptionIndex; altKind = LayoutNavEntry::Exceptions; break; @@ -2385,6 +2396,8 @@ static void writeDefaultQuickLinks(TextStream &t,bool compact, case HLI_UserGroup: kind = LayoutNavEntry::UserGroup; break; case HLI_ClassVisible: kind = LayoutNavEntry::ClassList; altKind = LayoutNavEntry::Classes; highlightParent = TRUE; break; + case HLI_ConceptVisible: kind = LayoutNavEntry::Concepts; + highlightParent = TRUE; break; case HLI_InterfaceVisible: kind = LayoutNavEntry::InterfaceList; altKind = LayoutNavEntry::Interfaces; highlightParent = TRUE; break; case HLI_StructVisible: kind = LayoutNavEntry::StructList; altKind = LayoutNavEntry::Structs; diff --git a/src/htmlgen.h b/src/htmlgen.h index 5c8eff5..3abb733 100644 --- a/src/htmlgen.h +++ b/src/htmlgen.h @@ -185,6 +185,8 @@ class HtmlGenerator : public OutputGenerator void endMemberItem(); void startMemberTemplateParams(); void endMemberTemplateParams(const char *anchor,const char *inheritId); + void startCompoundTemplateParams(); + void endCompoundTemplateParams(); void startMemberGroupHeader(bool); void endMemberGroupHeader(); diff --git a/src/index.cpp b/src/index.cpp index 3d3169b..1a91430 100644 --- a/src/index.cpp +++ b/src/index.cpp @@ -67,6 +67,7 @@ int hierarchyExceptions; int documentedFiles; int documentedGroups; int documentedNamespaces; +int documentedConcepts; int indexedPages; int documentedClassMembers[CMHL_Total]; int documentedFileMembers[FMHL_Total]; @@ -80,6 +81,7 @@ static void countFiles(int &htmlFiles,int &files); static int countGroups(); static int countDirs(); static int countNamespaces(); +static int countConcepts(); static int countAnnotatedClasses(int *cp,ClassDef::CompoundType ct); static void countRelatedPages(int &docPages,int &indexPages); @@ -102,6 +104,7 @@ void countDataStructures() countRelatedPages(documentedPages,indexedPages); // "pages" documentedGroups = countGroups(); // "modules" documentedNamespaces = countNamespaces(); // "namespaces" + documentedConcepts = countConcepts(); // "concepts" documentedDirs = countDirs(); // "dirs" // "globals" // "namespacemembers" @@ -347,7 +350,9 @@ static void writeMemberToIndex(const Definition *def,const MemberDef *md,bool ad template void addMembersToIndex(T *def,LayoutDocManager::LayoutPart part, const QCString &name,const QCString &anchor, - bool addToIndex=TRUE,bool preventSeparateIndex=FALSE) + bool addToIndex=TRUE,bool preventSeparateIndex=FALSE, + const ConceptLinkedRefMap *concepts = nullptr) + { bool hasMembers = !def->getMemberLists().empty() || !def->getMemberGroups().empty(); Doxygen::indexList->addContentsItem(hasMembers,name, @@ -360,13 +365,22 @@ void addMembersToIndex(T *def,LayoutDocManager::LayoutPart part, { if (cd->isLinkable()) numClasses++; } + int numConcepts=0; + if (concepts) + { + for (const auto &cd : *concepts) + { + if (cd->isLinkable()) numConcepts++; + } + } //printf("addMembersToIndex(def=%s hasMembers=%d numClasses=%d)\n",def->name().data(),hasMembers,numClasses); - if (hasMembers || numClasses>0) + if (hasMembers || numClasses>0 || numConcepts>0) { Doxygen::indexList->incContentsDepth(); for (const auto &lde : LayoutDocManager::instance().docEntries(part)) { - if (lde->kind()==LayoutDocEntry::MemberDef) + auto kind = lde->kind(); + if (kind==LayoutDocEntry::MemberDef) { const LayoutDocEntryMemberDef *lmd = (const LayoutDocEntryMemberDef*)lde.get(); MemberList *ml = def->getMemberList(lmd->type); @@ -381,9 +395,9 @@ void addMembersToIndex(T *def,LayoutDocManager::LayoutPart part, } } } - else if (lde->kind()==LayoutDocEntry::NamespaceClasses || - lde->kind()==LayoutDocEntry::FileClasses || - lde->kind()==LayoutDocEntry::ClassNestedClasses + else if (kind==LayoutDocEntry::NamespaceClasses || + kind==LayoutDocEntry::FileClasses || + kind==LayoutDocEntry::ClassNestedClasses ) { for (const auto &cd : def->getClasses()) @@ -392,12 +406,26 @@ void addMembersToIndex(T *def,LayoutDocManager::LayoutPart part, { static bool inlineSimpleStructs = Config_getBool(INLINE_SIMPLE_STRUCTS); bool isNestedClass = def->definitionType()==Definition::TypeClass; - addMembersToIndex(cd,LayoutDocManager::Class,cd->displayName(FALSE),cd->anchor(), + addMembersToIndex(cd,LayoutDocManager::Class,cd->displayName(lde->kind()==LayoutDocEntry::FileClasses),cd->anchor(), addToIndex && (isNestedClass || (cd->isSimple() && inlineSimpleStructs)), preventSeparateIndex || cd->isEmbeddedInOuterScope()); } } } + else if (kind==LayoutDocEntry::FileConcepts && concepts) + { + for (const auto &cd : *concepts) + { + if (cd->isLinkable() && (cd->partOfGroups().empty() || def->definitionType()==Definition::TypeGroup)) + { + Doxygen::indexList->addContentsItem(false,cd->displayName(), + cd->getReference(),cd->getOutputFileBase(),0, + false, + false, + cd); + } + } + } } Doxygen::indexList->decContentsDepth(); @@ -675,7 +703,8 @@ static void writeDirTreeNode(OutputList &ol, const DirDef *dd, int level, FTVHel doc = fileVisibleInIndex(fd,src); if (doc) { - addMembersToIndex(fd,LayoutDocManager::File,fd->displayName(),QCString(),TRUE); + addMembersToIndex(fd,LayoutDocManager::File,fd->displayName(),QCString(), + TRUE,FALSE,&fd->getConcepts()); } else if (src) { @@ -743,7 +772,7 @@ static void writeDirHierarchy(OutputList &ol, FTVHelp* ftv,bool addToIndex) { if (doc) { - addMembersToIndex(fd.get(),LayoutDocManager::File,fd->displayName(),QCString(),TRUE); + addMembersToIndex(fd.get(),LayoutDocManager::File,fd->displayName(),QCString(),TRUE,FALSE,&fd->getConcepts()); } else if (src) { @@ -1486,6 +1515,18 @@ static int countNamespaces() } //---------------------------------------------------------------------------- +static int countConcepts() +{ + int count=0; + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + if (cd->isLinkableInProject()) count++; + } + return count; +} + + +//---------------------------------------------------------------------------- template const ClassDef *get_pointer(const Ptr &p); template<> const ClassDef *get_pointer(const ClassLinkedMap::Ptr &p) { return p.get(); } template<> const ClassDef *get_pointer(const ClassLinkedRefMap::Ptr &p) { return p; } @@ -1603,6 +1644,7 @@ static void writeNamespaceMembers(const NamespaceDef *nd,bool addToIndex) } } +static void writeConceptList(const ConceptLinkedRefMap &concepts, FTVHelp *ftv,bool addToIndex); static void writeNamespaceTree(const NamespaceLinkedRefMap &nsLinkedMap,FTVHelp *ftv, bool rootOnly,bool addToIndex); @@ -1614,7 +1656,8 @@ static void writeNamespaceTreeElement(const NamespaceDef *nd,FTVHelp *ftv, { bool hasChildren = namespaceHasNestedNamespace(nd) || - namespaceHasNestedClass(nd,false,ClassDef::Class); + namespaceHasNestedClass(nd,false,ClassDef::Class) || + namespaceHasNestedConcept(nd); bool isLinkable = nd->isLinkableInProject(); int visibleMembers = countVisibleMembers(nd); @@ -1647,13 +1690,12 @@ static void writeNamespaceTreeElement(const NamespaceDef *nd,FTVHelp *ftv, Doxygen::indexList->incContentsDepth(); } - //printf("*** writeNamespaceTree count=%d addToIndex=%d false=%d classCount=%d\n", - // count,addToIndex,false,classCount); if (isDir) { ftv->incContentsDepth(); writeNamespaceTree(nd->getNamespaces(),ftv,FALSE,addToIndex); writeClassTree(nd->getClasses(),ftv,FALSE,FALSE,ClassDef::Class); + writeConceptList(nd->getConcepts(),ftv,FALSE); writeNamespaceMembers(nd,addToIndex); ftv->decContentsDepth(); } @@ -3736,6 +3778,7 @@ static void writeGroupTreeNode(OutputList &ol, const GroupDef *gd, int level, FT numSubItems += gd->getNamespaces().size(); numSubItems += gd->getClasses().size(); numSubItems += gd->getFiles().size(); + numSubItems += gd->getConcepts().size(); numSubItems += gd->getDirs().size(); numSubItems += gd->getPages().size(); } @@ -3819,7 +3862,7 @@ static void writeGroupTreeNode(OutputList &ol, const GroupDef *gd, int level, FT //if (cd->isEmbeddedInOuterScope()) //{ //printf("add class & members %d\n",addToIndex); - addMembersToIndex(cd,LayoutDocManager::Class,cd->displayName(FALSE),cd->anchor(),addToIndex,TRUE); + addMembersToIndex(cd,LayoutDocManager::Class,cd->displayName(),cd->anchor(),addToIndex,TRUE); //} //else // only index the class, not its members //{ @@ -3838,11 +3881,23 @@ static void writeGroupTreeNode(OutputList &ol, const GroupDef *gd, int level, FT if (nd->isVisible()) { Doxygen::indexList->addContentsItem(FALSE, - nd->localName(),nd->getReference(), + nd->displayName(),nd->getReference(), nd->getOutputFileBase(),0,FALSE,FALSE); } } } + else if (lde->kind()==LayoutDocEntry::GroupConcepts && addToIndex) + { + for (const auto &cd : gd->getConcepts()) + { + if (cd->isVisible()) + { + Doxygen::indexList->addContentsItem(FALSE, + cd->displayName(),cd->getReference(), + cd->getOutputFileBase(),0,FALSE,FALSE); + } + } + } else if (lde->kind()==LayoutDocEntry::GroupFiles && addToIndex) { for (const auto &fd : gd->getFiles()) @@ -4016,6 +4071,211 @@ static void writeGroupIndex(OutputList &ol) //---------------------------------------------------------------------------- +static void writeConceptList(const ConceptLinkedRefMap &concepts, FTVHelp *ftv,bool addToIndex) +{ + for (const auto &cd : concepts) + { + ftv->addContentsItem(false,cd->displayName(FALSE),cd->getReference(), + cd->getOutputFileBase(),0,false,true,cd); + if (addToIndex) + { + Doxygen::indexList->addContentsItem(false,cd->displayName(FALSE),cd->getReference(), + cd->getOutputFileBase(),0,false,true); + } + } +} + +static void writeConceptTreeInsideNamespaceElement(const NamespaceDef *nd,FTVHelp *ftv, + bool rootOnly, bool addToIndex); + +static void writeConceptTreeInsideNamespace(const NamespaceLinkedRefMap &nsLinkedMap,FTVHelp *ftv, + bool rootOnly, bool addToIndex) +{ + for (const auto &nd : nsLinkedMap) + { + writeConceptTreeInsideNamespaceElement(nd,ftv,rootOnly,addToIndex); + } +} + + +static void writeConceptTreeInsideNamespaceElement(const NamespaceDef *nd,FTVHelp *ftv, + bool rootOnly, bool addToIndex) +{ + if (!nd->isAnonymous() && + (!rootOnly || nd->getOuterScope()==Doxygen::globalScope)) + { + bool isDir = namespaceHasNestedConcept(nd); + bool isLinkable = nd->isLinkableInProject(); + + //printf("namespace %s isDir=%d\n",nd->name().data(),isDir); + + QCString ref; + QCString file; + if (isLinkable) + { + ref = nd->getReference(); + file = nd->getOutputFileBase(); + } + + if (isDir) + { + ftv->addContentsItem(isDir,nd->localName(),ref,file,0,FALSE,TRUE,nd); + + if (addToIndex) + { + // the namespace entry is already shown under the namespace list so don't + // add it to the nav index and don't create a separate index file for it otherwise + // it will overwrite the one written for the namespace list. + Doxygen::indexList->addContentsItem(isDir,nd->localName(),ref,file,QCString(), + false, // separateIndex + false // addToNavIndex + ); + } + if (addToIndex) + { + Doxygen::indexList->incContentsDepth(); + } + + ftv->incContentsDepth(); + writeConceptTreeInsideNamespace(nd->getNamespaces(),ftv,FALSE,addToIndex); + writeConceptList(nd->getConcepts(),ftv,addToIndex); + ftv->decContentsDepth(); + + if (addToIndex) + { + Doxygen::indexList->decContentsDepth(); + } + } + } +} + +static void writeConceptRootList(FTVHelp *ftv,bool addToIndex) +{ + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + if (cd->getOuterScope()==0 || + cd->getOuterScope()==Doxygen::globalScope) + { + //printf("*** adding %s hasSubPages=%d hasSections=%d\n",pageTitle.data(),hasSubPages,hasSections); + ftv->addContentsItem( + false,cd->localName(),cd->getReference(),cd->getOutputFileBase(), + 0,false,true,cd.get()); + if (addToIndex) + { + Doxygen::indexList->addContentsItem( + false,cd->localName(),cd->getReference(),cd->getOutputFileBase(), + 0,false,true); + } + } + } +} + +static void writeConceptIndex(OutputList &ol) +{ + if (documentedConcepts==0) return; + ol.pushGeneratorState(); + // 1.{ + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::Docbook); + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Concepts); + QCString title = lne ? lne->title() : theTranslator->trConceptList(); + bool addToIndex = lne==0 || lne->visible(); + + startFile(ol,"concepts",0,title,HLI_Concepts); + startTitle(ol,0); + ol.parseText(title); + endTitle(ol,0,0); + ol.startContents(); + ol.startTextBlock(); + ol.parseText(lne ? lne->intro() : theTranslator->trConceptListDescription(Config_getBool(EXTRACT_ALL))); + ol.endTextBlock(); + + // --------------- + // Normal group index for Latex/RTF + // --------------- + // 2.{ + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + + bool first=TRUE; + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + if (cd->isLinkableInProject()) + { + if (first) + { + ol.startIndexList(); + first=FALSE; + } + //ol.writeStartAnnoItem("namespace",nd->getOutputFileBase(),0,nd->name()); + ol.startIndexKey(); + ol.writeObjectLink(0,cd->getOutputFileBase(),0,cd->displayName()); + ol.endIndexKey(); + + bool hasBrief = !cd->briefDescription().isEmpty(); + ol.startIndexValue(hasBrief); + if (hasBrief) + { + //ol.docify(" ("); + ol.generateDoc( + cd->briefFile(),cd->briefLine(), + cd.get(),0, + cd->briefDescription(TRUE), + FALSE, // index words + FALSE, // isExample + 0, // example name + TRUE, // single line + TRUE, // link from index + Config_getBool(MARKDOWN_SUPPORT) + ); + //ol.docify(")"); + } + ol.endIndexValue(cd->getOutputFileBase(),hasBrief); + + } + } + if (!first) ol.endIndexList(); + + ol.popGeneratorState(); + // 2.} + + // --------------- + // interactive group index for HTML + // --------------- + // 2.{ + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + { + if (addToIndex) + { + Doxygen::indexList->addContentsItem(TRUE,title,0,"concepts",0,TRUE,TRUE); + Doxygen::indexList->incContentsDepth(); + } + FTVHelp ftv(false); + for (const auto &nd : *Doxygen::namespaceLinkedMap) + { + writeConceptTreeInsideNamespaceElement(nd.get(),&ftv,true,addToIndex); + } + writeConceptRootList(&ftv,addToIndex); + TextStream t; + ftv.generateTreeViewInline(t); + ol.writeString(t.str().c_str()); + if (addToIndex) + { + Doxygen::indexList->decContentsDepth(); + } + } + ol.popGeneratorState(); + // 2.} + + endFile(ol); + ol.popGeneratorState(); + // 1.} +} + +//---------------------------------------------------------------------------- + static void writeUserGroupStubPage(OutputList &ol,LayoutNavEntry *lne) { if (lne->baseFile().left(9)=="usergroup") @@ -4298,6 +4558,12 @@ static void writeIndex(OutputList &ol) ol.parseText(/*projPrefix+*/(fortranOpt?theTranslator->trModulesIndex():theTranslator->trNamespaceIndex())); ol.endIndexSection(isNamespaceIndex); } + if (documentedConcepts>0) + { + ol.startIndexSection(isConceptIndex); + ol.parseText(/*projPrefix+*/theTranslator->trConceptIndex()); + ol.endIndexSection(isConceptIndex); + } if (hierarchyInterfaces>0) { ol.startIndexSection(isClassHierarchyIndex); @@ -4369,6 +4635,12 @@ static void writeIndex(OutputList &ol) ol.parseText(/*projPrefix+*/(fortranOpt?theTranslator->trModuleDocumentation():theTranslator->trNamespaceDocumentation())); ol.endIndexSection(isNamespaceDocumentation); } + if (documentedConcepts>0) + { + ol.startIndexSection(isConceptDocumentation); + ol.parseText(/*projPrefix+*/theTranslator->trConceptDocumentation()); + ol.endIndexSection(isConceptDocumentation); + } if (annotatedInterfacesPrinted>0) { ol.startIndexSection(isClassDocumentation); @@ -4510,6 +4782,10 @@ static void writeIndexHierarchyEntries(OutputList &ol,const LayoutNavEntryList & writeAnnotatedIndex(ol); } break; + case LayoutNavEntry::Concepts: + msg("Generating concept index...\n"); + writeConceptIndex(ol); + break; case LayoutNavEntry::ClassList: msg("Generating annotated compound index...\n"); writeAnnotatedIndex(ol); @@ -4747,6 +5023,7 @@ static bool quickLinkVisible(LayoutNavEntry::Kind kind) case LayoutNavEntry::Namespaces: return documentedNamespaces>0 && showNamespaces; case LayoutNavEntry::NamespaceList: return documentedNamespaces>0 && showNamespaces; case LayoutNavEntry::NamespaceMembers: return documentedNamespaceMembers[NMHL_All]>0; + case LayoutNavEntry::Concepts: return documentedConcepts>0; case LayoutNavEntry::Classes: return annotatedClasses>0; case LayoutNavEntry::ClassList: return annotatedClasses>0; case LayoutNavEntry::ClassIndex: return annotatedClasses>0; diff --git a/src/index.h b/src/index.h index 8b090dc..a595ec2 100644 --- a/src/index.h +++ b/src/index.h @@ -119,6 +119,7 @@ enum IndexSections isModuleIndex, isDirIndex, isNamespaceIndex, + isConceptIndex, isClassHierarchyIndex, isCompoundIndex, isFileIndex, @@ -127,6 +128,7 @@ enum IndexSections isDirDocumentation, isNamespaceDocumentation, isClassDocumentation, + isConceptDocumentation, isFileDocumentation, isExampleDocumentation, isPageDocumentation, @@ -145,6 +147,7 @@ enum HighlightedItem HLI_InterfaceHierarchy, HLI_ExceptionHierarchy, HLI_Classes, + HLI_Concepts, HLI_Interfaces, HLI_Structs, HLI_Exceptions, @@ -162,6 +165,7 @@ enum HighlightedItem HLI_UserGroup, HLI_ClassVisible, + HLI_ConceptVisible, HLI_InterfaceVisible, HLI_StructVisible, HLI_ExceptionVisible, @@ -238,6 +242,7 @@ extern int hierarchyExceptions; extern int documentedFiles; extern int documentedGroups; extern int documentedNamespaces; +extern int documentedConcepts; extern int indexedPages; extern int documentedClassMembers[CMHL_Total]; extern int documentedFileMembers[FMHL_Total]; diff --git a/src/latexgen.cpp b/src/latexgen.cpp index 0f6d110..92bbfd7 100644 --- a/src/latexgen.cpp +++ b/src/latexgen.cpp @@ -719,6 +719,10 @@ void LatexGenerator::startIndexSection(IndexSections is) if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Namespace Index}\n" break; + case isConceptIndex: + if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; + m_t << "{"; //Concept Index}\n" + break; case isClassHierarchyIndex: if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; m_t << "{"; //Hierarchical Index}\n" @@ -774,6 +778,19 @@ void LatexGenerator::startIndexSection(IndexSections is) } } break; + case isConceptDocumentation: + { + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + if (cd->isLinkableInProject() && !cd->isAlias()) + { + if (compactLatex) m_t << "\\doxysection"; else m_t << "\\chapter"; + m_t << "{"; // Concept Documentation}\n": + break; + } + } + } + break; case isClassDocumentation: { for (const auto &cd : *Doxygen::classLinkedMap) @@ -858,6 +875,9 @@ void LatexGenerator::endIndexSection(IndexSections is) case isNamespaceIndex: m_t << "}\n\\input{namespaces}\n"; break; + case isConceptIndex: + m_t << "}\n\\input{concepts}\n"; + break; case isClassHierarchyIndex: m_t << "}\n\\input{hierarchy}\n"; break; @@ -921,6 +941,23 @@ void LatexGenerator::endIndexSection(IndexSections is) } } break; + case isConceptDocumentation: + { + bool found=FALSE; + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + if (cd->isLinkableInProject() && !cd->isAlias()) + { + if (!found) + { + m_t << "}\n"; + found=true; + } + m_t << "\\input{" << cd->getOutputFileBase() << "}\n"; + } + } + } + break; case isClassDocumentation: { bool found=FALSE; diff --git a/src/latexgen.h b/src/latexgen.h index 4e92280..4a8be62 100644 --- a/src/latexgen.h +++ b/src/latexgen.h @@ -192,6 +192,8 @@ class LatexGenerator : public OutputGenerator void endMemberItem(); void startMemberTemplateParams(); void endMemberTemplateParams(const char *,const char *); + void startCompoundTemplateParams() { startSubsubsection(); } + void endCompoundTemplateParams() { endSubsubsection(); } void startMemberGroupHeader(bool); void endMemberGroupHeader(); diff --git a/src/layout.cpp b/src/layout.cpp index fe71db0..bd88d35 100644 --- a/src/layout.cpp +++ b/src/layout.cpp @@ -319,6 +319,13 @@ class LayoutParser fortranOpt || sliceOpt ? theTranslator->trModulesMemberDescription(extractAll) : theTranslator->trNamespaceMemberDescription(extractAll), "namespacemembers" }, + { "concepts", + LayoutNavEntry::Concepts, + theTranslator->trConcept(true,false), + theTranslator->trConceptList(), + theTranslator->trConceptListDescription(extractAll), + "concepts" + }, { "classindex", LayoutNavEntry::ClassIndex, fortranOpt ? theTranslator->trDataTypes() : vhdlOpt ? theTranslator->trDesignUnits() : theTranslator->trCompoundIndex(), @@ -585,6 +592,19 @@ class LayoutParser m_part = -1; } + void startConcept(const XMLHandlers::Attributes &) + { + LayoutDocManager::instance().clear(LayoutDocManager::Concept); + m_scope="concept/"; + m_part = (int)LayoutDocManager::Concept; + } + + void endConcept() + { + m_scope=""; + m_part = -1; + } + void startFile(const XMLHandlers::Attributes &) { LayoutDocManager::instance().clear(LayoutDocManager::File); @@ -973,6 +993,31 @@ static const std::map< std::string, ElementCallbacks > g_elementHandlers = endCb() } }, + // concept layout handlers + { "concept", { startCb(&LayoutParser::startConcept), + endCb(&LayoutParser::endConcept) + } }, + + { "concept/briefdescription", { startCb(&LayoutParser::startSimpleEntry, LayoutDocEntry::BriefDesc), + endCb() + } }, + { "concept/definition", { startCb(&LayoutParser::startSectionEntry, LayoutDocEntry::ConceptDefinition, + []() { return compileOptions(theTranslator->trConceptDefinition()); }), + endCb() + } }, + { "concept/includes", { startCb(&LayoutParser::startSimpleEntry, LayoutDocEntry::ClassIncludes), + endCb() + } }, + { "concept/sourcelink", { startCb(&LayoutParser::startSimpleEntry, LayoutDocEntry::FileSourceLink), + endCb() + } }, + { "concept/detaileddescription", { startCb(&LayoutParser::startSectionEntry,LayoutDocEntry::DetailedDesc, + []() { return compileOptions(theTranslator->trDetailedDescription()); }), + endCb() + } }, + { "concept/authorsection", { startCb(&LayoutParser::startSimpleEntry, LayoutDocEntry::AuthorSection), + endCb() + } }, // namespace layout handlers { "namespace", { startCb(&LayoutParser::startNamespace), endCb(&LayoutParser::endNamespace) @@ -1016,6 +1061,10 @@ static const std::map< std::string, ElementCallbacks > g_elementHandlers = SrcLangExt_Fortran,theTranslator->trDataTypes()); }), endCb() } }, + { "namespace/memberdecl/concepts", { startCb(&LayoutParser::startSectionEntry, LayoutDocEntry::NamespaceConcepts, + []() { return compileOptions(theTranslator->trConcept(true,false)); }), + endCb() + } }, { "namespace/memberdecl/structs", { startCb(&LayoutParser::startSectionEntry,LayoutDocEntry::NamespaceStructs, []() { return compileOptions(theTranslator->trStructs()); }), endCb() @@ -1135,6 +1184,10 @@ static const std::map< std::string, ElementCallbacks > g_elementHandlers = SrcLangExt_Fortran,theTranslator->trDataTypes()); }), endCb() } }, + { "file/memberdecl/concepts", { startCb(&LayoutParser::startSectionEntry, LayoutDocEntry::FileConcepts, + []() { return compileOptions(theTranslator->trConcept(true,false)); }), + endCb() + } }, { "file/memberdecl/structs", { startCb(&LayoutParser::startSectionEntry,LayoutDocEntry::FileStructs, []() { return compileOptions(theTranslator->trStructs()); }), endCb() @@ -1255,6 +1308,10 @@ static const std::map< std::string, ElementCallbacks > g_elementHandlers = []() { return compileOptions(/* default */ theTranslator->trCompounds(), SrcLangExt_VHDL, theTranslator->trVhdlType(VhdlDocGen::ENTITY,FALSE), SrcLangExt_Fortran, theTranslator->trDataTypes()); }), + endCb() + } }, + { "group/memberdecl/concepts", { startCb(&LayoutParser::startSectionEntry, LayoutDocEntry::GroupConcepts, + []() { return compileOptions(theTranslator->trConcept(true,false)); }), endCb() } }, { "group/memberdecl/namespaces", { startCb(&LayoutParser::startSectionEntry, LayoutDocEntry::GroupNamespaces, diff --git a/src/layout.h b/src/layout.h index 851af22..900d192 100644 --- a/src/layout.h +++ b/src/layout.h @@ -45,19 +45,22 @@ struct LayoutDocEntry ClassCollaborationGraph, ClassAllMembersLink, ClassUsedFiles, + // Concept specific items + ConceptDefinition, + // Namespace specific items NamespaceNestedNamespaces, NamespaceNestedConstantGroups, - NamespaceClasses, NamespaceInterfaces, NamespaceStructs, NamespaceExceptions, + NamespaceClasses, NamespaceConcepts, NamespaceInterfaces, NamespaceStructs, NamespaceExceptions, NamespaceInlineClasses, // File specific items - FileClasses, FileInterfaces, FileStructs, FileExceptions, FileConstantGroups, FileNamespaces, + FileClasses, FileConcepts, FileInterfaces, FileStructs, FileExceptions, FileConstantGroups, FileNamespaces, FileIncludes, FileIncludeGraph, FileIncludedByGraph, FileSourceLink, FileInlineClasses, // Group specific items - GroupClasses, GroupInlineClasses, GroupNamespaces, + GroupClasses, GroupConcepts, GroupInlineClasses, GroupNamespaces, GroupDirs, GroupNestedGroups, GroupFiles, GroupGraph, GroupPageDocs, @@ -130,6 +133,7 @@ struct LayoutNavEntry Namespaces, NamespaceList, NamespaceMembers, + Concepts, Classes, ClassList, ClassIndex, @@ -196,7 +200,7 @@ class LayoutDocManager public: enum LayoutPart { - Class, Namespace, File, Group, Directory, + Class, Concept, Namespace, File, Group, Directory, NrParts }; /** Returns a reference to this singleton. */ diff --git a/src/mangen.h b/src/mangen.h index e621988..8b9c3cd 100644 --- a/src/mangen.h +++ b/src/mangen.h @@ -111,6 +111,8 @@ class ManGenerator : public OutputGenerator void endMemberItem(); void startMemberTemplateParams() {} void endMemberTemplateParams(const char *,const char *) {} + void startCompoundTemplateParams() { startSubsubsection(); } + void endCompoundTemplateParams() { endSubsubsection(); } void startMemberGroupHeader(bool); void endMemberGroupHeader(); diff --git a/src/memberdef.cpp b/src/memberdef.cpp index 38164ef..4e9f4a9 100644 --- a/src/memberdef.cpp +++ b/src/memberdef.cpp @@ -4074,6 +4074,10 @@ void MemberDefImpl::setAnchor() buf[19]='\0'; memAnchor.prepend(buf); } + if (!m_impl->requiresClause.isEmpty()) + { + memAnchor+=" "+m_impl->requiresClause; + } // convert to md5 hash uchar md5_sig[16]; diff --git a/src/namespacedef.cpp b/src/namespacedef.cpp index d392f69..4bfaa2b 100644 --- a/src/namespacedef.cpp +++ b/src/namespacedef.cpp @@ -32,6 +32,7 @@ #include "config.h" #include "definitionimpl.h" #include "membername.h" +#include "conceptdef.h" //------------------------------------------------------------------ static QCString makeDisplayName(const NamespaceDef *nd,bool includeScope) @@ -65,6 +66,7 @@ class NamespaceDefImpl : public DefinitionMixin virtual void writeQuickMemberLinks(OutputList &ol,const MemberDef *currentMd) const; virtual void writeTagFile(TextStream &); virtual void insertClass(const ClassDef *cd); + virtual void insertConcept(const ConceptDef *cd); virtual void insertNamespace(const NamespaceDef *nd); virtual void insertMember(MemberDef *md); virtual void computeAnchors(); @@ -103,6 +105,7 @@ class NamespaceDefImpl : public DefinitionMixin virtual ClassLinkedRefMap getStructs() const { return structs; } virtual ClassLinkedRefMap getExceptions() const { return exceptions; } virtual NamespaceLinkedRefMap getNamespaces() const { return namespaces; } + virtual ConceptLinkedRefMap getConcepts() const { return m_concepts; } virtual QCString title() const; virtual QCString compoundTypeString() const; @@ -118,6 +121,7 @@ class NamespaceDefImpl : public DefinitionMixin void startMemberDeclarations(OutputList &ol); void endMemberDeclarations(OutputList &ol); void writeClassDeclarations(OutputList &ol,const QCString &title,const ClassLinkedRefMap &d); + void writeConcepts(OutputList &ol,const QCString &title); void writeInlineClasses(OutputList &ol); void writeMemberGroups(OutputList &ol); void writeAuthorSection(OutputList &ol); @@ -126,6 +130,7 @@ class NamespaceDefImpl : public DefinitionMixin void writeSummaryLinks(OutputList &ol) const; void addNamespaceAttributes(OutputList &ol); void writeClassesToTagFile(TextStream &,const ClassLinkedRefMap &d); + void writeConceptsToTagFile(TextStream &); void writeNamespaceDeclarations(OutputList &ol,const QCString &title, bool isConstantGroup=false); @@ -144,6 +149,7 @@ class NamespaceDefImpl : public DefinitionMixin ClassLinkedRefMap interfaces; ClassLinkedRefMap structs; ClassLinkedRefMap exceptions; + ConceptLinkedRefMap m_concepts; NamespaceLinkedRefMap namespaces; bool m_subGrouping = false; enum { NAMESPACE, MODULE, CONSTANT_GROUP, LIBRARY } m_type; @@ -223,6 +229,8 @@ class NamespaceDefAliasImpl : public DefinitionAliasMixin { return getNSAlias()->getExceptions(); } virtual NamespaceLinkedRefMap getNamespaces() const { return getNSAlias()->getNamespaces(); } + virtual ConceptLinkedRefMap getConcepts() const + { return getNSAlias()->getConcepts(); } virtual QCString title() const { return getNSAlias()->title(); } virtual QCString compoundTypeString() const @@ -345,6 +353,10 @@ void NamespaceDefImpl::addInnerCompound(const Definition *d) { insertClass(toClassDef(d)); } + else if (d->definitionType()==Definition::TypeConcept) + { + insertConcept(toConceptDef(d)); + } } void NamespaceDefImpl::insertClass(const ClassDef *cd) @@ -370,6 +382,11 @@ void NamespaceDefImpl::insertClass(const ClassDef *cd) d.add(cd->name(),cd); } +void NamespaceDefImpl::insertConcept(const ConceptDef *cd) +{ + m_concepts.add(cd->name(),cd); +} + void NamespaceDefImpl::insertNamespace(const NamespaceDef *nd) { namespaces.add(nd->name(),nd); @@ -578,6 +595,11 @@ void NamespaceDefImpl::writeTagFile(TextStream &tagFile) writeClassesToTagFile(tagFile, exceptions); } break; + case LayoutDocEntry::NamespaceConcepts: + { + writeConceptsToTagFile(tagFile); + } + break; case LayoutDocEntry::MemberDecl: { const LayoutDocEntryMemberDecl *lmd = (const LayoutDocEntryMemberDecl*)lde.get(); @@ -740,6 +762,11 @@ void NamespaceDefImpl::writeClassDeclarations(OutputList &ol,const QCString &tit d.writeDeclaration(ol,0,title,TRUE); } +void NamespaceDefImpl::writeConcepts(OutputList &ol,const QCString &title) +{ + m_concepts.writeDeclaration(ol,title,TRUE); +} + void NamespaceDefImpl::writeInlineClasses(OutputList &ol) { classes.writeDocumentation(ol,this); @@ -819,6 +846,13 @@ void NamespaceDefImpl::writeSummaryLinks(OutputList &ol) const ol.writeSummaryLink(0,label,ls->title(lang),first); first=FALSE; } + else if (lde->kind()==LayoutDocEntry::NamespaceConcepts && m_concepts.declVisible()) + { + const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get(); + QCString label = "concepts"; + ol.writeSummaryLink(0,label,ls->title(lang),first); + first=FALSE; + } else if (lde->kind()== LayoutDocEntry::MemberDecl) { const LayoutDocEntryMemberDecl *lmd = (const LayoutDocEntryMemberDecl*)lde.get(); @@ -863,6 +897,17 @@ void NamespaceDefImpl::writeClassesToTagFile(TextStream &tagFile,const ClassLink } } +void NamespaceDefImpl::writeConceptsToTagFile(TextStream &tagFile) +{ + for (const auto &cd : m_concepts) + { + if (cd->isLinkableInProject()) + { + tagFile << " " << convertToXML(cd->name()) << "\n"; + } + } +} + void NamespaceDefImpl::writeDocumentation(OutputList &ol) { static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); @@ -933,6 +978,12 @@ void NamespaceDefImpl::writeDocumentation(OutputList &ol) writeClassDeclarations(ol,ls->title(lang),exceptions); } break; + case LayoutDocEntry::NamespaceConcepts: + { + const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get(); + writeConcepts(ol,ls->title(lang)); + } + break; case LayoutDocEntry::NamespaceNestedNamespaces: { const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get(); @@ -988,7 +1039,9 @@ void NamespaceDefImpl::writeDocumentation(OutputList &ol) case LayoutDocEntry::ClassAllMembersLink: case LayoutDocEntry::ClassUsedFiles: case LayoutDocEntry::ClassInlineClasses: + case LayoutDocEntry::ConceptDefinition: case LayoutDocEntry::FileClasses: + case LayoutDocEntry::FileConcepts: case LayoutDocEntry::FileInterfaces: case LayoutDocEntry::FileStructs: case LayoutDocEntry::FileExceptions: @@ -1000,6 +1053,7 @@ void NamespaceDefImpl::writeDocumentation(OutputList &ol) case LayoutDocEntry::FileSourceLink: case LayoutDocEntry::FileInlineClasses: case LayoutDocEntry::GroupClasses: + case LayoutDocEntry::GroupConcepts: case LayoutDocEntry::GroupInlineClasses: case LayoutDocEntry::GroupNamespaces: case LayoutDocEntry::GroupDirs: @@ -1449,7 +1503,7 @@ QCString NamespaceDefImpl::compoundTypeString() const } else if(lang==SrcLangExt_CSharp) { - return "namespace"; + return "namespace"; } else if (lang==SrcLangExt_Fortran) { @@ -1474,7 +1528,7 @@ QCString NamespaceDefImpl::compoundTypeString() const err_full(getDefFileName(),getDefLine(),"Internal inconsistency: namespace in IDL not module, library or constant group"); } } - return ""; + return "namespace"; } void NamespaceDefImpl::setMetaData(const QCString &m) diff --git a/src/namespacedef.h b/src/namespacedef.h index 0dc0005..711c9df 100644 --- a/src/namespacedef.h +++ b/src/namespacedef.h @@ -25,8 +25,10 @@ class MemberList; class ClassDef; +class ConceptDef; class OutputList; class ClassLinkedRefMap; +class ConceptLinkedRefMap; class MemberDef; class NamespaceDef; class NamespaceDef; @@ -94,6 +96,9 @@ class NamespaceDef : public Definition /*! Returns the namespaces contained in this namespace */ virtual NamespaceLinkedRefMap getNamespaces() const = 0; + /*! Returns the concepts contained in this namespace */ + virtual ConceptLinkedRefMap getConcepts() const = 0; + virtual QCString title() const = 0; virtual QCString compoundTypeString() const = 0; }; @@ -110,6 +115,7 @@ class NamespaceDefMutable : public DefinitionMutable, public NamespaceDef virtual void writeQuickMemberLinks(OutputList &ol,const MemberDef *currentMd) const = 0; virtual void writeTagFile(TextStream &) = 0; virtual void insertClass(const ClassDef *cd) = 0; + virtual void insertConcept(const ConceptDef *cd) = 0; virtual void insertNamespace(const NamespaceDef *nd) = 0; virtual void insertMember(MemberDef *md) = 0; // md cannot be const, since setSectionList is called on it virtual void computeAnchors() = 0; diff --git a/src/outputgen.h b/src/outputgen.h index 9eab898..6cfb14b 100644 --- a/src/outputgen.h +++ b/src/outputgen.h @@ -404,6 +404,8 @@ class OutputGenerator : public BaseOutputDocInterface virtual void endMemberItem() = 0; virtual void startMemberTemplateParams() = 0; virtual void endMemberTemplateParams(const char *,const char *) = 0; + virtual void startCompoundTemplateParams() = 0; + virtual void endCompoundTemplateParams() = 0; virtual void startMemberGroupHeader(bool) = 0; virtual void endMemberGroupHeader() = 0; virtual void startMemberGroupDocs() = 0; diff --git a/src/outputlist.h b/src/outputlist.h index 7baef7a..fbb8801 100644 --- a/src/outputlist.h +++ b/src/outputlist.h @@ -213,6 +213,10 @@ class OutputList : public OutputDocInterface { forall(&OutputGenerator::startMemberTemplateParams); } void endMemberTemplateParams(const char *anchor,const char *inheritId) { forall(&OutputGenerator::endMemberTemplateParams,anchor,inheritId); } + void startCompoundTemplateParams() + { forall(&OutputGenerator::startCompoundTemplateParams); } + void endCompoundTemplateParams() + { forall(&OutputGenerator::endCompoundTemplateParams); } void startMemberGroupHeader(bool b) { forall(&OutputGenerator::startMemberGroupHeader,b); } void endMemberGroupHeader() diff --git a/src/parserintf.h b/src/parserintf.h index 05b3adf..9c43e93 100644 --- a/src/parserintf.h +++ b/src/parserintf.h @@ -88,9 +88,9 @@ class CodeParserInterface /** Parses a source file or fragment with the goal to produce * highlighted and cross-referenced output. * @param[in] codeOutIntf Abstract interface for writing the result. - * @param[in] lang The programming language of the code fragment. * @param[in] scopeName Name of scope to which the code belongs. * @param[in] input Actual code in the form of a string + * @param[in] lang The programming language of the code fragment. * @param[in] isExampleBlock TRUE iff the code is part of an example. * @param[in] exampleName Name of the example. * @param[in] fileDef File definition to which the code diff --git a/src/perlmodgen.cpp b/src/perlmodgen.cpp index ab931f9..6bf7319 100644 --- a/src/perlmodgen.cpp +++ b/src/perlmodgen.cpp @@ -1434,6 +1434,11 @@ static void addTemplateList(const ClassDef *cd,PerlModOutput &output) addTemplateArgumentList(cd->templateArguments(),output,cd->name()); } +static void addTemplateList(const ConceptDef *cd,PerlModOutput &output) +{ + addTemplateArgumentList(cd->getTemplateParameterList(),output,cd->name()); +} + static void addPerlModDocBlock(PerlModOutput &output, const char *name, const QCString &fileName, @@ -1516,7 +1521,9 @@ public: void generatePerlModSection(const Definition *d, MemberList *ml, const char *name, const char *header=0); void addListOfAllMembers(const ClassDef *cd); + void addIncludeInfo(const IncludeInfo *ii); void generatePerlModForClass(const ClassDef *cd); + void generatePerlModForConcept(const ConceptDef *cd); void generatePerlModForNamespace(const NamespaceDef *nd); void generatePerlModForFile(const FileDef *fd); void generatePerlModForGroup(const GroupDef *gd); @@ -1780,6 +1787,22 @@ void PerlModGenerator::generatePerlUserDefinedSection(const Definition *d, const } } +void PerlModGenerator::addIncludeInfo(const IncludeInfo *ii) +{ + if (ii) + { + QCString nm = ii->includeName; + if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName(); + if (!nm.isEmpty()) + { + m_output.openHash("includes"); + m_output.addFieldBoolean("local", ii->local) + .addFieldQuotedString("name", nm) + .closeHash(); + } + } +} + void PerlModGenerator::generatePerlModForClass(const ClassDef *cd) { // + brief description @@ -1844,23 +1867,7 @@ void PerlModGenerator::generatePerlModForClass(const ClassDef *cd) m_output.closeList(); } - const IncludeInfo *ii=cd->includeInfo(); - if (ii) - { - QCString nm = ii->includeName; - if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName(); - if (!nm.isEmpty()) - { - m_output.openHash("includes"); -#if 0 - if (ii->fileDef && !ii->fileDef->isReference()) // TODO: support external references - t << " id=\"" << ii->fileDef->getOutputFileBase() << "\""; -#endif - m_output.addFieldBoolean("local", ii->local) - .addFieldQuotedString("name", nm) - .closeHash(); - } - } + addIncludeInfo(cd->includeInfo()); addTemplateList(cd,m_output); addListOfAllMembers(cd); @@ -1922,6 +1929,22 @@ void PerlModGenerator::generatePerlModForClass(const ClassDef *cd) m_output.closeHash(); } +void PerlModGenerator::generatePerlModForConcept(const ConceptDef *cd) +{ + if (cd->isReference()) return; // skip external references + + m_output.openHash() + .addFieldQuotedString("name", cd->name()); + + addIncludeInfo(cd->includeInfo()); + addTemplateList(cd,m_output); + m_output.addFieldQuotedString("initializer", cd->initializer()); + addPerlModDocBlock(m_output,"brief",cd->getDefFileName(),cd->getDefLine(),0,0,cd->briefDescription()); + addPerlModDocBlock(m_output,"detailed",cd->getDefFileName(),cd->getDefLine(),0,0,cd->documentation()); + + m_output.closeHash(); +} + void PerlModGenerator::generatePerlModForNamespace(const NamespaceDef *nd) { // + contained class definitions @@ -2154,6 +2177,11 @@ bool PerlModGenerator::generatePerlModOutput() generatePerlModForClass(cd.get()); m_output.closeList(); + m_output.openList("concepts"); + for (const auto &cd : *Doxygen::conceptLinkedMap) + generatePerlModForConcept(cd.get()); + m_output.closeList(); + m_output.openList("namespaces"); for (const auto &nd : *Doxygen::namespaceLinkedMap) generatePerlModForNamespace(nd.get()); diff --git a/src/rtfgen.cpp b/src/rtfgen.cpp index 91e4996..032d568 100644 --- a/src/rtfgen.cpp +++ b/src/rtfgen.cpp @@ -447,6 +447,10 @@ void RTFGenerator::startIndexSection(IndexSections is) //Namespace Index beginRTFChapter(); break; + case isConceptIndex: + //Concept Index + beginRTFChapter(); + break; case isClassHierarchyIndex: //Hierarchical Index DBG_RTF(m_t << "{\\comment start classhierarchy}\n") @@ -503,6 +507,19 @@ void RTFGenerator::startIndexSection(IndexSections is) } } break; + case isConceptDocumentation: + { + // Concept Documentation + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + if (cd->isLinkableInProject()) + { + beginRTFChapter(); + break; + } + } + } + break; case isClassDocumentation: { //Compound Documentation @@ -700,6 +717,11 @@ void RTFGenerator::endIndexSection(IndexSections is) m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"namespaces.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; + case isConceptIndex: + m_t << "\\par " << rtf_Style_Reset << "\n"; + m_t << "{\\tc \\v " << theTranslator->trConceptIndex() << "}\n"; + m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"concepts.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + break; case isClassHierarchyIndex: m_t << "\\par " << rtf_Style_Reset << "\n"; m_t << "{\\tc \\v " << theTranslator->trHierarchicalIndex() << "}\n"; @@ -793,6 +815,26 @@ void RTFGenerator::endIndexSection(IndexSections is) } } break; + case isConceptDocumentation: + { + bool first=true; + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + if (cd->isLinkableInProject() && !cd->isAlias()) + { + m_t << "\\par " << rtf_Style_Reset << "\n"; + if (!first) + { + beginRTFSection(); + } + first=false; + m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + m_t << cd->getOutputFileBase(); + m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + } + } + } + break; case isClassDocumentation: { bool first=true; diff --git a/src/rtfgen.h b/src/rtfgen.h index b1ae9f1..344121c 100644 --- a/src/rtfgen.h +++ b/src/rtfgen.h @@ -117,6 +117,8 @@ class RTFGenerator : public OutputGenerator void endMemberItem(); void startMemberTemplateParams() {} void endMemberTemplateParams(const char *,const char *) {} + void startCompoundTemplateParams() { startSubsubsection(); } + void endCompoundTemplateParams() { endSubsubsection(); } void insertMemberAlign(bool) {} void insertMemberAlignLeft(int,bool){} diff --git a/src/scanner.l b/src/scanner.l index 9e719d0..a37ff09 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -445,6 +445,8 @@ NONLopt [^\n]* /** C++20 concepts */ %x RequiresClause +%x RequiresExpression +%x ConceptName %% @@ -1622,6 +1624,19 @@ NONLopt [^\n]* if (yytext[yyleng-1]=='{') unput('{'); BEGIN( CompoundName ) ; } +{B}*"concept"{BN}+ { // C++20 concept + yyextra->isTypedef=FALSE; + yyextra->current->section = Entry::CONCEPT_SEC; + addType(yyscanner); + yyextra->current->type += " concept"; + yyextra->current->fileName = yyextra->yyFileName; + yyextra->current->startLine = yyextra->yyLineNr; + yyextra->current->startColumn = yyextra->yyColNr; + yyextra->current->bodyLine = yyextra->yyLineNr; + yyextra->current->bodyColumn = yyextra->yyColNr; + lineCount(yyscanner) ; + BEGIN( ConceptName ) ; + } "("{BN}*")"({BN}*"<"[^>]*">"){BNopt}/"(" { // A::operator()(int arg) lineCount(yyscanner); yyextra->current->name += "()"; @@ -2075,6 +2090,7 @@ NONLopt [^\n]* } "friend"{BN}+("class"|"union"|"struct"){BN}+ { yyextra->current->name=yytext; + lineCount(yyscanner) ; BEGIN(FindMembers); } "requires" { // C++20 requires clause @@ -2082,6 +2098,28 @@ NONLopt [^\n]* yyextra->requiresContext = YY_START; BEGIN(RequiresClause); } +"requires"{BN}*"(" { // requires requires(T x) { ... } + lineCount(yyscanner) ; + yyextra->current->req+=yytext; + yyextra->lastRoundContext=RequiresExpression; + yyextra->pCopyRoundString=&yyextra->current->req; + yyextra->roundCount=0; + BEGIN( CopyRound ) ; + } +"{" { + yyextra->current->req+=yytext; + yyextra->lastCurlyContext=RequiresClause; + yyextra->pCopyCurlyString=&yyextra->current->req; + yyextra->curlyCount=0; + BEGIN( CopyCurly ) ; + } +\n { + yyextra->current->req+=' '; + lineCount(yyextra); + } +. { + yyextra->current->req+=yytext; + } "(" { // requires "(A && B)" yyextra->current->req+=yytext; yyextra->lastRoundContext=RequiresClause; @@ -2119,6 +2157,7 @@ NONLopt [^\n]* } {BN}+ { yyextra->current->req+=' '; + lineCount(yyscanner) ; } . { unput(*yytext); @@ -2126,7 +2165,6 @@ NONLopt [^\n]* BEGIN(yyextra->requiresContext); } {SCOPENAME} { - if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); @@ -3314,7 +3352,12 @@ NONLopt [^\n]* yyextra->current->type.prepend("typedef "); } bool stat = yyextra->current->stat; - if (!yyextra->current->name.isEmpty() && yyextra->current->section!=Entry::ENUM_SEC) + if (yyextra->current->section==Entry::CONCEPT_SEC) // C++20 concept + { + yyextra->current_root->moveToSubEntryAndRefresh( yyextra->current ) ; + initEntry(yyscanner); + } + else if (!yyextra->current->name.isEmpty() && yyextra->current->section!=Entry::ENUM_SEC) { yyextra->current->type=yyextra->current->type.simplifyWhiteSpace(); yyextra->current->args=removeRedundantWhiteSpace(yyextra->current->args); @@ -5514,6 +5557,17 @@ NONLopt [^\n]* } \n { lineCount(yyscanner); } . +{ID} { + yyextra->current->name = yytext ; + } +"=" { + yyextra->current->bodyLine = yyextra->yyLineNr; + yyextra->current->bodyColumn = yyextra->yyColNr; + yyextra->current->initializer.str(std::string()); + yyextra->lastInitializerContext = FindMembers; + yyextra->initBracketCount=0; + BEGIN(ReadInitializer); + } {SCOPENAME}/{BN}*"," { // multiple forward declarations on one line // e.g. @protocol A,B; yyextra->current->reset(); diff --git a/src/searchindex.cpp b/src/searchindex.cpp index cd048c4..2b8df67 100644 --- a/src/searchindex.cpp +++ b/src/searchindex.cpp @@ -36,6 +36,7 @@ #include "namespacedef.h" #include "classdef.h" #include "utf8.h" +#include "classlist.h" //--------------------------------------------------------------------------------------------- // the following part is for the server based search engine @@ -452,6 +453,8 @@ static QCString definitionToName(const Definition *ctx) return "file"; case Definition::TypeNamespace: return "namespace"; + case Definition::TypeConcept: + return "concept"; case Definition::TypeGroup: return "group"; case Definition::TypePackage: @@ -593,6 +596,7 @@ QCString searchId(const Definition *d) #define SEARCH_INDEX_DEFINES 17 #define SEARCH_INDEX_GROUPS 18 #define SEARCH_INDEX_PAGES 19 +#define SEARCH_INDEX_CONCEPTS 20 static std::array g_searchIndexInfo = { { @@ -622,7 +626,8 @@ static std::array g_searchIndexInfo = { /* SEARCH_INDEX_RELATED */ "related" , []() { return theTranslator->trFriends(); }, {} }, { /* SEARCH_INDEX_DEFINES */ "defines" , []() { return theTranslator->trDefines(); }, {} }, { /* SEARCH_INDEX_GROUPS */ "groups" , []() { return theTranslator->trGroup(TRUE,FALSE); }, {} }, - { /* SEARCH_INDEX_PAGES */ "pages" , []() { return theTranslator->trPage(TRUE,FALSE); }, {} } + { /* SEARCH_INDEX_PAGES */ "pages" , []() { return theTranslator->trPage(TRUE,FALSE); }, {} }, + { /* SEARCH_INDEX_CONCEPTS */ "concepts" , []() { return theTranslator->trConcept(true,false); }, {} } } }; static void addMemberToSearchIndex(const MemberDef *md) @@ -791,6 +796,17 @@ void createJavaScriptSearchIndex() } } + // index concepts + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + std::string letter = convertUTF8ToLower(getUTF8CharAt(cd->name().str(),0)); + if (cd->isLinkable()) + { + g_searchIndexInfo[SEARCH_INDEX_ALL].add(letter,cd.get()); + g_searchIndexInfo[SEARCH_INDEX_CONCEPTS].add(letter,cd.get()); + } + } + // index files for (const auto &fn : *Doxygen::inputNameLinkedMap) { diff --git a/src/searchindex.h b/src/searchindex.h index ee56b08..0da7828 100644 --- a/src/searchindex.h +++ b/src/searchindex.h @@ -109,7 +109,7 @@ class SearchIndexExternal : public SearchIndexIntf //------- client side search index ---------------------- -#define NUM_SEARCH_INDICES 20 +#define NUM_SEARCH_INDICES 21 QCString searchId(const Definition *d); QCString searchName(const Definition *d); diff --git a/src/sqlite3gen.cpp b/src/sqlite3gen.cpp index 49cf00c..855f703 100644 --- a/src/sqlite3gen.cpp +++ b/src/sqlite3gen.cpp @@ -1372,9 +1372,15 @@ static void writeMemberTemplateLists(const MemberDef *md) { writeTemplateArgumentList(md->templateArguments(),md->getClassDef(),md->getFileDef()); } + static void writeTemplateList(const ClassDef *cd) { - writeTemplateArgumentList(cd->templateArguments(),cd,0); + writeTemplateArgumentList(cd->templateArguments(),cd,cd->getFileDef()); +} + +static void writeTemplateList(const ConceptDef *cd) +{ + writeTemplateArgumentList(cd->getTemplateParameterList(),cd,cd->getFileDef()); } QCString getSQLDocBlock(const Definition *scope, @@ -2003,6 +2009,30 @@ static void generateSqlite3ForClass(const ClassDef *cd) associateAllClassMembers(cd, refid); } +static void generateSqlite3ForConcept(const ConceptDef *cd) +{ + if (cd->isReference() || cd->isHidden()) return; // skip external references + + struct Refid refid = insertRefid(cd->getOutputFileBase()); + if(!refid.created && compounddefExists(refid)){return;} + bindIntParameter(compounddef_insert,":rowid", refid.rowid); + bindTextParameter(compounddef_insert,":name",cd->name()); + bindTextParameter(compounddef_insert,":kind","concept"); + + int file_id = insertPath(cd->getDefFileName()); + bindIntParameter(compounddef_insert,":file_id",file_id); + bindIntParameter(compounddef_insert,":line",cd->getDefLine()); + bindIntParameter(compounddef_insert,":column",cd->getDefColumn()); + + getSQLDesc(compounddef_insert,":briefdescription",cd->briefDescription(),cd); + getSQLDesc(compounddef_insert,":detaileddescription",cd->documentation(),cd); + + step(compounddef_insert); + + // + template argument list(s) + writeTemplateList(cd); +} + // kinds: constants library module namespace package static void generateSqlite3ForNamespace(const NamespaceDef *nd) { @@ -2477,6 +2507,13 @@ void generateSqlite3() generateSqlite3ForClass(cd.get()); } + // + concepts + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + msg("Generating Sqlite3 output for concept %s\n",cd->name().data()); + generateSqlite3ForConcept(cd.get()); + } + // + namespaces for (const auto &nd : *Doxygen::namespaceLinkedMap) { diff --git a/src/tagreader.cpp b/src/tagreader.cpp index 786c851..cb9b537 100644 --- a/src/tagreader.cpp +++ b/src/tagreader.cpp @@ -96,7 +96,7 @@ class TagMemberInfo class TagCompoundInfo { public: - enum class CompoundType { Class, Namespace, Package, File, Group, Page, Dir }; + enum class CompoundType { Class, Concept, Namespace, Package, File, Group, Page, Dir }; explicit TagCompoundInfo(CompoundType type) : m_type(type) {} virtual ~TagCompoundInfo() {} CompoundType compoundType() const { return m_type; } @@ -131,6 +131,22 @@ class TagClassInfo : public TagCompoundInfo } }; +/** Container for concept specific info that can be read from a tagfile */ +class TagConceptInfo : public TagCompoundInfo +{ + public: + TagConceptInfo() :TagCompoundInfo(CompoundType::Concept) {} + std::string clangId; + static TagConceptInfo *get(std::unique_ptr &t) + { + return dynamic_cast(t.get()); + } + static const TagConceptInfo *get(const std::unique_ptr &t) + { + return dynamic_cast(t.get()); + } +}; + /** Container for namespace specific info that can be read from a tagfile */ class TagNamespaceInfo : public TagCompoundInfo { @@ -138,6 +154,7 @@ class TagNamespaceInfo : public TagCompoundInfo TagNamespaceInfo() :TagCompoundInfo(CompoundType::Namespace) {} std::string clangId; StringVector classList; + StringVector conceptList; StringVector namespaceList; static TagNamespaceInfo *get(std::unique_ptr &t) { @@ -172,6 +189,7 @@ class TagFileInfo : public TagCompoundInfo TagFileInfo() : TagCompoundInfo(CompoundType::File) { } std::string path; StringVector classList; + StringVector conceptList; StringVector namespaceList; std::vector includes; static TagFileInfo *get(std::unique_ptr &t) @@ -192,6 +210,7 @@ class TagGroupInfo : public TagCompoundInfo std::string title; StringVector subgroupList; StringVector classList; + StringVector conceptList; StringVector namespaceList; StringVector fileList; StringVector pageList; @@ -279,6 +298,7 @@ class TagFileParser switch (m_state) { case InClass: + case InConcept: case InFile: case InNamespace: case InGroup: @@ -379,6 +399,7 @@ class TagFileParser switch(m_state) { case InClass: + case InConcept: case InFile: case InNamespace: case InGroup: @@ -395,6 +416,7 @@ class TagFileParser switch(m_state) { case InClass: + case InConcept: case InFile: case InNamespace: case InGroup: @@ -435,6 +457,25 @@ class TagFileParser } } + void endConcept() + { + switch(m_state) + { + case InNamespace: + TagNamespaceInfo::get(m_curCompound)->conceptList.push_back(m_curString); + break; + case InFile: + TagFileInfo::get(m_curCompound)->conceptList.push_back(m_curString); + break; + case InGroup: + TagGroupInfo::get(m_curCompound)->conceptList.push_back(m_curString); + break; + default: + warn("Unexpected tag 'concept' found"); + break; + } + } + void endNamespace() { switch(m_state) @@ -525,6 +566,7 @@ class TagFileParser switch (m_state) { case InClass: + case InConcept: case InFile: case InNamespace: case InGroup: @@ -623,6 +665,7 @@ class TagFileParser switch (m_state) { case InClass: + case InConcept: case InNamespace: case InFile: case InGroup: @@ -757,6 +800,7 @@ class TagFileParser enum State { Invalid, InClass, + InConcept, InFile, InNamespace, InGroup, @@ -839,6 +883,7 @@ static const std::map< std::string, ElementCallbacks > g_elementHandlers = { "title", { startCb(&TagFileParser::startStringValue ), endCb(&TagFileParser::endTitle ) } }, { "subgroup", { startCb(&TagFileParser::startStringValue ), endCb(&TagFileParser::endSubgroup ) } }, { "class", { startCb(&TagFileParser::startStringValue ), endCb(&TagFileParser::endClass ) } }, + { "concept", { startCb(&TagFileParser::startStringValue ), endCb(&TagFileParser::endConcept ) } }, { "namespace", { startCb(&TagFileParser::startStringValue ), endCb(&TagFileParser::endNamespace ) } }, { "file", { startCb(&TagFileParser::startStringValue ), endCb(&TagFileParser::endFile ) } }, { "dir", { startCb(&TagFileParser::startStringValue ), endCb(&TagFileParser::endDir ) } }, @@ -874,6 +919,7 @@ static const std::map< std::string, CompoundFactory > g_compoundFactory = { "singleton", { TagFileParser::InClass, []() { return std::make_unique(TagClassInfo::Kind::Singleton); } } }, { "file", { TagFileParser::InFile, []() { return std::make_unique(); } } }, { "namespace", { TagFileParser::InNamespace, []() { return std::make_unique(); } } }, + { "concept", { TagFileParser::InConcept, []() { return std::make_unique(); } } }, { "group", { TagFileParser::InGroup, []() { return std::make_unique(); } } }, { "page", { TagFileParser::InPage, []() { return std::make_unique(); } } }, { "package", { TagFileParser::InPackage, []() { return std::make_unique(); } } }, @@ -962,6 +1008,17 @@ void TagFileParser::dump() } } } + //============== CONCEPTS + for (const auto &comp : m_tagFileCompounds) + { + if (comp->compoundType()==TagCompoundInfo::CompoundType::Concept) + { + const TagConceptInfo *cd = TagConceptInfo::get(comp); + + msg("concept '%s'\n",cd->name.data()); + msg(" filename '%s'\n",cd->filename.data()); + } + } //============== NAMESPACES for (const auto &comp : m_tagFileCompounds) { @@ -1342,6 +1399,26 @@ void TagFileParser::buildLists(const std::shared_ptr &root) } } + // build concept list + for (const auto &comp : m_tagFileCompounds) + { + if (comp->compoundType()==TagCompoundInfo::CompoundType::Concept) + { + const TagConceptInfo *tci = TagConceptInfo::get(comp); + + std::shared_ptr ce = std::make_shared(); + ce->section = Entry::CONCEPT_SEC; + ce->name = tci->name; + addDocAnchors(ce,tci->docAnchors); + ce->tagInfoData.tagName = m_tagName; + ce->tagInfoData.fileName = tci->filename; + ce->hasTagInfo = TRUE; + ce->id = tci->clangId; + + root->moveToSubEntryAndKeep(ce); + } + } + // build namespace list for (const auto &comp : m_tagFileCompounds) { diff --git a/src/translator.h b/src/translator.h index bcc70ff..89e4216 100644 --- a/src/translator.h +++ b/src/translator.h @@ -657,6 +657,18 @@ class Translator ////////////////////////////////////////////////////////////////////////// virtual QCString trDesignUnitDocumentation() = 0; + +////////////////////////////////////////////////////////////////////////// +// new since 1.9.2 +////////////////////////////////////////////////////////////////////////// + + virtual QCString trConcept(bool first_capital, bool singular) = 0; + virtual QCString trConceptReference(const char *conceptName) = 0; + virtual QCString trConceptList() = 0; + virtual QCString trConceptIndex() = 0; + virtual QCString trConceptDocumentation() = 0; + virtual QCString trConceptListDescription(bool extractAll) = 0; + virtual QCString trConceptDefinition() = 0; }; #endif diff --git a/src/translator_adapter.h b/src/translator_adapter.h index 388304c..ad08910 100644 --- a/src/translator_adapter.h +++ b/src/translator_adapter.h @@ -41,7 +41,35 @@ class TranslatorAdapterBase : public Translator }; -class TranslatorAdapter_1_8_19 : public TranslatorAdapterBase +class TranslatorAdapter_1_9_2 : public TranslatorAdapterBase +{ + public: + virtual QCString updateNeededMessage() + { return createUpdateNeededMessage(idLanguage(),"release 1.9.2"); } + + virtual QCString trConcept(bool first_capital,bool singular) + { return english.trConcept(first_capital,singular); } + + virtual QCString trConceptReference(const char *conceptName) + { return english.trConceptReference(conceptName); } + + virtual QCString trConceptList() + { return english.trConceptList(); } + + virtual QCString trConceptIndex() + { return english.trConceptIndex(); } + + virtual QCString trConceptDocumentation() + { return english.trConceptDocumentation(); } + + virtual QCString trConceptListDescription(bool extractAll) + { return english.trConceptListDescription(extractAll); } + + virtual QCString trConceptDefinition() + { return english.trConceptDefinition(); } +}; + +class TranslatorAdapter_1_8_19 : public TranslatorAdapter_1_9_2 { public: virtual QCString updateNeededMessage() diff --git a/src/translator_br.h b/src/translator_br.h index e180f62..533e6cd 100644 --- a/src/translator_br.h +++ b/src/translator_br.h @@ -52,7 +52,7 @@ #ifndef TRANSLATOR_BR_H #define TRANSLATOR_BR_H -class TranslatorBrazilian : public Translator +class TranslatorBrazilian : public TranslatorAdapter_1_9_2 { public: @@ -2341,13 +2341,13 @@ class TranslatorBrazilian : public Translator ////////////////////////////////////////////////////////////////////////// // new since 1.8.19 ////////////////////////////////////////////////////////////////////////// - + /** VHDL design unit documentation */ virtual QCString trDesignUnitDocumentation() - { - return "Documentação da Unidade de Projeto"; + { + return "Documentação da Unidade de Projeto"; } - + }; #endif diff --git a/src/translator_en.h b/src/translator_en.h index ba26bc7..8f7676e 100644 --- a/src/translator_en.h +++ b/src/translator_en.h @@ -2262,6 +2262,51 @@ class TranslatorEnglish : public Translator virtual QCString trDesignUnitDocumentation() { return "Design Unit Documentation"; } +////////////////////////////////////////////////////////////////////////// +// new since 1.9.2 +////////////////////////////////////////////////////////////////////////// + + /** C++20 concept */ + virtual QCString trConcept(bool first_capital, bool singular) + { + QCString result((first_capital ? "Concept" : "concept")); + if (!singular) result+="s"; + return result; + } + /*! used as the title of the HTML page of a C++20 concept page */ + virtual QCString trConceptReference(const char *conceptName) + { + QCString result=conceptName; + result+=" Concept Reference"; + return result; + } + + /*! used as the title of page containing all the index of all concepts. */ + virtual QCString trConceptList() + { return "Concept List"; } + + /*! used as the title of chapter containing the index listing all concepts. */ + virtual QCString trConceptIndex() + { return "Concept Index"; } + + /*! used as the title of chapter containing all information about concepts. */ + virtual QCString trConceptDocumentation() + { return "Concept Documentation"; } + + /*! used as an introduction to the concept list */ + virtual QCString trConceptListDescription(bool extractAll) + { + QCString result="Here is a list of all "; + if (!extractAll) result+="documented "; + result+="concepts with brief descriptions:"; + return result; + } + + /*! used to introduce the definition of the C++20 concept */ + virtual QCString trConceptDefinition() + { + return "Concept definition"; + } }; #endif diff --git a/src/translator_nl.h b/src/translator_nl.h index 413d353..13b5ce1 100644 --- a/src/translator_nl.h +++ b/src/translator_nl.h @@ -1796,6 +1796,46 @@ class TranslatorDutch : public Translator ////////////////////////////////////////////////////////////////////////// virtual QCString trDesignUnitDocumentation() { return "Ontwerp Eenheid Documentatie"; } + +////////////////////////////////////////////////////////////////////////// +// new since 1.9.2 +////////////////////////////////////////////////////////////////////////// + virtual QCString trConcept(bool first_capital, bool singular) + { + QCString result((first_capital ? "Concept" : "concept")); + if (!singular) result+="en"; + return result; + } + + virtual QCString trConceptReference(const char *conceptName) + { + QCString result=conceptName; + result+=" Concept Referentie"; + return result; + } + + virtual QCString trConceptList() + { return "Concept Lijst"; } + + virtual QCString trConceptIndex() + { return "Concept Index"; } + + virtual QCString trConceptDocumentation() + { return "Concept Documentatie"; } + + virtual QCString trConceptListDescription(bool extractAll) + { + QCString result="Hieronder volgt de lijst met alle "; + if (!extractAll) result+="gedocumenteerde "; + result+="concepten, elk met een korte beschrijving:"; + return result; + } + + virtual QCString trConceptDefinition() + { + return "Concept definitie"; + } + }; #endif diff --git a/src/translator_pt.h b/src/translator_pt.h index 2273c97..c092e2e 100644 --- a/src/translator_pt.h +++ b/src/translator_pt.h @@ -27,7 +27,7 @@ * --------------- * History: * 20200112: - * - Updated to 1.9.1; + * - Updated to 1.9.1; * 20190203: * - Slice methods added; * 20180612: @@ -63,7 +63,7 @@ #define TRANSLATOR_PT_H -class TranslatorPortuguese : public Translator +class TranslatorPortuguese : public TranslatorAdapter_1_9_2 { public: @@ -2279,11 +2279,11 @@ class TranslatorPortuguese : public Translator ////////////////////////////////////////////////////////////////////////// // new since 1.8.19 ////////////////////////////////////////////////////////////////////////// - + /** VHDL design unit documentation */ virtual QCString trDesignUnitDocumentation() - { - return "Documentação da Unidade de Projeto"; + { + return "Documentação da Unidade de Projeto"; } }; diff --git a/src/translator_sv.h b/src/translator_sv.h index 853e265..b3c48dc 100644 --- a/src/translator_sv.h +++ b/src/translator_sv.h @@ -151,7 +151,7 @@ English: #ifndef TRANSLATOR_SE_H #define TRANSLATOR_SE_H -class TranslatorSwedish : public Translator +class TranslatorSwedish : public TranslatorAdapter_1_9_2 { public: diff --git a/src/util.cpp b/src/util.cpp index 16a3879..c7b82df 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -491,6 +491,26 @@ ClassDef *getClass(const char *n) return Doxygen::classLinkedMap->find(n); } + +ConceptDef *getConcept(const char *n) +{ + if (n==0 || n[0]=='\0') return 0; + return Doxygen::conceptLinkedMap->find(n); +} + +ConceptDef *getResolvedConcept(const Definition *d,const char *name) +{ + ConceptDef *cd=0; + while (d && d!=Doxygen::globalScope) + { + cd = getConcept(d->name()+"::"+name); + if (cd) return cd; + d = d->getOuterScope(); + } + cd = getConcept(name); + return cd; +} + NamespaceDef *getResolvedNamespace(const char *name) { if (name==0 || name[0]=='\0') return 0; @@ -973,6 +993,7 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope, const FileDef *fd=0; const NamespaceDef *nd=0; const GroupDef *gd=0; + const ConceptDef *cnd=0; //printf("** Match word '%s'\n",matchWord.data()); SymbolResolver resolver(fileScope); @@ -1018,18 +1039,18 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope, } } } -// else if ((cd=getClass(matchWord+"-g"))) // C# generic as well -// { -// // add link to the result -// if (external ? cd->isLinkable() : cd->isLinkableInProject()) -// { -// if (cd!=self) -// { -// out.writeLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),word); -// found=TRUE; -// } -// } -// } + else if ((cnd=getConcept(matchWord))) + { + // add link to the result + if (external ? cnd->isLinkable() : cnd->isLinkableInProject()) + { + if (cnd!=self) + { + out.writeLink(cnd->getReference(),cnd->getOutputFileBase(),cnd->anchor(),word.c_str()); + found=TRUE; + } + } + } else { //printf(" -> nothing\n"); @@ -2932,6 +2953,7 @@ bool resolveRef(/* in */ const char *scName, const FileDef *fd = 0; const NamespaceDef *nd = 0; const GroupDef *gd = 0; + const ConceptDef *cnd = 0; // check if nameStr is a member or global. //printf("getDefs(scope=%s,name=%s,args=%s checkScope=%d)\n", @@ -2974,6 +2996,11 @@ bool resolveRef(/* in */ const char *scName, *resContext=gd; return TRUE; } + else if ((cnd=Doxygen::conceptLinkedMap->find(nameStr))) + { + *resContext=cnd; + return TRUE; + } else if (tsName.find('.')!=-1) // maybe a link to a file { bool ambig; @@ -3113,6 +3140,7 @@ bool resolveLink(/* in */ const char *scName, const PageDef *pd; const ClassDef *cd; const DirDef *dir; + const ConceptDef *cnd; const NamespaceDef *nd; const SectionInfo *si=0; bool ambig; @@ -3175,12 +3203,12 @@ bool resolveLink(/* in */ const char *scName, resAnchor=cd->anchor(); return TRUE; } -// else if ((cd=getClass(linkRef+"-g"))) // C# generic link -// { -// *resContext=cd; -// resAnchor=cd->anchor(); -// return TRUE; -// } + else if ((cnd=getConcept(linkRef))) // C++20 concept definition + { + *resContext=cnd; + resAnchor=cnd->anchor(); + return TRUE; + } else if ((nd=Doxygen::namespaceLinkedMap->find(linkRef))) { *resContext=nd; @@ -6812,6 +6840,26 @@ bool namespaceHasNestedNamespace(const NamespaceDef *nd) return false; } +bool namespaceHasNestedConcept(const NamespaceDef *nd) +{ + for (const auto &cnd : nd->getNamespaces()) + { + if (namespaceHasNestedConcept(cnd)) + { + //printf("name().data(),includeClasses); + return true; + } + } + for (const auto &cnd : nd->getConcepts()) + { + if (cnd->isLinkableInProject()) + { + return true; + } + } + return false; +} + bool namespaceHasNestedClass(const NamespaceDef *nd,bool filterClasses,ClassDef::CompoundType ct) { //printf(">namespaceHasVisibleChild(%s,includeClasses=%d)\n",nd->name().data(),includeClasses); diff --git a/src/util.h b/src/util.h index ab30c61..8fe5ea1 100644 --- a/src/util.h +++ b/src/util.h @@ -36,6 +36,7 @@ #include "outputgen.h" #include "regex.h" #include "dir.h" +#include "conceptdef.h" //-------------------------------------------------------------------- @@ -173,6 +174,12 @@ inline ClassDefMutable *getClassMutable(const char *key) { return toClassDefMutable(getClass(key)); } +ConceptDef *getConcept(const char *key); +inline ConceptDefMutable *getConceptMutable(const char *key) +{ + return toConceptDefMutable(getConcept(key)); +} +ConceptDef *getResolvedConcept(const Definition *scope,const char *name); NamespaceDef *getResolvedNamespace(const char *key); inline NamespaceDefMutable *getResolvedNamespaceMutable(const char *key) @@ -228,6 +235,7 @@ QCString replaceAnonymousScopes(const char *s,const char *replacement=0); bool hasVisibleRoot(const BaseClassList &bcl); bool classHasVisibleChildren(const ClassDef *cd); bool namespaceHasNestedNamespace(const NamespaceDef *nd); +bool namespaceHasNestedConcept(const NamespaceDef *nd); bool namespaceHasNestedClass(const NamespaceDef *nd,bool filterClasses,ClassDef::CompoundType ct); bool classVisibleInIndex(const ClassDef *cd); diff --git a/src/xmlgen.cpp b/src/xmlgen.cpp index fa661a9..3eca727 100644 --- a/src/xmlgen.cpp +++ b/src/xmlgen.cpp @@ -398,7 +398,12 @@ static void writeMemberTemplateLists(const MemberDef *md,TextStream &t) static void writeTemplateList(const ClassDef *cd,TextStream &t) { - writeTemplateArgumentList(t,cd->templateArguments(),cd,0,4); + writeTemplateArgumentList(t,cd->templateArguments(),cd,cd->getFileDef(),4); +} + +static void writeTemplateList(const ConceptDef *cd,TextStream &t) +{ + writeTemplateArgumentList(t,cd->getTemplateParameterList(),cd,cd->getFileDef(),4); } static void writeXMLDocBlock(TextStream &t, @@ -928,6 +933,12 @@ static void generateXMLForMember(const MemberDef *md,TextStream &ti,TextStream & } } } + if (!md->requiresClause().isEmpty()) + { + t << " "; + linkifyText(TextGeneratorXMLImpl(t),md,md->getFileDef(),md,md->requiresClause()); + t << " \n"; + } if (md->hasOneLineInitializer() || md->hasMultiLineInitializer()) { @@ -1192,6 +1203,26 @@ static void writeInnerDirs(const DirList *dl,TextStream &t) } } +static void writeIncludeInfo(const IncludeInfo *ii,TextStream &t) +{ + if (ii) + { + QCString nm = ii->includeName; + if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName(); + if (!nm.isEmpty()) + { + t << " fileDef && !ii->fileDef->isReference()) // TODO: support external references + { + t << " refid=\"" << ii->fileDef->getOutputFileBase() << "\""; + } + t << " local=\"" << (ii->local ? "yes" : "no") << "\">"; + t << nm; + t << "\n"; + } + } +} + static void generateXMLForClass(const ClassDef *cd,TextStream &ti) { // + brief description @@ -1310,23 +1341,7 @@ static void generateXMLForClass(const ClassDef *cd,TextStream &ti) << "\n"; } - const IncludeInfo *ii=cd->includeInfo(); - if (ii) - { - QCString nm = ii->includeName; - if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName(); - if (!nm.isEmpty()) - { - t << " fileDef && !ii->fileDef->isReference()) // TODO: support external references - { - t << " refid=\"" << ii->fileDef->getOutputFileBase() << "\""; - } - t << " local=\"" << (ii->local ? "yes" : "no") << "\">"; - t << nm; - t << "\n"; - } - } + writeIncludeInfo(cd->includeInfo(),t); writeInnerClasses(cd->getClasses(),t); @@ -1345,6 +1360,13 @@ static void generateXMLForClass(const ClassDef *cd,TextStream &ti) } } + if (!cd->requiresClause().isEmpty()) + { + t << " "; + linkifyText(TextGeneratorXMLImpl(t),cd,cd->getFileDef(),0,cd->requiresClause()); + t << " \n"; + } + t << " \n"; writeXMLDocBlock(t,cd->briefFile(),cd->briefLine(),cd,0,cd->briefDescription()); t << " \n"; @@ -1387,6 +1409,50 @@ static void generateXMLForClass(const ClassDef *cd,TextStream &ti) ti << " \n"; } +static void generateXMLForConcept(const ConceptDef *cd,TextStream &ti) +{ + if (cd->isReference() || cd->isHidden()) return; // skip external references. + + ti << " getOutputFileBase() + << "\" kind=\"concept\"" << ">" + << convertToXML(cd->name()) << "\n"; + + QCString outputDirectory = Config_getString(XML_OUTPUT); + QCString fileName=outputDirectory+"/"+cd->getOutputFileBase()+".xml"; + std::ofstream f(fileName.str(),std::ofstream::out | std::ofstream::binary); + if (!f.is_open()) + { + err("Cannot open file %s for writing!\n",fileName.data()); + return; + } + TextStream t(&f); + writeXMLHeader(t); + t << " getOutputFileBase() + << "\" kind=\"concept\">\n"; + t << " "; + writeXMLString(t,cd->name()); + t << "\n"; + writeIncludeInfo(cd->includeInfo(),t); + writeTemplateList(cd,t); + t << " "; + linkifyText(TextGeneratorXMLImpl(t),cd,cd->getFileDef(),0,cd->initializer()); + t << " \n"; + t << " \n"; + writeXMLDocBlock(t,cd->briefFile(),cd->briefLine(),cd,0,cd->briefDescription()); + t << " \n"; + t << " \n"; + writeXMLDocBlock(t,cd->docFile(),cd->docLine(),cd,0,cd->documentation()); + t << " \n"; + t << " getDefFileName())) << "\" line=\"" + << cd->getDefLine() << "\"" << " column=\"" + << cd->getDefColumn() << "\"/>\n" ; + t << " \n"; + t << "\n"; + + ti << " \n"; +} + static void generateXMLForNamespace(const NamespaceDef *nd,TextStream &ti) { // + contained class definitions @@ -1817,6 +1883,7 @@ static void generateXMLForPage(PageDef *pd,TextStream &ti,bool isExample) void generateXML() { // + classes + // + concepts // + namespaces // + files // + groups @@ -1891,6 +1958,11 @@ void generateXML() { generateXMLForClass(cd.get(),t); } + for (const auto &cd : *Doxygen::conceptLinkedMap) + { + msg("Generating XML output for concept %s\n",cd->name().data()); + generateXMLForConcept(cd.get(),t); + } for (const auto &nd : *Doxygen::namespaceLinkedMap) { msg("Generating XML output for namespace %s\n",nd->name().data()); diff --git a/templates/general/layout_default.xml b/templates/general/layout_default.xml index 373bb20..c671020 100644 --- a/templates/general/layout_default.xml +++ b/templates/general/layout_default.xml @@ -9,6 +9,8 @@ + + @@ -103,6 +105,7 @@ + @@ -126,6 +129,15 @@ + + + + + + + + + @@ -139,6 +151,7 @@ + @@ -172,6 +185,7 @@ + diff --git a/templates/html/doxygen.css b/templates/html/doxygen.css index 5898d87..29dafbe 100644 --- a/templates/html/doxygen.css +++ b/templates/html/doxygen.css @@ -439,6 +439,12 @@ img.footer { vertical-align: middle; } +.compoundTemplParams { + color: ##60; + font-size: 80%; + line-height: 120%; +} + /* @group Code Colorization */ span.keyword { diff --git a/templates/xml/compound.xsd b/templates/xml/compound.xsd index 400bea5..c128140 100644 --- a/templates/xml/compound.xsd +++ b/templates/xml/compound.xsd @@ -33,6 +33,8 @@ + + @@ -147,6 +149,7 @@ + @@ -815,6 +818,7 @@ + diff --git a/templates/xml/index.xsd b/templates/xml/index.xsd index edb1d34..cfb7041 100644 --- a/templates/xml/index.xsd +++ b/templates/xml/index.xsd @@ -45,6 +45,7 @@ + -- cgit v0.12