/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include <cassert>#include <clang/AST/DeclCXX.h>#include "check.hxx"namespaceloplugin{TypeCheckTypeCheck::NonConst()const{return!type_.isNull()&&!type_.isConstQualified()?*this:TypeCheck();// returning TypeCheck(type_.getUnqualifiedType()) instead of *this// may look tempting, but could remove sugar we might be interested in// checking for}TypeCheckTypeCheck::NonConstVolatile()const{return(!type_.isNull()&&!type_.isConstQualified()&&!type_.isVolatileQualified())?*this:TypeCheck();// returning TypeCheck(type_.getUnqualifiedType()) instead of *this// may look tempting, but could remove sugar we might be interested in// checking for}TypeCheckTypeCheck::Const()const{return(!type_.isNull()&&type_.isConstQualified()&&!type_.isVolatileQualified())?*this:TypeCheck();// returning TypeCheck(type_.getUnqualifiedType()) instead of *this// may look tempting, but could remove sugar we might be interested in// checking for}TypeCheckTypeCheck::Volatile()const{<--- The function 'Volatile' is never used.return(!type_.isNull()&&!type_.isConstQualified()&&type_.isVolatileQualified())?*this:TypeCheck();// returning TypeCheck(type_.getUnqualifiedType()) instead of *this// may look tempting, but could remove sugar we might be interested in// checking for}TypeCheckTypeCheck::ConstVolatile()const{<--- The function 'ConstVolatile' is never used.return(!type_.isNull()&&type_.isConstQualified()&&type_.isVolatileQualified())?*this:TypeCheck();// returning TypeCheck(type_.getUnqualifiedType()) instead of *this// may look tempting, but could remove sugar we might be interested in// checking for}TerminalCheckTypeCheck::Void()const{returnTerminalCheck(!type_.isNull()&&type_->isSpecificBuiltinType(clang::BuiltinType::Void));}TerminalCheckTypeCheck::Char()const{returnTerminalCheck(!type_.isNull()&&(type_->isSpecificBuiltinType(clang::BuiltinType::Char_S)||type_->isSpecificBuiltinType(clang::BuiltinType::Char_U)));}TerminalCheckTypeCheck::AnyBoolean()const{if(type_->isBooleanType()){returnTerminalCheck(true);}autot=type_->getAs<clang::TypedefType>();if(t==nullptr){returnTerminalCheck(false);}auton=t->getDecl()->getName();returnTerminalCheck(n=="sal_Bool"||n=="BOOL"||n=="Boolean"||n=="FT_Bool"||n=="FcBool"||n=="GLboolean"||n=="NPBool"||n=="TW_BOOL"||n=="UBool"||n=="boolean"||n=="dbus_bool_t"||n=="gboolean"||n=="hb_bool_t"||n=="jboolean"||n=="my_bool");}TypeCheckTypeCheck::LvalueReference()const{if(!type_.isNull()){autoconstt=type_->getAs<clang::LValueReferenceType>();if(t!=nullptr){returnTypeCheck(t->getPointeeType());}}returnTypeCheck();}TypeCheckTypeCheck::Pointer()const{if(!type_.isNull()){autoconstt=type_->getAs<clang::PointerType>();if(t!=nullptr){returnTypeCheck(t->getPointeeType());}}returnTypeCheck();}TerminalCheckTypeCheck::Enum()const{if(!type_.isNull()){autoconstt=type_->getAs<clang::EnumType>();if(t!=nullptr){returnTerminalCheck(true);}}returnTerminalCheck(false);}TypeCheckTypeCheck::Typedef()const{if(!type_.isNull()){if(autoconstt=type_->getAs<clang::TypedefType>()){returnTypeCheck(t->desugar());}}returnTypeCheck();}TypeCheckTypeCheck::NotSubstTemplateTypeParmType()const{return(!type_.isNull()&&type_->getAs<clang::SubstTemplateTypeParmType>()==nullptr)?*this:TypeCheck();}ContextCheckDeclCheck::Operator(clang::OverloadedOperatorKindop)const{assert(op!=clang::OO_None);autof=llvm::dyn_cast_or_null<clang::FunctionDecl>(decl_);returnContextCheck(f!=nullptr&&f->getOverloadedOperator()==op?f->getDeclContext():nullptr);}ContextCheckDeclCheck::MemberFunction()const{autom=llvm::dyn_cast_or_null<clang::CXXMethodDecl>(decl_);returnContextCheck(m==nullptr?nullptr:m->getParent());}TerminalCheckContextCheck::GlobalNamespace()const{returnTerminalCheck(context_!=nullptr&&((context_->isLookupContext()?context_:context_->getLookupParent())->isTranslationUnit()));}TerminalCheckContextCheck::StdNamespace()const{returnTerminalCheck(context_!=nullptr&&context_->isStdNamespace());}ContextCheckContextCheck::AnonymousNamespace()const{auton=llvm::dyn_cast_or_null<clang::NamespaceDecl>(context_);returnContextCheck(n!=nullptr&&n->isAnonymousNamespace()?n->getParent():nullptr);}namespace{boolBaseCheckNotSomethingInterestingSubclass(constclang::CXXRecordDecl*BaseDefinition){if(BaseDefinition){autotc=TypeCheck(BaseDefinition);if(tc.Class("Dialog").GlobalNamespace()||tc.Class("SfxPoolItem").GlobalNamespace()){returnfalse;}}returntrue;}boolisDerivedFromSomethingInteresting(constclang::CXXRecordDecl*decl){if(!decl)returnfalse;autotc=TypeCheck(decl);if(tc.Class("Dialog"))returntrue;if(tc.Class("SfxPoolItem"))returntrue;if(!decl->hasDefinition()){returnfalse;}if(// not sure what hasAnyDependentBases() does,// but it avoids classes we don't want, e.g. WeakAggComponentImplHelper1!decl->hasAnyDependentBases()&&!decl->forallBases(BaseCheckNotSomethingInterestingSubclass,true)){returntrue;}returnfalse;}}boolisExtraWarnUnusedType(clang::QualTypetype){autoconstrec=type->getAsCXXRecordDecl();if(rec==nullptr){returnfalse;}autoconsttc=TypeCheck(rec);// Check some common non-LO types:if(tc.Class("basic_string").StdNamespace()||tc.Class("deque").StdNamespace()||tc.Class("list").StdNamespace()||tc.Class("map").StdNamespace()||tc.Class("pair").StdNamespace()||tc.Class("queue").StdNamespace()||tc.Class("set").StdNamespace()||tc.Class("stack").StdNamespace()||tc.Class("unordered_map").StdNamespace()||tc.Class("unordered_set").StdNamespace()||tc.Class("vector").StdNamespace()){returntrue;}returnisDerivedFromSomethingInteresting(rec);}namespace{boolisArithmeticOp(clang::Exprconst*expr){expr=expr->IgnoreParenImpCasts();if(autoconste=llvm::dyn_cast<clang::BinaryOperator>(expr)){switch(e->getOpcode()){caseclang::BO_Mul:caseclang::BO_Div:caseclang::BO_Rem:caseclang::BO_Add:caseclang::BO_Sub:caseclang::BO_Shl:caseclang::BO_Shr:caseclang::BO_And:caseclang::BO_Xor:caseclang::BO_Or:returntrue;caseclang::BO_Comma:returnisArithmeticOp(e->getRHS());default:returnfalse;}}returnllvm::isa<clang::UnaryOperator>(expr)||llvm::isa<clang::AbstractConditionalOperator>(expr);}}boolisOkToRemoveArithmeticCast(clang::ASTContext&context,clang::QualTypet1,clang::QualTypet2,constclang::Expr*subExpr){// Don't warn if the types are arithmetic (in the C++ meaning), and: either// at least one is a typedef or decltype (and if both are, they're different),// or the sub-expression involves some operation that is likely to change// types through promotion, or the sub-expression is an integer literal (so// its type generally depends on its value and suffix if any---even with a// suffix like L it could still be either long or long long):if((t1->isIntegralType(context)||t1->isRealFloatingType())&&((t1.getLocalUnqualifiedType()!=t2.getLocalUnqualifiedType()&&(loplugin::TypeCheck(t1).Typedef()||loplugin::TypeCheck(t2).Typedef()||llvm::isa<clang::DecltypeType>(t1)||llvm::isa<clang::DecltypeType>(t2)))||isArithmeticOp(subExpr)||llvm::isa<clang::IntegerLiteral>(subExpr->IgnoreParenImpCasts()))){returnfalse;}returntrue;}}/* vim:set shiftwidth=4 softtabstop=4 expandtab: */