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/.
13 #include "clang/Lex/Lexer.h"
20 class LiteralToBoolConversion
:
21 public loplugin::FilteringRewritePlugin
<LiteralToBoolConversion
>
24 explicit LiteralToBoolConversion(loplugin::InstantiationData
const & data
):
25 FilteringRewritePlugin(data
) {}
27 virtual void run() override
28 { TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
30 bool VisitImplicitCastExpr(ImplicitCastExpr
const * expr
);
32 bool TraverseLinkageSpecDecl(LinkageSpecDecl
* decl
);
35 bool isFromCIncludeFile(SourceLocation spellingLocation
) const;
37 bool isSharedCAndCppCode(SourceLocation location
) const;
39 void handleImplicitCastSubExpr(
40 ImplicitCastExpr
const * castExpr
, Expr
const * subExpr
);
42 unsigned int externCContexts_
= 0;
45 bool LiteralToBoolConversion::VisitImplicitCastExpr(
46 ImplicitCastExpr
const * expr
)
48 if (ignoreLocation(expr
)) {
51 if (!expr
->getType()->isBooleanType()) {
54 handleImplicitCastSubExpr(expr
, expr
->getSubExpr());
58 bool LiteralToBoolConversion::TraverseLinkageSpecDecl(LinkageSpecDecl
* decl
) {
59 assert(externCContexts_
!= std::numeric_limits
<unsigned int>::max()); //TODO
61 bool ret
= RecursiveASTVisitor::TraverseLinkageSpecDecl(decl
);
62 assert(externCContexts_
!= 0);
67 bool LiteralToBoolConversion::isFromCIncludeFile(
68 SourceLocation spellingLocation
) const
70 return !compiler
.getSourceManager().isInMainFile(spellingLocation
)
72 compiler
.getSourceManager().getPresumedLoc(spellingLocation
)
77 bool LiteralToBoolConversion::isSharedCAndCppCode(SourceLocation location
) const
79 // Assume that code is intended to be shared between C and C++ if it comes
80 // from an include file ending in .h, and is either in an extern "C" context
81 // or the body of a macro definition:
83 isFromCIncludeFile(compiler
.getSourceManager().getSpellingLoc(location
))
84 && (externCContexts_
!= 0
85 || compiler
.getSourceManager().isMacroBodyExpansion(location
));
88 void LiteralToBoolConversion::handleImplicitCastSubExpr(
89 ImplicitCastExpr
const * castExpr
, Expr
const * subExpr
)
91 Expr
const * expr2
= subExpr
;
92 // track sub-expr with potential parens, to e.g. rewrite all of expanded
94 // #define sal_False ((sal_Bool)0)
96 // including the parens
97 subExpr
= expr2
->IgnoreParenCasts();
99 BinaryOperator
const * op
= dyn_cast
<BinaryOperator
>(subExpr
);
100 if (op
== nullptr || op
->getOpcode() != BO_Comma
) {
103 expr2
= op
->getRHS();
104 subExpr
= expr2
->IgnoreParenCasts();
106 if (subExpr
->getType()->isBooleanType()) {
109 ConditionalOperator
const * op
= dyn_cast
<ConditionalOperator
>(subExpr
);
111 handleImplicitCastSubExpr(castExpr
, op
->getTrueExpr());
112 handleImplicitCastSubExpr(castExpr
, op
->getFalseExpr());
116 if (!subExpr
->isValueDependent()
117 && subExpr
->isIntegerConstantExpr(res
, compiler
.getASTContext())
118 && res
.getLimitedValue() <= 1)
120 SourceLocation loc
{ compat::getBeginLoc(subExpr
) };
121 while (compiler
.getSourceManager().isMacroArgExpansion(loc
)) {
122 loc
= compiler
.getSourceManager().getImmediateMacroCallerLoc(loc
);
124 if (compiler
.getSourceManager().isMacroBodyExpansion(loc
)) {
125 StringRef name
{ Lexer::getImmediateMacroName(
126 loc
, compiler
.getSourceManager(), compiler
.getLangOpts()) };
127 if (name
== "sal_False" || name
== "sal_True") {
128 loc
= compat::getImmediateExpansionRange(compiler
.getSourceManager(), loc
).first
;
130 if (isSharedCAndCppCode(loc
)) {
135 if (isa
<clang::StringLiteral
>(subExpr
)) {
136 SourceLocation loc
{ compat::getBeginLoc(subExpr
) };
137 if (compiler
.getSourceManager().isMacroArgExpansion(loc
)
138 && (Lexer::getImmediateMacroName(
139 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
145 if (isa
<IntegerLiteral
>(subExpr
) || isa
<CharacterLiteral
>(subExpr
)
146 || isa
<FloatingLiteral
>(subExpr
) || isa
<ImaginaryLiteral
>(subExpr
)
147 || isa
<clang::StringLiteral
>(subExpr
))
149 bool bRewritten
= false;
150 if (rewriter
!= nullptr) {
151 SourceLocation loc
{ compiler
.getSourceManager().getExpansionLoc(
152 compat::getBeginLoc(expr2
)) };
153 if (compiler
.getSourceManager().getExpansionLoc(compat::getEndLoc(expr2
))
156 char const * s
= compiler
.getSourceManager().getCharacterData(
158 unsigned n
= Lexer::MeasureTokenLength(
159 compat::getEndLoc(expr2
), compiler
.getSourceManager(),
160 compiler
.getLangOpts());
161 std::string tok
{ s
, n
};
162 if (tok
== "sal_False" || tok
== "0") {
163 bRewritten
= replaceText(
164 compiler
.getSourceManager().getExpansionLoc(
165 compat::getBeginLoc(expr2
)),
167 } else if (tok
== "sal_True" || tok
== "1") {
168 bRewritten
= replaceText(
169 compiler
.getSourceManager().getExpansionLoc(
170 compat::getBeginLoc(expr2
)),
177 DiagnosticsEngine::Warning
,
178 "implicit conversion (%0) of literal of type %1 to %2",
179 compat::getBeginLoc(expr2
))
180 << castExpr
->getCastKindName() << subExpr
->getType()
181 << castExpr
->getType() << expr2
->getSourceRange();
183 } else if (subExpr
->isNullPointerConstant(
184 compiler
.getASTContext(), Expr::NPC_ValueDependentIsNull
)
185 > Expr::NPCK_ZeroExpression
)
187 // The test above originally checked for != Expr::NPCK_NotNull, but in non-C++11
188 // mode we can get also Expr::NPCK_ZeroExpression inside templates, even though
189 // the expression is actually not a null pointer. Clang bug or C++98 misfeature?
190 // See Clang's NPCK_ZeroExpression declaration and beginning of isNullPointerConstant().
191 static_assert( Expr::NPCK_NotNull
== 0 && Expr::NPCK_ZeroExpression
== 1, "Clang API change" );
193 DiagnosticsEngine::Warning
,
194 ("implicit conversion (%0) of null pointer constant of type %1 to"
196 compat::getBeginLoc(expr2
))
197 << castExpr
->getCastKindName() << subExpr
->getType()
198 << castExpr
->getType() << expr2
->getSourceRange();
199 } else if (!subExpr
->isValueDependent()
200 && subExpr
->isIntegerConstantExpr(res
, compiler
.getASTContext()))
203 DiagnosticsEngine::Warning
,
204 ("implicit conversion (%0) of integer constant expression of type"
205 " %1 with value %2 to %3"),
206 compat::getBeginLoc(expr2
))
207 << castExpr
->getCastKindName() << subExpr
->getType()
208 << res
.toString(10) << castExpr
->getType()
209 << expr2
->getSourceRange();
213 loplugin::Plugin::Registration
<LiteralToBoolConversion
> X(
214 "literaltoboolconversion", true);