Move setting of LD_LIBRARY_PATH closer to invocation of cppunittester
[LibreOffice.git] / compilerplugins / clang / store / comparisonwithconstant.cxx
blobd796b7c3a3a1d6513d269bf12cb8ff7eda38af2b
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 <cassert>
11 #include <string>
12 #include <iostream>
13 #include <fstream>
14 #include <set>
16 #include "compat.hxx"
17 #include "plugin.hxx"
19 /**
20 Look for comparisons where the constant is on the left, it should be on the right.
23 namespace {
25 class ComparisonWithConstant :
26 public loplugin::FilteringRewritePlugin<ComparisonWithConstant>
28 public:
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);
48 occurrence_ = saved;
49 return ret;
52 bool VisitBinaryOperator(const BinaryOperator *);
53 private:
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)) {
64 return true;
66 if (!(binaryOp->getOpcode() == BO_EQ || binaryOp->getOpcode() == BO_NE)) {
67 return true;
69 // protect against clang assert
70 if (binaryOp->getLHS()->isValueDependent() || binaryOp->getRHS()->isValueDependent()) {
71 return true;
73 if (!binaryOp->getLHS()->isEvaluatable(compiler.getASTContext())) {
74 return true;
76 if (binaryOp->getRHS()->isEvaluatable(compiler.getASTContext())) {
77 return true;
79 if (occurrence_ || !rewrite(binaryOp))
81 report(
82 DiagnosticsEngine::Warning, "Rather put constant on right when comparing",
83 binaryOp->getSourceRange().getBegin())
84 << binaryOp->getSourceRange();
86 occurrence_ = true;
87 return true;
91 bool ComparisonWithConstant::rewrite(const BinaryOperator * binaryOp) {
92 if (rewriter == nullptr) {
93 return false;
96 auto lhsRange = ignoreMacroExpansions(binaryOp->getLHS()->getSourceRange());
97 if (!lhsRange.isValid()) {
98 return false;
100 auto rhsRange = ignoreMacroExpansions(binaryOp->getRHS()->getSourceRange());
101 if (!rhsRange.isValid()) {
102 return false;
105 const std::string lhsString = getExprAsString(lhsRange);
106 const std::string rhsString = getExprAsString(rhsRange);
108 // switch LHS and RHS
109 if (!replaceText(lhsRange, rhsString)) {
110 return false;
112 if (!replaceText(rhsRange, lhsString)) {
113 return false;
116 return true;
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())) {
133 range.setBegin(
134 compiler.getSourceManager().getImmediateMacroCallerLoc(
135 range.getBegin()));
137 if (range.getBegin().isMacroID()) {
138 SourceLocation loc;
139 if (Lexer::isAtStartOfMacroExpansion(
140 range.getBegin(), compiler.getSourceManager(),
141 compiler.getLangOpts(), &loc))
143 range.setBegin(loc);
146 while (compiler.getSourceManager().isMacroArgExpansion(range.getEnd())) {
147 range.setEnd(
148 compiler.getSourceManager().getImmediateMacroCallerLoc(
149 range.getEnd()));
151 if (range.getEnd().isMacroID()) {
152 SourceLocation loc;
153 if (Lexer::isAtEndOfMacroExpansion(
154 range.getEnd(), compiler.getSourceManager(),
155 compiler.getLangOpts(), &loc))
157 range.setEnd(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: */