1#!/usr/local/bin/python3.8 2 3import io 4import re 5import sys 6 7definitionSet = set() 8definitionToSourceLocationMap = dict() 9overridingSet = set() 10nonEmptySet = set() 11 12 13with io.open("workdir/loplugin.unnecessaryvirtual.log", "rb", buffering=1024*1024) as txt: 14 for line in txt: 15 tokens = line.strip().split("\t") 16 if tokens[0] == "definition:": 17 fullMethodName = tokens[1] 18 sourceLocation = tokens[2] 19 definitionSet.add(fullMethodName) 20 definitionToSourceLocationMap[fullMethodName] = sourceLocation 21 elif tokens[0] == "overriding:": 22 fullMethodName = tokens[1] 23 overridingSet.add(fullMethodName) 24 elif tokens[0] == "nonempty:": 25 fullMethodName = tokens[1] 26 nonEmptySet.add(fullMethodName) 27 else: 28 print( "unknown line: " + line) 29 30unnecessaryVirtualSet = set() 31 32for clazz in (definitionSet - overridingSet): 33 # windows-specific stuff 34 if clazz.startswith("canvas::"): continue 35 if clazz.startswith("psp::PrinterInfoManager"): continue 36 if clazz.startswith("DdeTopic::"): continue 37 if clazz == "basegfx::unotools::UnoPolyPolygon::void-modifying()const": continue 38 if clazz == "SalLayout::_Bool-IsKashidaPosValid(int,)const": continue 39 if clazz == "SalLayout::void-DisableGlyphInjection(_Bool,)": continue 40 # Linux-TDF specific 41 if clazz == "X11SalFrame::void-updateGraphics(_Bool,)": continue 42 # OSX specific 43 if clazz == "SalFrame::void-SetRepresentedURL(const class rtl::OUString &,)": continue 44 if clazz == "SalMenu::_Bool-AddMenuBarButton(const struct SalMenuButtonItem &,)": continue 45 if clazz == "SalMenu::class Rectangle-GetMenuBarButtonRectPixel(sal_uInt16,class SalFrame *,)": continue 46 if clazz == "SalMenu::void-RemoveMenuBarButton(sal_uInt16,)": continue 47 if clazz == "SalLayout::_Bool-DrawTextSpecial(class SalGraphics &,sal_uInt32,)const": continue 48 # GTK < 3 49 if clazz == "GtkSalDisplay::int-CaptureMouse(class SalFrame *,)": continue 50 # some test magic 51 if clazz.startswith("apitest::"): continue 52 53 loc = definitionToSourceLocationMap[clazz] 54 55 # ignore external code 56 if loc.startswith("external/"): continue 57 # there is a bunch of Windows specific code that we don't see 58 if loc.startswith("include/canvas/"): continue 59 # not sure what the problem is here 60 if loc.startswith("include/test/"): continue 61 62 unnecessaryVirtualSet.add( (clazz,loc) ) 63 64 65deadSet = set() 66 67for clazz in (definitionSet - nonEmptySet): 68 69 # ignore destructors 70 if "::~" in clazz: continue 71 72 loc = definitionToSourceLocationMap[clazz] 73 74 # ignore external code 75 if loc.startswith("external/"): continue 76 77 deadSet.add( (clazz,loc) ) 78 79 80# sort the results using a "natural order" so sequences like [item1,item2,item10] sort nicely 81def natural_sort_key(s, _nsre=re.compile('([0-9]+)')): 82 return [int(text) if text.isdigit() else text.lower() 83 for text in re.split(_nsre, s)] 84 85# sort results by name and line number 86tmp1list = sorted(unnecessaryVirtualSet, key=lambda v: natural_sort_key(v[1])) 87tmp2list = sorted(deadSet, key=lambda v: natural_sort_key(v[1])) 88 89with open("compilerplugins/clang/unnecessaryvirtual.results", "wt") as f: 90 for t in tmp1list: 91 f.write( t[1] + "\n" ) 92 f.write( " " + t[0] + "\n" ) 93 # add an empty line at the end to make it easier for the removevirtuals plugin to mmap() the output file 94 f.write("\n") 95 96with open("compilerplugins/clang/unnecessaryvirtual-dead.results", "wt") as f: 97 for t in tmp2list: 98 f.write( t[1] + "\n" ) 99 f.write( " " + t[0] + "\n" ) 100 101