diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp | 75 |
1 files changed, 60 insertions, 15 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp index 24eefdb..30fcba3 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp @@ -7,9 +7,14 @@ //===----------------------------------------------------------------------===// #include "UseUsingCheck.h" -#include "clang/AST/ASTContext.h" +#include "../utils/LexerUtils.h" #include "clang/AST/DeclGroup.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Lex/Lexer.h" +#include <string> using namespace clang::ast_matchers; namespace { @@ -83,6 +88,9 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { if (!ParentDecl) return; + const SourceManager &SM = *Result.SourceManager; + const LangOptions &LO = getLangOpts(); + // Match CXXRecordDecl only to store the range of the last non-implicit full // declaration, to later check whether it's within the typdef itself. const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>(TagDeclName); @@ -119,14 +127,51 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { return; } - PrintingPolicy PrintPolicy(getLangOpts()); - PrintPolicy.SuppressScope = true; - PrintPolicy.ConstantArraySizeAsWritten = true; - PrintPolicy.UseVoidForZeroParams = false; - PrintPolicy.PrintInjectedClassNameWithArguments = false; + const TypeLoc TL = MatchedDecl->getTypeSourceInfo()->getTypeLoc(); + + auto [Type, QualifierStr] = [MatchedDecl, this, &TL, &SM, + &LO]() -> std::pair<std::string, std::string> { + SourceRange TypeRange = TL.getSourceRange(); + + // Function pointer case, get the left and right side of the identifier + // without the identifier. + if (TypeRange.fullyContains(MatchedDecl->getLocation())) { + const auto RangeLeftOfIdentifier = CharSourceRange::getCharRange( + TypeRange.getBegin(), MatchedDecl->getLocation()); + const auto RangeRightOfIdentifier = CharSourceRange::getCharRange( + Lexer::getLocForEndOfToken(MatchedDecl->getLocation(), 0, SM, LO), + Lexer::getLocForEndOfToken(TypeRange.getEnd(), 0, SM, LO)); + const std::string VerbatimType = + (Lexer::getSourceText(RangeLeftOfIdentifier, SM, LO) + + Lexer::getSourceText(RangeRightOfIdentifier, SM, LO)) + .str(); + return {VerbatimType, ""}; + } + + StringRef ExtraReference = ""; + if (MainTypeEndLoc.isValid() && TypeRange.fullyContains(MainTypeEndLoc)) { + // Each type introduced in a typedef can specify being a reference or + // pointer type seperately, so we need to sigure out if the new using-decl + // needs to be to a reference or pointer as well. + const SourceLocation Tok = utils::lexer::findPreviousAnyTokenKind( + MatchedDecl->getLocation(), SM, LO, tok::TokenKind::star, + tok::TokenKind::amp, tok::TokenKind::comma, + tok::TokenKind::kw_typedef); + + ExtraReference = Lexer::getSourceText( + CharSourceRange::getCharRange(Tok, Tok.getLocWithOffset(1)), SM, LO); - std::string Type = MatchedDecl->getUnderlyingType().getAsString(PrintPolicy); - std::string Name = MatchedDecl->getNameAsString(); + if (ExtraReference != "*" && ExtraReference != "&") + ExtraReference = ""; + + TypeRange.setEnd(MainTypeEndLoc); + } + return { + Lexer::getSourceText(CharSourceRange::getTokenRange(TypeRange), SM, LO) + .str(), + ExtraReference.str()}; + }(); + StringRef Name = MatchedDecl->getName(); SourceRange ReplaceRange = MatchedDecl->getSourceRange(); // typedefs with multiple comma-separated definitions produce multiple @@ -143,7 +188,8 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { // This is the first (and possibly the only) TypedefDecl in a typedef. Save // Type and Name in case we find subsequent TypedefDecl's in this typedef. FirstTypedefType = Type; - FirstTypedefName = Name; + FirstTypedefName = Name.str(); + MainTypeEndLoc = TL.getEndLoc(); } else { // This is additional TypedefDecl in a comma-separated typedef declaration. // Start replacement *after* prior replacement and separate with semicolon. @@ -153,10 +199,10 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { // If this additional TypedefDecl's Type starts with the first TypedefDecl's // type, make this using statement refer back to the first type, e.g. make // "typedef int Foo, *Foo_p;" -> "using Foo = int;\nusing Foo_p = Foo*;" - if (Type.size() > FirstTypedefType.size() && - Type.substr(0, FirstTypedefType.size()) == FirstTypedefType) - Type = FirstTypedefName + Type.substr(FirstTypedefType.size() + 1); + if (Type == FirstTypedefType && !QualifierStr.empty()) + Type = FirstTypedefName; } + if (!ReplaceRange.getEnd().isMacroID()) { const SourceLocation::IntTy Offset = MatchedDecl->getFunctionType() ? 0 : Name.size(); @@ -171,13 +217,12 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { LastTagDeclRange->second.isValid() && ReplaceRange.fullyContains(LastTagDeclRange->second)) { Type = std::string(Lexer::getSourceText( - CharSourceRange::getTokenRange(LastTagDeclRange->second), - *Result.SourceManager, getLangOpts())); + CharSourceRange::getTokenRange(LastTagDeclRange->second), SM, LO)); if (Type.empty()) return; } - std::string Replacement = Using + Name + " = " + Type; + std::string Replacement = (Using + Name + " = " + Type + QualifierStr).str(); Diag << FixItHint::CreateReplacement(ReplaceRange, Replacement); } } // namespace clang::tidy::modernize |