Update git submodules
[LibreOffice.git] / compilerplugins / clang / buriedassign.cxx
blob8c2b13c3a708d511bc461c4b8900ee7771c96bbb
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 <unordered_set>
15 #include "plugin.hxx"
16 #include "check.hxx"
17 #include "config_clang.h"
18 #include "clang/AST/CXXInheritance.h"
19 #include "clang/AST/StmtVisitor.h"
21 // This checker aims to pull buried assignments out of complex expressions,
22 // where they are quite hard to notice amidst the other conditional logic.
24 namespace
26 class BuriedAssign : public loplugin::FilteringPlugin<BuriedAssign>
28 public:
29 explicit BuriedAssign(loplugin::InstantiationData const& data)
30 : FilteringPlugin(data)
34 virtual void run() override
36 std::string fn(handler.getMainFileName());
37 loplugin::normalizeDotDotInFilePath(fn);
39 // code where I don't have a better alternative
40 if (fn == SRCDIR "/sal/osl/unx/profile.cxx")
41 return;
42 if (fn == SRCDIR "/sal/rtl/uri.cxx")
43 return;
44 if (fn == SRCDIR "/sal/osl/unx/process.cxx")
45 return;
46 if (fn == SRCDIR "/sal/rtl/bootstrap.cxx")
47 return;
48 if (fn == SRCDIR "/i18npool/source/textconversion/genconv_dict.cxx")
49 return;
50 if (fn == SRCDIR "/soltools/cpp/_macro.c")
51 return;
52 if (fn == SRCDIR "/stoc/source/inspect/introspection.cxx")
53 return;
54 if (fn == SRCDIR "/tools/source/fsys/urlobj.cxx")
55 return;
56 if (fn == SRCDIR "/sax/source/tools/fastserializer.cxx")
57 return;
58 if (fn == SRCDIR "/svl/source/crypto/cryptosign.cxx")
59 return;
60 if (fn == SRCDIR "/svl/source/numbers/zforfind.cxx")
61 return;
62 if (fn == SRCDIR "/svl/source/numbers/zformat.cxx")
63 return;
64 if (fn == SRCDIR "/svl/source/numbers/zforscan.cxx")
65 return;
66 if (fn == SRCDIR "/svl/source/numbers/zforlist.cxx")
67 return;
68 if (fn == SRCDIR "/vcl/source/window/debugevent.cxx")
69 return;
70 if (fn == SRCDIR "/vcl/source/control/scrbar.cxx")
71 return;
72 if (fn == SRCDIR "/vcl/source/gdi/bitmap3.cxx")
73 return;
74 if (fn == SRCDIR "/vcl/source/window/menu.cxx")
75 return;
76 if (fn == SRCDIR "/vcl/source/fontsubset/sft.cxx")
77 return;
78 if (fn == SRCDIR "/vcl/unx/generic/print/prtsetup.cxx")
79 return;
80 if (fn == SRCDIR "/svtools/source/brwbox/brwbox1.cxx")
81 return;
82 if (fn == SRCDIR "/svtools/source/control/valueset.cxx")
83 return;
84 if (fn == SRCDIR "/basic/source/runtime/iosys.cxx")
85 return;
86 if (fn == SRCDIR "/basic/source/runtime/runtime.cxx")
87 return;
88 if (fn == SRCDIR "/basic/source/sbx/sbxvalue.cxx")
89 return;
90 if (fn == SRCDIR "/basic/source/sbx/sbxvalue.cxx")
91 return;
92 if (fn == SRCDIR "/sfx2/source/dialog/templdlg.cxx")
93 return;
94 if (fn == SRCDIR "/sfx2/source/view/viewfrm.cxx")
95 return;
96 if (fn == SRCDIR "/connectivity/source/commontools/dbtools.cxx")
97 return;
98 if (fn == SRCDIR "/xmloff/source/style/xmlnumfi.cxx")
99 return;
100 if (fn == SRCDIR "/xmloff/source/style/xmlnumfe .cxx")
101 return;
102 if (fn == SRCDIR "/editeng/source/items/textitem.cxx")
103 return;
104 if (fn == SRCDIR "/editeng/source/rtf/rtfitem.cxx")
105 return;
106 if (fn == SRCDIR "/editeng/source/rtf/svxrtf.cxx")
107 return;
108 if (fn == SRCDIR "/editeng/source/misc/svxacorr.cxx")
109 return;
110 if (fn == SRCDIR "/svx/source/items/numfmtsh.cxx")
111 return;
112 if (fn == SRCDIR "/svx/source/dialog/hdft.cxx")
113 return;
114 if (fn == SRCDIR "/cui/source/dialogs/insdlg.cxx")
115 return;
116 if (fn == SRCDIR "/cui/source/tabpages/paragrph.cxx")
117 return;
118 if (fn == SRCDIR "/cui/source/tabpages/page.cxx")
119 return;
120 if (fn == SRCDIR "/cui/source/tabpages/border.cxx")
121 return;
122 if (fn == SRCDIR "/cui/source/tabpages/chardlg.cxx")
123 return;
124 if (fn == SRCDIR "/cui/source/tabpages/numpages.cxx")
125 return;
126 if (fn == SRCDIR "/cui/source/dialogs/SpellDialog.cxx")
127 return;
128 if (fn == SRCDIR "/oox/source/drawingml/diagram/diagramlayoutatoms.cxx")
129 return;
130 if (fn == SRCDIR "/dbaccess/source/core/dataaccess/intercept.cxx")
131 return;
132 if (fn == SRCDIR "/sw/writerfilter/dmapper/DomainMapper.cxx")
133 return;
134 if (fn == SRCDIR "/sw/writerfilter/dmapper/DomainMapper_Impl.cxx")
135 return;
136 if (fn == SRCDIR "/lotuswordpro/source/filter/lwptablelayout.cxx")
137 return;
138 if (fn == SRCDIR "/i18npool/source/characterclassification/cclass_unicode_parser.cxx")
139 return;
140 if (fn == SRCDIR "/sd/source/filter/eppt/pptx-animations.cxx")
141 return;
142 if (fn == SRCDIR "/sc/source/core/tool/address.cxx")
143 return;
144 if (fn == SRCDIR "/sc/source/core/tool/interpr1.cxx")
145 return;
146 if (fn == SRCDIR "/sc/source/core/tool/interpr4.cxx")
147 return;
148 if (fn == SRCDIR "/sc/source/core/tool/interpr5.cxx")
149 return;
150 if (fn == SRCDIR "/sc/source/core/tool/compiler.cxx")
151 return;
152 if (fn == SRCDIR "/sc/source/core/data/table4.cxx")
153 return;
154 if (fn == SRCDIR "/sc/source/ui/drawfunc/fudraw.cxx")
155 return;
156 if (fn == SRCDIR "/sc/source/filter/xml/xmlcelli.cxx")
157 return;
158 if (fn == SRCDIR "/sc/source/ui/miscdlgs/crnrdlg.cxx")
159 return;
160 if (fn == SRCDIR "/sc/source/ui/app/inputwin.cxx")
161 return;
162 if (fn == SRCDIR "/sc/source/ui/view/viewfun2.cxx")
163 return;
164 if (fn == SRCDIR "/sc/source/ui/unoobj/docuno.cxx")
165 return;
166 if (fn == SRCDIR "/sc/source/ui/view/gridwin.cxx")
167 return;
168 if (fn == SRCDIR "/sw/source/core/crsr/callnk.cxx")
169 return;
170 if (fn == SRCDIR "/sw/source/core/crsr/findtxt.cxx")
171 return;
172 if (fn == SRCDIR "/sw/source/core/crsr/crsrsh.cxx")
173 return;
174 if (fn == SRCDIR "/sw/source/core/crsr/crstrvl.cxx")
175 return;
176 if (fn == SRCDIR "/sw/source/core/doc/doccomp.cxx")
177 return;
178 if (fn == SRCDIR "/sw/source/core/doc/docedt.cxx")
179 return;
180 if (fn == SRCDIR "/sw/source/core/doc/docfly.cxx")
181 return;
182 if (fn == SRCDIR "/sw/source/core/doc/DocumentRedlineManager.cxx")
183 return;
184 if (fn == SRCDIR "/sw/source/core/doc/notxtfrm.cxx")
185 return;
186 if (fn == SRCDIR "/sw/source/core/docnode/node.cxx")
187 return;
188 if (fn == SRCDIR "/sw/source/core/layout/ftnfrm.cxx")
189 return;
190 if (fn == SRCDIR "/sw/source/core/table/swtable.cxx")
191 return;
192 if (fn == SRCDIR "/sw/source/core/unocore/unoframe.cxx")
193 return;
194 if (fn == SRCDIR "/sw/source/filter/xml/xmlimp.cxx")
195 return;
196 if (fn == SRCDIR "/sw/source/uibase/docvw/edtwin.cxx")
197 return;
198 if (fn == SRCDIR "/sw/source/uibase/shells/langhelper.cxx")
199 return;
200 if (fn == SRCDIR "/sw/source/uibase/shells/tabsh.cxx")
201 return;
202 if (fn == SRCDIR "/sw/source/uibase/shells/textsh1.cxx")
203 return;
204 if (fn == SRCDIR "/sw/source/uibase/uiview/view2.cxx")
205 return;
206 if (fn == SRCDIR "/starmath/source/mathtype.cxx")
207 return;
208 if (fn == SRCDIR "/starmath/source/mathmlexport.cxx")
209 return;
210 if (fn == SRCDIR "/starmath/source/view.cxx")
211 return;
212 if (fn == SRCDIR "/xmlhelp/source/treeview/tvread.cxx")
213 return;
214 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
217 bool VisitBinaryOperator(BinaryOperator const*);
218 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr const*);
219 bool VisitCompoundStmt(CompoundStmt const*);
220 bool VisitIfStmt(IfStmt const*);
221 bool VisitLabelStmt(LabelStmt const*);
222 bool VisitForStmt(ForStmt const*);
223 bool VisitCXXForRangeStmt(CXXForRangeStmt const*);
224 bool VisitWhileStmt(WhileStmt const*);
225 bool VisitDoStmt(DoStmt const*);
226 bool VisitCaseStmt(CaseStmt const*);
227 bool VisitDefaultStmt(DefaultStmt const*);
228 bool VisitVarDecl(VarDecl const*);
229 bool VisitCXXFoldExpr(CXXFoldExpr const*);
231 private:
232 void MarkIfAssignment(Stmt const*);
233 void MarkAll(Stmt const*);
234 void MarkConditionForControlLoops(Expr const*);
236 std::unordered_set<const Stmt*> m_handled;
239 static bool isAssignmentOp(clang::BinaryOperatorKind op)
241 // We ignore BO_ShrAssign i.e. >>= because we use that everywhere for
242 // extracting data from css::uno::Any
243 return op == BO_Assign || op == BO_MulAssign || op == BO_DivAssign || op == BO_RemAssign
244 || op == BO_AddAssign || op == BO_SubAssign || op == BO_ShlAssign || op == BO_AndAssign
245 || op == BO_XorAssign || op == BO_OrAssign;
248 static bool isAssignmentOp(clang::OverloadedOperatorKind Opc)
250 // Same logic as CXXOperatorCallExpr::isAssignmentOp(), which our supported clang
251 // doesn't have yet.
252 // Except that we ignore OO_GreaterGreaterEqual i.e. >>= because we use that everywhere for
253 // extracting data from css::uno::Any
254 return Opc == OO_Equal || Opc == OO_StarEqual || Opc == OO_SlashEqual || Opc == OO_PercentEqual
255 || Opc == OO_PlusEqual || Opc == OO_MinusEqual || Opc == OO_LessLessEqual
256 || Opc == OO_AmpEqual || Opc == OO_CaretEqual || Opc == OO_PipeEqual;
259 static const Expr* IgnoreImplicitAndConversionOperator(const Expr* expr)
261 expr = expr->IgnoreImplicit();
262 if (auto memberCall = dyn_cast<CXXMemberCallExpr>(expr))
264 if (auto conversionDecl = dyn_cast_or_null<CXXConversionDecl>(memberCall->getMethodDecl()))
266 if (!conversionDecl->isExplicit())
267 expr = memberCall->getImplicitObjectArgument()->IgnoreImplicit();
270 return expr;
273 bool BuriedAssign::VisitBinaryOperator(BinaryOperator const* binaryOp)
275 if (ignoreLocation(binaryOp))
276 return true;
277 if (binaryOp->getBeginLoc().isMacroID())
278 return true;
279 if (!isAssignmentOp(binaryOp->getOpcode()))
280 return true;
281 auto expr = IgnoreImplicitAndConversionOperator(binaryOp->getRHS());
282 if (auto rhs = dyn_cast<BinaryOperator>(expr))
284 // Ignore chained assignment.
285 // TODO limit this to only ordinary assignment
286 if (isAssignmentOp(rhs->getOpcode()))
287 m_handled.insert(rhs);
289 else if (auto rhs = dyn_cast<CXXOperatorCallExpr>(expr))
291 // Ignore chained assignment.
292 // TODO limit this to only ordinary assignment
293 if (isAssignmentOp(rhs->getOperator()))
294 m_handled.insert(rhs);
296 else if (auto cxxConstruct = dyn_cast<CXXConstructExpr>(expr))
298 if (cxxConstruct->getNumArgs() == 1)
299 MarkIfAssignment(cxxConstruct->getArg(0));
301 if (!m_handled.insert(binaryOp).second)
302 return true;
304 // assignment in constructor
305 StringRef aFileName = getFilenameOfLocation(
306 compiler.getSourceManager().getSpellingLoc(binaryOp->getBeginLoc()));
307 if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/include/comphelper/flagguard.hxx"))
308 return true;
310 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
311 binaryOp->getBeginLoc())
312 << binaryOp->getSourceRange();
313 //getParentStmt(getParentStmt(getParentStmt(getParentStmt(getParentStmt(getParentStmt(binaryOp))))))->dump();
314 return true;
317 bool BuriedAssign::VisitCXXOperatorCallExpr(CXXOperatorCallExpr const* cxxOper)
319 if (ignoreLocation(cxxOper))
320 return true;
321 if (cxxOper->getBeginLoc().isMacroID())
322 return true;
323 if (!isAssignmentOp(cxxOper->getOperator()))
324 return true;
325 auto expr = IgnoreImplicitAndConversionOperator(cxxOper->getArg(1));
326 if (auto rhs = dyn_cast<BinaryOperator>(expr))
328 // Ignore chained assignment.
329 // TODO limit this to only ordinary assignment
330 if (isAssignmentOp(rhs->getOpcode()))
331 m_handled.insert(rhs);
333 else if (auto rhs = dyn_cast<CXXOperatorCallExpr>(expr))
335 // Ignore chained assignment.
336 // TODO limit this to only ordinary assignment
337 if (isAssignmentOp(rhs->getOperator()))
338 m_handled.insert(rhs);
340 else if (auto cxxConstruct = dyn_cast<CXXConstructExpr>(expr))
342 if (cxxConstruct->getNumArgs() == 1)
343 MarkIfAssignment(cxxConstruct->getArg(0));
345 if (!m_handled.insert(cxxOper).second)
346 return true;
347 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
348 cxxOper->getBeginLoc())
349 << cxxOper->getSourceRange();
350 //getParentStmt(getParentStmt(getParentStmt(getParentStmt(getParentStmt(cxxOper)))))->dump();
351 return true;
354 bool BuriedAssign::VisitCompoundStmt(CompoundStmt const* compoundStmt)
356 if (ignoreLocation(compoundStmt))
357 return true;
358 for (auto i = compoundStmt->child_begin(); i != compoundStmt->child_end(); ++i)
360 if (auto expr = dyn_cast<Expr>(*i))
362 expr = expr->IgnoreImplicit();
363 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
365 // ignore comma-chained statements at this level
366 if (binaryOp->getOpcode() == BO_Comma)
368 MarkIfAssignment(binaryOp->getLHS());
369 MarkIfAssignment(binaryOp->getRHS());
370 continue;
373 MarkIfAssignment(expr);
376 return true;
379 void BuriedAssign::MarkIfAssignment(Stmt const* stmt)
381 if (auto expr = dyn_cast_or_null<Expr>(stmt))
383 expr = expr->IgnoreImplicit();
384 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
386 if (isAssignmentOp(binaryOp->getOpcode()))
388 m_handled.insert(expr);
389 MarkIfAssignment(binaryOp->getRHS()); // in case it is chained
391 else if (binaryOp->getOpcode() == BO_Comma)
393 MarkIfAssignment(binaryOp->getLHS());
394 MarkIfAssignment(binaryOp->getRHS());
397 else if (auto cxxOper = dyn_cast<CXXOperatorCallExpr>(expr))
399 if (isAssignmentOp(cxxOper->getOperator()))
401 m_handled.insert(expr);
402 MarkIfAssignment(cxxOper->getArg(1)); // in case it is chained
408 void BuriedAssign::MarkAll(Stmt const* stmt)
410 m_handled.insert(stmt);
411 for (auto it = stmt->child_begin(); it != stmt->child_end(); ++it)
412 MarkAll(*it);
416 * Restrict this to cases where the buried assignment is part of the first
417 * condition inside the if condition. Other cases tend to be too hard
418 * too extract (notably in sw/)
420 bool BuriedAssign::VisitIfStmt(IfStmt const* ifStmt)
422 if (ignoreLocation(ifStmt))
423 return true;
424 MarkIfAssignment(ifStmt->getThen());
425 MarkIfAssignment(ifStmt->getElse());
427 auto expr = ifStmt->getCond();
428 expr = IgnoreImplicitAndConversionOperator(expr);
429 expr = expr->IgnoreParens();
430 expr = IgnoreImplicitAndConversionOperator(expr);
431 MarkAll(expr);
433 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
435 if (isAssignmentOp(binaryOp->getOpcode()))
437 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
438 expr->getBeginLoc())
439 << expr->getSourceRange();
441 else if (binaryOp->isComparisonOp())
443 if (auto binaryOp2
444 = dyn_cast<BinaryOperator>(binaryOp->getLHS()->IgnoreParenImpCasts()))
446 if (!binaryOp->getRHS()->isValueDependent()
447 && binaryOp->getRHS()->isCXX11ConstantExpr(compiler.getASTContext())
448 && isAssignmentOp(binaryOp2->getOpcode()))
449 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
450 expr->getBeginLoc())
451 << expr->getSourceRange();
453 if (auto binaryOp2
454 = dyn_cast<BinaryOperator>(binaryOp->getRHS()->IgnoreParenImpCasts()))
456 if (!binaryOp->getLHS()->isValueDependent()
457 && binaryOp->getLHS()->isCXX11ConstantExpr(compiler.getASTContext())
458 && isAssignmentOp(binaryOp2->getOpcode()))
459 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
460 expr->getBeginLoc())
461 << expr->getSourceRange();
464 else if (binaryOp->isLogicalOp())
466 if (auto binaryOp2
467 = dyn_cast<BinaryOperator>(binaryOp->getLHS()->IgnoreParenImpCasts()))
469 if (isAssignmentOp(binaryOp2->getOpcode()))
470 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
471 expr->getBeginLoc())
472 << expr->getSourceRange();
476 else if (auto operCall = dyn_cast<CXXOperatorCallExpr>(expr))
478 // Ignore chained assignment.
479 // TODO limit this to only ordinary assignment
480 if (isAssignmentOp(operCall->getOperator()))
482 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
483 expr->getBeginLoc())
484 << expr->getSourceRange();
488 return true;
491 bool BuriedAssign::VisitCaseStmt(CaseStmt const* stmt)
493 if (ignoreLocation(stmt))
494 return true;
495 MarkIfAssignment(stmt->getSubStmt());
496 return true;
499 bool BuriedAssign::VisitDefaultStmt(DefaultStmt const* stmt)
501 if (ignoreLocation(stmt))
502 return true;
503 MarkIfAssignment(stmt->getSubStmt());
504 return true;
507 bool BuriedAssign::VisitWhileStmt(WhileStmt const* stmt)
509 if (ignoreLocation(stmt))
510 return true;
511 MarkConditionForControlLoops(stmt->getCond());
512 MarkIfAssignment(stmt->getBody());
513 return true;
516 bool BuriedAssign::VisitDoStmt(DoStmt const* stmt)
518 if (ignoreLocation(stmt))
519 return true;
520 MarkConditionForControlLoops(stmt->getCond());
521 MarkIfAssignment(stmt->getBody());
522 return true;
525 /** stuff like
526 * while ((x = foo())
527 * and
528 * while ((x = foo() < 0)
529 * is considered idiomatic.
531 void BuriedAssign::MarkConditionForControlLoops(Expr const* expr)
533 if (!expr)
534 return;
535 expr = expr->IgnoreImplicit();
537 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
539 // ignore comma-chained statements at this level
540 if (binaryOp->getOpcode() == BO_Comma)
542 MarkConditionForControlLoops(binaryOp->getLHS());
543 MarkConditionForControlLoops(binaryOp->getRHS());
544 return;
548 // unwrap conversion to bool
549 if (auto memberCall = dyn_cast<CXXMemberCallExpr>(expr))
551 if (memberCall->getMethodDecl() && isa<CXXConversionDecl>(memberCall->getMethodDecl()))
553 // TODO check that the conversion is converting to bool
554 expr = memberCall->getImplicitObjectArgument()->IgnoreImplicit();
558 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
560 // handle: ((xxx = foo()) != error)
561 if (binaryOp->isComparisonOp())
563 MarkIfAssignment(binaryOp->getLHS()->IgnoreImplicit()->IgnoreParens());
564 MarkIfAssignment(binaryOp->getRHS()->IgnoreImplicit()->IgnoreParens());
567 else if (auto cxxOper = dyn_cast<CXXOperatorCallExpr>(expr))
569 // handle: ((xxx = foo()) != error)
570 if (cxxOper->isComparisonOp())
572 MarkIfAssignment(cxxOper->getArg(0)->IgnoreImplicit()->IgnoreParens());
573 MarkIfAssignment(cxxOper->getArg(1)->IgnoreImplicit()->IgnoreParens());
575 // handle: (!(xxx = foo()))
576 else if (cxxOper->getOperator() == OO_Exclaim)
577 MarkIfAssignment(cxxOper->getArg(0)->IgnoreImplicit()->IgnoreParens());
579 else if (auto parenExpr = dyn_cast<ParenExpr>(expr))
581 // handle: ((xxx = foo()))
582 MarkIfAssignment(parenExpr->getSubExpr()->IgnoreImplicit());
584 else if (auto unaryOp = dyn_cast<UnaryOperator>(expr))
586 // handle: (!(xxx = foo()))
587 MarkIfAssignment(unaryOp->getSubExpr()->IgnoreImplicit()->IgnoreParens());
589 else
590 MarkIfAssignment(expr);
593 bool BuriedAssign::VisitForStmt(ForStmt const* stmt)
595 if (ignoreLocation(stmt))
596 return true;
597 MarkIfAssignment(stmt->getInit());
598 MarkConditionForControlLoops(stmt->getCond());
599 MarkIfAssignment(stmt->getInc());
600 MarkIfAssignment(stmt->getBody());
601 return true;
604 bool BuriedAssign::VisitCXXForRangeStmt(CXXForRangeStmt const* stmt)
606 if (ignoreLocation(stmt))
607 return true;
608 MarkIfAssignment(stmt->getBody());
609 return true;
612 bool BuriedAssign::VisitLabelStmt(LabelStmt const* stmt)
614 if (ignoreLocation(stmt))
615 return true;
616 MarkIfAssignment(stmt->getSubStmt());
617 return true;
620 bool BuriedAssign::VisitVarDecl(VarDecl const* stmt)
622 if (ignoreLocation(stmt))
623 return true;
624 if (stmt->getInit())
626 auto expr = IgnoreImplicitAndConversionOperator(stmt->getInit());
627 MarkIfAssignment(expr);
628 if (auto cxxConstruct = dyn_cast<CXXConstructExpr>(expr))
630 if (cxxConstruct->getNumArgs() == 1)
631 MarkIfAssignment(cxxConstruct->getArg(0));
634 return true;
637 bool BuriedAssign::VisitCXXFoldExpr(CXXFoldExpr const* stmt)
639 if (ignoreLocation(stmt))
640 return true;
641 MarkConditionForControlLoops(stmt->getLHS());
642 MarkConditionForControlLoops(stmt->getRHS());
643 return true;
646 // off by default because it uses getParentStmt so it's more expensive to run
647 loplugin::Plugin::Registration<BuriedAssign> X("buriedassign", false);
650 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */