Kaydet (Commit) bb24492c authored tarafından Stephan Bergmann's avatar Stephan Bergmann

More loplugin::TypeCheck use

Change-Id: I2f4a26a918134568f541cd45bdcf5a12b1f1d2ee
üst 8d2c9a60
...@@ -12,11 +12,6 @@ ...@@ -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: ...@@ -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: ...@@ -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 @@ ...@@ -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) { ...@@ -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( ...@@ -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 @@ ...@@ -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: ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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 @@ ...@@ -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 @@ ...@@ -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) { ...@@ -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( ...@@ -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 @@ ...@@ -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: ...@@ -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: ...@@ -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]) ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment