summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2017-03-24 08:31:25 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2017-03-24 08:57:01 +0000
commitf0593478571009139cd12bac11a9b38e51c42f96 (patch)
tree7901d4c671ac3a8d8622cccabbffbbdf91f5cc6a /compilerplugins
parentad5bf6b72c89caf0ed7110e4a84e2d6bf1807a24 (diff)
loplugin:unusedfields
improve the plugin to find fields which are only assigned to in the constructor Change-Id: I95b5be238ebba83d950ca15093abdd1849740359 Reviewed-on: https://gerrit.libreoffice.org/35613 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins')
-rw-r--r--compilerplugins/clang/unusedfields.cxx30
-rwxr-xr-xcompilerplugins/clang/unusedfields.py20
2 files changed, 29 insertions, 21 deletions
diff --git a/compilerplugins/clang/unusedfields.cxx b/compilerplugins/clang/unusedfields.cxx
index 94a1cb6300d9..04c51195eaf3 100644
--- a/compilerplugins/clang/unusedfields.cxx
+++ b/compilerplugins/clang/unusedfields.cxx
@@ -57,7 +57,8 @@ bool operator < (const MyFieldInfo &lhs, const MyFieldInfo &rhs)
// try to limit the voluminous output a little
-static std::set<MyFieldInfo> touchedSet;
+static std::set<MyFieldInfo> touchedFromInsideSet;
+static std::set<MyFieldInfo> touchedFromConstructorSet;
static std::set<MyFieldInfo> touchedFromOutsideSet;
static std::set<MyFieldInfo> readFromSet;
static std::set<MyFieldInfo> definitionSet;
@@ -76,8 +77,10 @@ public:
// dump all our output in one write call - this is to try and limit IO "crosstalk" between multiple processes
// writing to the same logfile
std::string output;
- for (const MyFieldInfo & s : touchedSet)
- output += "touch:\t" + s.parentClass + "\t" + s.fieldName + "\n";
+ for (const MyFieldInfo & s : touchedFromInsideSet)
+ output += "inside:\t" + s.parentClass + "\t" + s.fieldName + "\n";
+ for (const MyFieldInfo & s : touchedFromConstructorSet)
+ output += "constructor:\t" + s.parentClass + "\t" + s.fieldName + "\n";
for (const MyFieldInfo & s : touchedFromOutsideSet)
output += "outside:\t" + s.parentClass + "\t" + s.fieldName + "\n";
for (const MyFieldInfo & s : readFromSet)
@@ -100,7 +103,7 @@ public:
bool VisitDeclRefExpr( const DeclRefExpr* );
private:
MyFieldInfo niceName(const FieldDecl*);
- void checkForTouchedFromOutside(const FieldDecl* fieldDecl, const Expr* memberExpr, const MyFieldInfo& fieldInfo);
+ void checkTouched(const FieldDecl* fieldDecl, const Expr* memberExpr);
};
MyFieldInfo UnusedFields::niceName(const FieldDecl* fieldDecl)
@@ -193,7 +196,7 @@ bool UnusedFields::VisitMemberExpr( const MemberExpr* memberExpr )
// for the touched-from-outside analysis
- checkForTouchedFromOutside(fieldDecl, memberExpr, fieldInfo);
+ checkTouched(fieldDecl, memberExpr);
// for the write-only analysis
@@ -281,19 +284,18 @@ bool UnusedFields::VisitDeclRefExpr( const DeclRefExpr* declRefExpr )
if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc(fieldDecl->getLocation()))) {
return true;
}
- MyFieldInfo fieldInfo = niceName(fieldDecl);
- touchedSet.insert(fieldInfo);
- checkForTouchedFromOutside(fieldDecl, declRefExpr, fieldInfo);
+ checkTouched(fieldDecl, declRefExpr);
return true;
}
-void UnusedFields::checkForTouchedFromOutside(const FieldDecl* fieldDecl, const Expr* memberExpr, const MyFieldInfo& fieldInfo) {
+void UnusedFields::checkTouched(const FieldDecl* fieldDecl, const Expr* memberExpr) {
const FunctionDecl* memberExprParentFunction = parentFunctionDecl(memberExpr);
const CXXMethodDecl* methodDecl = dyn_cast_or_null<CXXMethodDecl>(memberExprParentFunction);
+ MyFieldInfo fieldInfo = niceName(fieldDecl);
+
// it's touched from somewhere outside a class
if (!methodDecl) {
- touchedSet.insert(fieldInfo);
touchedFromOutsideSet.insert(fieldInfo);
return;
}
@@ -303,9 +305,13 @@ void UnusedFields::checkForTouchedFromOutside(const FieldDecl* fieldDecl, const
// ignore move/copy operator, it's self->self
} else if (constructorDecl && (constructorDecl->isCopyConstructor() || constructorDecl->isMoveConstructor())) {
// ignore move/copy constructor, it's self->self
+ } else if (constructorDecl && memberExprParentFunction->getParent() == fieldDecl->getParent()) {
+ // if the field is touched from inside it's parent class constructor
+ touchedFromConstructorSet.insert(fieldInfo);
} else {
- touchedSet.insert(fieldInfo);
- if (memberExprParentFunction->getParent() != fieldDecl->getParent()) {
+ if (memberExprParentFunction->getParent() == fieldDecl->getParent()) {
+ touchedFromInsideSet.insert(fieldInfo);
+ } else {
touchedFromOutsideSet.insert(fieldInfo);
}
}
diff --git a/compilerplugins/clang/unusedfields.py b/compilerplugins/clang/unusedfields.py
index 7bf910f62d80..77e6446e18e3 100755
--- a/compilerplugins/clang/unusedfields.py
+++ b/compilerplugins/clang/unusedfields.py
@@ -8,7 +8,8 @@ definitionSet = set()
protectedAndPublicDefinitionSet = set() # set of tuple(type, name)
definitionToSourceLocationMap = dict()
definitionToTypeMap = dict()
-callSet = set()
+touchedFromInsideSet = set()
+touchedFromConstructorSet = set()
readFromSet = set()
sourceLocationSet = set()
touchedFromOutsideSet = set()
@@ -45,20 +46,20 @@ with io.open("loplugin.unusedfields.log", "rb", buffering=1024*1024) as txt:
if access == "protected" or access == "public":
protectedAndPublicDefinitionSet.add(fieldInfo)
definitionToSourceLocationMap[fieldInfo] = tokens[5]
- elif tokens[0] == "touch:":
- callSet.add(parseFieldInfo(tokens))
- elif tokens[0] == "read:":
- readFromSet.add(parseFieldInfo(tokens))
- elif tokens[0] == "read:":
- readFromSet.add(parseFieldInfo(tokens))
+ elif tokens[0] == "inside:":
+ touchedFromInsideSet.add(parseFieldInfo(tokens))
+ elif tokens[0] == "constructor:":
+ touchedFromConstructorSet.add(parseFieldInfo(tokens))
elif tokens[0] == "outside:":
touchedFromOutsideSet.add(parseFieldInfo(tokens))
+ elif tokens[0] == "read:":
+ readFromSet.add(parseFieldInfo(tokens))
else:
print( "unknown line: " + line)
# Invert the definitionToSourceLocationMap
# If we see more than one method at the same sourceLocation, it's being autogenerated as part of a template
-# and we should just ignore
+# and we should just ignore it
sourceLocationToDefinitionMap = {}
for k, v in definitionToSourceLocationMap.iteritems():
sourceLocationToDefinitionMap[v] = sourceLocationToDefinitionMap.get(v, [])
@@ -68,9 +69,10 @@ for k, definitions in sourceLocationToDefinitionMap.iteritems():
for d in definitions:
definitionSet.remove(d)
+# Calculate untouched or untouched-except-for-in-constructor
untouchedSet = set()
for d in definitionSet:
- if d in callSet:
+ if d in touchedFromOutsideSet or d in touchedFromInsideSet:
continue
srcLoc = definitionToSourceLocationMap[d];
# this is all representations of on-disk data structures