compilerplugin: check that necessary Window subclasses have a dispose method

i.e. the ones that declare any VclPtr fields

Change-Id: I7adfc3b3b190a2ede60bfccd08f85a269fae33ca
diff --git a/compilerplugins/clang/vclwidgets.cxx b/compilerplugins/clang/vclwidgets.cxx
index aa2af7f..896cd3f 100644
--- a/compilerplugins/clang/vclwidgets.cxx
+++ b/compilerplugins/clang/vclwidgets.cxx
@@ -31,6 +31,8 @@ public:

    virtual void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }

    bool VisitCXXRecordDecl(const CXXRecordDecl * decl);

    bool VisitFieldDecl(const FieldDecl * decl);

    bool VisitParmVarDecl(ParmVarDecl const * decl);
@@ -76,6 +78,44 @@ bool isPointerToWindowSubclass(const QualType& pType) {
    return isDerivedFromWindow(recordDecl);
}

bool VCLWidgets::VisitCXXRecordDecl(const CXXRecordDecl * recordDecl) {
    if (ignoreLocation(recordDecl)) {
        return true;
    }
    if (!recordDecl->isCompleteDefinition())
        return true;
    // check if this field is derived from Window
    if (!isDerivedFromWindow(recordDecl)) {
        return true;
    }
    bool foundVclPtr = false;
    for(auto fieldDecl : recordDecl->fields()) {
        if (fieldDecl->getType().getAsString().find("VclPtr")==0) {
           foundVclPtr = true;
           break;
        }
    }
    if (!foundVclPtr) {
        return true;
    }
    bool foundDispose = false;
    for(auto methodDecl : recordDecl->methods()) {
        if (methodDecl->isInstance() && methodDecl->param_size()==0 && methodDecl->getNameAsString() == "dispose") {
           foundDispose = true;
           break;
        }
    }
    if (!foundDispose) {
        report(
            DiagnosticsEngine::Warning,
            "vcl::Window subclass with VclPtr members should declare a dispose() method.",
            recordDecl->getLocation())
          << recordDecl->getSourceRange();
    }
    return true;
}


bool VCLWidgets::VisitFieldDecl(const FieldDecl * fieldDecl) {
    if (ignoreLocation(fieldDecl)) {
        return true;
diff --git a/include/vcl/combobox.hxx b/include/vcl/combobox.hxx
index 8842477a..86e6af4 100644
--- a/include/vcl/combobox.hxx
+++ b/include/vcl/combobox.hxx
@@ -91,6 +91,7 @@ protected:
    bool            IsDropDownBox() const { return mpFloatWin ? true : false; }

    virtual void    FillLayoutData() const SAL_OVERRIDE;
    virtual void    dispose() SAL_OVERRIDE;
public:
    explicit        ComboBox( vcl::Window* pParent, WinBits nStyle = 0 );
    explicit        ComboBox( vcl::Window* pParent, const ResId& );
diff --git a/include/vcl/dialog.hxx b/include/vcl/dialog.hxx
index bd418e8..ab498f1 100644
--- a/include/vcl/dialog.hxx
+++ b/include/vcl/dialog.hxx
@@ -62,6 +62,7 @@ private:
protected:
    using Window::ImplInit;
    SAL_DLLPRIVATE void    ImplInit( vcl::Window* pParent, WinBits nStyle );
    virtual        void    dispose() SAL_OVERRIDE;

public:
    SAL_DLLPRIVATE bool    IsInClose() const { return mbInClose; }
diff --git a/include/vcl/layout.hxx b/include/vcl/layout.hxx
index d11da2c..fde7609 100644
--- a/include/vcl/layout.hxx
+++ b/include/vcl/layout.hxx
@@ -620,6 +620,8 @@ private:
    };

    VclPtr<EventBoxHelper> m_aEventBoxHelper;
protected:
    virtual void dispose() SAL_OVERRIDE;
public:
    VclEventBox(vcl::Window* pParent)
        : VclBin(pParent)
diff --git a/vcl/source/control/combobox.cxx b/vcl/source/control/combobox.cxx
index d847975..21877ec 100644
--- a/vcl/source/control/combobox.cxx
+++ b/vcl/source/control/combobox.cxx
@@ -78,6 +78,12 @@ ComboBox::~ComboBox()
    delete mpBtn;
}

void ComboBox::dispose()
{
    mpSubEdit.disposeAndClear();
    Edit::dispose();
}

void ComboBox::ImplInitComboBoxData()
{
    mpSubEdit.disposeAndClear();
diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx
index b5f7b53..60aa876 100644
--- a/vcl/source/window/dialog.cxx
+++ b/vcl/source/window/dialog.cxx
@@ -542,6 +542,13 @@ Dialog::~Dialog()
    mpDialogImpl = NULL;
}

void Dialog::dispose()
{
    mpActionArea.disposeAndClear();
    mpContentArea.disposeAndClear();
    SystemWindow::dispose();
}

IMPL_LINK_NOARG(Dialog, ImplAsyncCloseHdl)
{
    Close();
diff --git a/vcl/source/window/layout.cxx b/vcl/source/window/layout.cxx
index 6a6c154..5fee1f0f 100644
--- a/vcl/source/window/layout.cxx
+++ b/vcl/source/window/layout.cxx
@@ -1878,6 +1878,12 @@ void VclEventBox::Command(const CommandEvent&)
    //discard events by default to block them reaching children
}

void VclEventBox::dispose()
{
    m_aEventBoxHelper.disposeAndClear();
    VclBin::dispose();
}

void VclSizeGroup::trigger_queue_resize()
{
    //sufficient to trigger one widget to trigger all of them