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 (!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
526
527//---------------------------------------
528
529/*! Cache for storing the result of filtering a file */
531{
532 private:
534 {
535 size_t filePos;
536 size_t fileSize;
537 };
538 using LineOffsets = std::vector<size_t>;
539
540 public:
541 static FilterCache &instance();
542
543 //! collects the part of file \a fileName starting at \a startLine and ending at \a endLine into
544 //! buffer \a str. Applies filtering if FILTER_SOURCE_FILES is enabled and the file extension
545 //! matches a filter. Caches file information so that subsequent extraction of blocks from
546 //! the same file can be performed efficiently
547 bool getFileContents(const QCString &fileName,size_t startLine,size_t endLine, std::string &str)
548 {
549 bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
550 QCString filter = getFileFilter(fileName,TRUE);
551 bool usePipe = !filter.isEmpty() && filterSourceFiles;
552 return usePipe ? getFileContentsPipe(fileName,filter,startLine,endLine,str)
553 : getFileContentsDisk(fileName,startLine,endLine,str);
554 }
555 private:
556 bool getFileContentsPipe(const QCString &fileName,const QCString &filter,
557 size_t startLine,size_t endLine,std::string &str)
558 {
559 std::unique_lock<std::mutex> lock(m_mutex);
560 auto it = m_cache.find(fileName.str());
561 if (it!=m_cache.end()) // cache hit: reuse stored result
562 {
563 lock.unlock();
564 auto item = it->second;
565 //printf("getFileContents(%s): cache hit\n",qPrint(fileName));
566 // file already processed, get the results after filtering from the tmp file
567 Debug::print(Debug::FilterOutput,0,"Reusing filter result for %s from %s at offset=%lld size=%zu\n",
568 qPrint(fileName),qPrint(Doxygen::filterDBFileName),item.filePos,item.fileSize);
569
570 auto it_off = m_lineOffsets.find(fileName.str());
571 assert(it_off!=m_lineOffsets.end());
572 auto [ startLineOffset, fragmentSize] = getFragmentLocation(it_off->second,startLine,endLine);
573 //printf("%s: existing file [%zu-%zu]->[%zu-%zu] size=%zu\n",
574 // qPrint(fileName),startLine,endLine,startLineOffset,endLineOffset,fragmentSize);
576 item.filePos+startLineOffset, fragmentSize);
577 return true;
578 }
579 else // cache miss: filter active but file not previously processed
580 {
581 //printf("getFileContents(%s): cache miss\n",qPrint(fileName));
582 // filter file
583 QCString cmd=filter+" \""+fileName+"\"";
584 Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",qPrint(cmd));
585 FILE *f = Portable::popen(cmd,"r");
586 if (f==nullptr)
587 {
588 // handle error
589 err("Error opening filter pipe command '%s'\n",qPrint(cmd));
590 return false;
591 }
593 FilterCacheItem item;
594 item.filePos = m_endPos;
595 if (bf==nullptr)
596 {
597 // handle error
598 err("Error opening filter database file %s\n",qPrint(Doxygen::filterDBFileName));
600 return false;
601 }
602 // append the filtered output to the database file
603 size_t size=0;
604 while (!feof(f))
605 {
606 const int blockSize = 4096;
607 char buf[blockSize];
608 size_t bytesRead = fread(buf,1,blockSize,f);
609 size_t bytesWritten = fwrite(buf,1,bytesRead,bf);
610 if (bytesRead!=bytesWritten)
611 {
612 // handle error
613 err("Failed to write to filter database %s. Wrote %zu out of %zu bytes\n",
614 qPrint(Doxygen::filterDBFileName),bytesWritten,bytesRead);
616 fclose(bf);
617 return false;
618 }
619 size+=bytesWritten;
620 str+=std::string_view(buf,bytesWritten);
621 }
622 item.fileSize = size;
623 // add location entry to the dictionary
624 m_cache.emplace(fileName.str(),item);
625 Debug::print(Debug::FilterOutput,0,"Storing new filter result for %s in %s at offset=%lld size=%zu\n",
627 // update end of file position
628 m_endPos += size;
630 fclose(bf);
631
632 // shrink buffer to [startLine..endLine] part
633 shrinkBuffer(str,fileName,startLine,endLine);
634 }
635 return true;
636 }
637
638 //! reads the fragment start at \a startLine and ending at \a endLine from file \a fileName
639 //! into buffer \a str
640 bool getFileContentsDisk(const QCString &fileName,size_t startLine,size_t endLine,std::string &str)
641 {
642 std::unique_lock<std::mutex> lock(m_mutex);
643 // normal file
644 //printf("getFileContents(%s): no filter\n",qPrint(fileName));
645 auto it = m_lineOffsets.find(fileName.str());
646 if (it == m_lineOffsets.end()) // new file
647 {
648 // read file completely into str buffer
649 readFragmentFromFile(str,fileName,0);
650 // shrink buffer to [startLine..endLine] part
651 shrinkBuffer(str,fileName,startLine,endLine);
652 }
653 else // file already processed before
654 {
655 lock.unlock();
656 auto [ startLineOffset, fragmentSize] = getFragmentLocation(it->second,startLine,endLine);
657 //printf("%s: existing file [%zu-%zu] -> start=%zu size=%zu\n",
658 // qPrint(fileName),startLine,endLine,startLineOffset,fragmentSize);
659 readFragmentFromFile(str,fileName,startLineOffset,fragmentSize);
660 }
661 return true;
662 }
663
664 //! computes the starting offset for each line for file \a fileName, whose contents should
665 //! already be stored in buffer \a str.
666 void compileLineOffsets(const QCString &fileName,const std::string &str)
667 {
668 // line 1 (index 0) is at offset 0
669 auto it = m_lineOffsets.emplace(fileName.data(),LineOffsets{0}).first;
670 const char *p=str.data();
671 while (*p)
672 {
673 char c=0;
674 while ((c=*p)!='\n' && c!=0) p++; // search until end of the line
675 if (c!=0) p++;
676 it->second.push_back(p-str.data());
677 }
678 }
679
680 //! Returns the byte offset and size within a file of a fragment given the array of
681 //! line offsets and the start and end line of the fragment.
682 auto getFragmentLocation(const LineOffsets &lineOffsets,
683 size_t startLine,size_t endLine) -> std::tuple<size_t,size_t>
684 {
685 assert(startLine > 0);
686 assert(startLine <= endLine);
687 const size_t startLineOffset = lineOffsets[std::min(startLine-1,lineOffsets.size()-1)];
688 const size_t endLineOffset = lineOffsets[std::min(endLine, lineOffsets.size()-1)];
689 assert(startLineOffset <= endLineOffset);
690 const size_t fragmentSize = endLineOffset-startLineOffset;
691 return std::tie(startLineOffset,fragmentSize);
692 };
693
694 //! Shrinks buffer \a str which should hold the contents of \a fileName to the
695 //! fragment starting a line \a startLine and ending at line \a endLine
696 void shrinkBuffer(std::string &str,const QCString &fileName,size_t startLine,size_t endLine)
697 {
698 // compute offsets from start for each line
699 compileLineOffsets(fileName,str);
700 auto it = m_lineOffsets.find(fileName.str());
701 assert(it!=m_lineOffsets.end());
702 const LineOffsets &lineOffsets = it->second;
703 auto [ startLineOffset, fragmentSize] = getFragmentLocation(lineOffsets,startLine,endLine);
704 //printf("%s: new file [%zu-%zu]->[%zu-%zu] size=%zu\n",
705 // qPrint(fileName),startLine,endLine,startLineOffset,endLineOffset,fragmentSize);
706 str.erase(0,startLineOffset);
707 str.resize(fragmentSize);
708 }
709
710 //! Reads the fragment start at byte offset \a startOffset of file \a fileName into buffer \a str.
711 //! Result will be a null terminated. If size==0 the whole file will be read and startOffset is ignored.
712 //! If size>0, size bytes will be read.
713 void readFragmentFromFile(std::string &str,const QCString &fileName,size_t startOffset,size_t size=0)
714 {
715 std::ifstream ifs = Portable::openInputStream(fileName,true,true);
716 if (size==0) { startOffset=0; size = static_cast<size_t>(ifs.tellg()); }
717 ifs.seekg(startOffset, std::ios::beg);
718 str.resize(size);
719 ifs.read(str.data(), size);
720 }
721
723 std::unordered_map<std::string,FilterCacheItem> m_cache;
724 std::unordered_map<std::string,LineOffsets> m_lineOffsets;
725 std::mutex m_mutex;
726 size_t m_endPos;
727};
728
730{
731 static FilterCache theInstance;
732 return theInstance;
733}
734
735//-----------------------------------------
736
737
738/*! Reads a fragment of code from file \a fileName starting at
739 * line \a startLine and ending at line \a endLine (inclusive). The fragment is
740 * stored in \a result. If FALSE is returned the code fragment could not be
741 * found.
742 *
743 * The file is scanned for a opening bracket ('{') from \a startLine onward
744 * The line actually containing the bracket is returned via startLine.
745 * The file is scanned for a closing bracket ('}') from \a endLine backward.
746 * The line actually containing the bracket is returned via endLine.
747 * Note that for VHDL code the bracket search is not done.
748 */
749bool readCodeFragment(const QCString &fileName,bool isMacro,
750 int &startLine,int &endLine,QCString &result)
751{
752 bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
753 QCString filter = getFileFilter(fileName,TRUE);
754 bool usePipe = !filter.isEmpty() && filterSourceFiles;
755 int tabSize = Config_getInt(TAB_SIZE);
756 SrcLangExt lang = getLanguageFromFileName(fileName);
757 const int blockSize = 4096;
758 std::string str;
760 static_cast<size_t>(std::max(1,startLine)),
761 static_cast<size_t>(std::max({1,startLine,endLine})),str);
762 //printf("readCodeFragment(%s,startLine=%d,endLine=%d)=\n[[[\n%s]]]\n",qPrint(fileName),startLine,endLine,qPrint(str));
763
764 bool found = lang==SrcLangExt::VHDL ||
765 lang==SrcLangExt::Python ||
766 lang==SrcLangExt::Fortran ||
767 isMacro;
768 // for VHDL, Python, and Fortran no bracket search is possible
769 char *p=str.data();
770 if (p && *p)
771 {
772 char c=0;
773 int col=0;
774 int lineNr=startLine;
775 // skip until the opening bracket or lonely : is found
776 char cn=0;
777 while (*p && !found)
778 {
779 int pc=0;
780 while ((c=*p++)!='{' && c!=':' && c!=0)
781 {
782 //printf("parsing char '%c'\n",c);
783 if (c=='\n')
784 {
785 lineNr++,col=0;
786 }
787 else if (c=='\t')
788 {
789 col+=tabSize - (col%tabSize);
790 }
791 else if (pc=='/' && c=='/') // skip single line comment
792 {
793 while ((c=*p++)!='\n' && c!=0);
794 if (c=='\n') lineNr++,col=0;
795 }
796 else if (pc=='/' && c=='*') // skip C style comment
797 {
798 while (((c=*p++)!='/' || pc!='*') && c!=0)
799 {
800 if (c=='\n') lineNr++,col=0;
801 pc=c;
802 }
803 }
804 else
805 {
806 col++;
807 }
808 pc = c;
809 }
810 if (c==':')
811 {
812 cn=*p++;
813 if (cn!=':') found=TRUE;
814 }
815 else if (c=='{')
816 {
817 found=TRUE;
818 }
819 else if (c==0)
820 {
821 break;
822 }
823 }
824 //printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr);
825 if (found)
826 {
827 // For code with more than one line,
828 // fill the line with spaces until we are at the right column
829 // so that the opening brace lines up with the closing brace
830 if (endLine!=startLine)
831 {
832 QCString spaces;
833 spaces.fill(' ',col);
834 result+=spaces;
835 }
836 // copy until end of line
837 if (c) result+=c;
838 startLine=lineNr;
839 if (c==':')
840 {
841 result+=cn;
842 if (cn=='\n') lineNr++;
843 }
844 char lineStr[blockSize];
845 do
846 {
847 //printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine);
848 int size_read=0;
849 do
850 {
851 // read up to blockSize-1 non-zero characters
852 int i=0;
853 while ((c=*p) && i<blockSize-1)
854 {
855 lineStr[i++]=c;
856 p++;
857 if (c=='\n') break; // stop at end of the line
858 }
859 lineStr[i]=0;
860 size_read=i;
861 result+=lineStr; // append line to the output
862 } while (size_read == (blockSize-1)); // append more if line does not fit in buffer
863 lineNr++;
864 } while (*p);
865
866 // strip stuff after closing bracket
867 int newLineIndex = result.findRev('\n');
868 int braceIndex = result.findRev('}');
869 if (braceIndex > newLineIndex)
870 {
871 result.resize(static_cast<size_t>(braceIndex+1));
872 }
873 endLine=lineNr-1;
874 }
875 if (usePipe)
876 {
877 Debug::print(Debug::FilterOutput, 0, "Filter output\n");
878 Debug::print(Debug::FilterOutput,0,"-------------\n%s\n-------------\n",qPrint(result));
879 }
880 }
881 QCString encoding = getEncoding(FileInfo(fileName.str()));
882 if (encoding!="UTF-8")
883 {
884 std::string encBuf = result.str();
885 bool ok = transcodeCharacterStringToUTF8(encBuf,encoding.data());
886 if (ok)
887 {
888 result = QCString(encBuf);
889 }
890 else
891 {
892 err("failed to transcode characters in code fragment in file %s lines %d to %d, from input encoding %s to UTF-8\n",
893 qPrint(fileName),startLine,endLine,qPrint(encoding));
894
895 }
896 }
897 if (!result.isEmpty() && result.at(result.length()-1)!='\n') result += "\n";
898 //printf("readCodeFragment(%d-%d)=%s\n",startLine,endLine,qPrint(result));
899 return found;
900}
901
903{
904 ASSERT(p->def->definitionType()!=Definition::TypeFile); // file overloads this method
905 QCString fn;
906 bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
907 if (sourceBrowser &&
908 p->body && p->body->startLine!=-1 && p->body->fileDef)
909 {
910 fn = p->body->fileDef->getSourceFileBase();
911 }
912 return fn;
913}
914
916{
917 const int maxAnchorStrLen = 20;
918 char anchorStr[maxAnchorStrLen];
919 anchorStr[0]='\0';
920 if (p->body && p->body->startLine!=-1)
921 {
922 if (Htags::useHtags)
923 {
924 qsnprintf(anchorStr,maxAnchorStrLen,"L%d",p->body->defLine);
925 }
926 else
927 {
928 qsnprintf(anchorStr,maxAnchorStrLen,"l%05d",p->body->defLine);
929 }
930 }
931 return anchorStr;
932}
933
934/*! Write a reference to the source code defining this definition */
936{
937 //printf("DefinitionImpl::writeSourceRef %d %p\n",bodyLine,bodyDef);
939 if (!fn.isEmpty())
940 {
941 QCString refText = theTranslator->trDefinedAtLineInSourceFile();
942 int lineMarkerPos = refText.find("@0");
943 int fileMarkerPos = refText.find("@1");
944 if (lineMarkerPos!=-1 && fileMarkerPos!=-1) // should always pass this.
945 {
946 QCString lineStr;
947 lineStr.sprintf("%d",p->body->defLine);
948 QCString anchorStr = getSourceAnchor();
949 ol.startParagraph("definition");
950 if (lineMarkerPos<fileMarkerPos) // line marker before file marker
951 {
952 // write text left from linePos marker
953 ol.parseText(refText.left(lineMarkerPos));
954 ol.writeObjectLink(QCString(),fn,anchorStr,lineStr);
955 // write text between markers
956 ol.parseText(refText.mid(lineMarkerPos+2,fileMarkerPos-lineMarkerPos-2));
957 // write file link
958 ol.writeObjectLink(QCString(),fn,QCString(),p->body->fileDef->name());
959 // write text right from file marker
960 ol.parseText(refText.right(refText.length()-static_cast<size_t>(fileMarkerPos)-2));
961 }
962 else // file marker before line marker
963 {
964 // write text left from file marker
965 ol.parseText(refText.left(fileMarkerPos));
966 // write file link
967 ol.writeObjectLink(QCString(),fn,QCString(),p->body->fileDef->name());
968 // write text between markers
969 ol.parseText(refText.mid(fileMarkerPos+2,lineMarkerPos-fileMarkerPos-2));
970 // write line link
971 ol.writeObjectLink(QCString(),fn,anchorStr,lineStr);
972 // write text right from linePos marker
973 ol.parseText(refText.right(refText.length()-static_cast<size_t>(lineMarkerPos)-2));
974 }
975 ol.endParagraph();
976 }
977 else
978 {
979 err("translation error: invalid markers in trDefinedAtLineInSourceFile()\n");
980 }
981 }
982}
983
984void DefinitionImpl::setBodySegment(int defLine, int bls,int ble)
985{
986 if (!p->body.has_value())
987 {
988 p->body = std::make_optional<BodyInfo>();
989 }
990 BodyInfo &body = p->body.value();
991 body.defLine = defLine;
992 body.startLine = bls;
993 body.endLine = ble;
994}
995
997{
998 if (!p->body.has_value())
999 {
1000 p->body = std::make_optional<BodyInfo>();
1001 }
1002 p->body.value().fileDef=fd;
1003}
1004
1006{
1007 return p->body && p->body->startLine!=-1 &&
1008 p->body->endLine>=p->body->startLine &&
1009 p->body->fileDef;
1010}
1011
1012/*! Write code of this definition into the documentation */
1014{
1015 const MemberDef *thisMd = nullptr;
1016 if (p->def->definitionType()==Definition::TypeMember)
1017 {
1018 thisMd = toMemberDef(p->def);
1019 }
1020 bool inlineSources = thisMd && thisMd->hasInlineSource();
1021 //printf("Source Fragment %s: %d-%d\n",qPrint(name()),
1022 // p->body->startLine,p->body->endLine);
1023 if (inlineSources && hasSources())
1024 {
1025 ol.pushGeneratorState();
1026 QCString codeFragment;
1027 bool isMacro = thisMd && thisMd->memberType()==MemberType::Define;
1028 int actualStart=p->body->startLine,actualEnd=p->body->endLine;
1029 if (readCodeFragment(p->body->fileDef->absFilePath(),isMacro,
1030 actualStart,actualEnd,codeFragment)
1031 )
1032 {
1033 //printf("Adding code fragment '%s' ext='%s' range=%d-%d\n",
1034 // qPrint(codeFragment),qPrint(p->defFileExt),actualStart,actualEnd);
1035 auto intf = Doxygen::parserManager->getCodeParser(p->defFileExt);
1036 intf->resetCodeParserState();
1037 //printf("Read:\n'%s'\n\n",qPrint(codeFragment));
1038
1039 auto &codeOL = ol.codeGenerators();
1040 codeOL.startCodeFragment("DoxyCode");
1041 intf->parseCode(codeOL, // codeOutIntf
1042 scopeName, // scope
1043 codeFragment, // input
1044 p->lang, // lang
1045 Config_getBool(STRIP_CODE_COMMENTS),
1046 FALSE, // isExample
1047 QCString(), // exampleName
1048 p->body->fileDef, // fileDef
1049 actualStart, // startLine
1050 actualEnd, // endLine
1051 TRUE, // inlineFragment
1052 thisMd, // memberDef
1053 TRUE // show line numbers
1054 );
1055 codeOL.endCodeFragment("DoxyCode");
1056 }
1057 ol.popGeneratorState();
1058 }
1059}
1060
1061static inline MemberVector refMapToVector(const std::unordered_map<std::string,MemberDef *> &map)
1062{
1063 // convert map to a vector of values
1064 MemberVector result;
1065 std::transform(map.begin(),map.end(), // iterate over map
1066 std::back_inserter(result), // add results to vector
1067 [](const auto &item)
1068 { return item.second; } // extract value to add from map Key,Value pair
1069 );
1070 // and sort it
1071 std::stable_sort(result.begin(),result.end(),
1072 [](const auto &m1,const auto &m2) { return genericCompareMembers(m1,m2)<0; });
1073 return result;
1074}
1075
1076/*! Write a reference to the source code fragments in which this
1077 * definition is used.
1078 */
1080 const QCString &text,const std::unordered_map<std::string,MemberDef *> &membersMap,
1081 bool /*funcOnly*/) const
1082{
1083 if (!membersMap.empty())
1084 {
1085 auto members = refMapToVector(membersMap);
1086
1087 auto replaceFunc = [this,&members,scopeName,&ol](size_t entryIndex)
1088 {
1089 bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1090 bool refLinkSource = Config_getBool(REFERENCES_LINK_SOURCE);
1091 const MemberDef *md=members[entryIndex];
1092 if (md)
1093 {
1094 QCString scope=md->getScopeString();
1095 QCString name=md->name();
1096 //printf("class=%p scope=%s scopeName=%s\n",md->getClassDef(),qPrint(scope),scopeName);
1097 if (!scope.isEmpty() && scope!=scopeName)
1098 {
1099 name.prepend(scope+getLanguageSpecificSeparator(p->lang));
1100 }
1101 if (!md->isObjCMethod() &&
1102 (md->isFunction() || md->isSlot() ||
1103 md->isPrototype() || md->isSignal()
1104 )
1105 )
1106 {
1107 name+="()";
1108 }
1109 if (sourceBrowser &&
1110 !(md->isLinkable() && !refLinkSource) &&
1111 md->getStartBodyLine()!=-1 &&
1112 md->getBodyDef()
1113 )
1114 {
1115 const int maxLineNrStr = 10;
1116 char anchorStr[maxLineNrStr];
1117 qsnprintf(anchorStr,maxLineNrStr,"l%05d",md->getStartBodyLine());
1118 //printf("Write object link to %s\n",qPrint(md->getBodyDef()->getSourceFileBase()));
1119 ol.writeObjectLink(QCString(),md->getBodyDef()->getSourceFileBase(),anchorStr,name);
1120 }
1121 else if (md->isLinkable())
1122 {
1124 md->getOutputFileBase(),
1125 md->anchor(),name);
1126 }
1127 else
1128 {
1129 ol.docify(name);
1130 }
1131 }
1132 };
1133
1134 ol.startParagraph("reference");
1135 ol.parseText(text);
1136 ol.docify(" ");
1137 writeMarkerList(ol,
1138 theTranslator->trWriteList(static_cast<int>(members.size())).str(),
1139 members.size(),
1140 replaceFunc);
1141 ol.writeString(".");
1142 ol.endParagraph();
1143
1144 }
1145}
1146
1148{
1149 _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),p->sourceRefByDict,FALSE);
1150}
1151
1153{
1154 _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),p->sourceRefsDict,TRUE);
1155}
1156
1158{
1159 return !p->sourceRefByDict.empty();
1160}
1161
1163{
1164 return !p->sourceRefsDict.empty();
1165}
1166
1168{
1169 bool extractAll = Config_getBool(EXTRACT_ALL);
1170 //bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1171 bool hasDocs =
1172 (p->details && !p->details->doc.isEmpty()) || // has detailed docs
1173 (p->brief && !p->brief->doc.isEmpty()) || // has brief description
1174 (p->inbodyDocs && !p->inbodyDocs->doc.isEmpty()) || // has inbody docs
1175 extractAll //|| // extract everything
1176 // (sourceBrowser && p->body &&
1177 // p->body->startLine!=-1 && p->body->fileDef)
1178 ; // link to definition
1179 return hasDocs;
1180}
1181
1183{
1184 bool hasDocs =
1185 (p->details && !p->details->doc.isEmpty()) ||
1186 (p->brief && !p->brief->doc.isEmpty()) ||
1187 (p->inbodyDocs && !p->inbodyDocs->doc.isEmpty());
1188 return hasDocs;
1189}
1190
1192{
1193 if (md)
1194 {
1195 p->sourceRefByDict.emplace(sourceRefName.str(),md);
1196 }
1197}
1198
1200{
1201 if (md)
1202 {
1203 p->sourceRefsDict.emplace(sourceRefName.str(),md);
1204 }
1205}
1206
1208{
1209 return nullptr;
1210}
1211
1213{
1214 err("DefinitionImpl::addInnerCompound() called\n");
1215}
1216
1217static std::recursive_mutex g_qualifiedNameMutex;
1218
1220{
1221 std::lock_guard<std::recursive_mutex> lock(g_qualifiedNameMutex);
1222 if (!p->qualifiedName.isEmpty())
1223 {
1224 return p->qualifiedName;
1225 }
1226
1227 //printf("start %s::qualifiedName() localName=%s\n",qPrint(name()),qPrint(p->localName));
1228 if (p->outerScope==nullptr)
1229 {
1230 if (p->localName=="<globalScope>")
1231 {
1232 return "";
1233 }
1234 else
1235 {
1236 return p->localName;
1237 }
1238 }
1239
1240 if (p->outerScope->name()=="<globalScope>")
1241 {
1242 p->qualifiedName = p->localName;
1243 }
1244 else
1245 {
1246 p->qualifiedName = p->outerScope->qualifiedName()+
1248 p->localName;
1249 }
1250 //printf("end %s::qualifiedName()=%s\n",qPrint(name()),qPrint(p->qualifiedName));
1251 //count--;
1252 return p->qualifiedName;
1253}
1254
1256{
1257 std::lock_guard<std::recursive_mutex> lock(g_qualifiedNameMutex);
1258 //printf("%s::setOuterScope(%s)\n",qPrint(name()),d?qPrint(d->name()):"<none>");
1259 Definition *outerScope = p->outerScope;
1260 bool found=false;
1261 // make sure that we are not creating a recursive scope relation.
1262 while (outerScope && !found)
1263 {
1264 found = (outerScope==d);
1265 outerScope = outerScope->getOuterScope();
1266 }
1267 if (!found)
1268 {
1269 p->qualifiedName.clear(); // flush cached scope name
1270 p->outerScope = d;
1271 }
1272 p->hidden = p->hidden || d->isHidden();
1273 assert(p->def!=p->outerScope);
1274}
1275
1277{
1278 return p->localName;
1279}
1280
1282{
1283 p->partOfGroups.push_back(gd);
1284}
1285
1287{
1288 p->xrefListItems.insert(p->xrefListItems.end(), sli.cbegin(), sli.cend());
1289}
1290
1292{
1293 auto otherXrefList = d->xrefListItems();
1294
1295 // append vectors
1296 p->xrefListItems.reserve(p->xrefListItems.size()+otherXrefList.size());
1297 p->xrefListItems.insert (p->xrefListItems.end(),
1298 otherXrefList.begin(),otherXrefList.end());
1299
1300 // sort results on itemId
1301 std::stable_sort(p->xrefListItems.begin(),p->xrefListItems.end(),
1302 [](RefItem *left,RefItem *right)
1303 { return left->id() <right->id() ||
1304 (left->id()==right->id() &&
1305 left->list()->listName() < right->list()->listName());
1306 });
1307
1308 // filter out duplicates
1309 auto last = std::unique(p->xrefListItems.begin(),p->xrefListItems.end(),
1310 [](const RefItem *left,const RefItem *right)
1311 { return left->id()==right->id() &&
1312 left->list()->listName()==right->list()->listName();
1313 });
1314 p->xrefListItems.erase(last, p->xrefListItems.end());
1315}
1316
1318{
1319 for (const RefItem *item : p->xrefListItems)
1320 {
1321 if (item->list()->listName()==listName)
1322 {
1323 return item->id();
1324 }
1325 }
1326 return -1;
1327}
1328
1330{
1331 return p->xrefListItems;
1332}
1333
1335{
1336 QCString result;
1337 if (p->outerScope && p->outerScope!=Doxygen::globalScope)
1338 {
1339 result = p->outerScope->pathFragment();
1340 }
1341 if (p->def->isLinkable())
1342 {
1343 if (!result.isEmpty()) result+="/";
1344 if (p->def->definitionType()==Definition::TypeGroup &&
1345 !toGroupDef(p->def)->groupTitle().isEmpty())
1346 {
1347 result+=toGroupDef(p->def)->groupTitle();
1348 }
1349 else if (p->def->definitionType()==Definition::TypePage &&
1350 toPageDef(p->def)->hasTitle())
1351 {
1352 result+=toPageDef(p->def)->title();
1353 }
1354 else
1355 {
1356 result+=p->localName;
1357 }
1358 }
1359 else
1360 {
1361 result+=p->localName;
1362 }
1363 return result;
1364}
1365
1366//----------------------------------------------------------------------------------------
1367
1368// TODO: move to htmlgen
1369/*! Returns the string used in the footer for $navpath when
1370 * GENERATE_TREEVIEW is enabled
1371 */
1373{
1374 QCString result;
1375 Definition *outerScope = getOuterScope();
1376 QCString locName = localName();
1377 if (outerScope && outerScope!=Doxygen::globalScope)
1378 {
1379 result+=outerScope->navigationPathAsString();
1380 }
1381 else if (p->def->definitionType()==Definition::TypeFile &&
1382 toFileDef(p->def)->getDirDef())
1383 {
1384 result+=(toFileDef(p->def))->getDirDef()->navigationPathAsString();
1385 }
1386 result+="<li class=\"navelem\">";
1387 if (p->def->isLinkableInProject())
1388 {
1389 QCString fn = p->def->getOutputFileBase();
1391 if (p->def->definitionType()==Definition::TypeGroup &&
1392 !toGroupDef(p->def)->groupTitle().isEmpty())
1393 {
1394 result+="<a class=\"el\" href=\"$relpath^"+fn+"\">"+
1395 convertToHtml(toGroupDef(p->def)->groupTitle())+"</a>";
1396 }
1397 else if (p->def->definitionType()==Definition::TypePage &&
1398 toPageDef(p->def)->hasTitle())
1399 {
1400 result+="<a class=\"el\" href=\"$relpath^"+fn+"\">"+
1401 convertToHtml((toPageDef(p->def))->title())+"</a>";
1402 }
1403 else if (p->def->definitionType()==Definition::TypeClass)
1404 {
1405 QCString name = locName;
1406 if (name.endsWith("-p"))
1407 {
1408 name = name.left(name.length()-2);
1409 }
1410 result+="<a class=\"el\" href=\"$relpath^"+fn;
1411 if (!p->def->anchor().isEmpty()) result+="#"+p->def->anchor();
1412 result+="\">"+convertToHtml(name)+"</a>";
1413 }
1414 else
1415 {
1416 result+="<a class=\"el\" href=\"$relpath^"+fn+"\">"+
1417 convertToHtml(locName)+"</a>";
1418 }
1419 }
1420 else
1421 {
1422 result+="<b>"+convertToHtml(locName)+"</b>";
1423 }
1424 result+="</li>";
1425 return result;
1426}
1427
1428// TODO: move to htmlgen
1430{
1431 ol.pushGeneratorState();
1433
1434 QCString navPath;
1435 navPath += "<div id=\"nav-path\" class=\"navpath\">\n"
1436 " <ul>\n";
1437 navPath += navigationPathAsString();
1438 navPath += " </ul>\n"
1439 "</div>\n";
1440 ol.writeNavigationPath(navPath);
1441
1442 ol.popGeneratorState();
1443}
1444
1445void DefinitionImpl::writeToc(OutputList &ol, const LocalToc &localToc) const
1446{
1447 if (p->sectionRefs.empty()) return;
1448 ol.writeLocalToc(p->sectionRefs,localToc);
1449}
1450
1451//----------------------------------------------------------------------------------------
1452
1454{
1455 return p->sectionRefs;
1456}
1457
1459{
1460 return p->symbolName;
1461}
1462
1463//----------------------
1464
1466{
1467 return p->details ? p->details->doc : QCString("");
1468}
1469
1471{
1472 return p->details ? p->details->line : p->brief ? p->brief->line : 1;
1473}
1474
1476{
1477 if (p->details && !p->details->file.isEmpty()) return p->details->file;
1478 else if (p->brief && !p->brief->file.isEmpty()) return p->brief->file;
1479 else return "<" + p->name + ">";
1480}
1481
1482//----------------------------------------------------------------------------
1483// strips w from s iff s starts with w
1484static bool stripWord(QCString &s,QCString w)
1485{
1486 bool success=FALSE;
1487 if (s.left(w.length())==w)
1488 {
1489 success=TRUE;
1490 s=s.right(s.length()-w.length());
1491 }
1492 return success;
1493}
1494
1495//----------------------------------------------------------------------------
1496// some quasi intelligent brief description abbreviator :^)
1497static QCString abbreviate(const QCString &s,const QCString &name)
1498{
1499 QCString scopelessName=name;
1500 int i=scopelessName.findRev("::");
1501 if (i!=-1) scopelessName=scopelessName.mid(i+2);
1502 QCString result=s;
1503 result=result.stripWhiteSpace();
1504 // strip trailing .
1505 if (!result.isEmpty() && result.at(result.length()-1)=='.')
1506 result=result.left(result.length()-1);
1507
1508 // strip any predefined prefix
1509 const StringVector &briefDescAbbrev = Config_getList(ABBREVIATE_BRIEF);
1510 for (const auto &p : briefDescAbbrev)
1511 {
1512 QCString str = substitute(p.c_str(),"$name",scopelessName); // replace $name with entity name
1513 str += " ";
1514 stripWord(result,str);
1515 }
1516
1517 // capitalize first word
1518 if (!result.isEmpty())
1519 {
1520 char c=result[0];
1521 if (c>='a' && c<='z') c+='A'-'a';
1522 result[0]=c;
1523 }
1524 return result;
1525}
1526
1527
1528//----------------------
1529
1531{
1532 //printf("%s::briefDescription(%d)='%s'\n",qPrint(name()),abbr,p->brief?qPrint(p->brief->doc):"<none>");
1533 return p->brief ?
1534 (abbr ? abbreviate(p->brief->doc,p->def->displayName()) : p->brief->doc) :
1535 QCString("");
1536}
1537
1539{
1540 if (p->brief && p->brief->tooltip.isEmpty() && !p->brief->doc.isEmpty())
1541 {
1542 const MemberDef *md = p->def->definitionType()==Definition::TypeMember ? toMemberDef(p->def) : nullptr;
1543 const Definition *scope = p->def->definitionType()==Definition::TypeMember ? p->def->getOuterScope() : p->def;
1544 p->brief->tooltip = parseCommentAsText(scope,md,
1545 p->brief->doc, p->brief->file, p->brief->line);
1546 }
1547}
1548
1550{
1551 return p->brief ? p->brief->tooltip : QCString();
1552}
1553
1555{
1556 return p->brief ? p->brief->line : 1;
1557}
1558
1560{
1561 return p->brief && !p->brief->file.isEmpty() ? p->brief->file : QCString("<"+p->name+">");
1562}
1563
1564//----------------------
1565
1567{
1568 return p->inbodyDocs ? p->inbodyDocs->doc : QCString("");
1569}
1570
1572{
1573 return p->inbodyDocs ? p->inbodyDocs->line : 1;
1574}
1575
1577{
1578 return p->inbodyDocs && !p->inbodyDocs->file.isEmpty() ? p->inbodyDocs->file : QCString("<"+p->name+">");
1579}
1580
1581
1582//----------------------
1583
1585{
1586 return p->defFileName;
1587}
1588
1590{
1591 return p->defFileExt;
1592}
1593
1595{
1596 return p->hidden;
1597}
1598
1600{
1601 return p->def->isLinkableInProject() && !p->hidden;
1602}
1603
1605{
1606 return p->def->isLinkable() && !p->hidden;
1607}
1608
1610{
1611 return p->isArtificial;
1612}
1613
1615{
1616 return p->isExported;
1617}
1618
1620{
1621 return p->ref;
1622}
1623
1625{
1626 return !p->ref.isEmpty();
1627}
1628
1630{
1631 return p->body ? p->body->defLine : -1;
1632}
1633
1635{
1636 return p->body ? p->body->startLine : -1;
1637}
1638
1640{
1641 return p->body ? p->body->endLine : -1;
1642}
1643
1645{
1646 return p->body ? p->body->fileDef : nullptr;
1647}
1648
1650{
1651 return p->partOfGroups;
1652}
1653
1655{
1656 for (const auto &gd : partOfGroups())
1657 {
1658 if (gd->isLinkable()) return true;
1659 }
1660 return false;
1661}
1662
1664{
1665 return p->outerScope;
1666}
1667
1668static std::mutex g_memberReferenceMutex;
1669
1671{
1672 std::lock_guard<std::mutex> lock(g_memberReferenceMutex);
1673 if (p->referencesMembers.empty() && !p->sourceRefsDict.empty())
1674 {
1675 p->referencesMembers = refMapToVector(p->sourceRefsDict);
1676 }
1677 return p->referencesMembers;
1678}
1679
1681{
1682 std::lock_guard<std::mutex> lock(g_memberReferenceMutex);
1683 if (p->referencedByMembers.empty() && !p->sourceRefByDict.empty())
1684 {
1685 p->referencedByMembers = refMapToVector(p->sourceRefByDict);
1686 }
1687 return p->referencedByMembers;
1688}
1689
1691{
1692 const DefinitionImpl *defImpl = other->toDefinitionImpl_();
1693 if (defImpl)
1694 {
1695 for (const auto &kv : defImpl->p->sourceRefsDict)
1696 {
1697 auto it = p->sourceRefsDict.find(kv.first);
1698 if (it != p->sourceRefsDict.end())
1699 {
1700 p->sourceRefsDict.insert(kv);
1701 }
1702 }
1703 }
1704}
1705
1707{
1708 const DefinitionImpl *defImpl = other->toDefinitionImpl_();
1709 if (defImpl)
1710 {
1711 for (const auto &kv : defImpl->p->sourceRefByDict)
1712 {
1713 auto it = p->sourceRefByDict.find(kv.first);
1714 if (it != p->sourceRefByDict.end())
1715 {
1716 p->sourceRefByDict.emplace(kv.first,kv.second);
1717 }
1718 }
1719 }
1720}
1721
1722
1724{
1725 p->ref=r;
1726}
1727
1729{
1730 return p->lang;
1731}
1732
1734{
1735 p->hidden = p->hidden || b;
1736}
1737
1739{
1740 p->isArtificial = b;
1741}
1742
1744{
1745 p->isExported = b;
1746}
1747
1749{
1750 p->localName=name;
1751}
1752
1754{
1755 p->lang=lang;
1756}
1757
1758
1760{
1761 p->symbolName=name;
1762}
1763
1765{
1766 return p->symbolName;
1767}
1768
1770{
1771 bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC);
1772 return !briefDescription().isEmpty() && briefMemberDesc;
1773}
1774
1776{
1777 QCString ref = getReference();
1778 if (!ref.isEmpty())
1779 {
1780 auto it = Doxygen::tagDestinationMap.find(ref.str());
1782 {
1783 QCString result(it->second);
1784 size_t l = result.length();
1785 if (!relPath.isEmpty() && l>0 && result.at(0)=='.')
1786 { // relative path -> prepend relPath.
1787 result.prepend(relPath);
1788 l+=relPath.length();
1789 }
1790 if (l>0 && result.at(l-1)!='/') result+='/';
1791 return result;
1792 }
1793 }
1794 return relPath;
1795}
1796
1798{
1799 return p->name;
1800}
1801
1803{
1804 return p->isAnonymous;
1805}
1806
1808{
1809 return p->defLine;
1810}
1811
1813{
1814 return p->defColumn;
1815}
1816
1820
1824
1825//---------------------------------------------------------------------------------
1826
1828 : m_def(def), m_scope(scope), m_symbolName(alias->_symbolName())
1829{
1830}
1831
1835
1837{
1838 //printf("%s::addToMap(%s)\n",qPrint(name()),qPrint(alias->name()));
1840 if (m_scope==nullptr)
1841 {
1842 m_qualifiedName = m_def->localName();
1843 }
1844 else
1845 {
1846 m_qualifiedName = m_scope->qualifiedName()+
1847 getLanguageSpecificSeparator(m_scope->getLanguage())+
1848 m_def->localName();
1849 }
1850}
1851
1856
1861
1863{
1864 return m_qualifiedName;
1865}
1866
1867//---------------------------------------------------------------------------------
1868
1870{
1871 if (dm==nullptr) return nullptr;
1872 return dm->toDefinition_();
1873}
1874
1876{
1877 if (d==nullptr) return nullptr;
1878 return d->toDefinitionMutable_();
1879}
1880
static AnchorGenerator & instance()
Returns the singleton instance.
Definition anchor.cpp:38
@ FilterOutput
Definition debug.h:37
@ ExtCmd
Definition debug.h:35
static void print(DebugMask mask, int prio, const char *fmt,...)
Definition debug.cpp:81
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)
Shrinks buffer str which should hold the contents of fileName to the fragment starting a line startLi...
std::vector< size_t > LineOffsets
auto getFragmentLocation(const LineOffsets &lineOffsets, size_t startLine, size_t endLine) -> std::tuple< size_t, size_t >
Returns the byte offset and size within a file of a fragment given the array of line offsets and the ...
std::unordered_map< std::string, LineOffsets > m_lineOffsets
bool getFileContentsDisk(const QCString &fileName, size_t startLine, size_t endLine, std::string &str)
reads the fragment start at startLine and ending at endLine from file fileName into buffer str
static FilterCache & instance()
void readFragmentFromFile(std::string &str, const QCString &fileName, size_t startOffset, size_t size=0)
Reads the fragment start at byte offset startOffset of file fileName into buffer str.
size_t m_endPos
void compileLineOffsets(const QCString &fileName, const std::string &str)
computes the starting offset for each line for file fileName, whose contents should already be stored...
bool getFileContents(const QCString &fileName, size_t startLine, size_t endLine, std::string &str)
collects the part of file fileName starting at startLine and ending at endLine into buffer 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
Find an object given the key.
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:34
iterator end() noexcept
Definition memberlist.h:55
iterator begin() noexcept
Definition memberlist.h:53
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)
Add a new section given the data of an existing section.
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:84
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
const char * qPrint(const char *s)
Definition qcstring.h:672
#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:5549
QCString convertToHtml(const QCString &s, bool keepEntities)
Definition util.cpp:4317
QCString parseCommentAsText(const Definition *scope, const MemberDef *md, const QCString &doc, const QCString &fileName, int lineNr)
Definition util.cpp:5707
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:4133
int computeQualifiedIndex(const QCString &name)
Return the index of the last :: in the string name that is still before the first <.
Definition util.cpp:7152
QCString convertToXML(const QCString &s, bool keepEntities)
Definition util.cpp:4266
QCString getLanguageSpecificSeparator(SrcLangExt lang, bool classScope)
Returns the scope separator to use given the programming language lang.
Definition util.cpp:6230
QCString getEncoding(const FileInfo &fi)
Definition util.cpp:6008
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5368
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:5243
A bunch of utility functions.
bool isId(int c)
Definition util.h:202