diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2018-07-19 16:28:37 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2018-07-20 14:12:57 +0200 |
commit | 12dce07aec980562fa449fa1884e0e8379d680fb (patch) | |
tree | 77bfe25b147d33bccd8f3dfc656f533d547ab3ae /compilerplugins/clang/unusedfields.cxx | |
parent | fd0348d42568d5f32fb03e1e13055db5938d5f35 (diff) |
loplugin:unusedfields - look for fields that can be const, in comphelper
idea from tml.
Extend the unusedfields plugin to find fields that are only assigned in
the constructor.
Change-Id: I258d3581afbe651d53ce730c9ba27a4598cd9248
Reviewed-on: https://gerrit.libreoffice.org/57733
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins/clang/unusedfields.cxx')
-rw-r--r-- | compilerplugins/clang/unusedfields.cxx | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/compilerplugins/clang/unusedfields.cxx b/compilerplugins/clang/unusedfields.cxx index 8dca2f549933..94ad63a6f3a3 100644 --- a/compilerplugins/clang/unusedfields.cxx +++ b/compilerplugins/clang/unusedfields.cxx @@ -70,6 +70,7 @@ static std::set<MyFieldInfo> touchedFromOutsideSet; static std::set<MyFieldInfo> touchedFromOutsideConstructorSet; static std::set<MyFieldInfo> readFromSet; static std::set<MyFieldInfo> writeToSet; +static std::set<MyFieldInfo> writeToOutsideConstructorSet; static std::set<MyFieldInfo> definitionSet; /** @@ -159,6 +160,7 @@ public: private: MyFieldInfo niceName(const FieldDecl*); void checkTouchedFromOutside(const FieldDecl* fieldDecl, const Expr* memberExpr); + void checkWriteFromOutsideConstructor(const FieldDecl* fieldDecl, const Expr* memberExpr); void checkWriteOnly(const FieldDecl* fieldDecl, const Expr* memberExpr); void checkReadOnly(const FieldDecl* fieldDecl, const Expr* memberExpr); bool isSomeKindOfZero(const Expr* arg); @@ -193,6 +195,8 @@ void UnusedFields::run() output += "read:\t" + s.parentClass + "\t" + s.fieldName + "\n"; for (const MyFieldInfo & s : writeToSet) output += "write:\t" + s.parentClass + "\t" + s.fieldName + "\n"; + for (const MyFieldInfo & s : writeToOutsideConstructorSet) + output += "write-outside-constructor:\t" + s.parentClass + "\t" + s.fieldName + "\n"; for (const MyFieldInfo & s : definitionSet) output += "definition:\t" + s.access + "\t" + s.parentClass + "\t" + s.fieldName + "\t" + s.fieldType + "\t" + s.sourceLocation + "\n"; std::ofstream myfile; @@ -671,7 +675,11 @@ void UnusedFields::checkReadOnly(const FieldDecl* fieldDecl, const Expr* memberE RecordDecl const * cxxRecordDecl1 = fieldDecl->getParent(); // we don't care about writes to a field when inside the copy/move constructor/operator= for that field if (cxxRecordDecl1 && (cxxRecordDecl1 == insideMoveOrCopyOrCloneDeclParent)) + { + // ... but they matter to tbe can-be-const analysis + checkWriteFromOutsideConstructor(fieldDecl, memberExpr); return; + } } // if we're inside a block that looks like @@ -881,7 +889,10 @@ void UnusedFields::checkReadOnly(const FieldDecl* fieldDecl, const Expr* memberE MyFieldInfo fieldInfo = niceName(fieldDecl); if (bPotentiallyWrittenTo) + { writeToSet.insert(fieldInfo); + checkWriteFromOutsideConstructor(fieldDecl, memberExpr); + } } bool UnusedFields::IsPassedByNonConst(const FieldDecl* fieldDecl, const Stmt * child, CallerWrapper callExpr, @@ -1010,6 +1021,27 @@ void UnusedFields::checkTouchedFromOutside(const FieldDecl* fieldDecl, const Exp } } +// For the const-field analysis. +// Called when we have a write to a field, and we want to record that write only if it's writing from +// outside the constructor. +void UnusedFields::checkWriteFromOutsideConstructor(const FieldDecl* fieldDecl, const Expr* memberExpr) { + const FunctionDecl* memberExprParentFunction = getParentFunctionDecl(memberExpr); + bool doWrite = false; + + if (!memberExprParentFunction) + // If we are not inside a function + doWrite = true; + else if (memberExprParentFunction->getParent() != fieldDecl->getParent()) + // or we are inside a method from another class (than the one the field belongs to) + doWrite = true; + else if (!isa<CXXConstructorDecl>(memberExprParentFunction)) + // or we are not inside constructor + doWrite = true; + + if (doWrite) + writeToOutsideConstructorSet.insert(niceName(fieldDecl)); +} + llvm::Optional<CalleeWrapper> UnusedFields::getCallee(CallExpr const * callExpr) { FunctionDecl const * functionDecl = callExpr->getDirectCallee(); |