Doxygen
dotclassgraph.cpp
浏览该文件的文档.
1 /******************************************************************************
2 *
3 * Copyright (C) 1997-2019 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15 
16 #include <algorithm>
17 
18 #include "containers.h"
19 #include "dotclassgraph.h"
20 #include "dotnode.h"
21 #include "textstream.h"
22 
23 #include "config.h"
24 #include "util.h"
25 
26 void DotClassGraph::addClass(const ClassDef *cd,DotNode *n,int prot,
27  const QCString &label,const QCString &usedName,const QCString &templSpec,bool base,int distance)
28 {
29  if (Config_getBool(HIDE_UNDOC_CLASSES) && !cd->isLinkable()) return;
30 
31  int edgeStyle = (!label.isEmpty() || prot==EdgeInfo::Orange || prot==EdgeInfo::Orange2) ? EdgeInfo::Dashed : EdgeInfo::Solid;
32  QCString className;
33  QCString fullName;
34  if (cd->isAnonymous())
35  {
36  className="anonymous:";
37  className+=label;
38  fullName = className;
39  }
40  else if (!usedName.isEmpty()) // name is a typedef
41  {
42  className=usedName;
43  fullName = className;
44  }
45  else if (!templSpec.isEmpty()) // name has a template part
46  {
47  className=insertTemplateSpecifierInScope(cd->displayName(),templSpec);
48  fullName =insertTemplateSpecifierInScope(cd->name(),templSpec);
49  }
50  else // just a normal name
51  {
52  className=cd->displayName();
53  fullName = cd->name();
54  }
55  //printf("DotClassGraph::addClass(class='%s',parent=%s,prot=%d,label=%s,dist=%d,usedName=%s,templSpec=%s,base=%d)\n",
56  // qPrint(className),qPrint(n->label()),prot,label,distance,usedName,templSpec,base);
57  auto it = m_usedNodes.find(fullName.str());
58  if (it!=m_usedNodes.end()) // class already inserted
59  {
60  DotNode *bn = it->second;
61  if (base)
62  {
63  n->addChild(bn,prot,edgeStyle,label);
64  bn->addParent(n);
65  }
66  else
67  {
68  bn->addChild(n,prot,edgeStyle,label);
69  n->addParent(bn);
70  }
71  bn->setDistance(distance);
72  //printf(" add exiting node %s of %s\n",qPrint(bn->label()),qPrint(n->label()));
73  }
74  else // new class
75  {
76  QCString displayName=className;
77  if (Config_getBool(HIDE_SCOPE_NAMES)) displayName=stripScope(displayName);
78  QCString tmp_url;
79  if (cd->isLinkable() && !cd->isHidden())
80  {
81  tmp_url=cd->getReference()+"$"+cd->getOutputFileBase();
82  if (!cd->anchor().isEmpty())
83  {
84  tmp_url+="#"+cd->anchor();
85  }
86  }
87  QCString tooltip = cd->briefDescriptionAsTooltip();
88  DotNode *bn = new DotNode(getNextNodeNumber(),
89  displayName,
90  tooltip,
91  tmp_url,
92  FALSE, // rootNode
93  cd
94  );
95  if (base)
96  {
97  n->addChild(bn,prot,edgeStyle,label);
98  bn->addParent(n);
99  }
100  else
101  {
102  bn->addChild(n,prot,edgeStyle,label);
103  n->addParent(bn);
104  }
105  bn->setDistance(distance);
106  m_usedNodes.insert(std::make_pair(fullName.str(),bn));
107  //printf(" add new child node '%s' to %s hidden=%d url=%s\n",
108  // qPrint(className),qPrint(n->label()),cd->isHidden(),qPrint(tmp_url));
109 
110  buildGraph(cd,bn,base,distance+1);
111  }
112 }
113 
114 void DotClassGraph::determineTruncatedNodes(DotNodeDeque &queue,bool includeParents)
115 {
116  while (!queue.empty())
117  {
118  DotNode *n = queue.front();
119  queue.pop_front();
120  if (n->isVisible() && n->isTruncated()==DotNode::Unknown)
121  {
122  bool truncated = FALSE;
123  for (const auto &dn : n->children())
124  {
125  if (!dn->isVisible())
126  truncated = TRUE;
127  else
128  queue.push_back(dn);
129  }
130  if (includeParents)
131  {
132  for (const auto &dn : n->parents())
133  {
134  if (!dn->isVisible())
135  truncated = TRUE;
136  else
137  queue.push_back(dn);
138  }
139  }
140  n->markAsTruncated(truncated);
141  }
142  }
143 }
144 
146  int maxNodes,bool includeParents)
147 {
148  DotNodeDeque childQueue;
149  DotNodeDeque parentQueue;
150  IntVector childTreeWidth;
151  IntVector parentTreeWidth;
152  childQueue.push_back(rootNode);
153  if (includeParents) parentQueue.push_back(rootNode);
154  bool firstNode=TRUE; // flag to force reprocessing rootNode in the parent loop
155  // despite being marked visible in the child loop
156  while ((!childQueue.empty() || !parentQueue.empty()) && maxNodes>0)
157  {
158  if (!childQueue.empty())
159  {
160  DotNode *n = childQueue.front();
161  childQueue.pop_front();
162  int distance = n->distance();
163  if (!n->isVisible() && distance<=Config_getInt(MAX_DOT_GRAPH_DEPTH)) // not yet processed
164  {
165  if (distance>0)
166  {
167  int oldSize=(int)childTreeWidth.size();
168  if (distance>oldSize)
169  {
170  childTreeWidth.resize(std::max(childTreeWidth.size(),(size_t)distance));
171  int i; for (i=oldSize;i<distance;i++) childTreeWidth[i]=0;
172  }
173  childTreeWidth[distance-1]+=n->label().length();
174  }
175  n->markAsVisible();
176  maxNodes--;
177  // add direct children
178  for (const auto &dn : n->children())
179  {
180  childQueue.push_back(dn);
181  }
182  }
183  }
184  if (includeParents && !parentQueue.empty())
185  {
186  DotNode *n = parentQueue.front();
187  parentQueue.pop_front();
188  if ((!n->isVisible() || firstNode) && n->distance()<=Config_getInt(MAX_DOT_GRAPH_DEPTH)) // not yet processed
189  {
190  firstNode=FALSE;
191  int distance = n->distance();
192  if (distance>0)
193  {
194  int oldSize = (int)parentTreeWidth.size();
195  if (distance>oldSize)
196  {
197  parentTreeWidth.resize(std::max(parentTreeWidth.size(),(size_t)distance));
198  int i; for (i=oldSize;i<distance;i++) parentTreeWidth[i]=0;
199  }
200  parentTreeWidth[distance-1]+=n->label().length();
201  }
202  n->markAsVisible();
203  maxNodes--;
204  // add direct parents
205  for (const auto &dn : n->parents())
206  {
207  parentQueue.push_back(dn);
208  }
209  }
210  }
211  }
212  if (Config_getBool(UML_LOOK)) return FALSE; // UML graph are always top to bottom
213  int maxWidth=0;
214  int maxHeight=(int)std::max(childTreeWidth.size(),parentTreeWidth.size());
215  uint i;
216  for (i=0;i<childTreeWidth.size();i++)
217  {
218  if (childTreeWidth.at(i)>maxWidth) maxWidth=childTreeWidth.at(i);
219  }
220  for (i=0;i<parentTreeWidth.size();i++)
221  {
222  if (parentTreeWidth.at(i)>maxWidth) maxWidth=parentTreeWidth.at(i);
223  }
224  //printf("max tree width=%d, max tree height=%d\n",maxWidth,maxHeight);
225  return maxWidth>80 && maxHeight<12; // used metric to decide to render the tree
226  // from left to right instead of top to bottom,
227  // with the idea to render very wide trees in
228  // left to right order.
229 }
230 
231 static QCString joinLabels(const StringSet &ss)
232 {
233  QCString label;
234  int count=1;
235  int maxLabels=10;
236  auto it = std::begin(ss), e = std::end(ss);
237  if (it!=e) // set not empty
238  {
239  label += (*it++).c_str();
240  for (; it!=e && count < maxLabels ; ++it,++count)
241  {
242  label += '\n';
243  label += (*it).c_str();
244  }
245  if (count==maxLabels) label+="\n...";
246  }
247  return label;
248 }
249 
250 void DotClassGraph::buildGraph(const ClassDef *cd,DotNode *n,bool base,int distance)
251 {
252  //printf("DocClassGraph::buildGraph(%s,distance=%d,base=%d)\n",
253  // qPrint(cd->name()),distance,base);
254  // ---- Add inheritance relations
255 
257  {
258  for (const auto &bcd : base ? cd->baseClasses() : cd->subClasses())
259  {
260  //printf("-------- inheritance relation %s->%s templ='%s'\n",
261  // qPrint(cd->name()),qPrint(bcd->classDef->name()),qPrint(bcd->templSpecifiers));
262  addClass(bcd.classDef,n,bcd.prot,QCString(),bcd.usedName,bcd.templSpecifiers,base,distance);
263  }
264  }
265  if (m_graphType == Collaboration)
266  {
267  // ---- Add usage relations
268 
269  const UsesClassList &list = base ? cd->usedImplementationClasses() :
271  for (const auto &ucd : list)
272  {
273  //printf("addClass: %s templSpec=%s\n",qPrint(ucd.classDef->name()),qPrint(ucd.templSpecifiers));
274  addClass(ucd.classDef,n,EdgeInfo::Purple,joinLabels(ucd.accessors),QCString(),
275  ucd.templSpecifiers,base,distance);
276  }
277  }
278  if (Config_getBool(TEMPLATE_RELATIONS) && base)
279  {
280  for (const auto &ccd : cd->templateTypeConstraints())
281  {
282  //printf("addClass: %s\n",qPrint(ccd.classDef->name()));
283  addClass(ccd.classDef,n,EdgeInfo::Orange2,joinLabels(ccd.accessors),QCString(),
284  QCString(),TRUE,distance);
285  }
286  }
287 
288  // ---- Add template instantiation relations
289 
290  if (Config_getBool(TEMPLATE_RELATIONS))
291  {
292  if (base) // template relations for base classes
293  {
294  const ClassDef *templMaster=cd->templateMaster();
295  if (templMaster)
296  {
297  for (const auto &ti : templMaster->getTemplateInstances())
298  if (ti.classDef==cd)
299  {
300  addClass(templMaster,n,EdgeInfo::Orange,ti.templSpec,QCString(),QCString(),TRUE,distance);
301  }
302  }
303  }
304  else // template relations for super classes
305  {
306  for (const auto &ti : cd->getTemplateInstances())
307  {
308  addClass(ti.classDef,n,EdgeInfo::Orange,ti.templSpec,QCString(),QCString(),FALSE,distance);
309  }
310  }
311  }
312 }
313 
315 {
316  //printf("--------------- DotClassGraph::DotClassGraph '%s'\n",qPrint(cd->displayName()));
317  m_graphType = t;
318  QCString tmp_url="";
319  if (cd->isLinkable() && !cd->isHidden())
320  {
321  tmp_url=cd->getReference()+"$"+cd->getOutputFileBase();
322  if (!cd->anchor().isEmpty())
323  {
324  tmp_url+="#"+cd->anchor();
325  }
326  }
327  QCString className = cd->displayName();
328  QCString tooltip = cd->briefDescriptionAsTooltip();
330  className,
331  tooltip,
332  tmp_url,
333  TRUE, // is a root node
334  cd
335  );
337  m_usedNodes.insert(std::make_pair(className.str(),m_startNode));
338 
340  if (t==Inheritance) buildGraph(cd,m_startNode,FALSE,1);
341 
343  DotNodeDeque openNodeQueue;
344  openNodeQueue.push_back(m_startNode);
345  determineTruncatedNodes(openNodeQueue,t==Inheritance);
346 
349 }
350 
352 {
354  return m_startNode->children().empty() && m_startNode->parents().empty();
355  else
356  return !Config_getBool(UML_LOOK) && m_startNode->children().empty();
357 }
358 
360 {
361  return numNodes()>=Config_getInt(DOT_GRAPH_MAX_NODES);
362 }
363 
365 {
366  int numNodes = 0;
367  numNodes+= (int)m_startNode->children().size();
369  {
370  numNodes+= (int)m_startNode->parents().size();
371  }
372  return numNodes;
373 }
374 
376 {
378 }
379 
381 {
382  switch (m_graphType)
383  {
384  case Collaboration:
385  return m_collabFileName;
386  break;
387  case Inheritance:
388  return m_inheritFileName;
389  break;
390  default:
391  ASSERT(0);
392  break;
393  }
394  return "";
395 }
396 
398 {
399  computeGraph(
400  m_startNode,
401  m_graphType,
403  m_lrRank ? "LR" : "",
405  TRUE,
406  m_startNode->label(),
407  m_theGraph
408  );
409 }
410 
412 {
413  QCString mapName;
414  switch (m_graphType)
415  {
416  case Collaboration:
417  mapName="coll_map";
418  break;
419  case Inheritance:
420  mapName="inherit_map";
421  break;
422  default:
423  ASSERT(0);
424  break;
425  }
426 
428 }
429 
431 {
432  switch (m_graphType)
433  {
434  case Collaboration:
435  return "Collaboration graph";
436  break;
437  case Inheritance:
438  return "Inheritance graph";
439  break;
440  default:
441  ASSERT(0);
442  break;
443  }
444  return "";
445 }
446 
448  GraphOutputFormat graphFormat,
449  EmbeddedOutputFormat textFormat,
450  const QCString &path,
451  const QCString &fileName,
452  const QCString &relPath,
453  bool /*isTBRank*/,
454  bool generateImageMap,
455  int graphId)
456 {
457  return DotGraph::writeGraph(out, graphFormat, textFormat, path, fileName, relPath, generateImageMap, graphId);
458 }
459 
460 //--------------------------------------------------------------------
461 
463 {
464  for (const auto &kv : m_usedNodes)
465  {
466  kv.second->writeXML(t,TRUE);
467  }
468 }
469 
471 {
472  for (const auto &kv : m_usedNodes)
473  {
474  kv.second->writeDocbook(t,TRUE);
475  }
476 }
477 
479 {
480  for (const auto &kv : m_usedNodes)
481  {
482  kv.second->writeDEF(t);
483  }
484 }
DotGraph::computeGraph
static void computeGraph(DotNode *root, GraphType gt, GraphOutputFormat format, const QCString &rank, bool renderParents, bool backArrows, const QCString &title, QCString &graphStr)
Definition: dotgraph.cpp:305
DotNode::addChild
void addChild(DotNode *n, int edgeColor=EdgeInfo::Purple, int edgeStyle=EdgeInfo::Solid, const QCString &edgeLab=QCString(), const QCString &edgeURL=QCString(), int edgeLabCol=-1)
Definition: dotnode.cpp:281
DotNode::parents
const DotNodeRefVector & parents() const
Definition: dotnode.h:110
DotGraph::m_theGraph
QCString m_theGraph
Definition: dotgraph.h:89
stripScope
QCString stripScope(const QCString &name)
Definition: util.cpp:3815
DotNode::Unknown
@ Unknown
Definition: dotnode.h:65
DotNode::setDistance
void setDistance(int distance)
Definition: dotnode.cpp:333
QCString::length
uint length() const
Returns the length of the string, not counting the 0-terminator.
Definition: qcstring.h:147
dotnode.h
QCString::isEmpty
bool isEmpty() const
Returns TRUE iff the string is empty
Definition: qcstring.h:144
DotNode::markAsTruncated
void markAsTruncated(bool b=TRUE)
Definition: dotnode.h:108
StringSet
std::set< std::string > StringSet
Definition: containers.h:30
QCString::str
std::string str() const
Definition: qcstring.h:442
DotNode::deleteNodes
static void deleteNodes(DotNode *node)
Definition: dotnode.cpp:347
Definition::isHidden
virtual bool isHidden() const =0
DotClassGraph::writeGraph
QCString writeGraph(TextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef, const QCString &path, const QCString &fileName, const QCString &relPath, bool TBRank=TRUE, bool imageMap=TRUE, int graphId=-1)
Definition: dotclassgraph.cpp:447
DotNode::addParent
void addParent(DotNode *n)
Definition: dotnode.cpp:298
DotGraph::getNextNodeNumber
int getNextNodeNumber()
returns node numbers.
Definition: dotgraph.h:41
IntVector
std::vector< int > IntVector
Definition: containers.h:36
textstream.h
TextStream
Text streaming class that buffers data.
Definition: textstream.h:33
DotClassGraph::~DotClassGraph
~DotClassGraph()
Definition: dotclassgraph.cpp:375
EdgeInfo::Solid
@ Solid
Definition: dotnode.h:35
DotNode::markAsVisible
void markAsVisible(bool b=TRUE)
Definition: dotnode.h:107
begin
DirIterator begin(DirIterator it) noexcept
Definition: dir.cpp:123
EdgeInfo::Orange
@ Orange
Definition: dotnode.h:34
end
DirIterator end(const DirIterator &) noexcept
Definition: dir.cpp:128
ClassDef::templateMaster
virtual const ClassDef * templateMaster() const =0
Returns the template master of which this class is an instance.
uint
unsigned uint
Definition: qcstring.h:40
DotNode
A node in a dot graph
Definition: dotnode.h:56
DotClassGraph::m_inheritFileName
QCString m_inheritFileName
Definition: dotclassgraph.h:62
ClassDef
A abstract class representing of a compound symbol.
Definition: classdef.h:103
Config_getInt
#define Config_getInt(name)
Definition: config.h:34
DotClassGraph::computeTheGraph
virtual void computeTheGraph()
Definition: dotclassgraph.cpp:397
DotClassGraph::buildGraph
void buildGraph(const ClassDef *cd, DotNode *n, bool base, int distance)
Definition: dotclassgraph.cpp:250
Definition::isAnonymous
virtual bool isAnonymous() const =0
GraphType
GraphType
Definition: dotgraph.h:29
ClassDef::getTemplateInstances
virtual const TemplateInstanceList & getTemplateInstances() const =0
Returns a sorted dictionary with all template instances found for this template class.
ClassDef::getOutputFileBase
virtual QCString getOutputFileBase() const =0
Returns the unique base name (without extension) of the class's file on disk
ClassDef::baseClasses
virtual const BaseClassList & baseClasses() const =0
Returns the list of base classes from which this class directly inherits.
Definition::name
virtual QCString name() const =0
DotNode::label
QCString label() const
Definition: dotnode.h:89
joinLabels
static QCString joinLabels(const StringSet &ss)
Definition: dotclassgraph.cpp:231
DotClassGraph::getImgAltText
virtual QCString getImgAltText() const
Definition: dotclassgraph.cpp:430
DotGraph::m_graphFormat
GraphOutputFormat m_graphFormat
Definition: dotgraph.h:79
TRUE
#define TRUE
Definition: qcstring.h:36
DotClassGraph::m_lrRank
bool m_lrRank
Definition: dotclassgraph.h:63
EdgeInfo::Dashed
@ Dashed
Definition: dotnode.h:35
DotClassGraph::m_collabFileName
QCString m_collabFileName
Definition: dotclassgraph.h:61
DotNode::isTruncated
TruncState isTruncated() const
Definition: dotnode.h:92
DotClassGraph::m_startNode
DotNode * m_startNode
Definition: dotclassgraph.h:58
DotNode::isVisible
bool isVisible() const
Definition: dotnode.h:91
insertTemplateSpecifierInScope
QCString insertTemplateSpecifierInScope(const QCString &scope, const QCString &templ)
Definition: util.cpp:3782
DotClassGraph::m_graphType
GraphType m_graphType
Definition: dotclassgraph.h:60
Collaboration
@ Collaboration
Definition: dotgraph.h:29
DotClassGraph::addClass
void addClass(const ClassDef *cd, DotNode *n, int prot, const QCString &label, const QCString &usedName, const QCString &templSpec, bool base, int distance)
Definition: dotclassgraph.cpp:26
ClassDef::subClasses
virtual const BaseClassList & subClasses() const =0
Returns the list of sub classes that directly derive from this class
DotClassGraph::getBaseName
virtual QCString getBaseName() const
Definition: dotclassgraph.cpp:380
DotGraph::writeGraph
QCString writeGraph(TextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef, const QCString &path, const QCString &fileName, const QCString &relPath, bool writeImageMap=TRUE, int graphId=-1)
Definition: dotgraph.cpp:111
dotclassgraph.h
DotClassGraph::writeDEF
void writeDEF(TextStream &t)
Definition: dotclassgraph.cpp:478
containers.h
DotClassGraph::writeXML
void writeXML(TextStream &t)
Definition: dotclassgraph.cpp:462
DotNodeDeque
Definition: dotnode.h:137
DotClassGraph::m_usedNodes
DotNodeMap m_usedNodes
Definition: dotclassgraph.h:59
Config_getBool
#define Config_getBool(name)
Definition: config.h:33
DotNode::distance
int distance() const
Definition: dotnode.h:93
DotClassGraph::writeDocbook
void writeDocbook(TextStream &t)
Definition: dotclassgraph.cpp:470
ClassDef::collaborationGraphFileName
virtual QCString collaborationGraphFileName() const =0
returns the file name to use for the collaboration graph
ClassDef::getReference
virtual QCString getReference() const =0
If this class originated from a tagfile, this will return the tag file reference
escapeCharsInString
QCString escapeCharsInString(const QCString &name, bool allowDots, bool allowUnderscore)
Definition: util.cpp:3442
DotClassGraph::isTrivial
bool isTrivial() const
Definition: dotclassgraph.cpp:351
DotClassGraph::getMapLabel
virtual QCString getMapLabel() const
Definition: dotclassgraph.cpp:411
ClassDef::usedImplementationClasses
virtual const UsesClassList & usedImplementationClasses() const =0
EdgeInfo::Purple
@ Purple
Definition: dotnode.h:34
DotClassGraph::determineVisibleNodes
bool determineVisibleNodes(DotNode *rootNode, int maxNodes, bool includeParents)
Definition: dotclassgraph.cpp:145
Inheritance
@ Inheritance
Definition: dotgraph.h:29
config.h
ClassDef::displayName
virtual QCString displayName(bool includeScope=TRUE) const =0
Returns the name as it is appears in the documentation
ASSERT
#define ASSERT(x)
Definition: qcstring.h:44
EmbeddedOutputFormat
EmbeddedOutputFormat
Definition: dotgraph.h:28
GraphOutputFormat
GraphOutputFormat
Definition: dotgraph.h:27
DotClassGraph::determineTruncatedNodes
void determineTruncatedNodes(DotNodeDeque &queue, bool includeParents)
Definition: dotclassgraph.cpp:114
EdgeInfo::Orange2
@ Orange2
Definition: dotnode.h:34
Definition::briefDescriptionAsTooltip
virtual QCString briefDescriptionAsTooltip() const =0
util.h
A bunch of utility functions.
DotClassGraph::numNodes
int numNodes() const
Definition: dotclassgraph.cpp:364
UsesClassList
Definition: classdef.h:528
DotClassGraph::isTooBig
bool isTooBig() const
Definition: dotclassgraph.cpp:359
ClassDef::isLinkable
virtual bool isLinkable() const =0
return TRUE iff a link to this class is possible (either within this project, or as a cross-reference...
ClassDef::templateTypeConstraints
virtual const ConstraintClassList & templateTypeConstraints() const =0
ClassDef::inheritanceGraphFileName
virtual QCString inheritanceGraphFileName() const =0
returns the file name to use for the inheritance graph
DotNode::children
const DotNodeRefVector & children() const
Definition: dotnode.h:109
FALSE
#define FALSE
Definition: qcstring.h:33
ClassDef::usedByImplementationClasses
virtual const UsesClassList & usedByImplementationClasses() const =0
ClassDef::anchor
virtual QCString anchor() const =0
DotClassGraph::DotClassGraph
DotClassGraph(const ClassDef *cd, GraphType t)
Definition: dotclassgraph.cpp:314
QCString
This is an alternative implementation of QCString.
Definition: qcstring.h:108