lok: getSlideShowInfo: interactions: check that properties are available
[LibreOffice.git] / compilerplugins / clang / buriedassign.cxx
blob2974f84be998bbedd00e74c128ce343187ec21fb
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 "/sfx2/source/dialog/templdlg.cxx")
91 return;
92 if (fn == SRCDIR "/sfx2/source/view/viewfrm.cxx")
93 return;
94 if (fn == SRCDIR "/connectivity/source/commontools/dbtools.cxx")
95 return;
96 if (fn == SRCDIR "/xmloff/source/style/xmlnumfi.cxx")
97 return;
98 if (fn == SRCDIR "/xmloff/source/style/xmlnumfe .cxx")
99 return;
100 if (fn == SRCDIR "/editeng/source/items/textitem.cxx")
101 return;
102 if (fn == SRCDIR "/editeng/source/rtf/rtfitem.cxx")
103 return;
104 if (fn == SRCDIR "/editeng/source/rtf/svxrtf.cxx")
105 return;
106 if (fn == SRCDIR "/editeng/source/misc/svxacorr.cxx")
107 return;
108 if (fn == SRCDIR "/svx/source/items/numfmtsh.cxx")
109 return;
110 if (fn == SRCDIR "/svx/source/dialog/hdft.cxx")
111 return;
112 if (fn == SRCDIR "/cui/source/dialogs/insdlg.cxx")
113 return;
114 if (fn == SRCDIR "/cui/source/tabpages/paragrph.cxx")
115 return;
116 if (fn == SRCDIR "/cui/source/tabpages/page.cxx")
117 return;
118 if (fn == SRCDIR "/cui/source/tabpages/border.cxx")
119 return;
120 if (fn == SRCDIR "/cui/source/tabpages/chardlg.cxx")
121 return;
122 if (fn == SRCDIR "/cui/source/tabpages/numpages.cxx")
123 return;
124 if (fn == SRCDIR "/cui/source/dialogs/SpellDialog.cxx")
125 return;
126 if (fn == SRCDIR "/oox/source/drawingml/diagram/diagramlayoutatoms.cxx")
127 return;
128 if (fn == SRCDIR "/dbaccess/source/core/dataaccess/intercept.cxx")
129 return;
130 if (fn == SRCDIR "/sw/writerfilter/dmapper/DomainMapper.cxx")
131 return;
132 if (fn == SRCDIR "/sw/writerfilter/dmapper/DomainMapper_Impl.cxx")
133 return;
134 if (fn == SRCDIR "/lotuswordpro/source/filter/lwptablelayout.cxx")
135 return;
136 if (fn == SRCDIR "/i18npool/source/characterclassification/cclass_unicode_parser.cxx")
137 return;
138 if (fn == SRCDIR "/sd/source/filter/eppt/pptx-animations.cxx")
139 return;
140 if (fn == SRCDIR "/sc/source/core/tool/address.cxx")
141 return;
142 if (fn == SRCDIR "/sc/source/core/tool/interpr1.cxx")
143 return;
144 if (fn == SRCDIR "/sc/source/core/tool/interpr4.cxx")
145 return;
146 if (fn == SRCDIR "/sc/source/core/tool/interpr5.cxx")
147 return;
148 if (fn == SRCDIR "/sc/source/core/tool/compiler.cxx")
149 return;
150 if (fn == SRCDIR "/sc/source/core/data/table4.cxx")
151 return;
152 if (fn == SRCDIR "/sc/source/ui/drawfunc/fudraw.cxx")
153 return;
154 if (fn == SRCDIR "/sc/source/filter/xml/xmlcelli.cxx")
155 return;
156 if (fn == SRCDIR "/sc/source/ui/miscdlgs/crnrdlg.cxx")
157 return;
158 if (fn == SRCDIR "/sc/source/ui/app/inputwin.cxx")
159 return;
160 if (fn == SRCDIR "/sc/source/ui/view/viewfun2.cxx")
161 return;
162 if (fn == SRCDIR "/sc/source/ui/unoobj/docuno.cxx")
163 return;
164 if (fn == SRCDIR "/sc/source/ui/view/gridwin.cxx")
165 return;
166 if (fn == SRCDIR "/sw/source/core/crsr/callnk.cxx")
167 return;
168 if (fn == SRCDIR "/sw/source/core/crsr/findtxt.cxx")
169 return;
170 if (fn == SRCDIR "/sw/source/core/crsr/crsrsh.cxx")
171 return;
172 if (fn == SRCDIR "/sw/source/core/crsr/crstrvl.cxx")
173 return;
174 if (fn == SRCDIR "/sw/source/core/doc/doccomp.cxx")
175 return;
176 if (fn == SRCDIR "/sw/source/core/doc/docedt.cxx")
177 return;
178 if (fn == SRCDIR "/sw/source/core/doc/docfly.cxx")
179 return;
180 if (fn == SRCDIR "/sw/source/core/doc/DocumentRedlineManager.cxx")
181 return;
182 if (fn == SRCDIR "/sw/source/core/doc/notxtfrm.cxx")
183 return;
184 if (fn == SRCDIR "/sw/source/core/docnode/node.cxx")
185 return;
186 if (fn == SRCDIR "/sw/source/core/layout/ftnfrm.cxx")
187 return;
188 if (fn == SRCDIR "/sw/source/core/table/swtable.cxx")
189 return;
190 if (fn == SRCDIR "/sw/source/core/unocore/unoframe.cxx")
191 return;
192 if (fn == SRCDIR "/sw/source/filter/xml/xmlimp.cxx")
193 return;
194 if (fn == SRCDIR "/sw/source/uibase/docvw/edtwin.cxx")
195 return;
196 if (fn == SRCDIR "/sw/source/uibase/shells/langhelper.cxx")
197 return;
198 if (fn == SRCDIR "/sw/source/uibase/shells/tabsh.cxx")
199 return;
200 if (fn == SRCDIR "/sw/source/uibase/shells/textsh1.cxx")
201 return;
202 if (fn == SRCDIR "/sw/source/uibase/uiview/view2.cxx")
203 return;
204 if (fn == SRCDIR "/starmath/source/mathtype.cxx")
205 return;
206 if (fn == SRCDIR "/starmath/source/mathmlexport.cxx")
207 return;
208 if (fn == SRCDIR "/starmath/source/view.cxx")
209 return;
210 if (fn == SRCDIR "/xmlhelp/source/treeview/tvread.cxx")
211 return;
212 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
215 bool VisitBinaryOperator(BinaryOperator const*);
216 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr const*);
217 bool VisitCompoundStmt(CompoundStmt const*);
218 bool VisitIfStmt(IfStmt const*);
219 bool VisitLabelStmt(LabelStmt const*);
220 bool VisitForStmt(ForStmt const*);
221 bool VisitCXXForRangeStmt(CXXForRangeStmt const*);
222 bool VisitWhileStmt(WhileStmt const*);
223 bool VisitDoStmt(DoStmt const*);
224 bool VisitCaseStmt(CaseStmt const*);
225 bool VisitDefaultStmt(DefaultStmt const*);
226 bool VisitVarDecl(VarDecl const*);
227 bool VisitCXXFoldExpr(CXXFoldExpr const*);
229 private:
230 void MarkIfAssignment(Stmt const*);
231 void MarkAll(Stmt const*);
232 void MarkConditionForControlLoops(Expr const*);
234 std::unordered_set<const Stmt*> m_handled;
237 static bool isAssignmentOp(clang::BinaryOperatorKind op)
239 // We ignore BO_ShrAssign i.e. >>= because we use that everywhere for
240 // extracting data from css::uno::Any
241 return op == BO_Assign || op == BO_MulAssign || op == BO_DivAssign || op == BO_RemAssign
242 || op == BO_AddAssign || op == BO_SubAssign || op == BO_ShlAssign || op == BO_AndAssign
243 || op == BO_XorAssign || op == BO_OrAssign;
246 static bool isAssignmentOp(clang::OverloadedOperatorKind Opc)
248 // Same logic as CXXOperatorCallExpr::isAssignmentOp(), which our supported clang
249 // doesn't have yet.
250 // Except that we ignore OO_GreaterGreaterEqual i.e. >>= because we use that everywhere for
251 // extracting data from css::uno::Any
252 return Opc == OO_Equal || Opc == OO_StarEqual || Opc == OO_SlashEqual || Opc == OO_PercentEqual
253 || Opc == OO_PlusEqual || Opc == OO_MinusEqual || Opc == OO_LessLessEqual
254 || Opc == OO_AmpEqual || Opc == OO_CaretEqual || Opc == OO_PipeEqual;
257 static const Expr* IgnoreImplicitAndConversionOperator(const Expr* expr)
259 expr = expr->IgnoreImplicit();
260 if (auto memberCall = dyn_cast<CXXMemberCallExpr>(expr))
262 if (auto conversionDecl = dyn_cast_or_null<CXXConversionDecl>(memberCall->getMethodDecl()))
264 if (!conversionDecl->isExplicit())
265 expr = memberCall->getImplicitObjectArgument()->IgnoreImplicit();
268 return expr;
271 bool BuriedAssign::VisitBinaryOperator(BinaryOperator const* binaryOp)
273 if (ignoreLocation(binaryOp))
274 return true;
275 if (binaryOp->getBeginLoc().isMacroID())
276 return true;
277 if (!isAssignmentOp(binaryOp->getOpcode()))
278 return true;
279 auto expr = IgnoreImplicitAndConversionOperator(binaryOp->getRHS());
280 if (auto rhs = dyn_cast<BinaryOperator>(expr))
282 // Ignore chained assignment.
283 // TODO limit this to only ordinary assignment
284 if (isAssignmentOp(rhs->getOpcode()))
285 m_handled.insert(rhs);
287 else if (auto rhs = dyn_cast<CXXOperatorCallExpr>(expr))
289 // Ignore chained assignment.
290 // TODO limit this to only ordinary assignment
291 if (isAssignmentOp(rhs->getOperator()))
292 m_handled.insert(rhs);
294 else if (auto cxxConstruct = dyn_cast<CXXConstructExpr>(expr))
296 if (cxxConstruct->getNumArgs() == 1)
297 MarkIfAssignment(cxxConstruct->getArg(0));
299 if (!m_handled.insert(binaryOp).second)
300 return true;
302 // assignment in constructor
303 StringRef aFileName = getFilenameOfLocation(
304 compiler.getSourceManager().getSpellingLoc(binaryOp->getBeginLoc()));
305 if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/include/comphelper/flagguard.hxx"))
306 return true;
308 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
309 binaryOp->getBeginLoc())
310 << binaryOp->getSourceRange();
311 //getParentStmt(getParentStmt(getParentStmt(getParentStmt(getParentStmt(getParentStmt(binaryOp))))))->dump();
312 return true;
315 bool BuriedAssign::VisitCXXOperatorCallExpr(CXXOperatorCallExpr const* cxxOper)
317 if (ignoreLocation(cxxOper))
318 return true;
319 if (cxxOper->getBeginLoc().isMacroID())
320 return true;
321 if (!isAssignmentOp(cxxOper->getOperator()))
322 return true;
323 auto expr = IgnoreImplicitAndConversionOperator(cxxOper->getArg(1));
324 if (auto rhs = dyn_cast<BinaryOperator>(expr))
326 // Ignore chained assignment.
327 // TODO limit this to only ordinary assignment
328 if (isAssignmentOp(rhs->getOpcode()))
329 m_handled.insert(rhs);
331 else if (auto rhs = dyn_cast<CXXOperatorCallExpr>(expr))
333 // Ignore chained assignment.
334 // TODO limit this to only ordinary assignment
335 if (isAssignmentOp(rhs->getOperator()))
336 m_handled.insert(rhs);
338 else if (auto cxxConstruct = dyn_cast<CXXConstructExpr>(expr))
340 if (cxxConstruct->getNumArgs() == 1)
341 MarkIfAssignment(cxxConstruct->getArg(0));
343 if (!m_handled.insert(cxxOper).second)
344 return true;
345 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
346 cxxOper->getBeginLoc())
347 << cxxOper->getSourceRange();
348 //getParentStmt(getParentStmt(getParentStmt(getParentStmt(getParentStmt(cxxOper)))))->dump();
349 return true;
352 bool BuriedAssign::VisitCompoundStmt(CompoundStmt const* compoundStmt)
354 if (ignoreLocation(compoundStmt))
355 return true;
356 for (auto i = compoundStmt->child_begin(); i != compoundStmt->child_end(); ++i)
358 if (auto expr = dyn_cast<Expr>(*i))
360 expr = expr->IgnoreImplicit();
361 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
363 // ignore comma-chained statements at this level
364 if (binaryOp->getOpcode() == BO_Comma)
366 MarkIfAssignment(binaryOp->getLHS());
367 MarkIfAssignment(binaryOp->getRHS());
368 continue;
371 MarkIfAssignment(expr);
374 return true;
377 void BuriedAssign::MarkIfAssignment(Stmt const* stmt)
379 if (auto expr = dyn_cast_or_null<Expr>(stmt))
381 expr = expr->IgnoreImplicit();
382 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
384 if (isAssignmentOp(binaryOp->getOpcode()))
386 m_handled.insert(expr);
387 MarkIfAssignment(binaryOp->getRHS()); // in case it is chained
389 else if (binaryOp->getOpcode() == BO_Comma)
391 MarkIfAssignment(binaryOp->getLHS());
392 MarkIfAssignment(binaryOp->getRHS());
395 else if (auto cxxOper = dyn_cast<CXXOperatorCallExpr>(expr))
397 if (isAssignmentOp(cxxOper->getOperator()))
399 m_handled.insert(expr);
400 MarkIfAssignment(cxxOper->getArg(1)); // in case it is chained
406 void BuriedAssign::MarkAll(Stmt const* stmt)
408 m_handled.insert(stmt);
409 for (auto it = stmt->child_begin(); it != stmt->child_end(); ++it)
410 MarkAll(*it);
414 * Restrict this to cases where the buried assignment is part of the first
415 * condition inside the if condition. Other cases tend to be too hard
416 * too extract (notably in sw/)
418 bool BuriedAssign::VisitIfStmt(IfStmt const* ifStmt)
420 if (ignoreLocation(ifStmt))
421 return true;
422 MarkIfAssignment(ifStmt->getThen());
423 MarkIfAssignment(ifStmt->getElse());
425 auto expr = ifStmt->getCond();
426 expr = IgnoreImplicitAndConversionOperator(expr);
427 expr = expr->IgnoreParens();
428 expr = IgnoreImplicitAndConversionOperator(expr);
429 MarkAll(expr);
431 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
433 if (isAssignmentOp(binaryOp->getOpcode()))
435 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
436 expr->getBeginLoc())
437 << expr->getSourceRange();
439 else if (binaryOp->isComparisonOp())
441 if (auto binaryOp2
442 = dyn_cast<BinaryOperator>(binaryOp->getLHS()->IgnoreParenImpCasts()))
444 if (!binaryOp->getRHS()->isValueDependent()
445 && binaryOp->getRHS()->isCXX11ConstantExpr(compiler.getASTContext())
446 && isAssignmentOp(binaryOp2->getOpcode()))
447 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
448 expr->getBeginLoc())
449 << expr->getSourceRange();
451 if (auto binaryOp2
452 = dyn_cast<BinaryOperator>(binaryOp->getRHS()->IgnoreParenImpCasts()))
454 if (!binaryOp->getLHS()->isValueDependent()
455 && binaryOp->getLHS()->isCXX11ConstantExpr(compiler.getASTContext())
456 && isAssignmentOp(binaryOp2->getOpcode()))
457 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
458 expr->getBeginLoc())
459 << expr->getSourceRange();
462 else if (binaryOp->isLogicalOp())
464 if (auto binaryOp2
465 = dyn_cast<BinaryOperator>(binaryOp->getLHS()->IgnoreParenImpCasts()))
467 if (isAssignmentOp(binaryOp2->getOpcode()))
468 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
469 expr->getBeginLoc())
470 << expr->getSourceRange();
474 else if (auto operCall = dyn_cast<CXXOperatorCallExpr>(expr))
476 // Ignore chained assignment.
477 // TODO limit this to only ordinary assignment
478 if (isAssignmentOp(operCall->getOperator()))
480 report(DiagnosticsEngine::Warning, "buried assignment, rather put on own line",
481 expr->getBeginLoc())
482 << expr->getSourceRange();
486 return true;
489 bool BuriedAssign::VisitCaseStmt(CaseStmt const* stmt)
491 if (ignoreLocation(stmt))
492 return true;
493 MarkIfAssignment(stmt->getSubStmt());
494 return true;
497 bool BuriedAssign::VisitDefaultStmt(DefaultStmt const* stmt)
499 if (ignoreLocation(stmt))
500 return true;
501 MarkIfAssignment(stmt->getSubStmt());
502 return true;
505 bool BuriedAssign::VisitWhileStmt(WhileStmt const* stmt)
507 if (ignoreLocation(stmt))
508 return true;
509 MarkConditionForControlLoops(stmt->getCond());
510 MarkIfAssignment(stmt->getBody());
511 return true;
514 bool BuriedAssign::VisitDoStmt(DoStmt const* stmt)
516 if (ignoreLocation(stmt))
517 return true;
518 MarkConditionForControlLoops(stmt->getCond());
519 MarkIfAssignment(stmt->getBody());
520 return true;
523 /** stuff like
524 * while ((x = foo())
525 * and
526 * while ((x = foo() < 0)
527 * is considered idiomatic.
529 void BuriedAssign::MarkConditionForControlLoops(Expr const* expr)
531 if (!expr)
532 return;
533 expr = expr->IgnoreImplicit();
535 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
537 // ignore comma-chained statements at this level
538 if (binaryOp->getOpcode() == BO_Comma)
540 MarkConditionForControlLoops(binaryOp->getLHS());
541 MarkConditionForControlLoops(binaryOp->getRHS());
542 return;
546 // unwrap conversion to bool
547 if (auto memberCall = dyn_cast<CXXMemberCallExpr>(expr))
549 if (memberCall->getMethodDecl() && isa<CXXConversionDecl>(memberCall->getMethodDecl()))
551 // TODO check that the conversion is converting to bool
552 expr = memberCall->getImplicitObjectArgument()->IgnoreImplicit();
556 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
558 // handle: ((xxx = foo()) != error)
559 if (binaryOp->isComparisonOp())
561 MarkIfAssignment(binaryOp->getLHS()->IgnoreImplicit()->IgnoreParens());
562 MarkIfAssignment(binaryOp->getRHS()->IgnoreImplicit()->IgnoreParens());
565 else if (auto cxxOper = dyn_cast<CXXOperatorCallExpr>(expr))
567 // handle: ((xxx = foo()) != error)
568 if (cxxOper->isComparisonOp())
570 MarkIfAssignment(cxxOper->getArg(0)->IgnoreImplicit()->IgnoreParens());
571 MarkIfAssignment(cxxOper->getArg(1)->IgnoreImplicit()->IgnoreParens());
573 // handle: (!(xxx = foo()))
574 else if (cxxOper->getOperator() == OO_Exclaim)
575 MarkIfAssignment(cxxOper->getArg(0)->IgnoreImplicit()->IgnoreParens());
577 else if (auto parenExpr = dyn_cast<ParenExpr>(expr))
579 // handle: ((xxx = foo()))
580 MarkIfAssignment(parenExpr->getSubExpr()->IgnoreImplicit());
582 else if (auto unaryOp = dyn_cast<UnaryOperator>(expr))
584 // handle: (!(xxx = foo()))
585 MarkIfAssignment(unaryOp->getSubExpr()->IgnoreImplicit()->IgnoreParens());
587 else
588 MarkIfAssignment(expr);
591 bool BuriedAssign::VisitForStmt(ForStmt const* stmt)
593 if (ignoreLocation(stmt))
594 return true;
595 MarkIfAssignment(stmt->getInit());
596 MarkConditionForControlLoops(stmt->getCond());
597 MarkIfAssignment(stmt->getInc());
598 MarkIfAssignment(stmt->getBody());
599 return true;
602 bool BuriedAssign::VisitCXXForRangeStmt(CXXForRangeStmt const* stmt)
604 if (ignoreLocation(stmt))
605 return true;
606 MarkIfAssignment(stmt->getBody());
607 return true;
610 bool BuriedAssign::VisitLabelStmt(LabelStmt const* stmt)
612 if (ignoreLocation(stmt))
613 return true;
614 MarkIfAssignment(stmt->getSubStmt());
615 return true;
618 bool BuriedAssign::VisitVarDecl(VarDecl const* stmt)
620 if (ignoreLocation(stmt))
621 return true;
622 if (stmt->getInit())
624 auto expr = IgnoreImplicitAndConversionOperator(stmt->getInit());
625 MarkIfAssignment(expr);
626 if (auto cxxConstruct = dyn_cast<CXXConstructExpr>(expr))
628 if (cxxConstruct->getNumArgs() == 1)
629 MarkIfAssignment(cxxConstruct->getArg(0));
632 return true;
635 bool BuriedAssign::VisitCXXFoldExpr(CXXFoldExpr const* stmt)
637 if (ignoreLocation(stmt))
638 return true;
639 MarkConditionForControlLoops(stmt->getLHS());
640 MarkConditionForControlLoops(stmt->getRHS());
641 return true;
644 // off by default because it uses getParentStmt so it's more expensive to run
645 loplugin::Plugin::Registration<BuriedAssign> X("buriedassign", false);
648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */