bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / literaltoboolconversion.cxx
blob588b75ddd8e206f9de99fc6b6e4fa6d13e0b6300
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include "clang/Lex/Lexer.h"
12 #include "compat.hxx"
13 #include "plugin.hxx"
15 namespace {
17 class LiteralToBoolConversion:
18 public RecursiveASTVisitor<LiteralToBoolConversion>,
19 public loplugin::RewritePlugin
21 public:
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);
30 private:
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)) {
41 return true;
43 if (!expr->getType()->isBooleanType()) {
44 return true;
46 handleImplicitCastSubExpr(expr, expr->getSubExpr());
47 return true;
50 bool LiteralToBoolConversion::isFromCIncludeFile(
51 SourceLocation spellingLocation) const
53 return !compat::isInMainFile(compiler.getSourceManager(), spellingLocation)
54 && (StringRef(
55 compiler.getSourceManager().getPresumedLoc(spellingLocation)
56 .getFilename())
57 .endswith(".h"));
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();
70 for (;;) {
71 BinaryOperator const * op = dyn_cast<BinaryOperator>(subExpr);
72 if (op == nullptr || op->getOpcode() != BO_Comma) {
73 break;
75 expr2 = op->getRHS();
76 subExpr = expr2->IgnoreParenCasts();
78 if (subExpr->getType()->isBooleanType()) {
79 return;
81 ConditionalOperator const * op = dyn_cast<ConditionalOperator>(subExpr);
82 if (op != nullptr) {
83 handleImplicitCastSubExpr(castExpr, op->getTrueExpr());
84 handleImplicitCastSubExpr(castExpr, op->getFalseExpr());
85 return;
87 APSInt res;
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(
101 loc).first;
103 if (isFromCIncludeFile(
104 compiler.getSourceManager().getSpellingLoc(loc)))
106 return;
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())
115 == "assert"))
117 return;
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())
129 == loc)
131 char const * s = compiler.getSourceManager().getCharacterData(
132 loc);
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()),
141 n, "false");
142 } else if (tok == "sal_True" || tok == "1") {
143 rewritten = replaceText(
144 compiler.getSourceManager().getExpansionLoc(
145 expr2->getLocStart()),
146 n, "true");
150 if (!rewritten) {
151 report(
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" );
167 report(
168 DiagnosticsEngine::Warning,
169 ("implicit conversion (%0) of null pointer constant of type %1 to"
170 " %2"),
171 expr2->getLocStart())
172 << castExpr->getCastKindName() << subExpr->getType()
173 << castExpr->getType() << expr2->getSourceRange();
174 } else if (!subExpr->isValueDependent()
175 && subExpr->isIntegerConstantExpr(res, compiler.getASTContext()))
177 report(
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);