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
97 SrcLangExt lang = SrcLangExt::Unknown;
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 FileInfo fi(df.data());
116 QCString ext = fi.extension(false);
117 if (!ext.isEmpty()) defFileExt = "." + ext;
118}
119
121{
122 setDefFileName(df);
123 QCString lname = n;
124 if (lname!="<globalScope>")
125 {
126 //extractNamespaceName(m_name,m_localName,ns);
128 }
129 else
130 {
131 localName=n;
132 }
133 //printf("localName=%s\n",qPrint(localName));
134
135 brief.reset();
136 details.reset();
137 body.reset();
138 inbodyDocs.reset();
139 sourceRefByDict.clear();
140 sourceRefsDict.clear();
142 hidden = FALSE;
145 lang = SrcLangExt::Unknown;
146}
147
148void DefinitionImpl::setDefFile(const QCString &df,int defLine,int defCol)
149{
150 p->setDefFileName(df);
151 p->defLine = defLine;
152 p->defColumn = defCol;
153}
154
155//-----------------------------------------------------------------------------------------
156
158{
159 const StringVector &exclSyms = Config_getList(EXCLUDE_SYMBOLS);
160 if (exclSyms.empty()) return FALSE; // nothing specified
161 std::string symName = name.str();
162 for (const auto &pat : exclSyms)
163 {
164 QCString pattern = pat.c_str();
165 bool forceStart=FALSE;
166 bool forceEnd=FALSE;
167 if (pattern.at(0)=='^')
168 pattern=pattern.mid(1),forceStart=TRUE;
169 if (pattern.at(pattern.length()-1)=='$')
170 pattern=pattern.left(pattern.length()-1),forceEnd=TRUE;
171 if (pattern.find('*')!=-1) // wildcard mode
172 {
173 const reg::Ex re(substitute(pattern,"*",".*").str());
174 reg::Match match;
175 if (reg::search(symName,match,re)) // wildcard match
176 {
177 size_t ui = match.position();
178 size_t pl = match.length();
179 size_t sl = symName.length();
180 if ((ui==0 || pattern.at(0)=='*' || (!isId(symName.at(ui-1)) && !forceStart)) &&
181 (ui+pl==sl || pattern.at(pattern.length()-1)=='*' || (!isId(symName.at(ui+pl)) && !forceEnd))
182 )
183 {
184 //printf("--> name=%s pattern=%s match at %d\n",qPrint(symName),qPrint(pattern),i);
185 return TRUE;
186 }
187 }
188 }
189 else if (!pattern.isEmpty()) // match words
190 {
191 size_t i = symName.find(pattern.str());
192 if (i!=std::string::npos) // we have a match!
193 {
194 size_t ui=i;
195 size_t pl=pattern.length();
196 size_t sl=symName.length();
197 // check if it is a whole word match
198 if ((ui==0 || (!isId(symName.at(ui-1)) && !forceStart)) &&
199 (ui+pl==sl || (!isId(symName.at(ui+pl)) && !forceEnd))
200 )
201 {
202 //printf("--> name=%s pattern=%s match at %d\n",qPrint(symName),qPrint(pattern),i);
203 return TRUE;
204 }
205 }
206 }
207 }
208 //printf("--> name=%s: no match\n",name);
209 return FALSE;
210}
211
212static void addToMap(const QCString &name,Definition *d)
213{
214 bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
217 if (!vhdlOpt && index!=-1) symbolName=symbolName.mid(index+2);
218 if (!symbolName.isEmpty())
219 {
220 //printf("adding symbol %s\n",qPrint(symbolName));
222
224 }
225}
226
227static void removeFromMap(const QCString &name,Definition *d)
228{
229 Doxygen::symbolMap->remove(name,d);
230}
231
233 const QCString &df,int dl,int dc,
234 const QCString &name,const char *b,
235 const char *d,bool isSymbol)
236 : p(std::make_unique<Private>())
237{
238 setName(name);
239 p->def = def;
240 p->defLine = dl;
241 p->defColumn = dc;
242 p->init(df,name);
243 p->isSymbol = isSymbol;
244 if (isSymbol) addToMap(name,def);
245 _setBriefDescription(b,df,dl);
248 {
249 p->hidden = TRUE;
250 }
251}
252
254 : p(std::make_unique<Private>(*d.p))
255{
256 if (p->isSymbol) addToMap(p->name,p->def);
257}
258
260{
261 if (this!=&other)
262 {
263 p = std::make_unique<Private>(*other.p);
264 }
265 return *this;
266}
267
269{
270 if (p->isSymbol)
271 {
272 removeFromMap(p->symbolName,p->def);
273 }
274}
275
277{
278 if (name.isEmpty()) return;
279 p->name = name;
280 p->isAnonymous = p->name.isEmpty() ||
281 p->name.at(0)=='@' ||
282 p->name.find("::@")!=-1;
283}
284
286{
287 if (id.isEmpty()) return;
288 p->id = id;
290 {
291 //printf("DefinitionImpl::setId '%s'->'%s'\n",id,qPrint(p->name));
292 Doxygen::clangUsrMap->emplace(id.str(),p->def);
293 }
294}
295
297{
298 return p->id;
299}
301void DefinitionImpl::addSectionsToDefinition(const std::vector<const SectionInfo*> &anchorList)
302{
303 //printf("%s: addSectionsToDefinition(%d)\n",qPrint(name()),anchorList->count());
304 for (const SectionInfo *si : anchorList)
305 {
306 //printf("Add section '%s' to definition '%s'\n",
307 // qPrint(si->label()),qPrint(name()));
309 SectionInfo *gsi=sm.find(si->label());
310 //printf("===== label=%s gsi=%p\n",qPrint(si->label),gsi);
311 if (gsi==nullptr)
312 {
313 gsi = sm.add(*si);
314 }
315 if (p->sectionRefs.find(gsi->label())==nullptr)
316 {
317 p->sectionRefs.add(gsi);
318 gsi->setDefinition(p->def);
319 }
320 }
321}
322
324{
325 //printf("DefinitionImpl::hasSections(%s) #sections=%d\n",qPrint(name()),
326 // p->sectionRefs.size());
327 if (p->sectionRefs.empty()) return FALSE;
328 for (const SectionInfo *si : p->sectionRefs)
329 {
330 if (si->type().isSection())
331 {
332 return TRUE;
333 }
334 }
335 return FALSE;
336}
337
339{
340 if (!p->sectionRefs.empty())
341 {
342 //printf("%s: writeDocAnchorsToTagFile(%d)\n",qPrint(name()),p->sectionRef.size());
343 for (const SectionInfo *si : p->sectionRefs)
344 {
345 if (!si->generated() && si->ref().isEmpty() && !AnchorGenerator::instance().isGenerated(si->label().str()))
346 {
347 //printf("write an entry!\n");
348 if (p->def->definitionType()==Definition::TypeMember) tagFile << " ";
349 QCString fn = si->fileName();
351 tagFile << " <docanchor file=\"" << fn << "\"";
352 if (!si->title().isEmpty())
353 {
354 tagFile << " title=\"" << convertToXML(si->title()) << "\"";
355 }
356 tagFile << ">" << si->label() << "</docanchor>\n";
357 }
358 }
359 }
360}
361
363{
364 uint8_t md5_sig[16];
365 char sigStr[33];
366 // to avoid mismatches due to differences in indenting, we first remove
367 // double whitespaces...
368 QCString docStr = doc.simplifyWhiteSpace();
369 MD5Buffer(docStr.data(),static_cast<unsigned int>(docStr.length()),md5_sig);
370 MD5SigToString(md5_sig,sigStr);
371 //printf("%s:_docsAlreadyAdded doc='%s' sig='%s' docSigs='%s'\n",
372 // qPrint(name()),qPrint(doc),qPrint(sigStr),qPrint(sigList));
373 if (sigList.find(sigStr)==-1) // new docs, add signature to prevent re-adding it
374 {
375 sigList+=QCString(":")+sigStr;
376 return FALSE;
377 }
378 else
379 {
380 return TRUE;
381 }
382}
383
385 bool stripWhiteSpace,bool atTop)
386{
387 //printf("%s::setDocumentation(%s,%s,%d,%d)\n",qPrint(name()),d,docFile,docLine,stripWhiteSpace);
388 if (d.isEmpty()) return;
389 QCString doc = d;
390 if (stripWhiteSpace)
391 {
393 }
394 else // don't strip whitespace
395 {
396 doc=d;
397 }
398 if (!_docsAlreadyAdded(doc,p->docSignatures))
399 {
400 //printf("setting docs for %s: '%s'\n",qPrint(name()),qPrint(m_doc));
401 if (!p->details.has_value())
402 {
403 p->details = std::make_optional<DocInfo>();
404 }
405 DocInfo &details = p->details.value();
406 if (details.doc.isEmpty()) // fresh detailed description
407 {
408 details.doc = doc;
409 }
410 else if (atTop) // another detailed description, append it to the start
411 {
412 details.doc = doc+"\n\n"+details.doc;
413 }
414 else // another detailed description, append it to the end
415 {
416 details.doc += "\n\n"+doc;
417 }
418 if (docLine!=-1) // store location if valid
419 {
420 details.file = docFile;
421 details.line = docLine;
422 }
423 else
424 {
425 details.file = docFile;
426 details.line = 1;
427 }
428 }
429}
430
436
438{
439 QCString brief = b;
440 brief = brief.stripWhiteSpace();
442 brief = brief.stripWhiteSpace();
443 if (brief.isEmpty()) return;
444 size_t bl = brief.length();
445 if (bl>0)
446 {
447 if (!theTranslator || theTranslator->needsPunctuation()) // add punctuation if needed
448 {
449 int c = brief.at(bl-1);
450 switch(c)
451 {
452 case '.': case '!': case '?': case '>': case ':': case ')': break;
453 default:
454 if (isUTF8CharUpperCase(brief.str(),0) && !lastUTF8CharIsMultibyte(brief.str())) brief+='.';
455 break;
456 }
457 }
458 }
459
460 if (!_docsAlreadyAdded(brief,p->briefSignatures))
461 {
462 if (p->brief && !p->brief->doc.isEmpty())
463 {
464 //printf("adding to details\n");
466 }
467 else
468 {
469 //fprintf(stderr,"DefinitionImpl::setBriefDescription(%s,%s,%d)\n",b,briefFile,briefLine);
470 if (!p->brief.has_value())
471 {
472 p->brief = std::make_optional<BriefInfo>();
473 }
474 BriefInfo &briefInfo = p->brief.value();
475 briefInfo.doc=brief;
476 if (briefLine!=-1)
477 {
478 briefInfo.file = briefFile;
479 briefInfo.line = briefLine;
480 }
481 else
482 {
483 briefInfo.file = briefFile;
484 briefInfo.line = 1;
485 }
486 }
487 }
488 else
489 {
490 //printf("do nothing!\n");
491 }
492}
493
499
501{
502 if (!_docsAlreadyAdded(doc,p->docSignatures))
503 {
504 if (!p->inbodyDocs.has_value())
505 {
506 p->inbodyDocs = std::make_optional<DocInfo>();
507 }
508 DocInfo &inbodyDocs = p->inbodyDocs.value();
509 if (inbodyDocs.doc.isEmpty()) // fresh inbody docs
510 {
511 inbodyDocs.doc = doc;
512 inbodyDocs.file = inbodyFile;
513 inbodyDocs.line = inbodyLine;
514 }
515 else // another inbody documentation fragment, append this to the end
516 {
517 inbodyDocs.doc += QCString("\n\n")+doc;
518 }
519 }
520}
521
527
528//---------------------------------------
529
530/*! Cache for storing the result of filtering a file */
532{
533 private:
535 {
536 size_t filePos;
537 size_t fileSize;
538 };
539 using LineOffsets = std::vector<size_t>;
540
541 public:
542 static FilterCache &instance();
543
544 //! collects the part of file \a fileName starting at \a startLine and ending at \a endLine into
545 //! buffer \a str. Applies filtering if FILTER_SOURCE_FILES is enabled and the file extension
546 //! matches a filter. Caches file information so that subsequent extraction of blocks from
547 //! the same file can be performed efficiently
548 bool getFileContents(const QCString &fileName,size_t startLine,size_t endLine, std::string &str)
549 {
550 bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
551 QCString filter = getFileFilter(fileName,TRUE);
552 bool usePipe = !filter.isEmpty() && filterSourceFiles;
553 return usePipe ? getFileContentsPipe(fileName,filter,startLine,endLine,str)
554 : getFileContentsDisk(fileName,startLine,endLine,str);
555 }
556 private:
557 bool getFileContentsPipe(const QCString &fileName,const QCString &filter,
558 size_t startLine,size_t endLine,std::string &str)
559 {
560 std::unique_lock<std::mutex> lock(m_mutex);
561 auto it = m_cache.find(fileName.str());
562 if (it!=m_cache.end()) // cache hit: reuse stored result
563 {
564 lock.unlock();
565 auto item = it->second;
566 //printf("getFileContents(%s): cache hit\n",qPrint(fileName));
567 // file already processed, get the results after filtering from the tmp file
568 Debug::print(Debug::FilterOutput,0,"Reusing filter result for {} from {} at offset={} size={}\n",
569 fileName,Doxygen::filterDBFileName,item.filePos,item.fileSize);
570
571 auto it_off = m_lineOffsets.find(fileName.str());
572 assert(it_off!=m_lineOffsets.end());
573 auto [ startLineOffset, fragmentSize] = getFragmentLocation(it_off->second,startLine,endLine);
574 //printf("%s: existing file [%zu-%zu]->[%zu-%zu] size=%zu\n",
575 // qPrint(fileName),startLine,endLine,startLineOffset,endLineOffset,fragmentSize);
577 item.filePos+startLineOffset, fragmentSize);
578 return true;
579 }
580 else // cache miss: filter active but file not previously processed
581 {
582 //printf("getFileContents(%s): cache miss\n",qPrint(fileName));
583 // filter file
584 QCString cmd=filter+" \""+fileName+"\"";
585 Debug::print(Debug::ExtCmd,0,"Executing popen(`{}`)\n",cmd);
586 FILE *f = Portable::popen(cmd,"r");
587 if (f==nullptr)
588 {
589 // handle error
590 err("Error opening filter pipe command '{}'\n",cmd);
591 return false;
592 }
594 FilterCacheItem item;
595 item.filePos = m_endPos;
596 if (bf==nullptr)
597 {
598 // handle error
599 err("Error opening filter database file {}\n",Doxygen::filterDBFileName);
601 return false;
602 }
603 // append the filtered output to the database file
604 size_t size=0;
605 while (!feof(f))
606 {
607 const int blockSize = 4096;
608 char buf[blockSize];
609 size_t bytesRead = fread(buf,1,blockSize,f);
610 size_t bytesWritten = fwrite(buf,1,bytesRead,bf);
611 if (bytesRead!=bytesWritten)
612 {
613 // handle error
614 err("Failed to write to filter database {}. Wrote {} out of {} bytes\n",
615 Doxygen::filterDBFileName,bytesWritten,bytesRead);
617 fclose(bf);
618 return false;
619 }
620 size+=bytesWritten;
621 str+=std::string_view(buf,bytesWritten);
622 }
623 item.fileSize = size;
624 // add location entry to the dictionary
625 m_cache.emplace(fileName.str(),item);
626 Debug::print(Debug::FilterOutput,0,"Storing new filter result for {} in {} at offset={} size={}\n",
627 fileName,Doxygen::filterDBFileName,item.filePos,item.fileSize);
628 // update end of file position
629 m_endPos += size;
631 fclose(bf);
632
633 // shrink buffer to [startLine..endLine] part
634 shrinkBuffer(str,fileName,startLine,endLine);
635 }
636 return true;
637 }
638
639 //! reads the fragment start at \a startLine and ending at \a endLine from file \a fileName
640 //! into buffer \a str
641 bool getFileContentsDisk(const QCString &fileName,size_t startLine,size_t endLine,std::string &str)
642 {
643 std::unique_lock<std::mutex> lock(m_mutex);
644 // normal file
645 //printf("getFileContents(%s): no filter\n",qPrint(fileName));
646 auto it = m_lineOffsets.find(fileName.str());
647 if (it == m_lineOffsets.end()) // new file
648 {
649 // read file completely into str buffer
650 readFragmentFromFile(str,fileName,0);
651 // shrink buffer to [startLine..endLine] part
652 shrinkBuffer(str,fileName,startLine,endLine);
653 }
654 else // file already processed before
655 {
656 lock.unlock();
657 auto [ startLineOffset, fragmentSize] = getFragmentLocation(it->second,startLine,endLine);
658 //printf("%s: existing file [%zu-%zu] -> start=%zu size=%zu\n",
659 // qPrint(fileName),startLine,endLine,startLineOffset,fragmentSize);
660 readFragmentFromFile(str,fileName,startLineOffset,fragmentSize);
661 }
662 return true;
663 }
664
665 //! computes the starting offset for each line for file \a fileName, whose contents should
666 //! already be stored in buffer \a str.
667 void compileLineOffsets(const QCString &fileName,const std::string &str)
668 {
669 // line 1 (index 0) is at offset 0
670 auto it = m_lineOffsets.emplace(fileName.data(),LineOffsets{0}).first;
671 const char *p=str.data();
672 while (*p)
673 {
674 char c=0;
675 while ((c=*p)!='\n' && c!=0) p++; // search until end of the line
676 if (c!=0) p++;
677 it->second.push_back(p-str.data());
678 }
679 }
680
681 //! Returns the byte offset and size within a file of a fragment given the array of
682 //! line offsets and the start and end line of the fragment.
683 auto getFragmentLocation(const LineOffsets &lineOffsets,
684 size_t startLine,size_t endLine) -> std::tuple<size_t,size_t>
685 {
686 assert(startLine > 0);
687 assert(startLine <= endLine);
688 const size_t startLineOffset = lineOffsets[std::min(startLine-1,lineOffsets.size()-1)];
689 const size_t endLineOffset = lineOffsets[std::min(endLine, lineOffsets.size()-1)];
690 assert(startLineOffset <= endLineOffset);
691 const size_t fragmentSize = endLineOffset-startLineOffset;
692 return std::tie(startLineOffset,fragmentSize);
693 };
694
695 //! Shrinks buffer \a str which should hold the contents of \a fileName to the
696 //! fragment starting a line \a startLine and ending at line \a endLine
697 void shrinkBuffer(std::string &str,const QCString &fileName,size_t startLine,size_t endLine)
698 {
699 // compute offsets from start for each line
700 compileLineOffsets(fileName,str);
701 auto it = m_lineOffsets.find(fileName.str());
702 assert(it!=m_lineOffsets.end());
703 const LineOffsets &lineOffsets = it->second;
704 auto [ startLineOffset, fragmentSize] = getFragmentLocation(lineOffsets,startLine,endLine);
705 //printf("%s: new file [%zu-%zu]->[%zu-%zu] size=%zu\n",
706 // qPrint(fileName),startLine,endLine,startLineOffset,endLineOffset,fragmentSize);
707 str.erase(0,startLineOffset);
708 str.resize(fragmentSize);
709 }
710
711 //! Reads the fragment start at byte offset \a startOffset of file \a fileName into buffer \a str.
712 //! Result will be a null terminated. If size==0 the whole file will be read and startOffset is ignored.
713 //! If size>0, size bytes will be read.
714 void readFragmentFromFile(std::string &str,const QCString &fileName,size_t startOffset,size_t size=0)
715 {
716 std::ifstream ifs = Portable::openInputStream(fileName,true,true);
717 if (size==0) { startOffset=0; size = static_cast<size_t>(ifs.tellg()); }
718 ifs.seekg(startOffset, std::ios::beg);
719 str.resize(size);
720 ifs.read(str.data(), size);
721 }
722
724 std::unordered_map<std::string,FilterCacheItem> m_cache;
725 std::unordered_map<std::string,LineOffsets> m_lineOffsets;
726 std::mutex m_mutex;
727 size_t m_endPos;
728};
729
731{
732 static FilterCache theInstance;
733 return theInstance;
734}
735
736//-----------------------------------------
737
738
739/*! Reads a fragment of code from file \a fileName starting at
740 * line \a startLine and ending at line \a endLine (inclusive). The fragment is
741 * stored in \a result. If FALSE is returned the code fragment could not be
742 * found.
743 *
744 * The file is scanned for a opening bracket ('{') from \a startLine onward
745 * The line actually containing the bracket is returned via startLine.
746 * The file is scanned for a closing bracket ('}') from \a endLine backward.
747 * The line actually containing the bracket is returned via endLine.
748 * Note that for VHDL code the bracket search is not done.
749 */
750bool readCodeFragment(const QCString &fileName,bool isMacro,
751 int &startLine,int &endLine,QCString &result)
752{
753 bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
754 QCString filter = getFileFilter(fileName,TRUE);
755 bool usePipe = !filter.isEmpty() && filterSourceFiles;
756 int tabSize = Config_getInt(TAB_SIZE);
757 SrcLangExt lang = getLanguageFromFileName(fileName);
758 const int blockSize = 4096;
759 std::string str;
761 static_cast<size_t>(std::max(1,startLine)),
762 static_cast<size_t>(std::max({1,startLine,endLine})),str);
763 //printf("readCodeFragment(%s,startLine=%d,endLine=%d)=\n[[[\n%s]]]\n",qPrint(fileName),startLine,endLine,qPrint(str));
764
765 bool found = lang==SrcLangExt::VHDL ||
766 lang==SrcLangExt::Python ||
767 lang==SrcLangExt::Fortran ||
768 isMacro;
769 // for VHDL, Python, and Fortran no bracket search is possible
770 char *p=str.data();
771 if (p && *p)
772 {
773 char c=0;
774 int col=0;
775 int lineNr=startLine;
776 // skip until the opening bracket or lonely : is found
777 char cn=0;
778 while (*p && !found)
779 {
780 int pc=0;
781 while ((c=*p++)!='{' && c!=':' && c!=0)
782 {
783 //printf("parsing char '%c'\n",c);
784 if (c=='\n')
785 {
786 lineNr++,col=0;
787 }
788 else if (c=='\t')
789 {
790 col+=tabSize - (col%tabSize);
791 }
792 else if (pc=='/' && c=='/') // skip single line comment
793 {
794 while ((c=*p++)!='\n' && c!=0);
795 if (c=='\n') lineNr++,col=0;
796 }
797 else if (pc=='/' && c=='*') // skip C style comment
798 {
799 while (((c=*p++)!='/' || pc!='*') && c!=0)
800 {
801 if (c=='\n') lineNr++,col=0;
802 pc=c;
803 }
804 }
805 else
806 {
807 col++;
808 }
809 pc = c;
810 }
811 if (c==':')
812 {
813 cn=*p++;
814 if (cn!=':') found=TRUE;
815 }
816 else if (c=='{')
817 {
818 found=TRUE;
819 }
820 else if (c==0)
821 {
822 break;
823 }
824 }
825 //printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr);
826 if (found)
827 {
828 // For code with more than one line,
829 // fill the line with spaces until we are at the right column
830 // so that the opening brace lines up with the closing brace
831 if (endLine!=startLine)
832 {
833 QCString spaces;
834 spaces.fill(' ',col);
835 result+=spaces;
836 }
837 // copy until end of line
838 if (c) result+=c;
839 startLine=lineNr;
840 if (c==':')
841 {
842 result+=cn;
843 if (cn=='\n') lineNr++;
844 }
845 char lineStr[blockSize];
846 do
847 {
848 //printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine);
849 int size_read=0;
850 do
851 {
852 // read up to blockSize-1 non-zero characters
853 int i=0;
854 while ((c=*p) && i<blockSize-1)
855 {
856 lineStr[i++]=c;
857 p++;
858 if (c=='\n') break; // stop at end of the line
859 }
860 lineStr[i]=0;
861 size_read=i;
862 result+=lineStr; // append line to the output
863 } while (size_read == (blockSize-1)); // append more if line does not fit in buffer
864 lineNr++;
865 } while (*p);
866
867 // strip stuff after closing bracket
868 int newLineIndex = result.findRev('\n');
869 int braceIndex = result.findRev('}');
870 if (braceIndex > newLineIndex)
871 {
872 result.resize(static_cast<size_t>(braceIndex+1));
873 }
874 endLine=lineNr-1;
875 }
876 if (usePipe)
877 {
878 Debug::print(Debug::FilterOutput, 0, "Filter output\n");
879 Debug::print(Debug::FilterOutput,0,"-------------\n{}\n-------------\n",result);
880 }
881 }
882 QCString encoding = getEncoding(FileInfo(fileName.str()));
883 if (encoding!="UTF-8")
884 {
885 std::string encBuf = result.str();
886 bool ok = transcodeCharacterStringToUTF8(encBuf,encoding.data());
887 if (ok)
888 {
889 result = QCString(encBuf);
890 }
891 else
892 {
893 err("failed to transcode characters in code fragment in file {} lines {} to {}, from input encoding {} to UTF-8\n",
894 fileName,startLine,endLine,encoding);
895
896 }
897 }
898 if (!result.isEmpty() && result.at(result.length()-1)!='\n') result += "\n";
899 //printf("readCodeFragment(%d-%d)=%s\n",startLine,endLine,qPrint(result));
900 return found;
901}
902
904{
905 ASSERT(p->def->definitionType()!=Definition::TypeFile); // file overloads this method
906 QCString fn;
907 bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
908 if (sourceBrowser &&
909 p->body && p->body->startLine!=-1 && p->body->fileDef)
910 {
911 fn = p->body->fileDef->getSourceFileBase();
912 }
913 return fn;
914}
915
917{
918 const int maxAnchorStrLen = 20;
919 char anchorStr[maxAnchorStrLen];
920 anchorStr[0]='\0';
921 if (p->body && p->body->startLine!=-1)
922 {
923 if (Htags::useHtags)
924 {
925 qsnprintf(anchorStr,maxAnchorStrLen,"L%d",p->body->defLine);
926 }
927 else
928 {
929 qsnprintf(anchorStr,maxAnchorStrLen,"l%05d",p->body->defLine);
930 }
931 }
932 return anchorStr;
933}
934
935/*! Write a reference to the source code defining this definition */
937{
938 //printf("DefinitionImpl::writeSourceRef %d %p\n",bodyLine,bodyDef);
940 if (!fn.isEmpty())
941 {
942 QCString refText = theTranslator->trDefinedAtLineInSourceFile();
943 int lineMarkerPos = refText.find("@0");
944 int fileMarkerPos = refText.find("@1");
945 if (lineMarkerPos!=-1 && fileMarkerPos!=-1) // should always pass this.
946 {
947 QCString lineStr;
948 lineStr.sprintf("%d",p->body->defLine);
949 QCString anchorStr = getSourceAnchor();
950 ol.startParagraph("definition");
951 if (lineMarkerPos<fileMarkerPos) // line marker before file marker
952 {
953 // write text left from linePos marker
954 ol.parseText(refText.left(lineMarkerPos));
955 ol.writeObjectLink(QCString(),fn,anchorStr,lineStr);
956 // write text between markers
957 ol.parseText(refText.mid(lineMarkerPos+2,fileMarkerPos-lineMarkerPos-2));
958 // write file link
959 ol.writeObjectLink(QCString(),fn,QCString(),p->body->fileDef->name());
960 // write text right from file marker
961 ol.parseText(refText.right(refText.length()-static_cast<size_t>(fileMarkerPos)-2));
962 }
963 else // file marker before line marker
964 {
965 // write text left from file marker
966 ol.parseText(refText.left(fileMarkerPos));
967 // write file link
968 ol.writeObjectLink(QCString(),fn,QCString(),p->body->fileDef->name());
969 // write text between markers
970 ol.parseText(refText.mid(fileMarkerPos+2,lineMarkerPos-fileMarkerPos-2));
971 // write line link
972 ol.writeObjectLink(QCString(),fn,anchorStr,lineStr);
973 // write text right from linePos marker
974 ol.parseText(refText.right(refText.length()-static_cast<size_t>(lineMarkerPos)-2));
975 }
976 ol.endParagraph();
977 }
978 else
979 {
980 err("translation error: invalid markers in trDefinedAtLineInSourceFile()\n");
981 }
982 }
983}
984
985void DefinitionImpl::setBodySegment(int defLine, int bls,int ble)
986{
987 if (!p->body.has_value())
988 {
989 p->body = std::make_optional<BodyInfo>();
990 }
991 BodyInfo &body = p->body.value();
992 body.defLine = defLine;
993 body.startLine = bls;
994 body.endLine = ble;
995}
996
998{
999 if (!p->body.has_value())
1000 {
1001 p->body = std::make_optional<BodyInfo>();
1002 }
1003 p->body.value().fileDef=fd;
1004}
1005
1007{
1008 return p->body && p->body->startLine!=-1 &&
1009 p->body->endLine>=p->body->startLine &&
1010 p->body->fileDef;
1011}
1012
1013/*! Write code of this definition into the documentation */
1015{
1016 const MemberDef *thisMd = nullptr;
1017 if (p->def->definitionType()==Definition::TypeMember)
1018 {
1019 thisMd = toMemberDef(p->def);
1020 }
1021 bool inlineSources = thisMd && thisMd->hasInlineSource();
1022 //printf("Source Fragment %s: %d-%d\n",qPrint(name()),
1023 // p->body->startLine,p->body->endLine);
1024 if (inlineSources && hasSources())
1025 {
1026 ol.pushGeneratorState();
1027 QCString codeFragment;
1028 bool isMacro = thisMd && thisMd->memberType()==MemberType::Define;
1029 int actualStart=p->body->startLine,actualEnd=p->body->endLine;
1030 if (readCodeFragment(p->body->fileDef->absFilePath(),isMacro,
1031 actualStart,actualEnd,codeFragment)
1032 )
1033 {
1034 //printf("Adding code fragment '%s' ext='%s' range=%d-%d\n",
1035 // qPrint(codeFragment),qPrint(p->defFileExt),actualStart,actualEnd);
1036 auto intf = Doxygen::parserManager->getCodeParser(p->defFileExt);
1037 intf->resetCodeParserState();
1038 //printf("Read:\n'%s'\n\n",qPrint(codeFragment));
1039
1040 auto &codeOL = ol.codeGenerators();
1041 codeOL.startCodeFragment("DoxyCode");
1042 intf->parseCode(codeOL, // codeOutIntf
1043 scopeName, // scope
1044 codeFragment, // input
1045 p->lang, // lang
1046 Config_getBool(STRIP_CODE_COMMENTS),
1047 FALSE, // isExample
1048 QCString(), // exampleName
1049 p->body->fileDef, // fileDef
1050 actualStart, // startLine
1051 actualEnd, // endLine
1052 TRUE, // inlineFragment
1053 thisMd, // memberDef
1054 TRUE // show line numbers
1055 );
1056 codeOL.endCodeFragment("DoxyCode");
1057 }
1058 ol.popGeneratorState();
1059 }
1060}
1061
1062static inline MemberVector refMapToVector(const std::unordered_map<std::string,MemberDef *> &map)
1063{
1064 // convert map to a vector of values
1065 MemberVector result;
1066 std::transform(map.begin(),map.end(), // iterate over map
1067 std::back_inserter(result), // add results to vector
1068 [](const auto &item)
1069 { return item.second; } // extract value to add from map Key,Value pair
1070 );
1071 // and sort it
1072 std::stable_sort(result.begin(),result.end(),
1073 [](const auto &m1,const auto &m2) { return genericCompareMembers(m1,m2)<0; });
1074 return result;
1075}
1076
1077/*! Write a reference to the source code fragments in which this
1078 * definition is used.
1079 */
1081 const QCString &text,const std::unordered_map<std::string,MemberDef *> &membersMap,
1082 bool /*funcOnly*/) const
1083{
1084 if (!membersMap.empty())
1085 {
1086 auto members = refMapToVector(membersMap);
1087
1088 auto replaceFunc = [this,&members,scopeName,&ol](size_t entryIndex)
1089 {
1090 bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1091 bool refLinkSource = Config_getBool(REFERENCES_LINK_SOURCE);
1092 const MemberDef *md=members[entryIndex];
1093 if (md)
1094 {
1095 QCString scope=md->getScopeString();
1096 QCString name=md->name();
1097 //printf("class=%p scope=%s scopeName=%s\n",md->getClassDef(),qPrint(scope),scopeName);
1098 if (!scope.isEmpty() && scope!=scopeName)
1099 {
1100 name.prepend(scope+getLanguageSpecificSeparator(p->lang));
1101 }
1102 if (!md->isObjCMethod() &&
1103 (md->isFunction() || md->isSlot() ||
1104 md->isPrototype() || md->isSignal()
1105 )
1106 )
1107 {
1108 name+="()";
1109 }
1110 if (sourceBrowser &&
1111 !(md->isLinkable() && !refLinkSource) &&
1112 md->getStartBodyLine()!=-1 &&
1113 md->getBodyDef()
1114 )
1115 {
1116 const int maxLineNrStr = 10;
1117 char anchorStr[maxLineNrStr];
1118 qsnprintf(anchorStr,maxLineNrStr,"l%05d",md->getStartBodyLine());
1119 //printf("Write object link to %s\n",qPrint(md->getBodyDef()->getSourceFileBase()));
1120 ol.writeObjectLink(QCString(),md->getBodyDef()->getSourceFileBase(),anchorStr,name);
1121 }
1122 else if (md->isLinkable())
1123 {
1125 md->getOutputFileBase(),
1126 md->anchor(),name);
1127 }
1128 else
1129 {
1130 ol.docify(name);
1131 }
1132 }
1133 };
1134
1135 ol.startParagraph("reference");
1136 ol.parseText(text);
1137 ol.docify(" ");
1138 writeMarkerList(ol,
1139 theTranslator->trWriteList(static_cast<int>(members.size())).str(),
1140 members.size(),
1141 replaceFunc);
1142 ol.writeString(".");
1143 ol.endParagraph();
1144
1145 }
1146}
1147
1149{
1150 _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),p->sourceRefByDict,FALSE);
1151}
1152
1154{
1155 _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),p->sourceRefsDict,TRUE);
1156}
1157
1159{
1160 return !p->sourceRefByDict.empty();
1161}
1162
1164{
1165 return !p->sourceRefsDict.empty();
1166}
1167
1169{
1170 bool extractAll = Config_getBool(EXTRACT_ALL);
1171 //bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1172 bool hasDocs =
1173 (p->details && !p->details->doc.isEmpty()) || // has detailed docs
1174 (p->brief && !p->brief->doc.isEmpty()) || // has brief description
1175 (p->inbodyDocs && !p->inbodyDocs->doc.isEmpty()) || // has inbody docs
1176 extractAll //|| // extract everything
1177 // (sourceBrowser && p->body &&
1178 // p->body->startLine!=-1 && p->body->fileDef)
1179 ; // link to definition
1180 return hasDocs;
1181}
1182
1184{
1185 bool hasDocs =
1186 (p->details && !p->details->doc.isEmpty()) ||
1187 (p->brief && !p->brief->doc.isEmpty()) ||
1188 (p->inbodyDocs && !p->inbodyDocs->doc.isEmpty());
1189 return hasDocs;
1190}
1191
1193{
1194 if (md)
1195 {
1196 p->sourceRefByDict.emplace(sourceRefName.str(),md);
1197 }
1198}
1199
1201{
1202 if (md)
1203 {
1204 p->sourceRefsDict.emplace(sourceRefName.str(),md);
1205 }
1206}
1207
1209{
1210 return nullptr;
1211}
1212
1214{
1215 err("DefinitionImpl::addInnerCompound() called\n");
1216}
1217
1218static std::recursive_mutex g_qualifiedNameMutex;
1219
1221{
1222 std::lock_guard<std::recursive_mutex> lock(g_qualifiedNameMutex);
1223 if (!p->qualifiedName.isEmpty())
1224 {
1225 return p->qualifiedName;
1226 }
1227
1228 //printf("start %s::qualifiedName() localName=%s\n",qPrint(name()),qPrint(p->localName));
1229 if (p->outerScope==nullptr)
1230 {
1231 if (p->localName=="<globalScope>")
1232 {
1233 return "";
1234 }
1235 else
1236 {
1237 return p->localName;
1238 }
1239 }
1240
1241 if (p->outerScope->name()=="<globalScope>")
1242 {
1243 p->qualifiedName = p->localName;
1244 }
1245 else
1246 {
1247 p->qualifiedName = p->outerScope->qualifiedName()+
1249 p->localName;
1250 }
1251 //printf("end %s::qualifiedName()=%s\n",qPrint(name()),qPrint(p->qualifiedName));
1252 //count--;
1253 return p->qualifiedName;
1254}
1255
1257{
1258 std::lock_guard<std::recursive_mutex> lock(g_qualifiedNameMutex);
1259 //printf("%s::setOuterScope(%s)\n",qPrint(name()),d?qPrint(d->name()):"<none>");
1260 Definition *outerScope = p->outerScope;
1261 bool found=false;
1262 // make sure that we are not creating a recursive scope relation.
1263 while (outerScope && !found)
1264 {
1265 found = (outerScope==d);
1266 outerScope = outerScope->getOuterScope();
1267 }
1268 if (!found)
1269 {
1270 p->qualifiedName.clear(); // flush cached scope name
1271 p->outerScope = d;
1272 }
1273 p->hidden = p->hidden || d->isHidden();
1274 assert(p->def!=p->outerScope);
1275}
1276
1278{
1279 return p->localName;
1280}
1281
1283{
1284 p->partOfGroups.push_back(gd);
1285}
1286
1288{
1289 p->xrefListItems.insert(p->xrefListItems.end(), sli.cbegin(), sli.cend());
1290}
1291
1293{
1294 auto otherXrefList = d->xrefListItems();
1295
1296 // append vectors
1297 p->xrefListItems.reserve(p->xrefListItems.size()+otherXrefList.size());
1298 p->xrefListItems.insert (p->xrefListItems.end(),
1299 otherXrefList.begin(),otherXrefList.end());
1300
1301 // sort results on itemId
1302 std::stable_sort(p->xrefListItems.begin(),p->xrefListItems.end(),
1303 [](RefItem *left,RefItem *right)
1304 { return left->id() <right->id() ||
1305 (left->id()==right->id() &&
1306 left->list()->listName() < right->list()->listName());
1307 });
1308
1309 // filter out duplicates
1310 auto last = std::unique(p->xrefListItems.begin(),p->xrefListItems.end(),
1311 [](const RefItem *left,const RefItem *right)
1312 { return left->id()==right->id() &&
1313 left->list()->listName()==right->list()->listName();
1314 });
1315 p->xrefListItems.erase(last, p->xrefListItems.end());
1316}
1317
1319{
1320 for (const RefItem *item : p->xrefListItems)
1321 {
1322 if (item->list()->listName()==listName)
1323 {
1324 return item->id();
1325 }
1326 }
1327 return -1;
1328}
1329
1331{
1332 return p->xrefListItems;
1333}
1334
1336{
1337 QCString result;
1338 if (p->outerScope && p->outerScope!=Doxygen::globalScope)
1339 {
1340 result = p->outerScope->pathFragment();
1341 }
1342 if (p->def->isLinkable())
1343 {
1344 if (!result.isEmpty()) result+="/";
1345 if (p->def->definitionType()==Definition::TypeGroup &&
1346 !toGroupDef(p->def)->groupTitle().isEmpty())
1347 {
1348 result+=toGroupDef(p->def)->groupTitle();
1349 }
1350 else if (p->def->definitionType()==Definition::TypePage &&
1351 toPageDef(p->def)->hasTitle())
1352 {
1353 result+=toPageDef(p->def)->title();
1354 }
1355 else
1356 {
1357 result+=p->localName;
1358 }
1359 }
1360 else
1361 {
1362 result+=p->localName;
1363 }
1364 return result;
1365}
1366
1367//----------------------------------------------------------------------------------------
1368
1369// TODO: move to htmlgen
1370/*! Returns the string used in the footer for $navpath when
1371 * GENERATE_TREEVIEW is enabled
1372 */
1374{
1375 QCString result;
1376 Definition *outerScope = getOuterScope();
1377 QCString locName = localName();
1378 if (outerScope && outerScope!=Doxygen::globalScope)
1379 {
1380 result+=outerScope->navigationPathAsString();
1381 }
1382 else if (p->def->definitionType()==Definition::TypeFile &&
1383 toFileDef(p->def)->getDirDef())
1384 {
1385 result+=(toFileDef(p->def))->getDirDef()->navigationPathAsString();
1386 }
1387 result+="<li class=\"navelem\">";
1388 if (p->def->isLinkableInProject())
1389 {
1390 QCString fn = p->def->getOutputFileBase();
1392 if (p->def->definitionType()==Definition::TypeGroup &&
1393 !toGroupDef(p->def)->groupTitle().isEmpty())
1394 {
1395 result+="<a href=\"$relpath^"+fn+"\">"+
1396 convertToHtml(toGroupDef(p->def)->groupTitle())+"</a>";
1397 }
1398 else if (p->def->definitionType()==Definition::TypePage &&
1399 toPageDef(p->def)->hasTitle())
1400 {
1401 result+="<a href=\"$relpath^"+fn+"\">"+
1402 convertToHtml((toPageDef(p->def))->title())+"</a>";
1403 }
1404 else if (p->def->definitionType()==Definition::TypeClass)
1405 {
1406 QCString name = toClassDef(p->def)->className();
1407 if (name.endsWith("-p"))
1408 {
1409 name = name.left(name.length()-2);
1410 }
1411 result+="<a href=\"$relpath^"+fn;
1412 if (!p->def->anchor().isEmpty()) result+="#"+p->def->anchor();
1413 result+="\">"+convertToHtml(name)+"</a>";
1414 }
1415 else
1416 {
1417 result+="<a href=\"$relpath^"+fn+"\">"+
1418 convertToHtml(locName)+"</a>";
1419 }
1420 }
1421 else
1422 {
1423 result+="<b>"+convertToHtml(locName)+"</b>";
1424 }
1425 result+="</li>";
1426 return result;
1427}
1428
1429// TODO: move to htmlgen
1431{
1432 ol.pushGeneratorState();
1434
1435 QCString navPath;
1436 navPath += "<div id=\"nav-path\" class=\"navpath\">\n"
1437 " <ul>\n";
1438 navPath += navigationPathAsString();
1439 navPath += " </ul>\n"
1440 "</div>\n";
1441 ol.writeNavigationPath(navPath);
1442
1443 ol.popGeneratorState();
1444}
1445
1446void DefinitionImpl::writeToc(OutputList &ol, const LocalToc &localToc) const
1447{
1448 if (p->sectionRefs.empty()) return;
1449 ol.writeLocalToc(p->sectionRefs,localToc);
1450}
1451
1452//----------------------------------------------------------------------------------------
1453
1455{
1456 return p->sectionRefs;
1457}
1458
1460{
1461 return p->symbolName;
1462}
1463
1464//----------------------
1465
1467{
1468 return p->details ? p->details->doc : QCString("");
1469}
1470
1472{
1473 return p->details ? p->details->line : p->brief ? p->brief->line : 1;
1474}
1475
1477{
1478 if (p->details && !p->details->file.isEmpty()) return p->details->file;
1479 else if (p->brief && !p->brief->file.isEmpty()) return p->brief->file;
1480 else return "<" + p->name + ">";
1481}
1482
1483//----------------------------------------------------------------------------
1484// strips w from s iff s starts with w
1485static bool stripWord(QCString &s,QCString w)
1486{
1487 bool success=FALSE;
1488 if (s.left(w.length())==w)
1489 {
1490 success=TRUE;
1491 s=s.right(s.length()-w.length());
1492 }
1493 return success;
1494}
1495
1496//----------------------------------------------------------------------------
1497// some quasi intelligent brief description abbreviator :^)
1498static QCString abbreviate(const QCString &s,const QCString &name)
1499{
1500 QCString scopelessName=name;
1501 int i=scopelessName.findRev("::");
1502 if (i!=-1) scopelessName=scopelessName.mid(i+2);
1503 QCString result=s;
1504 result=result.stripWhiteSpace();
1505 // strip trailing .
1506 if (!result.isEmpty() && result.at(result.length()-1)=='.')
1507 result=result.left(result.length()-1);
1508
1509 // strip any predefined prefix
1510 const StringVector &briefDescAbbrev = Config_getList(ABBREVIATE_BRIEF);
1511 for (const auto &p : briefDescAbbrev)
1512 {
1513 QCString str = substitute(p.c_str(),"$name",scopelessName); // replace $name with entity name
1514 str += " ";
1515 stripWord(result,str);
1516 }
1517
1518 // capitalize first word
1519 if (!result.isEmpty())
1520 {
1521 char c=result[0];
1522 if (c>='a' && c<='z') c+='A'-'a';
1523 result[0]=c;
1524 }
1525 return result;
1526}
1527
1528
1529//----------------------
1530
1532{
1533 //printf("%s::briefDescription(%d)='%s'\n",qPrint(name()),abbr,p->brief?qPrint(p->brief->doc):"<none>");
1534 return p->brief ?
1535 (abbr ? abbreviate(p->brief->doc,p->def->displayName()) : p->brief->doc) :
1536 QCString("");
1537}
1538
1540{
1541 if (p->brief && p->brief->tooltip.isEmpty() && !p->brief->doc.isEmpty())
1542 {
1543 const MemberDef *md = p->def->definitionType()==Definition::TypeMember ? toMemberDef(p->def) : nullptr;
1544 const Definition *scope = p->def->definitionType()==Definition::TypeMember ? p->def->getOuterScope() : p->def;
1545 p->brief->tooltip = parseCommentAsText(scope,md,
1546 p->brief->doc, p->brief->file, p->brief->line);
1547 }
1548}
1549
1551{
1552 return p->brief ? p->brief->tooltip : QCString();
1553}
1554
1556{
1557 return p->brief ? p->brief->line : 1;
1558}
1559
1561{
1562 return p->brief && !p->brief->file.isEmpty() ? p->brief->file : QCString("<"+p->name+">");
1563}
1564
1565//----------------------
1566
1568{
1569 return p->inbodyDocs ? p->inbodyDocs->doc : QCString("");
1570}
1571
1573{
1574 return p->inbodyDocs ? p->inbodyDocs->line : 1;
1575}
1576
1578{
1579 return p->inbodyDocs && !p->inbodyDocs->file.isEmpty() ? p->inbodyDocs->file : QCString("<"+p->name+">");
1580}
1581
1582
1583//----------------------
1584
1586{
1587 return p->defFileName;
1588}
1589
1591{
1592 return p->defFileExt;
1593}
1594
1596{
1597 return p->hidden;
1598}
1599
1601{
1602 return p->def->isLinkableInProject() && !p->hidden;
1603}
1604
1606{
1607 return p->def->isLinkable() && !p->hidden;
1608}
1609
1611{
1612 return p->isArtificial;
1613}
1614
1616{
1617 return p->isExported;
1618}
1619
1621{
1622 return p->ref;
1623}
1624
1626{
1627 return !p->ref.isEmpty();
1628}
1629
1631{
1632 return p->body ? p->body->defLine : -1;
1633}
1634
1636{
1637 return p->body ? p->body->startLine : -1;
1638}
1639
1641{
1642 return p->body ? p->body->endLine : -1;
1643}
1644
1646{
1647 return p->body ? p->body->fileDef : nullptr;
1648}
1649
1651{
1652 return p->partOfGroups;
1653}
1654
1656{
1657 for (const auto &gd : partOfGroups())
1658 {
1659 if (gd->isLinkable()) return true;
1660 }
1661 return false;
1662}
1663
1665{
1666 return p->outerScope;
1667}
1668
1669static std::mutex g_memberReferenceMutex;
1670
1672{
1673 std::lock_guard<std::mutex> lock(g_memberReferenceMutex);
1674 if (p->referencesMembers.empty() && !p->sourceRefsDict.empty())
1675 {
1676 p->referencesMembers = refMapToVector(p->sourceRefsDict);
1677 }
1678 return p->referencesMembers;
1679}
1680
1682{
1683 std::lock_guard<std::mutex> lock(g_memberReferenceMutex);
1684 if (p->referencedByMembers.empty() && !p->sourceRefByDict.empty())
1685 {
1686 p->referencedByMembers = refMapToVector(p->sourceRefByDict);
1687 }
1688 return p->referencedByMembers;
1689}
1690
1692{
1693 const DefinitionImpl *defImpl = other->toDefinitionImpl_();
1694 if (defImpl)
1695 {
1696 for (const auto &kv : defImpl->p->sourceRefsDict)
1697 {
1698 auto it = p->sourceRefsDict.find(kv.first);
1699 if (it != p->sourceRefsDict.end())
1700 {
1701 p->sourceRefsDict.insert(kv);
1702 }
1703 }
1704 }
1705}
1706
1708{
1709 const DefinitionImpl *defImpl = other->toDefinitionImpl_();
1710 if (defImpl)
1711 {
1712 for (const auto &kv : defImpl->p->sourceRefByDict)
1713 {
1714 auto it = p->sourceRefByDict.find(kv.first);
1715 if (it != p->sourceRefByDict.end())
1716 {
1717 p->sourceRefByDict.emplace(kv.first,kv.second);
1718 }
1719 }
1720 }
1721}
1722
1723
1725{
1726 p->ref=r;
1727}
1728
1730{
1731 return p->lang;
1732}
1733
1735{
1736 p->hidden = p->hidden || b;
1737}
1738
1740{
1741 p->isArtificial = b;
1742}
1743
1745{
1746 p->isExported = b;
1747}
1748
1750{
1751 p->localName=name;
1752}
1753
1755{
1756 p->lang=lang;
1757}
1758
1759
1761{
1762 p->symbolName=name;
1763}
1764
1766{
1767 return p->symbolName;
1768}
1769
1771{
1772 bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC);
1773 return !briefDescription().isEmpty() && briefMemberDesc;
1774}
1775
1777{
1778 QCString ref = getReference();
1779 if (!ref.isEmpty())
1780 {
1781 auto it = Doxygen::tagDestinationMap.find(ref.str());
1783 {
1784 QCString result(it->second);
1785 size_t l = result.length();
1786 if (!relPath.isEmpty() && l>0 && result.at(0)=='.')
1787 { // relative path -> prepend relPath.
1788 result.prepend(relPath);
1789 l+=relPath.length();
1790 }
1791 if (l>0 && result.at(l-1)!='/') result+='/';
1792 return result;
1793 }
1794 }
1795 return relPath;
1796}
1797
1799{
1800 return p->name;
1801}
1802
1804{
1805 return p->isAnonymous;
1806}
1807
1809{
1810 return p->defLine;
1811}
1812
1814{
1815 return p->defColumn;
1816}
1817
1821
1825
1826//---------------------------------------------------------------------------------
1827
1829 : m_def(def), m_scope(scope), m_symbolName(alias->_symbolName())
1830{
1831}
1832
1836
1838{
1839 //printf("%s::addToMap(%s)\n",qPrint(name()),qPrint(alias->name()));
1841 if (m_scope==nullptr)
1842 {
1843 m_qualifiedName = m_def->localName();
1844 }
1845 else
1846 {
1847 m_qualifiedName = m_scope->qualifiedName()+
1848 getLanguageSpecificSeparator(m_scope->getLanguage())+
1849 m_def->localName();
1850 }
1851}
1852
1857
1862
1864{
1865 return m_qualifiedName;
1866}
1867
1868//---------------------------------------------------------------------------------
1869
1871{
1872 if (dm==nullptr) return nullptr;
1873 return dm->toDefinition_();
1874}
1875
1877{
1878 if (d==nullptr) return nullptr;
1879 return d->toDefinitionMutable_();
1880}
1881
static AnchorGenerator & instance()
Returns the singleton instance.
Definition anchor.cpp:38
virtual QCString className() const =0
Returns the name of the class including outer classes, but not including namespaces.
@ 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
std::string extension(bool complete) const
Definition fileinfo.cpp:130
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
ClassDef * toClassDef(Definition *d)
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:1926
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
Definition types.h:207
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:5714
QCString convertToHtml(const QCString &s, bool keepEntities)
Definition util.cpp:4472
QCString parseCommentAsText(const Definition *scope, const MemberDef *md, const QCString &doc, const QCString &fileName, int lineNr)
Definition util.cpp:5872
bool transcodeCharacterStringToUTF8(std::string &input, const char *inputEncoding)
Definition util.cpp:1403
bool found
Definition util.cpp:984
QCString stripScope(const QCString &name)
Definition util.cpp:4288
int computeQualifiedIndex(const QCString &name)
Return the index of the last :: in the string name that is still before the first <.
Definition util.cpp:7294
QCString convertToXML(const QCString &s, bool keepEntities)
Definition util.cpp:4421
QCString getLanguageSpecificSeparator(SrcLangExt lang, bool classScope)
Returns the scope separator to use given the programming language lang.
Definition util.cpp:6369
QCString getEncoding(const FileInfo &fi)
Definition util.cpp:6167
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5533
QCString getFileFilter(const QCString &name, bool isSourceCode)
Definition util.cpp:1369
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:5408
A bunch of utility functions.
bool isId(int c)
Definition util.h:208