Kaydet (Commit) d43e694d authored tarafından Noel Grandin's avatar Noel Grandin

some global loplugin improvements

for some reason we're hitting more template AST nodes now? Anyhow,
updated singlevalfields and unusedenumconstants to cope.

For unusedfields, ignore field access inside Clone() methods, since it's
like a constructor.
Similarly for unusedmethods.

Change-Id: Icb2f76fb2f06ae5df21f9d75312e42a2800befb9
Reviewed-on: https://gerrit.libreoffice.org/45470Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarNoel Grandin <noel.grandin@collabora.co.uk>
üst afbc75c2
...@@ -256,7 +256,7 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr ) ...@@ -256,7 +256,7 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr )
const Stmt* parent = getParentStmt(memberExpr); const Stmt* parent = getParentStmt(memberExpr);
bool bPotentiallyAssignedTo = false; bool bPotentiallyAssignedTo = false;
bool bDump = false; bool bDump = false;
std::string assignValue; std::string assignValue = "?";
// check for field being returned by non-const ref eg. Foo& getFoo() { return f; } // check for field being returned by non-const ref eg. Foo& getFoo() { return f; }
if (parentFunction && parent && isa<ReturnStmt>(parent)) { if (parentFunction && parent && isa<ReturnStmt>(parent)) {
...@@ -264,7 +264,6 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr ) ...@@ -264,7 +264,6 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr )
if (parent2 && isa<CompoundStmt>(parent2)) { if (parent2 && isa<CompoundStmt>(parent2)) {
QualType qt = compat::getReturnType(*parentFunction).getDesugaredType(compiler.getASTContext()); QualType qt = compat::getReturnType(*parentFunction).getDesugaredType(compiler.getASTContext());
if (!qt.isConstQualified() && qt->isReferenceType()) { if (!qt.isConstQualified() && qt->isReferenceType()) {
assignValue = "?";
bPotentiallyAssignedTo = true; bPotentiallyAssignedTo = true;
} }
} }
...@@ -279,7 +278,6 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr ) ...@@ -279,7 +278,6 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr )
if (varDecl) { if (varDecl) {
QualType qt = varDecl->getType().getDesugaredType(compiler.getASTContext()); QualType qt = varDecl->getType().getDesugaredType(compiler.getASTContext());
if (!qt.isConstQualified() && qt->isReferenceType()) { if (!qt.isConstQualified() && qt->isReferenceType()) {
assignValue = "?";
bPotentiallyAssignedTo = true; bPotentiallyAssignedTo = true;
break; break;
} }
...@@ -310,7 +308,6 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr ) ...@@ -310,7 +308,6 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr )
else if (isa<CXXOperatorCallExpr>(parent)) else if (isa<CXXOperatorCallExpr>(parent))
{ {
// FIXME need to handle this properly // FIXME need to handle this properly
assignValue = "?";
bPotentiallyAssignedTo = true; bPotentiallyAssignedTo = true;
break; break;
} }
...@@ -330,7 +327,6 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr ) ...@@ -330,7 +327,6 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr )
const ParmVarDecl* parmVarDecl = consDecl->getParamDecl(i); const ParmVarDecl* parmVarDecl = consDecl->getParamDecl(i);
QualType qt = parmVarDecl->getType().getDesugaredType(compiler.getASTContext()); QualType qt = parmVarDecl->getType().getDesugaredType(compiler.getASTContext());
if (!qt.isConstQualified() && qt->isReferenceType()) { if (!qt.isConstQualified() && qt->isReferenceType()) {
assignValue = "?";
bPotentiallyAssignedTo = true; bPotentiallyAssignedTo = true;
} }
break; break;
...@@ -348,7 +344,6 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr ) ...@@ -348,7 +344,6 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr )
assignValue = getExprValue(binaryOp->getRHS()); assignValue = getExprValue(binaryOp->getRHS());
bPotentiallyAssignedTo = true; bPotentiallyAssignedTo = true;
} else { } else {
assignValue = "?";
bPotentiallyAssignedTo = true; bPotentiallyAssignedTo = true;
} }
break; break;
...@@ -375,6 +370,13 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr ) ...@@ -375,6 +370,13 @@ bool SingleValFields::VisitMemberExpr( const MemberExpr* memberExpr )
{ {
break; break;
} }
#if CLANG_VERSION >= 40000
else if ( isa<ArrayInitLoopExpr>(parent) )
{
bPotentiallyAssignedTo = true;
break;
}
#endif
else { else {
bPotentiallyAssignedTo = true; bPotentiallyAssignedTo = true;
bDump = true; bDump = true;
......
...@@ -184,6 +184,22 @@ try_again: ...@@ -184,6 +184,22 @@ try_again:
|| isa<ExprWithCleanups>(parent)) || isa<ExprWithCleanups>(parent))
{ {
goto try_again; goto try_again;
} else if (isa<CXXDefaultArgExpr>(parent))
{
// TODO this could be improved
bWrite = true;
} else if (isa<DeclRefExpr>(parent))
{
// slightly weird case I saw in basegfx where the enum is being used as a template param
bWrite = true;
} else if (isa<MemberExpr>(parent))
{
// slightly weird case I saw in sc where the enum is being used as a template param
bWrite = true;
} else if (isa<UnresolvedLookupExpr>(parent))
{
bRead = true;
bWrite = true;
} else { } else {
bDump = true; bDump = true;
} }
...@@ -191,6 +207,7 @@ try_again: ...@@ -191,6 +207,7 @@ try_again:
// to let me know if I missed something // to let me know if I missed something
if (bDump) { if (bDump) {
parent->dump(); parent->dump();
declRefExpr->dump();
report( DiagnosticsEngine::Warning, report( DiagnosticsEngine::Warning,
"unhandled clang AST node type", "unhandled clang AST node type",
parent->getLocStart()); parent->getLocStart());
......
...@@ -159,7 +159,7 @@ private: ...@@ -159,7 +159,7 @@ private:
CalleeWrapper calleeFunctionDecl); CalleeWrapper calleeFunctionDecl);
llvm::Optional<CalleeWrapper> getCallee(CallExpr const *); llvm::Optional<CalleeWrapper> getCallee(CallExpr const *);
RecordDecl * insideMoveOrCopyDeclParent = nullptr; RecordDecl * insideMoveOrCopyOrCloneDeclParent = nullptr;
RecordDecl * insideStreamOutputOperator = nullptr; RecordDecl * insideStreamOutputOperator = nullptr;
// For reasons I do not understand, parentFunctionDecl() is not reliable, so // For reasons I do not understand, parentFunctionDecl() is not reliable, so
// we store the parent function on the way down the AST. // we store the parent function on the way down the AST.
...@@ -361,29 +361,31 @@ bool startswith(const std::string& rStr, const char* pSubStr) ...@@ -361,29 +361,31 @@ bool startswith(const std::string& rStr, const char* pSubStr)
bool UnusedFields::TraverseCXXConstructorDecl(CXXConstructorDecl* cxxConstructorDecl) bool UnusedFields::TraverseCXXConstructorDecl(CXXConstructorDecl* cxxConstructorDecl)
{ {
auto copy = insideMoveOrCopyDeclParent; auto copy = insideMoveOrCopyOrCloneDeclParent;
if (!ignoreLocation(cxxConstructorDecl) && cxxConstructorDecl->isThisDeclarationADefinition()) if (!ignoreLocation(cxxConstructorDecl) && cxxConstructorDecl->isThisDeclarationADefinition())
{ {
if (cxxConstructorDecl->isCopyOrMoveConstructor()) if (cxxConstructorDecl->isCopyOrMoveConstructor())
insideMoveOrCopyDeclParent = cxxConstructorDecl->getParent(); insideMoveOrCopyOrCloneDeclParent = cxxConstructorDecl->getParent();
} }
bool ret = RecursiveASTVisitor::TraverseCXXConstructorDecl(cxxConstructorDecl); bool ret = RecursiveASTVisitor::TraverseCXXConstructorDecl(cxxConstructorDecl);
insideMoveOrCopyDeclParent = copy; insideMoveOrCopyOrCloneDeclParent = copy;
return ret; return ret;
} }
bool UnusedFields::TraverseCXXMethodDecl(CXXMethodDecl* cxxMethodDecl) bool UnusedFields::TraverseCXXMethodDecl(CXXMethodDecl* cxxMethodDecl)
{ {
auto copy1 = insideMoveOrCopyDeclParent; auto copy1 = insideMoveOrCopyOrCloneDeclParent;
auto copy2 = insideFunctionDecl; auto copy2 = insideFunctionDecl;
if (!ignoreLocation(cxxMethodDecl) && cxxMethodDecl->isThisDeclarationADefinition()) if (!ignoreLocation(cxxMethodDecl) && cxxMethodDecl->isThisDeclarationADefinition())
{ {
if (cxxMethodDecl->isCopyAssignmentOperator() || cxxMethodDecl->isMoveAssignmentOperator()) if (cxxMethodDecl->isCopyAssignmentOperator()
insideMoveOrCopyDeclParent = cxxMethodDecl->getParent(); || cxxMethodDecl->isMoveAssignmentOperator()
|| (cxxMethodDecl->getIdentifier() && cxxMethodDecl->getName() == "Clone"))
insideMoveOrCopyOrCloneDeclParent = cxxMethodDecl->getParent();
} }
insideFunctionDecl = cxxMethodDecl; insideFunctionDecl = cxxMethodDecl;
bool ret = RecursiveASTVisitor::TraverseCXXMethodDecl(cxxMethodDecl); bool ret = RecursiveASTVisitor::TraverseCXXMethodDecl(cxxMethodDecl);
insideMoveOrCopyDeclParent = copy1; insideMoveOrCopyOrCloneDeclParent = copy1;
insideFunctionDecl = copy2; insideFunctionDecl = copy2;
return ret; return ret;
} }
...@@ -435,11 +437,11 @@ bool UnusedFields::VisitMemberExpr( const MemberExpr* memberExpr ) ...@@ -435,11 +437,11 @@ bool UnusedFields::VisitMemberExpr( const MemberExpr* memberExpr )
void UnusedFields::checkWriteOnly(const FieldDecl* fieldDecl, const Expr* memberExpr) void UnusedFields::checkWriteOnly(const FieldDecl* fieldDecl, const Expr* memberExpr)
{ {
if (insideMoveOrCopyDeclParent || insideStreamOutputOperator) if (insideMoveOrCopyOrCloneDeclParent || insideStreamOutputOperator)
{ {
RecordDecl const * cxxRecordDecl1 = fieldDecl->getParent(); RecordDecl const * cxxRecordDecl1 = fieldDecl->getParent();
// we don't care about reads from a field when inside the copy/move constructor/operator= for that field // we don't care about reads from a field when inside the copy/move constructor/operator= for that field
if (cxxRecordDecl1 && (cxxRecordDecl1 == insideMoveOrCopyDeclParent)) if (cxxRecordDecl1 && (cxxRecordDecl1 == insideMoveOrCopyOrCloneDeclParent))
return; return;
// we don't care about reads when the field is being used in an output operator, this is normally // we don't care about reads when the field is being used in an output operator, this is normally
// debug stuff // debug stuff
...@@ -629,11 +631,11 @@ void UnusedFields::checkWriteOnly(const FieldDecl* fieldDecl, const Expr* member ...@@ -629,11 +631,11 @@ void UnusedFields::checkWriteOnly(const FieldDecl* fieldDecl, const Expr* member
void UnusedFields::checkReadOnly(const FieldDecl* fieldDecl, const Expr* memberExpr) void UnusedFields::checkReadOnly(const FieldDecl* fieldDecl, const Expr* memberExpr)
{ {
if (insideMoveOrCopyDeclParent) if (insideMoveOrCopyOrCloneDeclParent)
{ {
RecordDecl const * cxxRecordDecl1 = fieldDecl->getParent(); RecordDecl const * cxxRecordDecl1 = fieldDecl->getParent();
// we don't care about writes to a field when inside the copy/move constructor/operator= for that field // we don't care about writes to a field when inside the copy/move constructor/operator= for that field
if (cxxRecordDecl1 && (cxxRecordDecl1 == insideMoveOrCopyDeclParent)) if (cxxRecordDecl1 && (cxxRecordDecl1 == insideMoveOrCopyOrCloneDeclParent))
return; return;
} }
...@@ -878,7 +880,7 @@ bool UnusedFields::VisitCXXConstructorDecl( const CXXConstructorDecl* cxxConstru ...@@ -878,7 +880,7 @@ bool UnusedFields::VisitCXXConstructorDecl( const CXXConstructorDecl* cxxConstru
return true; return true;
// we don't care about writes to a field when inside the copy/move constructor/operator= for that field // we don't care about writes to a field when inside the copy/move constructor/operator= for that field
if (insideMoveOrCopyDeclParent && cxxConstructorDecl->getParent() == insideMoveOrCopyDeclParent) if (insideMoveOrCopyOrCloneDeclParent && cxxConstructorDecl->getParent() == insideMoveOrCopyOrCloneDeclParent)
return true; return true;
for(auto it = cxxConstructorDecl->init_begin(); it != cxxConstructorDecl->init_end(); ++it) for(auto it = cxxConstructorDecl->init_begin(); it != cxxConstructorDecl->init_end(); ++it)
...@@ -975,33 +977,7 @@ llvm::Optional<CalleeWrapper> UnusedFields::getCallee(CallExpr const * callExpr) ...@@ -975,33 +977,7 @@ llvm::Optional<CalleeWrapper> UnusedFields::getCallee(CallExpr const * callExpr)
} }
} }
llvm::Optional<CalleeWrapper> ret; return llvm::Optional<CalleeWrapper>();
auto callee = callExpr->getCallee()->IgnoreParenImpCasts();
if (isa<CXXDependentScopeMemberExpr>(callee)) // template stuff
return ret;
if (isa<UnresolvedLookupExpr>(callee)) // template stuff
return ret;
if (isa<UnresolvedMemberExpr>(callee)) // template stuff
return ret;
calleeType = calleeType->getUnqualifiedDesugaredType();
if (isa<TemplateSpecializationType>(calleeType)) // template stuff
return ret;
if (auto builtinType = dyn_cast<BuiltinType>(calleeType)) {
if (builtinType->getKind() == BuiltinType::Kind::Dependent) // template stuff
return ret;
if (builtinType->getKind() == BuiltinType::Kind::BoundMember) // template stuff
return ret;
}
if (isa<TemplateTypeParmType>(calleeType)) // template stuff
return ret;
callExpr->dump();
callExpr->getCallee()->getType()->dump();
report(
DiagnosticsEngine::Warning, "can't get callee",
callExpr->getExprLoc())
<< callExpr->getSourceRange();
return ret;
} }
loplugin::Plugin::Registration< UnusedFields > X("unusedfields", false); loplugin::Plugin::Registration< UnusedFields > X("unusedfields", false);
......
...@@ -235,8 +235,16 @@ bool UnusedMethods::VisitCallExpr(CallExpr* expr) ...@@ -235,8 +235,16 @@ bool UnusedMethods::VisitCallExpr(CallExpr* expr)
gotfunc: gotfunc:
// for "unused method" analysis, ignore recursive calls
if (currentFunctionDecl != calleeFunctionDecl) if (currentFunctionDecl == calleeFunctionDecl)
; // for "unused method" analysis, ignore recursive calls
else if (currentFunctionDecl
&& currentFunctionDecl->getIdentifier()
&& currentFunctionDecl->getName() == "Clone"
&& currentFunctionDecl->getParent() == calleeFunctionDecl->getParent()
&& isa<CXXConstructorDecl>(calleeFunctionDecl))
; // if we are inside Clone(), ignore calls to the same class's constructor
else
logCallToRootMethods(calleeFunctionDecl, callSet); logCallToRootMethods(calleeFunctionDecl, callSet);
const Stmt* parent = getParentStmt(expr); const Stmt* parent = getParentStmt(expr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment