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", "r") as txt
:
20 tokens
= line
.strip().split("\t")
21 returnType
= normalizeTypeParams(tokens
[0])
22 nameAndParams
= normalizeTypeParams(tokens
[1])
23 sourceLocation
= tokens
[2]
25 paramType
= normalizeTypeParams(tokens
[4])
27 callInfo
= (returnType
, nameAndParams
, paramName
, paramType
, sourceLocation
)
28 if not callInfo
in callDict
:
29 callDict
[callInfo
] = set()
30 callDict
[callInfo
].add(callValue
)
32 except (IndexError,UnicodeDecodeError):
33 print("problem with line " + str(line_no
))
43 constructor_regex
= re
.compile(r
"^\w+\(\)$")
49 for callInfo
, callValues
in iter(callDict
.items()):
50 nameAndParams
= callInfo
[1]
51 if len(callValues
) != 1:
53 callValue
= next(iter(callValues
))
54 if "unknown" in callValue
:
56 sourceLoc
= callInfo
[4]
57 functionSig
= callInfo
[0] + " " + callInfo
[1]
59 # try to ignore setter methods
60 if ("," not in nameAndParams
) and (("::set" in nameAndParams
) or ("::Set" in nameAndParams
)):
62 # ignore code that follows a common pattern
63 if sourceLoc
.startswith("sw/inc/swatrset.hxx"): continue
64 if sourceLoc
.startswith("sw/inc/format.hxx"): continue
65 # template generated code
66 if sourceLoc
.startswith("include/sax/fshelper.hxx"): continue
68 if sourceLoc
.startswith("include/oox/dump"): continue
69 # part of our binary API
70 if sourceLoc
.startswith("include/LibreOfficeKit"): continue
72 # ignore methods generated by SFX macros
73 if "RegisterInterface(class SfxModule *)" in nameAndParams
: continue
74 if "RegisterChildWindow(_Bool,class SfxModule *,enum SfxChildWindowFlags)" in nameAndParams
: continue
75 if "RegisterControl(unsigned short,class SfxModule *)" in nameAndParams
: continue
77 if RepresentsInt(callValue
):
78 if callValue
== "0" or callValue
== "1":
79 tmp1list
.append((sourceLoc
, functionSig
, callInfo
[3] + " " + callInfo
[2], callValue
))
81 tmp2list
.append((sourceLoc
, functionSig
, callInfo
[3] + " " + callInfo
[2], callValue
))
82 # look for places where the callsite is always a constructor invocation
83 elif constructor_regex
.match(callValue
) or callValue
== "\"\"":
84 if callValue
.startswith("Get"): continue
85 if callValue
.startswith("get"): continue
86 if "operator=" in functionSig
: continue
87 if "&&" in functionSig
: continue
88 if callInfo
[2] == "###0" and callValue
== "InitData()": continue
89 if callInfo
[2] == "###0" and callValue
== "InitAggregate()": continue
90 if callValue
== "shared_from_this()": continue
91 tmp3list
.append((sourceLoc
, functionSig
, callInfo
[3] + " " + callInfo
[2], callValue
))
93 tmp4list
.append((sourceLoc
, functionSig
, callInfo
[3] + " " + callInfo
[2], callValue
))
96 # sort results by filename:lineno
97 def natural_sort_key(s
, _nsre
=re
.compile('([0-9]+)')):
98 return [int(text
) if text
.isdigit() else text
.lower()
99 for text
in re
.split(_nsre
, s
)]
100 # sort by both the source-line and the datatype, so the output file ordering is stable
101 # when we have multiple items on the same source line
103 return natural_sort_key(v
[0]) + [v
[1]]
104 tmp1list
.sort(key
=lambda v
: v_sort_key(v
))
105 tmp2list
.sort(key
=lambda v
: v_sort_key(v
))
106 tmp3list
.sort(key
=lambda v
: v_sort_key(v
))
107 tmp4list
.sort(key
=lambda v
: v_sort_key(v
))
109 # print out the results
110 with
open("compilerplugins/clang/constantparam.booleans.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.numbers.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.constructors.results", "wt") as f
:
125 f
.write(" " + v
[1] + "\n")
126 f
.write(" " + v
[2] + "\n")
127 f
.write(" " + v
[3] + "\n")
128 with
open("compilerplugins/clang/constantparam.others.results", "wt") as f
:
131 f
.write(" " + v
[1] + "\n")
132 f
.write(" " + v
[2] + "\n")
133 f
.write(" " + v
[3] + "\n")
135 # -------------------------------------------------------------
136 # Now a fun set of heuristics to look for methods that
137 # take bitmask parameters where one or more of the bits in the
138 # bitmask is always one or always zero
143 # I can't use python's ~ operator, because that produces negative numbers
145 return (1 << 32) - 1 - i
148 for callInfo
, callValues
in iter(callDict
.items()):
149 nameAndParams
= callInfo
[1]
150 if len(callValues
) < 2:
152 # we are only interested in enum parameters
153 if not "enum" in callInfo
[3]: continue
154 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
155 # try to ignore setter methods
156 if ("," not in nameAndParams
) and (("::set" in nameAndParams
) or ("::Set" in nameAndParams
)):
161 continue_flag
= False
163 for callValue
in callValues
:
164 if "unknown" == callValue
or not callValue
.isdigit():
168 setBits
= int(callValue
)
169 clearBits
= negate(int(callValue
))
172 setBits
= setBits
& int(callValue
)
173 clearBits
= clearBits
& negate(int(callValue
))
175 # estimate allBits by using the highest bit we have seen
176 # TODO dump more precise information about the allBits values of enums
177 allBits
= (1 << setBits
.bit_length()) - 1
178 clearBits
= clearBits
& allBits
179 if continue_flag
or (setBits
== 0 and clearBits
== 0): continue
181 sourceLoc
= callInfo
[4]
182 functionSig
= callInfo
[0] + " " + callInfo
[1]
184 v2
= callInfo
[3] + " " + callInfo
[2]
185 if setBits
!= 0: v2
+= " setBits=" + hex(setBits
)
186 if clearBits
!= 0: v2
+= " clearBits=" + hex(clearBits
)
187 tmp2list
.append((sourceLoc
, functionSig
, v2
))
190 # sort results by filename:lineno
191 tmp2list
.sort(key
=lambda v
: v_sort_key(v
))
193 # print out the results
194 with
open("compilerplugins/clang/constantparam.bitmask.results", "wt") as f
:
197 f
.write(" " + v
[1] + "\n")
198 f
.write(" " + v
[2] + "\n")