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/.
16 #include "clang/AST/Attr.h"
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();
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()) {
51 if (decl
->isInExternCContext()) {
57 enum class OverrideKind
{ NO
, YES
, MAYBE
};
59 OverrideKind
getOverrideKind(FunctionDecl
const * decl
) {
60 CXXMethodDecl
const * m
= dyn_cast
<CXXMethodDecl
>(decl
);
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 enum class BoolOverloadKind
{ No
, Yes
, CheckNext
};
75 BoolOverloadKind
isBoolOverloadOf(
76 FunctionDecl
const * f
, FunctionDecl
const * decl
, bool mustBeDeleted
)
78 if (!mustBeDeleted
|| f
->isDeleted()) {
79 unsigned n
= decl
->getNumParams();
80 if (f
->getNumParams() == n
) {
82 for (unsigned i
= 0; i
!= n
; ++i
) {
83 QualType t1
{ decl
->getParamDecl(i
)->getType() };
84 bool isSB
= isSalBool(t1
);
85 bool isSBRef
= !isSB
&& t1
->isReferenceType()
86 && isSalBool(t1
.getNonReferenceType());
87 QualType t2
{ f
->getParamDecl(i
)->getType() };
91 ? (t2
->isReferenceType()
92 && t2
.getNonReferenceType()->isBooleanType())
93 : t2
.getCanonicalType() == t1
.getCanonicalType()))
95 return BoolOverloadKind::CheckNext
;
97 hasSB
|= isSB
|| isSBRef
;
99 return hasSB
? BoolOverloadKind::Yes
: BoolOverloadKind::No
;
100 // cheaply protect against the case where decl would have no
101 // sal_Bool parameters at all and would match itself
104 return BoolOverloadKind::CheckNext
;
107 //TODO: current implementation is not at all general, just tests what we
108 // encounter in practice:
109 bool hasBoolOverload(FunctionDecl
const * decl
, bool mustBeDeleted
) {
110 auto ctx
= decl
->getDeclContext();
111 if (!ctx
->isLookupContext()) {
114 auto res
= ctx
->lookup(decl
->getDeclName());
115 for (auto d
= res
.begin(); d
!= res
.end(); ++d
) {
116 if (auto f
= dyn_cast
<FunctionDecl
>(*d
)) {
117 switch (isBoolOverloadOf(f
, decl
, mustBeDeleted
)) {
118 case BoolOverloadKind::No
:
120 case BoolOverloadKind::Yes
:
122 case BoolOverloadKind::CheckNext
:
125 } else if (auto ftd
= dyn_cast
<FunctionTemplateDecl
>(*d
)) {
126 for (auto f
: ftd
->specializations()) {
127 if (f
->getTemplateSpecializationKind()
128 == TSK_ExplicitSpecialization
)
130 switch (isBoolOverloadOf(f
, decl
, mustBeDeleted
)) {
131 case BoolOverloadKind::No
:
133 case BoolOverloadKind::Yes
:
135 case BoolOverloadKind::CheckNext
:
146 public loplugin::FilteringRewritePlugin
<SalBool
>
149 explicit SalBool(loplugin::InstantiationData
const & data
):
150 FilteringRewritePlugin(data
) {}
152 virtual void run() override
;
154 bool VisitUnaryAddrOf(UnaryOperator
const * op
);
156 bool VisitCallExpr(CallExpr
* expr
);
158 bool VisitCStyleCastExpr(CStyleCastExpr
* expr
);
160 bool VisitCXXStaticCastExpr(CXXStaticCastExpr
* expr
);
162 bool VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr
* expr
);
164 bool VisitImplicitCastExpr(ImplicitCastExpr
* expr
);
166 bool VisitReturnStmt(ReturnStmt
const * stmt
);
168 bool WalkUpFromParmVarDecl(ParmVarDecl
const * decl
);
169 bool VisitParmVarDecl(ParmVarDecl
const * decl
);
171 bool WalkUpFromVarDecl(VarDecl
const * decl
);
172 bool VisitVarDecl(VarDecl
const * decl
);
174 bool WalkUpFromFieldDecl(FieldDecl
const * decl
);
175 bool VisitFieldDecl(FieldDecl
const * decl
);
177 bool WalkUpFromFunctionDecl(FunctionDecl
const * decl
);
178 bool VisitFunctionDecl(FunctionDecl
const * decl
);
180 bool VisitValueDecl(ValueDecl
const * decl
);
182 bool TraverseStaticAssertDecl(StaticAssertDecl
* decl
);
184 bool TraverseLinkageSpecDecl(LinkageSpecDecl
* decl
);
187 bool isFromCIncludeFile(SourceLocation spellingLocation
) const;
189 bool isSharedCAndCppCode(SourceLocation location
) const;
191 bool isInSpecialMainFile(SourceLocation spellingLocation
) const;
193 bool rewrite(SourceLocation location
);
195 std::set
<VarDecl
const *> varDecls_
;
196 unsigned int externCContexts_
= 0;
199 void SalBool::run() {
200 if (compiler
.getLangOpts().CPlusPlus
) {
201 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
202 for (auto decl
: varDecls_
) {
203 SourceLocation loc
{ compat::getBeginLoc(decl
) };
204 TypeSourceInfo
* tsi
= decl
->getTypeSourceInfo();
205 if (tsi
!= nullptr) {
207 compiler
.getSourceManager().getExpansionLoc(
208 tsi
->getTypeLoc().getBeginLoc()) };
210 compiler
.getSourceManager().getExpansionLoc(
211 tsi
->getTypeLoc().getEndLoc()) };
212 assert(l
.isFileID() && end
.isFileID());
214 || compiler
.getSourceManager().isBeforeInTranslationUnit(
218 unsigned n
= Lexer::MeasureTokenLength(
219 l
, compiler
.getSourceManager(),
220 compiler
.getLangOpts());
222 compiler
.getSourceManager().getCharacterData(l
),
224 if (s
== "sal_Bool") {
231 l
= l
.getLocWithOffset(std::max
<unsigned>(n
, 1));
237 DiagnosticsEngine::Warning
,
238 "VarDecl, use \"bool\" instead of \"sal_Bool\"", loc
)
239 << decl
->getSourceRange();
245 bool SalBool::VisitUnaryAddrOf(UnaryOperator
const * op
) {
246 Expr
const * e1
= op
->getSubExpr()->IgnoreParenCasts();
247 if (isSalBool(e1
->getType())) {
248 DeclRefExpr
const * e2
= dyn_cast
<DeclRefExpr
>(e1
);
250 VarDecl
const * d
= dyn_cast
<VarDecl
>(e2
->getDecl());
259 bool SalBool::VisitCallExpr(CallExpr
* expr
) {
260 Decl
const * d
= expr
->getCalleeDecl();
261 FunctionProtoType
const * ft
= nullptr;
263 FunctionDecl
const * fd
= dyn_cast
<FunctionDecl
>(d
);
265 if (!hasBoolOverload(fd
, false)) {
266 clang::PointerType
const * pt
= fd
->getType()
267 ->getAs
<clang::PointerType
>();
269 pt
== nullptr ? fd
->getType() : pt
->getPointeeType());
270 ft
= t2
->getAs
<FunctionProtoType
>();
272 ft
!= nullptr || !compiler
.getLangOpts().CPlusPlus
273 || (fd
->getBuiltinID() != Builtin::NotBuiltin
274 && isa
<FunctionNoProtoType
>(t2
)));
275 // __builtin_*s have no proto type?
278 VarDecl
const * vd
= dyn_cast
<VarDecl
>(d
);
280 clang::PointerType
const * pt
= vd
->getType()
281 ->getAs
<clang::PointerType
>();
282 ft
= (pt
== nullptr ? vd
->getType() : pt
->getPointeeType())
283 ->getAs
<FunctionProtoType
>();
288 for (unsigned i
= 0; i
!= ft
->getNumParams(); ++i
) {
289 QualType
t(ft
->getParamType(i
));
291 if (t
->isLValueReferenceType()) {
292 t
= t
.getNonReferenceType();
293 b
= !t
.isConstQualified() && isSalBool(t
);
294 } else if (t
->isPointerType()) {
296 auto t2
= t
->getAs
<clang::PointerType
>();
300 t
= t2
->getPointeeType();
304 if (b
&& i
< expr
->getNumArgs()) {
305 DeclRefExpr
* ref
= dyn_cast
<DeclRefExpr
>(
306 expr
->getArg(i
)->IgnoreParenImpCasts());
307 if (ref
!= nullptr) {
308 VarDecl
const * d
= dyn_cast
<VarDecl
>(ref
->getDecl());
319 bool SalBool::VisitCStyleCastExpr(CStyleCastExpr
* expr
) {
320 if (ignoreLocation(expr
)) {
323 if (isSalBool(expr
->getType())) {
324 SourceLocation loc
{ compat::getBeginLoc(expr
) };
325 while (compiler
.getSourceManager().isMacroArgExpansion(loc
)) {
326 loc
= compiler
.getSourceManager().getImmediateMacroCallerLoc(loc
);
328 if (compiler
.getSourceManager().isMacroBodyExpansion(loc
)) {
329 StringRef name
{ Lexer::getImmediateMacroName(
330 loc
, compiler
.getSourceManager(), compiler
.getLangOpts()) };
331 if (name
== "sal_False" || name
== "sal_True") {
332 auto callLoc
= compiler
.getSourceManager()
333 .getImmediateMacroCallerLoc(loc
);
334 if (!isSharedCAndCppCode(callLoc
)) {
335 SourceLocation argLoc
;
336 if (compiler
.getSourceManager().isMacroArgExpansion(
337 compat::getBeginLoc(expr
), &argLoc
)
338 //TODO: check it's the complete (first) arg to the macro
339 && (Lexer::getImmediateMacroName(
340 argLoc
, compiler
.getSourceManager(),
341 compiler
.getLangOpts())
342 == "CPPUNIT_ASSERT_EQUAL"))
344 // Ignore sal_False/True that are directly used as
345 // arguments to CPPUNIT_ASSERT_EQUAL:
348 bool b
= name
== "sal_True";
349 if (rewriter
!= nullptr) {
350 auto callSpellLoc
= compiler
.getSourceManager()
351 .getSpellingLoc(callLoc
);
352 unsigned n
= Lexer::MeasureTokenLength(
353 callSpellLoc
, compiler
.getSourceManager(),
354 compiler
.getLangOpts());
356 compiler
.getSourceManager().getCharacterData(
362 callSpellLoc
, n
, b
? "true" : "false");
366 DiagnosticsEngine::Warning
,
367 "use '%select{false|true}0' instead of '%1'", callLoc
)
368 << b
<< name
<< expr
->getSourceRange();
374 DiagnosticsEngine::Warning
,
375 "CStyleCastExpr, suspicious cast from %0 to %1",
376 compat::getBeginLoc(expr
))
377 << expr
->getSubExpr()->IgnoreParenImpCasts()->getType()
378 << expr
->getType() << expr
->getSourceRange();
383 bool SalBool::VisitCXXStaticCastExpr(CXXStaticCastExpr
* expr
) {
384 if (ignoreLocation(expr
)) {
387 if (isSalBool(expr
->getType())
388 && !isInSpecialMainFile(
389 compiler
.getSourceManager().getSpellingLoc(compat::getBeginLoc(expr
))))
392 DiagnosticsEngine::Warning
,
393 "CXXStaticCastExpr, suspicious cast from %0 to %1",
394 compat::getBeginLoc(expr
))
395 << expr
->getSubExpr()->IgnoreParenImpCasts()->getType()
396 << expr
->getType() << expr
->getSourceRange();
401 bool SalBool::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr
* expr
) {
402 if (ignoreLocation(expr
)) {
405 if (isSalBool(expr
->getType())) {
407 DiagnosticsEngine::Warning
,
408 "CXXFunctionalCastExpr, suspicious cast from %0 to %1",
409 compat::getBeginLoc(expr
))
410 << expr
->getSubExpr()->IgnoreParenImpCasts()->getType()
411 << expr
->getType() << expr
->getSourceRange();
416 bool SalBool::VisitImplicitCastExpr(ImplicitCastExpr
* expr
) {
417 if (ignoreLocation(expr
)) {
420 if (!isSalBool(expr
->getType())) {
423 auto l
= compat::getBeginLoc(expr
);
424 while (compiler
.getSourceManager().isMacroArgExpansion(l
)) {
425 l
= compiler
.getSourceManager().getImmediateMacroCallerLoc(l
);
427 if (compiler
.getSourceManager().isMacroBodyExpansion(l
)) {
428 auto n
= Lexer::getImmediateMacroName(
429 l
, compiler
.getSourceManager(), compiler
.getLangOpts());
430 if (n
== "sal_False" || n
== "sal_True") {
434 auto e1
= expr
->getSubExprAsWritten();
435 auto t
= e1
->getType();
436 if (!t
->isFundamentalType() || loplugin::TypeCheck(t
).AnyBoolean()) {
439 auto e2
= dyn_cast
<ConditionalOperator
>(e1
);
441 auto ic1
= dyn_cast
<ImplicitCastExpr
>(
442 e2
->getTrueExpr()->IgnoreParens());
443 auto ic2
= dyn_cast
<ImplicitCastExpr
>(
444 e2
->getFalseExpr()->IgnoreParens());
445 if (ic1
!= nullptr && ic2
!= nullptr
446 && ic1
->getType()->isSpecificBuiltinType(BuiltinType::Int
)
447 && (loplugin::TypeCheck(ic1
->getSubExprAsWritten()->getType())
449 && ic2
->getType()->isSpecificBuiltinType(BuiltinType::Int
)
450 && (loplugin::TypeCheck(ic2
->getSubExprAsWritten()->getType())
457 DiagnosticsEngine::Warning
, "conversion from %0 to sal_Bool",
458 compat::getBeginLoc(expr
))
459 << t
<< expr
->getSourceRange();
463 bool SalBool::VisitReturnStmt(ReturnStmt
const * stmt
) {
464 // Just enough to avoid warnings in rtl_getUriCharClass (sal/rtl/uri.cxx),
467 // static sal_Bool const aCharClass[][nCharClassSize] = ...;
471 // return aCharClass[eCharClass];
473 if (ignoreLocation(stmt
)) {
476 auto e
= stmt
->getRetValue();
480 auto t
= e
->getType();
481 if (!t
->isPointerType()) {
485 auto t2
= t
->getAs
<clang::PointerType
>();
489 t
= t2
->getPointeeType();
494 auto e2
= dyn_cast
<ArraySubscriptExpr
>(e
->IgnoreParenImpCasts());
498 auto e3
= dyn_cast
<DeclRefExpr
>(e2
->getBase()->IgnoreParenImpCasts());
502 auto d
= dyn_cast
<VarDecl
>(e3
->getDecl());
510 bool SalBool::WalkUpFromParmVarDecl(ParmVarDecl
const * decl
) {
511 return VisitParmVarDecl(decl
);
514 bool SalBool::VisitParmVarDecl(ParmVarDecl
const * decl
) {
515 if (ignoreLocation(decl
)) {
518 if (isSalBool(decl
->getType().getNonReferenceType())) {
519 FunctionDecl
const * f
= dyn_cast
<FunctionDecl
>(decl
->getDeclContext());
520 if (f
!= nullptr) { // e.g.: typedef sal_Bool (* FuncPtr )( sal_Bool );
521 f
= f
->getCanonicalDecl();
522 if (!(hasCLanguageLinkageType(f
)
523 || (isInUnoIncludeFile(f
)
524 && (!f
->isInlined() || f
->hasAttr
<DeprecatedAttr
>()
525 || decl
->getType()->isReferenceType()
526 || hasBoolOverload(f
, false)))
527 || f
->isDeleted() || hasBoolOverload(f
, true)))
529 OverrideKind k
= getOverrideKind(f
);
530 if (k
!= OverrideKind::YES
) {
531 SourceLocation loc
{ compat::getBeginLoc(decl
) };
532 TypeSourceInfo
* tsi
= decl
->getTypeSourceInfo();
533 if (tsi
!= nullptr) {
535 compiler
.getSourceManager().getExpansionLoc(
536 tsi
->getTypeLoc().getBeginLoc()) };
538 compiler
.getSourceManager().getExpansionLoc(
539 tsi
->getTypeLoc().getEndLoc()) };
540 assert(l
.isFileID() && end
.isFileID());
542 || (compiler
.getSourceManager()
543 .isBeforeInTranslationUnit(l
, end
)))
546 unsigned n
= Lexer::MeasureTokenLength(
547 l
, compiler
.getSourceManager(),
548 compiler
.getLangOpts());
550 compiler
.getSourceManager().getCharacterData(l
),
552 if (s
== "sal_Bool") {
559 l
= l
.getLocWithOffset(std::max
<unsigned>(n
, 1));
563 // Only rewrite declarations in include files if a
564 // definition is also seen, to avoid compilation of a
565 // definition (in a main file only processed later) to fail
566 // with a "mismatch" error before the rewriter had a chance
567 // to act upon the definition (but use the heuristic of
568 // assuming pure virtual functions do not have definitions);
569 // also, do not automatically rewrite functions that could
570 // implicitly override depend base functions (and thus stop
571 // doing so after the rewrite; note that this is less
572 // dangerous for return types than for parameter types,
573 // where the function would still implicitly override and
574 // cause a compilation error due to the incompatible return
576 if (!((compiler
.getSourceManager().isInMainFile(
577 compiler
.getSourceManager().getSpellingLoc(
578 dyn_cast
<FunctionDecl
>(
579 decl
->getDeclContext())
580 ->getNameInfo().getLoc()))
581 || f
->isDefined() || f
->isPure())
582 && k
!= OverrideKind::MAYBE
&& rewrite(loc
)))
585 DiagnosticsEngine::Warning
,
586 ("ParmVarDecl, use \"bool\" instead of"
589 << (k
== OverrideKind::MAYBE
590 ? (" (unless this member function overrides a"
591 " dependent base member function, even"
592 " though it is not marked 'override')")
594 << decl
->getSourceRange();
603 bool SalBool::WalkUpFromVarDecl(VarDecl
const * decl
) {
604 return VisitVarDecl(decl
);
607 bool SalBool::VisitVarDecl(VarDecl
const * decl
) {
608 if (ignoreLocation(decl
)) {
611 if (!decl
->isExternC()
612 && (isSalBool(decl
->getType()) || isSalBoolArray(decl
->getType()))
613 && !isInSpecialMainFile(
614 compiler
.getSourceManager().getSpellingLoc(compat::getBeginLoc(decl
))))
616 varDecls_
.insert(decl
);
621 bool SalBool::WalkUpFromFieldDecl(FieldDecl
const * decl
) {
622 return VisitFieldDecl(decl
);
625 bool SalBool::VisitFieldDecl(FieldDecl
const * decl
) {
626 if (ignoreLocation(decl
)) {
629 if ((isSalBool(decl
->getType()) || isSalBoolArray(decl
->getType()))
630 && !isInSpecialMainFile(
631 compiler
.getSourceManager().getSpellingLoc(compat::getBeginLoc(decl
))))
633 TagDecl
const * td
= dyn_cast
<TagDecl
>(decl
->getDeclContext());
634 assert(td
!= nullptr);
635 if (!(((td
->isStruct() || td
->isUnion()) && td
->isExternCContext())
636 || isInUnoIncludeFile(
637 compiler
.getSourceManager().getSpellingLoc(
638 decl
->getLocation()))))
640 SourceLocation loc
{ compat::getBeginLoc(decl
) };
641 TypeSourceInfo
* tsi
= decl
->getTypeSourceInfo();
642 if (tsi
!= nullptr) {
644 compiler
.getSourceManager().getExpansionLoc(
645 tsi
->getTypeLoc().getBeginLoc()) };
647 compiler
.getSourceManager().getExpansionLoc(
648 tsi
->getTypeLoc().getEndLoc()) };
649 assert(l
.isFileID() && end
.isFileID());
651 || compiler
.getSourceManager().isBeforeInTranslationUnit(
655 unsigned n
= Lexer::MeasureTokenLength(
656 l
, compiler
.getSourceManager(),
657 compiler
.getLangOpts());
659 compiler
.getSourceManager().getCharacterData(l
),
661 if (s
== "sal_Bool") {
668 l
= l
.getLocWithOffset(std::max
<unsigned>(n
, 1));
674 DiagnosticsEngine::Warning
,
675 "FieldDecl, use \"bool\" instead of \"sal_Bool\"", loc
)
676 << decl
->getSourceRange();
683 bool SalBool::WalkUpFromFunctionDecl(FunctionDecl
const * decl
) {
684 return VisitFunctionDecl(decl
);
687 bool SalBool::VisitFunctionDecl(FunctionDecl
const * decl
) {
688 if (ignoreLocation(decl
)) {
691 if (isSalBool(decl
->getReturnType().getNonReferenceType())
692 && !(decl
->isDeletedAsWritten() && isa
<CXXConversionDecl
>(decl
)))
694 FunctionDecl
const * f
= decl
->getCanonicalDecl();
695 OverrideKind k
= getOverrideKind(f
);
696 if (k
!= OverrideKind::YES
697 && !(hasCLanguageLinkageType(f
)
698 || (isInUnoIncludeFile(f
)
699 && (!f
->isInlined() || f
->hasAttr
<DeprecatedAttr
>()))))
701 SourceLocation loc
{ compat::getBeginLoc(decl
) };
702 SourceLocation l
{ compiler
.getSourceManager().getExpansionLoc(
704 SourceLocation end
{ compiler
.getSourceManager().getExpansionLoc(
705 decl
->getNameInfo().getLoc()) };
706 assert(l
.isFileID() && end
.isFileID());
707 if (compiler
.getSourceManager().isBeforeInTranslationUnit(l
, end
)) {
709 unsigned n
= Lexer::MeasureTokenLength(
710 l
, compiler
.getSourceManager(), compiler
.getLangOpts());
712 compiler
.getSourceManager().getCharacterData(l
), n
};
713 if (s
== "sal_Bool") {
717 l
= l
.getLocWithOffset(std::max
<unsigned>(n
, 1));
720 // Only rewrite declarations in include files if a definition is
721 // also seen, to avoid compilation of a definition (in a main file
722 // only processed later) to fail with a "mismatch" error before the
723 // rewriter had a chance to act upon the definition (but use the
724 // heuristic of assuming pure virtual functions do not have
726 if (!((compiler
.getSourceManager().isInMainFile(
727 compiler
.getSourceManager().getSpellingLoc(
728 decl
->getNameInfo().getLoc()))
729 || f
->isDefined() || f
->isPure())
733 DiagnosticsEngine::Warning
,
734 "use \"bool\" instead of \"sal_Bool\" as return type%0",
736 << (k
== OverrideKind::MAYBE
737 ? (" (unless this member function overrides a dependent"
738 " base member function, even though it is not marked"
741 << decl
->getSourceRange();
748 bool SalBool::VisitValueDecl(ValueDecl
const * decl
) {
749 if (ignoreLocation(decl
)) {
752 if (isSalBool(decl
->getType()) && !rewrite(compat::getBeginLoc(decl
))) {
754 DiagnosticsEngine::Warning
,
755 "ValueDecl, use \"bool\" instead of \"sal_Bool\"",
756 compat::getBeginLoc(decl
))
757 << decl
->getSourceRange();
762 bool SalBool::TraverseStaticAssertDecl(StaticAssertDecl
* decl
) {
763 // Ignore special code like
765 // static_cast<sal_Bool>(true) == sal_True
767 // inside static_assert in cppu/source/uno/check.cxx:
769 loplugin::isSamePathname(
770 getFileNameOfSpellingLoc(decl
->getLocation()),
771 SRCDIR
"/cppu/source/uno/check.cxx")
772 || RecursiveASTVisitor::TraverseStaticAssertDecl(decl
);
775 bool SalBool::TraverseLinkageSpecDecl(LinkageSpecDecl
* decl
) {
776 assert(externCContexts_
!= std::numeric_limits
<unsigned int>::max()); //TODO
778 bool ret
= RecursiveASTVisitor::TraverseLinkageSpecDecl(decl
);
779 assert(externCContexts_
!= 0);
784 bool SalBool::isFromCIncludeFile(SourceLocation spellingLocation
) const {
785 return !compiler
.getSourceManager().isInMainFile(spellingLocation
)
787 compiler
.getSourceManager().getPresumedLoc(spellingLocation
)
792 bool SalBool::isSharedCAndCppCode(SourceLocation location
) const {
793 // Assume that code is intended to be shared between C and C++ if it comes
794 // from an include file ending in .h, and is either in an extern "C" context
795 // or the body of a macro definition:
797 isFromCIncludeFile(compiler
.getSourceManager().getSpellingLoc(location
))
798 && (externCContexts_
!= 0
799 || compiler
.getSourceManager().isMacroBodyExpansion(location
));
802 bool SalBool::isInSpecialMainFile(SourceLocation spellingLocation
) const {
803 if (!compiler
.getSourceManager().isInMainFile(spellingLocation
)) {
806 auto f
= getFileNameOfSpellingLoc(spellingLocation
);
807 return loplugin::isSamePathname(f
, SRCDIR
"/cppu/qa/test_any.cxx")
808 || loplugin::isSamePathname(f
, SRCDIR
"/cppu/source/uno/check.cxx");
809 // TODO: the offset checks
812 bool SalBool::rewrite(SourceLocation location
) {
813 if (rewriter
!= nullptr) {
814 //TODO: "::sal_Bool" -> "bool", not "::bool"
815 SourceLocation loc
{ compiler
.getSourceManager().getExpansionLoc(
817 unsigned n
= Lexer::MeasureTokenLength(
818 loc
, compiler
.getSourceManager(), compiler
.getLangOpts());
819 if (std::string(compiler
.getSourceManager().getCharacterData(loc
), n
)
822 return replaceText(loc
, n
, "bool");
828 loplugin::Plugin::Registration
<SalBool
> X("salbool", true);
832 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */