1#!/usr/local/bin/python3.8
2
3import sys
4import re
5import io
6
7definitionSet = set()
8readFromSet = set()
9writeToSet = set()
10defToTypeMap = dict()
11
12def parseFieldInfo( tokens ):
13    return (tokens[1].strip(), tokens[2].strip())
14
15with io.open("workdir/loplugin.unusedvarsglobal.log", "rb", buffering=1024*1024) as txt:
16    for line in txt:
17        try:
18            tokens = line.strip().split("\t")
19            if tokens[0] == "definition:":
20                srcLoc = tokens[3]
21                # ignore external source code
22                if (srcLoc.startswith("external/")):
23                    continue
24                # ignore build folder
25                if (srcLoc.startswith("workdir/")):
26                    continue
27                varname = tokens[1].strip()
28                vartype = tokens[2].strip()
29                if vartype.startswith("const "):
30                    vartype = vartype[6:]
31                if vartype.startswith("class "):
32                    vartype = vartype[6:]
33                if vartype.startswith("struct "):
34                    vartype = vartype[7:]
35                if vartype.startswith("::"):
36                    vartype = vartype[2:]
37                fieldInfo = (srcLoc, varname)
38                definitionSet.add(fieldInfo)
39                defToTypeMap[fieldInfo] = vartype
40            elif tokens[0] == "read:":
41                if len(tokens) == 3:
42                    readFromSet.add(parseFieldInfo(tokens))
43            elif tokens[0] == "write:":
44                if len(tokens) == 3:
45                    writeToSet.add(parseFieldInfo(tokens))
46            else:
47                print( "unknown line: " + line)
48        except IndexError:
49            print "problem with line " + line.strip()
50            raise
51
52definitionSet2 = set()
53for d in definitionSet:
54    varname = d[1]
55    vartype = defToTypeMap[d]
56    if len(varname) == 0:
57        continue
58    if varname.startswith("autoRegister"): # auto-generated CPPUNIT stuff
59        continue
60    if vartype in ["css::uno::ContextLayer", "SolarMutexGuard", "SolarMutexReleaser", "OpenGLZone"]:
61        continue
62    if vartype in ["PreDefaultWinNoOpenGLZone", "SchedulerGuard", "SkiaZone", "OpenGLVCLContextZone"]:
63        continue
64    if vartype in ["SwXDispatchProviderInterceptor::DispatchMutexLock_Impl", "SfxObjectShellLock", "OpenCLZone"]:
65        continue
66    if vartype in ["OpenCLInitialZone", "pyuno::PyThreadDetach", "SortRefUpdateSetter", "oglcanvas::TransformationPreserver"]:
67        continue
68    if vartype in ["StackHack", "osl::MutexGuard", "accessibility::SolarMethodGuard"]:
69        continue
70    if vartype in ["osl::ClearableMutexGuard", "comphelper::OExternalLockGuard", "osl::Guard< ::osl::Mutex>"]:
71        continue
72    if vartype in ["comphelper::OContextEntryGuard", "Guard<class osl::Mutex>", "basic::LibraryContainerMethodGuard"]:
73        continue
74    if vartype in ["canvas::CanvasBase::MutexType"]:
75        continue
76    definitionSet2.add(d)
77
78# Calculate untouched
79untouchedSet = set()
80for d in definitionSet2:
81    if d in readFromSet or d in writeToSet:
82        continue
83    varname = d[1]
84    if len(varname) == 0:
85        continue
86    untouchedSet.add(d)
87
88writeonlySet = set()
89for d in definitionSet2:
90    if d in readFromSet or d in untouchedSet:
91        continue
92    varname = d[1]
93    vartype = defToTypeMap[d]
94    if "Alive" in varname:
95        continue
96    if "Keep" in varname:
97        continue
98    if vartype.endswith(" &"):
99        continue
100    writeonlySet.add(d)
101
102readonlySet = set()
103for d in definitionSet2:
104    if d in writeToSet or d in untouchedSet:
105        continue
106    varname = d[1]
107    vartype = defToTypeMap[d]
108    if "Dummy" in varname:
109        continue
110    if "Empty" in varname:
111        continue
112    if varname in ["aOldValue", "aNewValue"]:
113        continue
114    if "Exception" in vartype and vartype.endswith(" &"):
115        continue
116    if "exception" in vartype and vartype.endswith(" &"):
117        continue
118    # TODO for now, focus on the simple stuff
119    if not (vartype in ["rtl::OUString", "Bool"]):
120        continue
121    readonlySet.add(d)
122
123# sort the results using a "natural order" so sequences like [item1,item2,item10] sort nicely
124def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
125    return [int(text) if text.isdigit() else text.lower()
126            for text in re.split(_nsre, s)]
127# sort by both the source-line and the datatype, so the output file ordering is stable
128# when we have multiple items on the same source line
129def v_sort_key(v):
130    return natural_sort_key(v[0]) + [v[1]]
131
132# sort results by name and line number
133tmp1list = sorted(untouchedSet, key=lambda v: v_sort_key(v))
134tmp2list = sorted(writeonlySet, key=lambda v: v_sort_key(v))
135tmp3list = sorted(readonlySet, key=lambda v: v_sort_key(v))
136
137# print out the results
138with open("compilerplugins/clang/unusedvarsglobal.untouched.results", "wt") as f:
139    for t in tmp1list:
140        f.write( t[0] + "\n" )
141        f.write( "    " + defToTypeMap[t] + " " + t[1] + "\n" )
142with open("compilerplugins/clang/unusedvarsglobal.writeonly.results", "wt") as f:
143    for t in tmp2list:
144        f.write( t[0] + "\n" )
145        f.write( "    " + defToTypeMap[t] + " " + t[1] + "\n" )
146with open("compilerplugins/clang/unusedvarsglobal.readonly.results", "wt") as f:
147    for t in tmp3list:
148        f.write( t[0] + "\n" )
149        f.write( "    " + defToTypeMap[t] + " " + t[1] + "\n" )
150
151
152