================
@@ -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

Reply via email to