Obfuscation/addon/doxmlparser/examples/metrics/metrics.py

226 lines
9.5 KiB
Python

# An example showing how to use the python doxmlparser module to extract some metrics from
# the XML output generated by analyze 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()