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 @@
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
......
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