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 "reflist.h"
50#include "utf8.h"
51#include "indexlist.h"
52#include "fileinfo.h"
53
54//-----------------------------------------------------------------------------------------
55
56/** Private data associated with a Symbol DefinitionImpl object. */
58{
59 public:
60 void init(const QCString &df, const QCString &n);
61 void setDefFileName(const QCString &df);
62
63 Definition *def = nullptr;
64
66
67 std::unordered_map<std::string,MemberDef *> sourceRefByDict;
68 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 if (n!="<globalScope>")
124 {
125 //extractNamespaceName(m_name,m_localName,ns);
127 }
128 else
129 {
130 localName=n;
131 }
132 //printf("localName=%s\n",qPrint(localName));
133
134 brief.reset();
135 details.reset();
136 body.reset();
137 inbodyDocs.reset();
138 sourceRefByDict.clear();
139 sourceRefsDict.clear();
140 requirementRefs.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 const std::string &symName = name.str();
162 for (const auto &pat : exclSyms)
163 {
164 QCString pattern = pat;
165 bool forceStart=FALSE;
166 bool forceEnd=FALSE;
167 if (pattern.at(0)=='^')
168 {
169 pattern = pattern.mid(1);
170 forceStart = true;
171 }
172 if (pattern.at(pattern.length() - 1) == '$')
173 {
174 pattern = pattern.left(pattern.length() - 1);
175 forceEnd = true;
176 }
177 if (pattern.find('*')!=-1) // wildcard mode
178 {
179 const reg::Ex re(substitute(pattern,"*",".*").str());
180 reg::Match match;
181 if (reg::search(symName,match,re)) // wildcard match
182 {
183 size_t ui = match.position();
184 size_t pl = match.length();
185 size_t sl = symName.length();
186 if ((ui==0 || pattern.at(0)=='*' || (!isId(symName.at(ui-1)) && !forceStart)) &&
187 (ui+pl==sl || pattern.at(pattern.length()-1)=='*' || (!isId(symName.at(ui+pl)) && !forceEnd))
188 )
189 {
190 //printf("--> name=%s pattern=%s match at %d\n",qPrint(symName),qPrint(pattern),i);
191 return TRUE;
192 }
193 }
194 }
195 else if (!pattern.isEmpty()) // match words
196 {
197 size_t i = symName.find(pattern.str());
198 if (i!=std::string::npos) // we have a match!
199 {
200 size_t ui=i;
201 size_t pl=pattern.length();
202 size_t sl=symName.length();
203 // check if it is a whole word match
204 if ((ui==0 || (!isId(symName.at(ui-1)) && !forceStart)) &&
205 (ui+pl==sl || (!isId(symName.at(ui+pl)) && !forceEnd))
206 )
207 {
208 //printf("--> name=%s pattern=%s match at %d\n",qPrint(symName),qPrint(pattern),i);
209 return TRUE;
210 }
211 }
212 }
213 }
214 //printf("--> name=%s: no match\n",name);
215 return FALSE;
216}
217
218static void addToMap(const QCString &name,Definition *d)
219{
220 bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
223 if (!vhdlOpt && index!=-1) symbolName=symbolName.mid(index+2);
224 if (!symbolName.isEmpty())
225 {
226 //printf("adding symbol %s\n",qPrint(symbolName));
228
230 }
231}
232
233static void removeFromMap(const QCString &name,Definition *d)
234{
235 Doxygen::symbolMap->remove(name,d);
236}
237
239 const QCString &df,int dl,int dc,
240 const QCString &name,const char *b,
241 const char *d,bool isSymbol)
242 : p(std::make_unique<Private>())
243{
244 setName(name);
245 p->def = def;
246 p->defLine = dl;
247 p->defColumn = dc;
248 p->init(df,name);
249 p->isSymbol = isSymbol;
250 if (isSymbol) addToMap(name,def);
251 _setBriefDescription(b,df,dl);
254 {
255 p->hidden = TRUE;
256 }
257}
258
260 : p(std::make_unique<Private>(*d.p))
261{
262 if (p->isSymbol) addToMap(p->name,p->def);
263}
264
266{
267 if (this!=&other)
268 {
269 p = std::make_unique<Private>(*other.p);
270 }
271 return *this;
272}
273
275{
276 if (p->isSymbol)
277 {
278 removeFromMap(p->symbolName,p->def);
279 }
280}
281
283{
284 if (name.isEmpty()) return;
285 p->name = name;
286 p->isAnonymous = p->name.isEmpty() ||
287 p->name.at(0)=='@' ||
288 p->name.find("::@")!=-1;
289}
290
292{
293 if (id.isEmpty()) return;
294 p->id = id;
296 {
297 //printf("DefinitionImpl::setId '%s'->'%s'\n",id,qPrint(p->name));
298 Doxygen::clangUsrMap->emplace(id.str(),p->def);
299 }
300}
301
304 return p->id;
305}
306
307void DefinitionImpl::addSectionsToDefinition(const std::vector<const SectionInfo*> &anchorList)
308{
309 //printf("%s: addSectionsToDefinition(%d)\n",qPrint(name()),anchorList->count());
310 for (const SectionInfo *si : anchorList)
311 {
312 //printf("Add section '%s' to definition '%s'\n",
313 // qPrint(si->label()),qPrint(name()));
315 SectionInfo *gsi=sm.find(si->label());
316 //printf("===== label=%s gsi=%p\n",qPrint(si->label()),(void*)gsi);
317 if (gsi==nullptr)
318 {
319 gsi = sm.add(*si);
320 }
321 if (p->sectionRefs.find(gsi->label())==nullptr)
322 {
323 p->sectionRefs.add(gsi);
324 }
325 gsi->setDefinition(p->def);
326 }
327}
328
330{
331 //printf("DefinitionImpl::hasSections(%s) #sections=%zu\n",qPrint(name()), p->sectionRefs.size());
332 if (p->sectionRefs.empty()) return FALSE;
333 for (const SectionInfo *si : p->sectionRefs)
334 {
335 if (si->type().isSection())
336 {
337 return TRUE;
338 }
339 }
340 return FALSE;
341}
342
344{
345 if (!p->sectionRefs.empty())
346 {
347 //printf("%s: writeDocAnchorsToTagFile(%d)\n",qPrint(name()),p->sectionRef.size());
348 for (const SectionInfo *si : p->sectionRefs)
349 {
350 if (!si->generated() && si->ref().isEmpty() && !AnchorGenerator::instance().isGenerated(si->label().str()))
351 {
352 //printf("write an entry!\n");
353 if (p->def->definitionType()==Definition::TypeMember) tagFile << " ";
354 QCString fn = si->fileName();
356 tagFile << " <docanchor file=\"" << fn << "\"";
357 if (!si->title().isEmpty())
358 {
359 tagFile << " title=\"" << convertToXML(si->title()) << "\"";
360 }
361 tagFile << ">" << si->label() << "</docanchor>\n";
362 }
363 }
364 }
365}
366
368{
369 uint8_t md5_sig[16];
370 char sigStr[33];
371 // to avoid mismatches due to differences in indenting, we first remove
372 // double whitespaces...
373 QCString docStr = doc.simplifyWhiteSpace();
374 MD5Buffer(docStr.data(),static_cast<unsigned int>(docStr.length()),md5_sig);
375 MD5SigToString(md5_sig,sigStr);
376 //printf("%s:_docsAlreadyAdded doc='%s' sig='%s' docSigs='%s'\n",
377 // qPrint(name()),qPrint(doc),qPrint(sigStr),qPrint(sigList));
378 if (sigList.find(sigStr)==-1) // new docs, add signature to prevent re-adding it
379 {
380 sigList+=QCString(":")+sigStr;
381 return FALSE;
382 }
383 else
384 {
385 return TRUE;
386 }
387}
388
390 bool stripWhiteSpace,bool atTop)
391{
392 //printf("%s::setDocumentation(%s,%s,%d,%d)\n",qPrint(name()),d,docFile,docLine,stripWhiteSpace);
393 if (d.isEmpty()) return;
394 QCString doc = d;
396 {
398 }
399 else // don't strip whitespace
400 {
401 doc=d;
402 }
403 if (!_docsAlreadyAdded(doc,p->docSignatures))
404 {
405 //printf("setting docs for %s: '%s'\n",qPrint(name()),qPrint(m_doc));
406 if (!p->details.has_value())
407 {
408 p->details = std::make_optional<DocInfo>();
409 }
410 DocInfo &details = p->details.value();
411 if (details.doc.isEmpty()) // fresh detailed description
412 {
413 details.doc = doc;
414 }
415 else if (atTop) // another detailed description, append it to the start
416 {
417 details.doc = doc+"\n\n"+details.doc;
418 }
419 else // another detailed description, append it to the end
420 {
421 details.doc += "\n\n"+doc;
422 }
423 if (docLine!=-1) // store location if valid
424 {
425 details.file = docFile;
426 details.line = docLine;
427 }
428 else
429 {
430 details.file = docFile;
431 details.line = 1;
432 }
433 }
434}
435
441
443{
444 QCString brief = b;
445 brief = brief.stripWhiteSpace();
447 brief = brief.stripWhiteSpace();
448 if (brief.isEmpty()) return;
449 size_t bl = brief.length();
450 if (bl>0)
451 {
452 if (!theTranslator || theTranslator->needsPunctuation()) // add punctuation if needed
453 {
454 int c = brief.at(bl-1);
455 switch(c)
456 {
457 case '.': case '!': case '?': case ':': break;
458 default:
459 if (isUTF8CharUpperCase(brief.str(),0) && !lastUTF8CharIsMultibyte(brief.str())) brief+='.';
460 break;
461 }
462 }
463 }
464
465 if (!_docsAlreadyAdded(brief,p->briefSignatures))
466 {
467 if (p->brief && !p->brief->doc.isEmpty())
468 {
469 //printf("adding to details\n");
471 }
472 else
473 {
474 //fprintf(stderr,"DefinitionImpl::setBriefDescription(%s,%s,%d)\n",b,briefFile,briefLine);
475 if (!p->brief.has_value())
476 {
477 p->brief = std::make_optional<BriefInfo>();
478 }
479 BriefInfo &briefInfo = p->brief.value();
480 briefInfo.doc=brief;
481 if (briefLine!=-1)
482 {
483 briefInfo.file = briefFile;
484 briefInfo.line = briefLine;
485 }
486 else
487 {
488 briefInfo.file = briefFile;
489 briefInfo.line = 1;
490 }
491 }
492 }
493 else
494 {
495 //printf("do nothing!\n");
496 }
497}
498
504
506{
507 if (!_docsAlreadyAdded(doc,p->docSignatures))
508 {
509 if (!p->inbodyDocs.has_value())
510 {
511 p->inbodyDocs = std::make_optional<DocInfo>();
512 }
513 DocInfo &inbodyDocs = p->inbodyDocs.value();
514 if (inbodyDocs.doc.isEmpty()) // fresh inbody docs
515 {
516 inbodyDocs.doc = doc;
517 inbodyDocs.file = inbodyFile;
518 inbodyDocs.line = inbodyLine;
519 }
520 else // another inbody documentation fragment, append this to the end
521 {
522 inbodyDocs.doc += QCString("\n\n")+doc;
523 }
524 }
525}
526
532
533//---------------------------------------
534
535/*! Cache for storing the result of filtering a file */
537{
538 private:
540 {
541 size_t filePos;
542 size_t fileSize;
543 };
544 using LineOffsets = std::vector<size_t>;
545
546 public:
547 static FilterCache &instance();
548
549 //! collects the part of file \a fileName starting at \a startLine and ending at \a endLine into
550 //! buffer \a str. Applies filtering if FILTER_SOURCE_FILES is enabled and the file extension
551 //! matches a filter. Caches file information so that subsequent extraction of blocks from
552 //! the same file can be performed efficiently
553 bool getFileContents(const QCString &fileName,size_t startLine,size_t endLine, std::string &str)
554 {
555 bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
556 QCString filter = getFileFilter(fileName,TRUE);
557 bool usePipe = !filter.isEmpty() && filterSourceFiles;
558 return usePipe ? getFileContentsPipe(fileName,filter,startLine,endLine,str)
559 : getFileContentsDisk(fileName,startLine,endLine,str);
560 }
561 private:
562 bool getFileContentsPipe(const QCString &fileName,const QCString &filter,
563 size_t startLine,size_t endLine,std::string &str)
564 {
565 std::unique_lock<std::mutex> lock(m_mutex);
566 auto it = m_cache.find(fileName.str());
567 if (it!=m_cache.end()) // cache hit: reuse stored result
568 {
569 lock.unlock();
570 auto item = it->second;
571 //printf("getFileContents(%s): cache hit\n",qPrint(fileName));
572 // file already processed, get the results after filtering from the tmp file
573 Debug::print(Debug::FilterOutput,0,"Reusing filter result for {} from {} at offset={} size={}\n",
574 fileName,Doxygen::filterDBFileName,item.filePos,item.fileSize);
575
576 auto it_off = m_lineOffsets.find(fileName.str());
577 assert(it_off!=m_lineOffsets.end());
578 auto [ startLineOffset, fragmentSize] = getFragmentLocation(it_off->second,startLine,endLine);
579 //printf("%s: existing file [%zu-%zu]->[%zu-%zu] size=%zu\n",
580 // qPrint(fileName),startLine,endLine,startLineOffset,endLineOffset,fragmentSize);
582 item.filePos+startLineOffset, fragmentSize);
583 return true;
584 }
585 else // cache miss: filter active but file not previously processed
586 {
587 //printf("getFileContents(%s): cache miss\n",qPrint(fileName));
588 // filter file
589 QCString cmd=filter+" \""+fileName+"\"";
590 Debug::print(Debug::ExtCmd,0,"Executing popen(`{}`)\n",cmd);
591 FILE *f = Portable::popen(cmd,"r");
592 if (f==nullptr)
593 {
594 // handle error
595 err("Error opening filter pipe command '{}'\n",cmd);
596 return false;
597 }
599 FilterCacheItem item;
600 item.filePos = m_endPos;
601 if (bf==nullptr)
602 {
603 // handle error
604 err("Error opening filter database file {}\n",Doxygen::filterDBFileName);
606 return false;
607 }
608 // append the filtered output to the database file
609 size_t size=0;
610 while (!feof(f))
611 {
612 const int blockSize = 4096;
613 char buf[blockSize];
614 size_t bytesRead = fread(buf,1,blockSize,f);
615 size_t bytesWritten = fwrite(buf,1,bytesRead,bf);
616 if (bytesRead!=bytesWritten)
617 {
618 // handle error
619 err("Failed to write to filter database {}. Wrote {} out of {} bytes\n",
620 Doxygen::filterDBFileName,bytesWritten,bytesRead);
622 fclose(bf);
623 return false;
624 }
625 size+=bytesWritten;
626 str+=std::string_view(buf,bytesWritten);
627 }
628 item.fileSize = size;
629 // add location entry to the dictionary
630 m_cache.emplace(fileName.str(),item);
631 Debug::print(Debug::FilterOutput,0,"Storing new filter result for {} in {} at offset={} size={}\n",
632 fileName,Doxygen::filterDBFileName,item.filePos,item.fileSize);
633 // update end of file position
634 m_endPos += size;
636 fclose(bf);
637
638 // shrink buffer to [startLine..endLine] part
639 shrinkBuffer(str,fileName,startLine,endLine);
640 }
641 return true;
642 }
643
644 //! reads the fragment start at \a startLine and ending at \a endLine from file \a fileName
645 //! into buffer \a str
646 bool getFileContentsDisk(const QCString &fileName,size_t startLine,size_t endLine,std::string &str)
647 {
648 std::unique_lock<std::mutex> lock(m_mutex);
649 // normal file
650 //printf("getFileContents(%s): no filter\n",qPrint(fileName));
651 auto it = m_lineOffsets.find(fileName.str());
652 if (it == m_lineOffsets.end()) // new file
653 {
654 // read file completely into str buffer
655 readFragmentFromFile(str,fileName,0);
656 // shrink buffer to [startLine..endLine] part
657 shrinkBuffer(str,fileName,startLine,endLine);
658 }
659 else // file already processed before
660 {
661 lock.unlock();
662 auto [ startLineOffset, fragmentSize] = getFragmentLocation(it->second,startLine,endLine);
663 //printf("%s: existing file [%zu-%zu] -> start=%zu size=%zu\n",
664 // qPrint(fileName),startLine,endLine,startLineOffset,fragmentSize);
665 readFragmentFromFile(str,fileName,startLineOffset,fragmentSize);
666 }
667 return true;
668 }
669
670 //! computes the starting offset for each line for file \a fileName, whose contents should
671 //! already be stored in buffer \a str.
672 void compileLineOffsets(const QCString &fileName,const std::string &str)
673 {
674 // line 1 (index 0) is at offset 0
675 auto it = m_lineOffsets.emplace(fileName.data(),LineOffsets{0}).first;
676 const char *p=str.data();
677 while (*p)
678 {
679 char c=0;
680 while ((c=*p)!='\n' && c!=0) p++; // search until end of the line
681 if (c!=0) p++;
682 it->second.push_back(p-str.data());
683 }
684 }
685
686 //! Returns the byte offset and size within a file of a fragment given the array of
687 //! line offsets and the start and end line of the fragment.
688 auto getFragmentLocation(const LineOffsets &lineOffsets,
689 size_t startLine,size_t endLine) -> std::tuple<size_t,size_t>
690 {
691 assert(startLine > 0);
692 assert(startLine <= endLine);
693 const size_t startLineOffset = lineOffsets[std::min(startLine-1,lineOffsets.size()-1)];
694 const size_t endLineOffset = lineOffsets[std::min(endLine, lineOffsets.size()-1)];
695 assert(startLineOffset <= endLineOffset);
696 const size_t fragmentSize = endLineOffset-startLineOffset;
697 return std::tie(startLineOffset,fragmentSize);
698 }
699
700 //! Shrinks buffer \a str which should hold the contents of \a fileName to the
701 //! fragment starting a line \a startLine and ending at line \a endLine
702 void shrinkBuffer(std::string &str,const QCString &fileName,size_t startLine,size_t endLine)
703 {
704 // compute offsets from start for each line
705 compileLineOffsets(fileName,str);
706 auto it = m_lineOffsets.find(fileName.str());
707 assert(it!=m_lineOffsets.end());
708 const LineOffsets &lineOffsets = it->second;
709 auto [ startLineOffset, fragmentSize] = getFragmentLocation(lineOffsets,startLine,endLine);
710 //printf("%s: new file [%zu-%zu]->[%zu-%zu] size=%zu\n",
711 // qPrint(fileName),startLine,endLine,startLineOffset,endLineOffset,fragmentSize);
712 str.erase(0,startLineOffset);
713 str.resize(fragmentSize);
714 }
715
716 //! Reads the fragment start at byte offset \a startOffset of file \a fileName into buffer \a str.
717 //! Result will be a null terminated. If size==0 the whole file will be read and startOffset is ignored.
718 //! If size>0, size bytes will be read.
719 void readFragmentFromFile(std::string &str,const QCString &fileName,size_t startOffset,size_t size=0)
720 {
721 std::ifstream ifs = Portable::openInputStream(fileName,true,true);
722 if (size==0) { startOffset=0; size = static_cast<size_t>(ifs.tellg()); }
723 ifs.seekg(startOffset, std::ios::beg);
724 str.resize(size);
725 ifs.read(str.data(), size);
726 }
727
729 std::unordered_map<std::string,FilterCacheItem> m_cache;
730 std::unordered_map<std::string,LineOffsets> m_lineOffsets;
731 std::mutex m_mutex;
732 size_t m_endPos;
733};
734
736{
737 static FilterCache theInstance;
738 return theInstance;
739}
740
741//-----------------------------------------
742
743
744/*! Reads a fragment of code from file \a fileName starting at
745 * line \a startLine and ending at line \a endLine (inclusive). The fragment is
746 * stored in \a result. If FALSE is returned the code fragment could not be
747 * found.
748 *
749 * The file is scanned for a opening bracket ('{') from \a startLine onward
750 * The line actually containing the bracket is returned via startLine.
751 * The file is scanned for a closing bracket ('}') from \a endLine backward.
752 * The line actually containing the bracket is returned via endLine.
753 * Note that for VHDL code the bracket search is not done.
754 */
755bool readCodeFragment(const QCString &fileName,bool isMacro,
756 int &startLine,int &endLine,QCString &result)
757{
758 bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
759 QCString filter = getFileFilter(fileName,TRUE);
760 bool usePipe = !filter.isEmpty() && filterSourceFiles;
761 int tabSize = Config_getInt(TAB_SIZE);
762 SrcLangExt lang = getLanguageFromFileName(fileName);
763 const int blockSize = 4096;
764 std::string str;
766 static_cast<size_t>(std::max(1,startLine)),
767 static_cast<size_t>(std::max({1,startLine,endLine})),str);
768 //printf("readCodeFragment(%s,startLine=%d,endLine=%d)=\n[[[\n%s]]]\n",qPrint(fileName),startLine,endLine,qPrint(str));
769
770 bool found = lang==SrcLangExt::VHDL ||
771 lang==SrcLangExt::Python ||
772 lang==SrcLangExt::Fortran ||
773 isMacro;
774 // for VHDL, Python, and Fortran no bracket search is possible
775 char *p=str.data();
776 if (p && *p)
777 {
778 char c=0;
779 int col=0;
780 int lineNr=startLine;
781 // skip until the opening bracket or lonely : is found
782 char cn=0;
783 while (*p && !found)
784 {
785 int pc=0;
786 while ((c=*p++)!='{' && c!=':' && c!='=' && c!=0)
787 {
788 //printf("parsing char '%c'\n",c);
789 if (c=='\n')
790 {
791 lineNr++;
792 col = 0;
793 }
794 else if (c=='\t')
795 {
796 col+=tabSize - (col%tabSize);
797 }
798 else if (pc=='/' && c=='/') // skip single line comment
799 {
800 while ((c=*p++)!='\n' && c!=0);
801 if (c == '\n')
802 {
803 lineNr++;
804 col = 0;
805 }
806 }
807 else if (pc=='/' && c=='*') // skip C style comment
808 {
809 while (((c=*p++)!='/' || pc!='*') && c!=0)
810 {
811 if (c == '\n')
812 {
813 lineNr++;
814 col = 0;
815 }
816 pc=c;
817 }
818 }
819 else
820 {
821 col++;
822 }
823 pc = c;
824 }
825 if (c==':')
826 {
827 cn=*p++;
828 if (cn!=':') found=TRUE;
829 }
830 else if (c=='=')
831 {
832 cn=*p++;
833 if (cn=='>') // C# Expression body
834 {
835 found=TRUE;
836 }
837 }
838 else if (c=='{')
839 {
840 found=TRUE;
841 }
842 else if (c==0)
843 {
844 break;
845 }
846 }
847 //printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr);
848 if (found)
849 {
850 // For code with more than one line,
851 // fill the line with spaces until we are at the right column
852 // so that the opening brace lines up with the closing brace
853 if (endLine!=startLine)
854 {
855 QCString spaces;
856 spaces.fill(' ',col);
857 result+=spaces;
858 }
859 // copy until end of line
860 if (c) result+=c;
861 startLine=lineNr;
862 if (c==':' || c=='=')
863 {
864 result+=cn;
865 if (cn=='\n') lineNr++;
866 }
867 char lineStr[blockSize];
868 do
869 {
870 //printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine);
871 int size_read=0;
872 do
873 {
874 // read up to blockSize-1 non-zero characters
875 int i=0;
876 while ((c=*p) && i<blockSize-1)
877 {
878 lineStr[i++]=c;
879 p++;
880 if (c=='\n') break; // stop at end of the line
881 }
882 lineStr[i]=0;
883 size_read=i;
884 result+=lineStr; // append line to the output
885 } while (size_read == (blockSize-1)); // append more if line does not fit in buffer
886 lineNr++;
887 } while (*p);
888
889 // strip stuff after closing bracket
890 int newLineIndex = result.findRev('\n');
891 int braceIndex = result.findRev('}');
892 if (braceIndex > newLineIndex)
893 {
894 result.resize(static_cast<size_t>(braceIndex+1));
895 }
896 endLine=lineNr-1;
897 }
898 if (usePipe)
899 {
900 Debug::print(Debug::FilterOutput, 0, "Filter output\n");
901 Debug::print(Debug::FilterOutput,0,"-------------\n{}\n-------------\n",result);
902 }
903 }
904 QCString encoding = getEncoding(FileInfo(fileName.str()));
905 if (encoding!="UTF-8")
906 {
907 std::string encBuf = result.str();
908 bool ok = transcodeCharacterStringToUTF8(encBuf,encoding.data());
909 if (ok)
910 {
911 result = encBuf;
912 }
913 else
914 {
915 err("failed to transcode characters in code fragment in file {} lines {} to {}, from input encoding {} to UTF-8\n",
916 fileName,startLine,endLine,encoding);
917
918 }
919 }
920 if (!result.isEmpty() && result.at(result.length()-1)!='\n') result += "\n";
921 //printf("readCodeFragment(%d-%d)=%s\n",startLine,endLine,qPrint(result));
922 return found;
923}
924
926{
927 ASSERT(p->def->definitionType()!=Definition::TypeFile); // file overloads this method
928 QCString fn;
929 bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
930 if (sourceBrowser &&
931 p->body && p->body->startLine!=-1 && p->body->fileDef)
932 {
933 fn = p->body->fileDef->getSourceFileBase();
934 }
935 return fn;
936}
937
939{
940 const int maxAnchorStrLen = 20;
941 char anchorStr[maxAnchorStrLen];
942 anchorStr[0]='\0';
943 if (p->body && p->body->startLine!=-1)
944 {
945 if (Htags::useHtags)
946 {
947 qsnprintf(anchorStr,maxAnchorStrLen,"L%d",p->body->defLine);
948 }
949 else
950 {
951 qsnprintf(anchorStr,maxAnchorStrLen,"l%05d",p->body->defLine);
952 }
953 }
954 return anchorStr;
955}
956
957/*! Write a reference to the source code defining this definition */
959{
960 //printf("DefinitionImpl::writeSourceRef %d %p\n",bodyLine,bodyDef);
962 if (!fn.isEmpty())
963 {
964 QCString refText = theTranslator->trDefinedAtLineInSourceFile();
965 int lineMarkerPos = refText.find("@0");
966 int fileMarkerPos = refText.find("@1");
967 if (lineMarkerPos!=-1 && fileMarkerPos!=-1) // should always pass this.
968 {
969 QCString lineStr;
970 lineStr.sprintf("%d",p->body->defLine);
971 QCString anchorStr = getSourceAnchor();
972 ol.startParagraph("definition");
973 if (lineMarkerPos<fileMarkerPos) // line marker before file marker
974 {
975 // write text left from linePos marker
976 ol.parseText(refText.left(lineMarkerPos));
977 ol.writeObjectLink(QCString(),fn,anchorStr,lineStr);
978 // write text between markers
979 ol.parseText(refText.mid(lineMarkerPos+2,fileMarkerPos-lineMarkerPos-2));
980 // write file link
981 ol.writeObjectLink(QCString(),fn,QCString(),p->body->fileDef->name());
982 // write text right from file marker
983 ol.parseText(refText.right(refText.length()-static_cast<size_t>(fileMarkerPos)-2));
984 }
985 else // file marker before line marker
986 {
987 // write text left from file marker
988 ol.parseText(refText.left(fileMarkerPos));
989 // write file link
990 ol.writeObjectLink(QCString(),fn,QCString(),p->body->fileDef->name());
991 // write text between markers
992 ol.parseText(refText.mid(fileMarkerPos+2,lineMarkerPos-fileMarkerPos-2));
993 // write line link
994 ol.writeObjectLink(QCString(),fn,anchorStr,lineStr);
995 // write text right from linePos marker
996 ol.parseText(refText.right(refText.length()-static_cast<size_t>(lineMarkerPos)-2));
997 }
998 ol.endParagraph();
999 }
1000 else
1001 {
1002 err("translation error: invalid markers in trDefinedAtLineInSourceFile()\n");
1003 }
1004 }
1005}
1006
1007void DefinitionImpl::setBodySegment(int defLine, int bls,int ble)
1008{
1009 if (!p->body.has_value())
1010 {
1011 p->body = std::make_optional<BodyInfo>();
1012 }
1013 BodyInfo &body = p->body.value();
1014 body.defLine = defLine;
1015 body.startLine = bls;
1016 body.endLine = ble;
1017}
1018
1020{
1021 if (!p->body.has_value())
1022 {
1023 p->body = std::make_optional<BodyInfo>();
1024 }
1025 p->body.value().fileDef=fd;
1026}
1027
1029{
1030 return p->body && p->body->startLine!=-1 &&
1031 p->body->endLine>=p->body->startLine &&
1032 p->body->fileDef;
1033}
1034
1035/*! Write code of this definition into the documentation */
1037{
1038 const MemberDef *thisMd = nullptr;
1039 if (p->def->definitionType()==Definition::TypeMember)
1040 {
1041 thisMd = toMemberDef(p->def);
1042 }
1043 bool inlineSources = thisMd && thisMd->hasInlineSource();
1044 //printf("Source Fragment %s: %d-%d\n",qPrint(name()),
1045 // p->body->startLine,p->body->endLine);
1046 if (inlineSources && hasSources())
1047 {
1048 ol.pushGeneratorState();
1049 QCString codeFragment;
1050 bool isMacro = thisMd && thisMd->memberType()==MemberType::Define;
1051 int actualStart=p->body->startLine,actualEnd=p->body->endLine;
1052 if (readCodeFragment(p->body->fileDef->absFilePath(),isMacro,
1053 actualStart,actualEnd,codeFragment)
1054 )
1055 {
1056 //printf("Adding code fragment '%s' ext='%s' range=%d-%d\n",
1057 // qPrint(codeFragment),qPrint(p->defFileExt),actualStart,actualEnd);
1058 auto intf = Doxygen::parserManager->getCodeParser(p->defFileExt);
1059 intf->resetCodeParserState();
1060 //printf("Read:\n'%s'\n\n",qPrint(codeFragment));
1061
1062 auto &codeOL = ol.codeGenerators();
1063 codeOL.startCodeFragment("DoxyCode");
1064 size_t indent = 0;
1065 intf->parseCode(codeOL, // codeOutIntf
1066 scopeName, // scope
1067 detab(codeFragment,indent), // input
1068 p->lang, // lang
1069 Config_getBool(STRIP_CODE_COMMENTS),
1071 .setFileDef(p->body->fileDef)
1072 .setStartLine(actualStart)
1073 .setEndLine(actualEnd)
1074 .setInlineFragment(true)
1075 .setMemberDef(thisMd)
1076 );
1077 codeOL.endCodeFragment("DoxyCode");
1078 }
1079 ol.popGeneratorState();
1080 }
1081}
1082
1083static inline MemberVector refMapToVector(const std::unordered_map<std::string,MemberDef *> &map)
1084{
1085 // convert map to a vector of values
1086 MemberVector result;
1087 std::transform(map.begin(),map.end(), // iterate over map
1088 std::back_inserter(result), // add results to vector
1089 [](const auto &item)
1090 { return item.second; } // extract value to add from map Key,Value pair
1091 );
1092 // and sort it
1093 std::stable_sort(result.begin(),result.end(),
1094 [](const auto &m1,const auto &m2) { return genericCompareMembers(m1,m2)<0; });
1095 return result;
1096}
1097
1098/*! Write a reference to the source code fragments in which this
1099 * definition is used.
1100 */
1102 const QCString &text,const std::unordered_map<std::string,MemberDef *> &membersMap,
1103 bool /*funcOnly*/) const
1104{
1105 if (!membersMap.empty())
1106 {
1107 auto members = refMapToVector(membersMap);
1108
1109 auto replaceFunc = [this,&members,scopeName,&ol](size_t entryIndex)
1110 {
1111 bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1112 bool refLinkSource = Config_getBool(REFERENCES_LINK_SOURCE);
1113 const MemberDef *md=members[entryIndex];
1114 if (md)
1115 {
1116 QCString scope=md->getScopeString();
1117 QCString name=md->name();
1118 //printf("class=%p scope=%s scopeName=%s\n",md->getClassDef(),qPrint(scope),scopeName);
1119 if (!scope.isEmpty() && scope!=scopeName)
1120 {
1121 name.prepend(scope+getLanguageSpecificSeparator(p->lang));
1122 }
1123 if (!md->isObjCMethod() &&
1124 (md->isFunction() || md->isSlot() ||
1125 md->isPrototype() || md->isSignal()
1126 )
1127 )
1128 {
1129 name+="()";
1130 }
1131 if (sourceBrowser &&
1132 !(md->isLinkable() && !refLinkSource) &&
1133 md->getStartBodyLine()!=-1 &&
1134 md->getBodyDef()
1135 )
1136 {
1137 const int maxLineNrStr = 10;
1138 char anchorStr[maxLineNrStr];
1139 qsnprintf(anchorStr,maxLineNrStr,"l%05d",md->getStartBodyLine());
1140 //printf("Write object link to %s\n",qPrint(md->getBodyDef()->getSourceFileBase()));
1141 ol.writeObjectLink(QCString(),md->getBodyDef()->getSourceFileBase(),anchorStr,name);
1142 }
1143 else if (md->isLinkable())
1144 {
1146 md->getOutputFileBase(),
1147 md->anchor(),name);
1148 }
1149 else
1150 {
1151 ol.docify(name);
1152 }
1153 }
1154 };
1155
1156 ol.startParagraph("reference");
1157 ol.parseText(text);
1158 ol.docify(" ");
1159 writeMarkerList(ol,
1160 theTranslator->trWriteList(static_cast<int>(members.size())).str(),
1161 members.size(),
1162 replaceFunc);
1163 ol.writeString(".");
1164 ol.endParagraph();
1165
1166 }
1167}
1168
1170{
1171 _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),p->sourceRefByDict,FALSE);
1172}
1173
1175{
1176 _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),p->sourceRefsDict,TRUE);
1177}
1178
1180{
1181 if (!Config_getBool(GENERATE_REQUIREMENTS)) return;
1182 auto writeRefsForType = [&ol](const RequirementRefs &refs,const char *parType,const QCString &text)
1183 {
1184 size_t num = refs.size();
1185 if (num>0)
1186 {
1187 ol.startParagraph(parType);
1188 ol.parseText(text);
1189 ol.docify(" ");
1190 writeMarkerList(ol,
1191 theTranslator->trWriteList(static_cast<int>(num)).str(), num,
1192 [&refs,&ol](size_t entryIndex) { RequirementManager::instance().writeRef(ol,refs[entryIndex]); }
1193 );
1194 ol.writeString(".");
1195 ol.endParagraph();
1196 }
1197 };
1198
1199 RequirementRefs satisfiesRefs;
1200 RequirementRefs verifiesRefs;
1201 splitRequirementRefs(p->requirementRefs,satisfiesRefs,verifiesRefs);
1202 writeRefsForType(satisfiesRefs,"satisfies",theTranslator->trSatisfies(satisfiesRefs.size()==1));
1203 writeRefsForType(verifiesRefs, "verifies", theTranslator->trVerifies(verifiesRefs.size()==1));
1204}
1205
1207{
1208 return !p->sourceRefByDict.empty();
1209}
1210
1212{
1213 return !p->sourceRefsDict.empty();
1214}
1215
1217{
1218 return !p->requirementRefs.empty();
1219}
1220
1222{
1223 bool extractAll = Config_getBool(EXTRACT_ALL);
1224 //bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1225 bool hasDocs =
1226 (p->details && !p->details->doc.isEmpty()) || // has detailed docs
1227 (p->brief && !p->brief->doc.isEmpty()) || // has brief description
1228 (p->inbodyDocs && !p->inbodyDocs->doc.isEmpty()) || // has inbody docs
1229 extractAll //|| // extract everything
1230 // (sourceBrowser && p->body &&
1231 // p->body->startLine!=-1 && p->body->fileDef)
1232 ; // link to definition
1233 return hasDocs;
1234}
1235
1237{
1238 bool hasDocs =
1239 (p->details && !p->details->doc.isEmpty()) ||
1240 (p->brief && !p->brief->doc.isEmpty()) ||
1241 (p->inbodyDocs && !p->inbodyDocs->doc.isEmpty());
1242 return hasDocs;
1243}
1244
1246{
1247 if (md)
1248 {
1249 p->sourceRefByDict.emplace(sourceRefName.str(),md);
1250 }
1251}
1252
1254{
1255 if (md)
1256 {
1257 p->sourceRefsDict.emplace(sourceRefName.str(),md);
1258 }
1259}
1260
1262{
1263 return nullptr;
1264}
1265
1267{
1268 err("DefinitionImpl::addInnerCompound() called\n");
1269}
1270
1271static std::recursive_mutex g_qualifiedNameMutex;
1272
1274{
1275 std::lock_guard<std::recursive_mutex> lock(g_qualifiedNameMutex);
1276 if (!p->qualifiedName.isEmpty())
1277 {
1278 return p->qualifiedName;
1279 }
1280
1281 //printf("start %s::qualifiedName() localName=%s\n",qPrint(name()),qPrint(p->localName));
1282 if (p->outerScope==nullptr)
1283 {
1284 if (p->localName=="<globalScope>")
1285 {
1286 return "";
1287 }
1288 else
1289 {
1290 return p->localName;
1291 }
1292 }
1293
1294 if (p->outerScope->name()=="<globalScope>")
1295 {
1296 p->qualifiedName = p->localName;
1297 }
1298 else
1299 {
1300 p->qualifiedName = p->outerScope->qualifiedName()+
1302 p->localName;
1303 }
1304 //printf("end %s::qualifiedName()=%s\n",qPrint(name()),qPrint(p->qualifiedName));
1305 //count--;
1306 return p->qualifiedName;
1307}
1308
1310{
1311 std::lock_guard<std::recursive_mutex> lock(g_qualifiedNameMutex);
1312 //printf("%s::setOuterScope(%s)\n",qPrint(name()),d?qPrint(d->name()):"<none>");
1313 Definition *outerScope = p->outerScope;
1314 bool found=false;
1315 // make sure that we are not creating a recursive scope relation.
1316 while (outerScope && !found)
1317 {
1318 found = (outerScope==d);
1319 outerScope = outerScope->getOuterScope();
1320 }
1321 if (!found)
1322 {
1323 p->qualifiedName.clear(); // flush cached scope name
1324 p->outerScope = d;
1325 }
1326 p->hidden = p->hidden || d->isHidden();
1327 assert(p->def!=p->outerScope);
1328}
1329
1331{
1332 return p->localName;
1333}
1334
1336{
1337 p->partOfGroups.push_back(gd);
1338}
1339
1341{
1342 p->xrefListItems.insert(p->xrefListItems.end(), sli.cbegin(), sli.cend());
1343}
1344
1346{
1347 p->requirementRefs.insert(p->requirementRefs.end(), rqli.cbegin(), rqli.cend());
1348}
1349
1351{
1352 auto otherXrefList = d->xrefListItems();
1353
1354 // append vectors
1355 p->xrefListItems.reserve(p->xrefListItems.size()+otherXrefList.size());
1356 p->xrefListItems.insert (p->xrefListItems.end(),
1357 otherXrefList.begin(),otherXrefList.end());
1358
1359 // sort results on itemId
1360 std::stable_sort(p->xrefListItems.begin(),p->xrefListItems.end(),
1361 [](RefItem *left,RefItem *right)
1362 { return left->id() <right->id() ||
1363 (left->id()==right->id() &&
1364 left->list()->listName() < right->list()->listName());
1365 });
1366
1367 // filter out duplicates
1368 auto last = std::unique(p->xrefListItems.begin(),p->xrefListItems.end(),
1369 [](const RefItem *left,const RefItem *right)
1370 { return left->id()==right->id() &&
1371 left->list()->listName()==right->list()->listName();
1372 });
1373 p->xrefListItems.erase(last, p->xrefListItems.end());
1374}
1375
1377{
1378 for (const RefItem *item : p->xrefListItems)
1379 {
1380 if (item->list()->listName()==listName)
1381 {
1382 return item->id();
1383 }
1384 }
1385 return -1;
1386}
1387
1389{
1390 return p->xrefListItems;
1391}
1392
1394{
1395 return p->requirementRefs;
1396}
1397
1399{
1400 QCString result;
1401 if (p->outerScope && p->outerScope!=Doxygen::globalScope)
1402 {
1403 result = p->outerScope->pathFragment();
1404 }
1405 if (p->def->isLinkable())
1406 {
1407 if (!result.isEmpty()) result+="/";
1408 if (p->def->definitionType()==Definition::TypeGroup &&
1409 !toGroupDef(p->def)->groupTitle().isEmpty())
1410 {
1411 result+=toGroupDef(p->def)->groupTitle();
1412 }
1413 else if (p->def->definitionType()==Definition::TypePage &&
1414 toPageDef(p->def)->hasTitle())
1415 {
1416 result+=toPageDef(p->def)->title();
1417 }
1418 else
1419 {
1420 result+=p->localName;
1421 }
1422 }
1423 else
1424 {
1425 result+=p->localName;
1426 }
1427 return result;
1428}
1429
1430//----------------------------------------------------------------------------------------
1431
1432// TODO: move to htmlgen
1433/*! Returns the string used in the footer for $navpath when
1434 * GENERATE_TREEVIEW is enabled
1435 */
1437{
1438 QCString result;
1439 Definition *outerScope = getOuterScope();
1440 QCString locName = localName();
1441 if (outerScope && outerScope!=Doxygen::globalScope)
1442 {
1443 result+=outerScope->navigationPathAsString();
1444 }
1445 else if (p->def->definitionType()==Definition::TypeFile &&
1446 toFileDef(p->def)->getDirDef())
1447 {
1448 result+=(toFileDef(p->def))->getDirDef()->navigationPathAsString();
1449 }
1450 result+="<li class=\"navelem\">";
1451 if (p->def->isLinkableInProject())
1452 {
1453 QCString fn = p->def->getOutputFileBase();
1455 if (p->def->definitionType()==Definition::TypeGroup &&
1456 !toGroupDef(p->def)->groupTitle().isEmpty())
1457 {
1458 QCString title = parseCommentAsHtml(p->def,nullptr,toGroupDef(p->def)->groupTitle(),
1459 p->def->getDefFileName(),p->def->getDefLine());
1460 result+="<a href=\"$relpath^"+fn+"\">"+title+"</a>";
1461 }
1462 else if (p->def->definitionType()==Definition::TypePage &&
1463 toPageDef(p->def)->hasTitle())
1464 {
1465 QCString title = parseCommentAsHtml(p->def,nullptr,toPageDef(p->def)->title(),
1466 p->def->getDefFileName(),p->def->getDefLine());
1467 result+="<a href=\"$relpath^"+fn+"\">"+title+"</a>";
1468 }
1469 else if (p->def->definitionType()==Definition::TypeClass)
1470 {
1471 QCString name = toClassDef(p->def)->className();
1472 if (name.endsWith("-p"))
1473 {
1474 name = name.left(name.length()-2);
1475 }
1476 result+="<a href=\"$relpath^"+fn;
1477 if (!p->def->anchor().isEmpty()) result+="#"+p->def->anchor();
1478 result+="\">"+convertToHtml(name)+"</a>";
1479 }
1480 else
1481 {
1482 result+="<a href=\"$relpath^"+fn+"\">"+
1483 convertToHtml(locName)+"</a>";
1484 }
1485 }
1486 else
1487 {
1488 result+="<b>"+convertToHtml(locName)+"</b>";
1489 }
1490 result+="</li>";
1491 return result;
1492}
1493
1494// TODO: move to htmlgen
1496{
1497 ol.pushGeneratorState();
1499
1500 QCString navPath;
1501 navPath += "<div id=\"nav-path\" class=\"navpath\">\n"
1502 " <ul>\n";
1503 navPath += navigationPathAsString();
1504 navPath += " </ul>\n"
1505 "</div>\n";
1506 ol.writeNavigationPath(navPath);
1507
1508 ol.popGeneratorState();
1509}
1510
1511void DefinitionImpl::writeToc(OutputList &ol, const LocalToc &localToc) const
1512{
1513 // first check if we have anything to show or if the outline is already shown on the outline panel
1514 if (p->sectionRefs.empty() || (Config_getBool(GENERATE_TREEVIEW) && Config_getBool(PAGE_OUTLINE_PANEL))) return;
1515 // generate the embedded toc
1516 //ol.writeLocalToc(p->sectionRefs,localToc);
1517
1518 auto generateTocEntries = [this,&ol]()
1519 {
1520 for (const SectionInfo *si : p->sectionRefs)
1521 {
1522 if (si->type().isSection())
1523 {
1524 ol.startTocEntry(si);
1525 const MemberDef *md = p->def->definitionType()==Definition::TypeMember ? toMemberDef(p->def) : nullptr;
1526 const Definition *scope = p->def->definitionType()==Definition::TypeMember ? p->def->getOuterScope() : p->def;
1527 QCString docTitle = si->title();
1528 if (docTitle.isEmpty()) docTitle = si->label();
1529 ol.generateDoc(docFile(),
1531 scope,
1532 md,
1533 docTitle,
1534 DocOptions()
1535 .setIndexWords(true)
1536 .setSingleLine(true)
1537 .setSectionLevel(si->type().level())
1538 );
1539 ol.endTocEntry(si);
1540 }
1541 }
1542 };
1543
1544 if (localToc.isHtmlEnabled())
1545 {
1546 ol.pushGeneratorState();
1548 ol.startLocalToc(localToc.htmlLevel());
1549 generateTocEntries();
1550 ol.endLocalToc();
1551 ol.popGeneratorState();
1552 }
1553 if (localToc.isDocbookEnabled())
1554 {
1555 ol.pushGeneratorState();
1557 ol.startLocalToc(localToc.docbookLevel());
1558 generateTocEntries();
1559 ol.endLocalToc();
1560 ol.popGeneratorState();
1561 }
1562 if (localToc.isLatexEnabled())
1563 {
1564 ol.pushGeneratorState();
1566 ol.startLocalToc(localToc.latexLevel());
1567 // no gneerateTocEntries() needed for LaTeX
1568 ol.endLocalToc();
1569 ol.popGeneratorState();
1570 }
1571}
1572
1573//----------------------------------------------------------------------------------------
1574
1576{
1577 return p->sectionRefs;
1578}
1579
1581{
1582 return p->symbolName;
1583}
1584
1585//----------------------
1586
1588{
1589 return p->details ? p->details->doc : QCString("");
1590}
1591
1593{
1594 return p->details ? p->details->line : p->brief ? p->brief->line : 1;
1595}
1596
1598{
1599 if (p->details && !p->details->file.isEmpty()) return p->details->file;
1600 else if (p->brief && !p->brief->file.isEmpty()) return p->brief->file;
1601 else return "<" + p->name + ">";
1602}
1603
1604//----------------------------------------------------------------------------
1605// strips w from s iff s starts with w
1606static bool stripWord(QCString &s,QCString w)
1607{
1608 bool success=FALSE;
1609 if (s.left(w.length())==w)
1610 {
1611 success=TRUE;
1612 s=s.right(s.length()-w.length());
1613 }
1614 return success;
1615}
1616
1617//----------------------------------------------------------------------------
1618// some quasi intelligent brief description abbreviator :^)
1619static QCString abbreviate(const QCString &s,const QCString &name)
1620{
1621 QCString scopelessName=name;
1622 int i=scopelessName.findRev("::");
1623 if (i!=-1) scopelessName=scopelessName.mid(i+2);
1624 QCString result=s;
1625 result=result.stripWhiteSpace();
1626 // strip trailing .
1627 if (!result.isEmpty() && result.at(result.length()-1)=='.')
1628 result=result.left(result.length()-1);
1629
1630 // strip any predefined prefix
1631 const StringVector &briefDescAbbrev = Config_getList(ABBREVIATE_BRIEF);
1632 for (const auto &p : briefDescAbbrev)
1633 {
1634 QCString str = substitute(p,"$name",scopelessName); // replace $name with entity name
1635 str += " ";
1636 stripWord(result,str);
1637 }
1638
1639 // capitalize first character
1640 if (!result.isEmpty())
1641 {
1642 char c = result[0];
1643 if (c >= 'a' && c <= 'z') result[0] += 'A' - 'a';
1644 }
1645
1646 return result;
1647}
1648
1649
1650//----------------------
1651
1653{
1654 //printf("%s::briefDescription(%d)='%s'\n",qPrint(name()),abbr,p->brief?qPrint(p->brief->doc):"<none>");
1655 return p->brief ?
1656 (abbr ? abbreviate(p->brief->doc,p->def->displayName()) : p->brief->doc) :
1657 QCString("");
1658}
1659
1661{
1662 if (p->brief && p->brief->tooltip.isEmpty() && !p->brief->doc.isEmpty())
1663 {
1664 const MemberDef *md = p->def->definitionType()==Definition::TypeMember ? toMemberDef(p->def) : nullptr;
1665 const Definition *scope = p->def->definitionType()==Definition::TypeMember ? p->def->getOuterScope() : p->def;
1666 p->brief->tooltip = parseCommentAsText(scope,md,
1667 p->brief->doc, p->brief->file, p->brief->line);
1668 }
1669}
1670
1672{
1673 return p->brief ? p->brief->tooltip : QCString();
1674}
1675
1677{
1678 return p->brief ? p->brief->line : 1;
1679}
1680
1682{
1683 return p->brief && !p->brief->file.isEmpty() ? p->brief->file : QCString("<"+p->name+">");
1684}
1685
1686//----------------------
1687
1689{
1690 return p->inbodyDocs ? p->inbodyDocs->doc : QCString("");
1691}
1692
1694{
1695 return p->inbodyDocs ? p->inbodyDocs->line : 1;
1696}
1697
1699{
1700 return p->inbodyDocs && !p->inbodyDocs->file.isEmpty() ? p->inbodyDocs->file : QCString("<"+p->name+">");
1701}
1702
1703
1704//----------------------
1705
1707{
1708 return p->defFileName;
1709}
1710
1712{
1713 return p->defFileExt;
1714}
1715
1717{
1718 return p->hidden;
1719}
1720
1722{
1723 return p->def->isLinkableInProject() && !p->hidden;
1724}
1725
1727{
1728 return p->def->isLinkable() && !p->hidden;
1729}
1730
1732{
1733 return p->isArtificial;
1734}
1735
1737{
1738 return p->isExported;
1739}
1740
1742{
1743 return p->ref;
1744}
1745
1747{
1748 return !p->ref.isEmpty();
1749}
1750
1752{
1753 return p->body ? p->body->defLine : -1;
1754}
1755
1757{
1758 return p->body ? p->body->startLine : -1;
1759}
1760
1762{
1763 return p->body ? p->body->endLine : -1;
1764}
1765
1767{
1768 return p->body ? p->body->fileDef : nullptr;
1769}
1770
1772{
1773 return p->partOfGroups;
1774}
1775
1777{
1778 for (const auto &gd : partOfGroups())
1779 {
1780 if (gd->isLinkable()) return true;
1781 }
1782 return false;
1783}
1784
1786{
1787 return p->outerScope;
1788}
1789
1790static std::mutex g_memberReferenceMutex;
1791
1793{
1794 std::lock_guard<std::mutex> lock(g_memberReferenceMutex);
1795 if (p->referencesMembers.empty() && !p->sourceRefsDict.empty())
1796 {
1797 p->referencesMembers = refMapToVector(p->sourceRefsDict);
1798 }
1799 return p->referencesMembers;
1800}
1801
1803{
1804 std::lock_guard<std::mutex> lock(g_memberReferenceMutex);
1805 if (p->referencedByMembers.empty() && !p->sourceRefByDict.empty())
1806 {
1807 p->referencedByMembers = refMapToVector(p->sourceRefByDict);
1808 }
1809 return p->referencedByMembers;
1810}
1811
1813{
1814 const DefinitionImpl *defImpl = other->toDefinitionImpl_();
1815 if (defImpl)
1816 {
1817 for (const auto &kv : defImpl->p->sourceRefsDict)
1818 {
1819 auto it = p->sourceRefsDict.find(kv.first);
1820 if (it != p->sourceRefsDict.end())
1821 {
1822 p->sourceRefsDict.insert(kv);
1823 }
1824 }
1825 }
1826}
1827
1829{
1830 const DefinitionImpl *defImpl = other->toDefinitionImpl_();
1831 if (defImpl)
1832 {
1833 for (const auto &kv : defImpl->p->sourceRefByDict)
1834 {
1835 auto it = p->sourceRefByDict.find(kv.first);
1836 if (it != p->sourceRefByDict.end())
1837 {
1838 p->sourceRefByDict.emplace(kv.first,kv.second);
1839 }
1840 }
1841 }
1842}
1843
1844
1846{
1847 p->ref=r;
1848}
1849
1851{
1852 return p->lang;
1853}
1854
1856{
1857 p->hidden = p->hidden || b;
1858}
1859
1861{
1862 p->isArtificial = b;
1863}
1864
1866{
1867 p->isExported = b;
1868}
1869
1871{
1872 p->localName=name;
1873}
1874
1876{
1877 p->lang=lang;
1878}
1879
1880
1882{
1883 p->symbolName=name;
1884}
1885
1887{
1888 return p->symbolName;
1889}
1890
1892{
1893 bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC);
1894 return !briefDescription().isEmpty() && briefMemberDesc;
1895}
1896
1898{
1899 QCString ref = getReference();
1900 if (!ref.isEmpty())
1901 {
1902 auto it = Doxygen::tagDestinationMap.find(ref.str());
1904 {
1905 QCString result(it->second);
1906 size_t l = result.length();
1907 if (!relPath.isEmpty() && l>0 && result.at(0)=='.')
1908 { // relative path -> prepend relPath.
1909 result.prepend(relPath);
1910 l+=relPath.length();
1911 }
1912 if (l>0 && result.at(l-1)!='/') result+='/';
1913 return result;
1914 }
1915 }
1916 return relPath;
1917}
1918
1920{
1921 return p->name;
1922}
1923
1925{
1926 return p->isAnonymous;
1927}
1928
1930{
1931 return p->defLine;
1932}
1933
1935{
1936 return p->defColumn;
1937}
1938
1942
1946
1950
1951//---------------------------------------------------------------------------------
1952
1954 : m_def(def), m_scope(scope), m_symbolName(alias->_symbolName())
1955{
1956}
1957
1961
1963{
1964 //printf("%s::addToMap(%s)\n",qPrint(name()),qPrint(alias->name()));
1966 if (m_scope==nullptr)
1967 {
1968 m_qualifiedName = m_def->localName();
1969 }
1970 else
1971 {
1972 m_qualifiedName = m_scope->qualifiedName()+
1973 getLanguageSpecificSeparator(m_scope->getLanguage())+
1974 m_def->localName();
1975 }
1976}
1977
1982
1987
1989{
1990 return m_qualifiedName;
1991}
1992
1993//---------------------------------------------------------------------------------
1994
1996{
1997 return dm ? dm->toDefinition_() : nullptr;
1998}
1999
2001{
2002 return d ? d->toDefinitionMutable_() : nullptr;
2003}
2004
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:77
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
RequirementRefs requirementRefs
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)
const RequirementRefs & requirementReferences() const
void setBodySegment(int defLine, int bls, int ble)
void setExported(bool b)
int getDefLine() const
bool isHidden() const
void mergeRefItems(Definition *d)
bool hasRequirementRefs() const
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)
void writePageNavigation(OutputList &ol) const
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
void setRequirementReferences(const RequirementRefs &rqli)
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 writeRequirementRefs(OutputList &ol) 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:130
static NamespaceDefMutable * globalScope
Definition doxygen.h:120
static StringMap tagDestinationMap
Definition doxygen.h:115
static QCString filterDBFileName
Definition doxygen.h:132
static SymbolMap< Definition > * symbolMap
Definition doxygen.h:124
static ClangUsrMap * clangUsrMap
Definition doxygen.h:125
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
constexpr int docbookLevel() const noexcept
Definition types.h:622
constexpr int latexLevel() const noexcept
Definition types.h:620
constexpr bool isDocbookEnabled() const noexcept
Definition types.h:617
constexpr bool isLatexEnabled() const noexcept
Definition types.h:615
constexpr int htmlLevel() const noexcept
Definition types.h:619
constexpr bool isHtmlEnabled() const noexcept
Definition types.h:614
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:279
Class representing a list of output generators that are written to in parallel.
Definition outputlist.h:315
void writeString(const QCString &text)
Definition outputlist.h:411
void startTocEntry(const SectionInfo *si)
Definition outputlist.h:748
const OutputCodeList & codeGenerators() const
Definition outputlist.h:358
void writeObjectLink(const QCString &ref, const QCString &file, const QCString &anchor, const QCString &name)
Definition outputlist.h:439
void docify(const QCString &s)
Definition outputlist.h:437
void generateDoc(const QCString &fileName, int startLine, const Definition *ctx, const MemberDef *md, const QCString &docStr, const DocOptions &options)
void startParagraph(const QCString &classDef=QCString())
Definition outputlist.h:407
void endParagraph()
Definition outputlist.h:409
void pushGeneratorState()
void endLocalToc()
Definition outputlist.h:746
void disableAllBut(OutputType o)
void popGeneratorState()
void endTocEntry(const SectionInfo *si)
Definition outputlist.h:750
void writeNavigationPath(const QCString &s)
Definition outputlist.h:608
void parseText(const QCString &textStr)
void startLocalToc(int level)
Definition outputlist.h:744
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
QCString & prepend(const char *s)
Definition qcstring.h:422
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:166
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:241
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:593
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:260
void resize(size_t newlen)
Definition qcstring.h:180
QCString fill(char c, int len=-1)
Fills a string with a predefined character.
Definition qcstring.h:193
const std::string & str() const
Definition qcstring.h:552
QCString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple whitespace cha...
Definition qcstring.cpp:190
QCString right(size_t len) const
Definition qcstring.h:234
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:96
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:172
QCString left(size_t len) const
Definition qcstring.h:229
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:58
QCString label() const
Definition section.h:69
QCString ref() const
Definition section.h:72
void setDefinition(Definition *d)
Definition section.h:83
QCString fileName() const
Definition section.h:74
bool generated() const
Definition section.h:75
QCString title() const
Definition section.h:70
SectionType type() const
Definition section.h:71
singleton class that owns the list of all sections
Definition section.h:135
SectionInfo * add(const SectionInfo &si)
Definition section.h:139
static SectionManager & instance()
returns a reference to the singleton
Definition section.h:179
class that represents a list of constant references to sections.
Definition section.h:103
constexpr bool isSection() const
Definition section.h:47
constexpr int level() 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:151
#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:1966
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:659
FILE * popen(const QCString &name, const QCString &type)
Definition portable.cpp:479
FILE * fopen(const QCString &fileName, const QCString &mode)
Definition portable.cpp:349
int pclose(FILE *stream)
Definition portable.cpp:488
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:844
PageDef * toPageDef(Definition *d)
Definition pagedef.cpp:502
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:571
#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
void splitRequirementRefs(const RequirementRefs &inputReqRefs, RequirementRefs &satisfiesRefs, RequirementRefs &verifiesRefs)
std::vector< RequirementRef > RequirementRefs
List of requirement references.
Definition requirement.h:56
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:64
int startLine
line number of the start of the definition's body
Definition definition.h:66
int endLine
line number of the end of the definition's body
Definition definition.h:67
int defLine
line number of the start of the definition
Definition definition.h:65
Data associated with a brief description.
Definition definition.h:55
QCString file
Definition definition.h:59
QCString doc
Definition definition.h:56
Options to configure the code parser.
Definition parserintf.h:78
CodeParserOptions & setStartLine(int lineNr)
Definition parserintf.h:101
CodeParserOptions & setInlineFragment(bool enable)
Definition parserintf.h:107
CodeParserOptions & setEndLine(int lineNr)
Definition parserintf.h:104
CodeParserOptions & setMemberDef(const MemberDef *md)
Definition parserintf.h:110
Data associated with a detailed description.
Definition definition.h:47
QCString doc
Definition definition.h:48
int line
Definition definition.h:49
QCString file
Definition definition.h:50
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:5193
QCString parseCommentAsHtml(const Definition *scope, const MemberDef *member, const QCString &doc, const QCString &fileName, int lineNr)
Definition util.cpp:5407
QCString convertToHtml(const QCString &s, bool keepEntities)
Definition util.cpp:3946
QCString parseCommentAsText(const Definition *scope, const MemberDef *md, const QCString &doc, const QCString &fileName, int lineNr)
Definition util.cpp:5351
bool transcodeCharacterStringToUTF8(std::string &input, const char *inputEncoding)
Definition util.cpp:1435
QCString stripScope(const QCString &name)
Definition util.cpp:3762
int computeQualifiedIndex(const QCString &name)
Return the index of the last :: in the string name that is still before the first <.
Definition util.cpp:6826
QCString convertToXML(const QCString &s, bool keepEntities)
Definition util.cpp:3895
QCString detab(const QCString &s, size_t &refIndent)
Definition util.cpp:6722
QCString getLanguageSpecificSeparator(SrcLangExt lang, bool classScope)
Returns the scope separator to use given the programming language lang.
Definition util.cpp:5899
QCString getEncoding(const FileInfo &fi)
Definition util.cpp:5693
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5012
QCString getFileFilter(const QCString &name, bool isSourceCode)
Definition util.cpp:1401
void writeMarkerList(OutputList &ol, const std::string &markerText, size_t numMarkers, std::function< void(size_t)> replaceFunc)
Definition util.cpp:1108
void addHtmlExtensionIfMissing(QCString &fName)
Definition util.cpp:4904
A bunch of utility functions.
bool isId(int c)
Definition util.h:208