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", "rb", 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/XIM.h")
74 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
75 or srcLoc
.startswith("include/svl/svdde.hxx")
76 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
77 or srcLoc
.startswith("hwpfilter/")
78 or srcLoc
.startswith("embeddedobj/source/inc/")
79 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")
80 or srcLoc
.startswith("bridges/")):
82 if d
[0] in set([ "AtkObjectWrapperClass", "AtkObjectWrapper", "GLOMenu", "GLOAction", "_XRegion", "SalMenuButtonItem", "Vertex",
83 "OOoMountOperationClass", "SwCSS1ItemIds", "ScCompiler::AddInMap", "MemoryByteGrabber", "textcat_t", "fp_t", "ngram_t",
84 "ImplPPTParaPropSet", "DataNode"]):
87 if srcLoc
.startswith("cppu/source/uno/check.cxx"):
89 fieldType
= definitionToTypeMap
[d
]
90 if "ModuleClient" in fieldType
:
92 # leave the weld stuff alone until Caolan is finished
93 if "weld::" in fieldType
:
95 if "::sfx2::sidebar::ControllerItem" in fieldType
:
97 untouchedSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
100 # Calculate only-touched-in-constructor set
101 onlyUsedInConstructorSet
= set()
102 for d
in definitionSet
:
103 if d
in touchedFromOutsideSet
or d
in touchedFromOutsideConstructorSet
:
105 srcLoc
= definitionToSourceLocationMap
[d
];
106 # this is all representations of on-disk data structures
107 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
108 or srcLoc
.startswith("sw/source/filter/ww8/")
109 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
110 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
111 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
112 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
113 or srcLoc
.startswith("include/svl/svdde.hxx")
114 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
115 or srcLoc
.startswith("hwpfilter/")
116 or srcLoc
.startswith("embeddedobj/source/inc/")
117 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")
118 or srcLoc
.startswith("bridges/")):
120 fieldType
= definitionToTypeMap
[d
]
121 if "std::unique_ptr" in fieldType
:
123 if "std::shared_ptr" in fieldType
:
125 if "Reference<" in fieldType
:
127 if "VclPtr<" in fieldType
:
129 # leave the weld stuff alone until Caolan is finished
130 if "weld::" in fieldType
:
132 if "osl::Mutex" in fieldType
:
134 if "::sfx2::sidebar::ControllerItem" in fieldType
:
136 onlyUsedInConstructorSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
139 for d
in definitionSet
:
141 if d
in readFromSet
or d
in untouchedSetD
:
143 srcLoc
= definitionToSourceLocationMap
[d
];
144 # this is all representations of on-disk data structures
145 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
146 or srcLoc
.startswith("sw/source/filter/ww8/")
147 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
148 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
149 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
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 # leave the weld stuff alone until Caolan is finished
175 if "weld::" in fieldType
:
177 # these are just all model classes
178 if (srcLoc
.startswith("oox/")
179 or srcLoc
.startswith("lotuswordpro/")
180 or srcLoc
.startswith("include/oox/")
181 or srcLoc
.startswith("include/filter/")
182 or srcLoc
.startswith("hwpfilter/")
183 or srcLoc
.startswith("filter/")):
186 writeonlySet
.add((d
[0] + " " + d
[1] + " " + definitionToTypeMap
[d
], srcLoc
))
190 for d
in definitionSet
:
192 if d
in writeToSet
or d
in untouchedSetD
:
194 fieldType
= definitionToTypeMap
[d
]
195 srcLoc
= definitionToSourceLocationMap
[d
];
196 if "ModuleClient" in fieldType
:
198 # this is all representations of on-disk data structures
199 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
200 or srcLoc
.startswith("sw/source/filter/ww8/")
201 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
202 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
203 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
204 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
205 or srcLoc
.startswith("include/svl/svdde.hxx")):
207 # I really don't care about these ancient file formats
208 if (srcLoc
.startswith("hwpfilter/")
209 or srcLoc
.startswith("lotuswordpro/")):
211 # leave the weld stuff alone until Caolan is finished
212 if "weld::" in fieldType
:
214 readonlySet
.add((d
[0] + " " + d
[1] + " " + definitionToTypeMap
[d
], srcLoc
))
217 canBePrivateSet
= set()
218 for d
in protectedAndPublicDefinitionSet
:
219 clazz
= d
[0] + " " + d
[1]
220 if d
in touchedFromOutsideSet
:
222 srcLoc
= definitionToSourceLocationMap
[d
];
224 canBePrivateSet
.add((clazz
+ " " + definitionToTypeMap
[d
], srcLoc
))
227 # --------------------------------------------------------------------------------------------
228 # "all fields in class can be made private" analysis
229 # --------------------------------------------------------------------------------------------
231 potentialClasses
= set()
232 excludedClasses
= set()
233 potentialClassesSourceLocationMap
= dict()
234 matchClassName
= re
.compile(r
"(\w+)::")
235 for d
in protectedAndPublicDefinitionSet
:
237 if d
in touchedFromOutsideSet
:
238 excludedClasses
.add(clazz
)
240 potentialClasses
.add(clazz
)
241 potentialClassesSourceLocationMap
[clazz
] = definitionToSourceLocationMap
[d
]
242 allFieldsCanBePrivateSet
= set()
243 for d
in (potentialClasses
- excludedClasses
):
244 sourceLoc
= potentialClassesSourceLocationMap
[d
]
245 # when the class is inside a compile unit, assume that the compiler can figure this out for itself, much less interesting to me
246 if not ".cxx" in sourceLoc
:
247 allFieldsCanBePrivateSet
.add((d
, sourceLoc
))
249 # sort the results using a "natural order" so sequences like [item1,item2,item10] sort nicely
250 def natural_sort_key(s
, _nsre
=re
.compile('([0-9]+)')):
251 return [int(text
) if text
.isdigit() else text
.lower()
252 for text
in re
.split(_nsre
, s
)]
254 # sort results by name and line number
255 tmp1list
= sorted(untouchedSet
, key
=lambda v
: natural_sort_key(v
[1]))
256 tmp2list
= sorted(writeonlySet
, key
=lambda v
: natural_sort_key(v
[1]))
257 tmp3list
= sorted(canBePrivateSet
, key
=lambda v
: natural_sort_key(v
[1]))
258 tmp4list
= sorted(readonlySet
, key
=lambda v
: natural_sort_key(v
[1]))
259 tmp5list
= sorted(onlyUsedInConstructorSet
, key
=lambda v
: natural_sort_key(v
[1]))
260 tmp6list
= sorted(allFieldsCanBePrivateSet
, key
=lambda v
: natural_sort_key(v
[1]))
262 # print out the results
263 with
open("compilerplugins/clang/unusedfields.untouched.results", "wt") as f
:
265 f
.write( t
[1] + "\n" )
266 f
.write( " " + t
[0] + "\n" )
267 with
open("compilerplugins/clang/unusedfields.writeonly.results", "wt") as f
:
269 f
.write( t
[1] + "\n" )
270 f
.write( " " + t
[0] + "\n" )
271 # this one is not checked in yet because I haven't actually done anything with it
272 with
open("loplugin.unusedfields.report-can-be-private", "wt") as f
:
274 f
.write( t
[1] + "\n" )
275 f
.write( " " + t
[0] + "\n" )
276 with
open("compilerplugins/clang/unusedfields.readonly.results", "wt") as f
:
278 f
.write( t
[1] + "\n" )
279 f
.write( " " + t
[0] + "\n" )
280 with
open("compilerplugins/clang/unusedfields.only-used-in-constructor.results", "wt") as f
:
282 f
.write( t
[1] + "\n" )
283 f
.write( " " + t
[0] + "\n" )
284 with
open("compilerplugins/clang/unusedfields.report-all-can-be-private", "wt") as f
:
286 f
.write( t
[1] + "\n" )
287 f
.write( " " + t
[0] + "\n" )