================
@@ -26,6 +26,129 @@ AST_MATCHER(clang::LinkageSpecDecl, isExternCLinkage) {
namespace clang::tidy::modernize {
+namespace lexer = clang::tidy::utils::lexer;
+
+namespace {
+struct RangeTextInfo {
+ std::string Text;
+ lexer::TokenRangeInfo Tokens;
+};
+} // namespace
+
+static bool hasNonWhitespace(llvm::StringRef Text) {
+ return Text.find_first_not_of(" \t\n\r\f\v") != llvm::StringRef::npos;
+}
+
+static RangeTextInfo getRangeTextInfo(clang::SourceLocation Begin,
+ clang::SourceLocation End,
+ const clang::SourceManager &SM,
+ const clang::LangOptions &LangOpts) {
+ RangeTextInfo Info;
+ if (!Begin.isValid() || !End.isValid() || Begin.isMacroID() ||
+ End.isMacroID())
+ return Info;
+
+ const clang::CharSourceRange Range =
+ clang::CharSourceRange::getCharRange(Begin, End);
+ Info.Text = lexer::getSourceText(Range, SM, LangOpts);
+ Info.Tokens = lexer::analyzeTokenRange(Range, SM, LangOpts);
+ return Info;
+}
+
+static std::string getFunctionPointerTypeText(clang::SourceRange TypeRange,
+ clang::SourceLocation NameLoc,
+ const clang::SourceManager &SM,
+ const clang::LangOptions &LO) {
+ clang::SourceLocation StartLoc = NameLoc;
+ clang::SourceLocation EndLoc = NameLoc;
+
+ while (true) {
+ const std::optional<clang::Token> Prev =
+ lexer::getPreviousToken(StartLoc, SM, LO);
+ const std::optional<clang::Token> Next =
+ lexer::findNextTokenSkippingComments(EndLoc, SM, LO);
+ if (!Prev || Prev->isNot(clang::tok::l_paren) || !Next ||
+ Next->isNot(clang::tok::r_paren))
+ break;
+
+ StartLoc = Prev->getLocation();
+ EndLoc = Next->getLocation();
+ }
+
+ const clang::CharSourceRange RangeLeftOfIdentifier =
+ clang::CharSourceRange::getCharRange(TypeRange.getBegin(), StartLoc);
+ const clang::CharSourceRange RangeRightOfIdentifier =
+ clang::CharSourceRange::getCharRange(
+ clang::Lexer::getLocForEndOfToken(EndLoc, 0, SM, LO),
+ clang::Lexer::getLocForEndOfToken(TypeRange.getEnd(), 0, SM, LO));
+ return lexer::getSourceText(RangeLeftOfIdentifier, SM, LO) +
+ lexer::getSourceText(RangeRightOfIdentifier, SM, LO);
+}
+
+static RangeTextInfo getLeadingTextInfo(bool IsFirstTypedefInGroup,
+ clang::SourceRange ReplaceRange,
+ clang::SourceRange TypeRange,
+ const clang::SourceManager &SM,
+ const clang::LangOptions &LO) {
+ RangeTextInfo Info;
+ if (!IsFirstTypedefInGroup)
+ return Info;
+
+ const clang::SourceLocation TypedefEnd =
+ clang::Lexer::getLocForEndOfToken(ReplaceRange.getBegin(), 0, SM, LO);
+ Info = getRangeTextInfo(TypedefEnd, TypeRange.getBegin(), SM, LO);
+ // Keep leading trivia only when it actually contains comments. This avoids
+ // shifting plain whitespace from between 'typedef' and the type into the
+ // replacement, preserving formatting for un-commented declarations.
+ if (!Info.Tokens.HasComment)
+ Info.Text.clear();
+ return Info;
+}
+
+static RangeTextInfo getSuffixTextInfo(bool FunctionPointerCase,
+ bool IsFirstTypedefInGroup,
+ clang::SourceLocation
PrevReplacementEnd,
+ clang::SourceRange TypeRange,
+ clang::SourceLocation NameLoc,
+ const clang::SourceManager &SM,
+ const clang::LangOptions &LO) {
+ RangeTextInfo Info;
+ if (FunctionPointerCase)
+ return Info;
+
+ // Capture the raw text between type and name to preserve trailing comments,
+ // including multi-line // blocks, without re-lexing individual comment
+ // tokens.
+ if (IsFirstTypedefInGroup) {
+ const clang::SourceLocation AfterType =
+ clang::Lexer::getLocForEndOfToken(TypeRange.getEnd(), 0, SM, LO);
+ return getRangeTextInfo(AfterType, NameLoc, SM, LO);
+ }
+
+ if (!PrevReplacementEnd.isValid() || PrevReplacementEnd.isMacroID())
+ return Info;
+
+ clang::SourceLocation AfterComma = PrevReplacementEnd;
+ if (const std::optional<clang::Token> NextTok =
+ lexer::findNextTokenSkippingComments(AfterComma, SM, LO)) {
+ if (NextTok->is(clang::tok::comma)) {
+ AfterComma =
+ clang::Lexer::getLocForEndOfToken(NextTok->getLocation(), 0, SM, LO);
+ }
+ }
+ return getRangeTextInfo(AfterComma, NameLoc, SM, LO);
+}
+
+static void stripLeadingComma(RangeTextInfo &Info) {
+ if (Info.Text.empty())
+ return;
+ // Overlapping ranges in multi-declarator typedefs can leave a leading comma
+ // in the captured suffix. Drop it so the replacement doesn't reintroduce it.
+ const size_t NonWs = Info.Text.find_first_not_of(" \t\n\r\f\v");
----------------
vbvictor wrote:
`hasNonWhitespace`?
https://github.com/llvm/llvm-project/pull/180372
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits