================
@@ -28,6 +30,205 @@ AST_MATCHER(LinkageSpecDecl, isExternCLinkage) {
} // namespace
+namespace {
+
+struct TokenRangeInfo {
+ bool HasComment = false;
+ bool HasIdentifier = false;
+ bool HasPointerOrRef = false;
+};
+
+struct RangeTextInfo {
+ std::string Text;
+ TokenRangeInfo Tokens;
+};
+
+} // namespace
+
+static bool hasNonWhitespace(StringRef Text) {
+ return Text.find_first_not_of(" \t\n\r\f\v") != StringRef::npos;
+}
+
+static std::optional<std::string> getSourceText(CharSourceRange Range,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (Range.isInvalid())
+ return std::nullopt;
+
+ const CharSourceRange FileRange =
+ Lexer::makeFileCharRange(Range, SM, LangOpts);
+ if (FileRange.isInvalid())
+ return std::nullopt;
+
+ bool IsInvalid = false;
+ const StringRef Text =
+ Lexer::getSourceText(FileRange, SM, LangOpts, &IsInvalid);
+ if (IsInvalid)
+ return std::nullopt;
+ return Text.str();
+}
+
+static TokenRangeInfo getTokenRangeInfo(CharSourceRange Range,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ TokenRangeInfo Info;
+ if (Range.isInvalid())
+ return Info;
+
+ const CharSourceRange FileRange =
+ Lexer::makeFileCharRange(Range, SM, LangOpts);
+ if (FileRange.isInvalid())
+ return Info;
+
+ const auto [BeginFID, BeginOffset] =
+ SM.getDecomposedLoc(FileRange.getBegin());
+ const auto [EndFID, EndOffset] = SM.getDecomposedLoc(FileRange.getEnd());
+ if (BeginFID != EndFID || BeginOffset > EndOffset)
+ return Info;
+
+ bool IsInvalid = false;
+ const StringRef Buffer = SM.getBufferData(BeginFID, &IsInvalid);
+ if (IsInvalid)
+ return Info;
+
+ const char *LexStart = Buffer.data() + BeginOffset;
+ Lexer TheLexer(SM.getLocForStartOfFile(BeginFID), LangOpts, Buffer.begin(),
+ LexStart, Buffer.end());
+ TheLexer.SetCommentRetentionState(true);
+
+ while (true) {
+ Token Tok;
+ if (TheLexer.LexFromRawLexer(Tok))
+ break;
+
+ if (Tok.is(tok::eof) || Tok.getLocation() == FileRange.getEnd() ||
+ SM.isBeforeInTranslationUnit(FileRange.getEnd(), Tok.getLocation()))
+ break;
+
+ if (Tok.is(tok::comment)) {
+ Info.HasComment = true;
+ continue;
+ }
+
+ if (Tok.isOneOf(tok::star, tok::amp))
+ Info.HasPointerOrRef = true;
+
+ if (tok::isAnyIdentifier(Tok.getKind()) ||
+ Tok.isOneOf(tok::kw_typedef, tok::kw_struct, tok::kw_class,
+ tok::kw_union, tok::kw_enum, tok::kw_typename,
+ tok::kw_template)) {
+ Info.HasIdentifier = true;
+ }
+ }
+
+ return Info;
+}
+
+static RangeTextInfo getRangeTextInfo(SourceLocation Begin, SourceLocation End,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (!Begin.isValid() || !End.isValid() || Begin.isMacroID() ||
+ End.isMacroID())
+ return {};
+
+ const CharSourceRange Range = CharSourceRange::getCharRange(Begin, End);
+ if (std::optional<std::string> Text = getSourceText(Range, SM, LangOpts))
+ return {*Text, getTokenRangeInfo(Range, SM, LangOpts)};
+ return {};
+}
+
+static std::optional<std::string>
+getFunctionPointerTypeText(SourceRange TypeRange, SourceLocation NameLoc,
+ const SourceManager &SM, const LangOptions &LO) {
+ SourceLocation StartLoc = NameLoc;
+ SourceLocation EndLoc = NameLoc;
+
+ while (true) {
+ const std::optional<Token> Prev = lexer::getPreviousToken(StartLoc, SM,
LO);
+ const std::optional<Token> Next =
+ lexer::findNextTokenSkippingComments(EndLoc, SM, LO);
+ if (!Prev || Prev->isNot(tok::l_paren) || !Next ||
+ Next->isNot(tok::r_paren))
+ break;
+
+ StartLoc = Prev->getLocation();
+ EndLoc = Next->getLocation();
+ }
+
+ const CharSourceRange RangeLeftOfIdentifier =
+ CharSourceRange::getCharRange(TypeRange.getBegin(), StartLoc);
+ const CharSourceRange RangeRightOfIdentifier = CharSourceRange::getCharRange(
+ Lexer::getLocForEndOfToken(EndLoc, 0, SM, LO),
+ Lexer::getLocForEndOfToken(TypeRange.getEnd(), 0, SM, LO));
+
+ const std::optional<std::string> LeftText =
+ getSourceText(RangeLeftOfIdentifier, SM, LO);
+ if (!LeftText)
+ return std::nullopt;
+
+ const std::optional<std::string> RightText =
+ getSourceText(RangeRightOfIdentifier, SM, LO);
+ if (!RightText)
+ return std::nullopt;
+
+ return *LeftText + *RightText;
+}
+
+static RangeTextInfo getLeadingTextInfo(bool IsFirstTypedefInGroup,
+ SourceRange ReplaceRange,
+ SourceRange TypeRange,
+ const SourceManager &SM,
+ const LangOptions &LO) {
+ if (!IsFirstTypedefInGroup)
+ return {};
+
+ const SourceLocation TypedefEnd =
+ Lexer::getLocForEndOfToken(ReplaceRange.getBegin(), 0, SM, LO);
+ RangeTextInfo Info =
+ getRangeTextInfo(TypedefEnd, TypeRange.getBegin(), SM, LO);
+ if (!Info.Tokens.HasComment)
+ Info.Text.clear();
+ return Info;
+}
+
+static RangeTextInfo
+getSuffixTextInfo(bool FunctionPointerCase, bool IsFirstTypedefInGroup,
+ SourceLocation PrevReplacementEnd, SourceRange TypeRange,
+ SourceLocation NameLoc, const SourceManager &SM,
+ const LangOptions &LO) {
+ if (FunctionPointerCase)
+ return {};
+
+ if (IsFirstTypedefInGroup) {
+ const SourceLocation AfterType =
+ Lexer::getLocForEndOfToken(TypeRange.getEnd(), 0, SM, LO);
+ return getRangeTextInfo(AfterType, NameLoc, SM, LO);
+ }
+
+ if (!PrevReplacementEnd.isValid() || PrevReplacementEnd.isMacroID())
+ return {};
+
+ SourceLocation AfterComma = PrevReplacementEnd;
+ if (const std::optional<Token> NextTok =
+ lexer::findNextTokenSkippingComments(AfterComma, SM, LO)) {
+ if (NextTok->is(tok::comma)) {
+ AfterComma =
+ Lexer::getLocForEndOfToken(NextTok->getLocation(), 0, SM, LO);
+ }
+ }
+
+ return getRangeTextInfo(AfterComma, NameLoc, SM, LO);
+}
+
+static void stripLeadingComma(RangeTextInfo &Info) {
+ if (!hasNonWhitespace(Info.Text))
+ return;
+
+ const size_t NonWs = Info.Text.find_first_not_of(" \t\n\r\f\v");
----------------
vbvictor wrote:
Why we have to make 2 operations if we can call find() right-away and then
compare NonWs to `npos`
https://github.com/llvm/llvm-project/pull/180372
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits