7 protectedAndPublicDefinitionSet
= set() # set of tuple(type, name)
8 definitionToSourceLocationMap
= dict()
9 definitionToTypeMap
= dict()
10 touchedFromInsideSet
= set()
11 touchedFromOutsideSet
= set()
12 touchedFromOutsideConstructorSet
= 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
):
25 return (normalizeTypeParams(tokens
[1]), tokens
[2])
27 return (normalizeTypeParams(tokens
[1]), "")
29 with io
.open("workdir/loplugin.unusedfields.log", "r", buffering
=1024*1024) as txt
:
31 tokens
= line
.strip().split("\t")
32 if tokens
[0] == "definition:":
34 fieldInfo
= (normalizeTypeParams(tokens
[2]), tokens
[3])
36 # ignore external source code
37 if (srcLoc
.startswith("external/")):
40 if (srcLoc
.startswith("workdir/")):
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
))
58 print( "unknown line: " + line
)
63 for d
in definitionSet
:
64 if d
in touchedFromOutsideSet
or d
in touchedFromInsideSet
:
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/")):
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"]):
85 if srcLoc
.startswith("cppu/source/uno/check.cxx"):
87 fieldType
= definitionToTypeMap
[d
]
88 if "ModuleClient" in fieldType
:
90 if "::sfx2::sidebar::ControllerItem" in fieldType
:
92 if "(lambda at " in d
[0]:
94 if "weld::CustomWeld" in fieldType
:
96 if "weld::Container" in fieldType
:
98 if "weld::Frame" in fieldType
:
100 untouchedSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
103 # Calculate only-touched-in-constructor set
104 onlyUsedInConstructorSet
= set()
105 for d
in definitionSet
:
106 if d
in touchedFromOutsideSet
or d
in touchedFromOutsideConstructorSet
:
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/")):
122 fieldType
= definitionToTypeMap
[d
]
123 if "std::unique_ptr" in fieldType
:
125 if "std::shared_ptr" in fieldType
:
127 if "Reference<" in fieldType
:
129 if "VclPtr<" in fieldType
:
131 if "osl::Mutex" in fieldType
:
133 if "::sfx2::sidebar::ControllerItem" in fieldType
:
135 if "(lambda at " in d
[0]:
137 onlyUsedInConstructorSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
140 for d
in definitionSet
:
142 if d
in readFromSet
or d
in untouchedSetD
:
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")):
155 fieldType
= definitionToTypeMap
[d
]
156 if "ModuleClient" in fieldType
:
158 if "::sfx2::sidebar::ControllerItem" in fieldType
:
160 # ignore reference fields, because writing to them actually writes to another field somewhere else
161 if fieldType
.endswith("&"):
163 # ignore the import/export data model stuff
164 if srcLoc
.startswith("sc/source/filter/inc/") and "Model" in fieldType
:
166 if srcLoc
.startswith("sc/source/filter/inc/") and (parentClazz
.startswith("Xcl") or parentClazz
.startswith("oox::xls::")):
168 # implement some kind of registration of errors
169 if fieldType
== "class SfxErrorHandler *":
172 if "Guard" in fieldType
:
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/")):
183 if "(lambda at " in d
[0]:
185 if "weld::CustomWeld" in fieldType
:
187 if "weld::Container" in fieldType
:
189 if "weld::Frame" in fieldType
:
191 writeonlySet
.add((d
[0] + " " + d
[1] + " " + definitionToTypeMap
[d
], srcLoc
))
195 for d
in definitionSet
:
197 if d
in writeToSet
or d
in untouchedSetD
:
199 fieldType
= definitionToTypeMap
[d
]
200 srcLoc
= definitionToSourceLocationMap
[d
];
201 if "ModuleClient" in fieldType
:
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")):
211 # I really don't care about these ancient file formats
212 if (srcLoc
.startswith("hwpfilter/")
213 or srcLoc
.startswith("lotuswordpro/")):
215 if "(lambda at " in d
[0]:
217 if "weld::CustomWeld" in fieldType
:
219 if "weld::Container" in fieldType
:
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
:
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
:
244 if d
in touchedFromOutsideSet
:
245 excludedClasses
.add(clazz
)
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
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
:
276 f
.write( t
[1] + "\n" )
277 f
.write( " " + t
[0] + "\n" )
278 with
open("compilerplugins/clang/unusedfields.writeonly.results", "wt") as f
:
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
:
285 f
.write( t
[1] + "\n" )
286 f
.write( " " + t
[0] + "\n" )
287 with
open("compilerplugins/clang/unusedfields.readonly.results", "wt") as f
:
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
:
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
:
297 f
.write( t
[1] + "\n" )
298 f
.write( " " + t
[0] + "\n" )