summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDimitri van Heesch <dimitri@stack.nl>2015-02-21 16:12:30 (GMT)
committerDimitri van Heesch <dimitri@stack.nl>2015-02-21 16:17:14 (GMT)
commit080a465b1321ff93c05ce398cd18a577e0ebae4b (patch)
tree0bae20bf26007d2856f0460143125a31cff131b5 /src
parent5bfda3d4c1158e5429349a2698339650dcfbbe88 (diff)
downloadDoxygen-080a465b1321ff93c05ce398cd18a577e0ebae4b.zip
Doxygen-080a465b1321ff93c05ce398cd18a577e0ebae4b.tar.gz
Doxygen-080a465b1321ff93c05ce398cd18a577e0ebae4b.tar.bz2
Added type constraint relations for Java generics to dot graphs and XML output
Diffstat (limited to 'src')
-rw-r--r--src/arguments.cpp2
-rw-r--r--src/arguments.h39
-rw-r--r--src/classdef.cpp85
-rw-r--r--src/classdef.h64
-rw-r--r--src/defargs.l31
-rw-r--r--src/dot.cpp47
-rw-r--r--src/dot.h2
-rw-r--r--src/doxygen.cpp1
-rw-r--r--src/scanner.l1
-rw-r--r--src/util.cpp11
10 files changed, 243 insertions, 40 deletions
diff --git a/src/arguments.cpp b/src/arguments.cpp
index 2acf855..87d0438 100644
--- a/src/arguments.cpp
+++ b/src/arguments.cpp
@@ -54,6 +54,7 @@ ArgumentList *ArgumentList::unmarshal(StorageIntf *s)
a->array = unmarshalQCString(s);
a->defval = unmarshalQCString(s);
a->docs = unmarshalQCString(s);
+ a->typeConstraint = unmarshalQCString(s);
result->append(a);
}
result->constSpecifier = unmarshalBool(s);
@@ -85,6 +86,7 @@ void ArgumentList::marshal(StorageIntf *s,ArgumentList *argList)
marshalQCString(s,a->array);
marshalQCString(s,a->defval);
marshalQCString(s,a->docs);
+ marshalQCString(s,a->typeConstraint);
}
}
marshalBool(s,argList->constSpecifier);
diff --git a/src/arguments.h b/src/arguments.h
index ed09869..14589c0 100644
--- a/src/arguments.h
+++ b/src/arguments.h
@@ -30,37 +30,39 @@ struct Argument
/*! Construct a new argument. */
Argument() {}
/*! Copy an argument (does a deep copy of all strings). */
- Argument(const Argument &a)
- {
- attrib=a.attrib.copy();
- type=a.type.copy();
- name=a.name.copy();
- defval=a.defval.copy();
- docs=a.docs.copy();
- array=a.array.copy();
+ Argument(const Argument &a)
+ {
+ attrib=a.attrib;
+ type=a.type;
+ name=a.name;
+ array=a.array;
+ defval=a.defval;
+ docs=a.docs;
+ typeConstraint=a.typeConstraint;
}
/*! Assignment of an argument (does a deep copy of all strings). */
Argument &operator=(const Argument &a)
{
if (this!=&a)
{
- attrib=a.attrib.copy();
- type=a.type.copy();
- name=a.name.copy();
- defval=a.defval.copy();
- docs=a.docs.copy();
- array=a.array.copy();
+ attrib=a.attrib;
+ type=a.type;
+ name=a.name;
+ array=a.array;
+ defval=a.defval;
+ docs=a.docs;
+ typeConstraint=a.typeConstraint;
}
return *this;
}
/*! return TRUE if this argument is documentation and the argument has a
* non empty name.
*/
- bool hasDocumentation() const
- {
- return !name.isEmpty() && !docs.isEmpty();
+ bool hasDocumentation() const
+ {
+ return !name.isEmpty() && !docs.isEmpty();
}
-
+
QCString attrib; /*!< Argument's attribute (IDL only) */
QCString type; /*!< Argument's type */
QCString canType; /*!< Cached value of canonical type (after type resolution). Empty initially. */
@@ -68,6 +70,7 @@ struct Argument
QCString array; /*!< Argument's array specifier (may be empty) */
QCString defval; /*!< Argument's default value (may be empty) */
QCString docs; /*!< Argument's documentation (may be empty) */
+ QCString typeConstraint; /*!< Used for Java generics: <T extends C> */
};
/*! \brief This class represents an function or template argument list.
diff --git a/src/classdef.cpp b/src/classdef.cpp
index 3a103af..486ee3f 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -118,6 +118,8 @@ class ClassDefImpl
UsesClassDict *usedByImplClassDict;
UsesClassDict *usesIntfClassDict;
+ ConstraintClassDict *constraintClassDict;
+
/*! Template instances that exists of this class, the key in the
* dictionary is the template argument list.
*/
@@ -216,6 +218,7 @@ void ClassDefImpl::init(const char *defFileName, const char *name,
usesImplClassDict=0;
usedByImplClassDict=0;
usesIntfClassDict=0;
+ constraintClassDict=0;
memberGroupSDict = 0;
innerClasses = 0;
subGrouping=Config_getBool("SUBGROUPING");
@@ -267,6 +270,7 @@ ClassDefImpl::~ClassDefImpl()
delete usesImplClassDict;
delete usedByImplClassDict;
delete usesIntfClassDict;
+ delete constraintClassDict;
delete incInfo;
delete memberGroupSDict;
delete innerClasses;
@@ -2526,20 +2530,66 @@ bool ClassDef::hasExamples() const
return result;
}
+void ClassDef::addTypeConstraint(const QCString &typeConstraint,const QCString &type)
+{
+ static bool hideUndocRelation = Config_getBool("HIDE_UNDOC_RELATIONS");
+ if (typeConstraint.isEmpty() || type.isEmpty()) return;
+ ClassDef *cd = getClass(typeConstraint);
+ if (cd==0 && !hideUndocRelation)
+ {
+ cd = new ClassDef(getDefFileName(),getDefLine(),getDefColumn(),typeConstraint,ClassDef::Class);
+ cd->setUsedOnly(TRUE);
+ cd->setLanguage(getLanguage());
+ Doxygen::hiddenClasses->append(typeConstraint,cd);
+ //printf("Adding undocumented constraint '%s' to class %s on type %s\n",
+ // typeConstraint.data(),name().data(),type.data());
+ }
+ if (cd)
+ {
+ if (m_impl->constraintClassDict==0)
+ {
+ m_impl->constraintClassDict = new ConstraintClassDict(17);
+ m_impl->constraintClassDict->setAutoDelete(TRUE);
+ }
+ ConstraintClassDef *ccd=m_impl->constraintClassDict->find(typeConstraint);
+ if (ccd==0)
+ {
+ ccd = new ConstraintClassDef(cd);
+ m_impl->constraintClassDict->insert(typeConstraint,ccd);
+ }
+ ccd->addAccessor(type);
+ //printf("Adding constraint '%s' to class %s on type %s\n",
+ // typeConstraint.data(),name().data(),type.data());
+ }
+}
-void ClassDef::setTemplateArguments(ArgumentList *al)
+// Java Type Constrains: A<T extends C & I>
+void ClassDef::addTypeConstraints()
{
- if (al==0) return;
- if (!m_impl->tempArgs) delete m_impl->tempArgs; // delete old list if needed
- m_impl->tempArgs=new ArgumentList;
- ArgumentListIterator ali(*al);
- Argument *a;
- for (;(a=ali.current());++ali)
+ if (m_impl->tempArgs)
{
- m_impl->tempArgs->append(new Argument(*a));
+ ArgumentListIterator ali(*m_impl->tempArgs);
+ Argument *a;
+ for (;(a=ali.current());++ali)
+ {
+ if (!a->typeConstraint.isEmpty())
+ {
+ QCString typeConstraint;
+ int i=0,p=0;
+ while ((i=a->typeConstraint.find('&',p))!=-1) // typeConstraint="A &I" for C<T extends A & I>
+ {
+ typeConstraint = a->typeConstraint.mid(p,i-p).stripWhiteSpace();
+ addTypeConstraint(typeConstraint,a->type);
+ p=i+1;
+ }
+ typeConstraint = a->typeConstraint.right(a->typeConstraint.length()-p).stripWhiteSpace();
+ addTypeConstraint(typeConstraint,a->type);
+ }
+ }
}
}
+// C# Type Constraints: D<T> where T : C, I
void ClassDef::setTypeConstraints(ArgumentList *al)
{
if (al==0) return;
@@ -2553,6 +2603,20 @@ void ClassDef::setTypeConstraints(ArgumentList *al)
}
}
+void ClassDef::setTemplateArguments(ArgumentList *al)
+{
+ if (al==0) return;
+ if (!m_impl->tempArgs) delete m_impl->tempArgs; // delete old list if needed
+ //printf("setting template args '%s' for '%s'\n",tempArgListToString(al,getLanguage()).data(),name().data());
+ m_impl->tempArgs=new ArgumentList;
+ ArgumentListIterator ali(*al);
+ Argument *a;
+ for (;(a=ali.current());++ali)
+ {
+ m_impl->tempArgs->append(new Argument(*a));
+ }
+}
+
/*! Returns \c TRUE iff this class or a class inheriting from this class
* is \e not defined in an external tag file.
*/
@@ -4405,6 +4469,11 @@ UsesClassDict *ClassDef::usedInterfaceClasses() const
return m_impl->usesIntfClassDict;
}
+ConstraintClassDict *ClassDef::templateTypeConstraints() const
+{
+ return m_impl->constraintClassDict;
+}
+
bool ClassDef::isTemplateArgument() const
{
return m_impl->isTemplArg;
diff --git a/src/classdef.h b/src/classdef.h
index 0729d20..d98e5de 100644
--- a/src/classdef.h
+++ b/src/classdef.h
@@ -24,6 +24,7 @@
#include "definition.h"
+struct Argument;
class MemberDef;
class MemberList;
class MemberDict;
@@ -38,6 +39,7 @@ class MemberDef;
class ExampleSDict;
class MemberNameInfoSDict;
class UsesClassDict;
+class ConstraintClassDict;
class MemberGroupSDict;
class QTextStream;
class PackageDef;
@@ -229,6 +231,8 @@ class ClassDef : public Definition
UsesClassDict *usedInterfaceClasses() const;
+ ConstraintClassDict *templateTypeConstraints() const;
+
bool isTemplateArgument() const;
/** Returns the definition of a nested compound if
@@ -371,6 +375,7 @@ class ClassDef : public Definition
void findSectionsInDocumentation();
void addMembersToMemberGroup();
void addListReferences();
+ void addTypeConstraints();
void computeAnchors();
void mergeMembers();
void sortMemberLists();
@@ -441,12 +446,13 @@ class ClassDef : public Definition
void getTitleForMemberListType(MemberListType type,
QCString &title,QCString &subtitle);
QCString includeStatement() const;
+ void addTypeConstraint(const QCString &typeConstraint,const QCString &type);
-
ClassDefImpl *m_impl;
-
};
+//------------------------------------------------------------------------
+
/** Class that contains information about a usage relation.
*/
struct UsesClassDef
@@ -500,6 +506,8 @@ class UsesClassDictIterator : public QDictIterator<UsesClassDef>
~UsesClassDictIterator() {}
};
+//------------------------------------------------------------------------
+
/** Class that contains information about an inheritance relation.
*/
struct BaseClassDef
@@ -558,4 +566,56 @@ class BaseClassListIterator : public QListIterator<BaseClassDef>
QListIterator<BaseClassDef>(bcl) {}
};
+//------------------------------------------------------------------------
+
+
+/** Class that contains information about a type constraint relations.
+ */
+struct ConstraintClassDef
+{
+ ConstraintClassDef(ClassDef *cd) : classDef(cd)
+ {
+ accessors = new QDict<void>(17);
+ }
+ ~ConstraintClassDef()
+ {
+ delete accessors;
+ }
+ void addAccessor(const char *s)
+ {
+ if (accessors->find(s)==0)
+ {
+ accessors->insert(s,(void *)666);
+ }
+ }
+ /** Class definition that this relation uses. */
+ ClassDef *classDef;
+
+ /** Dictionary of member types names that form the edge labels of the
+ * constraint relation.
+ */
+ QDict<void> *accessors;
+};
+
+/** Dictionary of constraint relations.
+ */
+class ConstraintClassDict : public QDict<ConstraintClassDef>
+{
+ public:
+ ConstraintClassDict(int size) : QDict<ConstraintClassDef>(size) {}
+ ~ConstraintClassDict() {}
+};
+
+/** Iterator class to iterate over a dictionary of constraint relations.
+ */
+class ConstraintClassDictIterator : public QDictIterator<ConstraintClassDef>
+{
+ public:
+ ConstraintClassDictIterator(const QDict<ConstraintClassDef> &d)
+ : QDictIterator<ConstraintClassDef>(d) {}
+ ~ConstraintClassDictIterator() {}
+};
+
+//------------------------------------------------------------------------
+
#endif
diff --git a/src/defargs.l b/src/defargs.l
index 164c100..70234b2 100644
--- a/src/defargs.l
+++ b/src/defargs.l
@@ -73,6 +73,7 @@ static QCString g_curArgName;
static QCString g_curArgDocs;
static QCString g_curArgAttrib;
static QCString g_curArgArray;
+static QCString g_curTypeConstraint;
static QCString g_extraTypeChars;
static int g_argRoundCount;
static int g_argSharpCount;
@@ -80,6 +81,7 @@ static int g_argCurlyCount;
static int g_readArgContext;
static int g_lastDocContext;
static int g_lastDocChar;
+static int g_lastExtendsContext;
static QCString g_delimiter;
/* -----------------------------------------------------------------
@@ -120,6 +122,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
%x FuncQual
%x ReadDocBlock
%x ReadDocLine
+%x ReadTypeConstraint
%x TrailingReturn
@@ -332,8 +335,9 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
int i=l-1;
while (i>=0 && (isspace((uchar)g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='.')) i--;
while (i>=0 && (isId(g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='$')) i--;
- Argument *a = new Argument;
- a->attrib = g_curArgAttrib.copy();
+ Argument *a = new Argument;
+ a->attrib = g_curArgAttrib.copy();
+ a->typeConstraint = g_curTypeConstraint.stripWhiteSpace();
//printf("a->type=%s a->name=%s i=%d l=%d\n",
// a->type.data(),a->name.data(),i,l);
a->array.resize(0);
@@ -413,6 +417,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
g_curArgDefValue.resize(0);
g_curArgArray.resize(0);
g_curArgDocs.resize(0);
+ g_curTypeConstraint.resize(0);
if (*yytext==')')
{
BEGIN(FuncQual);
@@ -424,6 +429,11 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
}
}
}
+<ReadFuncArgType,ReadFuncArgPtr>"extends" {
+ g_curTypeConstraint.resize(0);
+ g_lastExtendsContext=YY_START;
+ BEGIN(ReadTypeConstraint);
+ }
<ReadFuncArgType,ReadFuncArgPtr>"$"?{ID} {
QCString name=yytext; //resolveDefines(yytext);
if (YY_START==ReadFuncArgType && g_curArgArray=="[]") // Java style array
@@ -451,13 +461,23 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
<CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>. {
*g_copyArgValue += *yytext;
}
-<FuncQual>"const" {
+<ReadTypeConstraint>[,)>] {
+ unput(*yytext);
+ BEGIN(g_lastExtendsContext);
+ }
+<ReadTypeConstraint>. {
+ g_curTypeConstraint+=yytext;
+ }
+<ReadTypeConstraint>\n {
+ g_curTypeConstraint+=' ';
+ }
+<FuncQual>"const" {
g_argList->constSpecifier=TRUE;
}
-<FuncQual>"volatile" {
+<FuncQual>"volatile" {
g_argList->volatileSpecifier=TRUE;
}
-<FuncQual,TrailingReturn>"="{B}*"0" {
+<FuncQual,TrailingReturn>"="{B}*"0" {
g_argList->pureSpecifier=TRUE;
BEGIN(FuncQual);
}
@@ -534,6 +554,7 @@ void stringToArgumentList(const char *argsString,ArgumentList* al,QCString *extr
g_curArgDocs.resize(0);
g_curArgAttrib.resize(0);
g_curArgArray.resize(0);
+ g_curTypeConstraint.resize(0);
g_extraTypeChars.resize(0);
g_argRoundCount = 0;
g_argSharpCount = 0;
diff --git a/src/dot.cpp b/src/dot.cpp
index 1182e8d..cc81c44 100644
--- a/src/dot.cpp
+++ b/src/dot.cpp
@@ -164,7 +164,8 @@ static const char *normalEdgeColorMap[] =
"firebrick4", // Private
"darkorchid3", // "use" relation
"grey75", // Undocumented
- "orange" // template relation
+ "orange", // template relation
+ "orange" // type constraint
};
static const char *normalArrowStyleMap[] =
@@ -190,7 +191,8 @@ static const char *umlEdgeColorMap[] =
"firebrick4", // Private
"grey25", // "use" relation
"grey75", // Undocumented
- "orange" // template relation
+ "orange", // template relation
+ "orange" // type constraint
};
static const char *umlArrowStyleMap[] =
@@ -2003,6 +2005,7 @@ void DotNode::writeXML(FTextStream &t,bool isClassGraph)
case EdgeInfo::Red: t << "private-inheritance"; break;
case EdgeInfo::Purple: t << "usage"; break;
case EdgeInfo::Orange: t << "template-instance"; break;
+ case EdgeInfo::Orange2: t << "type-constraint"; break;
case EdgeInfo::Grey: ASSERT(0); break;
}
}
@@ -2071,6 +2074,7 @@ void DotNode::writeDocbook(FTextStream &t,bool isClassGraph)
case EdgeInfo::Red: t << "private-inheritance"; break;
case EdgeInfo::Purple: t << "usage"; break;
case EdgeInfo::Orange: t << "template-instance"; break;
+ case EdgeInfo::Orange2: t << "type-constraint"; break;
case EdgeInfo::Grey: ASSERT(0); break;
}
}
@@ -2148,6 +2152,7 @@ void DotNode::writeDEF(FTextStream &t)
case EdgeInfo::Red: t << "private-inheritance"; break;
case EdgeInfo::Purple: t << "usage"; break;
case EdgeInfo::Orange: t << "template-instance"; break;
+ case EdgeInfo::Orange2: t << "type-constraint"; break;
case EdgeInfo::Grey: ASSERT(0); break;
}
t << ';' << endl;
@@ -2591,7 +2596,7 @@ void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot,
{
if (Config_getBool("HIDE_UNDOC_CLASSES") && !cd->isLinkable()) return;
- int edgeStyle = (label || prot==EdgeInfo::Orange) ? EdgeInfo::Dashed : EdgeInfo::Solid;
+ int edgeStyle = (label || prot==EdgeInfo::Orange || prot==EdgeInfo::Orange2) ? EdgeInfo::Dashed : EdgeInfo::Solid;
QCString className;
if (usedName) // name is a typedef
{
@@ -2797,6 +2802,7 @@ bool DotClassGraph::determineVisibleNodes(DotNode *rootNode,
void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,bool base,int distance)
{
+ static bool templateRelations = Config_getBool("TEMPLATE_RELATIONS");
//printf("DocClassGraph::buildGraph(%s,distance=%d,base=%d)\n",
// cd->name().data(),distance,base);
// ---- Add inheritance relations
@@ -2856,10 +2862,43 @@ void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,bool base,int distance)
}
}
}
+ if (templateRelations && base)
+ {
+ ConstraintClassDict *dict = cd->templateTypeConstraints();
+ if (dict)
+ {
+ ConstraintClassDictIterator ccdi(*dict);
+ ConstraintClassDef *ccd;
+ for (;(ccd=ccdi.current());++ccdi)
+ {
+ QCString label;
+ QDictIterator<void> dvi(*ccd->accessors);
+ const char *s;
+ bool first=TRUE;
+ int count=0;
+ int maxLabels=10;
+ for (;(s=dvi.currentKey()) && count<maxLabels;++dvi,++count)
+ {
+ if (first)
+ {
+ label=s;
+ first=FALSE;
+ }
+ else
+ {
+ label+=QCString("\n")+s;
+ }
+ }
+ if (count==maxLabels) label+="\n...";
+ //printf("addClass: %s templSpec=%s\n",ucd->classDef->name().data(),ucd->templSpecifiers.data());
+ addClass(ccd->classDef,n,EdgeInfo::Orange2,label,0,
+ 0,TRUE,distance);
+ }
+ }
+ }
// ---- Add template instantiation relations
- static bool templateRelations = Config_getBool("TEMPLATE_RELATIONS");
if (templateRelations)
{
if (base) // template relations for base classes
diff --git a/src/dot.h b/src/dot.h
index 41a416e..df46aaf 100644
--- a/src/dot.h
+++ b/src/dot.h
@@ -45,7 +45,7 @@ enum EmbeddedOutputFormat { EOF_Html, EOF_LaTeX, EOF_Rtf, EOF_DocBook };
/** Attributes of an edge of a dot graph */
struct EdgeInfo
{
- enum Colors { Blue=0, Green=1, Red=2, Purple=3, Grey=4, Orange=5 };
+ enum Colors { Blue=0, Green=1, Red=2, Purple=3, Grey=4, Orange=5, Orange2=6 };
enum Styles { Solid=0, Dashed=1 };
EdgeInfo() : m_color(0), m_style(0), m_labColor(0) {}
~EdgeInfo() {}
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 54187a1..667227f 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -5018,6 +5018,7 @@ static void findUsedTemplateInstances()
{
rootNav->loadEntry(g_storage);
findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
+ cd->addTypeConstraints();
rootNav->releaseEntry();
}
}
diff --git a/src/scanner.l b/src/scanner.l
index 01d1677..21698ab 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -3592,6 +3592,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
sharpCount++;
}
<Sharp>{BN}+ {
+ current->type += ' ';
lineCount();
}
<Sharp>. { current->type += *yytext ; }
diff --git a/src/util.cpp b/src/util.cpp
index 83f65a4..ac0c1d6 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1741,9 +1741,11 @@ nextChar:
}
else if (i>0 &&
(
- (s.at(i-1)==')' && isId(c))
+ (s.at(i-1)==')' && isId(c)) // ")id" -> ") id"
||
- (c=='\'' && s.at(i-1)==' ')
+ (c=='\'' && s.at(i-1)==' ') // "'id" -> "' id"
+ ||
+ (i>1 && s.at(i-2)==' ' && s.at(i-1)==' ') // " id" -> " id"
)
)
{
@@ -2229,6 +2231,11 @@ QCString tempArgListToString(ArgumentList *al,SrcLangExt lang)
result+=a->type;
}
}
+ if (!a->typeConstraint.isEmpty() && lang==SrcLangExt_Java)
+ {
+ result+=" extends "; // TODO: now Java specific, C# has where...
+ result+=a->typeConstraint;
+ }
++ali;
a=ali.current();
if (a) result+=", ";