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