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/.
10 #include "clang/Lex/Lexer.h"
17 class LiteralToBoolConversion
:
18 public RecursiveASTVisitor
<LiteralToBoolConversion
>,
19 public loplugin::RewritePlugin
22 explicit LiteralToBoolConversion(InstantiationData
const & data
):
23 RewritePlugin(data
) {}
25 virtual void run() override
26 { TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
28 bool VisitImplicitCastExpr(ImplicitCastExpr
const * expr
);
31 bool isFromCIncludeFile(SourceLocation spellingLocation
) const;
33 void handleImplicitCastSubExpr(
34 ImplicitCastExpr
const * castExpr
, Expr
const * subExpr
);
37 bool LiteralToBoolConversion::VisitImplicitCastExpr(
38 ImplicitCastExpr
const * expr
)
40 if (ignoreLocation(expr
)) {
43 if (!expr
->getType()->isBooleanType()) {
46 handleImplicitCastSubExpr(expr
, expr
->getSubExpr());
50 bool LiteralToBoolConversion::isFromCIncludeFile(
51 SourceLocation spellingLocation
) const
53 return !compat::isInMainFile(compiler
.getSourceManager(), spellingLocation
)
55 compiler
.getSourceManager().getPresumedLoc(spellingLocation
)
60 void LiteralToBoolConversion::handleImplicitCastSubExpr(
61 ImplicitCastExpr
const * castExpr
, Expr
const * subExpr
)
63 Expr
const * expr2
= subExpr
;
64 // track sub-expr with potential parens, to e.g. rewrite all of expanded
66 // #define sal_False ((sal_Bool)0)
68 // including the parens
69 subExpr
= expr2
->IgnoreParenCasts();
71 BinaryOperator
const * op
= dyn_cast
<BinaryOperator
>(subExpr
);
72 if (op
== nullptr || op
->getOpcode() != BO_Comma
) {
76 subExpr
= expr2
->IgnoreParenCasts();
78 if (subExpr
->getType()->isBooleanType()) {
81 ConditionalOperator
const * op
= dyn_cast
<ConditionalOperator
>(subExpr
);
83 handleImplicitCastSubExpr(castExpr
, op
->getTrueExpr());
84 handleImplicitCastSubExpr(castExpr
, op
->getFalseExpr());
88 if (!subExpr
->isValueDependent()
89 && subExpr
->isIntegerConstantExpr(res
, compiler
.getASTContext())
90 && res
.getLimitedValue() <= 1)
92 SourceLocation loc
{ subExpr
->getLocStart() };
93 while (compiler
.getSourceManager().isMacroArgExpansion(loc
)) {
94 loc
= compiler
.getSourceManager().getImmediateMacroCallerLoc(loc
);
96 if (compat::isMacroBodyExpansion(compiler
, loc
)) {
97 StringRef name
{ Lexer::getImmediateMacroName(
98 loc
, compiler
.getSourceManager(), compiler
.getLangOpts()) };
99 if (name
== "sal_False" || name
== "sal_True") {
100 loc
= compiler
.getSourceManager().getImmediateExpansionRange(
103 if (isFromCIncludeFile(
104 compiler
.getSourceManager().getSpellingLoc(loc
)))
110 if (isa
<StringLiteral
>(subExpr
)) {
111 SourceLocation loc
{ subExpr
->getLocStart() };
112 if (compiler
.getSourceManager().isMacroArgExpansion(loc
)
113 && (Lexer::getImmediateMacroName(
114 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
120 if (isa
<IntegerLiteral
>(subExpr
) || isa
<CharacterLiteral
>(subExpr
)
121 || isa
<FloatingLiteral
>(subExpr
) || isa
<ImaginaryLiteral
>(subExpr
)
122 || isa
<StringLiteral
>(subExpr
))
124 bool rewritten
= false;
125 if (rewriter
!= nullptr) {
126 SourceLocation loc
{ compiler
.getSourceManager().getExpansionLoc(
127 expr2
->getLocStart()) };
128 if (compiler
.getSourceManager().getExpansionLoc(expr2
->getLocEnd())
131 char const * s
= compiler
.getSourceManager().getCharacterData(
133 unsigned n
= Lexer::MeasureTokenLength(
134 expr2
->getLocEnd(), compiler
.getSourceManager(),
135 compiler
.getLangOpts());
136 std::string tok
{ s
, n
};
137 if (tok
== "sal_False" || tok
== "0") {
138 rewritten
= replaceText(
139 compiler
.getSourceManager().getExpansionLoc(
140 expr2
->getLocStart()),
142 } else if (tok
== "sal_True" || tok
== "1") {
143 rewritten
= replaceText(
144 compiler
.getSourceManager().getExpansionLoc(
145 expr2
->getLocStart()),
152 DiagnosticsEngine::Warning
,
153 "implicit conversion (%0) of literal of type %1 to %2",
154 expr2
->getLocStart())
155 << castExpr
->getCastKindName() << subExpr
->getType()
156 << castExpr
->getType() << expr2
->getSourceRange();
158 } else if (subExpr
->isNullPointerConstant(
159 compiler
.getASTContext(), Expr::NPC_ValueDependentIsNull
)
160 > Expr::NPCK_ZeroExpression
)
162 // The test above originally checked for != Expr::NPCK_NotNull, but in non-C++11
163 // mode we can get also Expr::NPCK_ZeroExpression inside templates, even though
164 // the expression is actually not a null pointer. Clang bug or C++98 misfeature?
165 // See Clang's NPCK_ZeroExpression declaration and beginning of isNullPointerConstant().
166 static_assert( Expr::NPCK_NotNull
== 0 && Expr::NPCK_ZeroExpression
== 1, "Clang API change" );
168 DiagnosticsEngine::Warning
,
169 ("implicit conversion (%0) of null pointer constant of type %1 to"
171 expr2
->getLocStart())
172 << castExpr
->getCastKindName() << subExpr
->getType()
173 << castExpr
->getType() << expr2
->getSourceRange();
174 } else if (!subExpr
->isValueDependent()
175 && subExpr
->isIntegerConstantExpr(res
, compiler
.getASTContext()))
178 DiagnosticsEngine::Warning
,
179 ("implicit conversion (%0) of integer constant expression of type"
180 " %1 with value %2 to %3"),
181 expr2
->getLocStart())
182 << castExpr
->getCastKindName() << subExpr
->getType()
183 << res
.toString(10) << castExpr
->getType()
184 << expr2
->getSourceRange();
188 loplugin::Plugin::Registration
<LiteralToBoolConversion
> X(
189 "literaltoboolconversion", true);