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 compiler
.getSourceManager().getPresumedLoc(spellingLocation
)
90 bool LiteralToBoolConversion::isSharedCAndCppCode(SourceLocation location
) const
92 // Assume that code is intended to be shared between C and C++ if it comes
93 // from an include file ending in .h, and is either in an extern "C" context
94 // or the body of a macro definition:
96 isFromCIncludeFile(compiler
.getSourceManager().getSpellingLoc(location
))
97 && (externCContexts_
!= 0
98 || compiler
.getSourceManager().isMacroBodyExpansion(location
));
101 void LiteralToBoolConversion::handleImplicitCastSubExpr(
102 ImplicitCastExpr
const * castExpr
, Expr
const * subExpr
)
104 Expr
const * expr2
= subExpr
;
105 // track sub-expr with potential parens, to e.g. rewrite all of expanded
107 // #define sal_False ((sal_Bool)0)
109 // including the parens
110 subExpr
= expr2
->IgnoreParenCasts();
112 BinaryOperator
const * op
= dyn_cast
<BinaryOperator
>(subExpr
);
113 if (op
== nullptr || op
->getOpcode() != BO_Comma
) {
116 expr2
= op
->getRHS();
117 subExpr
= expr2
->IgnoreParenCasts();
119 if (subExpr
->getType()->isBooleanType()) {
122 ConditionalOperator
const * op
= dyn_cast
<ConditionalOperator
>(subExpr
);
124 handleImplicitCastSubExpr(castExpr
, op
->getTrueExpr());
125 handleImplicitCastSubExpr(castExpr
, op
->getFalseExpr());
128 if (!subExpr
->isValueDependent()) {
129 if (auto const res
= subExpr
->getIntegerConstantExpr(compiler
.getASTContext())) {
130 if (res
->getLimitedValue() <= 1)
132 SourceLocation loc
{ subExpr
->getBeginLoc() };
133 while (compiler
.getSourceManager().isMacroArgExpansion(loc
)) {
134 loc
= compiler
.getSourceManager().getImmediateMacroCallerLoc(loc
);
136 if (compiler
.getSourceManager().isMacroBodyExpansion(loc
)) {
137 StringRef name
{ Lexer::getImmediateMacroName(
138 loc
, compiler
.getSourceManager(), compiler
.getLangOpts()) };
139 if (name
== "sal_False" || name
== "sal_True") {
140 loc
= compat::getImmediateExpansionRange(compiler
.getSourceManager(), loc
)
143 if (isSharedCAndCppCode(loc
)) {
150 if (isa
<clang::StringLiteral
>(subExpr
)) {
151 SourceLocation loc
{ subExpr
->getBeginLoc() };
152 if (compiler
.getSourceManager().isMacroArgExpansion(loc
)
153 && (Lexer::getImmediateMacroName(
154 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
160 if (isa
<IntegerLiteral
>(subExpr
) || isa
<CharacterLiteral
>(subExpr
)
161 || isa
<FloatingLiteral
>(subExpr
) || isa
<ImaginaryLiteral
>(subExpr
)
162 || isa
<clang::StringLiteral
>(subExpr
))
164 bool bRewritten
= false;
165 if (rewriter
!= nullptr) {
166 SourceLocation loc
{ compiler
.getSourceManager().getExpansionLoc(
167 expr2
->getBeginLoc()) };
168 if (compiler
.getSourceManager().getExpansionLoc(expr2
->getEndLoc())
171 char const * s
= compiler
.getSourceManager().getCharacterData(
173 unsigned n
= Lexer::MeasureTokenLength(
174 expr2
->getEndLoc(), compiler
.getSourceManager(),
175 compiler
.getLangOpts());
176 std::string tok
{ s
, n
};
177 if (tok
== "sal_False" || tok
== "0") {
178 bRewritten
= replaceText(
179 compiler
.getSourceManager().getExpansionLoc(
180 expr2
->getBeginLoc()),
182 } else if (tok
== "sal_True" || tok
== "1") {
183 bRewritten
= replaceText(
184 compiler
.getSourceManager().getExpansionLoc(
185 expr2
->getBeginLoc()),
192 DiagnosticsEngine::Warning
,
193 "implicit conversion (%0) of literal of type %1 to %2",
194 expr2
->getBeginLoc())
195 << castExpr
->getCastKindName() << subExpr
->getType()
196 << castExpr
->getType() << expr2
->getSourceRange();
198 } else if (subExpr
->isNullPointerConstant(
199 compiler
.getASTContext(), Expr::NPC_ValueDependentIsNull
)
200 > Expr::NPCK_ZeroExpression
)
202 // The test above originally checked for != Expr::NPCK_NotNull, but in non-C++11
203 // mode we can get also Expr::NPCK_ZeroExpression inside templates, even though
204 // the expression is actually not a null pointer. Clang bug or C++98 misfeature?
205 // See Clang's NPCK_ZeroExpression declaration and beginning of isNullPointerConstant().
206 static_assert( Expr::NPCK_NotNull
== 0 && Expr::NPCK_ZeroExpression
== 1, "Clang API change" );
208 DiagnosticsEngine::Warning
,
209 ("implicit conversion (%0) of null pointer constant of type %1 to"
211 expr2
->getBeginLoc())
212 << castExpr
->getCastKindName() << subExpr
->getType()
213 << castExpr
->getType() << expr2
->getSourceRange();
214 } else if (!subExpr
->isValueDependent()) {
215 if (auto const res
= subExpr
->getIntegerConstantExpr(compiler
.getASTContext())) {
217 DiagnosticsEngine::Warning
,
218 ("implicit conversion (%0) of integer constant expression of type"
219 " %1 with value %2 to %3"),
220 expr2
->getBeginLoc())
221 << castExpr
->getCastKindName() << subExpr
->getType()
222 << compat::toString(*res
, 10) << castExpr
->getType()
223 << expr2
->getSourceRange();
228 loplugin::Plugin::Registration
<LiteralToBoolConversion
> literaltoboolconversion("literaltoboolconversion");
232 #endif // LO_CLANG_SHARED_PLUGINS