10 #include "../utils/LexerUtils.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
18 namespace readability {
21 AST_MATCHER(DeclStmt, isSingleDecl) {
return Node.isSingleDecl(); }
23 return llvm::all_of(Node.decls(), [](
Decl *
D) { return isa<VarDecl>(D); });
27 void IsolateDeclarationCheck::registerMatchers(MatchFinder *Finder) {
28 Finder->addMatcher(declStmt(onlyDeclaresVariables(), unless(isSingleDecl()),
29 hasParent(compoundStmt()))
36 const SourceManager &SM,
38 assert(Indirections >= 0 &&
"Indirections must be non-negative");
39 if (Indirections == 0)
44 while (Indirections-- != 0) {
46 if (Start.isInvalid() || Start.isMacroID())
47 return SourceLocation();
53 return R.getBegin().isMacroID() || R.getEnd().isMacroID();
61 if (T->isFunctionPointerType()) {
62 const auto *Pointee = T->getPointeeType()->castAs<FunctionType>();
64 Pointee->getReturnType().IgnoreParens().getTypePtr(), ++Indirections);
70 if (
const auto *AT = dyn_cast<ArrayType>(T))
74 if (isa<PointerType>(T) || isa<ReferenceType>(T))
82 if (isa<ArrayType>(T))
85 if ((isa<PointerType>(T) || isa<ReferenceType>(T)) &&
86 isa<PointerType>(T->getPointeeType()))
89 return isa<MemberPointerType>(T);
108 static Optional<std::vector<SourceRange>>
111 std::size_t DeclCount = std::distance(DS->decl_begin(), DS->decl_end());
122 std::vector<SourceRange> Slices;
123 Slices.reserve(DeclCount + 1);
127 const auto *FirstDecl = dyn_cast<VarDecl>(*DS->decl_begin());
129 if (FirstDecl ==
nullptr)
142 FirstDecl->getLocation(),
150 if (FirstDecl->getType()->isFunctionPointerType())
158 if (Start.isInvalid() || Start.isMacroID())
162 if (T.is(tok::l_paren)) {
169 SourceRange DeclRange(DS->getBeginLoc(), Start);
170 if (DeclRange.isInvalid() ||
isMacroID(DeclRange))
175 Slices.emplace_back(DeclRange);
178 SourceLocation DeclBegin = Start;
179 for (
const auto &
Decl : DS->decls()) {
180 const auto *CurrentDecl = cast<VarDecl>(
Decl);
187 SourceLocation DeclEnd =
188 CurrentDecl->hasInit()
193 SourceRange VarNameRange(DeclBegin, DeclEnd);
194 if (VarNameRange.isInvalid() ||
isMacroID(VarNameRange))
197 Slices.emplace_back(VarNameRange);
198 DeclBegin = DeclEnd.getLocWithOffset(1);
203 static Optional<std::vector<StringRef>>
206 std::vector<StringRef> Snippets;
207 Snippets.reserve(Ranges.size());
209 for (
const auto &
Range : Ranges) {
210 CharSourceRange CharRange = Lexer::getAsCharRange(
211 CharSourceRange::getCharRange(
Range.getBegin(),
Range.getEnd()), SM,
214 if (CharRange.isInvalid())
217 bool InvalidText =
false;
224 Snippets.emplace_back(
Snippet);
231 static std::vector<std::string>
234 assert(Snippets.size() > 2 &&
"Not enough snippets to create isolated decls");
235 std::vector<std::string> Decls(Snippets.size() - 1);
237 for (std::size_t I = 1; I < Snippets.size(); ++I)
238 Decls[I - 1] = Twine(Snippets[0])
239 .concat(Snippets[0].endswith(
" ") ?
"" :
" ")
240 .concat(Snippets[I].ltrim())
248 const auto *WholeDecl = Result.Nodes.getNodeAs<DeclStmt>(
"decl_stmt");
251 diag(WholeDecl->getBeginLoc(),
252 "multiple declarations in a single statement reduces readability");
254 Optional<std::vector<SourceRange>> PotentialRanges =
255 declRanges(WholeDecl, *Result.SourceManager, getLangOpts());
256 if (!PotentialRanges)
260 *PotentialRanges, *Result.SourceManager, getLangOpts());
262 if (!PotentialSnippets)
268 (Twine(
"\n") + Lexer::getIndentationForLine(WholeDecl->getBeginLoc(),
269 *Result.SourceManager))
272 Diag << FixItHint::CreateReplacement(WholeDecl->getSourceRange(),