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/.
20 Look for comparisons where the constant is on the left, it should be on the right.
25 class ComparisonWithConstant
:
26 public loplugin::FilteringRewritePlugin
<ComparisonWithConstant
>
29 explicit ComparisonWithConstant(loplugin::InstantiationData
const & data
): FilteringRewritePlugin(data
) {}
31 virtual void run() override
33 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
36 // Deliberately drop RecursiveASTVisitor::TraverseBinaryOperator's DataRecursionQueue
37 // parameter; TraverseBinaryOperator must use stack instead of data recursion for any
38 // children's VisitBinaryOperator to see changes to occurrence_ by a parent
39 // VisitBinaryOperator:
40 bool TraverseBinaryOperator(BinaryOperator
* S
)
42 auto const op
= S
->getOpcode();
43 if (op
!= BO_EQ
&& op
!= BO_NE
) {
44 return RecursiveASTVisitor::TraverseBinaryOperator(S
);
46 auto const saved
= occurrence_
;
47 auto const ret
= RecursiveASTVisitor::TraverseBinaryOperator(S
);
52 bool VisitBinaryOperator(const BinaryOperator
*);
54 bool rewrite(const BinaryOperator
*);
55 std::string
getExprAsString(SourceRange range
);
56 SourceRange
ignoreMacroExpansions(SourceRange range
);
58 bool occurrence_
= false;
61 bool ComparisonWithConstant::VisitBinaryOperator(const BinaryOperator
* binaryOp
)
63 if (ignoreLocation(binaryOp
)) {
66 if (!(binaryOp
->getOpcode() == BO_EQ
|| binaryOp
->getOpcode() == BO_NE
)) {
69 // protect against clang assert
70 if (binaryOp
->getLHS()->isValueDependent() || binaryOp
->getRHS()->isValueDependent()) {
73 if (!binaryOp
->getLHS()->isEvaluatable(compiler
.getASTContext())) {
76 if (binaryOp
->getRHS()->isEvaluatable(compiler
.getASTContext())) {
79 if (occurrence_
|| !rewrite(binaryOp
))
82 DiagnosticsEngine::Warning
, "Rather put constant on right when comparing",
83 binaryOp
->getSourceRange().getBegin())
84 << binaryOp
->getSourceRange();
91 bool ComparisonWithConstant::rewrite(const BinaryOperator
* binaryOp
) {
92 if (rewriter
== nullptr) {
96 auto lhsRange
= ignoreMacroExpansions(binaryOp
->getLHS()->getSourceRange());
97 if (!lhsRange
.isValid()) {
100 auto rhsRange
= ignoreMacroExpansions(binaryOp
->getRHS()->getSourceRange());
101 if (!rhsRange
.isValid()) {
105 const std::string lhsString
= getExprAsString(lhsRange
);
106 const std::string rhsString
= getExprAsString(rhsRange
);
108 // switch LHS and RHS
109 if (!replaceText(lhsRange
, rhsString
)) {
112 if (!replaceText(rhsRange
, lhsString
)) {
119 // get the expression contents
120 std::string
ComparisonWithConstant::getExprAsString(SourceRange range
)
122 SourceManager
& SM
= compiler
.getSourceManager();
123 SourceLocation startLoc
= range
.getBegin();
124 SourceLocation endLoc
= range
.getEnd();
125 const char *p1
= SM
.getCharacterData( startLoc
);
126 const char *p2
= SM
.getCharacterData( endLoc
);
127 unsigned n
= Lexer::MeasureTokenLength( endLoc
, SM
, compiler
.getLangOpts());
128 return std::string( p1
, p2
- p1
+ n
);
131 SourceRange
ComparisonWithConstant::ignoreMacroExpansions(SourceRange range
) {
132 while (compiler
.getSourceManager().isMacroArgExpansion(range
.getBegin())) {
134 compiler
.getSourceManager().getImmediateMacroCallerLoc(
137 if (range
.getBegin().isMacroID()) {
139 if (Lexer::isAtStartOfMacroExpansion(
140 range
.getBegin(), compiler
.getSourceManager(),
141 compiler
.getLangOpts(), &loc
))
146 while (compiler
.getSourceManager().isMacroArgExpansion(range
.getEnd())) {
148 compiler
.getSourceManager().getImmediateMacroCallerLoc(
151 if (range
.getEnd().isMacroID()) {
153 if (Lexer::isAtEndOfMacroExpansion(
154 range
.getEnd(), compiler
.getSourceManager(),
155 compiler
.getLangOpts(), &loc
))
160 return range
.getBegin().isMacroID() || range
.getEnd().isMacroID()
161 ? SourceRange() : range
;
164 loplugin::Plugin::Registration
< ComparisonWithConstant
> X("comparisonwithconstant", false);
168 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */