summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDimitri van Heesch <doxygen@gmail.com>2021-03-31 14:44:36 (GMT)
committerDimitri van Heesch <doxygen@gmail.com>2021-04-08 19:19:25 (GMT)
commita9e4a9e5b51ab33df64f3989c710e08546dcd45d (patch)
tree8e2b9dc39f2ac89b12ab4a0af4606e23d9165afe /src
parentfc2e284f9657abbe343d41b4a7922d5c4d788b11 (diff)
downloadDoxygen-a9e4a9e5b51ab33df64f3989c710e08546dcd45d.zip
Doxygen-a9e4a9e5b51ab33df64f3989c710e08546dcd45d.tar.gz
Doxygen-a9e4a9e5b51ab33df64f3989c710e08546dcd45d.tar.bz2
C++20 concepts: added support for parsing requires-clauses
Diffstat (limited to 'src')
-rw-r--r--src/classdef.cpp17
-rw-r--r--src/classdef.h3
-rw-r--r--src/doxygen.cpp13
-rw-r--r--src/entry.cpp2
-rw-r--r--src/entry.h1
-rw-r--r--src/memberdef.cpp85
-rw-r--r--src/memberdef.h4
-rw-r--r--src/scanner.l127
8 files changed, 225 insertions, 27 deletions
diff --git a/src/classdef.cpp b/src/classdef.cpp
index 542147a..6432e2a 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -239,6 +239,7 @@ class ClassDefImpl : public DefinitionMixin<ClassDefMutable>
virtual bool subGrouping() const;
virtual bool isSliceLocal() const;
virtual bool hasNonReferenceSuperClass() const;
+ virtual QCString requiresClause() const;
virtual ClassDef *insertTemplateInstance(const QCString &fileName,int startLine,int startColumn,
const QCString &templSpec,bool &freshInstance) const;
@@ -309,6 +310,7 @@ class ClassDefImpl : public DefinitionMixin<ClassDefMutable>
MemberListType lt,const QCString &title,
const char *subTitle=0,bool showInline=FALSE,const ClassDef *inheritedFrom=0,
int lt2=-1,bool invert=FALSE,bool showAlways=FALSE) const;
+ virtual void setRequiresClause(const char *req);
private:
void addUsedInterfaceClasses(MemberDef *md,const char *typeStr);
@@ -527,6 +529,8 @@ class ClassDefAliasImpl : public DefinitionAliasMixin<ClassDef>
{ return getCdAlias()->isSliceLocal(); }
virtual bool hasNonReferenceSuperClass() const
{ return getCdAlias()->hasNonReferenceSuperClass(); }
+ virtual QCString requiresClause() const
+ { return getCdAlias()->requiresClause(); }
virtual int countMembersIncludingGrouped(MemberListType lt,const ClassDef *inheritedFrom,bool additional) const
{ return getCdAlias()->countMembersIncludingGrouped(lt,inheritedFrom,additional); }
@@ -704,6 +708,9 @@ class ClassDefImpl::IMPL
uint64 spec = 0;
QCString metaData;
+
+ /** C++20 requires clause */
+ QCString requiresClause;
};
void ClassDefImpl::IMPL::init(const char *defFileName, const char *name,
@@ -3184,6 +3191,16 @@ bool ClassDefImpl::hasNonReferenceSuperClass() const
return found;
}
+QCString ClassDefImpl::requiresClause() const
+{
+ return m_impl->requiresClause;
+}
+
+void ClassDefImpl::setRequiresClause(const char *req)
+{
+ m_impl->requiresClause = req;
+}
+
/*! called from MemberDef::writeDeclaration() to (recursively) write the
* definition of an anonymous struct, union or class.
*/
diff --git a/src/classdef.h b/src/classdef.h
index d6c515d..b3e3325 100644
--- a/src/classdef.h
+++ b/src/classdef.h
@@ -358,6 +358,8 @@ class ClassDef : public Definition
virtual bool isSliceLocal() const = 0;
virtual bool hasNonReferenceSuperClass() const = 0;
+ virtual QCString requiresClause() const = 0;
+
//-----------------------------------------------------------------------------------
// --- count members ----
//-----------------------------------------------------------------------------------
@@ -405,6 +407,7 @@ class ClassDefMutable : public DefinitionMutable, public ClassDef
virtual void setTagLessReference(const ClassDef *cd) = 0;
virtual void setName(const char *name) = 0;
virtual void setMetaData(const char *md) = 0;
+ virtual void setRequiresClause(const char *req) = 0;
//-----------------------------------------------------------------------------------
// --- actions ----
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index d5e082d..9a9342b 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -1011,6 +1011,10 @@ static void addClassToContext(const Entry *root)
cd->setTemplateArguments(*tArgList);
}
}
+ if (cd->requiresClause().isEmpty() && !root->req.isEmpty())
+ {
+ cd->setRequiresClause(root->req);
+ }
cd->setCompoundType(convertToCompoundType(root->section,root->spec));
@@ -1081,6 +1085,7 @@ static void addClassToContext(const Entry *root)
{
cd->setTemplateArguments(*tArgList);
}
+ cd->setRequiresClause(root->req);
cd->setProtection(root->protection);
cd->setIsStatic(root->stat);
@@ -1365,6 +1370,7 @@ static ClassDefMutable *createTagLessInstance(const ClassDef *rootCd,const Class
imd->setMemberSpecifiers(md->getMemberSpecifiers());
imd->setMemberGroupId(md->getMemberGroupId());
imd->setInitializer(md->initializer());
+ imd->setRequiresClause(md->requiresClause());
imd->setMaxInitLines(md->initializerLines());
imd->setBitfields(md->bitfieldString());
imd->setLanguage(md->getLanguage());
@@ -1982,6 +1988,7 @@ static void findUsingDeclImports(const Entry *root)
newMd->setBodySegment(md->getDefLine(),md->getStartBodyLine(),md->getEndBodyLine());
newMd->setBodyDef(md->getBodyDef());
newMd->setInitializer(md->initializer());
+ newMd->setRequiresClause(md->requiresClause());
newMd->setMaxInitLines(md->initializerLines());
newMd->setMemberGroupId(root->mGrpId);
newMd->setMemberSpecifiers(md->getMemberSpecifiers());
@@ -3104,6 +3111,7 @@ static void addMethodToClass(const Entry *root,ClassDefMutable *cd,
md->setMemberGroupId(root->mGrpId);
md->setTypeConstraints(root->typeConstr);
md->setLanguage(root->lang);
+ md->setRequiresClause(root->req);
md->setId(root->id);
md->setBodyDef(fd);
md->setFileDef(fd);
@@ -3213,6 +3221,7 @@ static void addGlobalFunction(const Entry *root,const QCString &rname,const QCSt
md->addSectionsToDefinition(root->anchors);
md->setMemberSpecifiers(root->spec);
md->setMemberGroupId(root->mGrpId);
+ md->setRequiresClause(root->req);
NamespaceDefMutable *nd = 0;
// see if the function is inside a namespace that was not part of
@@ -5026,6 +5035,10 @@ static void addMemberDocs(const Entry *root,
//printf("setInitializer\n");
md->setInitializer(rootInit.c_str());
}
+ if (md->requiresClause().isEmpty() && !root->req.isEmpty())
+ {
+ md->setRequiresClause(root->req);
+ }
md->setMaxInitLines(root->initLines);
diff --git a/src/entry.cpp b/src/entry.cpp
index a0f8fa3..a58362c 100644
--- a/src/entry.cpp
+++ b/src/entry.cpp
@@ -108,6 +108,7 @@ Entry::Entry(const Entry &e)
id = e.id;
extends = e.extends;
groups = e.groups;
+ req = e.req;
m_fileDef = e.m_fileDef;
m_parent = e.m_parent;
@@ -242,6 +243,7 @@ void Entry::reset()
tArgLists.clear();
typeConstr.reset();
sli.clear();
+ req.resize(0);
m_fileDef = 0;
}
diff --git a/src/entry.h b/src/entry.h
index dd2b157..6ba88e8 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -295,6 +295,7 @@ class Entry
QCString id; //!< libclang id
LocalToc localToc;
QCString metaData; //!< Slice metadata
+ QCString req; //!< C++20 requires clause
/// return the command name used to define GROUPDOC_SEC
const char *groupDocCmd() const
diff --git a/src/memberdef.cpp b/src/memberdef.cpp
index 48291cb..38164ef 100644
--- a/src/memberdef.cpp
+++ b/src/memberdef.cpp
@@ -229,6 +229,7 @@ class MemberDefImpl : public DefinitionMixin<MemberDefMutable>
virtual QCString getDeclType() const;
virtual StringVector getLabels(const Definition *container) const;
virtual const ArgumentList &typeConstraints() const;
+ virtual QCString requiresClause() const;
virtual QCString documentation() const;
virtual QCString briefDescription(bool abbr=FALSE) const;
virtual QCString fieldType() const;
@@ -304,6 +305,7 @@ class MemberDefImpl : public DefinitionMixin<MemberDefMutable>
virtual void setBriefDescription(const char *b,const char *briefFile,int briefLine);
virtual void setInbodyDocumentation(const char *d,const char *inbodyFile,int inbodyLine);
virtual void setHidden(bool b);
+ virtual void setRequiresClause(const char *req);
virtual void incrementFlowKeyWordCount();
virtual void writeDeclaration(OutputList &ol,
const ClassDef *cd,const NamespaceDef *nd,const FileDef *fd,const GroupDef *gd,
@@ -344,6 +346,8 @@ class MemberDefImpl : public DefinitionMixin<MemberDefMutable>
const QCString &cname) const;
void _writeCategoryRelation(OutputList &ol) const;
void _writeTagData(const DefType) const;
+ void _writeTemplatePrefix(OutputList &ol, const Definition *def,
+ const ArgumentList &al, bool writeReqClause=true) const;
static int s_indentLevel;
@@ -735,6 +739,8 @@ class MemberDefAliasImpl : public DefinitionAliasMixin<MemberDef>
{ return getMdAlias()->getDeclLine(); }
virtual int getDeclColumn() const
{ return getMdAlias()->getDeclColumn(); }
+ virtual QCString requiresClause() const
+ { return getMdAlias()->requiresClause(); }
virtual void warnIfUndocumented() const {}
virtual void warnIfUndocumentedParams() const {}
@@ -1119,26 +1125,6 @@ static void writeExceptionList(OutputList &ol, const ClassDef *cd, const MemberD
}
}
-static void writeTemplatePrefix(OutputList &ol,const ArgumentList &al)
-{
- ol.docify("template<");
- for (auto it = al.begin(); it!=al.end();)
- {
- Argument a = *it;
- ol.docify(a.type);
- ol.docify(" ");
- ol.docify(a.name);
- if (a.defval.length()!=0)
- {
- ol.docify(" = ");
- ol.docify(a.defval);
- }
- ++it;
- if (it!=al.end()) ol.docify(", ");
- }
- ol.docify("> ");
-}
-
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
@@ -1189,6 +1175,7 @@ class MemberDefImpl::IMPL
QCString initializer; // initializer
QCString extraTypeChars; // extra type info found after the argument list
QCString enumBaseType; // base type of the enum (C++11)
+ QCString requiresClause; // requires clause (C++20)
int initLines = 0; // number of lines in the initializer
uint64 memSpec = 0; // The specifiers present for this member
@@ -2008,6 +1995,46 @@ QCString MemberDefImpl::getDeclType() const
return ltype;
}
+void MemberDefImpl::_writeTemplatePrefix(OutputList &ol, const Definition *def,
+ const ArgumentList &al, bool writeReqClause) const
+{
+ ol.docify("template<");
+ for (auto it = al.begin(); it!=al.end();)
+ {
+ Argument a = *it;
+ linkifyText(TextGeneratorOLImpl(ol), // out
+ def, // scope
+ getFileDef(), // fileScope
+ this, // self
+ a.type, // text
+ FALSE // autoBreak
+ );
+ ol.docify(" ");
+ ol.docify(a.name);
+ if (a.defval.length()!=0)
+ {
+ ol.docify(" = ");
+ ol.docify(a.defval);
+ }
+ ++it;
+ if (it!=al.end()) ol.docify(", ");
+ }
+ ol.docify("> ");
+ if (writeReqClause && !m_impl->requiresClause.isEmpty())
+ {
+ ol.lineBreak();
+ ol.docify("requires ");
+ linkifyText(TextGeneratorOLImpl(ol), // out
+ def, // scope
+ getFileDef(), // fileScope
+ this, // self
+ m_impl->requiresClause, // text
+ FALSE // autoBreak
+ );
+ }
+}
+
+
void MemberDefImpl::writeDeclaration(OutputList &ol,
const ClassDef *cd,const NamespaceDef *nd,const FileDef *fd,const GroupDef *gd,
bool inGroup, const ClassDef *inheritedFrom,const char *inheritId) const
@@ -2086,10 +2113,11 @@ void MemberDefImpl::writeDeclaration(OutputList &ol,
if (m_impl->tArgList.hasParameters() && getLanguage()==SrcLangExt_Cpp)
{
if (!isAnonType) ol.startMemberTemplateParams();
- writeTemplatePrefix(ol,m_impl->tArgList);
+ _writeTemplatePrefix(ol,d,m_impl->tArgList);
if (!isAnonType) ol.endMemberTemplateParams(anchor(),inheritId);
}
+
// *** write type
QCString ltype(m_impl->type);
if (isTypedef() && getLanguage() != SrcLangExt_Slice)
@@ -3280,7 +3308,7 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
{
if (!first) ol.docify(" ");
ol.startMemberDocPrefixItem();
- writeTemplatePrefix(ol,tal);
+ _writeTemplatePrefix(ol,scopedContainer,tal);
ol.endMemberDocPrefixItem();
}
}
@@ -3296,7 +3324,7 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
{
if (!first) ol.docify(" ");
ol.startMemberDocPrefixItem();
- writeTemplatePrefix(ol,tal);
+ _writeTemplatePrefix(ol,scopedContainer,tal,false);
ol.endMemberDocPrefixItem();
}
}
@@ -3304,7 +3332,7 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
if (m_impl->tArgList.hasParameters() && lang==SrcLangExt_Cpp) // function template prefix
{
ol.startMemberDocPrefixItem();
- writeTemplatePrefix(ol,m_impl->tArgList);
+ _writeTemplatePrefix(ol,scopedContainer,m_impl->tArgList);
ol.endMemberDocPrefixItem();
}
}
@@ -5604,6 +5632,15 @@ QCString MemberDefImpl::enumBaseType() const
return m_impl->enumBaseType;
}
+void MemberDefImpl::setRequiresClause(const char *req)
+{
+ m_impl->requiresClause = req;
+}
+
+QCString MemberDefImpl::requiresClause() const
+{
+ return m_impl->requiresClause;
+}
void MemberDefImpl::cacheTypedefVal(const ClassDef*val, const QCString & templSpec, const QCString &resolvedType)
{
diff --git a/src/memberdef.h b/src/memberdef.h
index d2d6e1d..d51fbc0 100644
--- a/src/memberdef.h
+++ b/src/memberdef.h
@@ -261,6 +261,8 @@ class MemberDef : public Definition
virtual const ArgumentList &typeConstraints() const = 0;
+ virtual QCString requiresClause() const = 0;
+
// overrules
virtual QCString documentation() const = 0;
virtual QCString briefDescription(bool abbr=FALSE) const = 0;
@@ -393,6 +395,8 @@ class MemberDefMutable : public DefinitionMutable, public MemberDef
virtual void setHidden(bool b) = 0;
+ virtual void setRequiresClause(const char *req) = 0;
+
//-----------------------------------------------------------------------------------
// --- actions ----
//-----------------------------------------------------------------------------------
diff --git a/src/scanner.l b/src/scanner.l
index 78afdab..9e719d0 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -74,6 +74,7 @@ struct scannerYY_state
int lastStringContext = 0;
int lastCurlyContext = 0;
int lastRoundContext = 0;
+ int lastSharpContext = 0;
int lastSquareContext = 0;
int lastInitializerContext = 0;
int lastClassTemplSpecContext = 0;
@@ -139,6 +140,7 @@ struct scannerYY_state
int currentArgumentContext = 0;
int lastCopyArgStringContext = 0;
int lastCopyArgContext = 0;
+ int requiresContext = 0;
QCString *copyArgString = 0;
QCString fullArgString;
QCString dummyRawString;
@@ -149,6 +151,7 @@ struct scannerYY_state
QCString *pCopyQuotedString = 0;
QCString *pCopyRoundString = 0;
QCString *pCopyCurlyString = 0;
+ QCString *pCopySharpString = 0;
QCString *pCopyRawString = 0;
TextStream *pCopyCurlyGString = 0;
TextStream *pCopyRoundGString = 0;
@@ -383,6 +386,7 @@ NONLopt [^\n]*
%x CopyGString
%x CopyPHPGString
%x CopyRound
+%x CopySharp
%x CopyCurly
%x GCopyRound
%x GCopySquare
@@ -438,6 +442,10 @@ NONLopt [^\n]*
%x DocBlock
%x DocCopyBlock
+ /** C++20 concepts */
+
+%x RequiresClause
+
%%
<NextSemi>"{" {
@@ -2069,6 +2077,54 @@ NONLopt [^\n]*
yyextra->current->name=yytext;
BEGIN(FindMembers);
}
+<FindMembers>"requires" { // C++20 requires clause
+ yyextra->current->req.resize(0);
+ yyextra->requiresContext = YY_START;
+ BEGIN(RequiresClause);
+ }
+<RequiresClause>"(" { // requires "(A && B)"
+ yyextra->current->req+=yytext;
+ yyextra->lastRoundContext=RequiresClause;
+ yyextra->pCopyRoundString=&yyextra->current->req;
+ yyextra->roundCount=0;
+ BEGIN( CopyRound ) ;
+ }
+<RequiresClause>{ID} { // something like "requires true"
+ if (yyextra->current->req.stripWhiteSpace().isEmpty())
+ {
+ yyextra->current->req=yytext;
+ BEGIN(yyextra->requiresContext);
+ }
+ else
+ {
+ REJECT;
+ }
+ }
+<RequiresClause>{SCOPENAME}{BNopt}"(" { // "requires func(x)"
+ yyextra->current->req+=yytext;
+ yyextra->lastRoundContext=RequiresClause;
+ yyextra->pCopyRoundString=&yyextra->current->req;
+ yyextra->roundCount=0;
+ BEGIN( CopyRound );
+ }
+<RequiresClause>{SCOPENAME}{BNopt}"<" { // "requires C<S,T>"
+ yyextra->current->req+=yytext;
+ yyextra->lastSharpContext=RequiresClause;
+ yyextra->pCopySharpString=&yyextra->current->req;
+ yyextra->sharpCount=0;
+ BEGIN( CopySharp );
+ }
+<RequiresClause>"||"|"&&" { // "requires A || B" or "requires A && B"
+ yyextra->current->req+=yytext;
+ }
+<RequiresClause>{BN}+ {
+ yyextra->current->req+=' ';
+ }
+<RequiresClause>. {
+ unput(*yytext);
+ yyextra->current->req=yyextra->current->req.simplifyWhiteSpace();
+ BEGIN(yyextra->requiresContext);
+ }
<FindMembers,FindMemberName>{SCOPENAME} {
if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC))
@@ -2948,6 +3004,59 @@ NONLopt [^\n]*
*yyextra->pCopyRoundString+=*yytext;
}
+ /* generic sharp bracket list copy rules */
+<CopySharp>\" {
+ *yyextra->pCopySharpString += *yytext;
+ yyextra->pCopyQuotedString=yyextra->pCopySharpString;
+ yyextra->lastStringContext=YY_START;
+ BEGIN(CopyString);
+ }
+<CopySharp>"<" {
+ *yyextra->pCopySharpString += *yytext;
+ yyextra->sharpCount++;
+ }
+<CopySharp>">" {
+ *yyextra->pCopySharpString += *yytext;
+ if (--yyextra->sharpCount<0)
+ {
+ BEGIN(yyextra->lastSharpContext);
+ }
+ }
+<CopySharp>\n {
+ lineCount(yyscanner);
+ *yyextra->pCopySharpString += *yytext;
+ }
+<CopySharp>\' {
+ if (yyextra->insidePHP)
+ {
+ yyextra->current->initializer << yytext;
+ yyextra->pCopyQuotedString = yyextra->pCopySharpString;
+ yyextra->lastStringContext=YY_START;
+ BEGIN(CopyPHPString);
+ }
+ else
+ {
+ *yyextra->pCopySharpString += yytext;
+ }
+ }
+<CopySharp>{CHARLIT} {
+ if (yyextra->insidePHP)
+ {
+ REJECT;
+ }
+ else
+ {
+ *yyextra->pCopySharpString+=yytext;
+ }
+ }
+<CopySharp>[^"'<>\n,]+ {
+ *yyextra->pCopySharpString+=yytext;
+ }
+<CopySharp>. {
+ *yyextra->pCopySharpString+=*yytext;
+ }
+
+
/* generic round bracket list copy rules for growable strings */
<GCopyRound>\" {
*yyextra->pCopyRoundGString << *yytext;
@@ -4627,6 +4736,11 @@ NONLopt [^\n]*
unput(*yytext);
BEGIN(FuncQual);
}
+<TrailingReturn>"requires"{BN}+ {
+ yyextra->requiresContext = FuncQual;
+ yyextra->current->req+=' ';
+ BEGIN(RequiresClause);
+ }
<TrailingReturn>"(" {
yyextra->roundCount++;
yyextra->current->argList.setTrailingReturnType(yyextra->current->argList.trailingReturnType()+yytext);
@@ -4734,8 +4848,15 @@ NONLopt [^\n]*
yyextra->current->args += *yytext;
lineCount(yyscanner);
}
-<FuncQual>{ID} { // typically a K&R style C function
- if (yyextra->insideCS && qstrcmp(yytext,"where")==0)
+<FuncQual>{ID} {
+ if (yyextra->insideCpp && qstrcmp(yytext,"requires")==0)
+ {
+ // c++20 trailing requires clause
+ yyextra->requiresContext = YY_START;
+ yyextra->current->req+=' ';
+ BEGIN(RequiresClause);
+ }
+ else if (yyextra->insideCS && qstrcmp(yytext,"where")==0)
{
// type constraint for a method
yyextra->current->typeConstr.clear();
@@ -4743,7 +4864,7 @@ NONLopt [^\n]*
yyextra->lastCSConstraint = YY_START;
BEGIN( CSConstraintName );
}
- else if (checkForKnRstyleC(yyscanner))
+ else if (checkForKnRstyleC(yyscanner)) // K&R style C function
{
yyextra->current->args = yytext;
yyextra->oldStyleArgType.resize(0);