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/.
9 #ifndef LO_CLANG_SHARED_PLUGINS
14 #include "clang/Lex/Lexer.h"
21 class LiteralToBoolConversion
:
22 public loplugin::FilteringRewritePlugin
<LiteralToBoolConversion
>
25 explicit LiteralToBoolConversion(loplugin::InstantiationData
const & data
):
26 FilteringRewritePlugin(data
) {}
28 virtual void run() override
29 { TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
31 bool VisitImplicitCastExpr(ImplicitCastExpr
const * expr
);
33 bool PreTraverseLinkageSpecDecl(LinkageSpecDecl
* decl
);
34 bool PostTraverseLinkageSpecDecl(LinkageSpecDecl
* decl
, bool);
35 bool TraverseLinkageSpecDecl(LinkageSpecDecl
* decl
);
38 bool isFromCIncludeFile(SourceLocation spellingLocation
) const;
40 bool isSharedCAndCppCode(SourceLocation location
) const;
42 void handleImplicitCastSubExpr(
43 ImplicitCastExpr
const * castExpr
, Expr
const * subExpr
);
45 unsigned int externCContexts_
= 0;
48 bool LiteralToBoolConversion::VisitImplicitCastExpr(
49 ImplicitCastExpr
const * expr
)
51 if (ignoreLocation(expr
)) {
54 if (!expr
->getType()->isBooleanType()) {
57 handleImplicitCastSubExpr(expr
, expr
->getSubExpr());
61 bool LiteralToBoolConversion::PreTraverseLinkageSpecDecl(LinkageSpecDecl
*) {
62 assert(externCContexts_
!= std::numeric_limits
<unsigned int>::max()); //TODO
67 bool LiteralToBoolConversion::PostTraverseLinkageSpecDecl(LinkageSpecDecl
*, bool) {
68 assert(externCContexts_
!= 0);
73 bool LiteralToBoolConversion::TraverseLinkageSpecDecl(LinkageSpecDecl
* decl
) {
74 PreTraverseLinkageSpecDecl(decl
);
75 bool ret
= RecursiveASTVisitor::TraverseLinkageSpecDecl(decl
);
76 PostTraverseLinkageSpecDecl(decl
, ret
);
80 bool LiteralToBoolConversion::isFromCIncludeFile(
81 SourceLocation spellingLocation
) const
83 return !compiler
.getSourceManager().isInMainFile(spellingLocation
)
85 StringRef(compiler
.getSourceManager().getPresumedLoc(spellingLocation
).getFilename()),
89 bool LiteralToBoolConversion::isSharedCAndCppCode(SourceLocation location
) const
91 // Assume that code is intended to be shared between C and C++ if it comes
92 // from an include file ending in .h, and is either in an extern "C" context
93 // or the body of a macro definition:
95 isFromCIncludeFile(compiler
.getSourceManager().getSpellingLoc(location
))
96 && (externCContexts_
!= 0
97 || compiler
.getSourceManager().isMacroBodyExpansion(location
));
100 void LiteralToBoolConversion::handleImplicitCastSubExpr(
101 ImplicitCastExpr
const * castExpr
, Expr
const * subExpr
)
103 Expr
const * expr2
= subExpr
;
104 // track sub-expr with potential parens, to e.g. rewrite all of expanded
106 // #define sal_False ((sal_Bool)0)
108 // including the parens
109 subExpr
= expr2
->IgnoreParenCasts();
111 BinaryOperator
const * op
= dyn_cast
<BinaryOperator
>(subExpr
);
112 if (op
== nullptr || op
->getOpcode() != BO_Comma
) {
115 expr2
= op
->getRHS();
116 subExpr
= expr2
->IgnoreParenCasts();
118 if (subExpr
->getType()->isBooleanType()) {
121 ConditionalOperator
const * op
= dyn_cast
<ConditionalOperator
>(subExpr
);
123 handleImplicitCastSubExpr(castExpr
, op
->getTrueExpr());
124 handleImplicitCastSubExpr(castExpr
, op
->getFalseExpr());
127 if (!subExpr
->isValueDependent()) {
128 if (auto const res
= subExpr
->getIntegerConstantExpr(compiler
.getASTContext())) {
129 if (res
->getLimitedValue() <= 1)
131 SourceLocation loc
{ subExpr
->getBeginLoc() };
132 while (compiler
.getSourceManager().isMacroArgExpansion(loc
)) {
133 loc
= compiler
.getSourceManager().getImmediateMacroCallerLoc(loc
);
135 if (compiler
.getSourceManager().isMacroBodyExpansion(loc
)) {
136 StringRef name
{ Lexer::getImmediateMacroName(
137 loc
, compiler
.getSourceManager(), compiler
.getLangOpts()) };
138 if (name
== "sal_False" || name
== "sal_True") {
139 loc
= compat::getImmediateExpansionRange(compiler
.getSourceManager(), loc
)
142 if (isSharedCAndCppCode(loc
)) {
149 if (isa
<clang::StringLiteral
>(subExpr
)) {
150 SourceLocation loc
{ subExpr
->getBeginLoc() };
151 if (compiler
.getSourceManager().isMacroArgExpansion(loc
)
152 && (Lexer::getImmediateMacroName(
153 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
159 if (isa
<IntegerLiteral
>(subExpr
) || isa
<CharacterLiteral
>(subExpr
)
160 || isa
<FloatingLiteral
>(subExpr
) || isa
<ImaginaryLiteral
>(subExpr
)
161 || isa
<clang::StringLiteral
>(subExpr
))
163 bool bRewritten
= false;
164 if (rewriter
!= nullptr) {
165 SourceLocation loc
{ compiler
.getSourceManager().getExpansionLoc(
166 expr2
->getBeginLoc()) };
167 if (compiler
.getSourceManager().getExpansionLoc(expr2
->getEndLoc())
170 char const * s
= compiler
.getSourceManager().getCharacterData(
172 unsigned n
= Lexer::MeasureTokenLength(
173 expr2
->getEndLoc(), compiler
.getSourceManager(),
174 compiler
.getLangOpts());
175 std::string tok
{ s
, n
};
176 if (tok
== "sal_False" || tok
== "0") {
177 bRewritten
= replaceText(
178 compiler
.getSourceManager().getExpansionLoc(
179 expr2
->getBeginLoc()),
181 } else if (tok
== "sal_True" || tok
== "1") {
182 bRewritten
= replaceText(
183 compiler
.getSourceManager().getExpansionLoc(
184 expr2
->getBeginLoc()),
191 DiagnosticsEngine::Warning
,
192 "implicit conversion (%0) of literal of type %1 to %2",
193 expr2
->getBeginLoc())
194 << castExpr
->getCastKindName() << subExpr
->getType()
195 << castExpr
->getType() << expr2
->getSourceRange();
197 } else if (subExpr
->isNullPointerConstant(
198 compiler
.getASTContext(), Expr::NPC_ValueDependentIsNull
)
199 > Expr::NPCK_ZeroExpression
)
201 // The test above originally checked for != Expr::NPCK_NotNull, but in non-C++11
202 // mode we can get also Expr::NPCK_ZeroExpression inside templates, even though
203 // the expression is actually not a null pointer. Clang bug or C++98 misfeature?
204 // See Clang's NPCK_ZeroExpression declaration and beginning of isNullPointerConstant().
205 static_assert( Expr::NPCK_NotNull
== 0 && Expr::NPCK_ZeroExpression
== 1, "Clang API change" );
207 DiagnosticsEngine::Warning
,
208 ("implicit conversion (%0) of null pointer constant of type %1 to"
210 expr2
->getBeginLoc())
211 << castExpr
->getCastKindName() << subExpr
->getType()
212 << castExpr
->getType() << expr2
->getSourceRange();
213 } else if (!subExpr
->isValueDependent()) {
214 if (auto const res
= subExpr
->getIntegerConstantExpr(compiler
.getASTContext())) {
216 DiagnosticsEngine::Warning
,
217 ("implicit conversion (%0) of integer constant expression of type"
218 " %1 with value %2 to %3"),
219 expr2
->getBeginLoc())
220 << castExpr
->getCastKindName() << subExpr
->getType()
221 << compat::toString(*res
, 10) << castExpr
->getType()
222 << expr2
->getSourceRange();
227 loplugin::Plugin::Registration
<LiteralToBoolConversion
> literaltoboolconversion("literaltoboolconversion");
231 #endif // LO_CLANG_SHARED_PLUGINS