loplugin:finalclasses look for classes with virtual members
where making them final gives the compiler freedom to de-virtualise some calls Change-Id: I5755a41c42d9f23af58b873efae37a1d240fbd89 Reviewed-on: https://gerrit.libreoffice.org/81618 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
This commit is contained in:
@@ -15,9 +15,14 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Look for classes that are final i.e. nothing extends them, and have protected fields or members.
|
Look for classes that are final i.e. nothing extends them, and have either
|
||||||
|
(a) protected fields or members.
|
||||||
|
or
|
||||||
|
(b) virtual members
|
||||||
|
|
||||||
These can be made private.
|
In the case of (a), those members/fields can be made private.
|
||||||
|
In the case of (b), making the class final means the compiler can devirtualise
|
||||||
|
some method class.
|
||||||
|
|
||||||
The process goes something like this:
|
The process goes something like this:
|
||||||
$ make check
|
$ make check
|
||||||
@@ -88,6 +93,8 @@ bool FinalClasses::VisitCXXRecordDecl(const CXXRecordDecl* decl)
|
|||||||
decl = decl->getCanonicalDecl();
|
decl = decl->getCanonicalDecl();
|
||||||
if (!decl->hasDefinition())
|
if (!decl->hasDefinition())
|
||||||
return true;
|
return true;
|
||||||
|
if (decl->hasAttr<FinalAttr>())
|
||||||
|
return true;
|
||||||
|
|
||||||
for (auto it = decl->bases_begin(); it != decl->bases_end(); ++it)
|
for (auto it = decl->bases_begin(); it != decl->bases_end(); ++it)
|
||||||
{
|
{
|
||||||
@@ -100,15 +107,16 @@ bool FinalClasses::VisitCXXRecordDecl(const CXXRecordDecl* decl)
|
|||||||
checkBase(spec.getType());
|
checkBase(spec.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool bFoundVirtual = false;
|
||||||
bool bFoundProtected = false;
|
bool bFoundProtected = false;
|
||||||
for (auto it = decl->method_begin(); it != decl->method_end(); ++it) {
|
for (auto it = decl->method_begin(); it != decl->method_end(); ++it) {
|
||||||
auto i = *it;
|
auto i = *it;
|
||||||
// ignore methods that are overriding base-class methods, making them private
|
// ignore methods that are overriding base-class methods, making them private
|
||||||
// isn't useful
|
// isn't useful
|
||||||
if ( !i->hasAttr<OverrideAttr>() && i->getAccess() == AS_protected ) {
|
if ( !i->hasAttr<OverrideAttr>() && i->getAccess() == AS_protected )
|
||||||
bFoundProtected = true;
|
bFoundProtected = true;
|
||||||
break;
|
if ( i->isVirtual() )
|
||||||
}
|
bFoundVirtual = true;
|
||||||
}
|
}
|
||||||
if (!bFoundProtected)
|
if (!bFoundProtected)
|
||||||
{
|
{
|
||||||
@@ -120,7 +128,7 @@ bool FinalClasses::VisitCXXRecordDecl(const CXXRecordDecl* decl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!bFoundProtected)
|
if (!bFoundProtected && !bFoundVirtual)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
std::string s = decl->getQualifiedNameAsString();
|
std::string s = decl->getQualifiedNameAsString();
|
||||||
|
Reference in New Issue
Block a user