diff options
author | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 13:58:24 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 14:11:53 +0300 |
commit | 11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch) | |
tree | fabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/tools/extra/clang-tidy/readability/MisleadingIndentationCheck.cpp | |
parent | 9685917341315774aad5733b1793b1e533a88bbb (diff) | |
download | ydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz |
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/tools/extra/clang-tidy/readability/MisleadingIndentationCheck.cpp')
-rw-r--r-- | contrib/libs/clang16/tools/extra/clang-tidy/readability/MisleadingIndentationCheck.cpp | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/readability/MisleadingIndentationCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/readability/MisleadingIndentationCheck.cpp new file mode 100644 index 0000000000..4c10b6f6ee --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/readability/MisleadingIndentationCheck.cpp @@ -0,0 +1,122 @@ +//===--- MisleadingIndentationCheck.cpp - clang-tidy-----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MisleadingIndentationCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::readability { + +static const IfStmt *getPrecedingIf(const SourceManager &SM, + ASTContext *Context, const IfStmt *If) { + auto Parents = Context->getParents(*If); + if (Parents.size() != 1) + return nullptr; + if (const auto *PrecedingIf = Parents[0].get<IfStmt>()) { + SourceLocation PreviousElseLoc = PrecedingIf->getElseLoc(); + if (SM.getExpansionLineNumber(PreviousElseLoc) == + SM.getExpansionLineNumber(If->getIfLoc())) + return PrecedingIf; + } + return nullptr; +} + +void MisleadingIndentationCheck::danglingElseCheck(const SourceManager &SM, + ASTContext *Context, + const IfStmt *If) { + SourceLocation IfLoc = If->getIfLoc(); + SourceLocation ElseLoc = If->getElseLoc(); + + if (IfLoc.isMacroID() || ElseLoc.isMacroID()) + return; + + if (SM.getExpansionLineNumber(If->getThen()->getEndLoc()) == + SM.getExpansionLineNumber(ElseLoc)) + return; + + // Find location of first 'if' in a 'if else if' chain. + for (const auto *PrecedingIf = getPrecedingIf(SM, Context, If); PrecedingIf; + PrecedingIf = getPrecedingIf(SM, Context, PrecedingIf)) + IfLoc = PrecedingIf->getIfLoc(); + + if (SM.getExpansionColumnNumber(IfLoc) != + SM.getExpansionColumnNumber(ElseLoc)) + diag(ElseLoc, "different indentation for 'if' and corresponding 'else'"); +} + +void MisleadingIndentationCheck::missingBracesCheck(const SourceManager &SM, + const CompoundStmt *CStmt) { + const static StringRef StmtNames[] = {"if", "for", "while"}; + for (unsigned int I = 0; I < CStmt->size() - 1; I++) { + const Stmt *CurrentStmt = CStmt->body_begin()[I]; + const Stmt *Inner = nullptr; + int StmtKind = 0; + + if (const auto *CurrentIf = dyn_cast<IfStmt>(CurrentStmt)) { + StmtKind = 0; + Inner = + CurrentIf->getElse() ? CurrentIf->getElse() : CurrentIf->getThen(); + } else if (const auto *CurrentFor = dyn_cast<ForStmt>(CurrentStmt)) { + StmtKind = 1; + Inner = CurrentFor->getBody(); + } else if (const auto *CurrentWhile = dyn_cast<WhileStmt>(CurrentStmt)) { + StmtKind = 2; + Inner = CurrentWhile->getBody(); + } else { + continue; + } + + if (isa<CompoundStmt>(Inner)) + continue; + + SourceLocation InnerLoc = Inner->getBeginLoc(); + SourceLocation OuterLoc = CurrentStmt->getBeginLoc(); + + if (InnerLoc.isInvalid() || InnerLoc.isMacroID() || OuterLoc.isInvalid() || + OuterLoc.isMacroID()) + continue; + + if (SM.getExpansionLineNumber(InnerLoc) == + SM.getExpansionLineNumber(OuterLoc)) + continue; + + const Stmt *NextStmt = CStmt->body_begin()[I + 1]; + SourceLocation NextLoc = NextStmt->getBeginLoc(); + + if (NextLoc.isInvalid() || NextLoc.isMacroID()) + continue; + + if (SM.getExpansionColumnNumber(InnerLoc) == + SM.getExpansionColumnNumber(NextLoc)) { + diag(NextLoc, "misleading indentation: statement is indented too deeply"); + diag(OuterLoc, "did you mean this line to be inside this '%0'", + DiagnosticIDs::Note) + << StmtNames[StmtKind]; + } + } +} + +void MisleadingIndentationCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(ifStmt(hasElse(stmt())).bind("if"), this); + Finder->addMatcher( + compoundStmt(has(stmt(anyOf(ifStmt(), forStmt(), whileStmt())))) + .bind("compound"), + this); +} + +void MisleadingIndentationCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *If = Result.Nodes.getNodeAs<IfStmt>("if")) + danglingElseCheck(*Result.SourceManager, Result.Context, If); + + if (const auto *CStmt = Result.Nodes.getNodeAs<CompoundStmt>("compound")) + missingBracesCheck(*Result.SourceManager, CStmt); +} + +} // namespace clang::tidy::readability |