1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
16 // We don't like using C-style casts in C++ code
21 bool hasCLanguageLinkageType(FunctionDecl
const * decl
) {
22 return decl
->isExternC() || compat::isInExternCContext(*decl
);
25 QualType
resolvePointers(QualType type
) {
26 while (type
->isPointerType()) {
27 type
= type
->getAs
<PointerType
>()->getPointeeType();
33 public RecursiveASTVisitor
<CStyleCast
>, public loplugin::Plugin
36 explicit CStyleCast(InstantiationData
const & data
):
37 Plugin(data
), externCFunction(false)
40 virtual void run() override
{
41 if (compiler
.getLangOpts().CPlusPlus
) {
42 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
46 bool TraverseFunctionDecl(FunctionDecl
* decl
);
48 bool VisitCStyleCastExpr(const CStyleCastExpr
* expr
);
54 static const char * recommendedFix(clang::CastKind ck
) {
56 case CK_IntegralToPointer
: return "reinterpret_cast";
57 case CK_PointerToIntegral
: return "reinterpret_cast";
58 case CK_BaseToDerived
: return "static_cast";
59 default: return "???";
63 bool CStyleCast::TraverseFunctionDecl(FunctionDecl
* decl
) {
64 bool ext
= hasCLanguageLinkageType(decl
)
65 && decl
->isThisDeclarationADefinition();
67 assert(!externCFunction
);
68 externCFunction
= true;
70 bool ret
= RecursiveASTVisitor::TraverseFunctionDecl(decl
);
72 externCFunction
= false;
77 bool CStyleCast::VisitCStyleCastExpr(const CStyleCastExpr
* expr
) {
78 if (ignoreLocation(expr
)) {
81 // casting to void is typically used when a parameter or field is only used in
82 // debug mode, and we want to eliminate an "unused" warning
83 if( expr
->getCastKind() == CK_ToVoid
) {
86 // ignore integral-type conversions for now, there is unsufficient agreement about
87 // the merits of C++ style casting in this case
88 if( expr
->getCastKind() == CK_IntegralCast
) {
91 if( expr
->getCastKind() == CK_NoOp
) {
92 QualType t1
= expr
->getSubExpr()->getType();
93 QualType t2
= expr
->getType();
94 if (t1
->isPointerType() && t2
->isPointerType()) {
95 t1
= t1
->getAs
<PointerType
>()->getPointeeType();
96 t2
= t2
->getAs
<PointerType
>()->getPointeeType();
97 } else if (t1
->isLValueReferenceType() && t2
->isLValueReferenceType()) {
98 t1
= t1
->getAs
<LValueReferenceType
>()->getPointeeType();
99 t2
= t2
->getAs
<LValueReferenceType
>()->getPointeeType();
103 if (expr
->getSubExprAsWritten()->getType() != expr
->getType()
104 && (!t1
.isMoreQualifiedThan(t2
)
105 || (t1
.getUnqualifiedType().getCanonicalType().getTypePtr()
106 != (t2
.getUnqualifiedType().getCanonicalType()
112 std::string incompFrom
;
113 std::string incompTo
;
114 if( expr
->getCastKind() == CK_BitCast
) {
115 if (resolvePointers(expr
->getSubExprAsWritten()->getType())
116 ->isIncompleteType())
118 incompFrom
= "incomplete ";
120 if (resolvePointers(expr
->getType())->isIncompleteType()) {
121 incompTo
= "incomplete ";
124 if (externCFunction
|| expr
->getLocStart().isMacroID()) {
125 SourceLocation spellingLocation
= compiler
.getSourceManager().getSpellingLoc(
126 expr
->getLocStart());
127 StringRef filename
= compiler
.getSourceManager().getFilename(spellingLocation
);
129 if ( filename
.endswith(".h") ) {
134 DiagnosticsEngine::Warning
,
135 "c-style cast, type=%0, from=%1%2, to=%3%4, recommendedFix=%5",
136 expr
->getSourceRange().getBegin())
137 << expr
->getCastKind()
138 << incompFrom
<< expr
->getSubExprAsWritten()->getType()
139 << incompTo
<< expr
->getType()
140 << recommendedFix(expr
->getCastKind())
141 << expr
->getSourceRange();
145 loplugin::Plugin::Registration
< CStyleCast
> X("cstylecast");
149 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */