summaryrefslogtreecommitdiffstats
path: root/addon/doxmlparser/examples/metrics/metrics.py
diff options
context:
space:
mode:
authorDimitri van Heesch <doxygen@gmail.com>2021-04-29 17:26:11 (GMT)
committerGitHub <noreply@github.com>2021-04-29 17:26:11 (GMT)
commitb8a3ff6c33264c43cdf30c04baa9793e7e8d51a2 (patch)
tree9d60ced4b8fceb00c068b56d699c1ba57540d415 /addon/doxmlparser/examples/metrics/metrics.py
parent4dba9fbdda10889d2285b85b7e9ff6282b34fccf (diff)
parentc6d77227efaf332a5d24bc12d32f4b1fec6b13b9 (diff)
downloadDoxygen-b8a3ff6c33264c43cdf30c04baa9793e7e8d51a2.zip
Doxygen-b8a3ff6c33264c43cdf30c04baa9793e7e8d51a2.tar.gz
Doxygen-b8a3ff6c33264c43cdf30c04baa9793e7e8d51a2.tar.bz2
Merge branch 'master' into feature/bug_305773
Diffstat (limited to 'addon/doxmlparser/examples/metrics/metrics.py')
-rw-r--r--addon/doxmlparser/examples/metrics/metrics.py225
1 files changed, 225 insertions, 0 deletions
diff --git a/addon/doxmlparser/examples/metrics/metrics.py b/addon/doxmlparser/examples/metrics/metrics.py
new file mode 100644
index 0000000..a83e16f
--- /dev/null
+++ b/addon/doxmlparser/examples/metrics/metrics.py
@@ -0,0 +1,225 @@
+# An example showing how to use the python doxmlparser module to extract some metrics from
+# the XML output generated by doxygen for a project.
+
+import sys
+
+import doxmlparser
+
+from doxmlparser.compound import DoxCompoundKind, DoxMemberKind, DoxSectionKind, MixedContainer
+
+class Metrics:
+ def __init__(self):
+ self.numClasses = 0
+ self.numDocClasses = 0
+ self.numStructs = 0
+ self.numUnions = 0
+ self.numInterfaces = 0
+ self.numExceptions = 0
+ self.numNamespaces = 0
+ self.numFiles = 0
+ self.numDocFiles = 0
+ self.numGroups = 0
+ self.numPages = 0
+ self.numPubMethods = 0
+ self.numDocPubMethods = 0
+ self.numProMethods = 0
+ self.numDocProMethods = 0
+ self.numPriMethods = 0
+ self.numDocPriMethods = 0
+ self.numAttributes = 0
+ self.numDocAttributes = 0
+ self.numFunctions = 0
+ self.numDocFunctions = 0
+ self.numVariables = 0
+ self.numDocVariables = 0
+ self.numParams = 0
+ def print(self):
+ numMethods = self.numPubMethods + self.numProMethods + self.numPriMethods
+ numDocMethods = self.numDocPubMethods + self.numDocProMethods + self.numDocPriMethods
+ print("Metrics:");
+ print("-----------------------------------");
+ if self.numClasses>0:
+ print("Classes: {:=10} ({} documented)".format(self.numClasses,self.numDocClasses))
+ if self.numStructs>0:
+ print("Structs: {:=10}".format(self.numStructs))
+ if self.numUnions>0:
+ print("Unions: {:=10}".format(self.numUnions))
+ if self.numExceptions>0:
+ print("Exceptions: {:=10}".format(self.numExceptions))
+ if self.numNamespaces>0:
+ print("Namespaces: {:=10}".format(self.numNamespaces))
+ if self.numFiles>0:
+ print("Files: {:=10} ({} documented)".format(self.numFiles,self.numDocFiles))
+ if self.numGroups>0:
+ print("Groups: {:=10}".format(self.numGroups))
+ if self.numPages>0:
+ print("Pages: {:=10}".format(self.numPages))
+ if numMethods>0:
+ print("Methods: {:=10} ({} documented)".format(numMethods,numDocMethods))
+ if self.numPubMethods>0:
+ print(" Public: {:=10} ({} documented)".format(self.numPubMethods,self.numDocPubMethods))
+ if self.numProMethods>0:
+ print(" Protected: {:=10} ({} documented)".format(self.numProMethods,self.numDocProMethods))
+ if self.numPriMethods>0:
+ print(" Private: {:=10} ({} documented)".format(self.numPriMethods,self.numDocPriMethods))
+ if self.numFunctions>0:
+ print("Functions: {:=10} ({} documented)".format(self.numFunctions,self.numDocFunctions))
+ if self.numAttributes>0:
+ print("Attributes: {:=10} ({} documented)".format(self.numAttributes,self.numDocAttributes))
+ if self.numVariables>0:
+ print("Variables: {:=10} ({} documented)".format(self.numVariables,self.numDocVariables))
+ if self.numParams>0:
+ print("Params: {:=10}".format(self.numParams))
+ print("-----------------------------------");
+ if self.numClasses>0:
+ print("Avg. #methods/compound: {:=10}".format(float(numMethods)/float(self.numClasses)))
+ if numMethods>0:
+ print("Avg. #params/method: {:=10}".format(float(self.numParams)/float(numMethods)))
+ print("-----------------------------------");
+
+
+def description_is_empty(description):
+ for content in description.content_:
+ if content.getCategory()==MixedContainer.CategoryText:
+ if not content.getValue().isspace():
+ return False # non space-only text
+ elif not content.getCategory()==MixedContainer.CategoryNone:
+ return False # some internal object like a paragraph
+ return True
+
+def is_documented(definition):
+ return not description_is_empty(definition.get_briefdescription()) or \
+ not description_is_empty(definition.get_detaileddescription())
+
+def section_is_protected(sectionkind):
+ return sectionkind in [DoxSectionKind.PROTECTEDTYPE,
+ DoxSectionKind.PROTECTEDFUNC,
+ DoxSectionKind.PROTECTEDATTRIB,
+ DoxSectionKind.PROTECTEDSLOT,
+ DoxSectionKind.PROTECTEDSTATICFUNC,
+ DoxSectionKind.PROTECTEDSTATICATTRIB]
+
+def section_is_private(sectionkind):
+ return sectionkind in [DoxSectionKind.PRIVATETYPE,
+ DoxSectionKind.PRIVATEFUNC,
+ DoxSectionKind.PRIVATEATTRIB,
+ DoxSectionKind.PRIVATESLOT,
+ DoxSectionKind.PRIVATESTATICFUNC,
+ DoxSectionKind.PRIVATESTATICATTRIB]
+
+def section_is_public(sectionkind):
+ return not section_is_protected(sectionkind) and not section_is_private(sectionkind)
+
+def linked_text_to_string(linkedtext):
+ str=''
+ if linkedtext:
+ for text_or_ref in linkedtext.content_:
+ if text_or_ref.getCategory()==MixedContainer.CategoryText:
+ str+=text_or_ref.getValue()
+ else:
+ str+=text_or_ref.getValue().get_valueOf_()
+ return str
+
+def parse_members(compounddef,sectiondef,metrics):
+ functionLikeKind = [DoxMemberKind.FUNCTION,
+ DoxMemberKind.PROTOTYPE,
+ DoxMemberKind.SIGNAL,
+ DoxMemberKind.SLOT,
+ DoxMemberKind.DCOP]
+ variableLikeKind = [DoxMemberKind.VARIABLE, DoxMemberKind.PROPERTY]
+ for memberdef in sectiondef.get_memberdef():
+ if compounddef.get_kind() in [DoxCompoundKind.CLASS, DoxCompoundKind.STRUCT, DoxCompoundKind.INTERFACE]:
+ if memberdef.get_kind() in functionLikeKind:
+ if section_is_public(sectiondef.get_kind()):
+ metrics.numPubMethods+=1
+ if is_documented(memberdef):
+ metrics.numDocPubMethods+=1
+ elif section_is_protected(sectiondef.get_kind()):
+ metrics.numProMethods+=1
+ if is_documented(memberdef):
+ metrics.numDocProMethods+=1
+ elif section_is_private(sectiondef.get_kind()):
+ metrics.numPriMethods+=1
+ if is_documented(memberdef):
+ metrics.numDocPriMethods+=1
+ elif memberdef.get_kind() in variableLikeKind:
+ metrics.numAttributes+=1
+ if is_documented(memberdef):
+ metrics.numDocAttributes+=1
+ elif compounddef.get_kind() in [DoxCompoundKind.FILE, DoxCompoundKind.NAMESPACE]:
+ if memberdef.get_kind() in functionLikeKind:
+ metrics.numFunctions+=1
+ if is_documented(memberdef):
+ metrics.numDocFunctions+=1
+ elif memberdef.get_kind() in variableLikeKind:
+ metrics.numVariables+=1
+ if is_documented(memberdef):
+ metrics.numDocVariables+=1
+ #for param in memberdef.get_param():
+ # name = ''
+ # if param.get_defname():
+ # name = param.get_defname()
+ # if param.get_declname():
+ # name = param.get_declname()
+ # print("param '{}':'{}'".format(linked_text_to_string(param.get_type()),name))
+ metrics.numParams+=len(memberdef.get_param())
+ if memberdef.get_type() and memberdef.get_type()!="void" and linked_text_to_string(memberdef.get_type()):
+ metrics.numParams+=1 # count non-void return types as well
+ #print("returns '{}'".format(linked_text_to_string(memberdef.get_type())))
+
+def parse_sections(compounddef,metrics):
+ for sectiondef in compounddef.get_sectiondef():
+ parse_members(compounddef,sectiondef,metrics)
+
+def parse_compound(inDirName,baseName,metrics):
+ rootObj = doxmlparser.compound.parse(inDirName+"/"+baseName+".xml",True)
+ for compounddef in rootObj.get_compounddef():
+ kind = compounddef.get_kind()
+ if kind==DoxCompoundKind.CLASS:
+ metrics.numClasses+=1
+ if is_documented(compounddef):
+ metrics.numDocClasses+=1
+ elif kind==DoxCompoundKind.STRUCT:
+ metrics.numStructs+=1
+ elif kind==DoxCompoundKind.UNION:
+ metrics.numUnions+=1
+ elif kind==DoxCompoundKind.INTERFACE:
+ metrics.numInterfaces+=1
+ elif kind==DoxCompoundKind.EXCEPTION:
+ metrics.numExceptions+=1
+ elif kind==DoxCompoundKind.NAMESPACE:
+ metrics.numNamespaces+=1
+ elif kind==DoxCompoundKind.FILE:
+ metrics.numFiles+=1
+ if is_documented(compounddef):
+ metrics.numDocFiles+=1
+ elif kind==DoxCompoundKind.GROUP:
+ metrics.numGroups+=1
+ elif kind==DoxCompoundKind.PAGE:
+ metrics.numPages+=1
+ else:
+ continue
+ parse_sections(compounddef,metrics)
+
+def parse_index(inDirName):
+ metrics = Metrics()
+ rootObj = doxmlparser.index.parse(inDirName+"/index.xml",True)
+ for compound in rootObj.get_compound(): # for each compound defined in the index
+ print("Processing {0}...".format(compound.get_name()))
+ parse_compound(inDirName,compound.get_refid(),metrics)
+ metrics.print()
+
+def usage():
+ print("Usage {0} <xml_output_dir>".format(sys.argv[0]))
+ sys.exit(1)
+
+def main():
+ args = sys.argv[1:]
+ if len(args)==1:
+ parse_index(args[0])
+ else:
+ usage()
+
+if __name__ == '__main__':
+ main()
+