cURL: follow redirects
[LibreOffice.git] / compilerplugins / clang / salbool.cxx
bloba443234e779c8c08d35081112f826a32e446c5fd
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 <algorithm>
11 #include <cassert>
12 #include <limits>
13 #include <set>
14 #include <string>
16 #include "clang/AST/Attr.h"
18 #include "check.hxx"
19 #include "compat.hxx"
20 #include "plugin.hxx"
22 namespace {
24 bool isSalBool(QualType type) {
25 TypedefType const * t = type->getAs<TypedefType>();
26 return t != nullptr && t->getDecl()->getNameAsString() == "sal_Bool";
29 bool isSalBoolArray(QualType type) {
30 auto t = type->getAsArrayTypeUnsafe();
31 return t != nullptr
32 && (isSalBool(t->getElementType())
33 || isSalBoolArray(t->getElementType()));
36 // It appears that, given a function declaration, there is no way to determine
37 // the language linkage of the function's type, only of the function's name
38 // (via FunctionDecl::isExternC); however, in a case like
40 // extern "C" { static void f(); }
42 // the function's name does not have C language linkage while the function's
43 // type does (as clarified in C++11 [decl.link]); cf. <http://clang-developers.
44 // 42468.n3.nabble.com/Language-linkage-of-function-type-tt4037248.html>
45 // "Language linkage of function type":
46 bool hasCLanguageLinkageType(FunctionDecl const * decl) {
47 assert(decl != nullptr);
48 if (decl->isExternC()) {
49 return true;
51 if (decl->isInExternCContext()) {
52 return true;
54 return false;
57 enum class OverrideKind { NO, YES, MAYBE };
59 OverrideKind getOverrideKind(FunctionDecl const * decl) {
60 CXXMethodDecl const * m = dyn_cast<CXXMethodDecl>(decl);
61 if (m == nullptr) {
62 return OverrideKind::NO;
64 if (m->size_overridden_methods() != 0 || m->hasAttr<OverrideAttr>()) {
65 return OverrideKind::YES;
67 if (!dyn_cast<CXXRecordDecl>(m->getDeclContext())->hasAnyDependentBases()) {
68 return OverrideKind::NO;
70 return OverrideKind::MAYBE;
73 //TODO: current implementation is not at all general, just tests what we
74 // encounter in practice:
75 bool hasBoolOverload(FunctionDecl const * decl, bool mustBeDeleted) {
76 unsigned n = decl->getNumParams();
77 auto res = decl->getDeclContext()->lookup(decl->getDeclName());
78 for (auto d = res.begin(); d != res.end(); ++d) {
79 FunctionDecl const * f = dyn_cast<FunctionDecl>(*d);
80 if (f != nullptr && (!mustBeDeleted || f->isDeleted())) {
81 if (f->getNumParams() == n) {
82 bool hasSB = false;
83 for (unsigned i = 0; i != n; ++i) {
84 QualType t1 { decl->getParamDecl(i)->getType() };
85 bool isSB = isSalBool(t1);
86 bool isSBRef = !isSB && t1->isReferenceType()
87 && isSalBool(t1.getNonReferenceType());
88 QualType t2 { f->getParamDecl(i)->getType() };
89 if (!(isSB
90 ? t2->isBooleanType()
91 : isSBRef
92 ? (t2->isReferenceType()
93 && t2.getNonReferenceType()->isBooleanType())
94 : t2 == t1))
96 goto next;
98 hasSB |= isSB || isSBRef;
100 return hasSB;
101 // cheaply protect against the case where decl would have no
102 // sal_Bool parameters at all and would match itself
103 next:;
107 return false;
110 class SalBool:
111 public RecursiveASTVisitor<SalBool>, public loplugin::RewritePlugin
113 public:
114 explicit SalBool(InstantiationData const & data): RewritePlugin(data) {}
116 virtual void run() override;
118 bool VisitUnaryAddrOf(UnaryOperator const * op);
120 bool VisitCallExpr(CallExpr * expr);
122 bool VisitCStyleCastExpr(CStyleCastExpr * expr);
124 bool VisitCXXStaticCastExpr(CXXStaticCastExpr * expr);
126 bool VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr * expr);
128 bool VisitImplicitCastExpr(ImplicitCastExpr * expr);
130 bool VisitReturnStmt(ReturnStmt const * stmt);
132 bool WalkUpFromParmVarDecl(ParmVarDecl const * decl);
133 bool VisitParmVarDecl(ParmVarDecl const * decl);
135 bool WalkUpFromVarDecl(VarDecl const * decl);
136 bool VisitVarDecl(VarDecl const * decl);
138 bool WalkUpFromFieldDecl(FieldDecl const * decl);
139 bool VisitFieldDecl(FieldDecl const * decl);
141 bool WalkUpFromFunctionDecl(FunctionDecl const * decl);
142 bool VisitFunctionDecl(FunctionDecl const * decl);
144 bool VisitValueDecl(ValueDecl const * decl);
146 bool TraverseStaticAssertDecl(StaticAssertDecl * decl);
148 bool TraverseLinkageSpecDecl(LinkageSpecDecl * decl);
150 private:
151 bool isFromCIncludeFile(SourceLocation spellingLocation) const;
153 bool isSharedCAndCppCode(SourceLocation location) const;
155 bool isInSpecialMainFile(SourceLocation spellingLocation) const;
157 bool rewrite(SourceLocation location);
159 std::set<VarDecl const *> varDecls_;
160 unsigned int externCContexts_ = 0;
163 void SalBool::run() {
164 if (compiler.getLangOpts().CPlusPlus) {
165 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
166 for (auto decl: varDecls_) {
167 SourceLocation loc { decl->getLocStart() };
168 TypeSourceInfo * tsi = decl->getTypeSourceInfo();
169 if (tsi != nullptr) {
170 SourceLocation l {
171 compiler.getSourceManager().getExpansionLoc(
172 tsi->getTypeLoc().getBeginLoc()) };
173 SourceLocation end {
174 compiler.getSourceManager().getExpansionLoc(
175 tsi->getTypeLoc().getEndLoc()) };
176 assert(l.isFileID() && end.isFileID());
177 if (l == end
178 || compiler.getSourceManager().isBeforeInTranslationUnit(
179 l, end))
181 for (;;) {
182 unsigned n = Lexer::MeasureTokenLength(
183 l, compiler.getSourceManager(),
184 compiler.getLangOpts());
185 std::string s {
186 compiler.getSourceManager().getCharacterData(l),
187 n };
188 if (s == "sal_Bool") {
189 loc = l;
190 break;
192 if (l == end) {
193 break;
195 l = l.getLocWithOffset(std::max<unsigned>(n, 1));
199 if (!rewrite(loc)) {
200 report(
201 DiagnosticsEngine::Warning,
202 "VarDecl, use \"bool\" instead of \"sal_Bool\"", loc)
203 << decl->getSourceRange();
209 bool SalBool::VisitUnaryAddrOf(UnaryOperator const * op) {
210 Expr const * e1 = op->getSubExpr()->IgnoreParenCasts();
211 if (isSalBool(e1->getType())) {
212 DeclRefExpr const * e2 = dyn_cast<DeclRefExpr>(e1);
213 if (e2 != nullptr) {
214 VarDecl const * d = dyn_cast<VarDecl>(e2->getDecl());
215 if (d != nullptr) {
216 varDecls_.erase(d);
220 return true;
223 bool SalBool::VisitCallExpr(CallExpr * expr) {
224 Decl const * d = expr->getCalleeDecl();
225 FunctionProtoType const * ft = nullptr;
226 if (d != nullptr) {
227 FunctionDecl const * fd = dyn_cast<FunctionDecl>(d);
228 if (fd != nullptr) {
229 PointerType const * pt = fd->getType()->getAs<PointerType>();
230 QualType t2(pt == nullptr ? fd->getType() : pt->getPointeeType());
231 ft = t2->getAs<FunctionProtoType>();
232 assert(
233 ft != nullptr || !compiler.getLangOpts().CPlusPlus
234 || (fd->getBuiltinID() != Builtin::NotBuiltin
235 && isa<FunctionNoProtoType>(t2)));
236 // __builtin_*s have no proto type?
237 } else {
238 VarDecl const * vd = dyn_cast<VarDecl>(d);
239 if (vd != nullptr) {
240 PointerType const * pt = vd->getType()->getAs<PointerType>();
241 ft = (pt == nullptr ? vd->getType() : pt->getPointeeType())
242 ->getAs<FunctionProtoType>();
246 if (ft != nullptr) {
247 for (unsigned i = 0; i != compat::getNumParams(*ft); ++i) {
248 QualType t(compat::getParamType(*ft, i));
249 bool b = false;
250 if (t->isLValueReferenceType()) {
251 t = t.getNonReferenceType();
252 b = !t.isConstQualified() && isSalBool(t);
253 } else if (t->isPointerType()) {
254 for (;;) {
255 auto t2 = t->getAs<PointerType>();
256 if (t2 == nullptr) {
257 break;
259 t = t2->getPointeeType();
261 b = isSalBool(t);
263 if (b && i < expr->getNumArgs()) {
264 DeclRefExpr * ref = dyn_cast<DeclRefExpr>(
265 expr->getArg(i)->IgnoreParenImpCasts());
266 if (ref != nullptr) {
267 VarDecl const * d = dyn_cast<VarDecl>(ref->getDecl());
268 if (d != nullptr) {
269 varDecls_.erase(d);
275 return true;
278 bool SalBool::VisitCStyleCastExpr(CStyleCastExpr * expr) {
279 if (ignoreLocation(expr)) {
280 return true;
282 if (isSalBool(expr->getType())) {
283 SourceLocation loc { expr->getLocStart() };
284 while (compiler.getSourceManager().isMacroArgExpansion(loc)) {
285 loc = compiler.getSourceManager().getImmediateMacroCallerLoc(loc);
287 if (compiler.getSourceManager().isMacroBodyExpansion(loc)) {
288 StringRef name { Lexer::getImmediateMacroName(
289 loc, compiler.getSourceManager(), compiler.getLangOpts()) };
290 if (name == "sal_False" || name == "sal_True") {
291 auto callLoc = compiler.getSourceManager()
292 .getImmediateMacroCallerLoc(loc);
293 if (!isSharedCAndCppCode(callLoc)) {
294 SourceLocation argLoc;
295 if (compat::isMacroArgExpansion(
296 compiler, expr->getLocStart(), &argLoc)
297 //TODO: check it's the complete (first) arg to the macro
298 && (Lexer::getImmediateMacroName(
299 argLoc, compiler.getSourceManager(),
300 compiler.getLangOpts())
301 == "CPPUNIT_ASSERT_EQUAL"))
303 // Ignore sal_False/True that are directly used as
304 // arguments to CPPUNIT_ASSERT_EQUAL:
305 return true;
307 bool b = name == "sal_True";
308 if (rewriter != nullptr) {
309 auto callSpellLoc = compiler.getSourceManager()
310 .getSpellingLoc(callLoc);
311 unsigned n = Lexer::MeasureTokenLength(
312 callSpellLoc, compiler.getSourceManager(),
313 compiler.getLangOpts());
314 if (StringRef(
315 compiler.getSourceManager().getCharacterData(
316 callSpellLoc),
318 == name)
320 return replaceText(
321 callSpellLoc, n, b ? "true" : "false");
324 report(
325 DiagnosticsEngine::Warning,
326 "use '%select{false|true}0' instead of '%1'", callLoc)
327 << b << name << expr->getSourceRange();
329 return true;
332 report(
333 DiagnosticsEngine::Warning,
334 "CStyleCastExpr, suspicious cast from %0 to %1",
335 expr->getLocStart())
336 << expr->getSubExpr()->IgnoreParenImpCasts()->getType()
337 << expr->getType() << expr->getSourceRange();
339 return true;
342 bool SalBool::VisitCXXStaticCastExpr(CXXStaticCastExpr * expr) {
343 if (ignoreLocation(expr)) {
344 return true;
346 if (isSalBool(expr->getType())
347 && !isInSpecialMainFile(
348 compiler.getSourceManager().getSpellingLoc(expr->getLocStart())))
350 report(
351 DiagnosticsEngine::Warning,
352 "CXXStaticCastExpr, suspicious cast from %0 to %1",
353 expr->getLocStart())
354 << expr->getSubExpr()->IgnoreParenImpCasts()->getType()
355 << expr->getType() << expr->getSourceRange();
357 return true;
360 bool SalBool::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr * expr) {
361 if (ignoreLocation(expr)) {
362 return true;
364 if (isSalBool(expr->getType())) {
365 report(
366 DiagnosticsEngine::Warning,
367 "CXXFunctionalCastExpr, suspicious cast from %0 to %1",
368 expr->getLocStart())
369 << expr->getSubExpr()->IgnoreParenImpCasts()->getType()
370 << expr->getType() << expr->getSourceRange();
372 return true;
375 bool SalBool::VisitImplicitCastExpr(ImplicitCastExpr * expr) {
376 if (ignoreLocation(expr)) {
377 return true;
379 if (!isSalBool(expr->getType())) {
380 return true;
382 auto l = expr->getLocStart();
383 while (compiler.getSourceManager().isMacroArgExpansion(l)) {
384 l = compiler.getSourceManager().getImmediateMacroCallerLoc(l);
386 if (compiler.getSourceManager().isMacroBodyExpansion(l)) {
387 auto n = Lexer::getImmediateMacroName(
388 l, compiler.getSourceManager(), compiler.getLangOpts());
389 if (n == "sal_False" || n == "sal_True") {
390 return true;
393 auto e1 = expr->getSubExprAsWritten();
394 auto t = e1->getType();
395 if (!t->isFundamentalType() || loplugin::TypeCheck(t).AnyBoolean()) {
396 return true;
398 auto e2 = dyn_cast<ConditionalOperator>(e1);
399 if (e2 != nullptr) {
400 auto ic1 = dyn_cast<ImplicitCastExpr>(
401 e2->getTrueExpr()->IgnoreParens());
402 auto ic2 = dyn_cast<ImplicitCastExpr>(
403 e2->getFalseExpr()->IgnoreParens());
404 if (ic1 != nullptr && ic2 != nullptr
405 && ic1->getType()->isSpecificBuiltinType(BuiltinType::Int)
406 && (loplugin::TypeCheck(ic1->getSubExprAsWritten()->getType())
407 .AnyBoolean())
408 && ic2->getType()->isSpecificBuiltinType(BuiltinType::Int)
409 && (loplugin::TypeCheck(ic2->getSubExprAsWritten()->getType())
410 .AnyBoolean()))
412 return true;
415 report(
416 DiagnosticsEngine::Warning, "conversion from %0 to sal_Bool",
417 expr->getLocStart())
418 << t << expr->getSourceRange();
419 return true;
422 bool SalBool::VisitReturnStmt(ReturnStmt const * stmt) {
423 // Just enough to avoid warnings in rtl_getUriCharClass (sal/rtl/uri.cxx),
424 // which has
426 // static sal_Bool const aCharClass[][nCharClassSize] = ...;
428 // and
430 // return aCharClass[eCharClass];
432 if (ignoreLocation(stmt)) {
433 return true;
435 auto e = stmt->getRetValue();
436 if (e == nullptr) {
437 return true;
439 auto t = e->getType();
440 if (!t->isPointerType()) {
441 return true;
443 for (;;) {
444 auto t2 = t->getAs<PointerType>();
445 if (t2 == nullptr) {
446 break;
448 t = t2->getPointeeType();
450 if (!isSalBool(t)) {
451 return true;
453 auto e2 = dyn_cast<ArraySubscriptExpr>(e->IgnoreParenImpCasts());
454 if (e2 == nullptr) {
455 return true;
457 auto e3 = dyn_cast<DeclRefExpr>(e2->getBase()->IgnoreParenImpCasts());
458 if (e3 == nullptr) {
459 return true;
461 auto d = dyn_cast<VarDecl>(e3->getDecl());
462 if (d == nullptr) {
463 return true;
465 varDecls_.erase(d);
466 return true;
469 bool SalBool::WalkUpFromParmVarDecl(ParmVarDecl const * decl) {
470 return VisitParmVarDecl(decl);
473 bool SalBool::VisitParmVarDecl(ParmVarDecl const * decl) {
474 if (ignoreLocation(decl)) {
475 return true;
477 if (isSalBool(decl->getType().getNonReferenceType())) {
478 FunctionDecl const * f = dyn_cast<FunctionDecl>(decl->getDeclContext());
479 if (f != nullptr) { // e.g.: typedef sal_Bool (* FuncPtr )( sal_Bool );
480 f = f->getCanonicalDecl();
481 if (!(hasCLanguageLinkageType(f)
482 || (isInUnoIncludeFile(f)
483 && (!f->isInlined() || f->hasAttr<DeprecatedAttr>()
484 || decl->getType()->isReferenceType()
485 || hasBoolOverload(f, false)))
486 || f->isDeleted() || hasBoolOverload(f, true)))
488 OverrideKind k = getOverrideKind(f);
489 if (k != OverrideKind::YES) {
490 SourceLocation loc { decl->getLocStart() };
491 TypeSourceInfo * tsi = decl->getTypeSourceInfo();
492 if (tsi != nullptr) {
493 SourceLocation l {
494 compiler.getSourceManager().getExpansionLoc(
495 tsi->getTypeLoc().getBeginLoc()) };
496 SourceLocation end {
497 compiler.getSourceManager().getExpansionLoc(
498 tsi->getTypeLoc().getEndLoc()) };
499 assert(l.isFileID() && end.isFileID());
500 if (l == end
501 || (compiler.getSourceManager()
502 .isBeforeInTranslationUnit(l, end)))
504 for (;;) {
505 unsigned n = Lexer::MeasureTokenLength(
506 l, compiler.getSourceManager(),
507 compiler.getLangOpts());
508 std::string s {
509 compiler.getSourceManager().getCharacterData(l),
510 n };
511 if (s == "sal_Bool") {
512 loc = l;
513 break;
515 if (l == end) {
516 break;
518 l = l.getLocWithOffset(std::max<unsigned>(n, 1));
522 // Only rewrite declarations in include files if a
523 // definition is also seen, to avoid compilation of a
524 // definition (in a main file only processed later) to fail
525 // with a "mismatch" error before the rewriter had a chance
526 // to act upon the definition (but use the heuristic of
527 // assuming pure virtual functions do not have definitions);
528 // also, do not automatically rewrite functions that could
529 // implicitly override depend base functions (and thus stop
530 // doing so after the rewrite; note that this is less
531 // dangerous for return types than for parameter types,
532 // where the function would still implicitly override and
533 // cause a compilation error due to the incompatible return
534 // type):
535 if (!((compiler.getSourceManager().isInMainFile(
536 compiler.getSourceManager().getSpellingLoc(
537 dyn_cast<FunctionDecl>(
538 decl->getDeclContext())
539 ->getNameInfo().getLoc()))
540 || f->isDefined() || f->isPure())
541 && k != OverrideKind::MAYBE && rewrite(loc)))
543 report(
544 DiagnosticsEngine::Warning,
545 ("ParmVarDecl, use \"bool\" instead of"
546 " \"sal_Bool\"%0"),
547 loc)
548 << (k == OverrideKind::MAYBE
549 ? (" (unless this member function overrides a"
550 " dependent base member function, even"
551 " though it is not marked 'override')")
552 : "")
553 << decl->getSourceRange();
559 return true;
562 bool SalBool::WalkUpFromVarDecl(VarDecl const * decl) {
563 return VisitVarDecl(decl);
566 bool SalBool::VisitVarDecl(VarDecl const * decl) {
567 if (ignoreLocation(decl)) {
568 return true;
570 if (!decl->isExternC()
571 && (isSalBool(decl->getType()) || isSalBoolArray(decl->getType()))
572 && !isInSpecialMainFile(
573 compiler.getSourceManager().getSpellingLoc(decl->getLocStart())))
575 varDecls_.insert(decl);
577 return true;
580 bool SalBool::WalkUpFromFieldDecl(FieldDecl const * decl) {
581 return VisitFieldDecl(decl);
584 bool SalBool::VisitFieldDecl(FieldDecl const * decl) {
585 if (ignoreLocation(decl)) {
586 return true;
588 if ((isSalBool(decl->getType()) || isSalBoolArray(decl->getType()))
589 && !isInSpecialMainFile(
590 compiler.getSourceManager().getSpellingLoc(decl->getLocStart())))
592 TagDecl const * td = dyn_cast<TagDecl>(decl->getDeclContext());
593 assert(td != nullptr);
594 if (!(((td->isStruct() || td->isUnion()) && td->isExternCContext())
595 || isInUnoIncludeFile(
596 compiler.getSourceManager().getSpellingLoc(
597 decl->getLocation()))))
599 SourceLocation loc { decl->getLocStart() };
600 TypeSourceInfo * tsi = decl->getTypeSourceInfo();
601 if (tsi != nullptr) {
602 SourceLocation l {
603 compiler.getSourceManager().getExpansionLoc(
604 tsi->getTypeLoc().getBeginLoc()) };
605 SourceLocation end {
606 compiler.getSourceManager().getExpansionLoc(
607 tsi->getTypeLoc().getEndLoc()) };
608 assert(l.isFileID() && end.isFileID());
609 if (l == end
610 || compiler.getSourceManager().isBeforeInTranslationUnit(
611 l, end))
613 for (;;) {
614 unsigned n = Lexer::MeasureTokenLength(
615 l, compiler.getSourceManager(),
616 compiler.getLangOpts());
617 std::string s {
618 compiler.getSourceManager().getCharacterData(l),
619 n };
620 if (s == "sal_Bool") {
621 loc = l;
622 break;
624 if (l == end) {
625 break;
627 l = l.getLocWithOffset(std::max<unsigned>(n, 1));
631 if (!rewrite(loc)) {
632 report(
633 DiagnosticsEngine::Warning,
634 "FieldDecl, use \"bool\" instead of \"sal_Bool\"", loc)
635 << decl->getSourceRange();
639 return true;
642 bool SalBool::WalkUpFromFunctionDecl(FunctionDecl const * decl) {
643 return VisitFunctionDecl(decl);
646 bool SalBool::VisitFunctionDecl(FunctionDecl const * decl) {
647 if (ignoreLocation(decl)) {
648 return true;
650 if (isSalBool(compat::getReturnType(*decl).getNonReferenceType())) {
651 FunctionDecl const * f = decl->getCanonicalDecl();
652 OverrideKind k = getOverrideKind(f);
653 if (k != OverrideKind::YES
654 && !(hasCLanguageLinkageType(f)
655 || (isInUnoIncludeFile(f)
656 && (!f->isInlined() || f->hasAttr<DeprecatedAttr>()))))
658 SourceLocation loc { decl->getLocStart() };
659 SourceLocation l { compiler.getSourceManager().getExpansionLoc(
660 loc) };
661 SourceLocation end { compiler.getSourceManager().getExpansionLoc(
662 decl->getNameInfo().getLoc()) };
663 assert(l.isFileID() && end.isFileID());
664 if (compiler.getSourceManager().isBeforeInTranslationUnit(l, end)) {
665 while (l != end) {
666 unsigned n = Lexer::MeasureTokenLength(
667 l, compiler.getSourceManager(), compiler.getLangOpts());
668 std::string s {
669 compiler.getSourceManager().getCharacterData(l), n };
670 if (s == "sal_Bool") {
671 loc = l;
672 break;
674 l = l.getLocWithOffset(std::max<unsigned>(n, 1));
677 // Only rewrite declarations in include files if a definition is
678 // also seen, to avoid compilation of a definition (in a main file
679 // only processed later) to fail with a "mismatch" error before the
680 // rewriter had a chance to act upon the definition (but use the
681 // heuristic of assuming pure virtual functions do not have
682 // definitions):
683 if (!((compiler.getSourceManager().isInMainFile(
684 compiler.getSourceManager().getSpellingLoc(
685 decl->getNameInfo().getLoc()))
686 || f->isDefined() || f->isPure())
687 && rewrite(loc)))
689 report(
690 DiagnosticsEngine::Warning,
691 "use \"bool\" instead of \"sal_Bool\" as return type%0",
692 loc)
693 << (k == OverrideKind::MAYBE
694 ? (" (unless this member function overrides a dependent"
695 " base member function, even though it is not marked"
696 " 'override')")
697 : "")
698 << decl->getSourceRange();
702 return true;
705 bool SalBool::VisitValueDecl(ValueDecl const * decl) {
706 if (ignoreLocation(decl)) {
707 return true;
709 if (isSalBool(decl->getType()) && !rewrite(decl->getLocStart())) {
710 report(
711 DiagnosticsEngine::Warning,
712 "ValueDecl, use \"bool\" instead of \"sal_Bool\"",
713 decl->getLocStart())
714 << decl->getSourceRange();
716 return true;
719 bool SalBool::TraverseStaticAssertDecl(StaticAssertDecl * decl) {
720 // Ignore special code like
722 // static_cast<sal_Bool>(true) == sal_True
724 // inside static_assert in cppu/source/uno/check.cxx:
725 return
726 (compiler.getSourceManager().getFilename(decl->getLocation())
727 == SRCDIR "/cppu/source/uno/check.cxx")
728 || RecursiveASTVisitor::TraverseStaticAssertDecl(decl);
731 bool SalBool::TraverseLinkageSpecDecl(LinkageSpecDecl * decl) {
732 assert(externCContexts_ != std::numeric_limits<unsigned int>::max()); //TODO
733 ++externCContexts_;
734 bool ret = RecursiveASTVisitor::TraverseLinkageSpecDecl(decl);
735 assert(externCContexts_ != 0);
736 --externCContexts_;
737 return ret;
740 bool SalBool::isFromCIncludeFile(SourceLocation spellingLocation) const {
741 return !compiler.getSourceManager().isInMainFile(spellingLocation)
742 && (StringRef(
743 compiler.getSourceManager().getPresumedLoc(spellingLocation)
744 .getFilename())
745 .endswith(".h"));
748 bool SalBool::isSharedCAndCppCode(SourceLocation location) const {
749 // Assume that code is intended to be shared between C and C++ if it comes
750 // from an include file ending in .h, and is either in an extern "C" context
751 // or the body of a macro definition:
752 return
753 isFromCIncludeFile(compiler.getSourceManager().getSpellingLoc(location))
754 && (externCContexts_ != 0
755 || compiler.getSourceManager().isMacroBodyExpansion(location));
758 bool SalBool::isInSpecialMainFile(SourceLocation spellingLocation) const {
759 if (!compiler.getSourceManager().isInMainFile(spellingLocation)) {
760 return false;
762 auto f = compiler.getSourceManager().getFilename(spellingLocation);
763 return f == SRCDIR "/cppu/qa/test_any.cxx"
764 || f == SRCDIR "/cppu/source/uno/check.cxx"; // TODO: the offset checks
767 bool SalBool::rewrite(SourceLocation location) {
768 if (rewriter != nullptr) {
769 //TODO: "::sal_Bool" -> "bool", not "::bool"
770 SourceLocation loc { compiler.getSourceManager().getExpansionLoc(
771 location) };
772 unsigned n = Lexer::MeasureTokenLength(
773 loc, compiler.getSourceManager(), compiler.getLangOpts());
774 if (std::string(compiler.getSourceManager().getCharacterData(loc), n)
775 == "sal_Bool")
777 return replaceText(loc, n, "bool");
780 return false;
783 loplugin::Plugin::Registration<SalBool> X("salbool", true);
787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */