bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / cstylecast.cxx
blobafbcacd9f15c1f14a6c2a47e7ec960481f7338d3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <cassert>
11 #include <string>
12 #include "plugin.hxx"
13 #include "compat.hxx"
16 // We don't like using C-style casts in C++ code
19 namespace {
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();
29 return type;
32 class CStyleCast:
33 public RecursiveASTVisitor<CStyleCast>, public loplugin::Plugin
35 public:
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);
50 private:
51 bool externCFunction;
54 static const char * recommendedFix(clang::CastKind ck) {
55 switch(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();
66 if (ext) {
67 assert(!externCFunction);
68 externCFunction = true;
70 bool ret = RecursiveASTVisitor::TraverseFunctionDecl(decl);
71 if (ext) {
72 externCFunction = false;
74 return ret;
77 bool CStyleCast::VisitCStyleCastExpr(const CStyleCastExpr * expr) {
78 if (ignoreLocation(expr)) {
79 return true;
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 ) {
84 return true;
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 ) {
89 return true;
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();
100 } else {
101 return true;
103 if (expr->getSubExprAsWritten()->getType() != expr->getType()
104 && (!t1.isMoreQualifiedThan(t2)
105 || (t1.getUnqualifiedType().getCanonicalType().getTypePtr()
106 != (t2.getUnqualifiedType().getCanonicalType()
107 .getTypePtr()))))
109 return true;
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);
128 // ignore C code
129 if ( filename.endswith(".h") ) {
130 return true;
133 report(
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();
142 return true;
145 loplugin::Plugin::Registration< CStyleCast > X("cstylecast");
149 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */