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/LangOptions.h"
13+ #include " clang/Basic/SourceLocation.h"
14+ #include " clang/Basic/SourceManager.h"
15+ #include " clang/Basic/TokenKinds.h"
1216#include " clang/Lex/Lexer.h"
17+ #include < string>
1318
1419using namespace clang ::ast_matchers;
1520namespace {
@@ -83,6 +88,9 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
8388 if (!ParentDecl)
8489 return ;
8590
91+ const SourceManager &SM = *Result.SourceManager ;
92+ const LangOptions &LO = getLangOpts ();
93+
8694 // Match CXXRecordDecl only to store the range of the last non-implicit full
8795 // declaration, to later check whether it's within the typdef itself.
8896 const auto *MatchedTagDecl = Result.Nodes .getNodeAs <TagDecl>(TagDeclName);
@@ -119,14 +127,51 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
119127 return ;
120128 }
121129
122- PrintingPolicy PrintPolicy (getLangOpts ());
123- PrintPolicy.SuppressScope = true ;
124- PrintPolicy.ConstantArraySizeAsWritten = true ;
125- PrintPolicy.UseVoidForZeroParams = false ;
126- PrintPolicy.PrintInjectedClassNameWithArguments = false ;
130+ const TypeLoc TL = MatchedDecl->getTypeSourceInfo ()->getTypeLoc ();
131+
132+ auto [Type, QualifierStr] = [MatchedDecl, this , &TL, &SM,
133+ &LO]() -> std::pair<std::string, std::string> {
134+ SourceRange TypeRange = TL.getSourceRange ();
135+
136+ // Function pointer case, get the left and right side of the identifier
137+ // without the identifier.
138+ if (TypeRange.fullyContains (MatchedDecl->getLocation ())) {
139+ const auto RangeLeftOfIdentifier = CharSourceRange::getCharRange (
140+ TypeRange.getBegin (), MatchedDecl->getLocation ());
141+ const auto RangeRightOfIdentifier = CharSourceRange::getCharRange (
142+ Lexer::getLocForEndOfToken (MatchedDecl->getLocation (), 0 , SM, LO),
143+ Lexer::getLocForEndOfToken (TypeRange.getEnd (), 0 , SM, LO));
144+ const std::string VerbatimType =
145+ (Lexer::getSourceText (RangeLeftOfIdentifier, SM, LO) +
146+ Lexer::getSourceText (RangeRightOfIdentifier, SM, LO))
147+ .str ();
148+ return {VerbatimType, " " };
149+ }
150+
151+ StringRef ExtraReference = " " ;
152+ if (MainTypeEndLoc.isValid () && TypeRange.fullyContains (MainTypeEndLoc)) {
153+ // Each type introduced in a typedef can specify being a reference or
154+ // pointer type seperately, so we need to sigure out if the new using-decl
155+ // needs to be to a reference or pointer as well.
156+ const SourceLocation Tok = utils::lexer::findPreviousAnyTokenKind (
157+ MatchedDecl->getLocation (), SM, LO, tok::TokenKind::star,
158+ tok::TokenKind::amp, tok::TokenKind::comma,
159+ tok::TokenKind::kw_typedef);
160+
161+ ExtraReference = Lexer::getSourceText (
162+ CharSourceRange::getCharRange (Tok, Tok.getLocWithOffset (1 )), SM, LO);
127163
128- std::string Type = MatchedDecl->getUnderlyingType ().getAsString (PrintPolicy);
129- std::string Name = MatchedDecl->getNameAsString ();
164+ if (ExtraReference != " *" && ExtraReference != " &" )
165+ ExtraReference = " " ;
166+
167+ TypeRange.setEnd (MainTypeEndLoc);
168+ }
169+ return {
170+ Lexer::getSourceText (CharSourceRange::getTokenRange (TypeRange), SM, LO)
171+ .str (),
172+ ExtraReference.str ()};
173+ }();
174+ StringRef Name = MatchedDecl->getName ();
130175 SourceRange ReplaceRange = MatchedDecl->getSourceRange ();
131176
132177 // typedefs with multiple comma-separated definitions produce multiple
@@ -143,7 +188,8 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
143188 // This is the first (and possibly the only) TypedefDecl in a typedef. Save
144189 // Type and Name in case we find subsequent TypedefDecl's in this typedef.
145190 FirstTypedefType = Type;
146- FirstTypedefName = Name;
191+ FirstTypedefName = Name.str ();
192+ MainTypeEndLoc = TL.getEndLoc ();
147193 } else {
148194 // This is additional TypedefDecl in a comma-separated typedef declaration.
149195 // Start replacement *after* prior replacement and separate with semicolon.
@@ -153,10 +199,10 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
153199 // If this additional TypedefDecl's Type starts with the first TypedefDecl's
154200 // type, make this using statement refer back to the first type, e.g. make
155201 // "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 );
202+ if (Type == FirstTypedefType && !QualifierStr.empty ())
203+ Type = FirstTypedefName;
159204 }
205+
160206 if (!ReplaceRange.getEnd ().isMacroID ()) {
161207 const SourceLocation::IntTy Offset =
162208 MatchedDecl->getFunctionType () ? 0 : Name.size ();
@@ -171,13 +217,12 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
171217 LastTagDeclRange->second .isValid () &&
172218 ReplaceRange.fullyContains (LastTagDeclRange->second )) {
173219 Type = std::string (Lexer::getSourceText (
174- CharSourceRange::getTokenRange (LastTagDeclRange->second ),
175- *Result.SourceManager , getLangOpts ()));
220+ CharSourceRange::getTokenRange (LastTagDeclRange->second ), SM, LO));
176221 if (Type.empty ())
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