72 const SourceManager &SM,
73 const LangOptions &LangOpts) {
75 if (Range.isInvalid())
78 const CharSourceRange FileRange =
79 Lexer::makeFileCharRange(Range, SM, LangOpts);
80 if (FileRange.isInvalid())
83 const auto [BeginFID, BeginOffset] =
84 SM.getDecomposedLoc(FileRange.getBegin());
85 const auto [EndFID, EndOffset] = SM.getDecomposedLoc(FileRange.getEnd());
86 if (BeginFID != EndFID || BeginOffset > EndOffset)
89 bool IsInvalid =
false;
90 const StringRef Buffer = SM.getBufferData(BeginFID, &IsInvalid);
94 const char *LexStart = Buffer.data() + BeginOffset;
95 Lexer TheLexer(SM.getLocForStartOfFile(BeginFID), LangOpts, Buffer.begin(),
96 LexStart, Buffer.end());
97 TheLexer.SetCommentRetentionState(
true);
101 if (TheLexer.LexFromRawLexer(Tok))
104 if (Tok.is(tok::eof) || Tok.getLocation() == FileRange.getEnd() ||
105 SM.isBeforeInTranslationUnit(FileRange.getEnd(), Tok.getLocation()))
108 if (Tok.is(tok::comment)) {
109 Info.HasComment =
true;
113 if (Tok.isOneOf(tok::star, tok::amp))
114 Info.HasPointerOrRef =
true;
116 if (tok::isAnyIdentifier(Tok.getKind()) ||
117 Tok.isOneOf(tok::kw_typedef, tok::kw_struct, tok::kw_class,
118 tok::kw_union, tok::kw_enum, tok::kw_typename,
120 Info.HasIdentifier =
true;
142 const SourceManager &SM,
const LangOptions &LO) {
143 SourceLocation StartLoc = NameLoc;
144 SourceLocation EndLoc = NameLoc;
147 const std::optional<Token> Prev = lexer::getPreviousToken(StartLoc, SM, LO);
148 const std::optional<Token> Next =
149 lexer::findNextTokenSkippingComments(EndLoc, SM, LO);
150 if (!Prev || Prev->isNot(tok::l_paren) || !Next ||
151 Next->isNot(tok::r_paren))
154 StartLoc = Prev->getLocation();
155 EndLoc = Next->getLocation();
158 const CharSourceRange RangeLeftOfIdentifier =
159 CharSourceRange::getCharRange(TypeRange.getBegin(), StartLoc);
160 const CharSourceRange RangeRightOfIdentifier = CharSourceRange::getCharRange(
161 Lexer::getLocForEndOfToken(EndLoc, 0, SM, LO),
162 Lexer::getLocForEndOfToken(TypeRange.getEnd(), 0, SM, LO));
164 const std::optional<std::string> LeftText =
169 const std::optional<std::string> RightText =
174 return *LeftText + *RightText;
196 SourceLocation PrevReplacementEnd, SourceRange TypeRange,
197 SourceLocation NameLoc,
const SourceManager &SM,
198 const LangOptions &LO) {
199 if (FunctionPointerCase)
202 if (IsFirstTypedefInGroup) {
203 const SourceLocation AfterType =
204 Lexer::getLocForEndOfToken(TypeRange.getEnd(), 0, SM, LO);
208 if (!PrevReplacementEnd.isValid() || PrevReplacementEnd.isMacroID())
211 SourceLocation AfterComma = PrevReplacementEnd;
212 if (
const std::optional<Token> NextTok =
213 lexer::findNextTokenSkippingComments(AfterComma, SM, LO)) {
214 if (NextTok->is(tok::comma)) {
216 Lexer::getLocForEndOfToken(NextTok->getLocation(), 0, SM, LO);
274 const auto *ParentDecl = Result.Nodes.getNodeAs<Decl>(
ParentDeclName);
277 const auto *ParentDeclStmt = Result.Nodes.getNodeAs<DeclStmt>(
DeclStmtName);
278 if (ParentDeclStmt) {
279 if (ParentDeclStmt->isSingleDecl())
280 ParentDecl = ParentDeclStmt->getSingleDecl();
283 ParentDeclStmt->getDeclGroup().getDeclGroup()
284 [ParentDeclStmt->getDeclGroup().getDeclGroup().size() - 1];
291 const SourceManager &SM = *Result.SourceManager;
292 const LangOptions &LO = getLangOpts();
296 const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>(
TagDeclName);
297 if (MatchedTagDecl) {
303 if (MatchedTagDecl->isThisDeclarationADefinition())
304 LastTagDeclRanges[ParentDecl] = MatchedTagDecl->getSourceRange();
308 const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>(
TypedefName);
309 if (MatchedDecl->getLocation().isInvalid())
312 const auto *ExternCDecl =
314 if (ExternCDecl && IgnoreExternC)
317 const SourceLocation StartLoc = MatchedDecl->getBeginLoc();
319 if (StartLoc.isMacroID() && IgnoreMacros)
322 static constexpr StringRef UseUsingWarning =
323 "use 'using' instead of 'typedef'";
326 if (MatchedDecl->getUnderlyingType()->isArrayType() || StartLoc.isMacroID()) {
327 diag(StartLoc, UseUsingWarning);
331 const TypeLoc TL = MatchedDecl->getTypeSourceInfo()->getTypeLoc();
335 bool FunctionPointerCase =
false;
338 std::string Qualifier;
341 const TypeInfo TI = [&] {
343 Info.Range = TL.getSourceRange();
347 if (Info.Range.fullyContains(MatchedDecl->getLocation())) {
348 Info.FunctionPointerCase =
true;
350 Info.Range, MatchedDecl->getLocation(), SM, LO)) {
357 std::string ExtraReference;
358 if (MainTypeEndLoc.isValid() && Info.Range.fullyContains(MainTypeEndLoc)) {
362 const SourceLocation Tok = lexer::findPreviousAnyTokenKind(
363 MatchedDecl->getLocation(), SM, LO, tok::TokenKind::star,
364 tok::TokenKind::amp, tok::TokenKind::comma,
365 tok::TokenKind::kw_typedef);
368 CharSourceRange::getCharRange(Tok, Tok.getLocWithOffset(1)), SM, LO);
371 ExtraReference = *Reference;
373 if (ExtraReference !=
"*" && ExtraReference !=
"&")
374 ExtraReference.clear();
376 Info.Range.setEnd(MainTypeEndLoc);
379 if (std::optional<std::string> Type =
380 getSourceText(CharSourceRange::getTokenRange(Info.Range), SM, LO)) {
382 Info.Qualifier = ExtraReference;
389 diag(StartLoc, UseUsingWarning);
393 const SourceRange TypeRange = TI.Range;
394 const bool FunctionPointerCase = TI.FunctionPointerCase;
395 std::string Type = TI.Type;
396 const std::string QualifierStr = TI.Qualifier;
397 const StringRef Name = MatchedDecl->getName();
398 const SourceLocation NameLoc = MatchedDecl->getLocation();
399 SourceRange ReplaceRange = MatchedDecl->getSourceRange();
400 const SourceLocation PrevReplacementEnd = LastReplacementEnd;
408 std::string Using =
"using ";
409 const bool IsFirstTypedefInGroup =
410 ReplaceRange.getBegin().isMacroID() ||
411 (Result.SourceManager->getFileID(ReplaceRange.getBegin()) !=
412 Result.SourceManager->getFileID(LastReplacementEnd)) ||
413 (ReplaceRange.getBegin() >= LastReplacementEnd);
415 if (IsFirstTypedefInGroup) {
418 FirstTypedefType = Type;
419 FirstTypedefName = Name.str();
420 MainTypeEndLoc = TL.getEndLoc();
424 ReplaceRange.setBegin(LastReplacementEnd);
430 if (Type == FirstTypedefType && !QualifierStr.empty())
431 Type = FirstTypedefName;
435 IsFirstTypedefInGroup, ReplaceRange, TypeRange, SM, LO);
436 RangeTextInfo SuffixTextInfo =
438 PrevReplacementEnd, TypeRange, NameLoc, SM, LO);
439 if (!IsFirstTypedefInGroup)
442 const bool SuffixHasComment = SuffixTextInfo.Tokens.HasComment;
443 std::string SuffixText;
444 if (SuffixHasComment) {
445 SuffixText = SuffixTextInfo.Text;
446 }
else if (QualifierStr.empty() &&
448 SuffixTextInfo.Tokens.HasPointerOrRef &&
449 !SuffixTextInfo.Tokens.HasIdentifier) {
450 SuffixText = SuffixTextInfo.Text;
452 const std::string QualifierText = SuffixHasComment ?
"" : QualifierStr;
454 if (!ReplaceRange.getEnd().isMacroID()) {
455 const SourceLocation::IntTy Offset = FunctionPointerCase ? 0 : Name.size();
456 LastReplacementEnd = ReplaceRange.getEnd().getLocWithOffset(Offset);
459 auto Diag = diag(ReplaceRange.getBegin(), UseUsingWarning);
462 auto LastTagDeclRange = LastTagDeclRanges.find(ParentDecl);
463 if (LastTagDeclRange != LastTagDeclRanges.end() &&
464 LastTagDeclRange->second.isValid() &&
465 ReplaceRange.fullyContains(LastTagDeclRange->second)) {
467 CharSourceRange::getTokenRange(LastTagDeclRange->second), SM, LO);
473 std::string TypeExpr =
474 LeadingTextInfo.Text + Type + QualifierText + SuffixText;
475 TypeExpr = StringRef(TypeExpr).rtrim(
" \t").str();
476 StringRef Assign =
" = ";
477 if (!TypeExpr.empty() &&
478 (TypeExpr.front() ==
' ' || TypeExpr.front() ==
'\t'))
481 const std::string Replacement = (Using + Name + Assign + TypeExpr).str();
482 Diag << FixItHint::CreateReplacement(ReplaceRange, Replacement);