7 callDict
= dict() # callInfo tuple -> callValue
9 # clang does not always use exactly the same numbers in the type-parameter vars it generates
10 # so I need to substitute them to ensure we can match correctly.
11 normalizeTypeParamsRegex
= re
.compile(r
"type-parameter-\d+-\d+")
12 def normalizeTypeParams( line
):
13 return normalizeTypeParamsRegex
.sub("type-parameter-?-?", line
)
15 # reading as binary (since we known it is pure ascii) is much faster than reading as unicode
16 with io
.open("workdir/loplugin.constantparam.log", "rb", buffering
=1024*1024) as txt
:
19 tokens
= line
.strip().split("\t")
20 returnType
= normalizeTypeParams(tokens
[0])
21 nameAndParams
= normalizeTypeParams(tokens
[1])
22 sourceLocation
= tokens
[2]
24 paramType
= normalizeTypeParams(tokens
[4])
26 callInfo
= (returnType
, nameAndParams
, paramName
, paramType
, sourceLocation
)
27 if not callInfo
in callDict
:
28 callDict
[callInfo
] = set()
29 callDict
[callInfo
].add(callValue
)
31 print "problem with line " + line
.strip()
41 constructor_regex
= re
.compile("^\w+\(\)$")
47 for callInfo
, callValues
in callDict
.iteritems():
48 nameAndParams
= callInfo
[1]
49 if len(callValues
) != 1:
51 callValue
= next(iter(callValues
))
52 if "unknown" in callValue
:
54 sourceLoc
= callInfo
[4]
55 functionSig
= callInfo
[0] + " " + callInfo
[1]
57 # try to ignore setter methods
58 if ("," not in nameAndParams
) and (("::set" in nameAndParams
) or ("::Set" in nameAndParams
)):
60 # ignore code that follows a common pattern
61 if sourceLoc
.startswith("sw/inc/swatrset.hxx"): continue
62 if sourceLoc
.startswith("sw/inc/format.hxx"): continue
63 # template generated code
64 if sourceLoc
.startswith("include/sax/fshelper.hxx"): continue
66 if sourceLoc
.startswith("include/oox/dump"): continue
67 # part of our binary API
68 if sourceLoc
.startswith("include/LibreOfficeKit"): continue
70 # ignore methods generated by SFX macros
71 if "RegisterInterface(class SfxModule *)" in nameAndParams
: continue
72 if "RegisterChildWindow(_Bool,class SfxModule *,enum SfxChildWindowFlags)" in nameAndParams
: continue
73 if "RegisterControl(unsigned short,class SfxModule *)" in nameAndParams
: continue
75 if RepresentsInt(callValue
):
76 if callValue
== "0" or callValue
== "1":
77 tmp1list
.append((sourceLoc
, functionSig
, callInfo
[3] + " " + callInfo
[2], callValue
))
79 tmp2list
.append((sourceLoc
, functionSig
, callInfo
[3] + " " + callInfo
[2], callValue
))
80 # look for places where the callsite is always a constructor invocation
81 elif constructor_regex
.match(callValue
) or callValue
== "\"\"":
82 if callValue
.startswith("Get"): continue
83 if callValue
.startswith("get"): continue
84 if "operator=" in functionSig
: continue
85 if "&&" in functionSig
: continue
86 if callInfo
[2] == "###0" and callValue
== "InitData()": continue
87 if callInfo
[2] == "###0" and callValue
== "InitAggregate()": continue
88 if callValue
== "shared_from_this()": continue
89 tmp3list
.append((sourceLoc
, functionSig
, callInfo
[3] + " " + callInfo
[2], callValue
))
91 tmp4list
.append((sourceLoc
, functionSig
, callInfo
[3] + " " + callInfo
[2], callValue
))
94 # sort results by filename:lineno
95 def natural_sort_key(s
, _nsre
=re
.compile('([0-9]+)')):
96 return [int(text
) if text
.isdigit() else text
.lower()
97 for text
in re
.split(_nsre
, s
)]
98 tmp1list
.sort(key
=lambda v
: natural_sort_key(v
[0]))
99 tmp2list
.sort(key
=lambda v
: natural_sort_key(v
[0]))
100 tmp3list
.sort(key
=lambda v
: natural_sort_key(v
[0]))
101 tmp4list
.sort(key
=lambda v
: natural_sort_key(v
[0]))
103 # print out the results
104 with
open("compilerplugins/clang/constantparam.booleans.results", "wt") as f
:
107 f
.write(" " + v
[1] + "\n")
108 f
.write(" " + v
[2] + "\n")
109 f
.write(" " + v
[3] + "\n")
110 with
open("compilerplugins/clang/constantparam.numbers.results", "wt") as f
:
113 f
.write(" " + v
[1] + "\n")
114 f
.write(" " + v
[2] + "\n")
115 f
.write(" " + v
[3] + "\n")
116 with
open("compilerplugins/clang/constantparam.constructors.results", "wt") as f
:
119 f
.write(" " + v
[1] + "\n")
120 f
.write(" " + v
[2] + "\n")
121 f
.write(" " + v
[3] + "\n")
122 with
open("compilerplugins/clang/constantparam.others.results", "wt") as f
:
125 f
.write(" " + v
[1] + "\n")
126 f
.write(" " + v
[2] + "\n")
127 f
.write(" " + v
[3] + "\n")
129 # -------------------------------------------------------------
130 # Now a fun set of heuristics to look for methods that
131 # take bitmask parameters where one or more of the bits in the
132 # bitmask is always one or always zero
137 # I can't use python's ~ operator, because that produces negative numbers
139 return (1 << 32) - 1 - i
142 for callInfo
, callValues
in callDict
.iteritems():
143 nameAndParams
= callInfo
[1]
144 if len(callValues
) < 2:
146 # we are only interested in enum parameters
147 if not "enum" in callInfo
[3]: continue
148 if not "Flag" in callInfo
[3] and not "flag" in callInfo
[3] and not "Bit" in callInfo
[3] and not "State" in callInfo
[3]: continue
149 # try to ignore setter methods
150 if ("," not in nameAndParams
) and (("::set" in nameAndParams
) or ("::Set" in nameAndParams
)):
155 continue_flag
= False
157 for callValue
in callValues
:
158 if "unknown" == callValue
or not callValue
.isdigit():
162 setBits
= int(callValue
)
163 clearBits
= negate(int(callValue
))
166 setBits
= setBits
& int(callValue
)
167 clearBits
= clearBits
& negate(int(callValue
))
169 # estimate allBits by using the highest bit we have seen
170 # TODO dump more precise information about the allBits values of enums
171 allBits
= (1 << setBits
.bit_length()) - 1
172 clearBits
= clearBits
& allBits
173 if continue_flag
or (setBits
== 0 and clearBits
== 0): continue
175 sourceLoc
= callInfo
[4]
176 functionSig
= callInfo
[0] + " " + callInfo
[1]
178 v2
= callInfo
[3] + " " + callInfo
[2]
179 if setBits
!= 0: v2
+= " setBits=" + hex(setBits
)
180 if clearBits
!= 0: v2
+= " clearBits=" + hex(clearBits
)
181 tmp2list
.append((sourceLoc
, functionSig
, v2
))
184 # sort results by filename:lineno
185 tmp2list
.sort(key
=lambda v
: natural_sort_key(v
[0]))
187 # print out the results
188 with
open("compilerplugins/clang/constantparam.bitmask.results", "wt") as f
:
191 f
.write(" " + v
[1] + "\n")
192 f
.write(" " + v
[2] + "\n")