diff --git a/.gitattributes b/.gitattributes index 3bba172..44d8cf5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -30,6 +30,10 @@ *.psd binary *.rc binary *.xlsx binary +*.woff binary +*.woff2 binary +*.otf binary +*.ttf binary */generated/** linguist-generated */m.css/** linguist-vendored diff --git a/poxy/doxygen.py b/poxy/doxygen.py index 9134741..9b02d13 100644 --- a/poxy/doxygen.py +++ b/poxy/doxygen.py @@ -289,6 +289,9 @@ def _parse_xml_file(g: graph.Graph, path: Path, parser: etree.XMLParser, log_fun root = etree.fromstring(read_all_text_from_file(path, logger=log_func).encode(r'utf-8'), parser=parser) + if root.tag not in (r'doxygenindex', r'doxygen'): + return + def extract_subelement_text(elem, subelem_tag: str): assert elem is not None assert subelem_tag is not None @@ -307,14 +310,60 @@ def extract_qualified_name(elem): return n return None - if root.tag not in (r'doxygenindex', r'doxygen'): - return + def parse_structured_text(node: graph.Node, elem): + nonlocal g + # top-level text in the tag + if elem.text: + text = g.get_or_create_node(type=graph.Text) + text.text = elem.text + node.connect_to(text) + # child + for child_elem in elem: + if child_elem.tag == r'para': + para = g.get_or_create_node(type=graph.Paragraph) + parse_structured_text(para, child_elem) + node.connect_to(para) + elif child_elem.tag == r'ref': + ref = g.get_or_create_node(type=graph.Text) + ref.text = child_elem.text + ref.reference_id = child_elem.get(r'refid') + node.connect_to(ref) + else: + raise Error(rf'Unknown <{elem.tag}> child element <{child_elem.tag}>') + # text that came after the child + if child_elem.tail: + text = g.get_or_create_node(type=graph.Text) + text.text = child_elem.tail + node.connect_to(text) + + def parse_text_subnode(node: graph.Node, subnode_type, elem, subelem_tag: str): + assert node is not None + assert elem is not None + assert subelem_tag is not None + assert subnode_type is not None + if subnode_type in node: + return + subelem = elem.find(subelem_tag) + if subelem is None: + return + nonlocal g + subnode = g.get_or_create_node(type=subnode_type) + node.connect_to(subnode) + parse_structured_text(subnode, subelem) + + def parse_brief(node, elem): + parse_text_subnode(node, graph.BriefDescription, elem, r'briefdescription') + + def parse_detail(node, elem): + parse_text_subnode(node, graph.DetailedDescription, elem, r'detaileddescription') + + def parse_initializer(node, elem): + parse_text_subnode(node, graph.Initializer, elem, r'initializer') # # (these are doxygen's version of 'forward declarations') for compound in root.findall(r'compound'): - node = g.get_or_create_node(compound.get(r'refid')) - node.node_type = _to_node_type(compound.get(r'kind')) + node = g.get_or_create_node(id=compound.get(r'refid'), type=_to_node_type(compound.get(r'kind'))) node.qualified_name = extract_qualified_name(compound) # @@ -322,8 +371,7 @@ def extract_qualified_name(elem): member_kind = member_elem.get(r'kind') if member_kind == r'enumvalue': continue - member = g.get_or_create_node(member_elem.get(r'refid')) - member.node_type = _to_node_type(member_kind) + member = g.get_or_create_node(id=member_elem.get(r'refid'), type=_to_node_type(member_kind)) node.connect_to(member) # manually rebuild the fully-qualified name name = extract_subelement_text(member_elem, r'name') @@ -338,8 +386,7 @@ def extract_qualified_name(elem): # for compounddef in root.findall(r'compounddef'): - node = g.get_or_create_node(compounddef.get(r'id')) - node.node_type = _to_node_type(compounddef.get(r'kind')) + node = g.get_or_create_node(id=compounddef.get(r'id'), type=_to_node_type(compounddef.get(r'kind'))) node.qualified_name = extract_qualified_name(compounddef) node.access_level = compounddef.get(r'prot') @@ -369,25 +416,27 @@ def get_all_attrib_memberdefs(kind: str): # enums for enum_elem in get_all_type_memberdefs(r'enum'): - enum = g.get_or_create_node(enum_elem.get(r'id')) - enum.node_type = graph.Enum + enum = g.get_or_create_node(id=enum_elem.get(r'id'), type=graph.Enum) enum.access_level = enum_elem.get(r'prot') enum.strong = enum_elem.get(r'strong') enum.static = enum_elem.get(r'static') enum.local_name = extract_subelement_text(enum_elem, r'name') enum.qualified_name = extract_qualified_name(enum_elem) + parse_brief(enum, enum_elem) + parse_detail(enum, enum_elem) node.connect_to(enum) for value_elem in enum_elem.findall(r'enumvalue'): - value = g.get_or_create_node(value_elem.get(r'id')) - value.node_type = graph.EnumValue + value = g.get_or_create_node(id=value_elem.get(r'id'), type=graph.EnumValue) value.access_level = value_elem.get(r'prot') value.local_name = extract_subelement_text(value_elem, r'name') + parse_brief(value, value_elem) + parse_detail(value, value_elem) + parse_initializer(value, value_elem) enum.connect_to(value) # vars for var_elem in get_all_attrib_memberdefs(r'variable'): - var = g.get_or_create_node(var_elem.get(r'id')) - var.node_type = graph.Variable + var = g.get_or_create_node(id=var_elem.get(r'id'), type=graph.Variable) var.access_level = var_elem.get(r'prot') var.static = var_elem.get(r'static') var.constexpr = var_elem.get(r'constexpr') @@ -397,12 +446,15 @@ def get_all_attrib_memberdefs(kind: str): var.definition = extract_subelement_text(var_elem, r'definition') var.local_name = extract_subelement_text(var_elem, r'name') var.qualified_name = extract_qualified_name(var_elem) + parse_brief(var, var_elem) + parse_detail(var, var_elem) + parse_initializer(var, var_elem) node.connect_to(var) # for inner_suffix in (r'namespace', r'class', r'concept', r'dir', r'file'): for inner_elem in compounddef.findall(rf'inner{inner_suffix}'): - inner = g.get_or_create_node(inner_elem.get(r'refid')) + inner = g.get_or_create_node(id=inner_elem.get(r'refid')) if inner_suffix == r'class': if inner.id.startswith(r'class'): inner.node_type = graph.Class @@ -416,7 +468,7 @@ def get_all_attrib_memberdefs(kind: str): node.connect_to(inner) # deduce any missing qualified_names - # for _, node in g(graph.Namespace, graph.Class, graph.Struct, graph.Union): + # for node in g(graph.Namespace, graph.Class, graph.Struct, graph.Union): @@ -453,8 +505,69 @@ def write_graph_to_xml(g: graph.Graph, folder: Path, log_func=None): global NODE_TYPES_TO_KINDS global VERSION + def make_text_subnode(elem, subelem_tag: str, node: graph.Node, subnode_type): + assert node is not None + assert elem is not None + assert subelem_tag is not None + assert subnode_type is not None + subelem = etree.SubElement(elem, subelem_tag) + subelem.text = r'' + if subnode_type not in node: + return + text = [n for n in node(subnode_type)] # list of BriefDescription + text = [[i for i in n(graph.Paragraph, graph.Text)] for n in text] # list of lists of Text/Paragraph + text = list(itertools.chain.from_iterable(text)) # list of Text/Paragraph + if not text: + return + # all the ones at the start that are just plain text get + # concatenated and set as the main text of the root subelement + while text and text[0].node_type is graph.Text and not text[0].reference_id: + subelem.text = subelem.text + text[0].text + text.pop(0) + # otherwise we need to loop through and make paragraphs/references + prev = None + while text: + if text[0].node_type is graph.Paragraph: + para = etree.SubElement(subelem, rf'para') + para.text = text[0].text + para_children = [n for n in text[0](graph.Text)] + text.pop(0) + prev = para + while para_children and not para_children[0].reference_id: + para.text = para.text + para_children[0].text + para_children.pop(0) + para_prev = None + while para_children: + if para_children[0].reference_id: + para_prev = etree.SubElement(subelem, rf'ref', attrib={r'refid': para_children[0].reference_id}) + para_prev.text = para_children[0].text + para_children.pop(0) + else: + assert para_prev is not None + while para_children and not para_children[0].reference_id: + para_prev.tail = para_prev.tail + para_children[0].text + para_children.pop(0) + elif text[0].reference_id: + prev = etree.SubElement(subelem, rf'ref', attrib={r'refid': text[0].reference_id}) + prev.text = text[0].text + text.pop(0) + else: + assert prev is not None + while text and text[0].node_type is graph.Text and not text[0].reference_id: + prev.tail = prev.tail + text[0].text + text.pop(0) + + def make_brief(elem, node): + make_text_subnode(elem, r'briefdescription', node, graph.BriefDescription) + + def make_detail(elem, node): + make_text_subnode(elem, r'detaileddescription', node, graph.DetailedDescription) + + def make_initializer(elem, node): + make_text_subnode(elem, r'initializer', node, graph.Initializer) + # serialize the compound nodes - for _, node in g(*COMPOUND_NODE_TYPES): + for node in g(*COMPOUND_NODE_TYPES): if not node: continue assert node.qualified_name @@ -486,14 +599,14 @@ def write_graph_to_xml(g: graph.Graph, folder: Path, log_func=None): # if node.node_type in (graph.Class, graph.Struct, graph.Union): - files = [f for _, f in g(graph.File) if (f and f is not node and node in f)] + files = [f for f in g(graph.File) if (f and f is not node and node in f)] for f in files: assert f.qualified_name elem = etree.SubElement(compounddef, rf'includes', attrib={r'local': r'no'}) elem.text = f.qualified_name # add the inners - for _, inner_node in node( + for inner_node in node( graph.Namespace, graph.Class, graph.Struct, graph.Union, graph.Concept, graph.Directory, graph.File ): if not inner_node: @@ -528,7 +641,7 @@ def write_graph_to_xml(g: graph.Graph, folder: Path, log_func=None): sectiondefs = {k: etree.SubElement(compounddef, r'sectiondef', attrib={r'kind': k}) for k in sectiondefs} # enums - for _, enum in node(graph.Enum): + for enum in node(graph.Enum): section = r'enum' if node.node_type in (graph.Class, graph.Struct, graph.Union): section = rf'{Prot(enum.access_level)}-type' @@ -546,10 +659,10 @@ def write_graph_to_xml(g: graph.Graph, folder: Path, log_func=None): etree.SubElement(enum_elem, r'type').text = enum.type etree.SubElement(enum_elem, r'name').text = enum.local_name etree.SubElement(enum_elem, r'qualified_name').text = enum.qualified_name - etree.SubElement(enum_elem, r'briefdescription') - etree.SubElement(enum_elem, r'detaileddescription') - etree.SubElement(enum_elem, r'inbodydescription') - for _, value in enum(graph.EnumValue): + make_brief(enum_elem, enum) + make_detail(enum_elem, enum) + etree.SubElement(enum_elem, r'inbodydescription').text = r'' # todo + for value in enum(graph.EnumValue): value_elem = etree.SubElement( enum_elem, rf'enumvalue', attrib={ r'id': value.id, @@ -557,11 +670,12 @@ def write_graph_to_xml(g: graph.Graph, folder: Path, log_func=None): } ) etree.SubElement(value_elem, r'name').text = value.local_name - etree.SubElement(value_elem, r'briefdescription') - etree.SubElement(value_elem, r'detaileddescription') + make_brief(value_elem, value) + make_detail(value_elem, value) + make_initializer(value_elem, value) # variables - for _, var in node(graph.Variable): + for var in node(graph.Variable): section = r'var' if node.node_type in (graph.Class, graph.Struct, graph.Union): section = rf'{Prot(var.access_level)}-{"static-" if var.static else ""}attrib' @@ -580,10 +694,14 @@ def write_graph_to_xml(g: graph.Graph, folder: Path, log_func=None): ) etree.SubElement(var_elem, r'type').text = var.type etree.SubElement(var_elem, r'definition').text = var.definition + etree.SubElement(var_elem, r'argsstring') etree.SubElement(var_elem, r'name').text = var.local_name etree.SubElement(var_elem, r'qualified_name').text = var.qualified_name - etree.SubElement(var_elem, r'briefdescription') - etree.SubElement(var_elem, r'detaileddescription') + make_brief(var_elem, var) + make_detail(var_elem, var) + make_initializer(var_elem, var) + etree.SubElement(var_elem, r'inbodydescription').text = r'' # todo + etree.SubElement(var_elem, r'location') # if node.node_type in (graph.Class, graph.Struct, graph.Union): diff --git a/poxy/graph.py b/poxy/graph.py index 9a6b58c..9b2ba60 100644 --- a/poxy/graph.py +++ b/poxy/graph.py @@ -112,26 +112,67 @@ class File(object): +class BriefDescription(object): + '''A brief description of an element.''' + pass + + + +class DetailedDescription(object): + '''A more detailed description of an element.''' + pass + + + +class Initializer(object): + '''An initializer block (usually a code snippet).''' + pass + + + +class Paragraph(object): + '''A paragraph.''' + pass + + + +class Text(object): + '''Plain text, optionally with reference semantics.''' + pass + + + +DESCRIPTION_NODE_TYPES = {BriefDescription, DetailedDescription} NODE_TYPES = { Namespace, Class, Struct, Union, Concept, Function, Variable, Enum, EnumValue, Typedef, Define, Group, MemberGroup, - Article, Directory, File + Article, Directory, File, *DESCRIPTION_NODE_TYPES, Initializer, Paragraph, Text +} +Namespace.CAN_CONNECT_TO = { + Function, Class, Struct, Union, Variable, Typedef, Namespace, Concept, Enum, *DESCRIPTION_NODE_TYPES } -Namespace.CAN_CONNECT_TO = {Function, Class, Struct, Union, Variable, Typedef, Namespace, Concept, Enum} -Class.CAN_CONNECT_TO = {Class, Struct, Union, Function, Variable, Typedef, Enum, MemberGroup} +Class.CAN_CONNECT_TO = {Class, Struct, Union, Function, Variable, Typedef, Enum, MemberGroup, *DESCRIPTION_NODE_TYPES} Struct.CAN_CONNECT_TO = Class.CAN_CONNECT_TO Union.CAN_CONNECT_TO = Class.CAN_CONNECT_TO -Concept.CAN_CONNECT_TO = set() -Function.CAN_CONNECT_TO = set() # not stricty true in C++ but true w.r.t documentation -Variable.CAN_CONNECT_TO = set() -Enum.CAN_CONNECT_TO = {EnumValue} -EnumValue.CAN_CONNECT_TO = set() -Typedef.CAN_CONNECT_TO = set() -Define.CAN_CONNECT_TO = set() +Concept.CAN_CONNECT_TO = {Initializer, *DESCRIPTION_NODE_TYPES} +Function.CAN_CONNECT_TO = DESCRIPTION_NODE_TYPES +Variable.CAN_CONNECT_TO = {Initializer, *DESCRIPTION_NODE_TYPES} +Enum.CAN_CONNECT_TO = {EnumValue, *DESCRIPTION_NODE_TYPES} +EnumValue.CAN_CONNECT_TO = {Initializer, *DESCRIPTION_NODE_TYPES} +Typedef.CAN_CONNECT_TO = DESCRIPTION_NODE_TYPES +Define.CAN_CONNECT_TO = {Initializer, *DESCRIPTION_NODE_TYPES} Group.CAN_CONNECT_TO = {t for t in NODE_TYPES if t not in (Article, )} MemberGroup.CAN_CONNECT_TO = {t for t in Class.CAN_CONNECT_TO if t not in (MemberGroup, )} -Article.CAN_CONNECT_TO = set() -File.CAN_CONNECT_TO = {Namespace, Class, Struct, Union, Concept, Function, Variable, Enum, Typedef, Define, Article} -Directory.CAN_CONNECT_TO = {Directory, File} +Article.CAN_CONNECT_TO = DESCRIPTION_NODE_TYPES +File.CAN_CONNECT_TO = { + Namespace, Class, Struct, Union, Concept, Function, Variable, Enum, Typedef, Define, Article, + *DESCRIPTION_NODE_TYPES +} +Directory.CAN_CONNECT_TO = {Directory, File, *DESCRIPTION_NODE_TYPES} +BriefDescription.CAN_CONNECT_TO = {Paragraph, Text} +DetailedDescription.CAN_CONNECT_TO = {Paragraph, Text} +Initializer.CAN_CONNECT_TO = {Text} +Paragraph.CAN_CONNECT_TO = {Text} +Text.CAN_CONNECT_TO = set() @@ -157,7 +198,8 @@ class _Props(object): def __init__(self, id: str): assert id is not None self.__id = id - self.__connections = dict() + self.__connections = [] + self.__connections_by_id = dict() self.__props = Node._Props() #============== @@ -263,12 +305,16 @@ def access_level(self) -> AccessLevel: ) @property - def brief(self) -> str: - return self.__property_get(r'brief', str, r'') + def text(self) -> str: + return self.__property_get(r'text', str, r'') + + @property + def reference_id(self) -> str: + return self.__property_get(r'reference_id', str, r'') @property - def detail(self) -> str: - return self.__property_get(r'detail', str, r'') + def is_paragraph(self) -> bool: + return self.__property_get(r'is_paragraph', bool, False) def __bool__(self) -> bool: return self.has_node_type and bool(self.id) @@ -281,7 +327,7 @@ def __property_is_set(self, name: str) -> bool: assert name is not None return hasattr(self.__props, str(name)) - def __property_set(self, name: str, out_type, value): + def __property_set(self, name: str, out_type, value, strip_strings=False): assert name is not None # known types that have a sensible __bool__ operator can convert to None if false if isinstance(value, (str, Path, list, tuple, dict)): @@ -294,7 +340,7 @@ def __property_set(self, name: str, out_type, value): elif value.lower() in (r'yes', r'true', r'enabled'): value = True else: - raise Exception(rf"C++ node '{self.id}' property '{name}' could not parse a boolean from '{value}'") + raise Error(rf"C++ node '{self.id}' property '{name}' could not parse a boolean from '{value}'") elif out_type is AccessLevel: if value.lower() in (r'pub', r'public'): value = AccessLevel.PUBLIC @@ -303,9 +349,7 @@ def __property_set(self, name: str, out_type, value): elif value.lower() in (r'priv', r'private'): value = AccessLevel.PRIVATE else: - raise Exception( - rf"C++ node '{self.id}' property '{name}' could not parse access level from '{value}'" - ) + raise Error(rf"C++ node '{self.id}' property '{name}' could not parse access level from '{value}'") assert isinstance(value, AccessLevel) # None == keep whatever the current value is (no-op) # (None is never a valid value for a real graph attribute) @@ -313,17 +357,19 @@ def __property_set(self, name: str, out_type, value): return if out_type is not None and not isinstance(value, out_type): value = out_type(value) + if strip_strings and isinstance(value, str): + value = value.strip() current = getattr(self.__props, str(name), None) # it's OK if there's already a value as long as it's identical to the new one, # otherwise we throw so that we can detect when the source data is bad or the adapter is faulty # (since if a property _can_ be defined in multiple places it should be identical in all of them) if current is not None: if type(current) != type(value): - raise Exception( + raise Error( rf"C++ node '{self.id}' property '{name}' first seen with type {type(current)}, now seen with type {type(value)}" ) if current != value: - raise Exception( + raise Error( rf"C++ node '{self.id}' property '{name}' first seen with value {current}, now seen with value {value}" ) return @@ -335,12 +381,12 @@ def node_type(self, value): if value is None: return if value not in NODE_TYPES: - raise Exception(rf"Unknown C++ node type '{value}'") + raise Error(rf"Unknown C++ node type '{value}'") had_node_type = self.has_node_type self.__property_set(r'node_type', None, value) if had_node_type != self.has_node_type: self.__deduce_local_name() - for _, node in self.__connections: + for node in self.__connections: Node._check_connection(self, node) def __deduce_local_name(self): @@ -363,36 +409,32 @@ def __deduce_local_name(self): @qualified_name.setter def qualified_name(self, value: str): - if value is not None: - value = str(value).strip() - self.__property_set(r'qualified_name', str, value) + self.__property_set(r'qualified_name', str, value, strip_strings=True) self.__deduce_local_name() @local_name.setter def local_name(self, value: str): - if value is not None: - value = str(value).strip() - self.__property_set(r'local_name', str, value) + self.__property_set(r'local_name', str, value, strip_strings=True) @type.setter def type(self, value: str): if value is not None: value = str(value).strip() - # extract constexpr, constinit, static, mutable etc out of the type if possible - attrs = re.fullmatch(r'^((?:(?:const(?:expr|init|eval)|static|mutable)\s)+).*?$', value) - if attrs: - value = value[len(attrs[1]):].strip() - if attrs[1].find(r'constexpr') != -1: - self.constexpr = True - if attrs[1].find(r'constinit') != -1: - self.constinit = True - if attrs[1].find(r'consteval') != -1: - self.consteval = True - if attrs[1].find(r'static') != -1: - self.static = True - if attrs[1].find(r'mutable') != -1: - self.mutable = True - self.__property_set(r'type', str, value) + # extract constexpr, constinit, static, mutable etc out of the type if possible + attrs = re.fullmatch(r'^((?:(?:const(?:expr|init|eval)|static|mutable)\s)+).*?$', value) + if attrs: + value = value[len(attrs[1]):].strip() + if attrs[1].find(r'constexpr') != -1: + self.constexpr = True + if attrs[1].find(r'constinit') != -1: + self.constinit = True + if attrs[1].find(r'consteval') != -1: + self.consteval = True + if attrs[1].find(r'static') != -1: + self.static = True + if attrs[1].find(r'mutable') != -1: + self.mutable = True + self.__property_set(r'type', str, value, strip_strings=True) @definition.setter def definition(self, value: str): @@ -450,14 +492,40 @@ def strong(self, value: bool): def access_level(self, value: AccessLevel): self.__property_set(r'access_level', AccessLevel, value) + @text.setter + def text(self, value: str): + self.__property_set(r'text', str, value) + + @reference_id.setter + def reference_id(self, value: str): + self.__property_set(r'reference_id', str, value, strip_strings=True) + + @is_paragraph.setter + def is_paragraph(self, value: bool): + self.__property_set(r'is_paragraph', bool, value) + #============== - # membership + # connections #============== @property def is_leaf(self) -> bool: return not bool(self.__connections) + def __contains__(self, node_or_id) -> bool: + global NODE_TYPES + assert node_or_id is not None + assert isinstance(node_or_id, (str, Node)) or node_or_id in NODE_TYPES + if isinstance(node_or_id, str): + return node_or_id in self.__connections_by_id + elif isinstance(node_or_id, Node): + return node_or_id in self.__connections + else: + for c in self.__connections: + if c.node_type is node_or_id: + return True + return False + @classmethod def _check_connection(cls, source, dest): assert source is not None @@ -467,7 +535,7 @@ def _check_connection(cls, source, dest): # self-connection is always illegal, regardless of node_type information if id(source) == id(dest): - raise Exception(rf"C++ node '{source.id}' may not connect to itself") + raise Error(rf"C++ node '{source.id}' may not connect to itself") # otherwise if we don't have node_type information the connection is 'OK' # (really this just means we defer the check until later) @@ -475,7 +543,7 @@ def _check_connection(cls, source, dest): return if dest.node_type not in source.node_type.CAN_CONNECT_TO: - raise Exception( + raise Error( rf"C++ node '{source.id}' with type {source.node_type_name} is not allowed to connect to nodes of type {dest.node_type_name}" ) @@ -486,24 +554,19 @@ def connect_to(self, dest): Node._check_connection(self, dest) # connecting to the same node twice is fine (no-op) - if dest.id in self.__connections: - existing_dest = self.__connections[dest.id] + if dest.id in self.__connections_by_id: + existing_dest = self.__connections_by_id[dest.id] # check that identity is unique if id(dest) != id(existing_dest): - raise Exception(rf"Two different C++ nodes seen with the same ID ('{dest.id}')") + raise Error(rf"Two different C++ nodes seen with the same ID ('{dest.id}')") return - self.__connections[dest.id] = dest - - def __contains__(self, node_or_id) -> bool: - assert isinstance(node_or_id, (str, Node)) - if isinstance(node_or_id, str): - return node_or_id in self.__connections - return node_or_id in self.__connections.values() + self.__connections.append(dest) + self.__connections_by_id[dest.id] = dest def __iter__(self): - for id, node in self.__connections.items(): - yield (id, node) + for node in self.__connections: + yield node def __call__(self, *node_types): assert node_types is not None @@ -518,12 +581,12 @@ def make_generator(nodes): nonlocal node_types yield_with_no_node_type = False in node_types or None in node_types yield_with_any_node_type = True in node_types - for id, node in nodes: + for node in nodes: if ((node.node_type is None and yield_with_no_node_type) or (node.node_type is not None and (yield_with_any_node_type or node.node_type in node_types))): - yield (id, node) + yield node - return make_generator(self.__connections.items()) + return make_generator(self.__connections) @@ -538,8 +601,12 @@ class Graph(object): def __init__(self): self.__nodes: typing.Dict[str, Node] self.__nodes = dict() + self.__next_unique_id = 0 - def get_or_create_node(self, id: str) -> Node: + def get_or_create_node(self, id: str = None, type=None) -> Node: + if id is None: + id = rf'__graph_unique_id_{self.__next_unique_id}' + self.__next_unique_id += 1 assert id node = None if id not in self.__nodes: @@ -547,6 +614,7 @@ def get_or_create_node(self, id: str) -> Node: self.__nodes[id] = node else: node = self.__nodes[id] + node.node_type = type return node def __iter__(self): @@ -566,9 +634,9 @@ def make_generator(nodes): nonlocal node_types yield_with_no_node_type = False in node_types or None in node_types yield_with_any_node_type = True in node_types - for id, node in nodes: + for _, node in nodes: if ((node.node_type is None and yield_with_no_node_type) or (node.node_type is not None and (yield_with_any_node_type or node.node_type in node_types))): - yield (id, node) + yield node return make_generator(self.__nodes.items()) diff --git a/tests/test_empty_project/test.toml b/tests/test_empty_project/test.toml index 7f9bdba..abd6076 100644 --- a/tests/test_empty_project/test.toml +++ b/tests/test_empty_project/test.toml @@ -1,4 +1,4 @@ -skip = false +#skip = true [xml] enabled = false diff --git a/tests/test_project/expected_html/Test!.tagfile.xml b/tests/test_project/expected_html/Test!.tagfile.xml index 09be7d2..c59f1ee 100644 --- a/tests/test_project/expected_html/Test!.tagfile.xml +++ b/tests/test_project/expected_html/Test!.tagfile.xml @@ -12,6 +12,13 @@ test::empty test::concept_1 test::nested::concept_2 + + #define + KEK + code_8h.html + a867e1e9e6c924393462cf7c1a78c6c3e + + unscoped_enum diff --git a/tests/test_project/expected_html/code_8h.html b/tests/test_project/expected_html/code_8h.html index f37632a..101c191 100644 --- a/tests/test_project/expected_html/code_8h.html +++ b/tests/test_project/expected_html/code_8h.html @@ -68,6 +68,7 @@

Contents

  • Classes
  • Enums
  • Variables
  • +
  • Defines
  • @@ -132,6 +133,25 @@

    Variables

    An inline variable.
    +
    +

    Defines

    +
    +
    + #define KEK +
    +
    A macro.
    +
    +
    +
    +

    Define documentation

    +
    +

    + #define KEK +

    +

    A macro.

    +

    More info.

    +
    +
    diff --git a/tests/test_project/expected_html/searchdata-v2.js b/tests/test_project/expected_html/searchdata-v2.js index 5eaf7ba..8d68fc3 100644 --- a/tests/test_project/expected_html/searchdata-v2.js +++ b/tests/test_project/expected_html/searchdata-v2.js @@ -1,2 +1,2 @@ /* Generated by https://mcss.mosra.cz/documentation/doxygen/. Do not edit. */ -Search.load('O+!-x000009RL6T3I_lH(hL9q%mx4e0RR9100CtL00001YzP1V00CkS00001VH5xW00C(l00001av%Tz00Chp00001b}Rq@00Cbz00001V>kc+00C(}00001bVL9E00Ci200001bWi{Q0RRC200CuO00001Y+wKY00ClV00001VQc^Z00C)o00001a(Dm$00Cis00002b9Pn$0E7Sl00Cc$00001W0U{@00C*500001Y@h%D00CmA000310ssI3WwHPO00C^a00001V!QwV00Cjb00001X~+No00DB&00001VblNs00DN|00001U*G@$00Cp>00001Y3u+100DIJ00001VfX+500DIV000310{{R4WeNcR00C?c0RR92ViW-Y00Chd0RR92X&?ar00D9)0RR92VJrav00MJ%1OWgt0RR92UpN5(00Cq|0RR92Wk>-400DGP0RR92V^jeE00CuM0RR92bYKAh00D1i0RR93b#kl#0BivO00D4v0RR92I(z{D0RaR6I)VX!00A+G0RR92UyuO+00DEB0RR92bDRMH00Cj50RRC22LJ#8F|Gjs00CdJ0RR92bhrTk00D5m0RR92WyAph00Cpl0RR92ZqNY$00L}pr~v@h0RRC21poj6G3EgP00Cd>0RR92bMOHG00DFM0RR92Vf+CA00C?Q0ssI3V+aBO00CbP0ssI3WfTGc00DFw0ssI3VITqk00C?!0ssI3a4Z4<00C_>0ssI3WjF!=0RRX900A;Y0ssI3Uq}J~00DGP0ssI3a8v>S00CuM0ssI3V_*UR00C}h0ssI3Z)^ep00Coi0ssI3I(PyA0Ra^NI(`Cx00Cr#0ssI3WsCv<00DH80ssI3bC?1E00Cv50ssL33IG8B3jhHC3;+NFFflT!0syW80I~uA00CdN0ssI3Y{UWp00Cjj0ssI3cF+O<00BDI0ssL44FEda0)PMkZQ=p|00DLC0ssI3ZtwyC00Cw80ssI3U;F|900CqI0{{R4We5WR00D3g0{{R4ZxjOn0RR>N0RR^O0RR{P00S^FG9Uv0Bm)2_0{{R4Un~Ov00C?|0{{R4VL$@_00DMJ0{{R4I!prq0Rb5RI#L6G00C`S0{{R4bzlPk00C}h0{{U48~^|TbaDd#00Com0{{R4b$kN=00DA>0{{R4bch2000L!mYy$v}0{{R4Uz7s?00Cs40{{R4WuyZD00DHW0{{R4bFc#d00CvT0{{U48UO$RWx@jh00C^q0{{R4V$1^o00Cjr0{{R4Y1jh*00DB|0{{R4VdMh<00DOD0{{R4U+@C}00Cq60{{R4Y5W5K00DFY1ONa5VF&~O00DFk1ONa6Zgac?02BlO00BB01ONd68vr^a1b_emF)9QA00Cbz1ONa5bT|Y600Cn@1ONa5bwmUJ00DAJ1ONa6V{{q=08j(~0RRpF0RRsG0RRvH00S^FGGGJ%WCQ?c1ONa5Uu*;b00C@z1ONa5VSoex00DM}1ONa5UyK9*00C{11ONa5b(jPI00C~E1ONa5WuycE00CdB1ONa5d9VZk00CpR1ONa5VY~zY00C#h1ONa5Wyk~o00C^y1ONa5I@AOJ0Ra&JI@$z)00C{_1ONa5b?5{D00D091ONa5W%L9900Ce61ONa5WB>&K00CtN1poj6a0~?i00D0j1poj6V;BVh00DCz1poj6ZX^W&0RR#J00Ct%1poj6Y%~P`00Ck;1poj6VL$}{00C)61poj6a!dsP00CiA1poj6c31@f00CcK1poj6Wn={a00C}l1poj6X>bJq00C@v1poj6ZhQp*0RR*L00DW31poj6bc_W600D541poj6ZI}fB00(1qZgX{MW!wP(J^}!w0svM704fClf&~Dc1poj6I-~^v0Ra;LI>H5j00DH!1poj7b8XNC05Spq00Cvz1pom61^@s7Xyyd~00A!Q1poj6W$*<600J>Gt^oi<0ssI3U;G6C00DFc1^@s7a0~_j00CtZ1^@s7V;BYi00Lxg_5}bQ1^@s8Y;ULm03-$g00Ct71poj6Z#V`300Cn@1^@v82>>rd27mwoV@d`900MGhN(2B11ONa7a$|H-1^^lZ09Xb90Rj~OI$wSQfRqCO00Crh1^@s7Wqbwz00DG@1^@s7bBG2200Cu=1^@y83IG-W0sspD7XShP3;-Aa00S^FGMWYepauY@1^@s7U#tcI00C^e1^@s7VZa6e019+taC2^Ub!=&6-~|9K1^{va0AdCJlm-CC1^_Ar0L}yef&~Dc1ps#d0JQ)B>;M2Q0RU$K0FD6w$N>P~0RRjF07C)*Z~_3F0szPY0Q3R?Cj$Uq0|1u;0M7#e1Oxy(1OQS50BZyQh6Dhz1OVOy015>FJp}-C1puA}0LTRZ=;-L^NJyCY_<-2h*vQz}*vRN0C@9$2*vRNuSOfqXIy!K5Vr*$+UvqR}bZKK>c42a9VPb4$03%^CH#s&oF*Gc42a9VPb4$03%^DGcY+hGi5nqGGS#mG-EboVliPdI5jmhH#IqCWjQtk02(?vaB^>SWn*+@WM6h+a%o{=Y-Io=VP!OAIAvxuF=H}jGGb*hH)Jz7WI1JFV>B>jH8VCjITHW?Iyz%)VRLg|F#uz1VRLhIWpi|2F<&ubY+-YAUtcjUXmo9C6951@I&@`iaBN|8WnW`#VRLg|F#uz1VRLhIWpi|2F<&usWo>Y5VRU6*Ut?@xb8}x`F)nCyZEOhu054;2WMwXB0Ap`tWnVaGE@*UZY!d(gIyz%-ZewL|bYC$5V{dL_WpH$KWpi|2F<&ubZ*F5{aCBc^F)nCyZEO_)06IEjZ*F5{aCBcX0Ap`%V`Xr3bY*jNUol@XZe??HWn^D5Uom5EZewL|bYEXGE@*UZY;$sB0Ay)$Up6>0HaBE3GcY+}F=1vnWjHc9H)UotV>4xDVq;`tVJ>KNZEOtyG&(wVVQgP80AVsPIb}37Ff?LeV>M)EHa9RZVKp%_WM(;KIXF0CVKWT?G&(wVVQgP90AXY{Ib>#LG%;giF)=kcHZ@^nW@TYvFlIG4W@ThHG%*bTG&(wVVQgPA0AVvXG&N#nF*0R0WHMwoIbk(5HaIe2HexYlW;HlAGh-6~5;{6_V{dR}WM5@&b!`A6VKZSeVmUN8I5A=}V`MZrG%_|eH#s*oI5#CHqWn?*KV>dT6IALREWnyD6VKg~0Ff=(dWD@`qIy!Z3b7OCCWn^DvZgp({BVl7PVKOl?W@a{KWH@3tVPQ5iVq`F6H8nFfVP!WkHZ>Cf5;{6*Zft38WnXq-a%o{=Y-Io=VP-OBHDWL}F*0R2IAvioWo9{KWivTtVlgl|I59XkIdo-nbO3H)ZDn(CVPj=YmZbY)~NXmo9C82~;yI(A`fUoZe+GB7!1G&C?YVqs%7WM(!uFfd^?F*0OkIb}IGIAUQl82~;yI(A`fUoik-WHvcuW@a=oV`DKfH90mlVPs}yVPP<4H8^HvWHvN082~;yI(A`fUorq;GdDCfVr4NhWjACpWH&isH8nOkGGR7iF=b{oI5sn58vq7|W-wzL0313xb97;JX=7h@VRC6LUtcjUXmo9C8vqwNI&NiibY)~;b98cbV{`ytF<&umWpi|8WM5x%baHiLbS`LgZEOM{0VDz~0WtwM0X+di14#o+1yBW40a^fF0A>Mc0B~?&XJu|-ZDn(CVPj=ya&L8TV{Bn_b8~cZbz^jOZfS3Bba`-PWMyV#X>w+1Y-MJ3ZewI+W@&C^Wo~tCWo~tCAa-GFc42a3Z*F5{aC86w'); +Search.load('O+!-x000009smFU9tQvb91Q>f+y(#u0RR9100CtL00001YzP1V00CkS00001VH5xW00C(l00001av%Tz00Chp00001b}Rq@00Cbz00001V>kc+00C(}00001bVL9E00Ci200001bWi{Q0RRC200CuO00001Y+wKY00ClV00001VQc^Z00C)o00001a(Dm$00Cis00002b9Pn$0E7Sl00Cc$00001W0U{@00C*500001Y@h%D00CmA000310ssI3WwHPO00C^a00001V!QwV00Cjb00001X~+No00DB&00001VblNs00DN|00001U*G@$00Cp>00001Y3u+100DIJ00001VfX+500DIV000310{{R4WeNcR00C?c0RR92ViW-Y00Chd0RR92X&?ar00D9)0RR92VJrav00MJ%1OWgt0RR92UpN5(00Cq|0RR92Wk>-400DGP0RR92V^jeE00CuM0RR92bYKAh00D1i0RR93b#kl#0BivO00D4v0RR92I(z{D0RaR6I)VX!00A+G0RR92UyuO+00DEB0RR92bDRMH00Cj50RRC22mk;9F|Gjs00CdJ0RR92bhrTk00D5m0RR92WyAph00Cpl0RR92ZqNY$00L}pr~v@h0RRC21poj6G3EgP00Cd>0RR92bMOHG00DFM0RR92Vf+CA00C?Q0ssI3V+aBO00CbP0ssI3WfTGc00DFw0ssI3VITqk00C?!0ssI3a4Z4<00C_>0ssI3WjF!=0RRaA00A;Y0ssI3Uq}J~00DGP0ssI3a8v>S00CuM0ssI3V_*UR00C}h0ssI3Z)^ep00Coi0ssI3I(PyA0Ra{OI(`Cx00Cr#0ssI3WsCv<00DH80ssI3bC?1E00Cv50ssL33jhHC3;+QD4FCWGFflT!0syW80I~uA00CdN0ssI3Y{UWp00Cjj0ssI3cF+O<00BDI0ssL44gfmb0)PMkZQ=p|00DLC0ssI3ZtwyC00Cw80ssI3U;F|900CqI0{{R4We5WR00D3g0{{R4ZxjOn0RR^O0RR{P0RR~Q00S^FG9Uv0Bm)2_0{{R4Un~Ov00C?|0{{R4VL$@_00DMJ0{{R4I!prq0Rb8SI#L6G00C`S0{{R4bzlPk00C}h0{{U49RL6UbaDd#00Com0{{R4b$kN=00DA>0{{R4bch2000L!mYy$v}0{{R4Uz7s?00Cs40{{R4WuyZD00DHW0{{R4bFc#d00CvT0{{U48vp&K00CtN1poj6a0~?i00D0j1poj6V;BVh00DCz1poj6ZX^W&0RR&K00Ct%1poj6Y%~P`00Ck;1poj6VL$}{00C)61poj6a!dsP00CiA1poj6c31@f00CcK1poj6Wn={a00C}l1poj6X>bJq00C@v1poj6ZhQp*0RR;M00DW31poj6bc_W600D541poj6ZI}fB00(1qZgX{MW!wP(J^}!w0svM704fClf&~Dc1poj6I-~^v0Ra>MI>H5j00DH!1poj7b8XNC05Spq00Cvz1pom62LJ#8Xyyd~00A!Q1poj6W$*<600J>Gt^oi<0ssI3U;G6C00DFc1^@s7a0~_j00CtZ1^@s7V;BYi00Lxg_5}bQ1^@s8Y;ULm03-$g0RRR700C<_1^@s7WjqD|00Ct71poj6Z%76J00Co81^@v83IH!u27mwoV_F6P00MGhN(2B11ONa7a$|I21^^lZ0B8mP0Rk2PI$wSQfRqCO00Crx1^@s7WsC*@00DH81^@s7bC?DI00Cv51^@y83jh}Y0sssE7ytqQ4FDMc00S^FGO7juum%9O1^@s7U%UnY00C^u1^@s7VbBHu01I?uaBFjJc6DrNW#9z>E(QQ{0RTb<0CENZqy_-i1^_Ar0L}yef&~Dc1ps>h0J#7F@BjcY0RU?O0FnU!%mD!Y0RR;O073!)c>(~Y0szti0R931Dgyvr0|1o+0L=pc1q1*(1ORaa0Eh$tp#%WD1OVs+02BoPKm`DE1pulA0MrEl{sjQ&=;-K3NU)gr_<-2h*vQz}*vRN0C@9$2*vRNuSOfqXIy!K5Vr*$+UvqR}bZKK>c42a9VPb4$03%^CH#s&oF*Gc42a9VPb4$03%^DGcY+hGi5nqGGS#mG-EboVliPdI5jmhH#IqCWjQtk02(?vaB^>SWn*+@WM6h+a%o{=Y-Io=VP!OAIAvxuF=H}jGGb*hH)Jz7WI1JFV>B>jH8VCjITQc@Iyz%)VRLg|F#uz1VRLhIWpi|2F<&ubY+-YAUtcjUXmo9C6aWA^I&@`iaBN|8WnW`#VRLg|F#uz1VRLhIWpi|2F<&usWo>Y5VRU6*Ut?@xb8}x`F)nCyZEQwmSI5IXjWHB=^IbktjW;kUyGC4P8W;A0nWoBYyWMW}1Xmo9C4gfSdI(A`fUoZe+GB7!1G&C?YVqs%7WM(!uFfd^?F*0OkIb}IGIAUQl4gfSdI(A`fUoik-WHvcuW@a=oV`DKfH90mlVPs}yVPP<4H8^HvWHvN04gfSdI(A`fUorq;GdDCfVr4NhWjACpWH&isH8nOkGGR7iF=b{oI5sn56aW%BI&))haAjm)Wo~tC03%^DVKQPlG&ndhVlrc7G&wXfHa0goH#ImnIbu0EGGaLr05m!}OhrdQLs?%%PE}1`RzXZ(FaTjQVm4+sH)LXDFgay0H)AzrIAJp|WMgDAG&eLbF*0Tn05m!}OhrdQLs?%%PE}1`RzXZ(F#us^F*splHDNPiW-w$kF*YzTGc`0cI5Re3I5#siW@I!H05m!}OhrdQLs?%%PE}1`RzXZ(G5}#WGcjW{Ib&sHIc8%wH#9h5V`gPyV=!SfIWaIaIW%Mx01`Snb#8NGZ*XN~UuAA}Z2%)-V=-YeF*0UmHfCfvVmM)8HZx*mFl03~Gd5vmH!wCe6aW%BI%#ffX>Mg-c42a9VPb4$03%^$GG;YmFg7tVWjQ!yVKZfBIb>xsIb~uoFgZ9eI5#M)EHa9RZVKp%_WM(;KIXF0CVKW*4J~}#fVQgP90AXY{Ib>#LG%;giF)=kcHZ@^nW@TYvFlIG4W@ThHG%*?gJ~}#fVQgPA0AVvXG&N#nF*0R0WHMwoIbk(5HaIe2HexYlW;HlAGh-Y896CB~Wpi|8WM5@&b!`A6VKQVlV`eZkH#229F=H@cH#jjhVlgpfWHM$lF*9Z`V;le+Iy!T7VRUI@Uv^<~X<=e)WdI{#IWuHtVrDfsF=aMoGht$4GC4IdHZeFeGBGqWWMelq6aWA^I&*Y#bz^j2F#vOPa&=>LbY*jNUol@Xb98cbV{~6%F)nCyZEPF>7dkp_Wpi|8WM6Z1a&=>L0ADd*F>YmZbY)~;UvqSFbz^icXmo9C0w4h-0xbbD0XG3X0YU>w155=_1yliA0A2uQ0cikmaA9Xtest::empty test::concept_1 test::nested::concept_2 + + #define + KEK + code_8h.html + a867e1e9e6c924393462cf7c1a78c6c3e + + unscoped_enum diff --git a/tests/test_project/expected_xml/classtest_1_1class__1.xml b/tests/test_project/expected_xml/classtest_1_1class__1.xml index 18f60f7..263d3e1 100644 --- a/tests/test_project/expected_xml/classtest_1_1class__1.xml +++ b/tests/test_project/expected_xml/classtest_1_1class__1.xml @@ -9,7 +9,6 @@ constexpr bool test::class_1::public_static_variable public_static_variable - test::class_1::public_static_variable = false A public static variable. @@ -19,7 +18,7 @@ - + @@ -28,7 +27,6 @@ bool test::class_1::public_variable public_variable - test::class_1::public_variable A public variable. @@ -37,7 +35,7 @@ - + @@ -46,7 +44,6 @@ constexpr bool test::class_1::protected_static_variable protected_static_variable - test::class_1::protected_static_variable = false A protected static variable. @@ -56,7 +53,7 @@ - + @@ -65,7 +62,6 @@ bool test::class_1::protected_variable protected_variable - test::class_1::protected_variable A protected variable. @@ -74,7 +70,7 @@ - + @@ -83,7 +79,6 @@ constexpr bool test::class_1::private_static_variable private_static_variable - test::class_1::private_static_variable = false A private static variable. @@ -93,7 +88,7 @@ - + @@ -102,7 +97,6 @@ bool test::class_1::private_variable private_variable - test::class_1::private_variable A private variable. @@ -111,7 +105,7 @@ - + @@ -120,7 +114,7 @@ More info. - + test::class_1private_static_variable test::class_1private_variable diff --git a/tests/test_project/expected_xml/classtest_1_1template__class__1.xml b/tests/test_project/expected_xml/classtest_1_1template__class__1.xml index 7182626..486a37b 100644 --- a/tests/test_project/expected_xml/classtest_1_1template__class__1.xml +++ b/tests/test_project/expected_xml/classtest_1_1template__class__1.xml @@ -23,7 +23,7 @@ - +
    diff --git a/tests/test_project/expected_xml/code_8h.xml b/tests/test_project/expected_xml/code_8h.xml index 84c8a00..8981b76 100644 --- a/tests/test_project/expected_xml/code_8h.xml +++ b/tests/test_project/expected_xml/code_8h.xml @@ -9,11 +9,25 @@ test test::nested test::empty + + + KEK + 1 + +A macro. + + +More info. + + + + + + scoped_enum - test::scoped_enum val_0 @@ -48,12 +62,11 @@ - + unscoped_enum - test::unscoped_enum LEGACY_ENUM_VAL_0 @@ -88,7 +101,7 @@ - + @@ -97,7 +110,6 @@ constexpr bool test::inline_variable inline_variable - test::inline_variable = false An inline variable. @@ -107,7 +119,7 @@ - + diff --git a/tests/test_project/expected_xml/concepttest_1_1concept__1.xml b/tests/test_project/expected_xml/concepttest_1_1concept__1.xml index 5bd997a..9d7e73c 100644 --- a/tests/test_project/expected_xml/concepttest_1_1concept__1.xml +++ b/tests/test_project/expected_xml/concepttest_1_1concept__1.xml @@ -29,6 +29,6 @@ concept test::concept_ - + diff --git a/tests/test_project/expected_xml/concepttest_1_1nested_1_1concept__2.xml b/tests/test_project/expected_xml/concepttest_1_1nested_1_1concept__2.xml index f35e922..4d56ed7 100644 --- a/tests/test_project/expected_xml/concepttest_1_1nested_1_1concept__2.xml +++ b/tests/test_project/expected_xml/concepttest_1_1nested_1_1concept__2.xml @@ -29,6 +29,6 @@ concept test - + diff --git a/tests/test_project/expected_xml/index.xml b/tests/test_project/expected_xml/index.xml index efdbb2f..4227c21 100644 --- a/tests/test_project/expected_xml/index.xml +++ b/tests/test_project/expected_xml/index.xml @@ -39,6 +39,7 @@ test::nested code.h + KEK unscoped_enum LEGACY_ENUM_VAL_0 LEGACY_ENUM_VAL_1 diff --git a/tests/test_project/expected_xml/namespacetest.xml b/tests/test_project/expected_xml/namespacetest.xml index d6a2b95..7fcdf37 100644 --- a/tests/test_project/expected_xml/namespacetest.xml +++ b/tests/test_project/expected_xml/namespacetest.xml @@ -6,7 +6,6 @@ scoped_enum - test::scoped_enum val_0 @@ -41,12 +40,11 @@ - + unscoped_enum - test::unscoped_enum LEGACY_ENUM_VAL_0 @@ -81,7 +79,7 @@ - + @@ -90,7 +88,6 @@ constexpr bool test::inline_variable inline_variable - test::inline_variable = false An inline variable. @@ -100,7 +97,7 @@ - + @@ -118,7 +115,7 @@ } - + test::class_1 test::empty test::nested diff --git a/tests/test_project/expected_xml/namespacetest_1_1empty.xml b/tests/test_project/expected_xml/namespacetest_1_1empty.xml index 2fce9f3..6c722fe 100644 --- a/tests/test_project/expected_xml/namespacetest_1_1empty.xml +++ b/tests/test_project/expected_xml/namespacetest_1_1empty.xml @@ -8,6 +8,6 @@ More info. - + diff --git a/tests/test_project/expected_xml/namespacetest_1_1nested.xml b/tests/test_project/expected_xml/namespacetest_1_1nested.xml index 8bafaf2..790db5f 100644 --- a/tests/test_project/expected_xml/namespacetest_1_1nested.xml +++ b/tests/test_project/expected_xml/namespacetest_1_1nested.xml @@ -7,6 +7,6 @@ - + test::nested::concept_2 \ No newline at end of file diff --git a/tests/test_project/expected_xml/structtest_1_1struct__1.xml b/tests/test_project/expected_xml/structtest_1_1struct__1.xml index 55f6f54..bbeeb88 100644 --- a/tests/test_project/expected_xml/structtest_1_1struct__1.xml +++ b/tests/test_project/expected_xml/structtest_1_1struct__1.xml @@ -8,7 +8,6 @@ nested_enum - test::struct_1::nested_enum val_0 @@ -43,7 +42,7 @@ - + @@ -52,7 +51,6 @@ constexpr bool test::struct_1::static_variable static_variable - test::struct_1::static_variable = false A static variable. @@ -62,7 +60,7 @@ - + @@ -71,7 +69,7 @@ More info. - + test::struct_1nested_enum test::struct_1static_variable diff --git a/tests/test_project/expected_xml/structtest_1_1struct__1_1_1nested__struct.xml b/tests/test_project/expected_xml/structtest_1_1struct__1_1_1nested__struct.xml index 12000df..4f5485e 100644 --- a/tests/test_project/expected_xml/structtest_1_1struct__1_1_1nested__struct.xml +++ b/tests/test_project/expected_xml/structtest_1_1struct__1_1_1nested__struct.xml @@ -9,7 +9,7 @@ More info. - + diff --git a/tests/test_project/src/code.h b/tests/test_project/src/code.h index c90d20c..e939557 100644 --- a/tests/test_project/src/code.h +++ b/tests/test_project/src/code.h @@ -2,6 +2,10 @@ /// \brief Code, yo. /// \details More info. +/// \brief A macro. +/// \details More info. +#define KEK 1 + #include /// \brief A namespace. diff --git a/tests/test_project/test.toml b/tests/test_project/test.toml index c98fda8..c7567ef 100644 --- a/tests/test_project/test.toml +++ b/tests/test_project/test.toml @@ -3,4 +3,4 @@ [xml] enabled = true -#v2 = true \ No newline at end of file +#v2 = true