Doxygen
Loading...
Searching...
No Matches
definition.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2023 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#include <iterator>
18#include <unordered_map>
19#include <string>
20#include <optional>
21#include <cctype>
22#include <cstdio>
23#include <cstdlib>
24#include <cassert>
25
26#include "anchor.h"
27#include "md5.h"
28#include "regex.h"
29#include "config.h"
30#include "definitionimpl.h"
31#include "doxygen.h"
32#include "language.h"
33#include "message.h"
34#include "portable.h"
35#include "outputlist.h"
36#include "code.h"
37#include "util.h"
38#include "groupdef.h"
39#include "pagedef.h"
40#include "section.h"
41#include "htags.h"
42#include "parserintf.h"
43#include "debug.h"
44#include "vhdldocgen.h"
45#include "memberlist.h"
46#include "namespacedef.h"
47#include "filedef.h"
48#include "dirdef.h"
49#include "pagedef.h"
50#include "reflist.h"
51#include "utf8.h"
52#include "indexlist.h"
53#include "fileinfo.h"
54
55//-----------------------------------------------------------------------------------------
56
57/** Private data associated with a Symbol DefinitionImpl object. */
59{
60 public:
61 void init(const QCString &df, const QCString &n);
62 void setDefFileName(const QCString &df);
63
64 Definition *def = nullptr;
65
67
68 std::unordered_map<std::string,MemberDef *> sourceRefByDict;
69 std::unordered_map<std::string,MemberDef *> sourceRefsDict;
72
73 std::optional<DocInfo> details; // not exported
74 std::optional<DocInfo> inbodyDocs; // not exported
75 std::optional<BriefInfo> brief; // not exported
76 std::optional<BodyInfo> body; // not exported
77
80
81 QCString localName; // local (unqualified) name of the definition
82 // in the future m_name should become m_localName
84 QCString ref; // reference to external documentation
85
86 bool hidden = FALSE;
90
91 Definition *outerScope = nullptr; // not owner
92
93 // where the item was defined
96
98
99 QCString id; // clang unique id
100
106
107 MemberVector referencesMembers; // cache for getReferencesMembers()
108 MemberVector referencedByMembers; // cache for getReferencedByMembers()
109};
110
111
113{
114 defFileName = df;
115 int lastDot = defFileName.findRev('.');
116 if (lastDot!=-1)
117 {
118 defFileExt = defFileName.mid(lastDot);
119 }
120}
121
123{
124 setDefFileName(df);
125 QCString lname = n;
126 if (lname!="<globalScope>")
127 {
128 //extractNamespaceName(m_name,m_localName,ns);
130 }
131 else
132 {
133 localName=n;
134 }
135 //printf("localName=%s\n",qPrint(localName));
136
137 brief.reset();
138 details.reset();
139 body.reset();
140 inbodyDocs.reset();
141 sourceRefByDict.clear();
142 sourceRefsDict.clear();
144 hidden = FALSE;
148}
149
150void DefinitionImpl::setDefFile(const QCString &df,int defLine,int defCol)
151{
152 p->setDefFileName(df);
153 p->defLine = defLine;
154 p->defColumn = defCol;
155}
156
157//-----------------------------------------------------------------------------------------
158
160{
161 const StringVector &exclSyms = Config_getList(EXCLUDE_SYMBOLS);
162 if (exclSyms.empty()) return FALSE; // nothing specified
163 std::string symName = name.str();
164 for (const auto &pat : exclSyms)
165 {
166 QCString pattern = pat.c_str();
167 bool forceStart=FALSE;
168 bool forceEnd=FALSE;
169 if (pattern.at(0)=='^')
170 pattern=pattern.mid(1),forceStart=TRUE;
171 if (pattern.at(pattern.length()-1)=='$')
172 pattern=pattern.left(pattern.length()-1),forceEnd=TRUE;
173 if (pattern.find('*')!=-1) // wildcard mode
174 {
175 const reg::Ex re(substitute(pattern,"*",".*").str());
176 reg::Match match;
177 if (reg::search(symName,match,re)) // wildcard match
178 {
179 size_t ui = match.position();
180 size_t pl = match.length();
181 size_t sl = symName.length();
182 if ((ui==0 || pattern.at(0)=='*' || (!isId(symName.at(ui-1)) && !forceStart)) &&
183 (ui+pl==sl || pattern.at(pattern.length()-1)=='*' || (!isId(symName.at(ui+pl)) && !forceEnd))
184 )
185 {
186 //printf("--> name=%s pattern=%s match at %d\n",qPrint(symName),qPrint(pattern),i);
187 return TRUE;
188 }
189 }
190 }
191 else if (!pattern.isEmpty()) // match words
192 {
193 size_t i = symName.find(pattern.str());
194 if (i!=std::string::npos) // we have a match!
195 {
196 size_t ui=i;
197 size_t pl=pattern.length();
198 size_t sl=symName.length();
199 // check if it is a whole word match
200 if ((ui==0 || (!isId(symName.at(ui-1)) && !forceStart)) &&
201 (ui+pl==sl || (!isId(symName.at(ui+pl)) && !forceEnd))
202 )
203 {
204 //printf("--> name=%s pattern=%s match at %d\n",qPrint(symName),qPrint(pattern),i);
205 return TRUE;
206 }
207 }
208 }
209 }
210 //printf("--> name=%s: no match\n",name);
211 return FALSE;
212}
213
214static void addToMap(const QCString &name,Definition *d)
215{
216 bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
219 if (!vhdlOpt && index!=-1) symbolName=symbolName.mid(index+2);
220 if (!symbolName.isEmpty())
221 {
222 //printf("adding symbol %s\n",qPrint(symbolName));
224
226 }
227}
228
229static void removeFromMap(const QCString &name,Definition *d)
230{
231 Doxygen::symbolMap->remove(name,d);
232}
233
235 const QCString &df,int dl,int dc,
236 const QCString &name,const char *b,
237 const char *d,bool isSymbol)
238 : p(std::make_unique<Private>())
239{
240 setName(name);
241 p->def = def;
242 p->defLine = dl;
243 p->defColumn = dc;
244 p->init(df,name);
245 p->isSymbol = isSymbol;
246 if (isSymbol) addToMap(name,def);
247 _setBriefDescription(b,df,dl);
250 {
251 p->hidden = TRUE;
252 }
253}
254
256 : p(std::make_unique<Private>(*d.p))
257{
258 if (p->isSymbol) addToMap(p->name,p->def);
259}
260
262{
263 if (this!=&other)
264 {
265 p = std::make_unique<Private>(*other.p);
266 }
267 return *this;
268}
269
271{
272 if (p->isSymbol)
273 {
274 removeFromMap(p->symbolName,p->def);
275 }
276}
277
279{
280 if (name.isEmpty()) return;
281 p->name = name;
282 p->isAnonymous = p->name.isEmpty() ||
283 p->name.at(0)=='@' ||
284 p->name.find("::@")!=-1;
285}
286
288{
289 if (id.isEmpty()) return;
290 p->id = id;
292 {
293 //printf("DefinitionImpl::setId '%s'->'%s'\n",id,qPrint(p->name));
294 Doxygen::clangUsrMap->emplace(id.str(),p->def);
295 }
296}
297
299{
300 return p->id;
301}
302
303void DefinitionImpl::addSectionsToDefinition(const std::vector<const SectionInfo*> &anchorList)
304{
305 //printf("%s: addSectionsToDefinition(%d)\n",qPrint(name()),anchorList->count());
306 for (const SectionInfo *si : anchorList)
307 {
308 //printf("Add section '%s' to definition '%s'\n",
309 // qPrint(si->label()),qPrint(name()));
311 SectionInfo *gsi=sm.find(si->label());
312 //printf("===== label=%s gsi=%p\n",qPrint(si->label),gsi);
313 if (gsi==nullptr)
314 {
315 gsi = sm.add(*si);
316 }
317 if (p->sectionRefs.find(gsi->label())==nullptr)
318 {
319 p->sectionRefs.add(gsi);
320 gsi->setDefinition(p->def);
321 }
322 }
323}
324
326{
327 //printf("DefinitionImpl::hasSections(%s) #sections=%d\n",qPrint(name()),
328 // p->sectionRefs.size());
329 if (p->sectionRefs.empty()) return FALSE;
330 for (const SectionInfo *si : p->sectionRefs)
331 {
332 if (si->type().isSection())
333 {
334 return TRUE;
335 }
336 }
337 return FALSE;
338}
339
341{
342 if (!p->sectionRefs.empty())
343 {
344 //printf("%s: writeDocAnchorsToTagFile(%d)\n",qPrint(name()),p->sectionRef.size());
345 for (const SectionInfo *si : p->sectionRefs)
346 {
347 if (!si->generated() && si->ref().isEmpty() && !AnchorGenerator::instance().isGenerated(si->label().str()))
348 {
349 //printf("write an entry!\n");
350 if (p->def->definitionType()==Definition::TypeMember) tagFile << " ";
351 QCString fn = si->fileName();
353 tagFile << " <docanchor file=\"" << fn << "\"";
354 if (!si->title().isEmpty())
355 {
356 tagFile << " title=\"" << convertToXML(si->title()) << "\"";
357 }
358 tagFile << ">" << si->label() << "</docanchor>\n";
359 }
360 }
361 }
362}
363
365{
366 uint8_t md5_sig[16];
367 char sigStr[33];
368 // to avoid mismatches due to differences in indenting, we first remove
369 // double whitespaces...
370 QCString docStr = doc.simplifyWhiteSpace();
371 MD5Buffer(docStr.data(),static_cast<unsigned int>(docStr.length()),md5_sig);
372 MD5SigToString(md5_sig,sigStr);
373 //printf("%s:_docsAlreadyAdded doc='%s' sig='%s' docSigs='%s'\n",
374 // qPrint(name()),qPrint(doc),qPrint(sigStr),qPrint(sigList));
375 if (sigList.find(sigStr)==-1) // new docs, add signature to prevent re-adding it
376 {
377 sigList+=QCString(":")+sigStr;
378 return FALSE;
379 }
380 else
381 {
382 return TRUE;
383 }
384}
385
387 bool stripWhiteSpace,bool atTop)
389 //printf("%s::setDocumentation(%s,%s,%d,%d)\n",qPrint(name()),d,docFile,docLine,stripWhiteSpace);
390 if (d.isEmpty()) return;
391 QCString doc = d;
392 if (stripWhiteSpace)
393 {
395 }
396 else // don't strip whitespace
397 {
398 doc=d;
399 }
400 if (!_docsAlreadyAdded(doc,p->docSignatures))
401 {
402 //printf("setting docs for %s: '%s'\n",qPrint(name()),qPrint(m_doc));
403 if (!p->details.has_value())
404 {
405 p->details = std::make_optional<DocInfo>();
406 }
407 DocInfo &details = p->details.value();
408 if (details.doc.isEmpty()) // fresh detailed description
409 {
410 details.doc = doc;
411 }
412 else if (atTop) // another detailed description, append it to the start
413 {
414 details.doc = doc+"\n\n"+details.doc;
415 }
416 else // another detailed description, append it to the end
417 {
418 details.doc += "\n\n"+doc;
419 }
420 if (docLine!=-1) // store location if valid
421 {
422 details.file = docFile;
423 details.line = docLine;
424 }
425 else
426 {
427 details.file = docFile;
428 details.line = 1;
429 }
430 }
431}
432
438
440{
441 QCString brief = b;
442 brief = brief.stripWhiteSpace();
444 brief = brief.stripWhiteSpace();
445 if (brief.isEmpty()) return;
446 size_t bl = brief.length();
447 if (bl>0)
448 {
449 if (!theTranslator || theTranslator->needsPunctuation()) // add punctuation if needed
450 {
451 int c = brief.at(bl-1);
452 switch(c)
453 {
454 case '.': case '!': case '?': case '>': case ':': case ')': break;
455 default:
456 if (isUTF8CharUpperCase(brief.str(),0) && !lastUTF8CharIsMultibyte(brief.str())) brief+='.';
457 break;
458 }
459 }
460 }
461
462 if (!_docsAlreadyAdded(brief,p->briefSignatures))
463 {
464 if (p->brief && !p->brief->doc.isEmpty())
465 {
466 //printf("adding to details\n");
468 }
469 else
470 {
471 //fprintf(stderr,"DefinitionImpl::setBriefDescription(%s,%s,%d)\n",b,briefFile,briefLine);
472 if (!p->brief.has_value())
473 {
474 p->brief = std::make_optional<BriefInfo>();
475 }
476 BriefInfo &briefInfo = p->brief.value();
477 briefInfo.doc=brief;
478 if (briefLine!=-1)
479 {
480 briefInfo.file = briefFile;
481 briefInfo.line = briefLine;
482 }
483 else
484 {
485 briefInfo.file = briefFile;
486 briefInfo.line = 1;
487 }
488 }
489 }
490 else
491 {
492 //printf("do nothing!\n");
493 }
494}
495
501
503{
504 if (!_docsAlreadyAdded(doc,p->docSignatures))
505 {
506 if (!p->inbodyDocs.has_value())
507 {
508 p->inbodyDocs = std::make_optional<DocInfo>();
509 }
510 DocInfo &inbodyDocs = p->inbodyDocs.value();
511 if (inbodyDocs.doc.isEmpty()) // fresh inbody docs
512 {
513 inbodyDocs.doc = doc;
514 inbodyDocs.file = inbodyFile;
515 inbodyDocs.line = inbodyLine;
516 }
517 else // another inbody documentation fragment, append this to the end
518 {
519 inbodyDocs.doc += QCString("\n\n")+doc;
520 }
521 }
522}
523
529
530//---------------------------------------
531
532/*! Cache for storing the result of filtering a file */
534{
535 private:
537 {
538 size_t filePos;
539 size_t fileSize;
540 };
541 using LineOffsets = std::vector<size_t>;
542
543 public:
544 static FilterCache &instance();
545
546 //! collects the part of file \a fileName starting at \a startLine and ending at \a endLine into
547 //! buffer \a str. Applies filtering if FILTER_SOURCE_FILES is enabled and the file extension
548 //! matches a filter. Caches file information so that subsequent extraction of blocks from
549 //! the same file can be performed efficiently
550 bool getFileContents(const QCString &fileName,size_t startLine,size_t endLine, std::string &str)
551 {
552 bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
553 QCString filter = getFileFilter(fileName,TRUE);
554 bool usePipe = !filter.isEmpty() && filterSourceFiles;
555 return usePipe ? getFileContentsPipe(fileName,filter,startLine,endLine,str)
556 : getFileContentsDisk(fileName,startLine,endLine,str);
557 }
558 private:
559 bool getFileContentsPipe(const QCString &fileName,const QCString &filter,
560 size_t startLine,size_t endLine,std::string &str)
561 {
562 std::unique_lock<std::mutex> lock(m_mutex);
563 auto it = m_cache.find(fileName.str());
564 if (it!=m_cache.end()) // cache hit: reuse stored result
565 {
566 lock.unlock();
567 auto item = it->second;
568 //printf("getFileContents(%s): cache hit\n",qPrint(fileName));
569 // file already processed, get the results after filtering from the tmp file
570 Debug::print(Debug::FilterOutput,0,"Reusing filter result for {} from {} at offset={} size={}\n",
571 fileName,Doxygen::filterDBFileName,item.filePos,item.fileSize);
572
573 auto it_off = m_lineOffsets.find(fileName.str());
574 assert(it_off!=m_lineOffsets.end());
575 auto [ startLineOffset, fragmentSize] = getFragmentLocation(it_off->second,startLine,endLine);
576 //printf("%s: existing file [%zu-%zu]->[%zu-%zu] size=%zu\n",
577 // qPrint(fileName),startLine,endLine,startLineOffset,endLineOffset,fragmentSize);
579 item.filePos+startLineOffset, fragmentSize);
580 return true;
581 }
582 else // cache miss: filter active but file not previously processed
583 {
584 //printf("getFileContents(%s): cache miss\n",qPrint(fileName));
585 // filter file
586 QCString cmd=filter+" \""+fileName+"\"";
587 Debug::print(Debug::ExtCmd,0,"Executing popen(`{}`)\n",cmd);
588 FILE *f = Portable::popen(cmd,"r");
589 if (f==nullptr)
590 {
591 // handle error
592 err("Error opening filter pipe command '{}'\n",cmd);
593 return false;
594 }
596 FilterCacheItem item;
597 item.filePos = m_endPos;
598 if (bf==nullptr)
599 {
600 // handle error
601 err("Error opening filter database file {}\n",Doxygen::filterDBFileName);
603 return false;
604 }
605 // append the filtered output to the database file
606 size_t size=0;
607 while (!feof(f))
608 {
609 const int blockSize = 4096;
610 char buf[blockSize];
611 size_t bytesRead = fread(buf,1,blockSize,f);
612 size_t bytesWritten = fwrite(buf,1,bytesRead,bf);
613 if (bytesRead!=bytesWritten)
614 {
615 // handle error
616 err("Failed to write to filter database {}. Wrote {} out of {} bytes\n",
617 Doxygen::filterDBFileName,bytesWritten,bytesRead);
619 fclose(bf);
620 return false;
621 }
622 size+=bytesWritten;
623 str+=std::string_view(buf,bytesWritten);
624 }
625 item.fileSize = size;
626 // add location entry to the dictionary
627 m_cache.emplace(fileName.str(),item);
628 Debug::print(Debug::FilterOutput,0,"Storing new filter result for {} in {} at offset={} size={}\n",
629 fileName,Doxygen::filterDBFileName,item.filePos,item.fileSize);
630 // update end of file position
631 m_endPos += size;
633 fclose(bf);
634
635 // shrink buffer to [startLine..endLine] part
636 shrinkBuffer(str,fileName,startLine,endLine);
637 }
638 return true;
639 }
640
641 //! reads the fragment start at \a startLine and ending at \a endLine from file \a fileName
642 //! into buffer \a str
643 bool getFileContentsDisk(const QCString &fileName,size_t startLine,size_t endLine,std::string &str)
644 {
645 std::unique_lock<std::mutex> lock(m_mutex);
646 // normal file
647 //printf("getFileContents(%s): no filter\n",qPrint(fileName));
648 auto it = m_lineOffsets.find(fileName.str());
649 if (it == m_lineOffsets.end()) // new file
650 {
651 // read file completely into str buffer
652 readFragmentFromFile(str,fileName,0);
653 // shrink buffer to [startLine..endLine] part
654 shrinkBuffer(str,fileName,startLine,endLine);
655 }
656 else // file already processed before
657 {
658 lock.unlock();
659 auto [ startLineOffset, fragmentSize] = getFragmentLocation(it->second,startLine,endLine);
660 //printf("%s: existing file [%zu-%zu] -> start=%zu size=%zu\n",
661 // qPrint(fileName),startLine,endLine,startLineOffset,fragmentSize);
662 readFragmentFromFile(str,fileName,startLineOffset,fragmentSize);
663 }
664 return true;
665 }
666
667 //! computes the starting offset for each line for file \a fileName, whose contents should
668 //! already be stored in buffer \a str.
669 void compileLineOffsets(const QCString &fileName,const std::string &str)
670 {
671 // line 1 (index 0) is at offset 0
672 auto it = m_lineOffsets.emplace(fileName.data(),LineOffsets{0}).first;
673 const char *p=str.data();
674 while (*p)
675 {
676 char c=0;
677 while ((c=*p)!='\n' && c!=0) p++; // search until end of the line
678 if (c!=0) p++;
679 it->second.push_back(p-str.data());
680 }
681 }
682
683 //! Returns the byte offset and size within a file of a fragment given the array of
684 //! line offsets and the start and end line of the fragment.
685 auto getFragmentLocation(const LineOffsets &lineOffsets,
686 size_t startLine,size_t endLine) -> std::tuple<size_t,size_t>
687 {
688 assert(startLine > 0);
689 assert(startLine <= endLine);
690 const size_t startLineOffset = lineOffsets[std::min(startLine-1,lineOffsets.size()-1)];
691 const size_t endLineOffset = lineOffsets[std::min(endLine, lineOffsets.size()-1)];
692 assert(startLineOffset <= endLineOffset);
693 const size_t fragmentSize = endLineOffset-startLineOffset;
694 return std::tie(startLineOffset,fragmentSize);
695 };
696
697 //! Shrinks buffer \a str which should hold the contents of \a fileName to the
698 //! fragment starting a line \a startLine and ending at line \a endLine
699 void shrinkBuffer(std::string &str,const QCString &fileName,size_t startLine,size_t endLine)
700 {
701 // compute offsets from start for each line
702 compileLineOffsets(fileName,str);
703 auto it = m_lineOffsets.find(fileName.str());
704 assert(it!=m_lineOffsets.end());
705 const LineOffsets &lineOffsets = it->second;
706 auto [ startLineOffset, fragmentSize] = getFragmentLocation(lineOffsets,startLine,endLine);
707 //printf("%s: new file [%zu-%zu]->[%zu-%zu] size=%zu\n",
708 // qPrint(fileName),startLine,endLine,startLineOffset,endLineOffset,fragmentSize);
709 str.erase(0,startLineOffset);
710 str.resize(fragmentSize);
711 }
712
713 //! Reads the fragment start at byte offset \a startOffset of file \a fileName into buffer \a str.
714 //! Result will be a null terminated. If size==0 the whole file will be read and startOffset is ignored.
715 //! If size>0, size bytes will be read.
716 void readFragmentFromFile(std::string &str,const QCString &fileName,size_t startOffset,size_t size=0)
717 {
718 std::ifstream ifs = Portable::openInputStream(fileName,true,true);
719 if (size==0) { startOffset=0; size = static_cast<size_t>(ifs.tellg()); }
720 ifs.seekg(startOffset, std::ios::beg);
721 str.resize(size);
722 ifs.read(str.data(), size);
723 }
724
726 std::unordered_map<std::string,FilterCacheItem> m_cache;
727 std::unordered_map<std::string,LineOffsets> m_lineOffsets;
728 std::mutex m_mutex;
729 size_t m_endPos;
730};
731
733{
734 static FilterCache theInstance;
735 return theInstance;
736}
737
738//-----------------------------------------
739
740
741/*! Reads a fragment of code from file \a fileName starting at
742 * line \a startLine and ending at line \a endLine (inclusive). The fragment is
743 * stored in \a result. If FALSE is returned the code fragment could not be
744 * found.
745 *
746 * The file is scanned for a opening bracket ('{') from \a startLine onward
747 * The line actually containing the bracket is returned via startLine.
748 * The file is scanned for a closing bracket ('}') from \a endLine backward.
749 * The line actually containing the bracket is returned via endLine.
750 * Note that for VHDL code the bracket search is not done.
751 */
752bool readCodeFragment(const QCString &fileName,bool isMacro,
753 int &startLine,int &endLine,QCString &result)
754{
755 bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
756 QCString filter = getFileFilter(fileName,TRUE);
757 bool usePipe = !filter.isEmpty() && filterSourceFiles;
758 int tabSize = Config_getInt(TAB_SIZE);
759 SrcLangExt lang = getLanguageFromFileName(fileName);
760 const int blockSize = 4096;
761 std::string str;
763 static_cast<size_t>(std::max(1,startLine)),
764 static_cast<size_t>(std::max({1,startLine,endLine})),str);
765 //printf("readCodeFragment(%s,startLine=%d,endLine=%d)=\n[[[\n%s]]]\n",qPrint(fileName),startLine,endLine,qPrint(str));
766
767 bool found = lang==SrcLangExt::VHDL ||
768 lang==SrcLangExt::Python ||
769 lang==SrcLangExt::Fortran ||
770 isMacro;
771 // for VHDL, Python, and Fortran no bracket search is possible
772 char *p=str.data();
773 if (p && *p)
774 {
775 char c=0;
776 int col=0;
777 int lineNr=startLine;
778 // skip until the opening bracket or lonely : is found
779 char cn=0;
780 while (*p && !found)
781 {
782 int pc=0;
783 while ((c=*p++)!='{' && c!=':' && c!=0)
784 {
785 //printf("parsing char '%c'\n",c);
786 if (c=='\n')
787 {
788 lineNr++,col=0;
789 }
790 else if (c=='\t')
791 {
792 col+=tabSize - (col%tabSize);
793 }
794 else if (pc=='/' && c=='/') // skip single line comment
795 {
796 while ((c=*p++)!='\n' && c!=0);
797 if (c=='\n') lineNr++,col=0;
798 }
799 else if (pc=='/' && c=='*') // skip C style comment
800 {
801 while (((c=*p++)!='/' || pc!='*') && c!=0)
802 {
803 if (c=='\n') lineNr++,col=0;
804 pc=c;
805 }
806 }
807 else
808 {
809 col++;
810 }
811 pc = c;
812 }
813 if (c==':')
814 {
815 cn=*p++;
816 if (cn!=':') found=TRUE;
817 }
818 else if (c=='{')
819 {
820 found=TRUE;
821 }
822 else if (c==0)
823 {
824 break;
825 }
826 }
827 //printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr);
828 if (found)
829 {
830 // For code with more than one line,
831 // fill the line with spaces until we are at the right column
832 // so that the opening brace lines up with the closing brace
833 if (endLine!=startLine)
834 {
835 QCString spaces;
836 spaces.fill(' ',col);
837 result+=spaces;
838 }
839 // copy until end of line
840 if (c) result+=c;
841 startLine=lineNr;
842 if (c==':')
843 {
844 result+=cn;
845 if (cn=='\n') lineNr++;
846 }
847 char lineStr[blockSize];
848 do
849 {
850 //printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine);
851 int size_read=0;
852 do
853 {
854 // read up to blockSize-1 non-zero characters
855 int i=0;
856 while ((c=*p) && i<blockSize-1)
857 {
858 lineStr[i++]=c;
859 p++;
860 if (c=='\n') break; // stop at end of the line
861 }
862 lineStr[i]=0;
863 size_read=i;
864 result+=lineStr; // append line to the output
865 } while (size_read == (blockSize-1)); // append more if line does not fit in buffer
866 lineNr++;
867 } while (*p);
868
869 // strip stuff after closing bracket
870 int newLineIndex = result.findRev('\n');
871 int braceIndex = result.findRev('}');
872 if (braceIndex > newLineIndex)
873 {
874 result.resize(static_cast<size_t>(braceIndex+1));
875 }
876 endLine=lineNr-1;
877 }
878 if (usePipe)
879 {
880 Debug::print(Debug::FilterOutput, 0, "Filter output\n");
881 Debug::print(Debug::FilterOutput,0,"-------------\n{}\n-------------\n",result);
882 }
883 }
884 QCString encoding = getEncoding(FileInfo(fileName.str()));
885 if (encoding!="UTF-8")
886 {
887 std::string encBuf = result.str();
888 bool ok = transcodeCharacterStringToUTF8(encBuf,encoding.data());
889 if (ok)
890 {
891 result = QCString(encBuf);
892 }
893 else
894 {
895 err("failed to transcode characters in code fragment in file {} lines {} to {}, from input encoding {} to UTF-8\n",
896 fileName,startLine,endLine,encoding);
897
898 }
899 }
900 if (!result.isEmpty() && result.at(result.length()-1)!='\n') result += "\n";
901 //printf("readCodeFragment(%d-%d)=%s\n",startLine,endLine,qPrint(result));
902 return found;
903}
904
906{
907 ASSERT(p->def->definitionType()!=Definition::TypeFile); // file overloads this method
908 QCString fn;
909 bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
910 if (sourceBrowser &&
911 p->body && p->body->startLine!=-1 && p->body->fileDef)
912 {
913 fn = p->body->fileDef->getSourceFileBase();
914 }
915 return fn;
916}
917
919{
920 const int maxAnchorStrLen = 20;
921 char anchorStr[maxAnchorStrLen];
922 anchorStr[0]='\0';
923 if (p->body && p->body->startLine!=-1)
924 {
925 if (Htags::useHtags)
926 {
927 qsnprintf(anchorStr,maxAnchorStrLen,"L%d",p->body->defLine);
928 }
929 else
930 {
931 qsnprintf(anchorStr,maxAnchorStrLen,"l%05d",p->body->defLine);
932 }
933 }
934 return anchorStr;
935}
936
937/*! Write a reference to the source code defining this definition */
939{
940 //printf("DefinitionImpl::writeSourceRef %d %p\n",bodyLine,bodyDef);
942 if (!fn.isEmpty())
943 {
944 QCString refText = theTranslator->trDefinedAtLineInSourceFile();
945 int lineMarkerPos = refText.find("@0");
946 int fileMarkerPos = refText.find("@1");
947 if (lineMarkerPos!=-1 && fileMarkerPos!=-1) // should always pass this.
948 {
949 QCString lineStr;
950 lineStr.sprintf("%d",p->body->defLine);
951 QCString anchorStr = getSourceAnchor();
952 ol.startParagraph("definition");
953 if (lineMarkerPos<fileMarkerPos) // line marker before file marker
954 {
955 // write text left from linePos marker
956 ol.parseText(refText.left(lineMarkerPos));
957 ol.writeObjectLink(QCString(),fn,anchorStr,lineStr);
958 // write text between markers
959 ol.parseText(refText.mid(lineMarkerPos+2,fileMarkerPos-lineMarkerPos-2));
960 // write file link
961 ol.writeObjectLink(QCString(),fn,QCString(),p->body->fileDef->name());
962 // write text right from file marker
963 ol.parseText(refText.right(refText.length()-static_cast<size_t>(fileMarkerPos)-2));
964 }
965 else // file marker before line marker
966 {
967 // write text left from file marker
968 ol.parseText(refText.left(fileMarkerPos));
969 // write file link
970 ol.writeObjectLink(QCString(),fn,QCString(),p->body->fileDef->name());
971 // write text between markers
972 ol.parseText(refText.mid(fileMarkerPos+2,lineMarkerPos-fileMarkerPos-2));
973 // write line link
974 ol.writeObjectLink(QCString(),fn,anchorStr,lineStr);
975 // write text right from linePos marker
976 ol.parseText(refText.right(refText.length()-static_cast<size_t>(lineMarkerPos)-2));
977 }
978 ol.endParagraph();
979 }
980 else
981 {
982 err("translation error: invalid markers in trDefinedAtLineInSourceFile()\n");
983 }
984 }
985}
986
987void DefinitionImpl::setBodySegment(int defLine, int bls,int ble)
988{
989 if (!p->body.has_value())
990 {
991 p->body = std::make_optional<BodyInfo>();
992 }
993 BodyInfo &body = p->body.value();
994 body.defLine = defLine;
995 body.startLine = bls;
996 body.endLine = ble;
997}
998
1000{
1001 if (!p->body.has_value())
1002 {
1003 p->body = std::make_optional<BodyInfo>();
1004 }
1005 p->body.value().fileDef=fd;
1006}
1007
1009{
1010 return p->body && p->body->startLine!=-1 &&
1011 p->body->endLine>=p->body->startLine &&
1012 p->body->fileDef;
1013}
1014
1015/*! Write code of this definition into the documentation */
1017{
1018 const MemberDef *thisMd = nullptr;
1019 if (p->def->definitionType()==Definition::TypeMember)
1020 {
1021 thisMd = toMemberDef(p->def);
1022 }
1023 bool inlineSources = thisMd && thisMd->hasInlineSource();
1024 //printf("Source Fragment %s: %d-%d\n",qPrint(name()),
1025 // p->body->startLine,p->body->endLine);
1026 if (inlineSources && hasSources())
1027 {
1028 ol.pushGeneratorState();
1029 QCString codeFragment;
1030 bool isMacro = thisMd && thisMd->memberType()==MemberType::Define;
1031 int actualStart=p->body->startLine,actualEnd=p->body->endLine;
1032 if (readCodeFragment(p->body->fileDef->absFilePath(),isMacro,
1033 actualStart,actualEnd,codeFragment)
1034 )
1035 {
1036 //printf("Adding code fragment '%s' ext='%s' range=%d-%d\n",
1037 // qPrint(codeFragment),qPrint(p->defFileExt),actualStart,actualEnd);
1038 auto intf = Doxygen::parserManager->getCodeParser(p->defFileExt);
1039 intf->resetCodeParserState();
1040 //printf("Read:\n'%s'\n\n",qPrint(codeFragment));
1041
1042 auto &codeOL = ol.codeGenerators();
1043 codeOL.startCodeFragment("DoxyCode");
1044 intf->parseCode(codeOL, // codeOutIntf
1045 scopeName, // scope
1046 codeFragment, // input
1047 p->lang, // lang
1048 Config_getBool(STRIP_CODE_COMMENTS),
1049 FALSE, // isExample
1050 QCString(), // exampleName
1051 p->body->fileDef, // fileDef
1052 actualStart, // startLine
1053 actualEnd, // endLine
1054 TRUE, // inlineFragment
1055 thisMd, // memberDef
1056 TRUE // show line numbers
1057 );
1058 codeOL.endCodeFragment("DoxyCode");
1059 }
1060 ol.popGeneratorState();
1061 }
1062}
1063
1064static inline MemberVector refMapToVector(const std::unordered_map<std::string,MemberDef *> &map)
1065{
1066 // convert map to a vector of values
1067 MemberVector result;
1068 std::transform(map.begin(),map.end(), // iterate over map
1069 std::back_inserter(result), // add results to vector
1070 [](const auto &item)
1071 { return item.second; } // extract value to add from map Key,Value pair
1072 );
1073 // and sort it
1074 std::stable_sort(result.begin(),result.end(),
1075 [](const auto &m1,const auto &m2) { return genericCompareMembers(m1,m2)<0; });
1076 return result;
1077}
1078
1079/*! Write a reference to the source code fragments in which this
1080 * definition is used.
1081 */
1083 const QCString &text,const std::unordered_map<std::string,MemberDef *> &membersMap,
1084 bool /*funcOnly*/) const
1085{
1086 if (!membersMap.empty())
1087 {
1088 auto members = refMapToVector(membersMap);
1089
1090 auto replaceFunc = [this,&members,scopeName,&ol](size_t entryIndex)
1091 {
1092 bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1093 bool refLinkSource = Config_getBool(REFERENCES_LINK_SOURCE);
1094 const MemberDef *md=members[entryIndex];
1095 if (md)
1096 {
1097 QCString scope=md->getScopeString();
1098 QCString name=md->name();
1099 //printf("class=%p scope=%s scopeName=%s\n",md->getClassDef(),qPrint(scope),scopeName);
1100 if (!scope.isEmpty() && scope!=scopeName)
1101 {
1102 name.prepend(scope+getLanguageSpecificSeparator(p->lang));
1103 }
1104 if (!md->isObjCMethod() &&
1105 (md->isFunction() || md->isSlot() ||
1106 md->isPrototype() || md->isSignal()
1107 )
1108 )
1109 {
1110 name+="()";
1111 }
1112 if (sourceBrowser &&
1113 !(md->isLinkable() && !refLinkSource) &&
1114 md->getStartBodyLine()!=-1 &&
1115 md->getBodyDef()
1116 )
1117 {
1118 const int maxLineNrStr = 10;
1119 char anchorStr[maxLineNrStr];
1120 qsnprintf(anchorStr,maxLineNrStr,"l%05d",md->getStartBodyLine());
1121 //printf("Write object link to %s\n",qPrint(md->getBodyDef()->getSourceFileBase()));
1122 ol.writeObjectLink(QCString(),md->getBodyDef()->getSourceFileBase(),anchorStr,name);
1123 }
1124 else if (md->isLinkable())
1125 {
1127 md->getOutputFileBase(),
1128 md->anchor(),name);
1129 }
1130 else
1131 {
1132 ol.docify(name);
1133 }
1134 }
1135 };
1136
1137 ol.startParagraph("reference");
1138 ol.parseText(text);
1139 ol.docify(" ");
1140 writeMarkerList(ol,
1141 theTranslator->trWriteList(static_cast<int>(members.size())).str(),
1142 members.size(),
1143 replaceFunc);
1144 ol.writeString(".");
1145 ol.endParagraph();
1146
1147 }
1148}
1149
1151{
1152 _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),p->sourceRefByDict,FALSE);
1153}
1154
1156{
1157 _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),p->sourceRefsDict,TRUE);
1158}
1159
1161{
1162 return !p->sourceRefByDict.empty();
1163}
1164
1166{
1167 return !p->sourceRefsDict.empty();
1168}
1169
1171{
1172 bool extractAll = Config_getBool(EXTRACT_ALL);
1173 //bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1174 bool hasDocs =
1175 (p->details && !p->details->doc.isEmpty()) || // has detailed docs
1176 (p->brief && !p->brief->doc.isEmpty()) || // has brief description
1177 (p->inbodyDocs && !p->inbodyDocs->doc.isEmpty()) || // has inbody docs
1178 extractAll //|| // extract everything
1179 // (sourceBrowser && p->body &&
1180 // p->body->startLine!=-1 && p->body->fileDef)
1181 ; // link to definition
1182 return hasDocs;
1183}
1184
1186{
1187 bool hasDocs =
1188 (p->details && !p->details->doc.isEmpty()) ||
1189 (p->brief && !p->brief->doc.isEmpty()) ||
1190 (p->inbodyDocs && !p->inbodyDocs->doc.isEmpty());
1191 return hasDocs;
1192}
1193
1195{
1196 if (md)
1197 {
1198 p->sourceRefByDict.emplace(sourceRefName.str(),md);
1199 }
1200}
1201
1203{
1204 if (md)
1205 {
1206 p->sourceRefsDict.emplace(sourceRefName.str(),md);
1207 }
1208}
1209
1211{
1212 return nullptr;
1213}
1214
1216{
1217 err("DefinitionImpl::addInnerCompound() called\n");
1218}
1219
1220static std::recursive_mutex g_qualifiedNameMutex;
1221
1223{
1224 std::lock_guard<std::recursive_mutex> lock(g_qualifiedNameMutex);
1225 if (!p->qualifiedName.isEmpty())
1226 {
1227 return p->qualifiedName;
1228 }
1229
1230 //printf("start %s::qualifiedName() localName=%s\n",qPrint(name()),qPrint(p->localName));
1231 if (p->outerScope==nullptr)
1232 {
1233 if (p->localName=="<globalScope>")
1234 {
1235 return "";
1236 }
1237 else
1238 {
1239 return p->localName;
1240 }
1241 }
1242
1243 if (p->outerScope->name()=="<globalScope>")
1244 {
1245 p->qualifiedName = p->localName;
1246 }
1247 else
1248 {
1249 p->qualifiedName = p->outerScope->qualifiedName()+
1251 p->localName;
1252 }
1253 //printf("end %s::qualifiedName()=%s\n",qPrint(name()),qPrint(p->qualifiedName));
1254 //count--;
1255 return p->qualifiedName;
1256}
1257
1259{
1260 std::lock_guard<std::recursive_mutex> lock(g_qualifiedNameMutex);
1261 //printf("%s::setOuterScope(%s)\n",qPrint(name()),d?qPrint(d->name()):"<none>");
1262 Definition *outerScope = p->outerScope;
1263 bool found=false;
1264 // make sure that we are not creating a recursive scope relation.
1265 while (outerScope && !found)
1266 {
1267 found = (outerScope==d);
1268 outerScope = outerScope->getOuterScope();
1269 }
1270 if (!found)
1271 {
1272 p->qualifiedName.clear(); // flush cached scope name
1273 p->outerScope = d;
1274 }
1275 p->hidden = p->hidden || d->isHidden();
1276 assert(p->def!=p->outerScope);
1277}
1278
1280{
1281 return p->localName;
1282}
1283
1285{
1286 p->partOfGroups.push_back(gd);
1287}
1288
1290{
1291 p->xrefListItems.insert(p->xrefListItems.end(), sli.cbegin(), sli.cend());
1292}
1293
1295{
1296 auto otherXrefList = d->xrefListItems();
1297
1298 // append vectors
1299 p->xrefListItems.reserve(p->xrefListItems.size()+otherXrefList.size());
1300 p->xrefListItems.insert (p->xrefListItems.end(),
1301 otherXrefList.begin(),otherXrefList.end());
1302
1303 // sort results on itemId
1304 std::stable_sort(p->xrefListItems.begin(),p->xrefListItems.end(),
1305 [](RefItem *left,RefItem *right)
1306 { return left->id() <right->id() ||
1307 (left->id()==right->id() &&
1308 left->list()->listName() < right->list()->listName());
1309 });
1310
1311 // filter out duplicates
1312 auto last = std::unique(p->xrefListItems.begin(),p->xrefListItems.end(),
1313 [](const RefItem *left,const RefItem *right)
1314 { return left->id()==right->id() &&
1315 left->list()->listName()==right->list()->listName();
1316 });
1317 p->xrefListItems.erase(last, p->xrefListItems.end());
1318}
1319
1321{
1322 for (const RefItem *item : p->xrefListItems)
1323 {
1324 if (item->list()->listName()==listName)
1325 {
1326 return item->id();
1327 }
1328 }
1329 return -1;
1330}
1331
1333{
1334 return p->xrefListItems;
1335}
1336
1338{
1339 QCString result;
1340 if (p->outerScope && p->outerScope!=Doxygen::globalScope)
1341 {
1342 result = p->outerScope->pathFragment();
1343 }
1344 if (p->def->isLinkable())
1345 {
1346 if (!result.isEmpty()) result+="/";
1347 if (p->def->definitionType()==Definition::TypeGroup &&
1348 !toGroupDef(p->def)->groupTitle().isEmpty())
1349 {
1350 result+=toGroupDef(p->def)->groupTitle();
1351 }
1352 else if (p->def->definitionType()==Definition::TypePage &&
1353 toPageDef(p->def)->hasTitle())
1354 {
1355 result+=toPageDef(p->def)->title();
1356 }
1357 else
1358 {
1359 result+=p->localName;
1360 }
1361 }
1362 else
1363 {
1364 result+=p->localName;
1365 }
1366 return result;
1367}
1368
1369//----------------------------------------------------------------------------------------
1370
1371// TODO: move to htmlgen
1372/*! Returns the string used in the footer for $navpath when
1373 * GENERATE_TREEVIEW is enabled
1374 */
1376{
1377 QCString result;
1378 Definition *outerScope = getOuterScope();
1379 QCString locName = localName();
1380 if (outerScope && outerScope!=Doxygen::globalScope)
1381 {
1382 result+=outerScope->navigationPathAsString();
1383 }
1384 else if (p->def->definitionType()==Definition::TypeFile &&
1385 toFileDef(p->def)->getDirDef())
1386 {
1387 result+=(toFileDef(p->def))->getDirDef()->navigationPathAsString();
1388 }
1389 result+="<li class=\"navelem\">";
1390 if (p->def->isLinkableInProject())
1391 {
1392 QCString fn = p->def->getOutputFileBase();
1394 if (p->def->definitionType()==Definition::TypeGroup &&
1395 !toGroupDef(p->def)->groupTitle().isEmpty())
1396 {
1397 result+="<a class=\"el\" href=\"$relpath^"+fn+"\">"+
1398 convertToHtml(toGroupDef(p->def)->groupTitle())+"</a>";
1399 }
1400 else if (p->def->definitionType()==Definition::TypePage &&
1401 toPageDef(p->def)->hasTitle())
1402 {
1403 result+="<a class=\"el\" href=\"$relpath^"+fn+"\">"+
1404 convertToHtml((toPageDef(p->def))->title())+"</a>";
1405 }
1406 else if (p->def->definitionType()==Definition::TypeClass)
1407 {
1408 QCString name = locName;
1409 if (name.endsWith("-p"))
1410 {
1411 name = name.left(name.length()-2);
1412 }
1413 result+="<a class=\"el\" href=\"$relpath^"+fn;
1414 if (!p->def->anchor().isEmpty()) result+="#"+p->def->anchor();
1415 result+="\">"+convertToHtml(name)+"</a>";
1416 }
1417 else
1418 {
1419 result+="<a class=\"el\" href=\"$relpath^"+fn+"\">"+
1420 convertToHtml(locName)+"</a>";
1421 }
1422 }
1423 else
1424 {
1425 result+="<b>"+convertToHtml(locName)+"</b>";
1426 }
1427 result+="</li>";
1428 return result;
1429}
1430
1431// TODO: move to htmlgen
1433{
1434 ol.pushGeneratorState();
1436
1437 QCString navPath;
1438 navPath += "<div id=\"nav-path\" class=\"navpath\">\n"
1439 " <ul>\n";
1440 navPath += navigationPathAsString();
1441 navPath += " </ul>\n"
1442 "</div>\n";
1443 ol.writeNavigationPath(navPath);
1444
1445 ol.popGeneratorState();
1446}
1447
1448void DefinitionImpl::writeToc(OutputList &ol, const LocalToc &localToc) const
1449{
1450 if (p->sectionRefs.empty()) return;
1451 ol.writeLocalToc(p->sectionRefs,localToc);
1452}
1453
1454//----------------------------------------------------------------------------------------
1455
1457{
1458 return p->sectionRefs;
1459}
1460
1462{
1463 return p->symbolName;
1464}
1465
1466//----------------------
1467
1469{
1470 return p->details ? p->details->doc : QCString("");
1471}
1472
1474{
1475 return p->details ? p->details->line : p->brief ? p->brief->line : 1;
1476}
1477
1479{
1480 if (p->details && !p->details->file.isEmpty()) return p->details->file;
1481 else if (p->brief && !p->brief->file.isEmpty()) return p->brief->file;
1482 else return "<" + p->name + ">";
1483}
1484
1485//----------------------------------------------------------------------------
1486// strips w from s iff s starts with w
1487static bool stripWord(QCString &s,QCString w)
1488{
1489 bool success=FALSE;
1490 if (s.left(w.length())==w)
1491 {
1492 success=TRUE;
1493 s=s.right(s.length()-w.length());
1494 }
1495 return success;
1496}
1497
1498//----------------------------------------------------------------------------
1499// some quasi intelligent brief description abbreviator :^)
1500static QCString abbreviate(const QCString &s,const QCString &name)
1501{
1502 QCString scopelessName=name;
1503 int i=scopelessName.findRev("::");
1504 if (i!=-1) scopelessName=scopelessName.mid(i+2);
1505 QCString result=s;
1506 result=result.stripWhiteSpace();
1507 // strip trailing .
1508 if (!result.isEmpty() && result.at(result.length()-1)=='.')
1509 result=result.left(result.length()-1);
1510
1511 // strip any predefined prefix
1512 const StringVector &briefDescAbbrev = Config_getList(ABBREVIATE_BRIEF);
1513 for (const auto &p : briefDescAbbrev)
1514 {
1515 QCString str = substitute(p.c_str(),"$name",scopelessName); // replace $name with entity name
1516 str += " ";
1517 stripWord(result,str);
1518 }
1519
1520 // capitalize first word
1521 if (!result.isEmpty())
1522 {
1523 char c=result[0];
1524 if (c>='a' && c<='z') c+='A'-'a';
1525 result[0]=c;
1526 }
1527 return result;
1528}
1529
1530
1531//----------------------
1532
1534{
1535 //printf("%s::briefDescription(%d)='%s'\n",qPrint(name()),abbr,p->brief?qPrint(p->brief->doc):"<none>");
1536 return p->brief ?
1537 (abbr ? abbreviate(p->brief->doc,p->def->displayName()) : p->brief->doc) :
1538 QCString("");
1539}
1540
1542{
1543 if (p->brief && p->brief->tooltip.isEmpty() && !p->brief->doc.isEmpty())
1544 {
1545 const MemberDef *md = p->def->definitionType()==Definition::TypeMember ? toMemberDef(p->def) : nullptr;
1546 const Definition *scope = p->def->definitionType()==Definition::TypeMember ? p->def->getOuterScope() : p->def;
1547 p->brief->tooltip = parseCommentAsText(scope,md,
1548 p->brief->doc, p->brief->file, p->brief->line);
1549 }
1550}
1551
1553{
1554 return p->brief ? p->brief->tooltip : QCString();
1555}
1556
1558{
1559 return p->brief ? p->brief->line : 1;
1560}
1561
1563{
1564 return p->brief && !p->brief->file.isEmpty() ? p->brief->file : QCString("<"+p->name+">");
1565}
1566
1567//----------------------
1568
1570{
1571 return p->inbodyDocs ? p->inbodyDocs->doc : QCString("");
1572}
1573
1575{
1576 return p->inbodyDocs ? p->inbodyDocs->line : 1;
1577}
1578
1580{
1581 return p->inbodyDocs && !p->inbodyDocs->file.isEmpty() ? p->inbodyDocs->file : QCString("<"+p->name+">");
1582}
1583
1584
1585//----------------------
1586
1588{
1589 return p->defFileName;
1590}
1591
1593{
1594 return p->defFileExt;
1595}
1596
1598{
1599 return p->hidden;
1600}
1601
1603{
1604 return p->def->isLinkableInProject() && !p->hidden;
1605}
1606
1608{
1609 return p->def->isLinkable() && !p->hidden;
1610}
1611
1613{
1614 return p->isArtificial;
1615}
1616
1618{
1619 return p->isExported;
1620}
1621
1623{
1624 return p->ref;
1625}
1626
1628{
1629 return !p->ref.isEmpty();
1630}
1631
1633{
1634 return p->body ? p->body->defLine : -1;
1635}
1636
1638{
1639 return p->body ? p->body->startLine : -1;
1640}
1641
1643{
1644 return p->body ? p->body->endLine : -1;
1645}
1646
1648{
1649 return p->body ? p->body->fileDef : nullptr;
1650}
1651
1653{
1654 return p->partOfGroups;
1655}
1656
1658{
1659 for (const auto &gd : partOfGroups())
1660 {
1661 if (gd->isLinkable()) return true;
1662 }
1663 return false;
1664}
1665
1667{
1668 return p->outerScope;
1669}
1670
1671static std::mutex g_memberReferenceMutex;
1672
1674{
1675 std::lock_guard<std::mutex> lock(g_memberReferenceMutex);
1676 if (p->referencesMembers.empty() && !p->sourceRefsDict.empty())
1677 {
1678 p->referencesMembers = refMapToVector(p->sourceRefsDict);
1679 }
1680 return p->referencesMembers;
1681}
1682
1684{
1685 std::lock_guard<std::mutex> lock(g_memberReferenceMutex);
1686 if (p->referencedByMembers.empty() && !p->sourceRefByDict.empty())
1687 {
1688 p->referencedByMembers = refMapToVector(p->sourceRefByDict);
1689 }
1690 return p->referencedByMembers;
1691}
1692
1694{
1695 const DefinitionImpl *defImpl = other->toDefinitionImpl_();
1696 if (defImpl)
1697 {
1698 for (const auto &kv : defImpl->p->sourceRefsDict)
1699 {
1700 auto it = p->sourceRefsDict.find(kv.first);
1701 if (it != p->sourceRefsDict.end())
1702 {
1703 p->sourceRefsDict.insert(kv);
1704 }
1705 }
1706 }
1707}
1708
1710{
1711 const DefinitionImpl *defImpl = other->toDefinitionImpl_();
1712 if (defImpl)
1713 {
1714 for (const auto &kv : defImpl->p->sourceRefByDict)
1715 {
1716 auto it = p->sourceRefByDict.find(kv.first);
1717 if (it != p->sourceRefByDict.end())
1718 {
1719 p->sourceRefByDict.emplace(kv.first,kv.second);
1720 }
1721 }
1722 }
1723}
1724
1725
1727{
1728 p->ref=r;
1729}
1730
1732{
1733 return p->lang;
1734}
1735
1737{
1738 p->hidden = p->hidden || b;
1739}
1740
1742{
1743 p->isArtificial = b;
1744}
1745
1747{
1748 p->isExported = b;
1749}
1750
1752{
1753 p->localName=name;
1754}
1755
1757{
1758 p->lang=lang;
1759}
1760
1761
1763{
1764 p->symbolName=name;
1765}
1766
1768{
1769 return p->symbolName;
1770}
1771
1773{
1774 bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC);
1775 return !briefDescription().isEmpty() && briefMemberDesc;
1776}
1777
1779{
1780 QCString ref = getReference();
1781 if (!ref.isEmpty())
1782 {
1783 auto it = Doxygen::tagDestinationMap.find(ref.str());
1785 {
1786 QCString result(it->second);
1787 size_t l = result.length();
1788 if (!relPath.isEmpty() && l>0 && result.at(0)=='.')
1789 { // relative path -> prepend relPath.
1790 result.prepend(relPath);
1791 l+=relPath.length();
1792 }
1793 if (l>0 && result.at(l-1)!='/') result+='/';
1794 return result;
1795 }
1796 }
1797 return relPath;
1798}
1799
1801{
1802 return p->name;
1803}
1804
1806{
1807 return p->isAnonymous;
1808}
1809
1811{
1812 return p->defLine;
1813}
1814
1816{
1817 return p->defColumn;
1818}
1819
1823
1827
1828//---------------------------------------------------------------------------------
1829
1831 : m_def(def), m_scope(scope), m_symbolName(alias->_symbolName())
1832{
1833}
1834
1838
1840{
1841 //printf("%s::addToMap(%s)\n",qPrint(name()),qPrint(alias->name()));
1843 if (m_scope==nullptr)
1844 {
1845 m_qualifiedName = m_def->localName();
1846 }
1847 else
1848 {
1849 m_qualifiedName = m_scope->qualifiedName()+
1850 getLanguageSpecificSeparator(m_scope->getLanguage())+
1851 m_def->localName();
1852 }
1853}
1854
1859
1864
1866{
1867 return m_qualifiedName;
1868}
1869
1870//---------------------------------------------------------------------------------
1871
1873{
1874 if (dm==nullptr) return nullptr;
1875 return dm->toDefinition_();
1876}
1877
1879{
1880 if (d==nullptr) return nullptr;
1881 return d->toDefinitionMutable_();
1882}
1883
static AnchorGenerator & instance()
Returns the singleton instance.
Definition anchor.cpp:38
@ FilterOutput
Definition debug.h:38
@ ExtCmd
Definition debug.h:36
static void print(DebugMask mask, int prio, fmt::format_string< Args... > fmt, Args &&... args)
Definition debug.h:76
DefinitionAliasImpl(Definition *def, const Definition *scope, const Definition *alias)
const Definition * m_scope
const QCString & name() const
QCString qualifiedName() const
virtual ~DefinitionAliasImpl()
The common base class of all entity definitions found in the sources.
Definition definition.h:76
virtual const RefItemVector & xrefListItems() const =0
virtual QCString navigationPathAsString() const =0
virtual bool isLinkable() const =0
virtual QCString anchor() const =0
virtual DefinitionMutable * toDefinitionMutable_()=0
virtual const FileDef * getBodyDef() const =0
virtual bool isHidden() const =0
virtual QCString getReference() const =0
virtual void _setSymbolName(const QCString &name)=0
virtual QCString getSourceFileBase() const =0
virtual QCString getOutputFileBase() const =0
virtual Definition * getOuterScope() const =0
virtual int getStartBodyLine() const =0
virtual const DefinitionImpl * toDefinitionImpl_() const =0
virtual const QCString & name() const =0
Private data associated with a Symbol DefinitionImpl object.
MemberVector referencesMembers
std::optional< BriefInfo > brief
std::optional< BodyInfo > body
void init(const QCString &df, const QCString &n)
std::optional< DocInfo > inbodyDocs
MemberVector referencedByMembers
std::unordered_map< std::string, MemberDef * > sourceRefByDict
std::unordered_map< std::string, MemberDef * > sourceRefsDict
RefItemVector xrefListItems
void setDefFileName(const QCString &df)
void setId(const QCString &name)
void setBodySegment(int defLine, int bls, int ble)
void setExported(bool b)
int getDefLine() const
bool isHidden() const
void mergeRefItems(Definition *d)
QCString documentation() const
void addSourceReferencedBy(MemberDef *d, const QCString &sourceRefName)
const RefItemVector & xrefListItems() const
void writeSummaryLinks(OutputList &) const
void setHidden(bool b)
QCString _symbolName() const
QCString getSourceFileBase() const
QCString externalReference(const QCString &relPath) const
bool isReference() const
bool isVisible() const
int briefLine() const
void addSectionsToDefinition(const std::vector< const SectionInfo * > &anchorList)
bool isAnonymous() const
bool isLinkableViaGroup() const
void setDefFile(const QCString &df, int defLine, int defColumn)
const Definition * findInnerCompound(const QCString &name) const
void setName(const QCString &name)
SrcLangExt getLanguage() const
void addInnerCompound(Definition *d)
void setArtificial(bool b)
bool hasSourceReffedBy() const
void _writeSourceRefList(OutputList &ol, const QCString &scopeName, const QCString &text, const std::unordered_map< std::string, MemberDef * > &members, bool) const
void writeNavigationPath(OutputList &ol) const
QCString getDefFileName() const
void writeSourceReffedBy(OutputList &ol, const QCString &scopeName) const
bool _docsAlreadyAdded(const QCString &doc, QCString &sigList)
void _setInbodyDocumentation(const QCString &d, const QCString &docFile, int docLine)
void setRefItems(const RefItemVector &sli)
int getStartBodyLine() const
void setLocalName(const QCString &name)
QCString symbolName() const
QCString id() const
void setOuterScope(Definition *d)
void _setBriefDescription(const QCString &b, const QCString &briefFile, int briefLine)
QCString qualifiedName() const
const MemberVector & getReferencesMembers() const
void setBodyDef(const FileDef *fd)
void writeInlineCode(OutputList &ol, const QCString &scopeName) const
int docLine() const
void setInbodyDocumentation(const QCString &d, const QCString &docFile, int docLine)
bool isArtificial() const
bool isExported() const
QCString briefDescriptionAsTooltip() const
int _getXRefListId(const QCString &listName) const
QCString inbodyDocumentation() const
QCString getSourceAnchor() const
QCString getDefFileExtension() const
void writeQuickMemberLinks(OutputList &, const MemberDef *) const
const GroupList & partOfGroups() const
void setBriefDescription(const QCString &b, const QCString &briefFile, int briefLine)
const QCString & name() const
QCString briefFile() const
bool hasUserDocumentation() const
int inbodyLine() const
QCString briefDescription(bool abbreviate=FALSE) const
bool hasBriefDescription() const
bool hasSources() const
const SectionRefs & getSectionRefs() const
DefinitionImpl & operator=(const DefinitionImpl &d)
bool isVisibleInProject() const
void writeSourceRefs(OutputList &ol, const QCString &scopeName) const
void makePartOfGroup(GroupDef *gd)
const QCString & localName() const
void mergeReferencedBy(const Definition *other)
int getStartDefLine() const
void setDocumentation(const QCString &d, const QCString &docFile, int docLine, bool stripWhiteSpace=TRUE)
void setReference(const QCString &r)
bool hasSourceRefs() const
void writeToc(OutputList &ol, const LocalToc &lt) const
QCString navigationPathAsString() const
void _setDocumentation(const QCString &d, const QCString &docFile, int docLine, bool stripWhiteSpace, bool atTop)
const FileDef * getBodyDef() const
void writeSourceDef(OutputList &ol) const
void setLanguage(SrcLangExt lang)
void mergeReferences(const Definition *other)
QCString inbodyFile() const
std::unique_ptr< Private > p
bool hasSections() const
QCString docFile() const
bool hasDocumentation() const
Definition * getOuterScope() const
const MemberVector & getReferencedByMembers() const
QCString pathFragment() const
DefinitionImpl(Definition *def, const QCString &defFileName, int defLine, int defColumn, const QCString &name, const char *b=nullptr, const char *d=nullptr, bool isSymbol=TRUE)
int getDefColumn() const
int getEndBodyLine() const
void writeDocAnchorsToTagFile(TextStream &) const
void _setSymbolName(const QCString &name)
QCString getReference() const
void addSourceReferences(MemberDef *d, const QCString &sourceRefName)
virtual Definition * toDefinition_()=0
static ParserManager * parserManager
Definition doxygen.h:131
static NamespaceDefMutable * globalScope
Definition doxygen.h:121
static StringMap tagDestinationMap
Definition doxygen.h:116
static QCString filterDBFileName
Definition doxygen.h:133
static SymbolMap< Definition > * symbolMap
Definition doxygen.h:125
static ClangUsrMap * clangUsrMap
Definition doxygen.h:126
A model of a file symbol.
Definition filedef.h:99
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
void shrinkBuffer(std::string &str, const QCString &fileName, size_t startLine, size_t endLine)
std::vector< size_t > LineOffsets
auto getFragmentLocation(const LineOffsets &lineOffsets, size_t startLine, size_t endLine) -> std::tuple< size_t, size_t >
std::unordered_map< std::string, LineOffsets > m_lineOffsets
bool getFileContentsDisk(const QCString &fileName, size_t startLine, size_t endLine, std::string &str)
static FilterCache & instance()
void readFragmentFromFile(std::string &str, const QCString &fileName, size_t startOffset, size_t size=0)
size_t m_endPos
void compileLineOffsets(const QCString &fileName, const std::string &str)
bool getFileContents(const QCString &fileName, size_t startLine, size_t endLine, std::string &str)
bool getFileContentsPipe(const QCString &fileName, const QCString &filter, size_t startLine, size_t endLine, std::string &str)
std::unordered_map< std::string, FilterCacheItem > m_cache
std::mutex m_mutex
A model of a group of symbols.
Definition groupdef.h:52
virtual QCString groupTitle() const =0
const T * find(const std::string &key) const
Definition linkedmap.h:47
A model of a class/file/namespace member symbol.
Definition memberdef.h:48
virtual bool isSignal() const =0
virtual bool isObjCMethod() const =0
virtual bool isSlot() const =0
virtual bool isFunction() const =0
virtual QCString getScopeString() const =0
virtual bool hasInlineSource() const =0
virtual MemberType memberType() const =0
virtual bool isPrototype() const =0
A vector of MemberDef object.
Definition memberlist.h:35
iterator end() noexcept
Definition memberlist.h:56
iterator begin() noexcept
Definition memberlist.h:54
void startCodeFragment(const QCString &style)
Definition outputlist.h:278
Class representing a list of output generators that are written to in parallel.
Definition outputlist.h:314
void writeString(const QCString &text)
Definition outputlist.h:412
const OutputCodeList & codeGenerators() const
Definition outputlist.h:357
void writeObjectLink(const QCString &ref, const QCString &file, const QCString &anchor, const QCString &name)
Definition outputlist.h:440
void docify(const QCString &s)
Definition outputlist.h:438
void startParagraph(const QCString &classDef=QCString())
Definition outputlist.h:408
void endParagraph()
Definition outputlist.h:410
void pushGeneratorState()
void disableAllBut(OutputType o)
void popGeneratorState()
void writeLocalToc(const SectionRefs &refs, const LocalToc &lt)
Definition outputlist.h:743
void writeNavigationPath(const QCString &s)
Definition outputlist.h:609
void parseText(const QCString &textStr)
virtual QCString title() const =0
This is an alternative implementation of QCString.
Definition qcstring.h:101
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
void fill(char c, int len=-1)
Fills a string with a predefined character.
Definition qcstring.h:180
QCString & prepend(const char *s)
Definition qcstring.h:407
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:153
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:226
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:578
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:245
void resize(size_t newlen)
Definition qcstring.h:167
const std::string & str() const
Definition qcstring.h:537
QCString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple whitespace cha...
Definition qcstring.cpp:185
QCString right(size_t len) const
Definition qcstring.h:219
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:91
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:159
QCString left(size_t len) const
Definition qcstring.h:214
This struct represents an item in the list of references.
Definition reflist.h:32
int id() const
Definition reflist.h:52
RefList * list() const
Definition reflist.h:53
QCString listName() const
Definition reflist.h:101
class that provide information about a section.
Definition section.h:57
QCString label() const
Definition section.h:68
QCString ref() const
Definition section.h:71
void setDefinition(Definition *d)
Definition section.h:82
QCString fileName() const
Definition section.h:73
bool generated() const
Definition section.h:74
QCString title() const
Definition section.h:69
SectionType type() const
Definition section.h:70
singleton class that owns the list of all sections
Definition section.h:134
SectionInfo * add(const SectionInfo &si)
Definition section.h:138
static SectionManager & instance()
returns a reference to the singleton
Definition section.h:175
class that represents a list of constant references to sections.
Definition section.h:102
constexpr bool isSection() const
Definition section.h:46
Text streaming class that buffers data.
Definition textstream.h:36
Class representing a regular expression.
Definition regex.h:39
Object representing the matching results.
Definition regex.h:153
#define Config_getInt(name)
Definition config.h:34
#define Config_getList(name)
Definition config.h:38
#define Config_getBool(name)
Definition config.h:33
std::vector< std::string > StringVector
Definition containers.h:33
static std::mutex g_memberReferenceMutex
static void removeFromMap(const QCString &name, Definition *d)
bool readCodeFragment(const QCString &fileName, bool isMacro, int &startLine, int &endLine, QCString &result)
Reads a fragment from file fileName starting with line startLine and ending with line endLine.
static void addToMap(const QCString &name, Definition *d)
static bool matchExcludedSymbols(const QCString &name)
static QCString abbreviate(const QCString &s, const QCString &name)
Definition * toDefinition(DefinitionMutable *dm)
static MemberVector refMapToVector(const std::unordered_map< std::string, MemberDef * > &map)
static std::recursive_mutex g_qualifiedNameMutex
static bool stripWord(QCString &s, QCString w)
DefinitionMutable * toDefinitionMutable(Definition *d)
DirIterator end(const DirIterator &) noexcept
Definition dir.cpp:175
FileDef * toFileDef(Definition *d)
Definition filedef.cpp:1894
GroupDef * toGroupDef(Definition *d)
Translator * theTranslator
Definition language.cpp:71
MemberDef * toMemberDef(Definition *d)
#define err(fmt,...)
Definition message.h:127
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:676
FILE * popen(const QCString &name, const QCString &type)
Definition portable.cpp:496
FILE * fopen(const QCString &fileName, const QCString &mode)
Definition portable.cpp:366
int pclose(FILE *stream)
Definition portable.cpp:505
bool search(std::string_view str, Match &match, const Ex &re, size_t pos)
Search in a given string str starting at position pos for a match against regular expression re.
Definition regex.cpp:748
PageDef * toPageDef(Definition *d)
Definition pagedef.cpp:467
Portable versions of functions that are platform dependent.
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:477
#define qsnprintf
Definition qcstring.h:49
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
#define ASSERT(x)
Definition qcstring.h:39
std::vector< RefItem * > RefItemVector
Definition reflist.h:133
std::string_view stripWhiteSpace(std::string_view s)
Given a string view s, returns a new, narrower view on that string, skipping over any leading or trai...
Definition stringutil.h:72
Data associated with description found in the body.
Definition definition.h:63
int startLine
line number of the start of the definition's body
Definition definition.h:65
int endLine
line number of the end of the definition's body
Definition definition.h:66
int defLine
line number of the start of the definition
Definition definition.h:64
Data associated with a brief description.
Definition definition.h:54
QCString file
Definition definition.h:58
QCString doc
Definition definition.h:55
Data associated with a detailed description.
Definition definition.h:46
QCString doc
Definition definition.h:47
int line
Definition definition.h:48
QCString file
Definition definition.h:49
static bool useHtags
Definition htags.h:23
SrcLangExt
Language as given by extension.
Definition types.h:42
@ Fortran
Definition types.h:53
@ Unknown
Definition types.h:43
@ Python
Definition types.h:52
bool isUTF8CharUpperCase(const std::string &input, size_t pos)
Returns true iff the input string at byte position pos holds an upper case character.
Definition utf8.cpp:218
bool lastUTF8CharIsMultibyte(const std::string &input)
Returns true iff the last character in input is a multibyte character.
Definition utf8.cpp:212
Various UTF8 related helper functions.
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5645
QCString convertToHtml(const QCString &s, bool keepEntities)
Definition util.cpp:4403
QCString parseCommentAsText(const Definition *scope, const MemberDef *md, const QCString &doc, const QCString &fileName, int lineNr)
Definition util.cpp:5803
bool transcodeCharacterStringToUTF8(std::string &input, const char *inputEncoding)
Definition util.cpp:1376
bool found
Definition util.cpp:984
QCString stripScope(const QCString &name)
Definition util.cpp:4219
int computeQualifiedIndex(const QCString &name)
Return the index of the last :: in the string name that is still before the first <.
Definition util.cpp:7248
QCString convertToXML(const QCString &s, bool keepEntities)
Definition util.cpp:4352
QCString getLanguageSpecificSeparator(SrcLangExt lang, bool classScope)
Returns the scope separator to use given the programming language lang.
Definition util.cpp:6326
QCString getEncoding(const FileInfo &fi)
Definition util.cpp:6104
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5464
QCString getFileFilter(const QCString &name, bool isSourceCode)
Definition util.cpp:1342
void writeMarkerList(OutputList &ol, const std::string &markerText, size_t numMarkers, std::function< void(size_t)> replaceFunc)
Definition util.cpp:1103
void addHtmlExtensionIfMissing(QCString &fName)
Definition util.cpp:5339
A bunch of utility functions.
bool isId(int c)
Definition util.h:206