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 */
135
136using TagConceptInfoPtr = std::unique_ptr<TagConceptInfo>;
137
138/** Container for module specific info that can be read from a tagfile */
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 m_curMember.lineNr = m_locator->lineNr();
403 if (protStr=="protected")
404 {
405 m_curMember.prot = Protection::Protected;
406 }
407 else if (protStr=="private")
408 {
409 m_curMember.prot = Protection::Private;
410 }
411 if (virtStr=="virtual")
412 {
413 m_curMember.virt = Specifier::Virtual;
414 }
415 else if (virtStr=="pure")
416 {
417 m_curMember.virt = Specifier::Pure;
418 }
419 if (staticStr=="yes")
420 {
421 m_curMember.isStatic = TRUE;
422 }
423 m_stateStack.push(m_state);
425 }
426
428 {
429 m_state = m_stateStack.top();
430 m_stateStack.pop();
431 switch(m_state)
432 {
433 case InClass:
434 case InFile:
435 case InNamespace:
436 case InGroup:
437 case InPackage:
438 {
439 TagCompoundInfo *info = m_curCompound.getCompoundInfo();
440 if (info)
441 {
442 info->members.push_back(m_curMember);
443 }
444 }
445 break;
446 default:
447 p_warn("Unexpected tag 'member' found");
448 break;
449 }
450 }
451
453 {
454 if (m_state==InMember)
455 {
456 m_curString = "";
458 m_curEnumValue.file = XMLHandlers::value(attrib,"file");
459 m_curEnumValue.anchor = XMLHandlers::value(attrib,"anchor");
460 m_curEnumValue.clangid = XMLHandlers::value(attrib,"clangid");
461 m_stateStack.push(m_state);
463 }
464 else
465 {
466 p_warn("Found 'enumvalue' tag outside of member tag");
467 }
468 }
469
471 {
473 m_state = m_stateStack.top();
474 m_stateStack.pop();
475 if (m_state==InMember)
476 {
477 m_curMember.enumValues.push_back(m_curEnumValue);
479 }
480 }
481
483 {
484 // Check whether or not the tag is automatically generate, in that case ignore the tag.
485 switch(m_state)
486 {
487 case InClass:
488 case InConcept:
489 case InFile:
490 case InNamespace:
491 case InGroup:
492 case InPage:
493 case InMember:
494 case InPackage:
495 case InDir:
496 case InModule:
498 break;
499 default:
500 p_warn("Unexpected tag 'docanchor' found");
501 return;
502 }
503 switch(m_state)
504 {
505 case InClass:
506 case InConcept:
507 case InFile:
508 case InNamespace:
509 case InGroup:
510 case InPage:
511 case InPackage:
512 case InDir:
513 case InModule:
514 {
515 TagCompoundInfo *info = m_curCompound.getCompoundInfo();
516 if (info)
517 {
518 info->docAnchors.emplace_back(m_fileName,m_curString,m_title);
519 }
520 }
521 break;
522 case InMember:
523 m_curMember.docAnchors.emplace_back(m_fileName,m_curString,m_title);
524 break;
525 default: break; // will not be reached
526 }
527 }
528
529 void endClass()
530 {
531 switch(m_state)
532 {
533 case InClass:
534 {
535 TagClassInfo *info = m_curCompound.getClassInfo();
536 if (info) info->classList.push_back(m_curString.str());
537 }
538 break;
539 case InFile:
540 {
541 TagFileInfo *info = m_curCompound.getFileInfo();
542 if (info) info->classList.push_back(m_curString.str());
543 }
544 break;
545 case InNamespace:
546 {
547 TagNamespaceInfo *info = m_curCompound.getNamespaceInfo();
548 if (info) info->classList.push_back(m_curString.str());
549 }
550 break;
551 case InGroup:
552 {
553 TagGroupInfo *info = m_curCompound.getGroupInfo();
554 if (info) info->classList.push_back(m_curString.str());
555 }
556 break;
557 case InPackage:
558 {
559 TagPackageInfo *info = m_curCompound.getPackageInfo();
560 if (info) info->classList.push_back(m_curString.str());
561 }
562 break;
563 default:
564 p_warn("Unexpected tag 'class' found");
565 break;
566 }
567 }
568
570 {
571 switch(m_state)
572 {
573 case InNamespace:
574 {
575 TagNamespaceInfo *info = m_curCompound.getNamespaceInfo();
576 if (info) info->conceptList.push_back(m_curString.str());
577 }
578 break;
579 case InFile:
580 {
581 TagFileInfo *info = m_curCompound.getFileInfo();
582 if (info) info->conceptList.push_back(m_curString.str());
583 }
584 break;
585 case InGroup:
586 {
587 TagGroupInfo *info = m_curCompound.getGroupInfo();
588 if (info) info->conceptList.push_back(m_curString.str());
589 }
590 break;
591 default:
592 p_warn("Unexpected tag 'concept' found");
593 break;
594 }
595 }
596
598 {
599 switch(m_state)
600 {
601 case InGroup:
602 {
603 TagGroupInfo *info = m_curCompound.getGroupInfo();
604 if (info) info->moduleList.push_back(m_curString.str());
605 }
606 break;
607 default:
608 p_warn("Unexpected tag 'module' found");
609 break;
610 }
611 }
612
614 {
615 switch(m_state)
616 {
617 case InNamespace:
618 {
619 TagNamespaceInfo *info = m_curCompound.getNamespaceInfo();
620 if (info) info->namespaceList.push_back(m_curString.str());
621 }
622 break;
623 case InFile:
624 {
625 TagFileInfo *info = m_curCompound.getFileInfo();
626 if (info) info->namespaceList.push_back(m_curString.str());
627 }
628 break;
629 case InGroup:
630 {
631 TagGroupInfo *info = m_curCompound.getGroupInfo();
632 if (info) info->namespaceList.push_back(m_curString.str());
633 }
634 break;
635 default:
636 p_warn("Unexpected tag 'namespace' found");
637 break;
638 }
639 }
640
641 void endFile()
642 {
643 switch(m_state)
644 {
645 case InGroup:
646 {
647 TagGroupInfo *info = m_curCompound.getGroupInfo();
648 if (info) info->fileList.push_back(m_curString.str());
649 }
650 break;
651 case InDir:
652 {
653 TagDirInfo *info = m_curCompound.getDirInfo();
654 if (info) info->fileList.push_back(m_curString.str());
655 }
656 break;
657 default:
658 p_warn("Unexpected tag 'file' found");
659 break;
660 }
661 }
662
663 void endPage()
664 {
665 switch(m_state)
666 {
667 case InGroup:
668 {
669 TagGroupInfo *info = m_curCompound.getGroupInfo();
670 if (info) info->fileList.push_back(m_curString.str());
671 }
672 break;
673 default:
674 p_warn("Unexpected tag 'page' found");
675 break;
676 }
677 }
678
680 {
681 switch(m_state)
682 {
683 case InPage:
684 {
685 TagPageInfo *info = m_curCompound.getPageInfo();
686 if (info) info->subpages.push_back(m_curString.str());
687 }
688 break;
689 default:
690 p_warn("Unexpected tag 'subpage' found");
691 break;
692 }
693 }
694
695 void endDir()
696 {
697 switch(m_state)
698 {
699 case InDir:
700 {
701 TagDirInfo *info = m_curCompound.getDirInfo();
702 if (info) info->subdirList.push_back(m_curString.str());
703 }
704 break;
705 default:
706 p_warn("Unexpected tag 'dir' found");
707 break;
708 }
709 }
710
712 {
713 m_curString = "";
714 }
715
717 {
718 m_fileName = XMLHandlers::value(attrib,"file");
719 m_title = XMLHandlers::value(attrib,"title");
720 m_curString = "";
721 }
722
723 void endType()
724 {
725 if (m_state==InMember)
726 {
728 }
729 else
730 {
731 p_warn("Unexpected tag 'type' found");
732 }
733 }
734
735 void endName()
736 {
737 switch (m_state)
738 {
739 case InClass:
740 case InConcept:
741 case InFile:
742 case InNamespace:
743 case InGroup:
744 case InPage:
745 case InDir:
746 case InPackage:
747 case InModule:
748 {
749 TagCompoundInfo *info = m_curCompound.getCompoundInfo();
750 if (info) info->name = m_curString;
751 }
752 break;
753 case InMember:
755 break;
756 default:
757 p_warn("Unexpected tag 'name' found");
758 break;
759 }
760 }
761
762 void endId()
763 {
764 switch (m_state)
765 {
766 case InRequirement:
767 {
768 TagRequirementInfo *info = m_curCompound.getRequirementInfo();
769 if (info) info->id = m_curString;
770 }
771 break;
772 default:
773 p_warn("Unexpected tag 'id' found");
774 break;
775 }
776 }
777
779 {
780 m_curString="";
781 TagClassInfo *info = m_curCompound.getClassInfo();
782 if (m_state==InClass && info)
783 {
784 QCString protStr = XMLHandlers::value(attrib,"protection");
785 QCString virtStr = XMLHandlers::value(attrib,"virtualness");
786 Protection prot = Protection::Public;
787 Specifier virt = Specifier::Normal;
788 if (protStr=="protected")
789 {
790 prot = Protection::Protected;
791 }
792 else if (protStr=="private")
793 {
794 prot = Protection::Private;
795 }
796 if (virtStr=="virtual")
797 {
798 virt = Specifier::Virtual;
799 }
800 info->bases.emplace_back(m_curString,prot,virt);
801 }
802 else
803 {
804 p_warn("Unexpected tag 'base' found");
805 }
806 }
807
808 void endBase()
809 {
810 TagClassInfo *info = m_curCompound.getClassInfo();
811 if (m_state==InClass && info)
812 {
813 info->bases.back().name = m_curString;
814 }
815 else
816 {
817 p_warn("Unexpected tag 'base' found");
818 }
819 }
820
822 {
824 m_curIncludes.id = XMLHandlers::value(attrib,"id");
825 m_curIncludes.name = XMLHandlers::value(attrib,"name");
826 m_curIncludes.isLocal = XMLHandlers::value(attrib,"local")=="yes";
827 m_curIncludes.isImported = XMLHandlers::value(attrib,"imported")=="yes";
828 m_curIncludes.isModule = XMLHandlers::value(attrib,"module")=="yes";
829 m_curIncludes.isObjC = XMLHandlers::value(attrib,"objc")=="yes";
830 m_curString="";
831 }
832
834 {
836 TagFileInfo *info = m_curCompound.getFileInfo();
837 if (m_state==InFile && info)
838 {
839 info->includes.push_back(m_curIncludes);
840 }
841 else
842 {
843 p_warn("Unexpected tag 'includes' found");
844 }
845 }
846
848 {
849 TagClassInfo *info = m_curCompound.getClassInfo();
850 if (m_state==InClass && info)
851 {
852 info->templateArguments.push_back(m_curString.str());
853 }
854 else
855 {
856 p_warn("Unexpected tag 'templarg' found");
857 }
858 }
859
861 {
862 switch (m_state)
863 {
864 case InClass:
865 case InConcept:
866 case InNamespace:
867 case InFile:
868 case InGroup:
869 case InPage:
870 case InPackage:
871 case InDir:
872 case InRequirement:
873 case InModule:
874 {
875 TagCompoundInfo *info = m_curCompound.getCompoundInfo();
876 if (info) info->filename = m_curString;
877 }
878 break;
879 default:
880 p_warn("Unexpected tag 'filename' found");
881 break;
882 }
883 }
884
885 void endPath()
886 {
887 switch (m_state)
888 {
889 case InFile:
890 {
891 TagFileInfo *info = m_curCompound.getFileInfo();
892 if (info) info->path = m_curString;
893 }
894 break;
895 case InDir:
896 {
897 TagDirInfo *info = m_curCompound.getDirInfo();
898 if (info) info->path = m_curString;
899 }
900 break;
901 default:
902 p_warn("Unexpected tag 'path' found");
903 break;
904 }
905 }
906
908 {
909 if (m_state==InMember)
910 {
911 m_curMember.anchor = m_curString;
912 }
913 else if (m_state==InClass)
914 {
915 TagClassInfo *info = m_curCompound.getClassInfo();
916 if (info) info->anchor = m_curString;
917 }
918 else
919 {
920 p_warn("Unexpected tag 'anchor' found");
921 }
922 }
923
925 {
926 if (m_state==InMember)
927 {
928 m_curMember.clangId = m_curString;
929 }
930 else if (m_state==InClass)
931 {
932 TagClassInfo *info = m_curCompound.getClassInfo();
933 if (info) info->clangId = m_curString;
934 }
935 else if (m_state==InNamespace)
936 {
937 TagNamespaceInfo *info = m_curCompound.getNamespaceInfo();
938 if (info) info->clangId = m_curString;
939 }
940 else
941 {
942 p_warn("Unexpected tag 'clangid' found");
943 }
944 }
945
946
947
949 {
950 if (m_state==InMember)
951 {
952 m_curMember.anchorFile = m_curString;
953 }
954 else
955 {
956 p_warn("Unexpected tag 'anchorfile' found");
957 }
958 }
959
961 {
962 if (m_state==InMember)
963 {
964 m_curMember.arglist = m_curString;
965 }
966 else
967 {
968 p_warn("Unexpected tag 'arglist' found");
969 }
970 }
971
972 void endTitle()
973 {
974 switch (m_state)
975 {
976 case InGroup:
977 {
978 TagGroupInfo *info = m_curCompound.getGroupInfo();
979 if (info) info->title = m_curString;
980 }
981 break;
982 case InPage:
983 {
984 TagPageInfo *info = m_curCompound.getPageInfo();
985 if (info) info->title = m_curString;
986 }
987 break;
988 case InRequirement:
989 {
990 TagRequirementInfo *info = m_curCompound.getRequirementInfo();
991 if (info) info->title = m_curString;
992 }
993 break;
994 default:
995 p_warn("Unexpected tag 'title' found");
996 break;
997 }
998 }
999
1001 {
1002 if (m_state==InGroup)
1003 {
1004 TagGroupInfo *info = m_curCompound.getGroupInfo();
1005 if (info) info->subgroupList.push_back(m_curString.str());
1006 }
1007 else
1008 {
1009 p_warn("Unexpected tag 'subgroup' found");
1010 }
1011 }
1012
1014 {
1015 }
1016
1018 {
1019 }
1020
1021 void buildMemberList(const std::shared_ptr<Entry> &ce,const std::vector<TagMemberInfo> &members);
1022 void addDocAnchors(const std::shared_ptr<Entry> &e,const std::vector<TagAnchorInfo> &l);
1023
1024
1039 };
1040 private:
1041
1043 {
1044 ClassNode(const std::string &n) : name(n) {}
1045 std::string name;
1046 const TagClassInfo *tci = nullptr;
1047 std::unordered_map<std::string,std::unique_ptr<ClassNode>> children;
1048 };
1049
1050 void buildClassEntry(const std::shared_ptr<Entry> &root, const TagClassInfo *tci);
1051 void buildClassTree(const std::shared_ptr<Entry> &root, const ClassNode &node);
1052 //------------------------------------
1053
1054 std::vector< TagCompoundVariant > m_tagFileCompounds;
1056
1060
1066 std::stack<State> m_stateStack;
1067 const XMLLocator *m_locator = nullptr;
1068};
1069
1070//---------------------------------------------------------------------------------------------------------------
1071
1073{
1074 using StartCallback = std::function<void(TagFileParser&,const XMLHandlers::Attributes&)>;
1075 using EndCallback = std::function<void(TagFileParser&)>;
1076
1079};
1080
1082{
1083 return [fn](TagFileParser &parser,const XMLHandlers::Attributes &attr) { (parser.*fn)(attr); };
1084}
1085
1087{
1088 return [fn](TagFileParser &parser) { (parser.*fn)(); };
1089}
1090
1091static const std::map< std::string, ElementCallbacks > g_elementHandlers =
1092{
1093 // name, start element callback, end element callback
1121};
1122
1123//---------------------------------------------------------------------------------------------------------------
1124
1132
1133static const std::map< std::string, CompoundFactory > g_compoundFactory =
1134{
1135 // kind tag state creation function
1146 { "file", { TagFileParser::InFile, []() { return TagCompoundVariant::make<TagFileInfo>(); } } },
1147 { "namespace", { TagFileParser::InNamespace, []() { return TagCompoundVariant::make<TagNamespaceInfo>(); } } },
1148 { "concept", { TagFileParser::InConcept, []() { return TagCompoundVariant::make<TagConceptInfo>(); } } },
1149 { "module", { TagFileParser::InModule, []() { return TagCompoundVariant::make<TagModuleInfo>(); } } },
1150 { "group", { TagFileParser::InGroup, []() { return TagCompoundVariant::make<TagGroupInfo>(); } } },
1151 { "page", { TagFileParser::InPage, []() { return TagCompoundVariant::make<TagPageInfo>(); } } },
1152 { "package", { TagFileParser::InPackage, []() { return TagCompoundVariant::make<TagPackageInfo>(); } } },
1153 { "dir", { TagFileParser::InDir, []() { return TagCompoundVariant::make<TagDirInfo>(); } } },
1154 { "requirement", { TagFileParser::InRequirement, []() { return TagCompoundVariant::make<TagRequirementInfo>(); } } }
1155};
1156
1157//---------------------------------------------------------------------------------------------------------------
1158
1160{
1161 //printf("startElement '%s'\n",qPrint(name));
1162 auto it = g_elementHandlers.find(name.str());
1163 if (it!=std::end(g_elementHandlers))
1164 {
1165 it->second.startCb(*this,attrib);
1166 }
1167 else
1168 {
1169 p_warn("Unknown start tag '{}' found!",name);
1170 }
1171}
1172
1174{
1175 //printf("endElement '%s'\n",qPrint(name));
1176 auto it = g_elementHandlers.find(name.str());
1177 if (it!=std::end(g_elementHandlers))
1178 {
1179 it->second.endCb(*this);
1180 }
1181 else
1182 {
1183 p_warn("Unknown end tag '{}' found!",name);
1184 }
1185}
1186
1188{
1189 m_curString = "";
1190 std::string kind = XMLHandlers::value(attrib,"kind");
1191 std::string isObjC = XMLHandlers::value(attrib,"objc");
1192
1193 auto it = g_compoundFactory.find(kind);
1194 if (it!=g_compoundFactory.end())
1195 {
1196 m_curCompound = it->second.make_instance();
1197 m_state = it->second.state;
1198 TagCompoundInfo *info = m_curCompound.getCompoundInfo();
1199 if (info) info->lineNr = m_locator->lineNr();
1200 }
1201 else
1202 {
1203 p_warn("Unknown compound attribute '{}' found!",kind);
1204 m_state = Invalid;
1205 }
1206
1207 TagClassInfo *classInfo = m_curCompound.getClassInfo();
1208 if (isObjC=="yes" && classInfo)
1209 {
1210 classInfo->isObjC = TRUE;
1211 }
1212}
1213
1214/*! Dumps the internal structures. For debugging only! */
1216{
1217 Debug::print(Debug::Tag,0,"-------- Results --------\n");
1218 //============== CLASSES
1219 for (const auto &comp : m_tagFileCompounds)
1220 {
1221 if (comp.type()==TagCompoundVariant::Type::Class)
1222 {
1223 const TagClassInfo *cd = comp.getClassInfo();
1224 Debug::print(Debug::Tag,0,"class '{}'\n",cd->name);
1225 Debug::print(Debug::Tag,0," filename '{}'\n",cd->filename);
1226 for (const BaseInfo &bi : cd->bases)
1227 {
1228 Debug::print(Debug::Tag,0, " base: {}\n",bi.name);
1229 }
1230
1231 for (const auto &md : cd->members)
1232 {
1233 Debug::print(Debug::Tag,0," member:\n");
1234 Debug::print(Debug::Tag,0," kind: '{}'\n",md.kind);
1235 Debug::print(Debug::Tag,0," name: '{}'\n",md.name);
1236 Debug::print(Debug::Tag,0," anchor: '{}'\n",md.anchor);
1237 Debug::print(Debug::Tag,0," arglist: '{}'\n",md.arglist);
1238 }
1239 }
1240 }
1241 //============== CONCEPTS
1242 for (const auto &comp : m_tagFileCompounds)
1243 {
1244 if (comp.type()==TagCompoundVariant::Type::Concept)
1245 {
1246 const TagConceptInfo *cd = comp.getConceptInfo();
1247
1248 Debug::print(Debug::Tag,0,"concept '{}'\n",cd->name);
1249 Debug::print(Debug::Tag,0," filename '{}'\n",cd->filename);
1250 }
1251 }
1252 //============== MODULES
1253 for (const auto &comp : m_tagFileCompounds)
1254 {
1255 if (comp.type()==TagCompoundVariant::Type::Module)
1256 {
1257 const TagModuleInfo *mi = comp.getModuleInfo();
1258
1259 Debug::print(Debug::Tag,0,"module '{}'\n",mi->name);
1260 Debug::print(Debug::Tag,0," filename '{}'\n",mi->filename);
1261 }
1262 }
1263 //============== NAMESPACES
1264 for (const auto &comp : m_tagFileCompounds)
1265 {
1266 if (comp.type()==TagCompoundVariant::Type::Namespace)
1267 {
1268 const TagNamespaceInfo *nd = comp.getNamespaceInfo();
1269
1270 Debug::print(Debug::Tag,0,"namespace '{}'\n",nd->name);
1271 Debug::print(Debug::Tag,0," filename '{}'\n",nd->filename);
1272 for (const auto &cls : nd->classList)
1273 {
1274 Debug::print(Debug::Tag,0, " class: {}\n",cls);
1275 }
1276
1277 for (const auto &md : nd->members)
1278 {
1279 Debug::print(Debug::Tag,0," member:\n");
1280 Debug::print(Debug::Tag,0," kind: '{}'\n",md.kind);
1281 Debug::print(Debug::Tag,0," name: '{}'\n",md.name);
1282 Debug::print(Debug::Tag,0," anchor: '{}'\n",md.anchor);
1283 Debug::print(Debug::Tag,0," arglist: '{}'\n",md.arglist);
1284 }
1285 }
1286 }
1287
1288 //============== FILES
1289 for (const auto &comp : m_tagFileCompounds)
1290 {
1291 if (comp.type()==TagCompoundVariant::Type::File)
1292 {
1293 const TagFileInfo *fd = comp.getFileInfo();
1294
1295 Debug::print(Debug::Tag,0,"file '{}'\n",fd->name);
1296 Debug::print(Debug::Tag,0," filename '{}'\n",fd->filename);
1297 for (const auto &ns : fd->namespaceList)
1298 {
1299 Debug::print(Debug::Tag,0, " namespace: {}\n",ns);
1300 }
1301 for (const auto &cs : fd->classList)
1302 {
1303 Debug::print(Debug::Tag,0, " class: {} \n",cs);
1304 }
1305
1306 for (const auto &md : fd->members)
1307 {
1308 Debug::print(Debug::Tag,0," member:\n");
1309 Debug::print(Debug::Tag,0," kind: '{}'\n",md.kind);
1310 Debug::print(Debug::Tag,0," name: '{}'\n",md.name);
1311 Debug::print(Debug::Tag,0," anchor: '{}'\n",md.anchor);
1312 Debug::print(Debug::Tag,0," arglist: '{}'\n",md.arglist);
1313 }
1314
1315 for (const auto &ii : fd->includes)
1316 {
1317 Debug::print(Debug::Tag,0," includes id: {} name: {}\n",ii.id,ii.name);
1318 }
1319 }
1320 }
1321
1322 //============== GROUPS
1323 for (const auto &comp : m_tagFileCompounds)
1324 {
1325 if (comp.type()==TagCompoundVariant::Type::Group)
1326 {
1327 const TagGroupInfo *gd = comp.getGroupInfo();
1328 Debug::print(Debug::Tag,0,"group '{}'\n",gd->name);
1329 Debug::print(Debug::Tag,0," filename '{}'\n",gd->filename);
1330
1331 for (const auto &ns : gd->namespaceList)
1332 {
1333 Debug::print(Debug::Tag,0, " namespace: {}\n",ns);
1334 }
1335 for (const auto &cs : gd->classList)
1336 {
1337 Debug::print(Debug::Tag,0, " class: {}\n",cs);
1338 }
1339 for (const auto &fi : gd->fileList)
1340 {
1341 Debug::print(Debug::Tag,0, " file: {}\n",fi);
1342 }
1343 for (const auto &sg : gd->subgroupList)
1344 {
1345 Debug::print(Debug::Tag,0, " subgroup: {}\n",sg);
1346 }
1347 for (const auto &pg : gd->pageList)
1348 {
1349 Debug::print(Debug::Tag,0, " page: {}\n",pg);
1350 }
1351
1352 for (const auto &md : gd->members)
1353 {
1354 Debug::print(Debug::Tag,0," member:\n");
1355 Debug::print(Debug::Tag,0," kind: '{}'\n",md.kind);
1356 Debug::print(Debug::Tag,0," name: '{}'\n",md.name);
1357 Debug::print(Debug::Tag,0," anchor: '{}'\n",md.anchor);
1358 Debug::print(Debug::Tag,0," arglist: '{}'\n",md.arglist);
1359 }
1360 }
1361 }
1362
1363 //============== PAGES
1364 for (const auto &comp : m_tagFileCompounds)
1365 {
1366 if (comp.type()==TagCompoundVariant::Type::Page)
1367 {
1368 const TagPageInfo *pd = comp.getPageInfo();
1369 Debug::print(Debug::Tag,0,"page '{}'\n",pd->name);
1370 Debug::print(Debug::Tag,0," title '{}'\n",pd->title);
1371 Debug::print(Debug::Tag,0," filename '{}'\n",pd->filename);
1372 }
1373 }
1374
1375 //============== DIRS
1376 for (const auto &comp : m_tagFileCompounds)
1377 {
1378 if (comp.type()==TagCompoundVariant::Type::Dir)
1379 {
1380 const TagDirInfo *dd = comp.getDirInfo();
1381 {
1382 Debug::print(Debug::Tag,0,"dir '{}'\n",dd->name);
1383 Debug::print(Debug::Tag,0," path '{}'\n",dd->path);
1384 for (const auto &fi : dd->fileList)
1385 {
1386 Debug::print(Debug::Tag,0, " file: {}\n",fi);
1387 }
1388 for (const auto &sd : dd->subdirList)
1389 {
1390 Debug::print(Debug::Tag,0, " subdir: {}\n",sd);
1391 }
1392 }
1393 }
1394 }
1395
1396 //============== REQUIREMENTS
1397 for (const auto &comp : m_tagFileCompounds)
1398 {
1400 {
1401 const TagRequirementInfo *rq = comp.getRequirementInfo();
1402 Debug::print(Debug::Tag,0,"requirement '{}'\n",rq->id);
1403 Debug::print(Debug::Tag,0," title '{}'\n",rq->title);
1404 Debug::print(Debug::Tag,0," filename '{}'\n",rq->filename);
1405 }
1406 }
1407 Debug::print(Debug::Tag,0,"-------------------------\n");
1408}
1409
1410void TagFileParser::addDocAnchors(const std::shared_ptr<Entry> &e,const std::vector<TagAnchorInfo> &l)
1411{
1412 for (const auto &ta : l)
1413 {
1414 if (SectionManager::instance().find(ta.label)==nullptr)
1415 {
1416 //printf("New sectionInfo file=%s anchor=%s\n",
1417 // qPrint(ta->fileName),qPrint(ta->label));
1419 ta.label,ta.fileName,-1,ta.title,
1421 e->anchors.push_back(si);
1422 }
1423 else
1424 {
1425 //printf("Replace sectionInfo file=%s anchor=%s\n",
1426 // qPrint(ta->fileName),qPrint(ta->label));
1428 ta.label,ta.fileName,-1,ta.title,
1430 }
1431 }
1432}
1433
1434void TagFileParser::buildMemberList(const std::shared_ptr<Entry> &ce,const std::vector<TagMemberInfo> &members)
1435{
1436 for (const auto &tmi : members)
1437 {
1438 std::shared_ptr<Entry> me = std::make_shared<Entry>();
1439 me->type = tmi.type;
1440 me->name = tmi.name;
1441 me->args = tmi.arglist;
1442 if (!me->args.isEmpty())
1443 {
1444 me->argList = *stringToArgumentList(SrcLangExt::Cpp,me->args);
1445 }
1446 if (tmi.enumValues.size()>0)
1447 {
1448 me->spec.setStrong(true);
1449 for (const auto &evi : tmi.enumValues)
1450 {
1451 std::shared_ptr<Entry> ev = std::make_shared<Entry>();
1452 ev->type = "@";
1453 ev->name = evi.name;
1454 ev->id = evi.clangid;
1455 ev->section = EntryType::makeVariable();
1456 ev->tagInfoData.tagName = m_tagName;
1457 ev->tagInfoData.anchor = evi.anchor;
1458 ev->tagInfoData.fileName = evi.file;
1459 ev->hasTagInfo = TRUE;
1460 me->moveToSubEntryAndKeep(ev);
1461 }
1462 }
1463 me->protection = tmi.prot;
1464 me->virt = tmi.virt;
1465 me->isStatic = tmi.isStatic;
1466 me->fileName = ce->fileName;
1467 me->id = tmi.clangId;
1468 me->startLine = tmi.lineNr;
1469 if (ce->section.isGroupDoc())
1470 {
1471 me->groups.emplace_back(ce->name,Grouping::GROUPING_INGROUP);
1472 }
1473 addDocAnchors(me,tmi.docAnchors);
1474 me->tagInfoData.tagName = m_tagName;
1475 me->tagInfoData.anchor = tmi.anchor;
1476 me->tagInfoData.fileName = tmi.anchorFile;
1477 me->hasTagInfo = TRUE;
1478 if (tmi.kind=="define")
1479 {
1480 me->type="#define";
1481 me->section = EntryType::makeDefine();
1482 }
1483 else if (tmi.kind=="enumvalue")
1484 {
1485 me->section = EntryType::makeVariable();
1486 me->mtype = MethodTypes::Method;
1487 }
1488 else if (tmi.kind=="property")
1489 {
1490 me->section = EntryType::makeVariable();
1491 me->mtype = MethodTypes::Property;
1492 }
1493 else if (tmi.kind=="event")
1494 {
1495 me->section = EntryType::makeVariable();
1496 me->mtype = MethodTypes::Event;
1497 }
1498 else if (tmi.kind=="variable")
1499 {
1500 me->section = EntryType::makeVariable();
1501 me->mtype = MethodTypes::Method;
1502 }
1503 else if (tmi.kind=="typedef")
1504 {
1505 me->section = EntryType::makeVariable();
1506 me->type.prepend("typedef ");
1507 me->mtype = MethodTypes::Method;
1508 }
1509 else if (tmi.kind=="enumeration")
1510 {
1511 me->section = EntryType::makeEnum();
1512 me->mtype = MethodTypes::Method;
1513 }
1514 else if (tmi.kind=="function")
1515 {
1516 me->section = EntryType::makeFunction();
1517 me->mtype = MethodTypes::Method;
1518 }
1519 else if (tmi.kind=="signal")
1520 {
1521 me->section = EntryType::makeFunction();
1522 me->mtype = MethodTypes::Signal;
1523 }
1524 else if (tmi.kind=="prototype")
1525 {
1526 me->section = EntryType::makeFunction();
1527 me->mtype = MethodTypes::Method;
1528 }
1529 else if (tmi.kind=="friend")
1530 {
1531 me->section = EntryType::makeFunction();
1532 me->type.prepend("friend ");
1533 me->mtype = MethodTypes::Method;
1534 }
1535 else if (tmi.kind=="dcop")
1536 {
1537 me->section = EntryType::makeFunction();
1538 me->mtype = MethodTypes::DCOP;
1539 }
1540 else if (tmi.kind=="slot")
1541 {
1542 me->section = EntryType::makeFunction();
1543 me->mtype = MethodTypes::Slot;
1544 }
1545 ce->moveToSubEntryAndKeep(me);
1546 }
1547}
1548
1549void TagFileParser::buildClassEntry(const std::shared_ptr<Entry> &root, const TagClassInfo *tci)
1550{
1551 std::shared_ptr<Entry> ce = std::make_shared<Entry>();
1552 ce->section = EntryType::makeClass();
1553 switch (tci->kind)
1554 {
1555 case TagClassInfo::Kind::Class: break;
1556 case TagClassInfo::Kind::Struct: ce->spec = TypeSpecifier().setStruct(true); break;
1557 case TagClassInfo::Kind::Union: ce->spec = TypeSpecifier().setUnion(true); break;
1558 case TagClassInfo::Kind::Interface: ce->spec = TypeSpecifier().setInterface(true); break;
1559 case TagClassInfo::Kind::Enum: ce->spec = TypeSpecifier().setEnum(true); break;
1560 case TagClassInfo::Kind::Exception: ce->spec = TypeSpecifier().setException(true); break;
1561 case TagClassInfo::Kind::Protocol: ce->spec = TypeSpecifier().setProtocol(true); break;
1562 case TagClassInfo::Kind::Category: ce->spec = TypeSpecifier().setCategory(true); break;
1563 case TagClassInfo::Kind::Service: ce->spec = TypeSpecifier().setService(true); break;
1564 case TagClassInfo::Kind::Singleton: ce->spec = TypeSpecifier().setSingleton(true); break;
1565 case TagClassInfo::Kind::None: // should never happen, means not properly initialized
1566 assert(tci->kind != TagClassInfo::Kind::None);
1567 break;
1568 }
1569 ce->name = tci->name;
1571 {
1572 ce->name+="-p";
1573 }
1574 addDocAnchors(ce,tci->docAnchors);
1575 ce->tagInfoData.tagName = m_tagName;
1576 ce->tagInfoData.anchor = tci->anchor;
1577 ce->tagInfoData.fileName = tci->filename;
1578 ce->startLine = tci->lineNr;
1579 ce->fileName = m_tagName;
1580 ce->hasTagInfo = TRUE;
1581 ce->id = tci->clangId;
1582 ce->lang = tci->isObjC ? SrcLangExt::ObjC : SrcLangExt::Unknown;
1583 // transfer base class list
1584 ce->extends = tci->bases;
1585 if (!tci->templateArguments.empty())
1586 {
1587 ArgumentList al;
1588 for (const auto &argName : tci->templateArguments)
1589 {
1590 Argument a;
1591 a.type = "class";
1592 a.name = argName;
1593 al.push_back(a);
1594 }
1595 ce->tArgLists.push_back(al);
1596 }
1597
1598 buildMemberList(ce,tci->members);
1599 root->moveToSubEntryAndKeep(ce);
1600}
1601
1602void TagFileParser::buildClassTree(const std::shared_ptr<Entry> &root,const ClassNode &node)
1603{
1604 if (node.tci)
1605 {
1606 buildClassEntry(root,node.tci);
1607 }
1608 for (const auto &child : node.children)
1609 {
1610 buildClassTree(root,*child.second);
1611 }
1612}
1613
1614/*! Injects the info gathered by the XML parser into the Entry tree.
1615 * This tree contains the information extracted from the input in a
1616 * "unrelated" form.
1617 */
1618void TagFileParser::buildLists(const std::shared_ptr<Entry> &root)
1619{
1620 // First reorganize the entries in m_tagFileCompounds such that
1621 // outer scope is processed before the nested class scope.
1622 // To solve issue #11569, where a class nested in a specialization is
1623 // processed first, which later causes the wrong class to be used
1624 ClassNode classRoot("");
1625 for (const auto &comp : m_tagFileCompounds)
1626 {
1627 const TagClassInfo *tci = comp.getClassInfo();
1628 if (tci)
1629 {
1630 ClassNode *current = &classRoot;
1631 auto parts = split(tci->name.str(),"::");
1632 for (size_t i=0; i<parts.size(); ++i)
1633 {
1634 const auto &part = parts[i];
1635 if (current->children.find(part)==current->children.end()) // new child node
1636 {
1637 current->children[part] = std::make_unique<ClassNode>(part);
1638 }
1639 current = current->children[part].get();
1640 if (i==parts.size()-1)
1641 {
1642 current->tci = tci;
1643 }
1644 }
1645 }
1646 }
1647
1648 // now process the classes following the tree structure
1649 buildClassTree(root,classRoot);
1650
1651
1652 // build file list
1653 for (const auto &comp : m_tagFileCompounds)
1654 {
1655 const TagFileInfo *tfi = comp.getFileInfo();
1656 if (tfi)
1657 {
1658 std::shared_ptr<Entry> fe = std::make_shared<Entry>();
1659 fe->section = guessSection(tfi->name);
1660 fe->name = tfi->name;
1661 addDocAnchors(fe,tfi->docAnchors);
1662 fe->tagInfoData.tagName = m_tagName;
1663 fe->tagInfoData.fileName = tfi->filename;
1664 fe->hasTagInfo = TRUE;
1665
1666 QCString fullName = m_tagName+":"+tfi->path+stripPath(tfi->name);
1667 fe->fileName = fullName;
1668 fe->startLine = tfi->lineNr;
1669 //printf("createFileDef() filename=%s\n",qPrint(tfi->filename));
1670 QCString tagid = m_tagName+":"+tfi->path;
1671 auto fd = createFileDef(tagid, tfi->name,m_tagName, tfi->filename);
1672 FileName *mn = Doxygen::inputNameLinkedMap->find(tfi->name);
1673 if (mn)
1674 {
1675 mn->push_back(std::move(fd));
1676 }
1677 else
1678 {
1679 mn = Doxygen::inputNameLinkedMap->add(tfi->name,fullName);
1680 mn->push_back(std::move(fd));
1681 }
1682 buildMemberList(fe,tfi->members);
1683 root->moveToSubEntryAndKeep(fe);
1684 }
1685 }
1686
1687 // build concept list
1688 for (const auto &comp : m_tagFileCompounds)
1689 {
1690 const TagConceptInfo *tci = comp.getConceptInfo();
1691 if (tci)
1692 {
1693 std::shared_ptr<Entry> ce = std::make_shared<Entry>();
1694 ce->section = EntryType::makeConcept();
1695 ce->name = tci->name;
1696 addDocAnchors(ce,tci->docAnchors);
1697 ce->tagInfoData.tagName = m_tagName;
1698 ce->tagInfoData.fileName = tci->filename;
1699 ce->startLine = tci->lineNr;
1700 ce->fileName = m_tagName;
1701 ce->hasTagInfo = TRUE;
1702 ce->id = tci->clangId;
1703
1704 root->moveToSubEntryAndKeep(ce);
1705 }
1706 }
1707
1708 // build module list
1709 for (const auto &comp : m_tagFileCompounds)
1710 {
1711 const TagModuleInfo *tmi = comp.getModuleInfo();
1712 if (tmi)
1713 {
1714 auto &mm = ModuleManager::instance();
1715 mm.createModuleDef(tmi->filename,tmi->lineNr,1,true,tmi->name,QCString());
1716 mm.addTagInfo(tmi->filename,m_tagName,tmi->clangId);
1717
1718 ModuleDef *mod = mm.getPrimaryInterface(tmi->name);
1719 if (mod && !tmi->docAnchors.empty())
1720 {
1721 std::vector<const SectionInfo *> anchorList;
1722 for (const auto &ta : tmi->docAnchors)
1723 {
1724 if (SectionManager::instance().find(ta.label)==nullptr)
1725 {
1726 //printf("New sectionInfo file=%s anchor=%s\n",
1727 // qPrint(ta->fileName),qPrint(ta->label));
1729 ta.label,ta.fileName,-1,ta.title,
1731 anchorList.push_back(si);
1732 }
1733 else
1734 {
1735 p_warn("Duplicate anchor {} found",ta.label);
1736 }
1737 }
1738 mod->addSectionsToDefinition(anchorList);
1739 }
1740 }
1741 }
1742
1743
1744 // build namespace list
1745 for (const auto &comp : m_tagFileCompounds)
1746 {
1747 const TagNamespaceInfo *tni = comp.getNamespaceInfo();
1748 if (tni)
1749 {
1750 std::shared_ptr<Entry> ne = std::make_shared<Entry>();
1751 ne->section = EntryType::makeNamespace();
1752 ne->name = tni->name;
1753 addDocAnchors(ne,tni->docAnchors);
1754 ne->tagInfoData.tagName = m_tagName;
1755 ne->tagInfoData.fileName = tni->filename;
1756 ne->startLine = tni->lineNr;
1757 ne->fileName = m_tagName;
1758 ne->hasTagInfo = TRUE;
1759 ne->id = tni->clangId;
1760
1761 buildMemberList(ne,tni->members);
1762 root->moveToSubEntryAndKeep(ne);
1763 }
1764 }
1765
1766 // build package list
1767 for (const auto &comp : m_tagFileCompounds)
1768 {
1769 const TagPackageInfo *tpgi = comp.getPackageInfo();
1770 if (tpgi)
1771 {
1772 std::shared_ptr<Entry> pe = std::make_shared<Entry>();
1773 pe->section = EntryType::makePackage();
1774 pe->name = tpgi->name;
1775 addDocAnchors(pe,tpgi->docAnchors);
1776 pe->tagInfoData.tagName = m_tagName;
1777 pe->tagInfoData.fileName = tpgi->filename;
1778 pe->startLine = tpgi->lineNr;
1779 pe->fileName = m_tagName;
1780 pe->hasTagInfo = TRUE;
1781
1782 buildMemberList(pe,tpgi->members);
1783 root->moveToSubEntryAndKeep(pe);
1784 }
1785 }
1786
1787 // build group list
1788 for (const auto &comp : m_tagFileCompounds)
1789 {
1790 const TagGroupInfo *tgi = comp.getGroupInfo();
1791 if (tgi)
1792 {
1793 std::shared_ptr<Entry> ge = std::make_shared<Entry>();
1794 ge->section = EntryType::makeGroupDoc();
1795 ge->name = tgi->name;
1796 ge->type = tgi->title;
1797 addDocAnchors(ge,tgi->docAnchors);
1798 ge->tagInfoData.tagName = m_tagName;
1799 ge->tagInfoData.fileName = tgi->filename;
1800 ge->startLine = tgi->lineNr;
1801 ge->fileName = m_tagName;
1802 ge->hasTagInfo = TRUE;
1803
1804 buildMemberList(ge,tgi->members);
1805 root->moveToSubEntryAndKeep(ge);
1806 }
1807 }
1808
1809 for (const auto &comp : m_tagFileCompounds)
1810 {
1811 const TagGroupInfo *tgi = comp.getGroupInfo();
1812 if (tgi)
1813 {
1814 // set subgroup relations bug_774118
1815 for (const auto &sg : tgi->subgroupList)
1816 {
1817 const auto &children = root->children();
1818 auto i = std::find_if(children.begin(),children.end(),
1819 [&](const std::shared_ptr<Entry> &e) { return e->name == sg; });
1820 if (i!=children.end())
1821 {
1822 (*i)->groups.emplace_back(tgi->name,Grouping::GROUPING_INGROUP);
1823 }
1824 }
1825 }
1826 }
1827
1828 // build page list
1829 for (const auto &comp : m_tagFileCompounds)
1830 {
1831 const TagPageInfo *tpi = comp.getPageInfo();
1832 if (tpi)
1833 {
1834 std::shared_ptr<Entry> pe = std::make_shared<Entry>();
1835 bool isIndex = (stripExtensionGeneral(tpi->filename,getFileNameExtension(tpi->filename))=="index");
1836 pe->section = isIndex ? EntryType::makeMainpageDoc() : EntryType::makePageDoc();
1837 pe->name = tpi->name;
1838 pe->args = tpi->title;
1839 for (const auto &subpage : tpi->subpages)
1840 {
1841 // we add subpage labels as a kind of "inheritance" relation to prevent
1842 // needing to add another list to the Entry class.
1843 pe->extends.emplace_back(stripExtension(subpage),Protection::Public,Specifier::Normal);
1844 }
1845 addDocAnchors(pe,tpi->docAnchors);
1846 pe->tagInfoData.tagName = m_tagName;
1847 pe->tagInfoData.fileName = stripExtension(tpi->filename);
1848 pe->startLine = tpi->lineNr;
1849 pe->fileName = m_tagName;
1850 pe->hasTagInfo = TRUE;
1851 root->moveToSubEntryAndKeep(pe);
1852 }
1853 }
1854
1855 // build requirement list
1856 for (const auto &comp : m_tagFileCompounds)
1857 {
1858 const TagRequirementInfo *tri = comp.getRequirementInfo();
1859 if (tri)
1860 {
1861 std::shared_ptr<Entry> pe = std::make_shared<Entry>();
1862 pe->section = EntryType::makeRequirementDoc();
1863 pe->name = tri->id;
1864 pe->type = tri->title;
1865 pe->tagInfoData.tagName = m_tagName;
1866 pe->tagInfoData.fileName = tri->filename;
1867 pe->startLine = tri->lineNr;
1868 pe->fileName = m_tagName;
1869 pe->hasTagInfo = true;
1870 //printf("Reading requirement '%s' from tag file. title=%s\n",qPrint(pe->name),qPrint(pe->type));
1871 root->moveToSubEntryAndKeep(pe);
1872 }
1873 }
1874}
1875
1877{
1878 for (const auto &comp : m_tagFileCompounds)
1879 {
1880 const TagFileInfo *tfi = comp.getFileInfo();
1881 if (tfi)
1882 {
1883 //printf("tag file tagName=%s path=%s name=%s\n",qPrint(m_tagName),qPrint(tfi->path),qPrint(tfi->name));
1884 FileName *fn = Doxygen::inputNameLinkedMap->find(tfi->name);
1885 if (fn)
1886 {
1887 for (const auto &fd : *fn)
1888 {
1889 //printf("input file path=%s name=%s\n",qPrint(fd->getPath()),qPrint(fd->name()));
1890 if (fd->getPath()==QCString(m_tagName+":"+tfi->path))
1891 {
1892 //printf("found\n");
1893 for (const auto &ii : tfi->includes)
1894 {
1895 //printf("ii->name='%s'\n",qPrint(ii->name));
1896 FileName *ifn = Doxygen::inputNameLinkedMap->find(ii.name);
1897 ASSERT(ifn!=nullptr);
1898 if (ifn)
1899 {
1900 for (const auto &ifd : *ifn)
1901 {
1902 //printf("ifd->getOutputFileBase()=%s ii->id=%s\n",
1903 // qPrint(ifd->getOutputFileBase()),qPrint(ii->id));
1904 if (ifd->getOutputFileBase()==ii.id)
1905 {
1907 if (ii.isModule)
1908 {
1910 }
1911 else if (ii.isImported)
1912 {
1914 }
1915 else if (ii.isLocal)
1916 {
1918 }
1919 fd->addIncludeDependency(ifd.get(),ii.text,kind);
1920 }
1921 }
1922 }
1923 }
1924 }
1925 }
1926 }
1927 }
1928 }
1929}
1930
1931} // namespace
1932
1933// ----------------- public part -----------------------------------------------
1934
1935void parseTagFile(const std::shared_ptr<Entry> &root,const char *fullName)
1936{
1937 TagFileParser tagFileParser(fullName);
1938 QCString inputStr = fileToString(fullName);
1939 XMLHandlers handlers;
1940 // connect the generic events handlers of the XML parser to the specific handlers of the tagFileParser object
1941 handlers.startDocument = [&tagFileParser]() { tagFileParser.startDocument(); };
1942 handlers.startElement = [&tagFileParser](const std::string &name,const XMLHandlers::Attributes &attrs) { tagFileParser.startElement(name,attrs); };
1943 handlers.endElement = [&tagFileParser](const std::string &name) { tagFileParser.endElement(name); };
1944 handlers.characters = [&tagFileParser](const std::string &chars) { tagFileParser.characters(chars); };
1945 handlers.error = [&tagFileParser](const std::string &fileName,int lineNr,const std::string &msg) { tagFileParser.error(fileName,lineNr,msg); };
1946 XMLParser parser(handlers);
1947 tagFileParser.setDocumentLocator(&parser);
1948 parser.parse(fullName,inputStr.data(),Debug::isFlagSet(Debug::Lex_xml),
1949 [&]() { DebugLex::print(Debug::Lex_xml,"Entering","libxml/xml.l",fullName); },
1950 [&]() { DebugLex::print(Debug::Lex_xml,"Finished", "libxml/xml.l",fullName); }
1951 );
1952 tagFileParser.buildLists(root);
1953 tagFileParser.addIncludes();
1955 {
1956 tagFileParser.dump();
1957 }
1958}
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:70
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:132
static void print(DebugMask mask, int prio, fmt::format_string< Args... > fmt, Args &&... args)
Definition debug.h:76
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:101
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:260
const std::string & str() const
Definition qcstring.h:552
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
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:654
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:822
std::unique_ptr< FileDef > createFileDef(const QCString &p, const QCString &n, const QCString &ref, const QCString &dn)
Definition filedef.cpp:269
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:4929
QCString fileToString(const QCString &name, bool filter, bool isSourceCode)
Definition util.cpp:1471
QCString stripExtensionGeneral(const QCString &fName, const QCString &ext)
Definition util.cpp:4914
QCString stripExtension(const QCString &fName)
Definition util.cpp:4924
EntryType guessSection(const QCString &name)
Definition util.cpp:339
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:6618
QCString getFileNameExtension(const QCString &fn)
Definition util.cpp:5233
A bunch of utility functions.