vclptr: calling disposeAndClear on all the fields is not great
sometimes we need to call clear() instead, and there is no
automatic way of figuring this out
Conflicts:
compilerplugins/clang/vclwidgets.cxx
Change-Id: Iad96342ce3fdb3fa2f548270392aa00e19fec599
diff --git a/compilerplugins/clang/vclwidgets.cxx b/compilerplugins/clang/vclwidgets.cxx
index da59dd2..ffa73a8 100644
--- a/compilerplugins/clang/vclwidgets.cxx
+++ b/compilerplugins/clang/vclwidgets.cxx
@@ -340,48 +340,6 @@ bool VCLWidgets::VisitParmVarDecl(ParmVarDecl const * pvDecl)
return true;
}
static void findDisposeAndClearStatements(std::vector<std::string>& aVclPtrFields, const Stmt *pStmt)
{
if (!pStmt)
return;
if (isa<CompoundStmt>(pStmt)) {
const CompoundStmt *pCompoundStatement = dyn_cast<CompoundStmt>(pStmt);
for(const Stmt* pStmt : pCompoundStatement->body()) {
findDisposeAndClearStatements(aVclPtrFields, pStmt);
}
return;
}
if (isa<ForStmt>(pStmt)) {
findDisposeAndClearStatements(aVclPtrFields, dyn_cast<ForStmt>(pStmt)->getBody());
return;
}
if (isa<IfStmt>(pStmt)) {
findDisposeAndClearStatements(aVclPtrFields, dyn_cast<IfStmt>(pStmt)->getThen());
findDisposeAndClearStatements(aVclPtrFields, dyn_cast<IfStmt>(pStmt)->getElse());
return;
}
if (!isa<CallExpr>(pStmt)) return;
const CallExpr *pCallExpr = dyn_cast<CallExpr>(pStmt);
if (!pCallExpr->getDirectCallee()) return;
if (!isa<CXXMethodDecl>(pCallExpr->getDirectCallee())) return;
const CXXMethodDecl *pCalleeMethodDecl = dyn_cast<CXXMethodDecl>(pCallExpr->getDirectCallee());
if (pCalleeMethodDecl->getNameAsString() != "disposeAndClear") return;
if (!pCallExpr->getCallee()) return;
if (!isa<MemberExpr>(pCallExpr->getCallee())) return;
const MemberExpr *pCalleeMemberExpr = dyn_cast<MemberExpr>(pCallExpr->getCallee());
if (!pCalleeMemberExpr->getBase()) return;
if (!isa<MemberExpr>(pCalleeMemberExpr->getBase())) return;
const MemberExpr *pCalleeMemberExprBase = dyn_cast<MemberExpr>(pCalleeMemberExpr->getBase());
std::string xxx = pCalleeMemberExprBase->getMemberDecl()->getNameAsString();
aVclPtrFields.erase(std::remove(aVclPtrFields.begin(), aVclPtrFields.end(), xxx), aVclPtrFields.end());
}
bool VCLWidgets::VisitFunctionDecl( const FunctionDecl* functionDecl )
{
if (ignoreLocation(functionDecl)) {
@@ -410,71 +368,7 @@ bool VCLWidgets::VisitFunctionDecl( const FunctionDecl* functionDecl )
}
}
}
// check dispose method to make sure we are actually disposing all of the VclPtr fields
if (pMethodDecl && pMethodDecl->isInstance() && pMethodDecl->getBody()
&& pMethodDecl->param_size()==0
&& pMethodDecl->getNameAsString() == "dispose"
&& isDerivedFromWindow(pMethodDecl->getParent()) )
{
// exclude a couple of methods with hard-to-parse code
/*
if (pMethodDecl->getQualifiedNameAsString() == "SvxRubyDialog::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "SvxPersonalizationTabPage::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "SelectPersonaDialog::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "MappingDialog_Impl::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "BibGeneralPage::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "SwCreateAuthEntryDlg_Impl::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "SwTableColumnPage::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "SwAssignFieldsControl::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "ScOptSolverDlg::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "ScPivotFilterDlg::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "SmToolBoxWindow::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "dbaui::DlgOrderCrit::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "SvxStyleBox_Impl::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "dbaui::OAppDetailPageHelper::dispose")
return true;
if (pMethodDecl->getQualifiedNameAsString() == "sd::CustomAnimationCreateDialog::dispose")
return true;
*/
if (pMethodDecl->getQualifiedNameAsString() == "VirtualDevice::dispose")
return true;
std::vector<std::string> aVclPtrFields;
for(auto fieldDecl : pMethodDecl->getParent()->fields()) {
if (startsWith(fieldDecl->getType().getAsString(), "VclPtr")) {
aVclPtrFields.push_back(fieldDecl->getNameAsString());
}
}
if (!aVclPtrFields.empty()) {
if (pMethodDecl->getBody())
findDisposeAndClearStatements( aVclPtrFields, pMethodDecl->getBody() );
if (!aVclPtrFields.empty()) {
//pMethodDecl->dump();
std::string aMessage = "OutputDevice subclass dispose() method does not call disposeAndClear() on the following field(s) ";
for(auto s : aVclPtrFields)
aMessage += "\n " + s + ".clear();";
report(
DiagnosticsEngine::Warning,
aMessage,
functionDecl->getLocStart())
<< functionDecl->getSourceRange();
}
}
}
return true;
}