8 protectedAndPublicDefinitionSet
= set() # set of tuple(type, name)
9 definitionToSourceLocationMap
= dict()
10 definitionToTypeMap
= dict()
11 touchedFromInsideSet
= set()
12 touchedFromOutsideSet
= set()
13 touchedFromOutsideConstructorSet
= set()
16 sourceLocationSet
= set()
18 # clang does not always use exactly the same numbers in the type-parameter vars it generates
19 # so I need to substitute them to ensure we can match correctly.
20 normalizeTypeParamsRegex
= re
.compile(r
"type-parameter-\d+-\d+")
21 def normalizeTypeParams( line
):
22 return normalizeTypeParamsRegex
.sub("type-parameter-?-?", line
)
24 def parseFieldInfo( tokens
):
26 return (normalizeTypeParams(tokens
[1]), tokens
[2])
28 return (normalizeTypeParams(tokens
[1]), "")
30 with io
.open("workdir/loplugin.unusedfields.log", "r", buffering
=1024*1024) as txt
:
32 tokens
= line
.strip().split("\t")
33 if tokens
[0] == "definition:":
35 fieldInfo
= (normalizeTypeParams(tokens
[2]), tokens
[3])
37 # ignore external source code
38 if (srcLoc
.startswith("external/")):
41 if (srcLoc
.startswith("workdir/")):
43 definitionSet
.add(fieldInfo
)
44 definitionToTypeMap
[fieldInfo
] = tokens
[4]
45 if access
== "protected" or access
== "public":
46 protectedAndPublicDefinitionSet
.add(fieldInfo
)
47 definitionToSourceLocationMap
[fieldInfo
] = tokens
[5]
48 elif tokens
[0] == "inside:":
49 touchedFromInsideSet
.add(parseFieldInfo(tokens
))
50 elif tokens
[0] == "outside:":
51 touchedFromOutsideSet
.add(parseFieldInfo(tokens
))
52 elif tokens
[0] == "outside-constructor:":
53 touchedFromOutsideConstructorSet
.add(parseFieldInfo(tokens
))
54 elif tokens
[0] == "read:":
55 readFromSet
.add(parseFieldInfo(tokens
))
56 elif tokens
[0] == "write:":
57 writeToSet
.add(parseFieldInfo(tokens
))
59 print( "unknown line: " + line
)
64 for d
in definitionSet
:
65 if d
in touchedFromOutsideSet
or d
in touchedFromInsideSet
:
67 srcLoc
= definitionToSourceLocationMap
[d
];
68 # this is all representations of on-disk data structures
69 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
70 or srcLoc
.startswith("sw/source/filter/ww8/")
71 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
72 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
73 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
74 or srcLoc
.startswith("include/svl/svdde.hxx")
75 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
76 or srcLoc
.startswith("hwpfilter/")
77 or srcLoc
.startswith("embeddedobj/source/inc/")
78 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")
79 or srcLoc
.startswith("bridges/")):
81 if d
[0] in set([ "AtkObjectWrapperClass", "AtkObjectWrapper", "GLOMenu", "GLOAction", "_XRegion", "SalMenuButtonItem", "Vertex",
82 "OOoMountOperationClass", "SwCSS1ItemIds", "ScCompiler::AddInMap", "MemoryByteGrabber", "textcat_t", "fp_t", "ngram_t",
83 "ImplPPTParaPropSet", "DataNode"]):
86 if srcLoc
.startswith("cppu/source/uno/check.cxx"):
88 fieldType
= definitionToTypeMap
[d
]
89 if "ModuleClient" in fieldType
:
91 # leave the weld stuff alone until Caolan is finished
92 if "weld::" in fieldType
:
94 if "::sfx2::sidebar::ControllerItem" in fieldType
:
96 untouchedSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
99 # Calculate only-touched-in-constructor set
100 onlyUsedInConstructorSet
= set()
101 for d
in definitionSet
:
102 if d
in touchedFromOutsideSet
or d
in touchedFromOutsideConstructorSet
:
104 srcLoc
= definitionToSourceLocationMap
[d
];
105 # this is all representations of on-disk data structures
106 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
107 or srcLoc
.startswith("sw/source/filter/ww8/")
108 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
109 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
110 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
111 or srcLoc
.startswith("include/svl/svdde.hxx")
112 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
113 or srcLoc
.startswith("hwpfilter/")
114 or srcLoc
.startswith("embeddedobj/source/inc/")
115 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")
116 or srcLoc
.startswith("bridges/")):
118 fieldType
= definitionToTypeMap
[d
]
119 if "std::unique_ptr" in fieldType
:
121 if "std::shared_ptr" in fieldType
:
123 if "Reference<" in fieldType
:
125 if "VclPtr<" in fieldType
:
127 # leave the weld stuff alone until Caolan is finished
128 if "weld::" in fieldType
:
130 if "osl::Mutex" in fieldType
:
132 if "::sfx2::sidebar::ControllerItem" in fieldType
:
134 onlyUsedInConstructorSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
137 for d
in definitionSet
:
139 if d
in readFromSet
or d
in untouchedSetD
:
141 srcLoc
= definitionToSourceLocationMap
[d
];
142 # this is all representations of on-disk data structures
143 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
144 or srcLoc
.startswith("sw/source/filter/ww8/")
145 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
146 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
147 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
148 or srcLoc
.startswith("include/svl/svdde.hxx")
149 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
150 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")):
152 fieldType
= definitionToTypeMap
[d
]
153 if "ModuleClient" in fieldType
:
155 if "::sfx2::sidebar::ControllerItem" in fieldType
:
157 # ignore reference fields, because writing to them actually writes to another field somewhere else
158 if fieldType
.endswith("&"):
160 # ignore the import/export data model stuff
161 if srcLoc
.startswith("sc/source/filter/inc/") and "Model" in fieldType
:
163 if srcLoc
.startswith("sc/source/filter/inc/") and (parentClazz
.startswith("Xcl") or parentClazz
.startswith("oox::xls::")):
165 # implement some kind of registration of errors
166 if fieldType
== "class SfxErrorHandler *":
169 if "Guard" in fieldType
:
171 # leave the weld stuff alone until Caolan is finished
172 if "weld::" 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/")):
184 writeonlySet
.add((d
[0] + " " + d
[1] + " " + definitionToTypeMap
[d
], srcLoc
))
188 for d
in definitionSet
:
190 if d
in writeToSet
or d
in untouchedSetD
:
192 fieldType
= definitionToTypeMap
[d
]
193 srcLoc
= definitionToSourceLocationMap
[d
];
194 if "ModuleClient" in fieldType
:
196 # this is all representations of on-disk data structures
197 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
198 or srcLoc
.startswith("sw/source/filter/ww8/")
199 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
200 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
201 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
202 or srcLoc
.startswith("include/svl/svdde.hxx")):
204 # I really don't care about these ancient file formats
205 if (srcLoc
.startswith("hwpfilter/")
206 or srcLoc
.startswith("lotuswordpro/")):
208 # leave the weld stuff alone until Caolan is finished
209 if "weld::" in fieldType
:
211 readonlySet
.add((d
[0] + " " + d
[1] + " " + definitionToTypeMap
[d
], srcLoc
))
214 canBePrivateSet
= set()
215 for d
in protectedAndPublicDefinitionSet
:
216 clazz
= d
[0] + " " + d
[1]
217 if d
in touchedFromOutsideSet
:
219 srcLoc
= definitionToSourceLocationMap
[d
];
221 canBePrivateSet
.add((clazz
+ " " + definitionToTypeMap
[d
], srcLoc
))
224 # --------------------------------------------------------------------------------------------
225 # "all fields in class can be made private" analysis
226 # --------------------------------------------------------------------------------------------
228 potentialClasses
= set()
229 excludedClasses
= set()
230 potentialClassesSourceLocationMap
= dict()
231 matchClassName
= re
.compile(r
"(\w+)::")
232 for d
in protectedAndPublicDefinitionSet
:
234 if d
in touchedFromOutsideSet
:
235 excludedClasses
.add(clazz
)
237 potentialClasses
.add(clazz
)
238 potentialClassesSourceLocationMap
[clazz
] = definitionToSourceLocationMap
[d
]
239 allFieldsCanBePrivateSet
= set()
240 for d
in (potentialClasses
- excludedClasses
):
241 sourceLoc
= potentialClassesSourceLocationMap
[d
]
242 # when the class is inside a compile unit, assume that the compiler can figure this out for itself, much less interesting to me
243 if not ".cxx" in sourceLoc
:
244 allFieldsCanBePrivateSet
.add((d
, sourceLoc
))
246 # sort the results using a "natural order" so sequences like [item1,item2,item10] sort nicely
247 def natural_sort_key(s
, _nsre
=re
.compile('([0-9]+)')):
248 return [int(text
) if text
.isdigit() else text
.lower()
249 for text
in re
.split(_nsre
, s
)]
250 # sort by both the source-line and the datatype, so the output file ordering is stable
251 # when we have multiple items on the same source line
253 return natural_sort_key(v
[1]) + [v
[0]]
255 # sort results by name and line number
256 tmp1list
= sorted(untouchedSet
, key
=lambda v
: v_sort_key(v
))
257 tmp2list
= sorted(writeonlySet
, key
=lambda v
: v_sort_key(v
))
258 tmp3list
= sorted(canBePrivateSet
, key
=lambda v
: v_sort_key(v
))
259 tmp4list
= sorted(readonlySet
, key
=lambda v
: v_sort_key(v
))
260 tmp5list
= sorted(onlyUsedInConstructorSet
, key
=lambda v
: v_sort_key(v
))
261 tmp6list
= sorted(allFieldsCanBePrivateSet
, key
=lambda v
: v_sort_key(v
))
263 # print out the results
264 with
open("compilerplugins/clang/unusedfields.untouched.results", "wt") as f
:
266 f
.write( t
[1] + "\n" )
267 f
.write( " " + t
[0] + "\n" )
268 with
open("compilerplugins/clang/unusedfields.writeonly.results", "wt") as f
:
270 f
.write( t
[1] + "\n" )
271 f
.write( " " + t
[0] + "\n" )
272 # this one is not checked in yet because I haven't actually done anything with it
273 with
open("loplugin.unusedfields.report-can-be-private", "wt") as f
:
275 f
.write( t
[1] + "\n" )
276 f
.write( " " + t
[0] + "\n" )
277 with
open("compilerplugins/clang/unusedfields.readonly.results", "wt") as f
:
279 f
.write( t
[1] + "\n" )
280 f
.write( " " + t
[0] + "\n" )
281 with
open("compilerplugins/clang/unusedfields.only-used-in-constructor.results", "wt") as f
:
283 f
.write( t
[1] + "\n" )
284 f
.write( " " + t
[0] + "\n" )
285 with
open("compilerplugins/clang/unusedfields.report-all-can-be-private", "wt") as f
:
287 f
.write( t
[1] + "\n" )
288 f
.write( " " + t
[0] + "\n" )