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/.
20 // We don't like using C-style casts in C++ code. Similarly, warn about function-style casts (which
21 // are semantically equivalent to C-style casts) that are not semantically equivalent to static_cast
22 // and should rather be written as const_cast or reinterpret_cast.
27 bool areSimilar(QualType type1
, QualType type2
) {
28 auto t1
= type1
.getCanonicalType().getTypePtr();
29 auto t2
= type2
.getCanonicalType().getTypePtr();
31 if (t1
->isPointerType()) {
32 if (!t2
->isPointerType()) {
35 auto t1a
= t1
->getAs
<clang::PointerType
>();
36 auto t2a
= t2
->getAs
<clang::PointerType
>();
37 t1
= t1a
->getPointeeType().getTypePtr();
38 t2
= t2a
->getPointeeType().getTypePtr();
39 } else if (t1
->isMemberPointerType()) {
40 if (!t2
->isMemberPointerType()) {
43 auto t1a
= t1
->getAs
<MemberPointerType
>();
44 auto t2a
= t2
->getAs
<MemberPointerType
>();
45 if (t1a
->getClass()->getCanonicalTypeInternal()
46 != t2a
->getClass()->getCanonicalTypeInternal())
50 t1
= t1a
->getPointeeType().getTypePtr();
51 t2
= t2a
->getPointeeType().getTypePtr();
52 } else if (t1
->isConstantArrayType()) {
53 if (!t2
->isConstantArrayType()) {
56 auto t1a
= static_cast<ConstantArrayType
const *>(
57 t1
->getAsArrayTypeUnsafe());
58 auto t2a
= static_cast<ConstantArrayType
const *>(
59 t2
->getAsArrayTypeUnsafe());
60 if (t1a
->getSize() != t2a
->getSize()) {
63 t1
= t1a
->getElementType().getTypePtr();
64 t2
= t2a
->getElementType().getTypePtr();
65 } else if (t1
->isIncompleteArrayType()) {
66 if (!t2
->isIncompleteArrayType()) {
69 auto t1a
= static_cast<IncompleteArrayType
const *>(
70 t1
->getAsArrayTypeUnsafe());
71 auto t2a
= static_cast<IncompleteArrayType
const *>(
72 t2
->getAsArrayTypeUnsafe());
73 t1
= t1a
->getElementType().getTypePtr();
74 t2
= t2a
->getElementType().getTypePtr();
84 QualType
resolvePointers(QualType type
) {
85 while (type
->isPointerType()) {
86 type
= type
->getAs
<clang::PointerType
>()->getPointeeType();
91 bool isLiteralLike(Expr
const * expr
) {
92 expr
= expr
->IgnoreParenImpCasts();
93 if (isa
<IntegerLiteral
>(expr
) || isa
<CharacterLiteral
>(expr
) || isa
<FloatingLiteral
>(expr
)
94 || isa
<ImaginaryLiteral
>(expr
) || isa
<CXXBoolLiteralExpr
>(expr
)
95 || isa
<CXXNullPtrLiteralExpr
>(expr
) || isa
<ObjCBoolLiteralExpr
>(expr
))
99 if (auto const e
= dyn_cast
<DeclRefExpr
>(expr
)) {
100 auto const d
= e
->getDecl();
101 if (isa
<EnumConstantDecl
>(d
)) {
104 if (auto const v
= dyn_cast
<VarDecl
>(d
)) {
105 if (d
->getType().isConstQualified()) {
106 if (auto const init
= v
->getAnyInitializer()) {
107 return isLiteralLike(init
);
113 if (auto const e
= dyn_cast
<UnaryExprOrTypeTraitExpr
>(expr
)) {
114 auto const k
= e
->getKind();
115 return k
== UETT_SizeOf
|| k
== UETT_AlignOf
;
117 if (auto const e
= dyn_cast
<UnaryOperator
>(expr
)) {
118 auto const k
= e
->getOpcode();
119 if (k
== UO_Plus
|| k
== UO_Minus
|| k
== UO_Not
|| k
== UO_LNot
) {
120 return isLiteralLike(e
->getSubExpr());
124 if (auto const e
= dyn_cast
<BinaryOperator
>(expr
)) {
125 auto const k
= e
->getOpcode();
126 if (k
== BO_Mul
|| k
== BO_Div
|| k
== BO_Rem
|| k
== BO_Add
|| k
== BO_Sub
|| k
== BO_Shl
127 || k
== BO_Shr
|| k
== BO_And
|| k
== BO_Xor
|| k
== BO_Or
)
129 return isLiteralLike(e
->getLHS()) && isLiteralLike(e
->getRHS());
133 if (auto const e
= dyn_cast
<ExplicitCastExpr
>(expr
)) {
134 auto const t
= e
->getTypeAsWritten();
135 return (t
->isArithmeticType() || t
->isEnumeralType())
136 && isLiteralLike(e
->getSubExprAsWritten());
141 bool canBeUsedForFunctionalCast(TypeSourceInfo
const * info
) {
142 // Must be <simple-type-specifier> or <typename-specifier>, lets approximate that here:
143 assert(info
!= nullptr);
144 auto const type
= info
->getType();
145 if (type
.hasLocalQualifiers()) {
148 if (auto const t
= dyn_cast
<BuiltinType
>(type
)) {
149 if (!(t
->isInteger() || t
->isFloatingPoint())) {
152 auto const loc
= info
->getTypeLoc().castAs
<BuiltinTypeLoc
>();
154 (int(loc
.hasWrittenSignSpec()) + int(loc
.hasWrittenWidthSpec())
155 + int(loc
.hasWrittenTypeSpec()))
158 if (isa
<TagType
>(type
) || isa
<TemplateTypeParmType
>(type
) || isa
<AutoType
>(type
)
159 || isa
<DecltypeType
>(type
) || isa
<TypedefType
>(type
))
163 if (auto const t
= dyn_cast
<ElaboratedType
>(type
)) {
164 return t
->getKeyword() == compat::ElaboratedTypeKeyword::None
;
170 public loplugin::FilteringRewritePlugin
<CStyleCast
>
173 explicit CStyleCast(loplugin::InstantiationData
const & data
): FilteringRewritePlugin(data
)
176 virtual void run() override
{
177 if (compiler
.getLangOpts().CPlusPlus
) {
178 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
182 bool TraverseInitListExpr(InitListExpr
* expr
, DataRecursionQueue
* queue
= nullptr) {
183 return WalkUpFromInitListExpr(expr
)
184 && TraverseSynOrSemInitListExpr(
185 expr
->isSemanticForm() ? expr
: expr
->getSemanticForm(), queue
);
188 bool TraverseLinkageSpecDecl(LinkageSpecDecl
* decl
);
190 bool VisitCStyleCastExpr(const CStyleCastExpr
* expr
);
192 bool VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr
const * expr
);
195 bool isConstCast(QualType from
, QualType to
);
197 bool isFromCIncludeFile(SourceLocation spellingLocation
) const;
199 bool isSharedCAndCppCode(SourceLocation location
) const;
201 bool isLastTokenOfImmediateMacroBodyExpansion(
202 SourceLocation loc
, SourceLocation
* macroEnd
= nullptr) const;
204 bool rewriteArithmeticCast(CStyleCastExpr
const * expr
, char const ** replacement
);
206 void reportCast(ExplicitCastExpr
const * expr
, char const * performsHint
);
208 unsigned int externCContexts_
= 0;
209 std::set
<SourceLocation
> rewritten_
;
210 // needed when rewriting in macros, in general to avoid "double code replacement, possible
211 // plugin error" warnings, and in particular to avoid adding multiple sets of parens around
213 std::set
<CStyleCastExpr
const *> rewrittenSubExprs_
;
216 const char * recommendedFix(clang::CastKind ck
) {
218 case CK_IntegralToPointer
: return "reinterpret_cast";
219 case CK_PointerToIntegral
: return "reinterpret_cast";
220 case CK_BaseToDerived
: return "static_cast";
221 default: return nullptr;
225 bool CStyleCast::TraverseLinkageSpecDecl(LinkageSpecDecl
* decl
) {
226 assert(externCContexts_
!= std::numeric_limits
<unsigned int>::max()); //TODO
228 bool ret
= RecursiveASTVisitor::TraverseLinkageSpecDecl(decl
);
229 assert(externCContexts_
!= 0);
234 bool CStyleCast::VisitCStyleCastExpr(const CStyleCastExpr
* expr
) {
235 if (ignoreLocation(expr
)) {
238 // casting to void is typically used when a parameter or field is only used in
239 // debug mode, and we want to eliminate an "unused" warning
240 if( expr
->getCastKind() == CK_ToVoid
) {
243 if (isSharedCAndCppCode(expr
->getBeginLoc())) {
246 char const * perf
= nullptr;
247 if( expr
->getCastKind() == CK_IntegralCast
) {
248 if (rewriteArithmeticCast(expr
, &perf
)) {
251 } else if( expr
->getCastKind() == CK_NoOp
) {
252 if (!((expr
->getSubExpr()->getType()->isPointerType()
253 && expr
->getType()->isPointerType())
254 || expr
->getTypeAsWritten()->isReferenceType()))
256 if (rewriteArithmeticCast(expr
, &perf
)) {
261 expr
->getSubExprAsWritten()->getType(),
262 expr
->getTypeAsWritten()))
267 reportCast(expr
, perf
);
271 bool CStyleCast::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr
const * expr
) {
272 if (ignoreLocation(expr
)) {
275 char const * perf
= nullptr;
276 switch (expr
->getCastKind()) {
277 case CK_ConstructorConversion
:
278 case CK_Dependent
: //TODO: really filter out all of these?
279 case CK_IntegralCast
:
280 case CK_IntegralToBoolean
:
285 expr
->getSubExprAsWritten()->getType(),
286 expr
->getTypeAsWritten()))
291 return true; //TODO: really filter out all of these?
295 reportCast(expr
, perf
);
299 bool CStyleCast::isConstCast(QualType from
, QualType to
) {
300 if (to
->isReferenceType()
301 && to
->getAs
<ReferenceType
>()->getPointeeType()->isObjectType())
303 if (!from
->isObjectType()) {
306 from
= compiler
.getASTContext().getPointerType(from
);
307 to
= compiler
.getASTContext().getPointerType(
308 to
->getAs
<ReferenceType
>()->getPointeeType());
310 if (from
->isArrayType()) {
311 from
= compiler
.getASTContext().getPointerType(
312 from
->getAsArrayTypeUnsafe()->getElementType());
313 } else if (from
->isFunctionType()) {
314 compiler
.getASTContext().getPointerType(from
);
317 return areSimilar(from
, to
);
320 bool CStyleCast::isFromCIncludeFile(SourceLocation spellingLocation
) const {
321 return !compiler
.getSourceManager().isInMainFile(spellingLocation
)
322 && compat::ends_with(
323 StringRef(compiler
.getSourceManager().getPresumedLoc(spellingLocation
).getFilename()),
327 bool CStyleCast::isSharedCAndCppCode(SourceLocation location
) const {
328 while (compiler
.getSourceManager().isMacroArgExpansion(location
)) {
329 location
= compiler
.getSourceManager().getImmediateMacroCallerLoc(
332 // Assume that code is intended to be shared between C and C++ if it comes
333 // from an include file ending in .h, and is either in an extern "C" context
334 // or the body of a macro definition:
336 isFromCIncludeFile(compiler
.getSourceManager().getSpellingLoc(location
))
337 && (externCContexts_
!= 0
338 || compiler
.getSourceManager().isMacroBodyExpansion(location
));
341 bool CStyleCast::isLastTokenOfImmediateMacroBodyExpansion(
342 SourceLocation loc
, SourceLocation
* macroEnd
) const
344 assert(compiler
.getSourceManager().isMacroBodyExpansion(loc
));
345 auto const spell
= compiler
.getSourceManager().getSpellingLoc(loc
);
346 auto name
= Lexer::getImmediateMacroName(
347 loc
, compiler
.getSourceManager(), compiler
.getLangOpts());
348 while (compat::starts_with(name
, "\\\n")) {
349 name
= name
.drop_front(2);
351 && (name
.front() == ' ' || name
.front() == '\t' || name
.front() == '\n'
352 || name
.front() == '\v' || name
.front() == '\f'))
354 name
= name
.drop_front(1);
358 = (compiler
.getPreprocessor().getMacroDefinitionAtLoc(
359 &compiler
.getASTContext().Idents
.get(name
), spell
)
361 assert(MI
!= nullptr);
362 if (spell
== MI
->getDefinitionEndLoc()) {
363 if (macroEnd
!= nullptr) {
364 *macroEnd
= compat::getImmediateExpansionRange(compiler
.getSourceManager(), loc
).second
;
371 bool CStyleCast::rewriteArithmeticCast(CStyleCastExpr
const * expr
, char const ** replacement
) {
372 assert(replacement
!= nullptr);
373 auto const sub
= expr
->getSubExprAsWritten();
374 auto const functional
= isLiteralLike(sub
)
375 && canBeUsedForFunctionalCast(expr
->getTypeInfoAsWritten());
376 *replacement
= functional
? "functional cast" : "static_cast";
377 if (rewriter
== nullptr) {
380 // Doing modifications for a chain of C-style casts as in
384 // leads to unpredictable results, so only rewrite them one at a time, starting with the
386 if (auto const e
= dyn_cast
<CStyleCastExpr
>(sub
)) {
387 rewrittenSubExprs_
.insert(e
);
389 if (rewrittenSubExprs_
.find(expr
) != rewrittenSubExprs_
.end()) {
392 // Two or four ranges to replace:
393 // First is the CStyleCast's LParen, plus following whitespace, replaced with either "" or
394 // "static_cast<". (TODO: insert space before "static_cast<" when converting "else(int)...".)
395 // Second is the CStyleCast's RParen, plus preceding and following whitespace, replaced with
397 // If the sub expr is not a ParenExpr, third is the sub expr's begin, inserting "(", and fourth
398 // is the sub expr's end, inserting ")".
399 // (The reason the second and third are not combined is in case there's a comment between them.)
400 auto firstBegin
= expr
->getLParenLoc();
401 auto secondBegin
= expr
->getRParenLoc();
402 while (compiler
.getSourceManager().isMacroArgExpansion(firstBegin
)
403 && compiler
.getSourceManager().isMacroArgExpansion(secondBegin
)
404 && (compat::getImmediateExpansionRange(compiler
.getSourceManager(), firstBegin
)
405 == compat::getImmediateExpansionRange(compiler
.getSourceManager(), secondBegin
)))
407 firstBegin
= compiler
.getSourceManager().getImmediateSpellingLoc(firstBegin
);
408 secondBegin
= compiler
.getSourceManager().getImmediateSpellingLoc(secondBegin
);
410 if (compiler
.getSourceManager().isMacroBodyExpansion(firstBegin
)
411 && compiler
.getSourceManager().isMacroBodyExpansion(secondBegin
)
412 && (compiler
.getSourceManager().getImmediateMacroCallerLoc(firstBegin
)
413 == compiler
.getSourceManager().getImmediateMacroCallerLoc(secondBegin
)))
415 firstBegin
= compiler
.getSourceManager().getSpellingLoc(firstBegin
);
416 secondBegin
= compiler
.getSourceManager().getSpellingLoc(secondBegin
);
418 auto third
= sub
->getBeginLoc();
419 auto fourth
= sub
->getEndLoc();
423 // #define FOO(x) (int)x
428 // #define FOO(x) static_cast<int>(x)
433 // #define FOO(x) static_cast<int>x
435 while (compiler
.getSourceManager().isMacroArgExpansion(third
)
436 && compiler
.getSourceManager().isMacroArgExpansion(fourth
)
437 && (compat::getImmediateExpansionRange(compiler
.getSourceManager(), third
)
438 == compat::getImmediateExpansionRange(compiler
.getSourceManager(), fourth
))
439 && compiler
.getSourceManager().isAtStartOfImmediateMacroExpansion(third
))
440 //TODO: check fourth is at end of immediate macro expansion, but
441 // SourceManager::isAtEndOfImmediateMacroExpansion requires a location pointing at the
442 // character end of the last token
444 auto const range
= compat::getImmediateExpansionRange(compiler
.getSourceManager(), third
);
446 fourth
= range
.second
;
448 assert(third
.isValid());
450 while (compiler
.getSourceManager().isMacroArgExpansion(third
)
451 && compiler
.getSourceManager().isMacroArgExpansion(fourth
)
452 && (compat::getImmediateExpansionRange(compiler
.getSourceManager(), third
)
453 == compat::getImmediateExpansionRange(compiler
.getSourceManager(), fourth
)))
455 third
= compiler
.getSourceManager().getImmediateSpellingLoc(third
);
456 fourth
= compiler
.getSourceManager().getImmediateSpellingLoc(fourth
);
458 if (isa
<ParenExpr
>(sub
)) {
469 // static_cast<int>(FOO)
473 // static_cast<int>FOO
474 for (;; macro
= true) {
475 if (!(compiler
.getSourceManager().isMacroBodyExpansion(third
)
476 && compiler
.getSourceManager().isMacroBodyExpansion(fourth
)
477 && (compiler
.getSourceManager().getImmediateMacroCallerLoc(third
)
478 == compiler
.getSourceManager().getImmediateMacroCallerLoc(fourth
))
479 && compiler
.getSourceManager().isAtStartOfImmediateMacroExpansion(third
)
480 && isLastTokenOfImmediateMacroBodyExpansion(fourth
)))
483 third
= fourth
= SourceLocation();
487 auto const range
= compat::getImmediateExpansionRange(
488 compiler
.getSourceManager(), third
);
490 fourth
= range
.second
;
491 assert(third
.isValid());
493 if (third
.isValid() && compiler
.getSourceManager().isMacroBodyExpansion(third
)
494 && compiler
.getSourceManager().isMacroBodyExpansion(fourth
)
495 && (compiler
.getSourceManager().getImmediateMacroCallerLoc(third
)
496 == compiler
.getSourceManager().getImmediateMacroCallerLoc(fourth
)))
498 third
= compiler
.getSourceManager().getSpellingLoc(third
);
499 fourth
= compiler
.getSourceManager().getSpellingLoc(fourth
);
500 assert(third
.isValid());
503 // Ensure that a cast like
507 // (where LONG_MAX expands to __LONG_MAX__, which in turn is a built-in expanding to a value
508 // like 9223372036854775807L) is changed to
512 // instead of trying to add the parentheses to the built-in __LONG_MAX__ definition:
514 if (!(compiler
.getSourceManager().isMacroBodyExpansion(third
)
515 && compiler
.getSourceManager().isMacroBodyExpansion(fourth
)
516 && (compiler
.getSourceManager().getImmediateMacroCallerLoc(third
)
517 == compiler
.getSourceManager().getImmediateMacroCallerLoc(fourth
))
518 && compiler
.getSourceManager().isAtStartOfImmediateMacroExpansion(third
)))
519 // TODO: check that fourth is at end of immediate macro expansion (but
520 // SourceManager::isAtEndOfImmediateMacroExpansion wants a location pointing at the
525 auto const range
= compat::getImmediateExpansionRange(
526 compiler
.getSourceManager(), third
);
528 fourth
= range
.second
;
530 // ...and additionally asymmetrically unwind macros only at the start or end, for code like
532 // (long)ubidi_getVisualIndex(...)
534 // (in editeng/source/editeng/impedit2.cxx) where ubidi_getVisualIndex is an object-like
537 // #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
539 // (in hwpfilter/source/lexer.cxx):
540 if (!fourth
.isMacroID()) {
541 while (compiler
.getSourceManager().isMacroBodyExpansion(third
)
542 && compiler
.getSourceManager().isAtStartOfImmediateMacroExpansion(third
, &third
))
544 } else if (compiler
.getSourceManager().isMacroBodyExpansion(fourth
)) {
545 while (compiler
.getSourceManager().isMacroArgExpansion(third
)
546 && compiler
.getSourceManager().isAtStartOfImmediateMacroExpansion(third
, &third
)) {}
548 if (!third
.isMacroID()) {
549 while (compiler
.getSourceManager().isMacroBodyExpansion(fourth
)
550 && isLastTokenOfImmediateMacroBodyExpansion(fourth
, &fourth
))
552 } else if (compiler
.getSourceManager().isMacroBodyExpansion(third
)) {
553 while (compiler
.getSourceManager().isMacroArgExpansion(fourth
, &fourth
)) {}
555 if (compiler
.getSourceManager().isMacroBodyExpansion(third
)
556 && compiler
.getSourceManager().isMacroBodyExpansion(fourth
)
557 && (compiler
.getSourceManager().getImmediateMacroCallerLoc(third
)
558 == compiler
.getSourceManager().getImmediateMacroCallerLoc(fourth
)))
560 third
= compiler
.getSourceManager().getSpellingLoc(third
);
561 fourth
= compiler
.getSourceManager().getSpellingLoc(fourth
);
563 assert(third
.isValid());
565 if (firstBegin
.isMacroID() || secondBegin
.isMacroID() || (third
.isValid() && third
.isMacroID())
566 || (fourth
.isValid() && fourth
.isMacroID()))
570 DiagnosticsEngine::Fatal
,
571 "TODO: cannot rewrite C-style cast in macro, needs investigation",
573 << expr
->getSourceRange();
577 unsigned firstLen
= Lexer::MeasureTokenLength(
578 firstBegin
, compiler
.getSourceManager(), compiler
.getLangOpts());
579 for (auto l
= firstBegin
.getLocWithOffset(std::max
<unsigned>(firstLen
, 1));;
580 l
= l
.getLocWithOffset(1))
582 unsigned n
= Lexer::MeasureTokenLength(
583 l
, compiler
.getSourceManager(), compiler
.getLangOpts());
589 unsigned secondLen
= Lexer::MeasureTokenLength(
590 secondBegin
, compiler
.getSourceManager(), compiler
.getLangOpts());
591 for (auto l
= secondBegin
.getLocWithOffset(std::max
<unsigned>(secondLen
, 1));;
592 l
= l
.getLocWithOffset(1))
594 unsigned n
= Lexer::MeasureTokenLength(
595 l
, compiler
.getSourceManager(), compiler
.getLangOpts());
602 auto l
= secondBegin
.getLocWithOffset(-1);
603 auto const c
= compiler
.getSourceManager().getCharacterData(l
)[0];
605 if (compiler
.getSourceManager().getCharacterData(l
.getLocWithOffset(-1))[0] == '\\') {
608 } else if (!(c
== ' ' || c
== '\t' || c
== '\v' || c
== '\f')) {
614 if (rewritten_
.insert(firstBegin
).second
) {
615 if (!replaceText(firstBegin
, firstLen
, functional
? "" : "static_cast<")) {
618 DiagnosticsEngine::Fatal
, "TODO: cannot rewrite #1, needs investigation",
621 DiagnosticsEngine::Note
, "when rewriting this C-style cast", expr
->getExprLoc())
622 << expr
->getSourceRange();
626 if (!replaceText(secondBegin
, secondLen
, functional
? "" : ">")) {
630 DiagnosticsEngine::Fatal
, "TODO: cannot rewrite #2, needs investigation",
633 DiagnosticsEngine::Note
, "when rewriting this C-style cast", expr
->getExprLoc())
634 << expr
->getSourceRange();
639 if (third
.isValid()) {
640 if (rewritten_
.insert(third
).second
) {
641 if (!insertTextBefore(third
, "(")) {
645 DiagnosticsEngine::Fatal
, "TODO: cannot rewrite #3, needs investigation",
648 DiagnosticsEngine::Note
, "when rewriting this C-style cast",
650 << expr
->getSourceRange();
654 if (!insertTextAfterToken(fourth
, ")")) {
658 DiagnosticsEngine::Fatal
, "TODO: cannot rewrite #4, needs investigation",
661 DiagnosticsEngine::Note
, "when rewriting this C-style cast",
663 << expr
->getSourceRange();
672 void CStyleCast::reportCast(ExplicitCastExpr
const * expr
, char const * performsHint
) {
673 std::string incompFrom
;
674 std::string incompTo
;
675 if( expr
->getCastKind() == CK_BitCast
) {
676 if (resolvePointers(expr
->getSubExprAsWritten()->getType())
677 ->isIncompleteType())
679 incompFrom
= "incomplete ";
681 if (resolvePointers(expr
->getType())->isIncompleteType()) {
682 incompTo
= "incomplete ";
685 if (performsHint
== nullptr) {
686 performsHint
= recommendedFix(expr
->getCastKind());
688 std::string performs
;
689 if (performsHint
!= nullptr) {
690 performs
= std::string(" (performs: ") + performsHint
+ ")";
693 DiagnosticsEngine::Warning
, "%select{C|Function}0-style cast from %1%2 to %3%4%5 (%6)",
694 expr
->getSourceRange().getBegin())
695 << isa
<CXXFunctionalCastExpr
>(expr
)
696 << incompFrom
<< expr
->getSubExprAsWritten()->getType()
697 << incompTo
<< expr
->getTypeAsWritten() << performs
698 << expr
->getCastKindName()
699 << expr
->getSourceRange();
702 loplugin::Plugin::Registration
< CStyleCast
> X("cstylecast", true);
706 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */