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/.
13 #include <unordered_map>
14 #include <unordered_set>
18 #include "clang/AST/CXXInheritance.h"
19 #include "clang/AST/StmtVisitor.h"
22 Look for nested if statements with relatively small conditions, where they can be collapsed into
27 class CollapseIf
: public loplugin::FilteringPlugin
<CollapseIf
>
30 explicit CollapseIf(loplugin::InstantiationData
const& data
)
31 : FilteringPlugin(data
)
35 virtual void run() override
{ TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
37 bool VisitIfStmt(IfStmt
const*);
40 int getNoCharsInSourceCodeOfExpr(IfStmt
const*);
43 bool CollapseIf::VisitIfStmt(IfStmt
const* ifStmt
)
45 if (ignoreLocation(ifStmt
))
47 if (ifStmt
->getElse())
50 IfStmt
const* secondIfStmt
= nullptr;
51 if (auto compoundStmt
= dyn_cast
<CompoundStmt
>(ifStmt
->getThen()))
53 if (compoundStmt
->size() != 1)
55 secondIfStmt
= dyn_cast
<IfStmt
>(*compoundStmt
->body_begin());
58 if (secondIfStmt
->getElse())
63 secondIfStmt
= dyn_cast
<IfStmt
>(ifStmt
->getThen());
68 int noChars1
= getNoCharsInSourceCodeOfExpr(ifStmt
);
69 int noChars2
= getNoCharsInSourceCodeOfExpr(secondIfStmt
);
70 if (noChars1
+ noChars2
> 40)
73 // Sometimes there is a comment between the first and second if, so
74 // merging them would make the comment more awkward to write.
75 if (containsComment(ifStmt
->getSourceRange()))
78 report(DiagnosticsEngine::Warning
, "nested if should be collapsed into one statement %0 %1",
79 ifStmt
->getBeginLoc())
80 << noChars1
<< noChars2
<< ifStmt
->getSourceRange();
84 int CollapseIf::getNoCharsInSourceCodeOfExpr(IfStmt
const* ifStmt
)
86 // Measure the space between the "if" the beginning of the "then" block because
87 // measuring the size of the condition expression is unreliable, because clang
88 // does not report the location of the last token accurately.
89 SourceManager
& SM
= compiler
.getSourceManager();
90 SourceLocation startLoc
= ifStmt
->getBeginLoc();
91 SourceLocation endLoc
= ifStmt
->getThen()->getBeginLoc();
92 char const* p1
= SM
.getCharacterData(startLoc
);
93 char const* p2
= SM
.getCharacterData(endLoc
);
96 for (auto p
= p1
; p
< p2
; ++p
)
103 /** Off by default because some places are a judgement call if it should be collapsed or not. */
104 loplugin::Plugin::Registration
<CollapseIf
> X("collapseif", false);
107 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */