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
)
61 # Invert the definitionToSourceLocationMap
62 # If we see more than one method at the same sourceLocation, it's being autogenerated as part of a template
63 # and we should just ignore it
64 sourceLocationToDefinitionMap
= {}
65 for k
, v
in definitionToSourceLocationMap
.iteritems():
66 sourceLocationToDefinitionMap
[v
] = sourceLocationToDefinitionMap
.get(v
, [])
67 sourceLocationToDefinitionMap
[v
].append(k
)
68 for k
, definitions
in sourceLocationToDefinitionMap
.iteritems():
69 if len(definitions
) > 1:
71 definitionSet
.remove(d
)
76 for d
in definitionSet
:
77 if d
in touchedFromOutsideSet
or d
in touchedFromInsideSet
:
79 srcLoc
= definitionToSourceLocationMap
[d
];
80 # this is all representations of on-disk data structures
81 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
82 or srcLoc
.startswith("sw/source/filter/ww8/")
83 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
84 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
85 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
86 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
87 or srcLoc
.startswith("include/svl/svdde.hxx")
88 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
89 or srcLoc
.startswith("hwpfilter/")
90 or srcLoc
.startswith("embeddedobj/source/inc/")
91 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")
92 or srcLoc
.startswith("bridges/")):
94 if d
[0] in set([ "AtkObjectWrapperClass", "AtkObjectWrapper", "GLOMenu", "GLOAction", "_XRegion", "SalMenuButtonItem", "Vertex",
95 "OOoMountOperationClass", "SwCSS1ItemIds", "ScCompiler::AddInMap", "MemoryByteGrabber", "textcat_t", "fp_t", "ngram_t",
96 "ImplPPTParaPropSet", "DataNode"]):
99 if srcLoc
.startswith("cppu/source/uno/check.cxx"):
101 fieldType
= definitionToTypeMap
[d
]
102 if "ModuleClient" in fieldType
:
104 if "::sfx2::sidebar::ControllerItem" in fieldType
:
106 untouchedSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
109 # Calculate only-touched-in-constructor set
110 onlyUsedInConstructorSet
= set()
111 for d
in definitionSet
:
112 if d
in touchedFromOutsideSet
or d
in touchedFromOutsideConstructorSet
:
114 srcLoc
= definitionToSourceLocationMap
[d
];
115 # this is all representations of on-disk data structures
116 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
117 or srcLoc
.startswith("sw/source/filter/ww8/")
118 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
119 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
120 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
121 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
122 or srcLoc
.startswith("include/svl/svdde.hxx")
123 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
124 or srcLoc
.startswith("hwpfilter/")
125 or srcLoc
.startswith("embeddedobj/source/inc/")
126 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")
127 or srcLoc
.startswith("bridges/")):
129 fieldType
= definitionToTypeMap
[d
]
130 if "std::unique_ptr" in fieldType
:
132 if "std::shared_ptr" in fieldType
:
134 if "Reference<" in fieldType
:
136 if "VclPtr<" in fieldType
:
138 if "osl::Mutex" in fieldType
:
140 if "::sfx2::sidebar::ControllerItem" in fieldType
:
142 onlyUsedInConstructorSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
145 for d
in definitionSet
:
147 if d
in readFromSet
or d
in untouchedSetD
:
149 srcLoc
= definitionToSourceLocationMap
[d
];
150 # this is all representations of on-disk data structures
151 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
152 or srcLoc
.startswith("sw/source/filter/ww8/")
153 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
154 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
155 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
156 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
157 or srcLoc
.startswith("include/svl/svdde.hxx")
158 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
159 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")):
161 fieldType
= definitionToTypeMap
[d
]
162 if "ModuleClient" in fieldType
:
164 if "::sfx2::sidebar::ControllerItem" in fieldType
:
166 # ignore reference fields, because writing to them actually writes to another field somewhere else
167 if fieldType
.endswith("&"):
169 # ignore the import/export data model stuff
170 if srcLoc
.startswith("sc/source/filter/inc/") and "Model" in fieldType
:
172 if srcLoc
.startswith("sc/source/filter/inc/") and (parentClazz
.startswith("Xcl") or parentClazz
.startswith("oox::xls::")):
174 # implement some kind of registration of errors
175 if fieldType
== "class SfxErrorHandler *":
178 if "Guard" in fieldType
:
180 # these are just all model classes
181 if (srcLoc
.startswith("oox/")
182 or srcLoc
.startswith("lotuswordpro/")
183 or srcLoc
.startswith("include/oox/")
184 or srcLoc
.startswith("include/filter/")
185 or srcLoc
.startswith("hwpfilter/")
186 or srcLoc
.startswith("filter/")):
189 writeonlySet
.add((d
[0] + " " + d
[1] + " " + definitionToTypeMap
[d
], srcLoc
))
193 for d
in definitionSet
:
195 if d
in writeToSet
or d
in untouchedSetD
:
197 fieldType
= definitionToTypeMap
[d
]
198 srcLoc
= definitionToSourceLocationMap
[d
];
199 if "ModuleClient" in fieldType
:
201 # this is all representations of on-disk data structures
202 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
203 or srcLoc
.startswith("sw/source/filter/ww8/")
204 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
205 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
206 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
207 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
208 or srcLoc
.startswith("include/svl/svdde.hxx")):
210 # I really don't care about these ancient file formats
211 if (srcLoc
.startswith("hwpfilter/")
212 or srcLoc
.startswith("lotuswordpro/")):
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 # sort the results using a "natural order" so sequences like [item1,item2,item10] sort nicely
228 def natural_sort_key(s
, _nsre
=re
.compile('([0-9]+)')):
229 return [int(text
) if text
.isdigit() else text
.lower()
230 for text
in re
.split(_nsre
, s
)]
232 # sort results by name and line number
233 tmp1list
= sorted(untouchedSet
, key
=lambda v
: natural_sort_key(v
[1]))
234 tmp2list
= sorted(writeonlySet
, key
=lambda v
: natural_sort_key(v
[1]))
235 tmp3list
= sorted(canBePrivateSet
, key
=lambda v
: natural_sort_key(v
[1]))
236 tmp4list
= sorted(readonlySet
, key
=lambda v
: natural_sort_key(v
[1]))
237 tmp5list
= sorted(onlyUsedInConstructorSet
, key
=lambda v
: natural_sort_key(v
[1]))
239 # print out the results
240 with
open("compilerplugins/clang/unusedfields.untouched.results", "wt") as f
:
242 f
.write( t
[1] + "\n" )
243 f
.write( " " + t
[0] + "\n" )
244 with
open("compilerplugins/clang/unusedfields.writeonly.results", "wt") as f
:
246 f
.write( t
[1] + "\n" )
247 f
.write( " " + t
[0] + "\n" )
248 # this one is not checked in yet because I haven't actually done anything with it
249 with
open("loplugin.unusedfields.report-can-be-private", "wt") as f
:
251 f
.write( t
[1] + "\n" )
252 f
.write( " " + t
[0] + "\n" )
253 with
open("compilerplugins/clang/unusedfields.readonly.results", "wt") as f
:
255 f
.write( t
[1] + "\n" )
256 f
.write( " " + t
[0] + "\n" )
257 with
open("compilerplugins/clang/unusedfields.only-used-in-constructor.results", "wt") as f
:
259 f
.write( t
[1] + "\n" )
260 f
.write( " " + t
[0] + "\n" )