summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2017-05-05 13:03:43 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2017-05-08 08:29:03 +0200
commit185ed3ddb8c01ee4465ce559e37113824f57b5c7 (patch)
tree596455ca4b9dc85666efbf06a1e1e0a3eec3ee2d /compilerplugins
parentd33e262a244f351febc9dbe605b05f76cb834eeb (diff)
teach loplugin:constantparam about simple constructor calls
Change-Id: I7d2a28ab5951fbdb5a427c84e9ac4c1e32ecf9f9 Reviewed-on: https://gerrit.libreoffice.org/37280 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins')
-rw-r--r--compilerplugins/clang/constantparam.cxx22
-rwxr-xr-xcompilerplugins/clang/constantparam.py69
2 files changed, 76 insertions, 15 deletions
diff --git a/compilerplugins/clang/constantparam.cxx b/compilerplugins/clang/constantparam.cxx
index d748919b0c7d..3f22324c60c2 100644
--- a/compilerplugins/clang/constantparam.cxx
+++ b/compilerplugins/clang/constantparam.cxx
@@ -24,6 +24,9 @@
$ ./compilerplugins/clang/constantparam.py
TODO look for OUString and OString params and check for call-params that are always either "" or default constructed
+
+ FIXME this plugin manages to trigger crashes inside clang, when calling EvaluateAsInt, so I end up disabling it for a handful of files
+ here and there.
*/
namespace {
@@ -172,7 +175,24 @@ std::string ConstantParam::getCallValue(const Expr* arg)
return "defaultConstruct";
}
}
- return "unknown2";
+
+ // Get the expression contents.
+ // This helps us find params which are always initialised with something like "OUString()".
+ SourceManager& SM = compiler.getSourceManager();
+ SourceLocation startLoc = arg->getLocStart();
+ SourceLocation endLoc = arg->getLocEnd();
+ const char *p1 = SM.getCharacterData( startLoc );
+ const char *p2 = SM.getCharacterData( endLoc );
+ if (!p1 || !p2 || (p2 - p1) < 0 || (p2 - p1) > 40) {
+ return "unknown";
+ }
+ unsigned n = Lexer::MeasureTokenLength( endLoc, SM, compiler.getLangOpts());
+ std::string s( p1, p2 - p1 + n);
+ // strip linefeed and tab characters so they don't interfere with the parsing of the log file
+ std::replace( s.begin(), s.end(), '\r', ' ');
+ std::replace( s.begin(), s.end(), '\n', ' ');
+ std::replace( s.begin(), s.end(), '\t', ' ');
+ return s;
}
bool ConstantParam::VisitCallExpr(const CallExpr * callExpr) {
diff --git a/compilerplugins/clang/constantparam.py b/compilerplugins/clang/constantparam.py
index 2dede4f1ad8d..fd299d85405b 100755
--- a/compilerplugins/clang/constantparam.py
+++ b/compilerplugins/clang/constantparam.py
@@ -15,19 +15,34 @@ def normalizeTypeParams( line ):
# reading as binary (since we known it is pure ascii) is much faster than reading as unicode
with io.open("loplugin.constantparam.log", "rb", buffering=1024*1024) as txt:
for line in txt:
- tokens = line.strip().split("\t")
- returnType = normalizeTypeParams(tokens[0])
- nameAndParams = normalizeTypeParams(tokens[1])
- sourceLocation = tokens[2]
- paramName = tokens[3]
- paramType = normalizeTypeParams(tokens[4])
- callValue = tokens[5]
- callInfo = (returnType, nameAndParams, paramName, paramType, sourceLocation)
- if not callInfo in callDict:
- callDict[callInfo] = set()
- callDict[callInfo].add(callValue)
+ try:
+ tokens = line.strip().split("\t")
+ returnType = normalizeTypeParams(tokens[0])
+ nameAndParams = normalizeTypeParams(tokens[1])
+ sourceLocation = tokens[2]
+ paramName = tokens[3]
+ paramType = normalizeTypeParams(tokens[4])
+ callValue = tokens[5]
+ callInfo = (returnType, nameAndParams, paramName, paramType, sourceLocation)
+ if not callInfo in callDict:
+ callDict[callInfo] = set()
+ callDict[callInfo].add(callValue)
+ except IndexError:
+ print "problem with line " + line.strip()
+ raise
+
+def RepresentsInt(s):
+ try:
+ int(s)
+ return True
+ except ValueError:
+ return False
+
+consRegex = re.compile("^\w+\(\)$")
tmp1list = list()
+tmp2list = list()
+tmp3list = list()
for callInfo, callValues in callDict.iteritems():
nameAndParams = callInfo[1]
if len(callValues) != 1:
@@ -51,21 +66,47 @@ for callInfo, callValues in callDict.iteritems():
# part of our binary API
if sourceLoc.startswith("include/LibreOfficeKit"): continue
- v2 = callInfo[3] + " " + callInfo[2] + " " + callValue
- tmp1list.append((sourceLoc, functionSig, v2))
+ if RepresentsInt(callValue):
+ if callValue == "0" or callValue == "1":
+ tmp1list.append((sourceLoc, functionSig, callInfo[3] + " " + callInfo[2], callValue))
+ else:
+ tmp2list.append((sourceLoc, functionSig, callInfo[3] + " " + callInfo[2], callValue))
+ # look for places where the callsite is always a constructor invocation
+ elif consRegex.match(callValue):
+ if callValue.startswith("Get"): continue
+ if callValue.startswith("get"): continue
+ if "operator=" in functionSig: continue
+ if "&&" in functionSig: continue
+ tmp3list.append((sourceLoc, functionSig, callInfo[3] + " " + callInfo[2], callValue))
+
# sort results by filename:lineno
def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
return [int(text) if text.isdigit() else text.lower()
for text in re.split(_nsre, s)]
tmp1list.sort(key=lambda v: natural_sort_key(v[0]))
+tmp2list.sort(key=lambda v: natural_sort_key(v[0]))
+tmp3list.sort(key=lambda v: natural_sort_key(v[0]))
# print out the results
-with open("loplugin.constantparam.report", "wt") as f:
+with open("loplugin.constantparam.report-booleans", "wt") as f:
for v in tmp1list:
f.write(v[0] + "\n")
f.write(" " + v[1] + "\n")
f.write(" " + v[2] + "\n")
+ f.write(" " + v[3] + "\n")
+with open("loplugin.constantparam.report-numbers", "wt") as f:
+ for v in tmp2list:
+ f.write(v[0] + "\n")
+ f.write(" " + v[1] + "\n")
+ f.write(" " + v[2] + "\n")
+ f.write(" " + v[3] + "\n")
+with open("loplugin.constantparam.report-constructors", "wt") as f:
+ for v in tmp3list:
+ f.write(v[0] + "\n")
+ f.write(" " + v[1] + "\n")
+ f.write(" " + v[2] + "\n")
+ f.write(" " + v[3] + "\n")
# -------------------------------------------------------------
# Now a fun set of heuristics to look for methods that