diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2017-09-29 09:05:54 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2017-09-29 09:10:36 +0200 |
commit | 26c82bd286e2331188db853d41f7a575d906b62c (patch) | |
tree | d135a914bae66d40fb66161b84d90df7865f00fa | |
parent | 2149bbfd2798cb5ed065ea25387616261a840634 (diff) |
loplugin:unusedfields improve finding callee
which makes absolutely no difference to the results, but anyhow, would
be a shame to waste the work
Change-Id: I4576528f30986a5ce522c76fdf21873f0ce23f0a
-rw-r--r-- | compilerplugins/clang/unusedfields.cxx | 122 |
1 files changed, 100 insertions, 22 deletions
diff --git a/compilerplugins/clang/unusedfields.cxx b/compilerplugins/clang/unusedfields.cxx index af2be7ba6076..cb17d8526560 100644 --- a/compilerplugins/clang/unusedfields.cxx +++ b/compilerplugins/clang/unusedfields.cxx @@ -83,15 +83,49 @@ public: }; class CalleeWrapper { - const FunctionDecl * m_calleeFunctionDecl; - const CXXConstructorDecl * m_cxxConstructorDecl; + const FunctionDecl * m_calleeFunctionDecl = nullptr; + const CXXConstructorDecl * m_cxxConstructorDecl = nullptr; + const FunctionProtoType * m_functionPrototype = nullptr; public: - CalleeWrapper(const FunctionDecl * calleeFunctionDecl) : m_calleeFunctionDecl(calleeFunctionDecl), m_cxxConstructorDecl(nullptr) {} - CalleeWrapper(const CXXConstructExpr * cxxConstructExpr) : m_calleeFunctionDecl(nullptr), m_cxxConstructorDecl(cxxConstructExpr->getConstructor()) {} - unsigned getNumParams () const - { return m_calleeFunctionDecl ? m_calleeFunctionDecl->getNumParams() : m_cxxConstructorDecl->getNumParams(); } - const ParmVarDecl * getParamDecl (unsigned i) const - { return m_calleeFunctionDecl ? m_calleeFunctionDecl->getParamDecl(i) : m_cxxConstructorDecl->getParamDecl(i); } + explicit CalleeWrapper(const FunctionDecl * calleeFunctionDecl) : m_calleeFunctionDecl(calleeFunctionDecl) {} + explicit CalleeWrapper(const CXXConstructExpr * cxxConstructExpr) : m_cxxConstructorDecl(cxxConstructExpr->getConstructor()) {} + explicit CalleeWrapper(const FunctionProtoType * functionPrototype) : m_functionPrototype(functionPrototype) {} + unsigned getNumParams() const + { + if (m_calleeFunctionDecl) + return m_calleeFunctionDecl->getNumParams(); + else if (m_cxxConstructorDecl) + return m_cxxConstructorDecl->getNumParams(); + else if (m_functionPrototype->param_type_begin() == m_functionPrototype->param_type_end()) + // FunctionProtoType will assert if we call getParamTypes() and it has no params + return 0; + else + return m_functionPrototype->getParamTypes().size(); + } + const QualType getParamType(unsigned i) const + { + if (m_calleeFunctionDecl) + return m_calleeFunctionDecl->getParamDecl(i)->getType(); + else if (m_cxxConstructorDecl) + return m_cxxConstructorDecl->getParamDecl(i)->getType(); + else + return m_functionPrototype->getParamTypes()[i]; + } + std::string getNameAsString() const + { + if (m_calleeFunctionDecl) + return m_calleeFunctionDecl->getNameAsString(); + else if (m_cxxConstructorDecl) + return m_cxxConstructorDecl->getNameAsString(); + else + return ""; + } + CXXMethodDecl const * getAsCXXMethodDecl() const + { + if (m_calleeFunctionDecl) + return dyn_cast<CXXMethodDecl>(m_calleeFunctionDecl); + return nullptr; + } }; class UnusedFields: @@ -122,6 +156,7 @@ private: bool isSomeKindOfZero(const Expr* arg); bool IsPassedByNonConst(const FieldDecl* fieldDecl, const Stmt * child, CallerWrapper callExpr, CalleeWrapper calleeFunctionDecl); + llvm::Optional<CalleeWrapper> getCallee(CallExpr const *); RecordDecl * insideMoveOrCopyDeclParent; RecordDecl * insideStreamOutputOperator; @@ -492,12 +527,12 @@ void UnusedFields::checkWriteOnly(const FieldDecl* fieldDecl, const Expr* member else if (auto callExpr = dyn_cast<CallExpr>(parent)) { // check for calls to ReadXXX() type methods and the operator>>= methods on Any. - const FunctionDecl * calleeFunctionDecl = callExpr->getDirectCallee(); - if (calleeFunctionDecl) + auto callee = getCallee(callExpr); + if (callee) { // FIXME perhaps a better solution here would be some kind of SAL_PARAM_WRITEONLY attribute // which we could scatter around. - std::string name = calleeFunctionDecl->getNameAsString(); + std::string name = callee->getNameAsString(); std::transform(name.begin(), name.end(), name.begin(), easytolower); if (startswith(name, "read")) // this is a write-only call @@ -657,17 +692,17 @@ void UnusedFields::checkReadOnly(const FieldDecl* fieldDecl, const Expr* memberE } else if (auto operatorCallExpr = dyn_cast<CXXOperatorCallExpr>(parent)) { - const FunctionDecl * calleeFunctionDecl = operatorCallExpr->getDirectCallee(); - if (calleeFunctionDecl) + auto callee = getCallee(operatorCallExpr); + if (callee) { // if calling a non-const operator on the field - auto calleeMethodDecl = dyn_cast<CXXMethodDecl>(calleeFunctionDecl); + auto calleeMethodDecl = callee->getAsCXXMethodDecl(); if (calleeMethodDecl && operatorCallExpr->getArg(0) == child && !calleeMethodDecl->isConst()) { bPotentiallyWrittenTo = true; } - else if (IsPassedByNonConst(fieldDecl, child, operatorCallExpr, calleeFunctionDecl)) + else if (IsPassedByNonConst(fieldDecl, child, operatorCallExpr, *callee)) { bPotentiallyWrittenTo = true; } @@ -692,7 +727,7 @@ void UnusedFields::checkReadOnly(const FieldDecl* fieldDecl, const Expr* memberE bPotentiallyWrittenTo = true; break; } - if (IsPassedByNonConst(fieldDecl, child, cxxMemberCallExpr, calleeMethodDecl)) + if (IsPassedByNonConst(fieldDecl, child, cxxMemberCallExpr, CalleeWrapper(calleeMethodDecl))) bPotentiallyWrittenTo = true; } else @@ -701,15 +736,15 @@ void UnusedFields::checkReadOnly(const FieldDecl* fieldDecl, const Expr* memberE } else if (auto cxxConstructExpr = dyn_cast<CXXConstructExpr>(parent)) { - if (IsPassedByNonConst(fieldDecl, child, cxxConstructExpr, cxxConstructExpr)) + if (IsPassedByNonConst(fieldDecl, child, cxxConstructExpr, CalleeWrapper(cxxConstructExpr))) bPotentiallyWrittenTo = true; break; } else if (auto callExpr = dyn_cast<CallExpr>(parent)) { - const FunctionDecl * calleeFunctionDecl = callExpr->getDirectCallee(); - if (calleeFunctionDecl) { - if (IsPassedByNonConst(fieldDecl, child, callExpr, calleeFunctionDecl)) + auto callee = getCallee(callExpr); + if (callee) { + if (IsPassedByNonConst(fieldDecl, child, callExpr, *callee)) bPotentiallyWrittenTo = true; } else bPotentiallyWrittenTo = true; // conservative, could improve @@ -807,14 +842,14 @@ bool UnusedFields::IsPassedByNonConst(const FieldDecl* fieldDecl, const Stmt * c { for (unsigned i = 0; i < len; ++i) if (callExpr.getArg(i) == child) - if (loplugin::TypeCheck(calleeFunctionDecl.getParamDecl(i)->getType()).Pointer().NonConst()) + if (loplugin::TypeCheck(calleeFunctionDecl.getParamType(i)).Pointer().NonConst()) return true; } else { for (unsigned i = 0; i < len; ++i) if (callExpr.getArg(i) == child) - if (loplugin::TypeCheck(calleeFunctionDecl.getParamDecl(i)->getType()).LvalueReference().NonConst()) + if (loplugin::TypeCheck(calleeFunctionDecl.getParamType(i)).LvalueReference().NonConst()) return true; } return false; @@ -920,6 +955,49 @@ void UnusedFields::checkTouchedFromOutside(const FieldDecl* fieldDecl, const Exp } } +llvm::Optional<CalleeWrapper> UnusedFields::getCallee(CallExpr const * callExpr) +{ + FunctionDecl const * functionDecl = callExpr->getDirectCallee(); + if (functionDecl) + return CalleeWrapper(functionDecl); + + // Extract the functionprototype from a type + Type const * calleeType = callExpr->getCallee()->getType().getTypePtr(); + if (auto pointerType = calleeType->getUnqualifiedDesugaredType()->getAs<PointerType>()) { + if (auto prototype = pointerType->getPointeeType()->getUnqualifiedDesugaredType()->getAs<FunctionProtoType>()) { + return CalleeWrapper(prototype); + } + } + + llvm::Optional<CalleeWrapper> ret; + 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); } |