More loplugin::TypeCheck use
Change-Id: I2f4a26a918134568f541cd45bdcf5a12b1f1d2ee
This commit is contained in:
@@ -12,11 +12,6 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static bool startsWith(const std::string& s, const char* other)
|
|
||||||
{
|
|
||||||
return s.compare(0, strlen(other), other) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
class BadStatics
|
class BadStatics
|
||||||
: public clang::RecursiveASTVisitor<BadStatics>
|
: public clang::RecursiveASTVisitor<BadStatics>
|
||||||
, public loplugin::Plugin
|
, public loplugin::Plugin
|
||||||
@@ -52,10 +47,10 @@ public:
|
|||||||
if (!pRecordType) {
|
if (!pRecordType) {
|
||||||
return std::make_pair(false, std::vector<FieldDecl const*>());
|
return std::make_pair(false, std::vector<FieldDecl const*>());
|
||||||
}
|
}
|
||||||
auto const type(pCanonical.getAsString());
|
auto const type = loplugin::TypeCheck(rpType);
|
||||||
if ( type == "class Image"
|
if ( type.Class("Image").GlobalNamespace()
|
||||||
|| type == "class Bitmap"
|
|| type.Class("Bitmap").GlobalNamespace()
|
||||||
|| type == "class BitmapEx"
|
|| type.Class("BitmapEx").GlobalNamespace()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return std::make_pair(true, chain);
|
return std::make_pair(true, chain);
|
||||||
@@ -64,12 +59,11 @@ public:
|
|||||||
if (!pDefinition) { // maybe no definition if it's a pointer/reference
|
if (!pDefinition) { // maybe no definition if it's a pointer/reference
|
||||||
return std::make_pair(false, std::vector<FieldDecl const*>());
|
return std::make_pair(false, std::vector<FieldDecl const*>());
|
||||||
}
|
}
|
||||||
if ( startsWith(type, "class vcl::DeleteOnDeinit")
|
if ( type.Class("DeleteOnDeinit").Namespace("vcl").GlobalNamespace()
|
||||||
|| loplugin::TypeCheck(rpType).Class("weak_ptr").StdNamespace()
|
|| type.Class("weak_ptr").StdNamespace() // not owning
|
||||||
// not owning
|
|| type.Class("ImplWallpaper").GlobalNamespace() // very odd static instance here
|
||||||
|| type == "class ImplWallpaper" // very odd static instance here
|
|| type.Class("Application").GlobalNamespace() // numerous odd subclasses in vclmain::createApplication()
|
||||||
|| type == "class Application" // numerous odd subclasses in vclmain::createApplication()
|
|| type.Class("DemoMtfApp").GlobalNamespace() // one of these Application with own VclPtr
|
||||||
|| type == "class DemoMtfApp" // one of these Application with own VclPtr
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return std::make_pair(false, std::vector<FieldDecl const*>());
|
return std::make_pair(false, std::vector<FieldDecl const*>());
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include "plugin.hxx"
|
#include "plugin.hxx"
|
||||||
|
#include "typecheck.hxx"
|
||||||
#include "clang/Frontend/CompilerInstance.h"
|
#include "clang/Frontend/CompilerInstance.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -45,11 +46,6 @@ clang::Expr const * ignoreParenImplicitComma(clang::Expr const * expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPlainChar(clang::QualType type) {
|
|
||||||
return type->isSpecificBuiltinType(clang::BuiltinType::Char_S)
|
|
||||||
|| type->isSpecificBuiltinType(clang::BuiltinType::Char_U);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool overridesXServiceInfo(clang::CXXMethodDecl const * decl) {
|
bool overridesXServiceInfo(clang::CXXMethodDecl const * decl) {
|
||||||
for (auto i = decl->begin_overridden_methods();
|
for (auto i = decl->begin_overridden_methods();
|
||||||
i != decl->end_overridden_methods(); ++i)
|
i != decl->end_overridden_methods(); ++i)
|
||||||
@@ -145,7 +141,8 @@ bool GetImplementationName::isStringConstant(
|
|||||||
{
|
{
|
||||||
QualType t = expr->getType();
|
QualType t = expr->getType();
|
||||||
if (!(t->isConstantArrayType() && t.isConstQualified()
|
if (!(t->isConstantArrayType() && t.isConstQualified()
|
||||||
&& isPlainChar(t->getAsArrayTypeUnsafe()->getElementType())))
|
&& (loplugin::TypeCheck(t->getAsArrayTypeUnsafe()->getElementType())
|
||||||
|
.Char())))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "plugin.hxx"
|
#include "plugin.hxx"
|
||||||
|
#include "typecheck.hxx"
|
||||||
|
|
||||||
// Find places where various things are passed by value.
|
// Find places where various things are passed by value.
|
||||||
// It's not very efficient, because we generally end up copying it twice - once into the parameter and
|
// It's not very efficient, because we generally end up copying it twice - once into the parameter and
|
||||||
@@ -38,7 +39,7 @@ public:
|
|||||||
bool VisitLambdaExpr(const LambdaExpr * expr);
|
bool VisitLambdaExpr(const LambdaExpr * expr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isFat(QualType type, std::string * name);
|
bool isFat(QualType type);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool PassStuffByRef::VisitFunctionDecl(const FunctionDecl * functionDecl) {
|
bool PassStuffByRef::VisitFunctionDecl(const FunctionDecl * functionDecl) {
|
||||||
@@ -63,14 +64,13 @@ bool PassStuffByRef::VisitFunctionDecl(const FunctionDecl * functionDecl) {
|
|||||||
unsigned n = functionDecl->getNumParams();
|
unsigned n = functionDecl->getNumParams();
|
||||||
for (unsigned i = 0; i != n; ++i) {
|
for (unsigned i = 0; i != n; ++i) {
|
||||||
const ParmVarDecl * pvDecl = functionDecl->getParamDecl(i);
|
const ParmVarDecl * pvDecl = functionDecl->getParamDecl(i);
|
||||||
std::string name;
|
auto const t = pvDecl->getType();
|
||||||
if (isFat(pvDecl->getType(), &name)) {
|
if (isFat(t)) {
|
||||||
report(
|
report(
|
||||||
DiagnosticsEngine::Warning,
|
DiagnosticsEngine::Warning,
|
||||||
("passing '%0' by value, rather pass by reference, e.g., '%0"
|
("passing %0 by value, rather pass by const lvalue reference"),
|
||||||
" const &'"),
|
|
||||||
pvDecl->getLocation())
|
pvDecl->getLocation())
|
||||||
<< name << pvDecl->getSourceRange();
|
<< t << pvDecl->getSourceRange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -82,14 +82,14 @@ bool PassStuffByRef::VisitLambdaExpr(const LambdaExpr * expr) {
|
|||||||
}
|
}
|
||||||
for (auto i(expr->capture_begin()); i != expr->capture_end(); ++i) {
|
for (auto i(expr->capture_begin()); i != expr->capture_end(); ++i) {
|
||||||
if (i->getCaptureKind() == LambdaCaptureKind::LCK_ByCopy) {
|
if (i->getCaptureKind() == LambdaCaptureKind::LCK_ByCopy) {
|
||||||
std::string name;
|
auto const t = i->getCapturedVar()->getType();
|
||||||
if (isFat(i->getCapturedVar()->getType(), &name)) {
|
if (isFat(t)) {
|
||||||
report(
|
report(
|
||||||
DiagnosticsEngine::Warning,
|
DiagnosticsEngine::Warning,
|
||||||
("%0 capture of '%1' variable by copy, rather use capture"
|
("%0 capture of %1 variable by copy, rather use capture"
|
||||||
" by reference---UNLESS THE LAMBDA OUTLIVES THE VARIABLE"),
|
" by reference---UNLESS THE LAMBDA OUTLIVES THE VARIABLE"),
|
||||||
i->getLocation())
|
i->getLocation())
|
||||||
<< (i->isImplicit() ? "implicit" : "explicit") << name
|
<< (i->isImplicit() ? "implicit" : "explicit") << t
|
||||||
<< expr->getSourceRange();
|
<< expr->getSourceRange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,13 +97,17 @@ bool PassStuffByRef::VisitLambdaExpr(const LambdaExpr * expr) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PassStuffByRef::isFat(QualType type, std::string * name) {
|
bool PassStuffByRef::isFat(QualType type) {
|
||||||
if (!type->isRecordType()) {
|
if (!type->isRecordType()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*name = type.getUnqualifiedType().getCanonicalType().getAsString();
|
if ((loplugin::TypeCheck(type).Class("OUString").Namespace("rtl")
|
||||||
if (*name == "class rtl::OUString" || *name == "class rtl::OString"
|
.GlobalNamespace())
|
||||||
|| name->compare(0, 35, "class com::sun::star::uno::Sequence") == 0)
|
|| (loplugin::TypeCheck(type).Class("OString").Namespace("rtl")
|
||||||
|
.GlobalNamespace())
|
||||||
|
|| (loplugin::TypeCheck(type).Class("Sequence").Namespace("uno")
|
||||||
|
.Namespace("star").Namespace("sun").Namespace("com")
|
||||||
|
.GlobalNamespace()))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "compat.hxx"
|
#include "compat.hxx"
|
||||||
#include "plugin.hxx"
|
#include "plugin.hxx"
|
||||||
|
#include "typecheck.hxx"
|
||||||
|
|
||||||
// Define a "string constant" to be a constant expression either of type "array
|
// Define a "string constant" to be a constant expression either of type "array
|
||||||
// of N char" where each array element is a non-NUL ASCII character---except
|
// of N char" where each array element is a non-NUL ASCII character---except
|
||||||
@@ -37,11 +38,6 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool isPlainChar(QualType type) {
|
|
||||||
return type->isSpecificBuiltinType(BuiltinType::Char_S)
|
|
||||||
|| type->isSpecificBuiltinType(BuiltinType::Char_U);
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation getMemberLocation(Expr const * expr) {
|
SourceLocation getMemberLocation(Expr const * expr) {
|
||||||
CallExpr const * e1 = dyn_cast<CallExpr>(expr);
|
CallExpr const * e1 = dyn_cast<CallExpr>(expr);
|
||||||
MemberExpr const * e2 = e1 == nullptr
|
MemberExpr const * e2 = e1 == nullptr
|
||||||
@@ -227,30 +223,14 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
|
|||||||
std::string qname(fdecl->getQualifiedNameAsString());
|
std::string qname(fdecl->getQualifiedNameAsString());
|
||||||
for (unsigned i = 0; i != fdecl->getNumParams(); ++i) {
|
for (unsigned i = 0; i != fdecl->getNumParams(); ++i) {
|
||||||
auto t = fdecl->getParamDecl(i)->getType();
|
auto t = fdecl->getParamDecl(i)->getType();
|
||||||
if (t->isLValueReferenceType()
|
if (loplugin::TypeCheck(t).NotSubstTemplateTypeParmType()
|
||||||
&& t->getAs<SubstTemplateTypeParmType>() == nullptr)
|
.LvalueReference().Const().NotSubstTemplateTypeParmType()
|
||||||
|
.Class("OUString").Namespace("rtl").GlobalNamespace())
|
||||||
{
|
{
|
||||||
t = t->getAs<LValueReferenceType>()->getPointeeType();
|
if (!(isLhsOfAssignment(fdecl, i)
|
||||||
if (t.isConstQualified() && !t.isVolatileQualified()
|
|| hasOverloads(fdecl, expr->getNumArgs())))
|
||||||
&& t->isClassType()
|
|
||||||
&& t->getAs<SubstTemplateTypeParmType>() == nullptr)
|
|
||||||
{
|
{
|
||||||
auto td = compat::getAsTagDecl(*t);
|
handleOUStringCtor(expr, i, qname, true);
|
||||||
auto id = td->getIdentifier();
|
|
||||||
if (id != nullptr && id->isStr("OUString")) {
|
|
||||||
auto nd = dyn_cast<NamespaceDecl>(td->getParent());
|
|
||||||
if (nd != nullptr) {
|
|
||||||
id = nd->getIdentifier();
|
|
||||||
if (id != nullptr && id->isStr("rtl")) {
|
|
||||||
//TODO: check rtl is outermost namespace
|
|
||||||
if (!(isLhsOfAssignment(fdecl, i)
|
|
||||||
|| hasOverloads(fdecl, expr->getNumArgs())))
|
|
||||||
{
|
|
||||||
handleOUStringCtor(expr, i, qname, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -839,7 +819,8 @@ bool StringConstant::isStringConstant(
|
|||||||
assert(terminatingNul != nullptr);
|
assert(terminatingNul != nullptr);
|
||||||
QualType t = expr->getType();
|
QualType t = expr->getType();
|
||||||
if (!(t->isConstantArrayType() && t.isConstQualified()
|
if (!(t->isConstantArrayType() && t.isConstQualified()
|
||||||
&& isPlainChar(t->getAsArrayTypeUnsafe()->getElementType())))
|
&& (loplugin::TypeCheck(t->getAsArrayTypeUnsafe()->getElementType())
|
||||||
|
.Char())))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -13,13 +13,13 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include <clang/AST/DeclBase.h>
|
#include <clang/AST/DeclBase.h>
|
||||||
|
#include <clang/AST/Decl.h>
|
||||||
#include <clang/AST/Type.h>
|
#include <clang/AST/Type.h>
|
||||||
|
|
||||||
#include "compat.hxx"
|
|
||||||
|
|
||||||
namespace loplugin {
|
namespace loplugin {
|
||||||
|
|
||||||
class NamespaceCheck;
|
class NamespaceCheck;
|
||||||
|
class TerminalCheck;
|
||||||
|
|
||||||
class TypeCheck {
|
class TypeCheck {
|
||||||
public:
|
public:
|
||||||
@@ -27,73 +27,33 @@ public:
|
|||||||
|
|
||||||
explicit operator bool() const { return !type_.isNull(); }
|
explicit operator bool() const { return !type_.isNull(); }
|
||||||
|
|
||||||
TypeCheck Const() const {
|
TypeCheck Const() const;
|
||||||
return
|
|
||||||
(!type_.isNull() && type_.isConstQualified()
|
|
||||||
&& !type_.isVolatileQualified())
|
|
||||||
? *this : TypeCheck();
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeCheck LvalueReference() const {
|
TerminalCheck Char() const;
|
||||||
if (!type_.isNull()) {
|
|
||||||
auto const t = type_->getAs<LValueReferenceType>();
|
TypeCheck LvalueReference() const;
|
||||||
if (t != nullptr) {
|
|
||||||
return TypeCheck(t->getPointeeType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TypeCheck();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t N> inline NamespaceCheck Class(char const (& id)[N])
|
template<std::size_t N> inline NamespaceCheck Class(char const (& id)[N])
|
||||||
const;
|
const;
|
||||||
|
|
||||||
|
TypeCheck NotSubstTemplateTypeParmType() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TypeCheck() = default;
|
TypeCheck() = default;
|
||||||
|
|
||||||
clang::QualType const type_;
|
clang::QualType const type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TerminalCheck {
|
|
||||||
public:
|
|
||||||
explicit operator bool() const { return satisfied_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend NamespaceCheck;
|
|
||||||
|
|
||||||
explicit TerminalCheck(bool satisfied): satisfied_(satisfied) {}
|
|
||||||
|
|
||||||
bool const satisfied_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NamespaceCheck {
|
class NamespaceCheck {
|
||||||
public:
|
public:
|
||||||
explicit operator bool() const { return context_ != nullptr; }
|
explicit operator bool() const { return context_ != nullptr; }
|
||||||
|
|
||||||
TerminalCheck GlobalNamespace() const {
|
TerminalCheck GlobalNamespace() const;
|
||||||
return TerminalCheck(
|
|
||||||
context_ != nullptr
|
|
||||||
&& ((compat::isLookupContext(*context_)
|
|
||||||
? context_ : context_->getLookupParent())
|
|
||||||
->isTranslationUnit()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t N> NamespaceCheck Namespace(char const (& id)[N]) const
|
template<std::size_t N> inline NamespaceCheck Namespace(
|
||||||
{
|
char const (& id)[N]) const;
|
||||||
if (context_) {
|
|
||||||
auto n = llvm::dyn_cast<clang::NamespaceDecl>(context_);
|
|
||||||
if (n != nullptr) {
|
|
||||||
auto const i = n->getIdentifier();
|
|
||||||
if (i != nullptr && i->isStr(id)) {
|
|
||||||
return NamespaceCheck(n->getParent());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NamespaceCheck();
|
|
||||||
}
|
|
||||||
|
|
||||||
TerminalCheck StdNamespace() const {
|
TerminalCheck StdNamespace() const;
|
||||||
return TerminalCheck(context_ != nullptr && context_->isStdNamespace());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class TypeCheck;
|
friend class TypeCheck;
|
||||||
@@ -104,11 +64,24 @@ private:
|
|||||||
clang::DeclContext const * const context_;
|
clang::DeclContext const * const context_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TerminalCheck {
|
||||||
|
public:
|
||||||
|
explicit operator bool() const { return satisfied_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend TypeCheck;
|
||||||
|
friend NamespaceCheck;
|
||||||
|
|
||||||
|
explicit TerminalCheck(bool satisfied): satisfied_(satisfied) {}
|
||||||
|
|
||||||
|
bool const satisfied_;
|
||||||
|
};
|
||||||
|
|
||||||
template<std::size_t N> NamespaceCheck TypeCheck::Class(char const (& id)[N])
|
template<std::size_t N> NamespaceCheck TypeCheck::Class(char const (& id)[N])
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
if (!type_.isNull()) {
|
if (!type_.isNull()) {
|
||||||
auto const t = type_->getAs<RecordType>();
|
auto const t = type_->getAs<clang::RecordType>();
|
||||||
if (t != nullptr) {
|
if (t != nullptr) {
|
||||||
auto const d = t->getDecl();
|
auto const d = t->getDecl();
|
||||||
if (d->isClass()) {
|
if (d->isClass()) {
|
||||||
@@ -122,6 +95,21 @@ template<std::size_t N> NamespaceCheck TypeCheck::Class(char const (& id)[N])
|
|||||||
return NamespaceCheck();
|
return NamespaceCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<std::size_t N> NamespaceCheck NamespaceCheck::Namespace(
|
||||||
|
char const (& id)[N]) const
|
||||||
|
{
|
||||||
|
if (context_) {
|
||||||
|
auto n = llvm::dyn_cast<clang::NamespaceDecl>(context_);
|
||||||
|
if (n != nullptr) {
|
||||||
|
auto const i = n->getIdentifier();
|
||||||
|
if (i != nullptr && i->isStr(id)) {
|
||||||
|
return NamespaceCheck(n->getParent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NamespaceCheck();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user