Doxygen
Loading...
Searching...
No Matches
tagreader.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 "tagreader.h"
17
18#include <map>
19#include <functional>
20#include <utility>
21#include <algorithm>
22#include <variant>
23
24#include <assert.h>
25#include <stdio.h>
26#include <stdarg.h>
27
28#include "xml.h"
29#include "entry.h"
30#include "doxygen.h"
31#include "util.h"
32#include "message.h"
33#include "defargs.h"
34#include "arguments.h"
35#include "filedef.h"
36#include "filename.h"
37#include "section.h"
38#include "containers.h"
39#include "debug.h"
40#include "anchor.h"
41#include "moduledef.h"
42#include "construct.h"
43
44// ----------------- private part -----------------------------------------------
45
46namespace {
47
48/** Information about an linkable anchor */
50{
51 public:
53 const QCString &l,
54 const QCString &t=QCString())
55 : label(l), fileName(f), title(t) {}
59};
60
61/** Container for enum values that are scoped within an enum */
70
71/** Container for include info that can be read from a tagfile */
83
84/** Container for member specific info that can be read from a tagfile */
86{
87 public:
95 std::vector<TagAnchorInfo> docAnchors;
96 Protection prot = Protection::Public;
97 Specifier virt = Specifier::Normal;
98 bool isStatic = false;
99 std::vector<TagEnumValueInfo> enumValues;
101};
102
103/** Base class for all compound types */
105{
106 std::vector<TagMemberInfo> members;
109 std::vector<TagAnchorInfo> docAnchors;
110 int lineNr = 0;
111};
112
113
114/** Container for class specific info that can be read from a tagfile */
127
128using TagClassInfoPtr = std::unique_ptr<TagClassInfo>;
129
130/** Container for concept specific info that can be read from a tagfile */
131struct TagConceptInfo final : public TagCompoundInfo
132{
134};
135
136using TagConceptInfoPtr = std::unique_ptr<TagConceptInfo>;
137
138/** Container for module specific info that can be read from a tagfile */
139struct TagModuleInfo final : public TagCompoundInfo
140{
142};
143
144using TagModuleInfoPtr = std::unique_ptr<TagModuleInfo>;
145
146
147/** Container for namespace specific info that can be read from a tagfile */
155
156using TagNamespaceInfoPtr = std::unique_ptr<TagNamespaceInfo>;
157
158/** Container for package specific info that can be read from a tagfile */
163
164using TagPackageInfoPtr = std::unique_ptr<TagPackageInfo>;
165
166/** Container for file specific info that can be read from a tagfile */
175
176using TagFileInfoPtr = std::unique_ptr<TagFileInfo>;
177
178/** Container for group specific info that can be read from a tagfile */
191
192using TagGroupInfoPtr = std::unique_ptr<TagGroupInfo>;
193
194/** Container for page specific info that can be read from a tagfile */
200
201using TagPageInfoPtr = std::unique_ptr<TagPageInfo>;
202
203/** Container for directory specific info that can be read from a tagfile */
210
211using TagDirInfoPtr = std::unique_ptr<TagDirInfo>;
212
213/** Container for requirement specific info that can be read from a tagfile */
220
221using TagRequirementInfoPtr = std::unique_ptr<TagRequirementInfo>;
222
223/** Variant class that holds a unique pointer to one of the specific container types */
225{
226 public:
227 using VariantT = std::variant< std::monostate, // 0
228 TagClassInfoPtr, // 1
232 TagFileInfoPtr, // 5
233 TagGroupInfoPtr, // 6
234 TagPageInfoPtr, // 7
235 TagDirInfoPtr, // 8
236 TagModuleInfoPtr, // 9
238
239 enum class Type : uint8_t
240 {
241 Uninitialized = 0,
242 Class = 1,
246 File = 5,
247 Group = 6,
248 Page = 7,
249 Dir = 8,
252 };
253
255 explicit TagCompoundVariant(VariantT &&v) : m_variant(std::move(v)) {}
257
258 /** Generic non-const getter */
259 template<class R>
260 R *get()
261 {
262 std::unique_ptr<R> *p = std::get_if<std::unique_ptr<R>>(&m_variant);
263 return p ? p->get() : nullptr;
264 }
265 /** Generic const getter */
266 template<class R>
267 const R *get() const
268 {
269 const std::unique_ptr<R> *p = std::get_if<std::unique_ptr<R>>(&m_variant);
270 return p ? p->get() : nullptr;
271 }
272
273 /** Generic factory method to create a variant holding a unique pointer to a given compound type */
274 template<class R,typename... Args>
275 static TagCompoundVariant make(Args&&... args)
276 {
277 return TagCompoundVariant(VariantT(std::make_unique<R>(std::forward<Args>(args)...)));
278 }
279
280 /** @name convenience const and non-const getters for each variant component
281 * @{
282 */
284 const TagClassInfo *getClassInfo() const { return get<TagClassInfo >(); }
292 const TagFileInfo *getFileInfo() const { return get<TagFileInfo >(); }
294 const TagGroupInfo *getGroupInfo() const { return get<TagGroupInfo >(); }
296 const TagPageInfo *getPageInfo() const { return get<TagPageInfo >(); }
298 const TagDirInfo *getDirInfo() const { return get<TagDirInfo >(); }
303 /** @} */
304
305 /** Convenience method to get the shared compound info */
307 {
308 switch(type())
309 {
310 case Type::Uninitialized: return nullptr;
311 case Type::Class: return getClassInfo();
312 case Type::Concept: return getConceptInfo();
313 case Type::Namespace: return getNamespaceInfo();
314 case Type::Package: return getPackageInfo();
315 case Type::File: return getFileInfo();
316 case Type::Group: return getGroupInfo();
317 case Type::Page: return getPageInfo();
318 case Type::Dir: return getDirInfo();
319 case Type::Module: return getModuleInfo();
321 }
322 return nullptr;
323 }
324 Type type() const
325 {
326 return static_cast<Type>(m_variant.index());
327 }
328
329 private:
331};
332
333
334/** Tag file parser.
335 *
336 * Reads an XML-structured tagfile and builds up the structure in
337 * memory. The method buildLists() is used to transfer/translate
338 * the structures to the doxygen engine.
339 */
341{
342#define p_warn(fmt,...) do { \
343 warn(m_locator->fileName(),m_locator->lineNr(),fmt,##__VA_ARGS__); \
344 } while(0)
345
346 public:
347
348 explicit TagFileParser(const char *tagName) : m_tagName(tagName) {}
349
350 void setDocumentLocator ( const XMLLocator * locator )
351 {
352 m_locator = locator;
353 }
354
356 {
358 }
359
360 void startElement( const QCString &name, const XMLHandlers::Attributes& attrib );
361 void endElement( const QCString &name );
362 void characters ( const QCString & ch ) { m_curString+=ch; }
363 void error( const QCString &fileName,int lineNr,const QCString &msg)
364 {
365 warn(fileName,lineNr,"{}",msg);
366 }
367
368 void dump();
369 void buildLists(const std::shared_ptr<Entry> &root);
370 void addIncludes();
371 void startCompound( const XMLHandlers::Attributes& attrib );
372
374 {
375 switch (m_state)
376 {
377 case InClass:
378 case InConcept:
379 case InFile:
380 case InNamespace:
381 case InGroup:
382 case InPage:
383 case InDir:
384 case InRequirement:
385 case InModule:
386 case InPackage:
387 m_tagFileCompounds.push_back(std::move(m_curCompound));
388 break;
389 default:
390 p_warn("tag 'compound' was not expected!");
391 break;
392 }
393 }
394
396 {
398 m_curMember.kind = XMLHandlers::value(attrib,"kind");
399 QCString protStr = XMLHandlers::value(attrib,"protection");
400 QCString virtStr = XMLHandlers::value(attrib,"virtualness");
401 QCString staticStr = XMLHandlers::value(attrib,"static");
402 QCString typeStr = XMLHandlers::value(attrib,"type");
403 m_curMember.lineNr = m_locator->lineNr();
404 if (protStr=="protected")
405 {
406 m_curMember.prot = Protection::Protected;
407 }
408 else if (protStr=="private")
409 {
410 m_curMember.prot = Protection::Private;
411 }
412 if (virtStr=="virtual")
413 {
414 m_curMember.virt = Specifier::Virtual;
415 }
416 else if (virtStr=="pure")
417 {
418 m_curMember.virt = Specifier::Pure;
419 }
420 if (staticStr=="yes")
421 {
422 m_curMember.isStatic = TRUE;
423 }
424 if (!typeStr.isEmpty())
425 {
426 m_curMember.type = typeStr;
427 }
428 m_stateStack.push(m_state);
430 }
431
433 {
434 m_state = m_stateStack.top();
435 m_stateStack.pop();
436 switch(m_state)
437 {
438 case InClass:
439 case InFile:
440 case InNamespace:
441 case InGroup:
442 case InPackage:
443 {
444 TagCompoundInfo *info = m_curCompound.getCompoundInfo();
445 if (info)
446 {
447 info->members.push_back(m_curMember);
448 }
449 }
450 break;
451 default:
452 p_warn("Unexpected tag 'member' found");
453 break;
454 }
455 }
456
458 {
459 if (m_state==InMember)
460 {
461 m_curString = "";
463 m_curEnumValue.file = XMLHandlers::value(attrib,"file");
464 m_curEnumValue.anchor = XMLHandlers::value(attrib,"anchor");
465 m_curEnumValue.clangid = XMLHandlers::value(attrib,"clangid");
466 m_stateStack.push(m_state);
468 }
469 else
470 {
471 p_warn("Found 'enumvalue' tag outside of member tag");
472 }
473 }
474
476 {
478 m_state = m_stateStack.top();
479 m_stateStack.pop();
480 if (m_state==InMember)
481 {
482 m_curMember.enumValues.push_back(m_curEnumValue);
484 }
485 }
486
488 {
489 // Check whether or not the tag is automatically generate, in that case ignore the tag.
490 switch(m_state)
491 {
492 case InClass:
493 case InConcept:
494 case InFile:
495 case InNamespace:
496 case InGroup:
497 case InPage:
498 case InMember:
499 case InPackage:
500 case InDir:
501 case InModule:
503 break;
504 default:
505 p_warn("Unexpected tag 'docanchor' found");
506 return;
507 }
508 switch(m_state)
509 {
510 case InClass:
511 case InConcept:
512 case InFile:
513 case InNamespace:
514 case InGroup:
515 case InPage:
516 case InPackage:
517 case InDir:
518 case InModule:
519 {
520 TagCompoundInfo *info = m_curCompound.getCompoundInfo();
521 if (info)
522 {
523 info->docAnchors.emplace_back(m_fileName,m_curString,m_title);
524 }
525 }
526 break;
527 case InMember:
528 m_curMember.docAnchors.emplace_back(m_fileName,m_curString,m_title);
529 break;
530 default: break; // will not be reached
531 }
532 }
533
534 void endClass()
535 {
536 switch(m_state)
537 {
538 case InClass:
539 {
540 TagClassInfo *info = m_curCompound.getClassInfo();
541 if (info) info->classList.push_back(m_curString.str());
542 }
543 break;
544 case InFile:
545 {
546 TagFileInfo *info = m_curCompound.getFileInfo();
547 if (info) info->classList.push_back(m_curString.str());
548 }
549 break;
550 case InNamespace:
551 {
552 TagNamespaceInfo *info = m_curCompound.getNamespaceInfo();
553 if (info) info->classList.push_back(m_curString.str());
554 }
555 break;
556 case InGroup:
557 {
558 TagGroupInfo *info = m_curCompound.getGroupInfo();
559 if (info) info->classList.push_back(m_curString.str());
560 }
561 break;
562 case InPackage:
563 {
564 TagPackageInfo *info = m_curCompound.getPackageInfo();
565 if (info) info->classList.push_back(m_curString.str());
566 }
567 break;
568 default:
569 p_warn("Unexpected tag 'class' found");
570 break;
571 }
572 }
573
575 {
576 switch(m_state)
577 {
578 case InNamespace:
579 {
580 TagNamespaceInfo *info = m_curCompound.getNamespaceInfo();
581 if (info) info->conceptList.push_back(m_curString.str());
582 }
583 break;
584 case InFile:
585 {
586 TagFileInfo *info = m_curCompound.getFileInfo();
587 if (info) info->conceptList.push_back(m_curString.str());
588 }
589 break;
590 case InGroup:
591 {
592 TagGroupInfo *info = m_curCompound.getGroupInfo();
593 if (info) info->conceptList.push_back(m_curString.str());
594 }
595 break;
596 default:
597 p_warn("Unexpected tag 'concept' found");
598 break;
599 }
600 }
601
603 {
604 switch(m_state)
605 {
606 case InGroup:
607 {
608 TagGroupInfo *info = m_curCompound.getGroupInfo();
609 if (info) info->moduleList.push_back(m_curString.str());
610 }
611 break;
612 default:
613 p_warn("Unexpected tag 'module' found");
614 break;
615 }
616 }
617
619 {
620 switch(m_state)
621 {
622 case InNamespace:
623 {
624 TagNamespaceInfo *info = m_curCompound.getNamespaceInfo();
625 if (info) info->namespaceList.push_back(m_curString.str());
626 }
627 break;
628 case InFile:
629 {
630 TagFileInfo *info = m_curCompound.getFileInfo();
631 if (info) info->namespaceList.push_back(m_curString.str());
632 }
633 break;
634 case InGroup:
635 {
636 TagGroupInfo *info = m_curCompound.getGroupInfo();
637 if (info) info->namespaceList.push_back(m_curString.str());
638 }
639 break;
640 default:
641 p_warn("Unexpected tag 'namespace' found");
642 break;
643 }
644 }
645
646 void endFile()
647 {
648 switch(m_state)
649 {
650 case InGroup:
651 {
652 TagGroupInfo *info = m_curCompound.getGroupInfo();
653 if (info) info->fileList.push_back(m_curString.str());
654 }
655 break;
656 case InDir:
657 {
658 TagDirInfo *info = m_curCompound.getDirInfo();
659 if (info) info->fileList.push_back(m_curString.str());
660 }
661 break;
662 default:
663 p_warn("Unexpected tag 'file' found");
664 break;
665 }
666 }
667
668 void endPage()
669 {
670 switch(m_state)
671 {
672 case InGroup:
673 {
674 TagGroupInfo *info = m_curCompound.getGroupInfo();
675 if (info) info->fileList.push_back(m_curString.str());
676 }
677 break;
678 default:
679 p_warn("Unexpected tag 'page' found");
680 break;
681 }
682 }
683
685 {
686 switch(m_state)
687 {
688 case InPage:
689 {
690 TagPageInfo *info = m_curCompound.getPageInfo();
691 if (info) info->subpages.push_back(m_curString.str());
692 }
693 break;
694 default:
695 p_warn("Unexpected tag 'subpage' found");
696 break;
697 }
698 }
699
700 void endDir()
701 {
702 switch(m_state)
703 {
704 case InDir:
705 {
706 TagDirInfo *info = m_curCompound.getDirInfo();
707 if (info) info->subdirList.push_back(m_curString.str());
708 }
709 break;
710 default:
711 p_warn("Unexpected tag 'dir' found");
712 break;
713 }
714 }
715
717 {
718 m_curString = "";
719 }
720
722 {
723 m_fileName = XMLHandlers::value(attrib,"file");
724 m_title = XMLHandlers::value(attrib,"title");
725 m_curString = "";
726 }
727
728 void endType()
729 {
730 if (m_state==InMember)
731 {
733 }
734 else
735 {
736 p_warn("Unexpected tag 'type' found");
737 }
738 }
739
740 void endName()
741 {
742 switch (m_state)
743 {
744 case InClass:
745 case InConcept:
746 case InFile:
747 case InNamespace:
748 case InGroup:
749 case InPage:
750 case InDir:
751 case InPackage:
752 case InModule:
753 {
754 TagCompoundInfo *info = m_curCompound.getCompoundInfo();
755 if (info) info->name = m_curString;
756 }
757 break;
758 case InMember:
760 break;
761 default:
762 p_warn("Unexpected tag 'name' found");
763 break;
764 }
765 }
766
767 void endId()
768 {
769 switch (m_state)
770 {
771 case InRequirement:
772 {
773 TagRequirementInfo *info = m_curCompound.getRequirementInfo();
774 if (info) info->id = m_curString;
775 }
776 break;
777 default:
778 p_warn("Unexpected tag 'id' found");
779 break;
780 }
781 }
782
784 {
785 m_curString="";
786 TagClassInfo *info = m_curCompound.getClassInfo();
787 if (m_state==InClass && info)
788 {
789 QCString protStr = XMLHandlers::value(attrib,"protection");
790 QCString virtStr = XMLHandlers::value(attrib,"virtualness");
791 Protection prot = Protection::Public;
792 Specifier virt = Specifier::Normal;
793 if (protStr=="protected")
794 {
795 prot = Protection::Protected;
796 }
797 else if (protStr=="private")
798 {
799 prot = Protection::Private;
800 }
801 if (virtStr=="virtual")
802 {
803 virt = Specifier::Virtual;
804 }
805 info->bases.emplace_back(m_curString,prot,virt);
806 }
807 else
808 {
809 p_warn("Unexpected tag 'base' found");
810 }
811 }
812
813 void endBase()
814 {
815 TagClassInfo *info = m_curCompound.getClassInfo();
816 if (m_state==InClass && info)
817 {
818 info->bases.back().name = m_curString;
819 }
820 else
821 {
822 p_warn("Unexpected tag 'base' found");
823 }
824 }
825
827 {
829 m_curIncludes.id = XMLHandlers::value(attrib,"id");
830 m_curIncludes.name = XMLHandlers::value(attrib,"name");
831 m_curIncludes.isLocal = XMLHandlers::value(attrib,"local")=="yes";
832 m_curIncludes.isImported = XMLHandlers::value(attrib,"imported")=="yes";
833 m_curIncludes.isModule = XMLHandlers::value(attrib,"module")=="yes";
834 m_curIncludes.isObjC = XMLHandlers::value(attrib,"objc")=="yes";
835 m_curString="";
836 }
837
839 {
841 TagFileInfo *info = m_curCompound.getFileInfo();
842 if (m_state==InFile && info)
843 {
844 info->includes.push_back(m_curIncludes);
845 }
846 else
847 {
848 p_warn("Unexpected tag 'includes' found");
849 }
850 }
851
853 {
854 TagClassInfo *info = m_curCompound.getClassInfo();
855 if (m_state==InClass && info)
856 {
857 info->templateArguments.push_back(m_curString.str());
858 }
859 else
860 {
861 p_warn("Unexpected tag 'templarg' found");
862 }
863 }
864
866 {
867 switch (m_state)
868 {
869 case InClass:
870 case InConcept:
871 case InNamespace:
872 case InFile:
873 case InGroup:
874 case InPage:
875 case InPackage:
876 case InDir:
877 case InRequirement:
878 case InModule:
879 {
880 TagCompoundInfo *info = m_curCompound.getCompoundInfo();
881 if (info) info->filename = m_curString;
882 }
883 break;
884 default:
885 p_warn("Unexpected tag 'filename' found");
886 break;
887 }
888 }
889
890 void endPath()
891 {
892 switch (m_state)
893 {
894 case InFile:
895 {
896 TagFileInfo *info = m_curCompound.getFileInfo();
897 if (info) info->path = m_curString;
898 }
899 break;
900 case InDir:
901 {
902 TagDirInfo *info = m_curCompound.getDirInfo();
903 if (info) info->path = m_curString;
904 }
905 break;
906 default:
907 p_warn("Unexpected tag 'path' found");
908 break;
909 }
910 }
911
913 {
914 if (m_state==InMember)
915 {
916 m_curMember.anchor = m_curString;
917 }
918 else if (m_state==InClass)
919 {
920 TagClassInfo *info = m_curCompound.getClassInfo();
921 if (info) info->anchor = m_curString;
922 }
923 else
924 {
925 p_warn("Unexpected tag 'anchor' found");
926 }
927 }
928
930 {
931 if (m_state==InMember)
932 {
933 m_curMember.clangId = m_curString;
934 }
935 else if (m_state==InClass)
936 {
937 TagClassInfo *info = m_curCompound.getClassInfo();
938 if (info) info->clangId = m_curString;
939 }
940 else if (m_state==InNamespace)
941 {
942 TagNamespaceInfo *info = m_curCompound.getNamespaceInfo();
943 if (info) info->clangId = m_curString;
944 }
945 else
946 {
947 p_warn("Unexpected tag 'clangid' found");
948 }
949 }
950
951
952
954 {
955 if (m_state==InMember)
956 {
957 m_curMember.anchorFile = m_curString;
958 }
959 else
960 {
961 p_warn("Unexpected tag 'anchorfile' found");
962 }
963 }
964
966 {
967 if (m_state==InMember)
968 {
969 m_curMember.arglist = m_curString;
970 }
971 else
972 {
973 p_warn("Unexpected tag 'arglist' found");
974 }
975 }
976
977 void endTitle()
978 {
979 switch (m_state)
980 {
981 case InGroup:
982 {
983 TagGroupInfo *info = m_curCompound.getGroupInfo();
984 if (info) info->title = m_curString;
985 }
986 break;
987 case InPage:
988 {
989 TagPageInfo *info = m_curCompound.getPageInfo();
990 if (info) info->title = m_curString;
991 }
992 break;
993 case InRequirement:
994 {
995 TagRequirementInfo *info = m_curCompound.getRequirementInfo();
996 if (info) info->title = m_curString;
997 }
998 break;
999 default:
1000 p_warn("Unexpected tag 'title' found");
1001 break;
1002 }
1003 }
1004
1006 {
1007 if (m_state==InGroup)
1008 {
1009 TagGroupInfo *info = m_curCompound.getGroupInfo();
1010 if (info) info->subgroupList.push_back(m_curString.str());
1011 }
1012 else
1013 {
1014 p_warn("Unexpected tag 'subgroup' found");
1015 }
1016 }
1017
1019 {
1020 }
1021
1023 {
1024 }
1025
1026 void buildMemberList(const std::shared_ptr<Entry> &ce,const std::vector<TagMemberInfo> &members);
1027 void addDocAnchors(const std::shared_ptr<Entry> &e,const std::vector<TagAnchorInfo> &l);
1028
1029
1044 };
1045 private:
1046
1048 {
1049 ClassNode(const std::string &n) : name(n) {}
1050 std::string name;
1051 const TagClassInfo *tci = nullptr;
1052 std::unordered_map<std::string,std::unique_ptr<ClassNode>> children;
1053 };
1054
1055 void buildClassEntry(const std::shared_ptr<Entry> &root, const TagClassInfo *tci);
1056 void buildClassTree(const std::shared_ptr<Entry> &root, const ClassNode &node);
1057 //------------------------------------
1058
1059 std::vector< TagCompoundVariant > m_tagFileCompounds;
1061
1065
1071 std::stack<State> m_stateStack;
1072 const XMLLocator *m_locator = nullptr;
1073};
1074
1075//---------------------------------------------------------------------------------------------------------------
1076
1078{
1079 using StartCallback = std::function<void(TagFileParser&,const XMLHandlers::Attributes&)>;
1080 using EndCallback = std::function<void(TagFileParser&)>;
1081
1084};
1085
1087{
1088 return [fn](TagFileParser &parser,const XMLHandlers::Attributes &attr) { (parser.*fn)(attr); };
1089}
1090
1092{
1093 return [fn](TagFileParser &parser) { (parser.*fn)(); };
1094}
1095
1096static const std::map< std::string, ElementCallbacks > g_elementHandlers =
1097{
1098 // name, start element callback, end element callback
1126};
1127
1128//---------------------------------------------------------------------------------------------------------------
1129
1137
1138static const std::map< std::string, CompoundFactory > g_compoundFactory =
1139{
1140 // kind tag state creation function
1151 { "file", { TagFileParser::InFile, []() { return TagCompoundVariant::make<TagFileInfo>(); } } },
1152 { "namespace", { TagFileParser::InNamespace, []() { return TagCompoundVariant::make<TagNamespaceInfo>(); } } },
1153 { "concept", { TagFileParser::InConcept, []() { return TagCompoundVariant::make<TagConceptInfo>(); } } },
1154 { "module", { TagFileParser::InModule, []() { return TagCompoundVariant::make<TagModuleInfo>(); } } },
1155 { "group", { TagFileParser::InGroup, []() { return TagCompoundVariant::make<TagGroupInfo>(); } } },
1156 { "page", { TagFileParser::InPage, []() { return TagCompoundVariant::make<TagPageInfo>(); } } },
1157 { "package", { TagFileParser::InPackage, []() { return TagCompoundVariant::make<TagPackageInfo>(); } } },
1158 { "dir", { TagFileParser::InDir, []() { return TagCompoundVariant::make<TagDirInfo>(); } } },
1159 { "requirement", { TagFileParser::InRequirement, []() { return TagCompoundVariant::make<TagRequirementInfo>(); } } }
1160};
1161
1162//---------------------------------------------------------------------------------------------------------------
1163
1165{
1166 //printf("startElement '%s'\n",qPrint(name));
1167 auto it = g_elementHandlers.find(name.str());
1168 if (it!=std::end(g_elementHandlers))
1169 {
1170 it->second.startCb(*this,attrib);
1171 }
1172 else
1173 {
1174 p_warn("Unknown start tag '{}' found!",name);
1175 }
1176}
1177
1179{
1180 //printf("endElement '%s'\n",qPrint(name));
1181 auto it = g_elementHandlers.find(name.str());
1182 if (it!=std::end(g_elementHandlers))
1183 {
1184 it->second.endCb(*this);
1185 }
1186 else
1187 {
1188 p_warn("Unknown end tag '{}' found!",name);
1189 }
1190}
1191
1193{
1194 m_curString = "";
1195 std::string kind = XMLHandlers::value(attrib,"kind");
1196 std::string isObjC = XMLHandlers::value(attrib,"objc");
1197
1198 auto it = g_compoundFactory.find(kind);
1199 if (it!=g_compoundFactory.end())
1200 {
1201 m_curCompound = it->second.make_instance();
1202 m_state = it->second.state;
1203 TagCompoundInfo *info = m_curCompound.getCompoundInfo();
1204 if (info) info->lineNr = m_locator->lineNr();
1205 }
1206 else
1207 {
1208 p_warn("Unknown compound attribute '{}' found!",kind);
1209 m_state = Invalid;
1210 }
1211
1212 TagClassInfo *classInfo = m_curCompound.getClassInfo();
1213 if (isObjC=="yes" && classInfo)
1214 {
1215 classInfo->isObjC = TRUE;
1216 }
1217}
1218
1219/*! Dumps the internal structures. For debugging only! */
1221{
1222 Debug::print(Debug::Tag,0,"-------- Results --------\n");
1223 //============== CLASSES
1224 for (const auto &comp : m_tagFileCompounds)
1225 {
1226 if (comp.type()==TagCompoundVariant::Type::Class)
1227 {
1228 const TagClassInfo *cd = comp.getClassInfo();
1229 Debug::print(Debug::Tag,0,"class '{}'\n",cd->name);
1230 Debug::print(Debug::Tag,0," filename '{}'\n",cd->filename);
1231 for (const BaseInfo &bi : cd->bases)
1232 {
1233 Debug::print(Debug::Tag,0, " base: {}\n",bi.name);
1234 }
1235
1236 for (const auto &md : cd->members)
1237 {
1238 Debug::print(Debug::Tag,0," member:\n");
1239 Debug::print(Debug::Tag,0," kind: '{}'\n",md.kind);
1240 Debug::print(Debug::Tag,0," name: '{}'\n",md.name);
1241 Debug::print(Debug::Tag,0," anchor: '{}'\n",md.anchor);
1242 Debug::print(Debug::Tag,0," arglist: '{}'\n",md.arglist);
1243 }
1244 }
1245 }
1246 //============== CONCEPTS
1247 for (const auto &comp : m_tagFileCompounds)
1248 {
1249 if (comp.type()==TagCompoundVariant::Type::Concept)
1250 {
1251 const TagConceptInfo *cd = comp.getConceptInfo();
1252
1253 Debug::print(Debug::Tag,0,"concept '{}'\n",cd->name);
1254 Debug::print(Debug::Tag,0," filename '{}'\n",cd->filename);
1255 }
1256 }
1257 //============== MODULES
1258 for (const auto &comp : m_tagFileCompounds)
1259 {
1260 if (comp.type()==TagCompoundVariant::Type::Module)
1261 {
1262 const TagModuleInfo *mi = comp.getModuleInfo();
1263
1264 Debug::print(Debug::Tag,0,"module '{}'\n",mi->name);
1265 Debug::print(Debug::Tag,0," filename '{}'\n",mi->filename);
1266 }
1267 }
1268 //============== NAMESPACES
1269 for (const auto &comp : m_tagFileCompounds)
1270 {
1271 if (comp.type()==TagCompoundVariant::Type::Namespace)
1272 {
1273 const TagNamespaceInfo *nd = comp.getNamespaceInfo();
1274
1275 Debug::print(Debug::Tag,0,"namespace '{}'\n",nd->name);
1276 Debug::print(Debug::Tag,0," filename '{}'\n",nd->filename);
1277 for (const auto &cls : nd->classList)
1278 {
1279 Debug::print(Debug::Tag,0, " class: {}\n",cls);
1280 }
1281
1282 for (const auto &md : nd->members)
1283 {
1284 Debug::print(Debug::Tag,0," member:\n");
1285 Debug::print(Debug::Tag,0," kind: '{}'\n",md.kind);
1286 Debug::print(Debug::Tag,0," name: '{}'\n",md.name);
1287 Debug::print(Debug::Tag,0," anchor: '{}'\n",md.anchor);
1288 Debug::print(Debug::Tag,0," arglist: '{}'\n",md.arglist);
1289 }
1290 }
1291 }
1292
1293 //============== FILES
1294 for (const auto &comp : m_tagFileCompounds)
1295 {
1296 if (comp.type()==TagCompoundVariant::Type::File)
1297 {
1298 const TagFileInfo *fd = comp.getFileInfo();
1299
1300 Debug::print(Debug::Tag,0,"file '{}'\n",fd->name);
1301 Debug::print(Debug::Tag,0," filename '{}'\n",fd->filename);
1302 for (const auto &ns : fd->namespaceList)
1303 {
1304 Debug::print(Debug::Tag,0, " namespace: {}\n",ns);
1305 }
1306 for (const auto &cs : fd->classList)
1307 {
1308 Debug::print(Debug::Tag,0, " class: {} \n",cs);
1309 }
1310
1311 for (const auto &md : fd->members)
1312 {
1313 Debug::print(Debug::Tag,0," member:\n");
1314 Debug::print(Debug::Tag,0," kind: '{}'\n",md.kind);
1315 Debug::print(Debug::Tag,0," name: '{}'\n",md.name);
1316 Debug::print(Debug::Tag,0," anchor: '{}'\n",md.anchor);
1317 Debug::print(Debug::Tag,0," arglist: '{}'\n",md.arglist);
1318 }
1319
1320 for (const auto &ii : fd->includes)
1321 {
1322 Debug::print(Debug::Tag,0," includes id: {} name: {}\n",ii.id,ii.name);
1323 }
1324 }
1325 }
1326
1327 //============== GROUPS
1328 for (const auto &comp : m_tagFileCompounds)
1329 {
1330 if (comp.type()==TagCompoundVariant::Type::Group)
1331 {
1332 const TagGroupInfo *gd = comp.getGroupInfo();
1333 Debug::print(Debug::Tag,0,"group '{}'\n",gd->name);
1334 Debug::print(Debug::Tag,0," filename '{}'\n",gd->filename);
1335
1336 for (const auto &ns : gd->namespaceList)
1337 {
1338 Debug::print(Debug::Tag,0, " namespace: {}\n",ns);
1339 }
1340 for (const auto &cs : gd->classList)
1341 {
1342 Debug::print(Debug::Tag,0, " class: {}\n",cs);
1343 }
1344 for (const auto &fi : gd->fileList)
1345 {
1346 Debug::print(Debug::Tag,0, " file: {}\n",fi);
1347 }
1348 for (const auto &sg : gd->subgroupList)
1349 {
1350 Debug::print(Debug::Tag,0, " subgroup: {}\n",sg);
1351 }
1352 for (const auto &pg : gd->pageList)
1353 {
1354 Debug::print(Debug::Tag,0, " page: {}\n",pg);
1355 }
1356
1357 for (const auto &md : gd->members)
1358 {
1359 Debug::print(Debug::Tag,0," member:\n");
1360 Debug::print(Debug::Tag,0," kind: '{}'\n",md.kind);
1361 Debug::print(Debug::Tag,0," name: '{}'\n",md.name);
1362 Debug::print(Debug::Tag,0," anchor: '{}'\n",md.anchor);
1363 Debug::print(Debug::Tag,0," arglist: '{}'\n",md.arglist);
1364 }
1365 }
1366 }
1367
1368 //============== PAGES
1369 for (const auto &comp : m_tagFileCompounds)
1370 {
1371 if (comp.type()==TagCompoundVariant::Type::Page)
1372 {
1373 const TagPageInfo *pd = comp.getPageInfo();
1374 Debug::print(Debug::Tag,0,"page '{}'\n",pd->name);
1375 Debug::print(Debug::Tag,0," title '{}'\n",pd->title);
1376 Debug::print(Debug::Tag,0," filename '{}'\n",pd->filename);
1377 }
1378 }
1379
1380 //============== DIRS
1381 for (const auto &comp : m_tagFileCompounds)
1382 {
1383 if (comp.type()==TagCompoundVariant::Type::Dir)
1384 {
1385 const TagDirInfo *dd = comp.getDirInfo();
1386 {
1387 Debug::print(Debug::Tag,0,"dir '{}'\n",dd->name);
1388 Debug::print(Debug::Tag,0," path '{}'\n",dd->path);
1389 for (const auto &fi : dd->fileList)
1390 {
1391 Debug::print(Debug::Tag,0, " file: {}\n",fi);
1392 }
1393 for (const auto &sd : dd->subdirList)
1394 {
1395 Debug::print(Debug::Tag,0, " subdir: {}\n",sd);
1396 }
1397 }
1398 }
1399 }
1400
1401 //============== REQUIREMENTS
1402 for (const auto &comp : m_tagFileCompounds)
1403 {
1405 {
1406 const TagRequirementInfo *rq = comp.getRequirementInfo();
1407 Debug::print(Debug::Tag,0,"requirement '{}'\n",rq->id);
1408 Debug::print(Debug::Tag,0," title '{}'\n",rq->title);
1409 Debug::print(Debug::Tag,0," filename '{}'\n",rq->filename);
1410 }
1411 }
1412 Debug::print(Debug::Tag,0,"-------------------------\n");
1413}
1414
1415void TagFileParser::addDocAnchors(const std::shared_ptr<Entry> &e,const std::vector<TagAnchorInfo> &l)
1416{
1417 for (const auto &ta : l)
1418 {
1419 if (SectionManager::instance().find(ta.label)==nullptr)
1420 {
1421 //printf("New sectionInfo file=%s anchor=%s\n",
1422 // qPrint(ta->fileName),qPrint(ta->label));
1424 ta.label,ta.fileName,-1,ta.title,
1426 e->anchors.push_back(si);
1427 }
1428 else
1429 {
1430 //printf("Replace sectionInfo file=%s anchor=%s\n",
1431 // qPrint(ta->fileName),qPrint(ta->label));
1433 ta.label,ta.fileName,-1,ta.title,
1435 }
1436 }
1437}
1438
1439void TagFileParser::buildMemberList(const std::shared_ptr<Entry> &ce,const std::vector<TagMemberInfo> &members)
1440{
1441 for (const auto &tmi : members)
1442 {
1443 std::shared_ptr<Entry> me = std::make_shared<Entry>();
1444 me->type = tmi.type;
1445 me->name = tmi.name;
1446 me->args = tmi.arglist;
1447 if (!me->args.isEmpty())
1448 {
1449 me->argList = *stringToArgumentList(SrcLangExt::Cpp,me->args);
1450 }
1451 if (tmi.enumValues.size()>0)
1452 {
1453 me->spec.setStrong(true);
1454 for (const auto &evi : tmi.enumValues)
1455 {
1456 std::shared_ptr<Entry> ev = std::make_shared<Entry>();
1457 ev->type = "@";
1458 ev->name = evi.name;
1459 ev->id = evi.clangid;
1460 ev->section = EntryType::makeVariable();
1461 ev->tagInfoData.tagName = m_tagName;
1462 ev->tagInfoData.anchor = evi.anchor;
1463 ev->tagInfoData.fileName = evi.file;
1464 ev->hasTagInfo = TRUE;
1465 me->moveToSubEntryAndKeep(ev);
1466 }
1467 }
1468 me->protection = tmi.prot;
1469 me->virt = tmi.virt;
1470 me->isStatic = tmi.isStatic;
1471 me->fileName = ce->fileName;
1472 me->id = tmi.clangId;
1473 me->startLine = tmi.lineNr;
1474 if (ce->section.isGroupDoc())
1475 {
1476 me->groups.emplace_back(ce->name,Grouping::GROUPING_INGROUP);
1477 }
1478 addDocAnchors(me,tmi.docAnchors);
1479 me->tagInfoData.tagName = m_tagName;
1480 me->tagInfoData.anchor = tmi.anchor;
1481 me->tagInfoData.fileName = tmi.anchorFile;
1482 me->hasTagInfo = TRUE;
1483 if (tmi.kind=="define")
1484 {
1485 me->type="#define";
1486 me->section = EntryType::makeDefine();
1487 }
1488 else if (tmi.kind=="enumvalue")
1489 {
1490 me->section = EntryType::makeVariable();
1491 me->mtype = MethodTypes::Method;
1492 }
1493 else if (tmi.kind=="property")
1494 {
1495 me->section = EntryType::makeVariable();
1496 me->mtype = MethodTypes::Property;
1497 }
1498 else if (tmi.kind=="event")
1499 {
1500 me->section = EntryType::makeVariable();
1501 me->mtype = MethodTypes::Event;
1502 }
1503 else if (tmi.kind=="variable")
1504 {
1505 me->section = EntryType::makeVariable();
1506 me->mtype = MethodTypes::Method;
1507 }
1508 else if (tmi.kind=="typedef")
1509 {
1510 me->section = EntryType::makeVariable();
1511 me->type.prepend("typedef ");
1512 me->mtype = MethodTypes::Method;
1513 }
1514 else if (tmi.kind=="enumeration")
1515 {
1516 me->section = EntryType::makeEnum();
1517 me->mtype = MethodTypes::Method;
1518 }
1519 else if (tmi.kind=="function")
1520 {
1521 me->section = EntryType::makeFunction();
1522 me->mtype = MethodTypes::Method;
1523 }
1524 else if (tmi.kind=="signal")
1525 {
1526 me->section = EntryType::makeFunction();
1527 me->mtype = MethodTypes::Signal;
1528 }
1529 else if (tmi.kind=="prototype")
1530 {
1531 me->section = EntryType::makeFunction();
1532 me->mtype = MethodTypes::Method;
1533 }
1534 else if (tmi.kind=="friend")
1535 {
1536 me->section = EntryType::makeFunction();
1537 me->type.prepend("friend ");
1538 me->mtype = MethodTypes::Method;
1539 }
1540 else if (tmi.kind=="dcop")
1541 {
1542 me->section = EntryType::makeFunction();
1543 me->mtype = MethodTypes::DCOP;
1544 }
1545 else if (tmi.kind=="slot")
1546 {
1547 me->section = EntryType::makeFunction();
1548 me->mtype = MethodTypes::Slot;
1549 }
1550 ce->moveToSubEntryAndKeep(me);
1551 }
1552}
1553
1554void TagFileParser::buildClassEntry(const std::shared_ptr<Entry> &root, const TagClassInfo *tci)
1555{
1556 std::shared_ptr<Entry> ce = std::make_shared<Entry>();
1557 ce->section = EntryType::makeClass();
1558 switch (tci->kind)
1559 {
1560 case TagClassInfo::Kind::Class: break;
1561 case TagClassInfo::Kind::Struct: ce->spec = TypeSpecifier().setStruct(true); break;
1562 case TagClassInfo::Kind::Union: ce->spec = TypeSpecifier().setUnion(true); break;
1563 case TagClassInfo::Kind::Interface: ce->spec = TypeSpecifier().setInterface(true); break;
1564 case TagClassInfo::Kind::Enum: ce->spec = TypeSpecifier().setEnum(true); break;
1565 case TagClassInfo::Kind::Exception: ce->spec = TypeSpecifier().setException(true); break;
1566 case TagClassInfo::Kind::Protocol: ce->spec = TypeSpecifier().setProtocol(true); break;
1567 case TagClassInfo::Kind::Category: ce->spec = TypeSpecifier().setCategory(true); break;
1568 case TagClassInfo::Kind::Service: ce->spec = TypeSpecifier().setService(true); break;
1569 case TagClassInfo::Kind::Singleton: ce->spec = TypeSpecifier().setSingleton(true); break;
1570 case TagClassInfo::Kind::None: // should never happen, means not properly initialized
1571 assert(tci->kind != TagClassInfo::Kind::None);
1572 break;
1573 }
1574 ce->name = tci->name;
1576 {
1577 ce->name+="-p";
1578 }
1579 addDocAnchors(ce,tci->docAnchors);
1580 ce->tagInfoData.tagName = m_tagName;
1581 ce->tagInfoData.anchor = tci->anchor;
1582 ce->tagInfoData.fileName = tci->filename;
1583 ce->startLine = tci->lineNr;
1584 ce->fileName = m_tagName;
1585 ce->hasTagInfo = TRUE;
1586 ce->id = tci->clangId;
1587 ce->lang = tci->isObjC ? SrcLangExt::ObjC : SrcLangExt::Unknown;
1588 // transfer base class list
1589 ce->extends = tci->bases;
1590 if (!tci->templateArguments.empty())
1591 {
1592 ArgumentList al;
1593 for (const auto &argName : tci->templateArguments)
1594 {
1595 Argument a;
1596 a.type = "class";
1597 a.name = argName;
1598 al.push_back(a);
1599 }
1600 ce->tArgLists.push_back(al);
1601 }
1602
1603 buildMemberList(ce,tci->members);
1604 root->moveToSubEntryAndKeep(ce);
1605}
1606
1607void TagFileParser::buildClassTree(const std::shared_ptr<Entry> &root,const ClassNode &node)
1608{
1609 if (node.tci)
1610 {
1611 buildClassEntry(root,node.tci);
1612 }
1613 for (const auto &child : node.children)
1614 {
1615 buildClassTree(root,*child.second);
1616 }
1617}
1618
1619/*! Injects the info gathered by the XML parser into the Entry tree.
1620 * This tree contains the information extracted from the input in a
1621 * "unrelated" form.
1622 */
1623void TagFileParser::buildLists(const std::shared_ptr<Entry> &root)
1624{
1625 // First reorganize the entries in m_tagFileCompounds such that
1626 // outer scope is processed before the nested class scope.
1627 // To solve issue #11569, where a class nested in a specialization is
1628 // processed first, which later causes the wrong class to be used
1629 ClassNode classRoot("");
1630 for (const auto &comp : m_tagFileCompounds)
1631 {
1632 const TagClassInfo *tci = comp.getClassInfo();
1633 if (tci)
1634 {
1635 ClassNode *current = &classRoot;
1636 auto parts = split(tci->name.str(),"::");
1637 for (size_t i=0; i<parts.size(); ++i)
1638 {
1639 const auto &part = parts[i];
1640 if (current->children.find(part)==current->children.end()) // new child node
1641 {
1642 current->children[part] = std::make_unique<ClassNode>(part);
1643 }
1644 current = current->children[part].get();
1645 if (i==parts.size()-1)
1646 {
1647 current->tci = tci;
1648 }
1649 }
1650 }
1651 }
1652
1653 // now process the classes following the tree structure
1654 buildClassTree(root,classRoot);
1655
1656
1657 // build file list
1658 for (const auto &comp : m_tagFileCompounds)
1659 {
1660 const TagFileInfo *tfi = comp.getFileInfo();
1661 if (tfi)
1662 {
1663 std::shared_ptr<Entry> fe = std::make_shared<Entry>();
1664 fe->section = guessSection(tfi->name);
1665 fe->name = tfi->name;
1666 addDocAnchors(fe,tfi->docAnchors);
1667 fe->tagInfoData.tagName = m_tagName;
1668 fe->tagInfoData.fileName = tfi->filename;
1669 fe->hasTagInfo = TRUE;
1670
1671 QCString fullName = m_tagName+":"+tfi->path+stripPath(tfi->name);
1672 fe->fileName = fullName;
1673 fe->startLine = tfi->lineNr;
1674 //printf("createFileDef() filename=%s\n",qPrint(tfi->filename));
1675 QCString tagid = m_tagName+":"+tfi->path;
1676 auto fd = createFileDef(tagid, tfi->name,m_tagName, tfi->filename);
1677 FileName *mn = Doxygen::inputNameLinkedMap->find(tfi->name);
1678 if (mn)
1679 {
1680 mn->push_back(std::move(fd));
1681 }
1682 else
1683 {
1684 mn = Doxygen::inputNameLinkedMap->add(tfi->name);
1685 mn->push_back(std::move(fd));
1686 }
1687 buildMemberList(fe,tfi->members);
1688 root->moveToSubEntryAndKeep(fe);
1689 }
1690 }
1691
1692 // build concept list
1693 for (const auto &comp : m_tagFileCompounds)
1694 {
1695 const TagConceptInfo *tci = comp.getConceptInfo();
1696 if (tci)
1697 {
1698 std::shared_ptr<Entry> ce = std::make_shared<Entry>();
1699 ce->section = EntryType::makeConcept();
1700 ce->name = tci->name;
1701 addDocAnchors(ce,tci->docAnchors);
1702 ce->tagInfoData.tagName = m_tagName;
1703 ce->tagInfoData.fileName = tci->filename;
1704 ce->startLine = tci->lineNr;
1705 ce->fileName = m_tagName;
1706 ce->hasTagInfo = TRUE;
1707 ce->id = tci->clangId;
1708
1709 root->moveToSubEntryAndKeep(ce);
1710 }
1711 }
1712
1713 // build module list
1714 for (const auto &comp : m_tagFileCompounds)
1715 {
1716 const TagModuleInfo *tmi = comp.getModuleInfo();
1717 if (tmi)
1718 {
1719 auto &mm = ModuleManager::instance();
1720 mm.createModuleDef(tmi->filename,tmi->lineNr,1,true,tmi->name,QCString());
1721 mm.addTagInfo(tmi->filename,m_tagName,tmi->clangId);
1722
1723 ModuleDef *mod = mm.getPrimaryInterface(tmi->name);
1724 if (mod && !tmi->docAnchors.empty())
1725 {
1726 std::vector<const SectionInfo *> anchorList;
1727 for (const auto &ta : tmi->docAnchors)
1728 {
1729 if (SectionManager::instance().find(ta.label)==nullptr)
1730 {
1731 //printf("New sectionInfo file=%s anchor=%s\n",
1732 // qPrint(ta->fileName),qPrint(ta->label));
1734 ta.label,ta.fileName,-1,ta.title,
1736 anchorList.push_back(si);
1737 }
1738 else
1739 {
1740 p_warn("Duplicate anchor {} found",ta.label);
1741 }
1742 }
1743 mod->addSectionsToDefinition(anchorList);
1744 }
1745 }
1746 }
1747
1748
1749 // build namespace list
1750 for (const auto &comp : m_tagFileCompounds)
1751 {
1752 const TagNamespaceInfo *tni = comp.getNamespaceInfo();
1753 if (tni)
1754 {
1755 std::shared_ptr<Entry> ne = std::make_shared<Entry>();
1756 ne->section = EntryType::makeNamespace();
1757 ne->name = tni->name;
1758 addDocAnchors(ne,tni->docAnchors);
1759 ne->tagInfoData.tagName = m_tagName;
1760 ne->tagInfoData.fileName = tni->filename;
1761 ne->startLine = tni->lineNr;
1762 ne->fileName = m_tagName;
1763 ne->hasTagInfo = TRUE;
1764 ne->id = tni->clangId;
1765
1766 buildMemberList(ne,tni->members);
1767 root->moveToSubEntryAndKeep(ne);
1768 }
1769 }
1770
1771 // build package list
1772 for (const auto &comp : m_tagFileCompounds)
1773 {
1774 const TagPackageInfo *tpgi = comp.getPackageInfo();
1775 if (tpgi)
1776 {
1777 std::shared_ptr<Entry> pe = std::make_shared<Entry>();
1778 pe->section = EntryType::makePackage();
1779 pe->name = tpgi->name;
1780 addDocAnchors(pe,tpgi->docAnchors);
1781 pe->tagInfoData.tagName = m_tagName;
1782 pe->tagInfoData.fileName = tpgi->filename;
1783 pe->startLine = tpgi->lineNr;
1784 pe->fileName = m_tagName;
1785 pe->hasTagInfo = TRUE;
1786
1787 buildMemberList(pe,tpgi->members);
1788 root->moveToSubEntryAndKeep(pe);
1789 }
1790 }
1791
1792 // build group list
1793 for (const auto &comp : m_tagFileCompounds)
1794 {
1795 const TagGroupInfo *tgi = comp.getGroupInfo();
1796 if (tgi)
1797 {
1798 std::shared_ptr<Entry> ge = std::make_shared<Entry>();
1799 ge->section = EntryType::makeGroupDoc();
1800 ge->name = tgi->name;
1801 ge->type = tgi->title;
1802 addDocAnchors(ge,tgi->docAnchors);
1803 ge->tagInfoData.tagName = m_tagName;
1804 ge->tagInfoData.fileName = tgi->filename;
1805 ge->startLine = tgi->lineNr;
1806 ge->fileName = m_tagName;
1807 ge->hasTagInfo = TRUE;
1808
1809 buildMemberList(ge,tgi->members);
1810 root->moveToSubEntryAndKeep(ge);
1811 }
1812 }
1813
1814 for (const auto &comp : m_tagFileCompounds)
1815 {
1816 const TagGroupInfo *tgi = comp.getGroupInfo();
1817 if (tgi)
1818 {
1819 // set subgroup relations bug_774118
1820 for (const auto &sg : tgi->subgroupList)
1821 {
1822 const auto &children = root->children();
1823 auto i = std::find_if(children.begin(),children.end(),
1824 [&](const std::shared_ptr<Entry> &e) { return e->name == sg; });
1825 if (i!=children.end())
1826 {
1827 (*i)->groups.emplace_back(tgi->name,Grouping::GROUPING_INGROUP);
1828 }
1829 }
1830 }
1831 }
1832
1833 // build page list
1834 for (const auto &comp : m_tagFileCompounds)
1835 {
1836 const TagPageInfo *tpi = comp.getPageInfo();
1837 if (tpi)
1838 {
1839 std::shared_ptr<Entry> pe = std::make_shared<Entry>();
1840 bool isIndex = (stripExtensionGeneral(tpi->filename,getFileNameExtension(tpi->filename))=="index");
1841 pe->section = isIndex ? EntryType::makeMainpageDoc() : EntryType::makePageDoc();
1842 pe->name = tpi->name;
1843 pe->args = tpi->title;
1844 for (const auto &subpage : tpi->subpages)
1845 {
1846 // we add subpage labels as a kind of "inheritance" relation to prevent
1847 // needing to add another list to the Entry class.
1848 pe->extends.emplace_back(stripExtension(subpage),Protection::Public,Specifier::Normal);
1849 }
1850 addDocAnchors(pe,tpi->docAnchors);
1851 pe->tagInfoData.tagName = m_tagName;
1852 pe->tagInfoData.fileName = stripExtension(tpi->filename);
1853 pe->startLine = tpi->lineNr;
1854 pe->fileName = m_tagName;
1855 pe->hasTagInfo = TRUE;
1856 root->moveToSubEntryAndKeep(pe);
1857 }
1858 }
1859
1860 // build requirement list
1861 for (const auto &comp : m_tagFileCompounds)
1862 {
1863 const TagRequirementInfo *tri = comp.getRequirementInfo();
1864 if (tri)
1865 {
1866 std::shared_ptr<Entry> pe = std::make_shared<Entry>();
1867 pe->section = EntryType::makeRequirementDoc();
1868 pe->name = tri->id;
1869 pe->type = tri->title;
1870 pe->tagInfoData.tagName = m_tagName;
1871 pe->tagInfoData.fileName = tri->filename;
1872 pe->startLine = tri->lineNr;
1873 pe->fileName = m_tagName;
1874 pe->hasTagInfo = true;
1875 //printf("Reading requirement '%s' from tag file. title=%s\n",qPrint(pe->name),qPrint(pe->type));
1876 root->moveToSubEntryAndKeep(pe);
1877 }
1878 }
1879}
1880
1882{
1883 for (const auto &comp : m_tagFileCompounds)
1884 {
1885 const TagFileInfo *tfi = comp.getFileInfo();
1886 if (tfi)
1887 {
1888 //printf("tag file tagName=%s path=%s name=%s\n",qPrint(m_tagName),qPrint(tfi->path),qPrint(tfi->name));
1889 FileName *fn = Doxygen::inputNameLinkedMap->find(tfi->name);
1890 if (fn)
1891 {
1892 for (const auto &fd : *fn)
1893 {
1894 //printf("input file path=%s name=%s\n",qPrint(fd->getPath()),qPrint(fd->name()));
1895 if (fd->getPath()==QCString(m_tagName+":"+tfi->path))
1896 {
1897 //printf("found\n");
1898 for (const auto &ii : tfi->includes)
1899 {
1900 //printf("ii->name='%s'\n",qPrint(ii->name));
1901 FileName *ifn = Doxygen::inputNameLinkedMap->find(ii.name);
1902 ASSERT(ifn!=nullptr);
1903 if (ifn)
1904 {
1905 for (const auto &ifd : *ifn)
1906 {
1907 //printf("ifd->getOutputFileBase()=%s ii->id=%s\n",
1908 // qPrint(ifd->getOutputFileBase()),qPrint(ii->id));
1909 if (ifd->getOutputFileBase()==ii.id)
1910 {
1912 if (ii.isModule)
1913 {
1915 }
1916 else if (ii.isImported)
1917 {
1919 }
1920 else if (ii.isLocal)
1921 {
1923 }
1924 fd->addIncludeDependency(ifd.get(),ii.text,kind);
1925 }
1926 }
1927 }
1928 }
1929 }
1930 }
1931 }
1932 }
1933 }
1934}
1935
1936} // namespace
1937
1938// ----------------- public part -----------------------------------------------
1939
1940void parseTagFile(const std::shared_ptr<Entry> &root,const char *fullName)
1941{
1942 TagFileParser tagFileParser(fullName);
1943 QCString inputStr = fileToString(fullName);
1944 XMLHandlers handlers;
1945 // connect the generic events handlers of the XML parser to the specific handlers of the tagFileParser object
1946 handlers.startDocument = [&tagFileParser]() { tagFileParser.startDocument(); };
1947 handlers.startElement = [&tagFileParser](const std::string &name,const XMLHandlers::Attributes &attrs) { tagFileParser.startElement(name,attrs); };
1948 handlers.endElement = [&tagFileParser](const std::string &name) { tagFileParser.endElement(name); };
1949 handlers.characters = [&tagFileParser](const std::string &chars) { tagFileParser.characters(chars); };
1950 handlers.error = [&tagFileParser](const std::string &fileName,int lineNr,const std::string &msg) { tagFileParser.error(fileName,lineNr,msg); };
1951 XMLParser parser(handlers);
1952 tagFileParser.setDocumentLocator(&parser);
1953 parser.parse(fullName,inputStr.data(),Debug::isFlagSet(Debug::Lex_xml),
1954 [&]() { DebugLex::print(Debug::Lex_xml,"Entering","libxml/xml.l",fullName); },
1955 [&]() { DebugLex::print(Debug::Lex_xml,"Finished", "libxml/xml.l",fullName); }
1956 );
1957 tagFileParser.buildLists(root);
1958 tagFileParser.addIncludes();
1960 {
1961 tagFileParser.dump();
1962 }
1963}
static bool looksGenerated(const std::string &anchor)
Returns true if anchor is a potentially generated anchor.
Definition anchor.cpp:134
This class represents an function or template argument list.
Definition arguments.h:65
void push_back(const Argument &a)
Definition arguments.h:102
@ Tag
Definition debug.h:45
@ Lex_xml
Definition debug.h:71
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:133
static void print(DebugMask mask, int prio, fmt::format_string< Args... > fmt, Args &&... args)
Definition debug.h:77
virtual void addSectionsToDefinition(const std::vector< const SectionInfo * > &anchorList)=0
Class representing a directory in the file system.
Definition dir.h:75
static FileNameLinkedMap * inputNameLinkedMap
Definition doxygen.h:104
Class representing all files with a certain base name.
Definition filename.h:30
static ModuleManager & instance()
This is an alternative implementation of QCString.
Definition qcstring.h:103
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:167
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:264
const std::string & str() const
Definition qcstring.h:556
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:176
class that provide information about a section.
Definition section.h:58
SectionInfo * replace(const QCString &label, const QCString &fileName, int lineNr, const QCString &title, SectionType type, int level, const QCString &ref=QCString())
Definition section.h:157
SectionInfo * add(const SectionInfo &si)
Definition section.h:139
static SectionManager & instance()
returns a reference to the singleton
Definition section.h:179
static constexpr int Anchor
Definition section.h:40
Wrapper class for a number of boolean properties.
Definition types.h:694
Event handlers that can installed by the client and called while parsing a XML document.
Definition xml.h:27
std::unordered_map< std::string, std::string > Attributes
Definition xml.h:29
std::function< EndElementType > endElement
handler invoked when a closing tag has been found
Definition xml.h:40
std::function< StartElementType > startElement
handler invoked when an opening tag has been found
Definition xml.h:39
std::function< CharsType > characters
handler invoked when content between tags has been found
Definition xml.h:41
static std::string value(const Attributes &attrib, const std::string &key)
Definition xml.h:44
std::function< ErrorType > error
handler invoked when the parser encounters an error
Definition xml.h:42
std::function< StartDocType > startDocument
handler invoked at the start of the document
Definition xml.h:37
void parse(const char *fileName, const char *inputString, bool debugEnabled, std::function< void()> debugStart, std::function< void()> debugEnd, std::function< Transcode > transcoder=[](std::string &s, const char *){ return true;})
Definition xml.l:447
TagAnchorInfo(const QCString &f, const QCString &l, const QCString &t=QCString())
Definition tagreader.cpp:52
Variant class that holds a unique pointer to one of the specific container types.
const R * get() const
Generic const getter.
static TagCompoundVariant make(Args &&... args)
Generic factory method to create a variant holding a unique pointer to a given compound type.
const TagNamespaceInfo * getNamespaceInfo() const
TagCompoundInfo * getCompoundInfo()
Convenience method to get the shared compound info.
std::variant< std::monostate, TagClassInfoPtr, TagConceptInfoPtr, TagNamespaceInfoPtr, TagPackageInfoPtr, TagFileInfoPtr, TagGroupInfoPtr, TagPageInfoPtr, TagDirInfoPtr, TagModuleInfoPtr, TagRequirementInfoPtr > VariantT
const TagRequirementInfo * getRequirementInfo() const
Container for enum values that are scoped within an enum.
Definition tagreader.cpp:63
void addDocAnchors(const std::shared_ptr< Entry > &e, const std::vector< TagAnchorInfo > &l)
void startIncludes(const XMLHandlers::Attributes &attrib)
void startDocAnchor(const XMLHandlers::Attributes &attrib)
void startElement(const QCString &name, const XMLHandlers::Attributes &attrib)
void startStringValue(const XMLHandlers::Attributes &)
void setDocumentLocator(const XMLLocator *locator)
void startBase(const XMLHandlers::Attributes &attrib)
void error(const QCString &fileName, int lineNr, const QCString &msg)
void startIgnoreElement(const XMLHandlers::Attributes &)
void buildLists(const std::shared_ptr< Entry > &root)
void startMember(const XMLHandlers::Attributes &attrib)
void buildMemberList(const std::shared_ptr< Entry > &ce, const std::vector< TagMemberInfo > &members)
void buildClassEntry(const std::shared_ptr< Entry > &root, const TagClassInfo *tci)
void startCompound(const XMLHandlers::Attributes &attrib)
void buildClassTree(const std::shared_ptr< Entry > &root, const ClassNode &node)
std::vector< TagCompoundVariant > m_tagFileCompounds
void startEnumValue(const XMLHandlers::Attributes &attrib)
Container for include info that can be read from a tagfile.
Definition tagreader.cpp:73
Container for member specific info that can be read from a tagfile.
Definition tagreader.cpp:86
std::vector< TagEnumValueInfo > enumValues
Definition tagreader.cpp:99
#define ONLY_DEFAULT_MOVABLE(cls)
Macro to help implementing the rule of 5 for a class that can be moved but not copied.
Definition construct.h:44
std::vector< std::string > StringVector
Definition containers.h:33
std::unique_ptr< ArgumentList > stringToArgumentList(SrcLangExt lang, const QCString &argsString, QCString *extraTypeChars=nullptr)
Definition defargs.l:826
std::unique_ptr< FileDef > createFileDef(const QCString &p, const QCString &n, const QCString &ref, const QCString &dn)
Definition filedef.cpp:268
IncludeKind
Definition filedef.h:47
@ ImportLocal
Definition filedef.h:54
@ ImportModule
Definition filedef.h:55
@ IncludeLocal
Definition filedef.h:50
@ IncludeSystem
Definition filedef.h:49
@ ImportSystem
Definition filedef.h:53
#define warn(file, line, fmt,...)
Definition message.h:97
#define msg(fmt,...)
Definition message.h:94
std::unique_ptr< TagPackageInfo > TagPackageInfoPtr
std::unique_ptr< TagRequirementInfo > TagRequirementInfoPtr
std::unique_ptr< TagFileInfo > TagFileInfoPtr
std::unique_ptr< TagClassInfo > TagClassInfoPtr
std::unique_ptr< TagNamespaceInfo > TagNamespaceInfoPtr
std::unique_ptr< TagDirInfo > TagDirInfoPtr
static const std::map< std::string, CompoundFactory > g_compoundFactory
std::unique_ptr< TagConceptInfo > TagConceptInfoPtr
std::unique_ptr< TagModuleInfo > TagModuleInfoPtr
std::unique_ptr< TagPageInfo > TagPageInfoPtr
ElementCallbacks::EndCallback endCb(void(TagFileParser::*fn)())
static const std::map< std::string, ElementCallbacks > g_elementHandlers
ElementCallbacks::StartCallback startCb(void(TagFileParser::*fn)(const XMLHandlers::Attributes &))
std::unique_ptr< TagGroupInfo > TagGroupInfoPtr
#define TRUE
Definition qcstring.h:37
#define ASSERT(x)
Definition qcstring.h:39
This class contains the information about the argument of a function or template.
Definition arguments.h:27
QCString type
Definition arguments.h:42
QCString name
Definition arguments.h:44
This class stores information about an inheritance relation.
Definition entry.h:91
QCString name
the name of the base class
Definition entry.h:95
@ GROUPING_INGROUP
membership in group was defined by @ingroup
Definition types.h:236
CompoundFactory(TagFileParser::State s, const CreateFunc &f)
std::function< TagCompoundVariant()> CreateFunc
std::function< void(TagFileParser &, const XMLHandlers::Attributes &)> StartCallback
std::function< void(TagFileParser &)> EndCallback
Container for class specific info that can be read from a tagfile.
Container for concept specific info that can be read from a tagfile.
Container for directory specific info that can be read from a tagfile.
Container for file specific info that can be read from a tagfile.
std::unordered_map< std::string, std::unique_ptr< ClassNode > > children
Container for group specific info that can be read from a tagfile.
Container for module specific info that can be read from a tagfile.
Container for namespace specific info that can be read from a tagfile.
Container for package specific info that can be read from a tagfile.
Container for page specific info that can be read from a tagfile.
Container for requirement specific info that can be read from a tagfile.
void parseTagFile(const std::shared_ptr< Entry > &root, const char *fullName)
#define p_warn(fmt,...)
Protection
Definition types.h:32
Specifier
Definition types.h:80
QCString stripPath(const QCString &s)
Definition util.cpp:4991
QCString fileToString(const QCString &name, bool filter, bool isSourceCode)
Definition util.cpp:1494
QCString stripExtensionGeneral(const QCString &fName, const QCString &ext)
Definition util.cpp:4976
QCString stripExtension(const QCString &fName)
Definition util.cpp:4986
EntryType guessSection(const QCString &name)
Definition util.cpp:338
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:6658
QCString getFileNameExtension(const QCString &fn)
Definition util.cpp:5295
A bunch of utility functions.