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