Files
TheRock/compiler/amd-llvm/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

182 lines
6.4 KiB
C++

//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file provides utilities to put braces around a statement.
///
//===----------------------------------------------------------------------===//
#include "BracesAroundStatement.h"
#include "../utils/LexerUtils.h"
#include "LexerUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Lex/Lexer.h"
namespace clang::tidy::utils {
BraceInsertionHints::operator bool() const { return DiagnosticPos.isValid(); }
bool BraceInsertionHints::offersFixIts() const {
return OpeningBracePos.isValid() && ClosingBracePos.isValid();
}
unsigned BraceInsertionHints::resultingCompoundLineExtent(
const SourceManager &SourceMgr) const {
return SourceMgr.getSpellingLineNumber(ClosingBracePos) -
SourceMgr.getSpellingLineNumber(OpeningBracePos);
}
FixItHint BraceInsertionHints::openingBraceFixIt() const {
return OpeningBracePos.isValid()
? FixItHint::CreateInsertion(OpeningBracePos, " {")
: FixItHint();
}
FixItHint BraceInsertionHints::closingBraceFixIt() const {
return ClosingBracePos.isValid()
? FixItHint::CreateInsertion(ClosingBracePos, ClosingBrace)
: FixItHint();
}
static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM,
const LangOptions &LangOpts) {
Token Tok;
const SourceLocation Beginning =
Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts);
assert(!Invalid && "Expected a valid token.");
if (Invalid)
return tok::NUM_TOKENS;
return Tok.getKind();
}
static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM,
const LangOptions &LangOpts) {
SourceLocation Loc = lexer::getUnifiedEndLoc(S, SM, LangOpts);
if (!Loc.isValid())
return Loc;
// Start searching right after S.
Loc = Loc.getLocWithOffset(1);
for (;;) {
assert(Loc.isValid());
while (isHorizontalWhitespace(*SM.getCharacterData(Loc)))
Loc = Loc.getLocWithOffset(1);
if (isVerticalWhitespace(*SM.getCharacterData(Loc))) {
// EOL, insert brace before.
break;
}
const tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts);
if (TokKind != tok::comment) {
// Non-comment token, insert brace before.
break;
}
const SourceLocation TokEndLoc =
Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
const SourceRange TokRange(Loc, TokEndLoc);
const StringRef Comment = Lexer::getSourceText(
CharSourceRange::getTokenRange(TokRange), SM, LangOpts);
if (Comment.starts_with("/*") && Comment.contains('\n')) {
// Multi-line block comment, insert brace before.
break;
}
// else: Trailing comment, insert brace after the newline.
// Fast-forward current token.
Loc = TokEndLoc;
}
return Loc;
}
BraceInsertionHints getBraceInsertionsHints(const Stmt *const S,
const LangOptions &LangOpts,
const SourceManager &SM,
SourceLocation StartLoc,
SourceLocation EndLocHint) {
// 1) If there's a corresponding "else" or "while", the check inserts "} "
// right before that token.
// 2) If there's a multi-line block comment starting on the same line after
// the location we're inserting the closing brace at, or there's a non-comment
// token, the check inserts "\n}" right before that token.
// 3) Otherwise the check finds the end of line (possibly after some block or
// line comments) and inserts "\n}" right before that EOL.
if (!S || isa<CompoundStmt>(S)) {
// Already inside braces.
return {};
}
// When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt.
// This NullStmt can be detected according to beginning token.
const SourceLocation StmtBeginLoc = S->getBeginLoc();
if (isa<NullStmt>(S) && StmtBeginLoc.isValid() &&
getTokenKind(StmtBeginLoc, SM, LangOpts) == tok::l_brace)
return {};
if (StartLoc.isInvalid())
return {};
const Stmt *InnerS = S;
while (const auto *AS = dyn_cast<AttributedStmt>(InnerS))
InnerS = AS->getSubStmt();
SourceLocation InsertLoc = StartLoc;
if (S != InnerS) {
if (std::optional<Token> Tok = utils::lexer::getPreviousToken(
InnerS->getBeginLoc(), SM, LangOpts, /*SkipComments=*/true)) {
InsertLoc = Tok->getLocation();
}
}
// Convert StartLoc to file location, if it's on the same macro expansion
// level as the start of the statement. We also need file locations for
// Lexer::getLocForEndOfToken working properly.
StartLoc = Lexer::makeFileCharRange(CharSourceRange::getCharRange(
InsertLoc, InnerS->getBeginLoc()),
SM, LangOpts)
.getBegin();
if (StartLoc.isInvalid())
return {};
StartLoc = Lexer::getLocForEndOfToken(StartLoc, 0, SM, LangOpts);
// StartLoc points at the location of the opening brace to be inserted.
SourceLocation EndLoc;
StringRef ClosingInsertion;
if (EndLocHint.isValid()) {
EndLoc = EndLocHint;
ClosingInsertion = "} ";
} else {
EndLoc = findEndLocation(*S, SM, LangOpts);
ClosingInsertion = "\n}";
}
assert(StartLoc.isValid());
// Change only if StartLoc and EndLoc are on the same macro expansion level.
// This will also catch invalid EndLoc.
// Example: LLVM_DEBUG( for(...) do_something() );
// In this case fix-it cannot be provided as the semicolon which is not
// visible here is part of the macro. Adding braces here would require adding
// another semicolon.
if (Lexer::makeFileCharRange(
CharSourceRange::getTokenRange(SourceRange(
SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))),
SM, LangOpts)
.isInvalid())
return {StartLoc};
return {StartLoc, EndLoc, ClosingInsertion};
}
} // namespace clang::tidy::utils