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