77// ===----------------------------------------------------------------------===//
88
99#include " UseUsingCheck.h"
10- #include " clang/AST/ASTContext .h"
10+ #include " ../utils/LexerUtils .h"
1111#include " clang/AST/DeclGroup.h"
12+ #include " clang/Basic/SourceLocation.h"
13+ #include " clang/Basic/TokenKinds.h"
1214#include " clang/Lex/Lexer.h"
15+ #include < string>
1316
1417using namespace clang ::ast_matchers;
1518namespace {
@@ -119,14 +122,55 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
119122 return ;
120123 }
121124
122- PrintingPolicy PrintPolicy (getLangOpts ());
123- PrintPolicy.SuppressScope = true ;
124- PrintPolicy.ConstantArraySizeAsWritten = true ;
125- PrintPolicy.UseVoidForZeroParams = false ;
126- PrintPolicy.PrintInjectedClassNameWithArguments = false ;
125+ const TypeLoc TL = MatchedDecl->getTypeSourceInfo ()->getTypeLoc ();
126+
127+ auto [Type, QualifierStr] = [MatchedDecl, &Result, this ,
128+ &TL]() -> std::pair<std::string, std::string> {
129+ SourceRange TypeRange = TL.getSourceRange ();
130+
131+ // Function pointer case, get the left and right side of the identifier
132+ // without the identifier.
133+ if (TypeRange.fullyContains (MatchedDecl->getLocation ())) {
134+ return {(Lexer::getSourceText (
135+ CharSourceRange::getCharRange (TL.getBeginLoc (),
136+ MatchedDecl->getLocation ()),
137+ *Result.SourceManager , getLangOpts ()) +
138+ Lexer::getSourceText (
139+ CharSourceRange::getCharRange (
140+ Lexer::getLocForEndOfToken (MatchedDecl->getLocation (), 0 ,
141+ *Result.SourceManager ,
142+ getLangOpts ()),
143+ Lexer::getLocForEndOfToken (TL.getEndLoc (), 0 ,
144+ *Result.SourceManager ,
145+ getLangOpts ())),
146+ *Result.SourceManager , getLangOpts ()))
147+ .str (),
148+ " " };
149+ }
150+
151+ StringRef ExtraReference = " " ;
152+ if (MainTypeEndLoc.isValid () && TypeRange.fullyContains (MainTypeEndLoc)) {
153+ const SourceLocation Tok = utils::lexer::findPreviousAnyTokenKind (
154+ MatchedDecl->getLocation (), *Result.SourceManager , getLangOpts (),
155+ tok::TokenKind::star, tok::TokenKind::amp, tok::TokenKind::comma,
156+ tok::TokenKind::kw_typedef);
157+
158+ ExtraReference = Lexer::getSourceText (
159+ CharSourceRange::getCharRange (Tok, Tok.getLocWithOffset (1 )),
160+ *Result.SourceManager , getLangOpts ());
127161
128- std::string Type = MatchedDecl->getUnderlyingType ().getAsString (PrintPolicy);
129- std::string Name = MatchedDecl->getNameAsString ();
162+ if (ExtraReference != " *" && ExtraReference != " &" )
163+ ExtraReference = " " ;
164+
165+ if (MainTypeEndLoc.isValid ())
166+ TypeRange.setEnd (MainTypeEndLoc);
167+ }
168+ return {Lexer::getSourceText (CharSourceRange::getTokenRange (TypeRange),
169+ *Result.SourceManager , getLangOpts ())
170+ .str (),
171+ ExtraReference.str ()};
172+ }();
173+ StringRef Name = MatchedDecl->getName ();
130174 SourceRange ReplaceRange = MatchedDecl->getSourceRange ();
131175
132176 // typedefs with multiple comma-separated definitions produce multiple
@@ -143,7 +187,8 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
143187 // This is the first (and possibly the only) TypedefDecl in a typedef. Save
144188 // Type and Name in case we find subsequent TypedefDecl's in this typedef.
145189 FirstTypedefType = Type;
146- FirstTypedefName = Name;
190+ FirstTypedefName = Name.str ();
191+ MainTypeEndLoc = TL.getEndLoc ();
147192 } else {
148193 // This is additional TypedefDecl in a comma-separated typedef declaration.
149194 // Start replacement *after* prior replacement and separate with semicolon.
@@ -153,10 +198,10 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
153198 // If this additional TypedefDecl's Type starts with the first TypedefDecl's
154199 // type, make this using statement refer back to the first type, e.g. make
155200 // "typedef int Foo, *Foo_p;" -> "using Foo = int;\nusing Foo_p = Foo*;"
156- if (Type.size () > FirstTypedefType.size () &&
157- Type.substr (0 , FirstTypedefType.size ()) == FirstTypedefType)
158- Type = FirstTypedefName + Type.substr (FirstTypedefType.size () + 1 );
201+ if (Type == FirstTypedefType && !QualifierStr.empty ())
202+ Type = FirstTypedefName;
159203 }
204+
160205 if (!ReplaceRange.getEnd ().isMacroID ()) {
161206 const SourceLocation::IntTy Offset =
162207 MatchedDecl->getFunctionType () ? 0 : Name.size ();
@@ -177,7 +222,7 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
177222 return ;
178223 }
179224
180- std::string Replacement = Using + Name + " = " + Type;
225+ std::string Replacement = ( Using + Name + " = " + Type + QualifierStr). str () ;
181226 Diag << FixItHint::CreateReplacement (ReplaceRange, Replacement);
182227}
183228} // namespace clang::tidy::modernize
0 commit comments