bump product version to 6.3.0.0.beta1
[LibreOffice.git] / compilerplugins / clang / redundantfcast.cxx
blob43049700ee35c3ef8635bef71bfdabe2e03db1a3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 "check.hxx"
11 #include "compat.hxx"
12 #include "plugin.hxx"
13 #include <iostream>
14 #include <fstream>
16 namespace
18 class RedundantFCast final : public loplugin::FilteringPlugin<RedundantFCast>
20 public:
21 explicit RedundantFCast(loplugin::InstantiationData const& data)
22 : FilteringPlugin(data)
26 bool TraverseFunctionDecl(FunctionDecl* functionDecl)
28 auto prev = m_CurrentFunctionDecl;
29 m_CurrentFunctionDecl = functionDecl;
30 auto rv = RecursiveASTVisitor<RedundantFCast>::TraverseFunctionDecl(functionDecl);
31 m_CurrentFunctionDecl = prev;
32 return rv;
35 bool VisitReturnStmt(ReturnStmt const* returnStmt)
37 if (ignoreLocation(returnStmt))
38 return true;
39 Expr const* expr = returnStmt->getRetValue();
40 if (!expr)
41 return true;
42 if (auto exprWithCleanups = dyn_cast<ExprWithCleanups>(expr))
43 expr = exprWithCleanups->getSubExpr();
44 if (auto cxxConstructExpr = dyn_cast<CXXConstructExpr>(expr))
46 if (cxxConstructExpr->getNumArgs() != 1)
47 return true;
48 expr = cxxConstructExpr->getArg(0);
50 if (auto materializeTemporaryExpr = dyn_cast<MaterializeTemporaryExpr>(expr))
51 expr = materializeTemporaryExpr->GetTemporaryExpr();
52 auto cxxFunctionalCastExpr = dyn_cast<CXXFunctionalCastExpr>(expr);
53 if (!cxxFunctionalCastExpr)
54 return true;
55 auto const t1 = cxxFunctionalCastExpr->getTypeAsWritten();
56 auto const t2 = compat::getSubExprAsWritten(cxxFunctionalCastExpr)->getType();
57 if (t1.getCanonicalType().getTypePtr() != t2.getCanonicalType().getTypePtr())
58 return true;
59 if (!loplugin::isOkToRemoveArithmeticCast(compiler.getASTContext(), t1, t2,
60 cxxFunctionalCastExpr->getSubExpr()))
62 return true;
64 report(DiagnosticsEngine::Warning, "redundant functional cast from %0 to %1",
65 cxxFunctionalCastExpr->getExprLoc())
66 << t2 << t1 << cxxFunctionalCastExpr->getSourceRange();
67 return true;
70 /* Check for the creation of unnecessary temporaries when calling a method that takes a param by const & */
71 bool VisitCallExpr(CallExpr const* callExpr)
73 if (ignoreLocation(callExpr))
74 return true;
75 const FunctionDecl* functionDecl;
76 if (isa<CXXMemberCallExpr>(callExpr))
77 functionDecl = dyn_cast<CXXMemberCallExpr>(callExpr)->getMethodDecl();
78 else
79 functionDecl = callExpr->getDirectCallee();
80 if (!functionDecl)
81 return true;
83 unsigned len = std::min(callExpr->getNumArgs(), functionDecl->getNumParams());
84 for (unsigned i = 0; i < len; ++i)
86 // check if param is const&
87 auto param = functionDecl->getParamDecl(i);
88 auto lvalueType = param->getType()->getAs<LValueReferenceType>();
89 if (!lvalueType)
90 continue;
91 if (!lvalueType->getPointeeType().isConstQualified())
92 continue;
93 auto paramClassOrStructType = lvalueType->getPointeeType()->getAs<RecordType>();
94 if (!paramClassOrStructType)
95 continue;
96 // check for temporary and functional cast in argument expression
97 auto arg = callExpr->getArg(i)->IgnoreImpCasts();
98 auto materializeTemporaryExpr = dyn_cast<MaterializeTemporaryExpr>(arg);
99 if (!materializeTemporaryExpr)
100 continue;
101 auto functionalCast = dyn_cast<CXXFunctionalCastExpr>(
102 materializeTemporaryExpr->GetTemporaryExpr()->IgnoreImpCasts());
103 if (!functionalCast)
104 continue;
105 auto const t1 = functionalCast->getTypeAsWritten();
106 auto const t2 = compat::getSubExprAsWritten(functionalCast)->getType();
107 if (t1.getCanonicalType().getTypePtr() != t2.getCanonicalType().getTypePtr())
108 continue;
109 // Check that the underlying expression is of the same class/struct type as the param i.e. that we are not instantiating
110 // something useful
111 if (t1.getCanonicalType().getTypePtr() != paramClassOrStructType)
112 continue;
114 report(DiagnosticsEngine::Warning, "redundant functional cast from %0 to %1",
115 arg->getExprLoc())
116 << t2 << t1 << arg->getSourceRange();
117 report(DiagnosticsEngine::Note, "in call to method here", param->getLocation())
118 << param->getSourceRange();
120 return true;
123 /* Check for the creation of unnecessary temporaries when calling a constructor that takes a param by const & */
124 bool VisitCXXConstructExpr(CXXConstructExpr const* callExpr)
126 if (ignoreLocation(callExpr))
127 return true;
128 const CXXConstructorDecl* functionDecl = callExpr->getConstructor();
130 unsigned len = std::min(callExpr->getNumArgs(), functionDecl->getNumParams());
131 for (unsigned i = 0; i < len; ++i)
133 // check if param is const&
134 auto param = functionDecl->getParamDecl(i);
135 auto lvalueType = param->getType()->getAs<LValueReferenceType>();
136 if (!lvalueType)
137 continue;
138 if (!lvalueType->getPointeeType().isConstQualified())
139 continue;
140 auto paramClassOrStructType = lvalueType->getPointeeType()->getAs<RecordType>();
141 if (!paramClassOrStructType)
142 continue;
143 // check for temporary and functional cast in argument expression
144 auto arg = callExpr->getArg(i)->IgnoreImplicit();
145 auto functionalCast = dyn_cast<CXXFunctionalCastExpr>(arg);
146 if (!functionalCast)
147 continue;
148 auto const t1 = functionalCast->getTypeAsWritten();
149 auto const t2 = compat::getSubExprAsWritten(functionalCast)->getType();
150 if (t1.getCanonicalType().getTypePtr() != t2.getCanonicalType().getTypePtr())
151 continue;
152 // Check that the underlying expression is of the same class/struct type as the param i.e. that we are not instantiating
153 // something useful
154 if (t1.getCanonicalType().getTypePtr() != paramClassOrStructType)
155 continue;
157 report(DiagnosticsEngine::Warning, "redundant functional cast from %0 to %1",
158 arg->getExprLoc())
159 << t2 << t1 << arg->getSourceRange();
160 report(DiagnosticsEngine::Note, "in call to method here", param->getLocation())
161 << param->getSourceRange();
163 return true;
166 bool VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr const* expr)
168 if (ignoreLocation(expr))
169 return true;
170 // specifying the name for an init-list is necessary sometimes
171 if (isa<InitListExpr>(expr->getSubExpr()->IgnoreImplicit()))
172 return true;
173 if (isa<CXXStdInitializerListExpr>(expr->getSubExpr()->IgnoreImplicit()))
174 return true;
175 auto const t1 = expr->getTypeAsWritten();
176 auto const t2 = compat::getSubExprAsWritten(expr)->getType();
177 if (t1.getCanonicalType().getTypePtr() != t2.getCanonicalType().getTypePtr())
179 return true;
181 // (a) we do a lot of int/sal_Int32 kind of casts which might be platform necessary?
182 // (b) we do bool/bool casts in unit tests to avoid one of the other plugins
183 // so just ignore this kind of thing for now
184 if (const auto* BT = dyn_cast<BuiltinType>(t1->getUnqualifiedDesugaredType()))
186 auto k = BT->getKind();
187 if (k == BuiltinType::Double || k == BuiltinType::Float
188 || (k >= BuiltinType::Bool && k <= BuiltinType::Int128))
189 return true;
191 if (const auto* BT = dyn_cast<BuiltinType>(t2->getUnqualifiedDesugaredType()))
193 auto k = BT->getKind();
194 if (k == BuiltinType::Double || k == BuiltinType::Float
195 || (k >= BuiltinType::Bool && k <= BuiltinType::Int128))
196 return true;
198 auto tc = loplugin::TypeCheck(t1);
199 if (tc.Typedef("sal_Int32").GlobalNamespace())
200 return true;
202 report(DiagnosticsEngine::Warning, "redundant functional cast from %0 to %1",
203 expr->getExprLoc())
204 << t2 << t1 << expr->getSourceRange();
205 //getParentStmt(expr)->dump();
206 return true;
209 private:
210 void run() override
212 if (!compiler.getLangOpts().CPlusPlus)
213 return;
214 std::string fn = handler.getMainFileName();
215 loplugin::normalizeDotDotInFilePath(fn);
216 // necessary on some other platforms
217 if (fn == SRCDIR "/sal/osl/unx/socket.cxx")
218 return;
219 // compile-time check of constant
220 if (fn == SRCDIR "/bridges/source/jni_uno/jni_bridge.cxx")
221 return;
222 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
224 FunctionDecl const* m_CurrentFunctionDecl;
227 static loplugin::Plugin::Registration<RedundantFCast> reg("redundantfcast");
230 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */