Remove exec bits from docx
[LibreOffice.git] / compilerplugins / clang / unusedfields.py
blob131303442ef91025d61a98fd1622bbfc692cff29
1 #!/usr/bin/python3
3 import re
4 import io
6 definitionSet = set()
7 protectedAndPublicDefinitionSet = set() # set of tuple(type, name)
8 definitionToSourceLocationMap = dict()
9 definitionToTypeMap = dict()
10 touchedFromInsideSet = set()
11 touchedFromOutsideSet = set()
12 touchedFromOutsideConstructorSet = set()
13 readFromSet = set()
14 writeToSet = set()
15 sourceLocationSet = set()
17 # clang does not always use exactly the same numbers in the type-parameter vars it generates
18 # so I need to substitute them to ensure we can match correctly.
19 normalizeTypeParamsRegex = re.compile(r"type-parameter-\d+-\d+")
20 def normalizeTypeParams( line ):
21 return normalizeTypeParamsRegex.sub("type-parameter-?-?", line)
23 def parseFieldInfo( tokens ):
24 if len(tokens) == 3:
25 return (normalizeTypeParams(tokens[1]), tokens[2])
26 else:
27 return (normalizeTypeParams(tokens[1]), "")
29 with io.open("workdir/loplugin.unusedfields.log", "r", buffering=1024*1024) as txt:
30 for line in txt:
31 tokens = line.strip().split("\t")
32 if tokens[0] == "definition:":
33 access = tokens[1]
34 fieldInfo = (normalizeTypeParams(tokens[2]), tokens[3])
35 srcLoc = tokens[5]
36 # ignore external source code
37 if (srcLoc.startswith("external/")):
38 continue
39 # ignore build folder
40 if (srcLoc.startswith("workdir/")):
41 continue
42 definitionSet.add(fieldInfo)
43 definitionToTypeMap[fieldInfo] = tokens[4]
44 if access == "protected" or access == "public":
45 protectedAndPublicDefinitionSet.add(fieldInfo)
46 definitionToSourceLocationMap[fieldInfo] = tokens[5]
47 elif tokens[0] == "inside:":
48 touchedFromInsideSet.add(parseFieldInfo(tokens))
49 elif tokens[0] == "outside:":
50 touchedFromOutsideSet.add(parseFieldInfo(tokens))
51 elif tokens[0] == "outside-constructor:":
52 touchedFromOutsideConstructorSet.add(parseFieldInfo(tokens))
53 elif tokens[0] == "read:":
54 readFromSet.add(parseFieldInfo(tokens))
55 elif tokens[0] == "write:":
56 writeToSet.add(parseFieldInfo(tokens))
57 else:
58 print( "unknown line: " + line)
60 # Calculate untouched
61 untouchedSet = set()
62 untouchedSetD = set()
63 for d in definitionSet:
64 if d in touchedFromOutsideSet or d in touchedFromInsideSet:
65 continue
66 srcLoc = definitionToSourceLocationMap[d];
67 # this is all representations of on-disk data structures
68 if (srcLoc.startswith("sc/source/filter/inc/scflt.hxx")
69 or srcLoc.startswith("sw/source/filter/ww8/")
70 or srcLoc.startswith("vcl/source/filter/sgvmain.hxx")
71 or srcLoc.startswith("vcl/source/filter/sgfbram.hxx")
72 or srcLoc.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
73 or srcLoc.startswith("include/svl/svdde.hxx")
74 or srcLoc.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
75 or srcLoc.startswith("hwpfilter/")
76 or srcLoc.startswith("embeddedobj/source/inc/")
77 or srcLoc.startswith("svtools/source/dialogs/insdlg.cxx")
78 or srcLoc.startswith("bridges/")):
79 continue
80 if d[0] in set([ "AtkObjectWrapperClass", "AtkObjectWrapper", "GLOMenu", "GLOAction", "_XRegion", "SalMenuButtonItem", "Vertex",
81 "OOoMountOperationClass", "SwCSS1ItemIds", "ScCompiler::AddInMap", "MemoryByteGrabber", "textcat_t", "fp_t", "ngram_t",
82 "ImplPPTParaPropSet", "DataNode"]):
83 continue
84 # unit testing code
85 if srcLoc.startswith("cppu/source/uno/check.cxx"):
86 continue
87 fieldType = definitionToTypeMap[d]
88 if "ModuleClient" in fieldType:
89 continue
90 if "::sfx2::sidebar::ControllerItem" in fieldType:
91 continue
92 if "(lambda at " in d[0]:
93 continue
94 if "weld::CustomWeld" in fieldType:
95 continue
96 if "weld::Container" in fieldType:
97 continue
98 if "weld::Frame" in fieldType:
99 continue
100 untouchedSet.add((d[0] + " " + d[1] + " " + fieldType, srcLoc))
101 untouchedSetD.add(d)
103 # Calculate only-touched-in-constructor set
104 onlyUsedInConstructorSet = set()
105 for d in definitionSet:
106 if d in touchedFromOutsideSet or d in touchedFromOutsideConstructorSet:
107 continue
108 srcLoc = definitionToSourceLocationMap[d];
109 # this is all representations of on-disk data structures
110 if (srcLoc.startswith("sc/source/filter/inc/scflt.hxx")
111 or srcLoc.startswith("sw/source/filter/ww8/")
112 or srcLoc.startswith("vcl/source/filter/sgvmain.hxx")
113 or srcLoc.startswith("vcl/source/filter/sgfbram.hxx")
114 or srcLoc.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
115 or srcLoc.startswith("include/svl/svdde.hxx")
116 or srcLoc.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
117 or srcLoc.startswith("hwpfilter/")
118 or srcLoc.startswith("embeddedobj/source/inc/")
119 or srcLoc.startswith("svtools/source/dialogs/insdlg.cxx")
120 or srcLoc.startswith("bridges/")):
121 continue
122 fieldType = definitionToTypeMap[d]
123 if "std::unique_ptr" in fieldType:
124 continue
125 if "std::shared_ptr" in fieldType:
126 continue
127 if "Reference<" in fieldType:
128 continue
129 if "VclPtr<" in fieldType:
130 continue
131 if "osl::Mutex" in fieldType:
132 continue
133 if "::sfx2::sidebar::ControllerItem" in fieldType:
134 continue
135 if "(lambda at " in d[0]:
136 continue
137 onlyUsedInConstructorSet.add((d[0] + " " + d[1] + " " + fieldType, srcLoc))
139 writeonlySet = set()
140 for d in definitionSet:
141 parentClazz = d[0];
142 if d in readFromSet or d in untouchedSetD:
143 continue
144 srcLoc = definitionToSourceLocationMap[d];
145 # this is all representations of on-disk data structures
146 if (srcLoc.startswith("sc/source/filter/inc/scflt.hxx")
147 or srcLoc.startswith("sw/source/filter/ww8/")
148 or srcLoc.startswith("vcl/source/filter/sgvmain.hxx")
149 or srcLoc.startswith("vcl/source/filter/sgfbram.hxx")
150 or srcLoc.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
151 or srcLoc.startswith("include/svl/svdde.hxx")
152 or srcLoc.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
153 or srcLoc.startswith("svtools/source/dialogs/insdlg.cxx")):
154 continue
155 fieldType = definitionToTypeMap[d]
156 if "ModuleClient" in fieldType:
157 continue
158 if "::sfx2::sidebar::ControllerItem" in fieldType:
159 continue
160 # ignore reference fields, because writing to them actually writes to another field somewhere else
161 if fieldType.endswith("&"):
162 continue
163 # ignore the import/export data model stuff
164 if srcLoc.startswith("sc/source/filter/inc/") and "Model" in fieldType:
165 continue
166 if srcLoc.startswith("sc/source/filter/inc/") and (parentClazz.startswith("Xcl") or parentClazz.startswith("oox::xls::")):
167 continue
168 # implement some kind of registration of errors
169 if fieldType == "class SfxErrorHandler *":
170 continue
171 # mutex locking
172 if "Guard" in fieldType:
173 continue
174 # these are just all model classes
175 if (srcLoc.startswith("oox/")
176 or srcLoc.startswith("lotuswordpro/")
177 or srcLoc.startswith("include/oox/")
178 or srcLoc.startswith("include/filter/")
179 or srcLoc.startswith("hwpfilter/")
180 or srcLoc.startswith("filter/")
181 or srcLoc.startswith("vcl/source/filter/")):
182 continue
183 if "(lambda at " in d[0]:
184 continue
185 if "weld::CustomWeld" in fieldType:
186 continue
187 if "weld::Container" in fieldType:
188 continue
189 if "weld::Frame" in fieldType:
190 continue
191 writeonlySet.add((d[0] + " " + d[1] + " " + definitionToTypeMap[d], srcLoc))
194 readonlySet = set()
195 for d in definitionSet:
196 parentClazz = d[0];
197 if d in writeToSet or d in untouchedSetD:
198 continue
199 fieldType = definitionToTypeMap[d]
200 srcLoc = definitionToSourceLocationMap[d];
201 if "ModuleClient" in fieldType:
202 continue
203 # this is all representations of on-disk data structures
204 if (srcLoc.startswith("sc/source/filter/inc/scflt.hxx")
205 or srcLoc.startswith("sw/source/filter/ww8/")
206 or srcLoc.startswith("vcl/source/filter/sgvmain.hxx")
207 or srcLoc.startswith("vcl/source/filter/sgfbram.hxx")
208 or srcLoc.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
209 or srcLoc.startswith("include/svl/svdde.hxx")):
210 continue
211 # I really don't care about these ancient file formats
212 if (srcLoc.startswith("hwpfilter/")
213 or srcLoc.startswith("lotuswordpro/")):
214 continue
215 if "(lambda at " in d[0]:
216 continue
217 if "weld::CustomWeld" in fieldType:
218 continue
219 if "weld::Container" in fieldType:
220 continue
221 readonlySet.add((d[0] + " " + d[1] + " " + definitionToTypeMap[d], srcLoc))
224 canBePrivateSet = set()
225 for d in protectedAndPublicDefinitionSet:
226 clazz = d[0] + " " + d[1]
227 if d in touchedFromOutsideSet:
228 continue
229 srcLoc = definitionToSourceLocationMap[d];
231 canBePrivateSet.add((clazz + " " + definitionToTypeMap[d], srcLoc))
234 # --------------------------------------------------------------------------------------------
235 # "all fields in class can be made private" analysis
236 # --------------------------------------------------------------------------------------------
238 potentialClasses = set()
239 excludedClasses = set()
240 potentialClassesSourceLocationMap = dict()
241 matchClassName = re.compile(r"(\w+)::")
242 for d in protectedAndPublicDefinitionSet:
243 clazz = d[0]
244 if d in touchedFromOutsideSet:
245 excludedClasses.add(clazz)
246 else:
247 potentialClasses.add(clazz)
248 potentialClassesSourceLocationMap[clazz] = definitionToSourceLocationMap[d]
249 allFieldsCanBePrivateSet = set()
250 for d in (potentialClasses - excludedClasses):
251 sourceLoc = potentialClassesSourceLocationMap[d]
252 # when the class is inside a compile unit, assume that the compiler can figure this out for itself, much less interesting to me
253 if not ".cxx" in sourceLoc:
254 allFieldsCanBePrivateSet.add((d, sourceLoc))
256 # sort the results using a "natural order" so sequences like [item1,item2,item10] sort nicely
257 def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
258 return [int(text) if text.isdigit() else text.lower()
259 for text in re.split(_nsre, s)]
260 # sort by both the source-line and the datatype, so the output file ordering is stable
261 # when we have multiple items on the same source line
262 def v_sort_key(v):
263 return natural_sort_key(v[1]) + [v[0]]
265 # sort results by name and line number
266 tmp1list = sorted(untouchedSet, key=lambda v: v_sort_key(v))
267 tmp2list = sorted(writeonlySet, key=lambda v: v_sort_key(v))
268 tmp3list = sorted(canBePrivateSet, key=lambda v: v_sort_key(v))
269 tmp4list = sorted(readonlySet, key=lambda v: v_sort_key(v))
270 tmp5list = sorted(onlyUsedInConstructorSet, key=lambda v: v_sort_key(v))
271 tmp6list = sorted(allFieldsCanBePrivateSet, key=lambda v: v_sort_key(v))
273 # print out the results
274 with open("compilerplugins/clang/unusedfields.untouched.results", "wt") as f:
275 for t in tmp1list:
276 f.write( t[1] + "\n" )
277 f.write( " " + t[0] + "\n" )
278 with open("compilerplugins/clang/unusedfields.writeonly.results", "wt") as f:
279 for t in tmp2list:
280 f.write( t[1] + "\n" )
281 f.write( " " + t[0] + "\n" )
282 # this one is not checked in yet because I haven't actually done anything with it
283 with open("loplugin.unusedfields.report-can-be-private", "wt") as f:
284 for t in tmp3list:
285 f.write( t[1] + "\n" )
286 f.write( " " + t[0] + "\n" )
287 with open("compilerplugins/clang/unusedfields.readonly.results", "wt") as f:
288 for t in tmp4list:
289 f.write( t[1] + "\n" )
290 f.write( " " + t[0] + "\n" )
291 with open("compilerplugins/clang/unusedfields.only-used-in-constructor.results", "wt") as f:
292 for t in tmp5list:
293 f.write( t[1] + "\n" )
294 f.write( " " + t[0] + "\n" )
295 with open("compilerplugins/clang/unusedfields.report-all-can-be-private", "wt") as f:
296 for t in tmp6list:
297 f.write( t[1] + "\n" )
298 f.write( " " + t[0] + "\n" )