8 protectedAndPublicDefinitionSet
= set() # set of tuple(type, name)
9 definitionToSourceLocationMap
= dict()
10 definitionToTypeMap
= dict()
13 sourceLocationSet
= set()
14 touchedFromOutsideSet
= set()
16 # clang does not always use exactly the same numbers in the type-parameter vars it generates
17 # so I need to substitute them to ensure we can match correctly.
18 normalizeTypeParamsRegex
= re
.compile(r
"type-parameter-\d+-\d+")
19 def normalizeTypeParams( line
):
20 return normalizeTypeParamsRegex
.sub("type-parameter-?-?", line
)
22 def parseFieldInfo( tokens
):
24 return (normalizeTypeParams(tokens
[1]), tokens
[2])
26 return (normalizeTypeParams(tokens
[1]), "")
28 # The parsing here is designed to avoid grabbing stuff which is mixed in from gbuild.
29 # I have not yet found a way of suppressing the gbuild output.
30 with io
.open("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] == "touch:":
49 callSet
.add(parseFieldInfo(tokens
))
50 elif tokens
[0] == "read:":
51 readFromSet
.add(parseFieldInfo(tokens
))
52 elif tokens
[0] == "read:":
53 readFromSet
.add(parseFieldInfo(tokens
))
54 elif tokens
[0] == "outside:":
55 touchedFromOutsideSet
.add(parseFieldInfo(tokens
))
57 print( "unknown line: " + line
)
59 # Invert the definitionToSourceLocationMap
60 # If we see more than one method at the same sourceLocation, it's being autogenerated as part of a template
61 # and we should just ignore
62 sourceLocationToDefinitionMap
= {}
63 for k
, v
in definitionToSourceLocationMap
.iteritems():
64 sourceLocationToDefinitionMap
[v
] = sourceLocationToDefinitionMap
.get(v
, [])
65 sourceLocationToDefinitionMap
[v
].append(k
)
66 for k
, definitions
in sourceLocationToDefinitionMap
.iteritems():
67 if len(definitions
) > 1:
69 definitionSet
.remove(d
)
72 for d
in definitionSet
:
75 srcLoc
= definitionToSourceLocationMap
[d
];
76 # this is all representations of on-disk data structures
77 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
78 or srcLoc
.startswith("sw/source/filter/ww8/")
79 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
80 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
81 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
82 or srcLoc
.startswith("vcl/inc/unx/gtk/gloactiongroup.h")
83 or srcLoc
.startswith("include/svl/svdde.hxx")
84 or srcLoc
.startswith("lotuswordpro/source/filter/lwpsdwdrawheader.hxx")
85 or srcLoc
.startswith("hwpfilter/")
86 or srcLoc
.startswith("embeddedobj/source/inc/")
87 or srcLoc
.startswith("svtools/source/dialogs/insdlg.cxx")
88 or srcLoc
.startswith("bridges/")):
90 if d
[0] in set([ "AtkObjectWrapperClass", "AtkObjectWrapper", "GLOMenu", "GLOAction", "_XRegion", "SalMenuButtonItem", "Vertex",
91 "OOoMountOperationClass", "SwCSS1ItemIds", "ScCompiler::AddInMap", "MemoryByteGrabber", "textcat_t", "fp_t", "ngram_t",
92 "ImplPPTParaPropSet", "DataNode"]):
95 if srcLoc
.startswith("cppu/source/uno/check.cxx"):
97 fieldType
= definitionToTypeMap
[d
]
98 if fieldType
in set([ "class rptui::OModuleClient" ]):
100 untouchedSet
.add((d
[0] + " " + d
[1] + " " + fieldType
, srcLoc
))
103 for d
in definitionSet
:
104 clazz
= d
[0] + " " + d
[1]
107 srcLoc
= definitionToSourceLocationMap
[d
];
108 # this is all representations of on-disk data structures
109 if (srcLoc
.startswith("sc/source/filter/inc/scflt.hxx")
110 or srcLoc
.startswith("sw/source/filter/ww8/")
111 or srcLoc
.startswith("vcl/source/filter/sgvmain.hxx")
112 or srcLoc
.startswith("vcl/source/filter/sgfbram.hxx")
113 or srcLoc
.startswith("vcl/inc/unx/XIM.h")
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("svtools/source/dialogs/insdlg.cxx")):
120 writeonlySet
.add((clazz
+ " " + definitionToTypeMap
[d
], srcLoc
))
123 canBePrivateSet
= set()
124 for d
in protectedAndPublicDefinitionSet
:
125 clazz
= d
[0] + " " + d
[1]
126 if d
in touchedFromOutsideSet
:
128 srcLoc
= definitionToSourceLocationMap
[d
];
130 canBePrivateSet
.add((clazz
+ " " + definitionToTypeMap
[d
], srcLoc
))
133 # sort the results using a "natural order" so sequences like [item1,item2,item10] sort nicely
134 def natural_sort_key(s
, _nsre
=re
.compile('([0-9]+)')):
135 return [int(text
) if text
.isdigit() else text
.lower()
136 for text
in re
.split(_nsre
, s
)]
138 # sort results by name and line number
139 tmp1list
= sorted(untouchedSet
, key
=lambda v
: natural_sort_key(v
[1]))
140 tmp2list
= sorted(writeonlySet
, key
=lambda v
: natural_sort_key(v
[1]))
141 tmp3list
= sorted(canBePrivateSet
, key
=lambda v
: natural_sort_key(v
[1]))
143 # print out the results
144 with
open("loplugin.unusedfields.report-untouched", "wt") as f
:
146 f
.write( t
[1] + "\n" )
147 f
.write( " " + t
[0] + "\n" )
148 with
open("loplugin.unusedfields.report-writeonly", "wt") as f
:
150 f
.write( t
[1] + "\n" )
151 f
.write( " " + t
[0] + "\n" )
152 with
open("loplugin.unusedfields.report-can-be-private", "wt") as f
:
154 f
.write( t
[1] + "\n" )
155 f
.write( " " + t
[0] + "\n" )