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 "config_clang.h"
22 Look for comparisons where the constant is on the left, it should be on the right.
27 class ComparisonWithConstant
:
28 public loplugin::FilteringRewritePlugin
<ComparisonWithConstant
>
31 explicit ComparisonWithConstant(loplugin::InstantiationData
const & data
): FilteringRewritePlugin(data
) {}
33 virtual void run() override
35 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
38 // Deliberately drop RecursiveASTVisitor::TraverseBinaryOperator's DataRecursionQueue
39 // parameter; TraverseBinaryOperator must use stack instead of data recursion for any
40 // children's VisitBinaryOperator to see changes to occurrence_ by a parent
41 // VisitBinaryOperator:
42 bool TraverseBinaryOperator(BinaryOperator
* S
)
44 auto const op
= S
->getOpcode();
45 if (op
!= BO_EQ
&& op
!= BO_NE
) {
46 return RecursiveASTVisitor::TraverseBinaryOperator(S
);
48 auto const saved
= occurrence_
;
49 auto const ret
= RecursiveASTVisitor::TraverseBinaryOperator(S
);
54 #if CLANG_VERSION < 110000
55 bool TraverseBinEQ(BinaryOperator
* expr
) { return TraverseBinaryOperator(expr
); }
56 bool TraverseBinNE(BinaryOperator
* expr
) { return TraverseBinaryOperator(expr
); }
59 bool VisitBinaryOperator(const BinaryOperator
*);
61 bool rewrite(const BinaryOperator
*);
62 std::string
getExprAsString(SourceRange range
);
63 SourceRange
ignoreMacroExpansions(SourceRange range
);
65 bool occurrence_
= false;
68 bool ComparisonWithConstant::VisitBinaryOperator(const BinaryOperator
* binaryOp
)
70 if (ignoreLocation(binaryOp
)) {
73 if (!(binaryOp
->getOpcode() == BO_EQ
|| binaryOp
->getOpcode() == BO_NE
)) {
76 // protect against clang assert
77 if (binaryOp
->getLHS()->isValueDependent() || binaryOp
->getRHS()->isValueDependent()) {
80 if (!binaryOp
->getLHS()->isEvaluatable(compiler
.getASTContext())) {
83 if (binaryOp
->getRHS()->isEvaluatable(compiler
.getASTContext())) {
86 if (occurrence_
|| !rewrite(binaryOp
))
89 DiagnosticsEngine::Warning
, "Rather put constant on right when comparing",
90 binaryOp
->getSourceRange().getBegin())
91 << binaryOp
->getSourceRange();
98 bool ComparisonWithConstant::rewrite(const BinaryOperator
* binaryOp
) {
99 if (rewriter
== nullptr) {
103 auto lhsRange
= ignoreMacroExpansions(binaryOp
->getLHS()->getSourceRange());
104 if (!lhsRange
.isValid()) {
107 auto rhsRange
= ignoreMacroExpansions(binaryOp
->getRHS()->getSourceRange());
108 if (!rhsRange
.isValid()) {
112 const std::string lhsString
= getExprAsString(lhsRange
);
113 const std::string rhsString
= getExprAsString(rhsRange
);
115 // switch LHS and RHS
116 if (!replaceText(lhsRange
, rhsString
)) {
119 if (!replaceText(rhsRange
, lhsString
)) {
126 // get the expression contents
127 std::string
ComparisonWithConstant::getExprAsString(SourceRange range
)
129 SourceManager
& SM
= compiler
.getSourceManager();
130 SourceLocation startLoc
= range
.getBegin();
131 SourceLocation endLoc
= range
.getEnd();
132 const char *p1
= SM
.getCharacterData( startLoc
);
133 const char *p2
= SM
.getCharacterData( endLoc
);
134 unsigned n
= Lexer::MeasureTokenLength( endLoc
, SM
, compiler
.getLangOpts());
135 return std::string( p1
, p2
- p1
+ n
);
138 SourceRange
ComparisonWithConstant::ignoreMacroExpansions(SourceRange range
) {
139 while (compiler
.getSourceManager().isMacroArgExpansion(range
.getBegin())) {
141 compiler
.getSourceManager().getImmediateMacroCallerLoc(
144 if (range
.getBegin().isMacroID()) {
146 if (Lexer::isAtStartOfMacroExpansion(
147 range
.getBegin(), compiler
.getSourceManager(),
148 compiler
.getLangOpts(), &loc
))
153 while (compiler
.getSourceManager().isMacroArgExpansion(range
.getEnd())) {
155 compiler
.getSourceManager().getImmediateMacroCallerLoc(
158 if (range
.getEnd().isMacroID()) {
160 if (Lexer::isAtEndOfMacroExpansion(
161 range
.getEnd(), compiler
.getSourceManager(),
162 compiler
.getLangOpts(), &loc
))
167 return range
.getBegin().isMacroID() || range
.getEnd().isMacroID()
168 ? SourceRange() : range
;
171 loplugin::Plugin::Registration
< ComparisonWithConstant
> X("comparisonwithconstant", false);
175 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */