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 if "::sfx2::sidebar::ControllerItem" in fieldType
:
94 untouchedSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
97 # Calculate only-touched-in-constructor set
98 onlyUsedInConstructorSet
= set()
99 for d
in definitionSet
:
100 if d
in touchedFromOutsideSet
or d
in touchedFromOutsideConstructorSet
:
102 srcLoc
= definitionToSourceLocationMap
[d
];
103 # this is all representations of on-disk data structures
104 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
105 or srcLoc
.startswith("sw/source/filter/ww8/")
106 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
107 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
108 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
109 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
110 or srcLoc
.startswith("include/svl/svdde.hxx")
111 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
112 or srcLoc
.startswith("hwpfilter/")
113 or srcLoc
.startswith("embeddedobj/source/inc/")
114 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")
115 or srcLoc
.startswith("bridges/")):
117 fieldType
= definitionToTypeMap
[d
]
118 if "std::unique_ptr" in fieldType
:
120 if "std::shared_ptr" in fieldType
:
122 if "Reference<" in fieldType
:
124 if "VclPtr<" in fieldType
:
126 if "osl::Mutex" in fieldType
:
128 if "::sfx2::sidebar::ControllerItem" in fieldType
:
130 onlyUsedInConstructorSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
133 for d
in definitionSet
:
135 if d
in readFromSet
or d
in untouchedSetD
:
137 srcLoc
= definitionToSourceLocationMap
[d
];
138 # this is all representations of on-disk data structures
139 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
140 or srcLoc
.startswith("sw/source/filter/ww8/")
141 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
142 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
143 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
144 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
145 or srcLoc
.startswith("include/svl/svdde.hxx")
146 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
147 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")):
149 fieldType
= definitionToTypeMap
[d
]
150 if "ModuleClient" in fieldType
:
152 if "::sfx2::sidebar::ControllerItem" in fieldType
:
154 # ignore reference fields, because writing to them actually writes to another field somewhere else
155 if fieldType
.endswith("&"):
157 # ignore the import/export data model stuff
158 if srcLoc
.startswith("sc/source/filter/inc/") and "Model" in fieldType
:
160 if srcLoc
.startswith("sc/source/filter/inc/") and (parentClazz
.startswith("Xcl") or parentClazz
.startswith("oox::xls::")):
162 # implement some kind of registration of errors
163 if fieldType
== "class SfxErrorHandler *":
166 if "Guard" in fieldType
:
168 # these are just all model classes
169 if (srcLoc
.startswith("oox/")
170 or srcLoc
.startswith("lotuswordpro/")
171 or srcLoc
.startswith("include/oox/")
172 or srcLoc
.startswith("include/filter/")
173 or srcLoc
.startswith("hwpfilter/")
174 or srcLoc
.startswith("filter/")):
177 writeonlySet
.add((d
[0] + " " + d
[1] + " " + definitionToTypeMap
[d
], srcLoc
))
181 for d
in definitionSet
:
183 if d
in writeToSet
or d
in untouchedSetD
:
185 fieldType
= definitionToTypeMap
[d
]
186 srcLoc
= definitionToSourceLocationMap
[d
];
187 if "ModuleClient" in fieldType
:
189 # this is all representations of on-disk data structures
190 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
191 or srcLoc
.startswith("sw/source/filter/ww8/")
192 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
193 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
194 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
195 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
196 or srcLoc
.startswith("include/svl/svdde.hxx")):
198 # I really don't care about these ancient file formats
199 if (srcLoc
.startswith("hwpfilter/")
200 or srcLoc
.startswith("lotuswordpro/")):
202 readonlySet
.add((d
[0] + " " + d
[1] + " " + definitionToTypeMap
[d
], srcLoc
))
205 canBePrivateSet
= set()
206 for d
in protectedAndPublicDefinitionSet
:
207 clazz
= d
[0] + " " + d
[1]
208 if d
in touchedFromOutsideSet
:
210 srcLoc
= definitionToSourceLocationMap
[d
];
212 canBePrivateSet
.add((clazz
+ " " + definitionToTypeMap
[d
], srcLoc
))
215 # --------------------------------------------------------------------------------------------
216 # "all fields in class can be made private" analysis
217 # --------------------------------------------------------------------------------------------
219 potentialClasses
= set()
220 excludedClasses
= set()
221 potentialClassesSourceLocationMap
= dict()
222 matchClassName
= re
.compile(r
"(\w+)::")
223 for d
in protectedAndPublicDefinitionSet
:
225 if d
in touchedFromOutsideSet
:
226 excludedClasses
.add(clazz
)
228 potentialClasses
.add(clazz
)
229 potentialClassesSourceLocationMap
[clazz
] = definitionToSourceLocationMap
[d
]
230 allFieldsCanBePrivateSet
= set()
231 for d
in (potentialClasses
- excludedClasses
):
232 sourceLoc
= potentialClassesSourceLocationMap
[d
]
233 # when the class is inside a compile unit, assume that the compiler can figure this out for itself, much less interesting to me
234 if not ".cxx" in sourceLoc
:
235 allFieldsCanBePrivateSet
.add((d
, sourceLoc
))
237 # sort the results using a "natural order" so sequences like [item1,item2,item10] sort nicely
238 def natural_sort_key(s
, _nsre
=re
.compile('([0-9]+)')):
239 return [int(text
) if text
.isdigit() else text
.lower()
240 for text
in re
.split(_nsre
, s
)]
242 # sort results by name and line number
243 tmp1list
= sorted(untouchedSet
, key
=lambda v
: natural_sort_key(v
[1]))
244 tmp2list
= sorted(writeonlySet
, key
=lambda v
: natural_sort_key(v
[1]))
245 tmp3list
= sorted(canBePrivateSet
, key
=lambda v
: natural_sort_key(v
[1]))
246 tmp4list
= sorted(readonlySet
, key
=lambda v
: natural_sort_key(v
[1]))
247 tmp5list
= sorted(onlyUsedInConstructorSet
, key
=lambda v
: natural_sort_key(v
[1]))
248 tmp6list
= sorted(allFieldsCanBePrivateSet
, key
=lambda v
: natural_sort_key(v
[1]))
250 # print out the results
251 with
open("compilerplugins/clang/unusedfields.untouched.results", "wt") as f
:
253 f
.write( t
[1] + "\n" )
254 f
.write( " " + t
[0] + "\n" )
255 with
open("compilerplugins/clang/unusedfields.writeonly.results", "wt") as f
:
257 f
.write( t
[1] + "\n" )
258 f
.write( " " + t
[0] + "\n" )
259 # this one is not checked in yet because I haven't actually done anything with it
260 with
open("loplugin.unusedfields.report-can-be-private", "wt") as f
:
262 f
.write( t
[1] + "\n" )
263 f
.write( " " + t
[0] + "\n" )
264 with
open("compilerplugins/clang/unusedfields.readonly.results", "wt") as f
:
266 f
.write( t
[1] + "\n" )
267 f
.write( " " + t
[0] + "\n" )
268 with
open("compilerplugins/clang/unusedfields.only-used-in-constructor.results", "wt") as f
:
270 f
.write( t
[1] + "\n" )
271 f
.write( " " + t
[0] + "\n" )
272 with
open("compilerplugins/clang/unusedfields.report-all-can-be-private", "wt") as f
:
274 f
.write( t
[1] + "\n" )
275 f
.write( " " + t
[0] + "\n" )