diff options
Diffstat (limited to 'clang-tools-extra')
72 files changed, 698 insertions, 710 deletions
diff --git a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp index 3e367ab..471ca45 100644 --- a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp +++ b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp @@ -31,24 +31,9 @@ llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef Name) { return Splitted; } -SourceLocation startLocationForType(TypeLoc TLoc) { - // For elaborated types (e.g. `struct a::A`) we want the portion after the - // `struct` but including the namespace qualifier, `a::`. - if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) { - NestedNameSpecifierLoc NestedNameSpecifier = - TLoc.castAs<ElaboratedTypeLoc>().getQualifierLoc(); - if (NestedNameSpecifier.getNestedNameSpecifier()) - return NestedNameSpecifier.getBeginLoc(); - TLoc = TLoc.getNextTypeLoc(); - } - return TLoc.getBeginLoc(); -} - SourceLocation endLocationForType(TypeLoc TLoc) { - // Dig past any namespace or keyword qualifications. - while (TLoc.getTypeLocClass() == TypeLoc::Elaborated || - TLoc.getTypeLocClass() == TypeLoc::Qualified) - TLoc = TLoc.getNextTypeLoc(); + if (auto QTL = TLoc.getAs<QualifiedTypeLoc>()) + TLoc = QTL.getUnqualifiedLoc(); // The location for template specializations (e.g. Foo<int>) includes the // templated types in its location range. We want to restrict this to just @@ -550,8 +535,8 @@ void ChangeNamespaceTool::run( Result.Nodes.getNodeAs<NestedNameSpecifierLoc>( "nested_specifier_loc")) { SourceLocation Start = Specifier->getBeginLoc(); - SourceLocation End = endLocationForType(Specifier->getTypeLoc()); - fixTypeLoc(Result, Start, End, Specifier->getTypeLoc()); + SourceLocation End = endLocationForType(Specifier->castAsTypeLoc()); + fixTypeLoc(Result, Start, End, Specifier->castAsTypeLoc()); } else if (const auto *BaseInitializer = Result.Nodes.getNodeAs<CXXCtorInitializer>( "base_initializer")) { @@ -562,19 +547,16 @@ void ChangeNamespaceTool::run( // filtered by matchers in some cases, e.g. the type is templated. We should // handle the record type qualifier instead. TypeLoc Loc = *TLoc; - while (Loc.getTypeLocClass() == TypeLoc::Qualified) - Loc = Loc.getNextTypeLoc(); - if (Loc.getTypeLocClass() == TypeLoc::Elaborated) { - NestedNameSpecifierLoc NestedNameSpecifier = - Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc(); - // FIXME: avoid changing injected class names. - if (auto *NNS = NestedNameSpecifier.getNestedNameSpecifier()) { - const Type *SpecifierType = NNS->getAsType(); - if (SpecifierType && SpecifierType->isRecordType()) - return; - } - } - fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc); + if (auto QTL = Loc.getAs<QualifiedTypeLoc>()) + Loc = QTL.getUnqualifiedLoc(); + // FIXME: avoid changing injected class names. + if (NestedNameSpecifier NestedNameSpecifier = + Loc.getPrefix().getNestedNameSpecifier(); + NestedNameSpecifier.getKind() == NestedNameSpecifier::Kind::Type && + NestedNameSpecifier.getAsType()->isRecordType()) + return; + fixTypeLoc(Result, Loc.getNonElaboratedBeginLoc(), endLocationForType(Loc), + Loc); } else if (const auto *VarRef = Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")) { const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl"); @@ -588,10 +570,9 @@ void ChangeNamespaceTool::run( } else if (const auto *EnumConstRef = Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) { // Do not rename the reference if it is already scoped by the EnumDecl name. - if (EnumConstRef->hasQualifier() && - EnumConstRef->getQualifier()->getKind() == - NestedNameSpecifier::SpecifierKind::TypeSpec && - EnumConstRef->getQualifier()->getAsType()->isEnumeralType()) + if (NestedNameSpecifier Qualifier = EnumConstRef->getQualifier(); + Qualifier.getKind() == NestedNameSpecifier::Kind::Type && + Qualifier.getAsType()->isEnumeralType()) return; const auto *EnumConstDecl = Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl"); diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index de73f68..bcab4f1 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -902,8 +902,8 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir, return; for (const CXXBaseSpecifier &B : D->bases()) { if (const RecordType *Ty = B.getType()->getAs<RecordType>()) { - if (const CXXRecordDecl *Base = - cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) { + if (const CXXRecordDecl *Base = cast_or_null<CXXRecordDecl>( + Ty->getOriginalDecl()->getDefinition())) { // Initialized without USR and name, this will be set in the following // if-else stmt. BaseRecordInfo BI( diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp index bb48883..1f30d27 100644 --- a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp @@ -216,8 +216,7 @@ void FindAllSymbols::registerMatchers(MatchFinder *MatchFinder) { // Uses of most types: just look at what the typeLoc refers to. MatchFinder->addMatcher( typeLoc(isExpansionInMainFile(), - loc(qualType(allOf(unless(elaboratedType()), - hasDeclaration(Types.bind("use")))))), + loc(qualType(hasDeclaration(Types.bind("use"))))), this); // Uses of typedefs: these are often transparent to hasDeclaration, so we need // to handle them explicitly. diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index f9d7597..fac6e04 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -533,7 +533,8 @@ void ClangTidyDiagnosticConsumer::forwardDiagnostic(const Diagnostic &Info) { Builder << reinterpret_cast<const NamedDecl *>(Info.getRawArg(Index)); break; case clang::DiagnosticsEngine::ak_nestednamespec: - Builder << reinterpret_cast<NestedNameSpecifier *>(Info.getRawArg(Index)); + Builder << NestedNameSpecifier::getFromVoidPointer( + reinterpret_cast<void *>(Info.getRawArg(Index))); break; case clang::DiagnosticsEngine::ak_declcontext: Builder << reinterpret_cast<DeclContext *>(Info.getRawArg(Index)); diff --git a/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp index 6565fa3..0625468 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/CrtpConstructorAccessibilityCheck.cpp @@ -43,7 +43,8 @@ static bool isDerivedClassBefriended(const CXXRecordDecl *CRTP, return false; } - return FriendType->getType()->getAsCXXRecordDecl() == Derived; + return declaresSameEntity(FriendType->getType()->getAsCXXRecordDecl(), + Derived); }); } @@ -55,7 +56,8 @@ getDerivedParameter(const ClassTemplateSpecializationDecl *CRTP, CRTP->getTemplateArgs().asArray(), [&](const TemplateArgument &Arg) { ++Idx; return Arg.getKind() == TemplateArgument::Type && - Arg.getAsType()->getAsCXXRecordDecl() == Derived; + declaresSameEntity(Arg.getAsType()->getAsCXXRecordDecl(), + Derived); }); return AnyOf ? CRTP->getSpecializedTemplate() diff --git a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp index a179d4bf..3cacb90 100644 --- a/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp @@ -577,7 +577,7 @@ approximateImplicitConversion(const TheCheck &Check, QualType LType, ImplicitConversionModellingMode ImplicitMode); static inline bool isUselessSugar(const Type *T) { - return isa<AttributedType, DecayedType, ElaboratedType, ParenType>(T); + return isa<AttributedType, DecayedType, ParenType>(T); } namespace { @@ -1040,7 +1040,9 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From, const auto *ToRecord = To->getAsCXXRecordDecl(); if (isDerivedToBase(FromRecord, ToRecord)) { LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived To Base.\n"); - WorkType = QualType{ToRecord->getTypeForDecl(), FastQualifiersToApply}; + WorkType = QualType{ + ToRecord->getASTContext().getCanonicalTagType(ToRecord)->getTypePtr(), + FastQualifiersToApply}; } if (Ctx.getLangOpts().CPlusPlus17 && FromPtr && ToPtr) { @@ -1072,9 +1074,9 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From, WorkType = To; } - if (WorkType == To) { + if (Ctx.hasSameType(WorkType, To)) { LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Reached 'To' type.\n"); - return {WorkType}; + return {Ctx.getCommonSugaredType(WorkType, To)}; } LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Did not reach 'To'.\n"); @@ -1219,7 +1221,7 @@ tryConversionOperators(const TheCheck &Check, const CXXRecordDecl *RD, if (std::optional<UserDefinedConversionSelector::PreparedConversion> SelectedConversion = ConversionSet()) { - QualType RecordType{RD->getTypeForDecl(), 0}; + CanQualType RecordType = RD->getASTContext().getCanonicalTagType(RD); ConversionSequence Result{RecordType, ToType}; // The conversion from the operator call's return type to ToType was @@ -1270,7 +1272,7 @@ tryConvertingConstructors(const TheCheck &Check, QualType FromType, if (std::optional<UserDefinedConversionSelector::PreparedConversion> SelectedConversion = ConversionSet()) { - QualType RecordType{RD->getTypeForDecl(), 0}; + CanQualType RecordType = RD->getASTContext().getCanonicalTagType(RD); ConversionSequence Result{FromType, RecordType}; Result.AfterFirstStandard = SelectedConversion->Seq.AfterFirstStandard; diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp index 75ef628..070ed04 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp @@ -69,10 +69,9 @@ void ForwardDeclarationNamespaceCheck::check( // struct B { friend A; }; // \endcode // `A` will not be marked as "referenced" in the AST. - if (const TypeSourceInfo *Tsi = Decl->getFriendType()) { - QualType Desugared = Tsi->getType().getDesugaredType(*Result.Context); - FriendTypes.insert(Desugared.getTypePtr()); - } + if (const TypeSourceInfo *Tsi = Decl->getFriendType()) + FriendTypes.insert( + Tsi->getType()->getCanonicalTypeUnqualified().getTypePtr()); } } @@ -119,7 +118,9 @@ void ForwardDeclarationNamespaceCheck::onEndOfTranslationUnit() { if (CurDecl->hasDefinition() || CurDecl->isReferenced()) { continue; // Skip forward declarations that are used/referenced. } - if (FriendTypes.contains(CurDecl->getTypeForDecl())) { + if (FriendTypes.contains(CurDecl->getASTContext() + .getCanonicalTagType(CurDecl) + ->getTypePtr())) { continue; // Skip forward declarations referenced as friend. } if (CurDecl->getLocation().isMacroID() || diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp index 00e8f7e..10b747e 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp @@ -33,21 +33,17 @@ AST_MATCHER(QualType, isEnableIf) { BaseType = BaseType->getPointeeType().getTypePtr(); } // Case: type parameter dependent (enable_if<is_integral<T>>). - if (const auto *Dependent = BaseType->getAs<DependentNameType>()) { - BaseType = Dependent->getQualifier()->getAsType(); - } + if (const auto *Dependent = BaseType->getAs<DependentNameType>()) + BaseType = Dependent->getQualifier().getAsType(); if (!BaseType) return false; if (CheckTemplate(BaseType->getAs<TemplateSpecializationType>())) return true; // Case: enable_if_t< >. - if (const auto *Elaborated = BaseType->getAs<ElaboratedType>()) { - if (const auto *Q = Elaborated->getQualifier()) - if (const auto *Qualifier = Q->getAsType()) { - if (CheckTemplate(Qualifier->getAs<TemplateSpecializationType>())) { - return true; // Case: enable_if< >::type. - } - } - } + if (const auto *TT = BaseType->getAs<TypedefType>()) + if (NestedNameSpecifier Q = TT->getQualifier(); + Q.getKind() == NestedNameSpecifier::Kind::Type) + if (CheckTemplate(Q.getAsType()->getAs<TemplateSpecializationType>())) + return true; // Case: enable_if< >::type. return false; } AST_MATCHER_P(TemplateTypeParmDecl, hasDefaultArgument, diff --git a/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp index 75f1107..07cd90d 100644 --- a/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/IncorrectEnableIfCheck.cpp @@ -32,13 +32,10 @@ AST_MATCHER_P(TemplateTypeParmDecl, hasUnnamedDefaultArgument, void IncorrectEnableIfCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( templateTypeParmDecl( - hasUnnamedDefaultArgument( - elaboratedTypeLoc( - hasNamedTypeLoc(templateSpecializationTypeLoc( - loc(qualType(hasDeclaration(namedDecl( - hasName("::std::enable_if")))))) - .bind("enable_if_specialization"))) - .bind("elaborated"))) + hasUnnamedDefaultArgument(templateSpecializationTypeLoc( + loc(qualType(hasDeclaration(namedDecl( + hasName("::std::enable_if")))))) + .bind("enable_if_specialization"))) .bind("enable_if"), this); } @@ -46,13 +43,11 @@ void IncorrectEnableIfCheck::registerMatchers(MatchFinder *Finder) { void IncorrectEnableIfCheck::check(const MatchFinder::MatchResult &Result) { const auto *EnableIf = Result.Nodes.getNodeAs<TemplateTypeParmDecl>("enable_if"); - const auto *ElaboratedLoc = - Result.Nodes.getNodeAs<ElaboratedTypeLoc>("elaborated"); const auto *EnableIfSpecializationLoc = Result.Nodes.getNodeAs<TemplateSpecializationTypeLoc>( "enable_if_specialization"); - if (!EnableIf || !ElaboratedLoc || !EnableIfSpecializationLoc) + if (!EnableIf || !EnableIfSpecializationLoc) return; const SourceManager &SM = *Result.SourceManager; @@ -62,8 +57,10 @@ void IncorrectEnableIfCheck::check(const MatchFinder::MatchResult &Result) { auto Diag = diag(EnableIf->getBeginLoc(), "incorrect std::enable_if usage detected; use " "'typename std::enable_if<...>::type'"); + // FIXME: This should handle the enable_if specialization already having an + // elaborated keyword. if (!getLangOpts().CPlusPlus20) { - Diag << FixItHint::CreateInsertion(ElaboratedLoc->getBeginLoc(), + Diag << FixItHint::CreateInsertion(EnableIfSpecializationLoc->getBeginLoc(), "typename "); } Diag << FixItHint::CreateInsertion(RAngleLoc.getLocWithOffset(1), "::type"); diff --git a/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp index f903e63..7d92ef3 100644 --- a/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp @@ -67,15 +67,15 @@ public: return Visit(T->getElementType().getTypePtr()); } bool VisitEnumType(const EnumType *T) { - if (isCompleteAndHasNoZeroValue(T->getDecl())) { + if (isCompleteAndHasNoZeroValue(T->getOriginalDecl())) { FoundEnum = T; return true; } return false; } bool VisitRecordType(const RecordType *T) { - const RecordDecl *RD = T->getDecl(); - if (RD->isUnion()) + const RecordDecl *RD = T->getOriginalDecl()->getDefinition(); + if (!RD || RD->isUnion()) return false; auto VisitField = [this](const FieldDecl *F) { return Visit(F->getType().getTypePtr()); @@ -125,7 +125,7 @@ void InvalidEnumDefaultInitializationCheck::check( if (!Finder.Visit(InitList->getArrayFiller()->getType().getTypePtr())) return; InitExpr = InitList; - Enum = Finder.FoundEnum->getDecl(); + Enum = Finder.FoundEnum->getOriginalDecl(); } if (!InitExpr || !Enum) diff --git a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp index bfa2ab5..5dc988d 100644 --- a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp @@ -39,24 +39,31 @@ static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee, // std::move(). This will hopefully prevent erroneous replacements if the // code does unusual things (e.g. create an alias for std::move() in // another namespace). - NestedNameSpecifier *NNS = Callee->getQualifier(); - if (!NNS) { + NestedNameSpecifier NNS = Callee->getQualifier(); + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Null: // Called as "move" (i.e. presumably the code had a "using std::move;"). // We still conservatively put a "std::" in front of the forward because // we don't know whether the code also had a "using std::forward;". Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName); - } else if (const NamespaceBaseDecl *Namespace = NNS->getAsNamespace()) { + break; + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix(); if (Namespace->getName() == "std") { - if (!NNS->getPrefix()) { + if (!Prefix) { // Called as "std::move". Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName); - } else if (NNS->getPrefix()->getKind() == NestedNameSpecifier::Global) { + } else if (Prefix.getKind() == NestedNameSpecifier::Kind::Global) { // Called as "::std::move". Diag << FixItHint::CreateReplacement(CallRange, "::std::" + ForwardName); } } + break; + } + default: + return; } } } diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp index 88e048e6..8da6227 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp @@ -425,7 +425,7 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) { "suspicious usage of 'sizeof(array)/sizeof(...)';" " denominator differs from the size of array elements") << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (NumTy && DenomTy && NumTy == DenomTy && + } else if (NumTy && DenomTy && Ctx.hasSameType(NumTy, DenomTy) && !NumTy->isDependentType()) { // Dependent type should not be compared. diag(E->getOperatorLoc(), @@ -434,7 +434,7 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) { << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } else if (!WarnOnSizeOfPointer) { // When 'WarnOnSizeOfPointer' is enabled, these messages become redundant: - if (PointedTy && DenomTy && PointedTy == DenomTy) { + if (PointedTy && DenomTy && Ctx.hasSameType(PointedTy, DenomTy)) { diag(E->getOperatorLoc(), "suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer " "is divided by size of pointed type") @@ -463,7 +463,8 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) { const auto *SizeOfExpr = Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-mul-expr"); - if ((LPtrTy == RPtrTy) && (LPtrTy == SizeofArgTy)) { + if (Ctx.hasSameType(LPtrTy, RPtrTy) && + Ctx.hasSameType(LPtrTy, SizeofArgTy)) { diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in " "pointer arithmetic") << SizeOfExpr->getSourceRange() << E->getOperatorLoc() @@ -477,7 +478,8 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) { const auto *SizeOfExpr = Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-div-expr"); - if ((LPtrTy == RPtrTy) && (LPtrTy == SizeofArgTy)) { + if (Ctx.hasSameType(LPtrTy, RPtrTy) && + Ctx.hasSameType(LPtrTy, SizeofArgTy)) { diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in " "pointer arithmetic") << SizeOfExpr->getSourceRange() << E->getOperatorLoc() diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/NoSuspendWithLockCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/NoSuspendWithLockCheck.cpp index ca29317..29470b1 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/NoSuspendWithLockCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/NoSuspendWithLockCheck.cpp @@ -23,9 +23,9 @@ void NoSuspendWithLockCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { } void NoSuspendWithLockCheck::registerMatchers(MatchFinder *Finder) { - auto LockType = elaboratedType(namesType(templateSpecializationType( + auto LockType = templateSpecializationType( hasDeclaration(namedDecl(matchers::matchesAnyListedName( - utils::options::parseStringList(LockGuards))))))); + utils::options::parseStringList(LockGuards))))); StatementMatcher Lock = declStmt(has(varDecl(hasType(LockType)).bind("lock-decl"))) diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp index b413b12..4060759 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp @@ -190,7 +190,7 @@ struct InitializerInsertion { // Convenience utility to get a RecordDecl from a QualType. const RecordDecl *getCanonicalRecordDecl(const QualType &Type) { if (const auto *RT = Type.getCanonicalType()->getAs<RecordType>()) - return RT->getDecl(); + return RT->getOriginalDecl(); return nullptr; } diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp index 7675439..40fd15c 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp @@ -92,7 +92,7 @@ void SlicingCheck::diagnoseSlicedOverriddenMethods( for (const auto &Base : DerivedDecl.bases()) { if (const auto *BaseRecordType = Base.getType()->getAs<RecordType>()) { if (const auto *BaseRecord = cast_or_null<CXXRecordDecl>( - BaseRecordType->getDecl()->getDefinition())) + BaseRecordType->getOriginalDecl()->getDefinition())) diagnoseSlicedOverriddenMethods(Call, *BaseRecord, BaseDecl); } } diff --git a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp index 80ff97a..0302a5a 100644 --- a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp +++ b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp @@ -74,7 +74,7 @@ bool MultipleInheritanceCheck::isInterface(const CXXRecordDecl *Node) { const auto *Ty = I.getType()->getAs<RecordType>(); if (!Ty) continue; - const RecordDecl *D = Ty->getDecl()->getDefinition(); + const RecordDecl *D = Ty->getOriginalDecl()->getDefinition(); if (!D) continue; const auto *Base = cast<CXXRecordDecl>(D); @@ -106,7 +106,8 @@ void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) { const auto *Ty = I.getType()->getAs<RecordType>(); if (!Ty) continue; - const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition()); + const auto *Base = + cast<CXXRecordDecl>(Ty->getOriginalDecl()->getDefinition()); if (!isInterface(Base)) NumConcrete++; } @@ -117,7 +118,8 @@ void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) { const auto *Ty = V.getType()->getAs<RecordType>(); if (!Ty) continue; - const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition()); + const auto *Base = + cast<CXXRecordDecl>(Ty->getOriginalDecl()->getDefinition()); if (!isInterface(Base)) NumConcrete++; } diff --git a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp index e076b39..14e11eb 100644 --- a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp +++ b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp @@ -89,6 +89,30 @@ static StringRef getDestTypeString(const SourceManager &SM, SM, LangOpts); } +static bool sameTypeAsWritten(QualType X, QualType Y) { + if (X.getCanonicalType() != Y.getCanonicalType()) + return false; + + auto TC = X->getTypeClass(); + if (TC != Y->getTypeClass()) + return false; + + switch (TC) { + case Type::Typedef: + return declaresSameEntity(cast<TypedefType>(X)->getDecl(), + cast<TypedefType>(Y)->getDecl()); + case Type::Pointer: + return sameTypeAsWritten(cast<PointerType>(X)->getPointeeType(), + cast<PointerType>(Y)->getPointeeType()); + case Type::RValueReference: + case Type::LValueReference: + return sameTypeAsWritten(cast<ReferenceType>(X)->getPointeeType(), + cast<ReferenceType>(Y)->getPointeeType()); + default: + return true; + } +} + void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) { const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast"); @@ -128,12 +152,7 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) { // case of overloaded functions, so detection of redundant casts is trickier // in this case. Don't emit "redundant cast" warnings for function // pointer/reference types. - QualType Src = SourceTypeAsWritten, Dst = DestTypeAsWritten; - if (const auto *ElTy = dyn_cast<ElaboratedType>(Src)) - Src = ElTy->getNamedType(); - if (const auto *ElTy = dyn_cast<ElaboratedType>(Dst)) - Dst = ElTy->getNamedType(); - if (Src == Dst) { + if (sameTypeAsWritten(SourceTypeAsWritten, DestTypeAsWritten)) { diag(CastExpr->getBeginLoc(), "redundant cast to the same type") << FixItHint::CreateRemoval(ReplaceRange); return; diff --git a/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp b/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp index 3deea06..68233ec 100644 --- a/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp +++ b/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp @@ -72,7 +72,7 @@ static bool isStdInitializerList(QualType Type) { } if (const auto *RT = Type->getAs<RecordType>()) { if (const auto *Specialization = - dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl())) + dyn_cast<ClassTemplateSpecializationDecl>(RT->getOriginalDecl())) return declIsStdInitializerList(Specialization->getSpecializedTemplate()); } return false; diff --git a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp b/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp index 805dcaf..274b8af 100644 --- a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp +++ b/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp @@ -257,8 +257,13 @@ getAliasNameRange(const MatchFinder::MatchResult &Result) { return CharSourceRange::getTokenRange( Using->getNameInfo().getSourceRange()); } - return CharSourceRange::getTokenRange( - Result.Nodes.getNodeAs<TypeLoc>("typeloc")->getSourceRange()); + TypeLoc TL = *Result.Nodes.getNodeAs<TypeLoc>("typeloc"); + if (auto QTL = TL.getAs<QualifiedTypeLoc>()) + TL = QTL.getUnqualifiedLoc(); + + if (auto TTL = TL.getAs<TypedefTypeLoc>()) + return CharSourceRange::getTokenRange(TTL.getNameLoc()); + return CharSourceRange::getTokenRange(TL.castAs<UsingTypeLoc>().getNameLoc()); } void UpgradeGoogletestCaseCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp index 697398a..b32507d 100644 --- a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp @@ -98,11 +98,12 @@ void ConstCorrectnessCheck::registerMatchers(MatchFinder *Finder) { hasType(referenceType(pointee(hasCanonicalType(templateTypeParmType())))), hasType(referenceType(pointee(substTemplateTypeParmType())))); - const auto AllowedType = hasType(qualType(anyOf( - hasDeclaration(namedDecl(matchers::matchesAnyListedName(AllowedTypes))), - references(namedDecl(matchers::matchesAnyListedName(AllowedTypes))), - pointerType(pointee(hasDeclaration( - namedDecl(matchers::matchesAnyListedName(AllowedTypes)))))))); + auto AllowedTypeDecl = namedDecl( + anyOf(matchers::matchesAnyListedName(AllowedTypes), usingShadowDecl())); + + const auto AllowedType = hasType(qualType( + anyOf(hasDeclaration(AllowedTypeDecl), references(AllowedTypeDecl), + pointerType(pointee(hasDeclaration(AllowedTypeDecl)))))); const auto AutoTemplateType = varDecl( anyOf(hasType(autoType()), hasType(referenceType(pointee(autoType()))), diff --git a/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp b/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp index 0cdd48c..bb64a56 100644 --- a/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp @@ -19,13 +19,13 @@ void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) { pointee(anyOf(isConstQualified(), ignoringParens(functionType())))))); Finder->addMatcher( - valueDecl(hasType(qualType( - isConstQualified(), - elaboratedType(namesType(typedefType(hasDeclaration( - anyOf(typedefDecl(NonConstAndNonFunctionPointerType) - .bind("typedef"), - typeAliasDecl(NonConstAndNonFunctionPointerType) - .bind("typeAlias"))))))))) + valueDecl( + hasType(qualType(isConstQualified(), + typedefType(hasDeclaration(anyOf( + typedefDecl(NonConstAndNonFunctionPointerType) + .bind("typedef"), + typeAliasDecl(NonConstAndNonFunctionPointerType) + .bind("typeAlias"))))))) .bind("decl"), this); } diff --git a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp index 9b2af2a..107eda2 100644 --- a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp @@ -45,14 +45,6 @@ static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result) { return Value < Result; } -static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left, - const NestedNameSpecifier *Right) { - llvm::FoldingSetNodeID LeftID, RightID; - Left->Profile(LeftID); - Right->Profile(RightID); - return LeftID == RightID; -} - static bool areEquivalentExpr(const Expr *Left, const Expr *Right) { if (!Left || !Right) return !Left && !Right; @@ -104,9 +96,8 @@ static bool areEquivalentExpr(const Expr *Left, const Expr *Right) { if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() != cast<DependentScopeDeclRefExpr>(Right)->getDeclName()) return false; - return areEquivalentNameSpecifier( - cast<DependentScopeDeclRefExpr>(Left)->getQualifier(), - cast<DependentScopeDeclRefExpr>(Right)->getQualifier()); + return cast<DependentScopeDeclRefExpr>(Left)->getQualifier() == + cast<DependentScopeDeclRefExpr>(Right)->getQualifier(); case Stmt::DeclRefExprClass: return cast<DeclRefExpr>(Left)->getDecl() == cast<DeclRefExpr>(Right)->getDecl(); diff --git a/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp index 86992cd..4fa679a 100644 --- a/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp @@ -35,12 +35,12 @@ void UnusedAliasDeclsCheck::check(const MatchFinder::MatchResult &Result) { } if (const auto *NestedName = - Result.Nodes.getNodeAs<NestedNameSpecifier>("nns")) { - if (const auto *AliasDecl = dyn_cast_if_present<NamespaceAliasDecl>( - NestedName->getAsNamespace())) { + Result.Nodes.getNodeAs<NestedNameSpecifier>("nns"); + NestedName && + NestedName->getKind() == NestedNameSpecifier::Kind::Namespace) + if (const auto *AliasDecl = dyn_cast<NamespaceAliasDecl>( + NestedName->getAsNamespaceAndPrefix().Namespace)) FoundDecls[AliasDecl] = CharSourceRange(); - } - } } void UnusedAliasDeclsCheck::onEndOfTranslationUnit() { diff --git a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp index d5c5fa3..8211a0e 100644 --- a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp @@ -71,11 +71,7 @@ void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) { templateArgument().bind("used")))), this); Finder->addMatcher(userDefinedLiteral().bind("used"), this); - Finder->addMatcher( - loc(elaboratedType(unless(hasQualifier(nestedNameSpecifier())), - hasUnqualifiedDesugaredType( - type(asTagDecl(tagDecl().bind("used")))))), - this); + Finder->addMatcher(loc(asTagDecl(tagDecl().bind("used"))), this); // Cases where we can identify the UsingShadowDecl directly, rather than // just its target. // FIXME: cover more cases in this way, as the AST supports it. @@ -136,7 +132,7 @@ void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) { } if (const auto *ECD = dyn_cast<EnumConstantDecl>(Used)) { if (const auto *ET = ECD->getType()->getAs<EnumType>()) - removeFromFoundDecls(ET->getDecl()); + removeFromFoundDecls(ET->getOriginalDecl()); } }; // We rely on the fact that the clang AST is walked in order, usages are only diff --git a/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp index f22f48d..2aca610 100644 --- a/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/DeprecatedIosBaseAliasesCheck.cpp @@ -29,8 +29,7 @@ static std::optional<const char *> getReplacementType(StringRef Type) { void DeprecatedIosBaseAliasesCheck::registerMatchers(MatchFinder *Finder) { auto IoStateDecl = typedefDecl(hasAnyName(DeprecatedTypes)).bind("TypeDecl"); - auto IoStateType = - qualType(hasDeclaration(IoStateDecl), unless(elaboratedType())); + auto IoStateType = typedefType(hasDeclaration(IoStateDecl)); Finder->addMatcher(typeLoc(loc(IoStateType)).bind("TypeLoc"), this); } @@ -43,12 +42,14 @@ void DeprecatedIosBaseAliasesCheck::check( StringRef TypeName = Typedef->getName(); auto Replacement = getReplacementType(TypeName); - const auto *TL = Result.Nodes.getNodeAs<TypeLoc>("TypeLoc"); - SourceLocation IoStateLoc = TL->getBeginLoc(); + TypeLoc TL = *Result.Nodes.getNodeAs<TypeLoc>("TypeLoc"); + if (auto QTL = TL.getAs<QualifiedTypeLoc>()) + TL = QTL.getUnqualifiedLoc(); + SourceLocation IoStateLoc = TL.castAs<TypedefTypeLoc>().getNameLoc(); // Do not generate fixits for matches depending on template arguments and // macro expansions. - bool Fix = Replacement && !TL->getType()->isDependentType(); + bool Fix = Replacement && !TL.getType()->isDependentType(); if (IoStateLoc.isMacroID()) { IoStateLoc = SM.getSpellingLoc(IoStateLoc); Fix = false; diff --git a/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp index 1e271dfa..a54d072 100644 --- a/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp @@ -77,8 +77,7 @@ AST_MATCHER_P(CXXRecordDecl, isMoveConstructibleInBoundCXXRecordDecl, StringRef, static TypeMatcher notTemplateSpecConstRefType() { return lValueReferenceType( - pointee(unless(elaboratedType(namesType(templateSpecializationType()))), - isConstQualified())); + pointee(unless(templateSpecializationType()), isConstQualified())); } static TypeMatcher nonConstValueType() { diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp index 1ad31d3..f2142b8 100644 --- a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp @@ -48,7 +48,7 @@ void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) { auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isInStdNamespace()); - auto AutoPtrType = qualType(hasDeclaration(AutoPtrDecl)); + auto AutoPtrType = hasCanonicalType(recordType(hasDeclaration(AutoPtrDecl))); // std::auto_ptr<int> a; // ^~~~~~~~~~~~~ @@ -58,11 +58,7 @@ void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) { // // std::auto_ptr<int> fn(std::auto_ptr<int>); // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~ - Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType, - // Skip elaboratedType() as the named - // type will match soon thereafter. - unless(elaboratedType())))) - .bind(AutoPtrTokenId), + Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType))).bind(AutoPtrTokenId), this); // using std::auto_ptr; @@ -118,10 +114,13 @@ void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) { } SourceLocation AutoPtrLoc; - if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) { + if (const auto *PTL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) { + auto TL = *PTL; + if (auto QTL = TL.getAs<QualifiedTypeLoc>()) + TL = QTL.getUnqualifiedLoc(); // std::auto_ptr<int> i; // ^ - if (auto Loc = TL->getAs<TemplateSpecializationTypeLoc>()) + if (auto Loc = TL.getAs<TemplateSpecializationTypeLoc>()) AutoPtrLoc = Loc.getTemplateNameLoc(); } else if (const auto *D = Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) { diff --git a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp index ff0b321..de2d42d 100644 --- a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp @@ -168,19 +168,6 @@ static DeclarationName getName(const DeclRefExpr &D) { return D.getDecl()->getDeclName(); } -static bool isNamedType(const ElaboratedTypeLoc &ETL) { - if (const auto *TFT = - ETL.getNamedTypeLoc().getTypePtr()->getAs<TypedefType>()) { - const TypedefNameDecl *Decl = TFT->getDecl(); - return Decl->getDeclName().isIdentifier() && Decl->getName() == "type"; - } - return false; -} - -static bool isNamedType(const DependentNameTypeLoc &DTL) { - return DTL.getTypePtr()->getIdentifier()->getName() == "type"; -} - namespace { AST_POLYMORPHIC_MATCHER(isValue, AST_POLYMORPHIC_SUPPORTED_TYPES( DeclRefExpr, DependentScopeDeclRefExpr)) { @@ -188,10 +175,14 @@ AST_POLYMORPHIC_MATCHER(isValue, AST_POLYMORPHIC_SUPPORTED_TYPES( return Ident && Ident->isStr("value"); } -AST_POLYMORPHIC_MATCHER(isType, - AST_POLYMORPHIC_SUPPORTED_TYPES(ElaboratedTypeLoc, - DependentNameTypeLoc)) { - return Node.getBeginLoc().isValid() && isNamedType(Node); +AST_MATCHER(TypeLoc, isType) { + if (auto TL = Node.getAs<TypedefTypeLoc>()) { + const auto *TD = TL.getDecl(); + return TD->getDeclName().isIdentifier() && TD->getName() == "type"; + } + if (auto TL = Node.getAs<DependentNameTypeLoc>()) + return TL.getTypePtr()->getIdentifier()->getName() == "type"; + return false; } } // namespace @@ -214,10 +205,7 @@ void TypeTraitsCheck::registerMatchers(MatchFinder *Finder) { .bind(Bind), this); } - Finder->addMatcher(mapAnyOf(elaboratedTypeLoc, dependentNameTypeLoc) - .with(isType()) - .bind(Bind), - this); + Finder->addMatcher(typeLoc(isType()).bind(Bind), this); } static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND, @@ -226,14 +214,11 @@ static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND, Set.contains(ND->getName()); } -static bool checkTemplatedDecl(const NestedNameSpecifier *NNS, +static bool checkTemplatedDecl(NestedNameSpecifier NNS, const llvm::StringSet<> &Set) { - if (!NNS) + if (NNS.getKind() != NestedNameSpecifier::Kind::Type) return false; - const Type *NNST = NNS->getAsType(); - if (!NNST) - return false; - const auto *TST = NNST->getAs<TemplateSpecializationType>(); + const auto *TST = NNS.getAsType()->getAs<TemplateSpecializationType>(); if (!TST) return false; if (const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl()) { @@ -250,8 +235,8 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) { auto EmitValueWarning = [this, &Result](const NestedNameSpecifierLoc &QualLoc, SourceLocation EndLoc) { SourceLocation TemplateNameEndLoc; - if (auto TSTL = QualLoc.getTypeLoc().getAs<TemplateSpecializationTypeLoc>(); - !TSTL.isNull()) + if (auto TSTL = + QualLoc.getAsTypeLoc().getAs<TemplateSpecializationTypeLoc>()) TemplateNameEndLoc = Lexer::getLocForEndOfToken( TSTL.getTemplateNameLoc(), 0, *Result.SourceManager, Result.Context->getLangOpts()); @@ -274,8 +259,8 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) { SourceLocation EndLoc, SourceLocation TypenameLoc) { SourceLocation TemplateNameEndLoc; - if (auto TSTL = QualLoc.getTypeLoc().getAs<TemplateSpecializationTypeLoc>(); - !TSTL.isNull()) + if (auto TSTL = + QualLoc.getAsTypeLoc().getAs<TemplateSpecializationTypeLoc>()) TemplateNameEndLoc = Lexer::getLocForEndOfToken( TSTL.getTemplateNameLoc(), 0, *Result.SourceManager, Result.Context->getLangOpts()); @@ -301,23 +286,21 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) { if (!DRE->hasQualifier()) return; if (const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>( - DRE->getQualifier()->getAsRecordDecl())) { + DRE->getQualifier().getAsRecordDecl())) { if (isNamedDeclInStdTraitsSet(CTSD, ValueTraits)) EmitValueWarning(DRE->getQualifierLoc(), DRE->getEndLoc()); } return; } - if (const auto *ETL = Result.Nodes.getNodeAs<ElaboratedTypeLoc>(Bind)) { - const NestedNameSpecifierLoc QualLoc = ETL->getQualifierLoc(); - const auto *NNS = QualLoc.getNestedNameSpecifier(); - if (!NNS) - return; + if (const auto *TL = Result.Nodes.getNodeAs<TypedefTypeLoc>(Bind)) { + const NestedNameSpecifierLoc QualLoc = TL->getQualifierLoc(); + NestedNameSpecifier NNS = QualLoc.getNestedNameSpecifier(); if (const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>( - NNS->getAsRecordDecl())) { + NNS.getAsRecordDecl())) { if (isNamedDeclInStdTraitsSet(CTSD, TypeTraits)) - EmitTypeWarning(ETL->getQualifierLoc(), ETL->getEndLoc(), - ETL->getElaboratedKeywordLoc()); + EmitTypeWarning(TL->getQualifierLoc(), TL->getEndLoc(), + TL->getElaboratedKeywordLoc()); } return; } diff --git a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp index f4b6308..b601620 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp @@ -186,16 +186,14 @@ TypeMatcher nestedIterator() { /// declarations and which name standard iterators for standard containers. TypeMatcher iteratorFromUsingDeclaration() { auto HasIteratorDecl = hasDeclaration(namedDecl(hasStdIteratorName())); - // Types resulting from using declarations are represented by elaboratedType. - return elaboratedType( - // Unwrap the nested name specifier to test for one of the standard - // containers. - hasQualifier(specifiesType(templateSpecializationType(hasDeclaration( - namedDecl(hasStdContainerName(), isInStdNamespace()))))), - // the named type is what comes after the final '::' in the type. It - // should name one of the standard iterator names. - namesType( - anyOf(typedefType(HasIteratorDecl), recordType(HasIteratorDecl)))); + // Unwrap the nested name specifier to test for one of the standard + // containers. + auto Qualifier = hasQualifier(specifiesType(templateSpecializationType( + hasDeclaration(namedDecl(hasStdContainerName(), isInStdNamespace()))))); + // the named type is what comes after the final '::' in the type. It should + // name one of the standard iterator names. + return anyOf(typedefType(HasIteratorDecl, Qualifier), + recordType(HasIteratorDecl, Qualifier)); } /// This matcher returns declaration statements that contain variable diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp index e9b96c4..07274d0 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp @@ -60,9 +60,11 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) { Keyword != ElaboratedTypeKeyword::None)) { return std::nullopt; } - TheType = Dep.getQualifierLoc().getTypeLoc(); + TheType = Dep.getQualifierLoc().getAsTypeLoc(); if (TheType.isNull()) return std::nullopt; + } else { + return std::nullopt; } if (const auto SpecializationLoc = @@ -89,9 +91,6 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) { static std::optional<TemplateSpecializationTypeLoc> matchEnableIfSpecializationImplTrait(TypeLoc TheType) { - if (const auto Elaborated = TheType.getAs<ElaboratedTypeLoc>()) - TheType = Elaborated.getNamedTypeLoc(); - if (const auto SpecializationLoc = TheType.getAs<TemplateSpecializationTypeLoc>()) { diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp index aaf24ea..ee49d8a 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp @@ -164,10 +164,10 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) { auto CallEmplacy = cxxMemberCallExpr( hasDeclaration( functionDecl(hasAnyNameIgnoringTemplates(EmplacyFunctions))), - on(hasTypeOrPointeeType(hasCanonicalType(hasDeclaration( - has(typedefNameDecl(hasName("value_type"), - hasType(type(hasUnqualifiedDesugaredType( - recordType().bind("value_type"))))))))))); + on(hasTypeOrPointeeType( + hasCanonicalType(hasDeclaration(has(typedefNameDecl( + hasName("value_type"), + hasType(hasCanonicalType(recordType().bind("value_type")))))))))); // We can't replace push_backs of smart pointer because // if emplacement fails (f.e. bad_alloc in vector) we will have leak of @@ -241,17 +241,16 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) { auto HasConstructExprWithValueTypeType = has(ignoringImplicit(cxxConstructExpr( - SoughtConstructExpr, hasType(type(hasUnqualifiedDesugaredType( - type(equalsBoundNode("value_type")))))))); - - auto HasBracedInitListWithValueTypeType = - anyOf(allOf(HasConstructInitListExpr, - has(initListExpr(hasType(type(hasUnqualifiedDesugaredType( - type(equalsBoundNode("value_type")))))))), - has(cxxBindTemporaryExpr( - HasConstructInitListExpr, - has(initListExpr(hasType(type(hasUnqualifiedDesugaredType( - type(equalsBoundNode("value_type")))))))))); + SoughtConstructExpr, + hasType(hasCanonicalType(type(equalsBoundNode("value_type"))))))); + + auto HasBracedInitListWithValueTypeType = anyOf( + allOf(HasConstructInitListExpr, + has(initListExpr(hasType( + hasCanonicalType(type(equalsBoundNode("value_type"))))))), + has(cxxBindTemporaryExpr(HasConstructInitListExpr, + has(initListExpr(hasType(hasCanonicalType( + type(equalsBoundNode("value_type"))))))))); auto HasConstructExprWithValueTypeTypeAsLastArgument = hasLastArgument( materializeTemporaryExpr( @@ -289,19 +288,17 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) { this); Finder->addMatcher( - traverse( - TK_AsIs, - cxxMemberCallExpr( - CallEmplacy, - on(hasType(cxxRecordDecl(has(typedefNameDecl( - hasName("value_type"), - hasType(type( - hasUnqualifiedDesugaredType(recordType(hasDeclaration( - cxxRecordDecl(hasAnyName(SmallVector<StringRef, 2>( - TupleTypes.begin(), TupleTypes.end()))))))))))))), - has(MakeTuple), hasSameNumArgsAsDeclNumParams(), - unless(isInTemplateInstantiation())) - .bind("emplacy_call")), + traverse(TK_AsIs, + cxxMemberCallExpr( + CallEmplacy, + on(hasType(cxxRecordDecl(has(typedefNameDecl( + hasName("value_type"), + hasType(hasCanonicalType(recordType(hasDeclaration( + cxxRecordDecl(hasAnyName(SmallVector<StringRef, 2>( + TupleTypes.begin(), TupleTypes.end())))))))))))), + has(MakeTuple), hasSameNumArgsAsDeclNumParams(), + unless(isInTemplateInstantiation())) + .bind("emplacy_call")), this); } diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp index 52e9a9f..5310f2f 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp @@ -29,7 +29,7 @@ static bool isLockGuardDecl(const NamedDecl *Decl) { static bool isLockGuard(const QualType &Type) { if (const auto *Record = Type->getAs<RecordType>()) - if (const RecordDecl *Decl = Record->getDecl()) + if (const RecordDecl *Decl = Record->getOriginalDecl()) return isLockGuardDecl(Decl); if (const auto *TemplateSpecType = Type->getAs<TemplateSpecializationType>()) @@ -89,17 +89,6 @@ findLocksInCompoundStmt(const CompoundStmt *Block, return LockGuardGroups; } -static TemplateSpecializationTypeLoc -getTemplateLockGuardTypeLoc(const TypeSourceInfo *SourceInfo) { - const TypeLoc Loc = SourceInfo->getTypeLoc(); - - const auto ElaboratedLoc = Loc.getAs<ElaboratedTypeLoc>(); - if (!ElaboratedLoc) - return {}; - - return ElaboratedLoc.getNamedTypeLoc().getAs<TemplateSpecializationTypeLoc>(); -} - // Find the exact source range of the 'lock_guard' token static SourceRange getLockGuardRange(const TypeSourceInfo *SourceInfo) { const TypeLoc LockGuardTypeLoc = SourceInfo->getTypeLoc(); @@ -110,7 +99,7 @@ static SourceRange getLockGuardRange(const TypeSourceInfo *SourceInfo) { // Find the exact source range of the 'lock_guard' name token static SourceRange getLockGuardNameRange(const TypeSourceInfo *SourceInfo) { const TemplateSpecializationTypeLoc TemplateLoc = - getTemplateLockGuardTypeLoc(SourceInfo); + SourceInfo->getTypeLoc().getAs<TemplateSpecializationTypeLoc>(); if (!TemplateLoc) return {}; @@ -136,11 +125,11 @@ void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) { const auto LockGuardClassDecl = namedDecl(hasName("lock_guard"), isInStdNamespace()); - const auto LockGuardType = qualType(anyOf( - hasUnqualifiedDesugaredType( - recordType(hasDeclaration(LockGuardClassDecl))), - elaboratedType(namesType(hasUnqualifiedDesugaredType( - templateSpecializationType(hasDeclaration(LockGuardClassDecl))))))); + const auto LockGuardType = + qualType(anyOf(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(LockGuardClassDecl))), + hasUnqualifiedDesugaredType(templateSpecializationType( + hasDeclaration(LockGuardClassDecl))))); const auto LockVarDecl = varDecl(hasType(LockGuardType)); @@ -165,18 +154,16 @@ void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) { if (WarnOnUsingAndTypedef) { // Match 'typedef std::lock_guard<std::mutex> Lock' Finder->addMatcher(typedefDecl(unless(isExpansionInSystemHeader()), - hasUnderlyingType(LockGuardType)) + hasType(hasUnderlyingType(LockGuardType))) .bind("lock-guard-typedef"), this); // Match 'using Lock = std::lock_guard<std::mutex>' - Finder->addMatcher( - typeAliasDecl( - unless(isExpansionInSystemHeader()), - hasType(elaboratedType(namesType(templateSpecializationType( - hasDeclaration(LockGuardClassDecl)))))) - .bind("lock-guard-using-alias"), - this); + Finder->addMatcher(typeAliasDecl(unless(isExpansionInSystemHeader()), + hasType(templateSpecializationType( + hasDeclaration(LockGuardClassDecl)))) + .bind("lock-guard-using-alias"), + this); // Match 'using std::lock_guard' Finder->addMatcher( @@ -288,8 +275,8 @@ void UseScopedLockCheck::diagOnSourceInfo( const ast_matchers::MatchFinder::MatchResult &Result) { const TypeLoc TL = LockGuardSourceInfo->getTypeLoc(); - if (const auto ElaboratedTL = TL.getAs<ElaboratedTypeLoc>()) { - auto Diag = diag(ElaboratedTL.getBeginLoc(), UseScopedLockMessage); + if (const auto TTL = TL.getAs<TemplateSpecializationTypeLoc>()) { + auto Diag = diag(TTL.getBeginLoc(), UseScopedLockMessage); const SourceRange LockGuardRange = getLockGuardNameRange(LockGuardSourceInfo); diff --git a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp index ced4825..82f6409 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp @@ -64,66 +64,65 @@ public: return false; } - bool TraverseTypeLoc(TypeLoc TL, bool Elaborated = false) { + bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) { if (TL.isNull()) return true; - if (!Elaborated) { - switch (TL.getTypeLocClass()) { - case TypeLoc::Record: - if (visitUnqualName( - TL.getAs<RecordTypeLoc>().getTypePtr()->getDecl()->getName())) - return false; + switch (TL.getTypeLocClass()) { + case TypeLoc::InjectedClassName: + case TypeLoc::Record: + case TypeLoc::Enum: { + auto TTL = TL.getAs<TagTypeLoc>(); + const auto *T = TTL.getTypePtr(); + if (T->getKeyword() != ElaboratedTypeKeyword::None || + TTL.getQualifierLoc()) break; - case TypeLoc::Enum: - if (visitUnqualName( - TL.getAs<EnumTypeLoc>().getTypePtr()->getDecl()->getName())) - return false; - break; - case TypeLoc::TemplateSpecialization: - if (visitUnqualName(TL.getAs<TemplateSpecializationTypeLoc>() - .getTypePtr() - ->getTemplateName() - .getAsTemplateDecl() - ->getName())) - return false; - break; - case TypeLoc::Typedef: - if (visitUnqualName( - TL.getAs<TypedefTypeLoc>().getTypePtr()->getDecl()->getName())) - return false; + if (visitUnqualName(T->getOriginalDecl()->getName())) + return false; + break; + } + case TypeLoc::TemplateSpecialization: { + auto TTL = TL.getAs<TemplateSpecializationTypeLoc>(); + const auto *T = TTL.getTypePtr(); + if (T->getKeyword() != ElaboratedTypeKeyword::None || + TTL.getQualifierLoc()) break; - case TypeLoc::Using: - if (visitUnqualName(TL.getAs<UsingTypeLoc>() - .getTypePtr() - ->getFoundDecl() - ->getName())) - return false; + if (visitUnqualName(T->getTemplateName().getAsTemplateDecl()->getName())) + return false; + break; + } + case TypeLoc::Typedef: { + auto TTL = TL.getAs<TypedefTypeLoc>(); + const auto *T = TTL.getTypePtr(); + if (T->getKeyword() != ElaboratedTypeKeyword::None || + TTL.getQualifierLoc()) break; - default: + if (visitUnqualName(T->getDecl()->getName())) + return false; + break; + } + case TypeLoc::Using: { + auto TTL = TL.getAs<UsingTypeLoc>(); + const auto *T = TTL.getTypePtr(); + if (T->getKeyword() != ElaboratedTypeKeyword::None || + TTL.getQualifierLoc()) break; - } + if (visitUnqualName(T->getDecl()->getName())) + return false; + break; + } + default: + break; } - return RecursiveASTVisitor<UnqualNameVisitor>::TraverseTypeLoc(TL); + return RecursiveASTVisitor<UnqualNameVisitor>::TraverseTypeLoc( + TL, TraverseQualifier); } // Replace the base method in order to call our own // TraverseTypeLoc(). - bool TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) { - return TraverseTypeLoc(TL.getUnqualifiedLoc()); - } - - // Replace the base version to inform TraverseTypeLoc that the type is - // elaborated. - bool TraverseElaboratedTypeLoc(ElaboratedTypeLoc TL) { - if (TL.getQualifierLoc() && - !TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())) - return false; - const auto *T = TL.getTypePtr(); - return TraverseTypeLoc(TL.getNamedTypeLoc(), - T->getKeyword() != ElaboratedTypeKeyword::None || - T->getQualifier()); + bool TraverseQualifiedTypeLoc(QualifiedTypeLoc TL, bool TraverseQualifier) { + return TraverseTypeLoc(TL.getUnqualifiedLoc(), TraverseQualifier); } bool VisitDeclRefExpr(DeclRefExpr *S) { diff --git a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp index a053c07..2373a26 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp @@ -37,15 +37,13 @@ void UseTransparentFunctorsCheck::registerMatchers(MatchFinder *Finder) { // Non-transparent functor mentioned as a template parameter. FIXIT. Finder->addMatcher( - loc(qualType( - unless(elaboratedType()), - hasDeclaration(classTemplateSpecializationDecl( - unless(hasAnyTemplateArgument(templateArgument(refersToType( - qualType(pointsTo(qualType(isAnyCharacter()))))))), - hasAnyTemplateArgument( - templateArgument(refersToType(qualType(hasDeclaration( - TransparentFunctors)))) - .bind("Functor")))))) + loc(qualType(hasDeclaration(classTemplateSpecializationDecl( + unless(hasAnyTemplateArgument(templateArgument(refersToType( + qualType(pointsTo(qualType(isAnyCharacter()))))))), + hasAnyTemplateArgument( + templateArgument(refersToType(qualType( + hasDeclaration(TransparentFunctors)))) + .bind("Functor")))))) .bind("FunctorParentLoc"), this); diff --git a/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp index 7022e9d..1c01899 100644 --- a/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp @@ -42,11 +42,11 @@ void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) { // A matcher for a `DstT::DstT(const Src&)` where DstT also has a // `DstT::DstT(Src&&)`. const auto LValueRefCtor = cxxConstructorDecl( - hasParameter(0, - hasType(lValueReferenceType(pointee(type().bind("SrcT"))))), + hasParameter(0, hasType(hasCanonicalType( + lValueReferenceType(pointee(type().bind("SrcT")))))), ofClass(cxxRecordDecl(hasMethod(cxxConstructorDecl( - hasParameter(0, hasType(rValueReferenceType( - pointee(type(equalsBoundNode("SrcT"))))))))))); + hasParameter(0, hasType(hasCanonicalType(rValueReferenceType( + pointee(type(equalsBoundNode("SrcT")))))))))))); // A matcher for `DstT::DstT(const Src&&)`, which typically comes from an // instantiation of `template <typename U> DstT::DstT(U&&)`. diff --git a/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.cpp b/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.cpp index 3b4d65b..5a3c9a4 100644 --- a/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/StdAllocatorConstCheck.cpp @@ -15,10 +15,11 @@ namespace clang::tidy::portability { void StdAllocatorConstCheck::registerMatchers(MatchFinder *Finder) { // Match std::allocator<const T>. - auto AllocatorConst = + auto AllocatorConst = qualType(hasCanonicalType( recordType(hasDeclaration(classTemplateSpecializationDecl( hasName("::std::allocator"), - hasTemplateArgument(0, refersToType(qualType(isConstQualified())))))); + hasTemplateArgument(0, + refersToType(qualType(isConstQualified())))))))); auto HasContainerName = hasAnyName("::std::vector", "::std::deque", "::std::list", @@ -31,8 +32,10 @@ void StdAllocatorConstCheck::registerMatchers(MatchFinder *Finder) { // aren't caught. Finder->addMatcher( typeLoc( - templateSpecializationTypeLoc(), - loc(hasUnqualifiedDesugaredType(anyOf( + anyOf(templateSpecializationTypeLoc(), + qualifiedTypeLoc( + hasUnqualifiedLoc(templateSpecializationTypeLoc()))), + loc(qualType(anyOf( recordType(hasDeclaration(classTemplateSpecializationDecl( HasContainerName, anyOf( diff --git a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp index ce736a8..c4dc319 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp @@ -238,9 +238,12 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) { ? MemberCallObject : (Pointee ? Pointee : Result.Nodes.getNodeAs<Expr>("STLObject")); FixItHint Hint; - std::string ReplacementText = std::string( - Lexer::getSourceText(CharSourceRange::getTokenRange(E->getSourceRange()), - *Result.SourceManager, getLangOpts())); + std::string ReplacementText = + E->isImplicitCXXThis() + ? "" + : std::string(Lexer::getSourceText( + CharSourceRange::getTokenRange(E->getSourceRange()), + *Result.SourceManager, getLangOpts())); const auto *OpCallExpr = dyn_cast<CXXOperatorCallExpr>(E); if (isBinaryOrTernary(E) || isa<UnaryOperator>(E) || (OpCallExpr && (OpCallExpr->getOperator() == OO_Star))) { @@ -251,6 +254,8 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) { // This can happen if the object is a smart pointer. Don't add anything // because a '->' is already there (PR#51776), just call the method. ReplacementText += "empty()"; + } else if (E->isImplicitCXXThis()) { + ReplacementText += "empty()"; } else if (E->getType()->isPointerType()) ReplacementText += "->empty()"; else diff --git a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp index fffb136..a7b3c4a 100644 --- a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp @@ -19,19 +19,25 @@ namespace { AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); } } // namespace -static unsigned getNameSpecifierNestingLevel(const QualType &QType) { - if (const auto *ElType = QType->getAs<ElaboratedType>()) { - if (const NestedNameSpecifier *NestedSpecifiers = ElType->getQualifier()) { - unsigned NameSpecifierNestingLevel = 1; - do { - NameSpecifierNestingLevel++; - NestedSpecifiers = NestedSpecifiers->getPrefix(); - } while (NestedSpecifiers); - +static unsigned getNameSpecifierNestingLevel(QualType QType) { + unsigned NameSpecifierNestingLevel = 1; + for (NestedNameSpecifier Qualifier = QType->getPrefix(); /**/; + ++NameSpecifierNestingLevel) { + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: return NameSpecifierNestingLevel; + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: + return NameSpecifierNestingLevel + 1; + case NestedNameSpecifier::Kind::Namespace: + Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix; + continue; + case NestedNameSpecifier::Kind::Type: + Qualifier = Qualifier.getAsType()->getPrefix(); + continue; } + llvm_unreachable("unhandled nested name specifier kind"); } - return 0; } void StaticAccessedThroughInstanceCheck::storeOptions( diff --git a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp index 5a04029..447c243 100644 --- a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp @@ -414,9 +414,9 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType, // Arithmetic types are interconvertible, except scoped enums. if (ParamType->isArithmeticType() && ArgType->isArithmeticType()) { if ((ParamType->isEnumeralType() && - ParamType->castAs<EnumType>()->getDecl()->isScoped()) || + ParamType->castAs<EnumType>()->getOriginalDecl()->isScoped()) || (ArgType->isEnumeralType() && - ArgType->castAs<EnumType>()->getDecl()->isScoped())) + ArgType->castAs<EnumType>()->getOriginalDecl()->isScoped())) return false; return true; diff --git a/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp b/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp index 6f6b8a8..718467e 100644 --- a/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp @@ -67,11 +67,7 @@ static QualType getNonTemplateAlias(QualType QT) { if (!TT->getDecl()->getDescribedTemplate() && !TT->getDecl()->getDeclContext()->isDependentContext()) return QT; - QT = TT->getDecl()->getUnderlyingType(); - } - // cast to elaborated type - else if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(QT)) { - QT = ET->getNamedType(); + QT = TT->desugar(); } else { break; } diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp index 0637d0e..aa6aefc 100644 --- a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp +++ b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp @@ -66,7 +66,8 @@ ExceptionSpecAnalyzer::analyzeBase(const CXXBaseSpecifier &Base, if (!RecType) return State::Unknown; - const auto *BaseClass = cast<CXXRecordDecl>(RecType->getDecl()); + const auto *BaseClass = + cast<CXXRecordDecl>(RecType->getOriginalDecl())->getDefinitionOrSelf(); return analyzeRecord(BaseClass, Kind); } diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp index e1c1bee..0df8e91 100644 --- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp +++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp @@ -461,8 +461,9 @@ bool FormatStringConverter::emitIntegerArgument( // the signedness based on the format string, so we need to do the // same. if (const auto *ET = ArgType->getAs<EnumType>()) { - if (const std::optional<std::string> MaybeCastType = - castTypeForArgument(ArgKind, ET->getDecl()->getIntegerType())) + if (const std::optional<std::string> MaybeCastType = castTypeForArgument( + ArgKind, + ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType())) ArgFixes.emplace_back( ArgIndex, (Twine("static_cast<") + *MaybeCastType + ">(").str()); else diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.cpp b/clang-tools-extra/clang-tidy/utils/Matchers.cpp index 4974a9c..bd7b03e 100644 --- a/clang-tools-extra/clang-tidy/utils/Matchers.cpp +++ b/clang-tools-extra/clang-tidy/utils/Matchers.cpp @@ -34,7 +34,7 @@ bool MatchesAnyListedTypeNameMatcher::matches( PrintingPolicy PrintingPolicyWithSuppressedTag( Finder->getASTContext().getLangOpts()); PrintingPolicyWithSuppressedTag.PrintAsCanonical = CanonicalTypes; - PrintingPolicyWithSuppressedTag.SuppressElaboration = true; + PrintingPolicyWithSuppressedTag.FullyQualifiedName = true; PrintingPolicyWithSuppressedTag.SuppressScope = false; PrintingPolicyWithSuppressedTag.SuppressTagKeyword = true; PrintingPolicyWithSuppressedTag.SuppressUnwrittenScope = true; diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp index eaa04fe..20853dc 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -281,9 +281,10 @@ public: } bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Loc) { - if (const NestedNameSpecifier *Spec = Loc.getNestedNameSpecifier()) { + if (NestedNameSpecifier Spec = Loc.getNestedNameSpecifier(); + Spec.getKind() == NestedNameSpecifier::Kind::Namespace) { if (const auto *Decl = - dyn_cast_if_present<NamespaceDecl>(Spec->getAsNamespace())) + dyn_cast<NamespaceDecl>(Spec.getAsNamespaceAndPrefix().Namespace)) Check->addUsage(Decl, Loc.getLocalSourceRange(), SM); } @@ -323,48 +324,34 @@ public: } bool VisitTypedefTypeLoc(const TypedefTypeLoc &Loc) { - Check->addUsage(Loc.getTypedefNameDecl(), Loc.getSourceRange(), SM); + Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM); return true; } bool VisitTagTypeLoc(const TagTypeLoc &Loc) { - Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM); - return true; - } - - bool VisitInjectedClassNameTypeLoc(const InjectedClassNameTypeLoc &Loc) { - Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM); + Check->addUsage(Loc.getOriginalDecl(), Loc.getNameLoc(), SM); return true; } bool VisitUnresolvedUsingTypeLoc(const UnresolvedUsingTypeLoc &Loc) { - Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM); + Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM); return true; } bool VisitTemplateTypeParmTypeLoc(const TemplateTypeParmTypeLoc &Loc) { - Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM); + Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM); return true; } bool VisitTemplateSpecializationTypeLoc(const TemplateSpecializationTypeLoc &Loc) { const TemplateDecl *Decl = - Loc.getTypePtr()->getTemplateName().getAsTemplateDecl(); + Loc.getTypePtr()->getTemplateName().getAsTemplateDecl( + /*IgnoreDeduced=*/true); - SourceRange Range(Loc.getTemplateNameLoc(), Loc.getTemplateNameLoc()); - if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl)) { + if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl)) if (const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl()) - Check->addUsage(TemplDecl, Range, SM); - } - - return true; - } - - bool VisitDependentTemplateSpecializationTypeLoc( - const DependentTemplateSpecializationTypeLoc &Loc) { - if (const TagDecl *Decl = Loc.getTypePtr()->getAsTagDecl()) - Check->addUsage(Decl, Loc.getSourceRange(), SM); + Check->addUsage(TemplDecl, Loc.getTemplateNameLoc(), SM); return true; } diff --git a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp index 44db0c2..96d3a5b 100644 --- a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp +++ b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp @@ -124,7 +124,8 @@ bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) { return true; if (const auto *RT = CanonicalType->getAs<RecordType>()) { - return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context); + return recordIsTriviallyDefaultConstructible( + *RT->getOriginalDecl()->getDefinitionOrSelf(), Context); } // No other types can match. diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp index f2631e5..82aee4c 100644 --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -102,54 +102,78 @@ getUsingNamespaceDirectives(const DeclContext *DestContext, // ancestor is redundant, therefore we stop at lowest common ancestor. // In addition to that stops early whenever IsVisible returns true. This can be // used to implement support for "using namespace" decls. -std::string -getQualification(ASTContext &Context, const DeclContext *DestContext, - const DeclContext *SourceContext, - llvm::function_ref<bool(NestedNameSpecifier *)> IsVisible) { - std::vector<const NestedNameSpecifier *> Parents; - bool ReachedNS = false; +std::string getQualification(ASTContext &Context, + const DeclContext *DestContext, + const DeclContext *SourceContext, + llvm::function_ref<bool(const Decl *)> IsVisible) { + std::vector<const Decl *> Parents; + [[maybe_unused]] bool ReachedNS = false; for (const DeclContext *CurContext = SourceContext; CurContext; CurContext = CurContext->getLookupParent()) { // Stop once we reach a common ancestor. if (CurContext->Encloses(DestContext)) break; - NestedNameSpecifier *NNS = nullptr; + const Decl *CurD; if (auto *TD = llvm::dyn_cast<TagDecl>(CurContext)) { // There can't be any more tag parents after hitting a namespace. assert(!ReachedNS); - (void)ReachedNS; - NNS = NestedNameSpecifier::Create(Context, nullptr, TD->getTypeForDecl()); + CurD = TD; } else if (auto *NSD = llvm::dyn_cast<NamespaceDecl>(CurContext)) { ReachedNS = true; - NNS = NestedNameSpecifier::Create(Context, nullptr, NSD); // Anonymous and inline namespace names are not spelled while qualifying // a name, so skip those. if (NSD->isAnonymousNamespace() || NSD->isInlineNamespace()) continue; + CurD = NSD; } else { // Other types of contexts cannot be spelled in code, just skip over // them. continue; } // Stop if this namespace is already visible at DestContext. - if (IsVisible(NNS)) + if (IsVisible(CurD)) break; - Parents.push_back(NNS); + Parents.push_back(CurD); + } + + // Go over the declarations in reverse order, since we stored inner-most + // parent first. + NestedNameSpecifier Qualifier = std::nullopt; + bool IsFirst = true; + for (const auto *CurD : llvm::reverse(Parents)) { + if (auto *TD = llvm::dyn_cast<TagDecl>(CurD)) { + QualType T; + if (const auto *RD = dyn_cast<CXXRecordDecl>(TD); + ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) { + ArrayRef<TemplateArgument> Args; + if (const auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) + Args = SD->getTemplateArgs().asArray(); + else + Args = CTD->getTemplateParameters()->getInjectedTemplateArgs(Context); + T = Context.getTemplateSpecializationType( + ElaboratedTypeKeyword::None, + Context.getQualifiedTemplateName( + Qualifier, /*TemplateKeyword=*/!IsFirst, TemplateName(CTD)), + Args, /*CanonicalArgs=*/{}, Context.getCanonicalTagType(RD)); + } else { + T = Context.getTagType(ElaboratedTypeKeyword::None, Qualifier, TD, + /*OwnsTag=*/false); + } + Qualifier = NestedNameSpecifier(T.getTypePtr()); + } else { + Qualifier = + NestedNameSpecifier(Context, cast<NamespaceDecl>(CurD), Qualifier); + } + IsFirst = false; } + if (!Qualifier) + return ""; - // Go over name-specifiers in reverse order to create necessary qualification, - // since we stored inner-most parent first. std::string Result; llvm::raw_string_ostream OS(Result); - for (const auto *Parent : llvm::reverse(Parents)) { - if (Parent != *Parents.rbegin() && Parent->isDependent() && - Parent->getAsRecordDecl() && - Parent->getAsRecordDecl()->getDescribedClassTemplate()) - OS << "template "; - Parent->print(OS, Context.getPrintingPolicy()); - } + Qualifier.print(OS, Context.getPrintingPolicy()); return OS.str(); } @@ -187,6 +211,7 @@ std::string printQualifiedName(const NamedDecl &ND) { // include them, but at query time it's hard to find all the inline // namespaces to query: the preamble doesn't have a dedicated list. Policy.SuppressUnwrittenScope = true; + Policy.SuppressScope = true; // (unnamed struct), not (unnamed struct at /path/to/foo.cc:42:1). // In clangd, context is usually available and paths are mostly noise. Policy.AnonymousTagLocations = false; @@ -213,8 +238,7 @@ std::string printUsingNamespaceName(const ASTContext &Ctx, std::string Name; llvm::raw_string_ostream Out(Name); - if (auto *Qual = D.getQualifier()) - Qual->print(Out, PP); + D.getQualifier().print(Out, PP); D.getNominatedNamespaceAsWritten()->printName(Out); return Out.str(); } @@ -229,8 +253,7 @@ std::string printName(const ASTContext &Ctx, const NamedDecl &ND) { // Handle 'using namespace'. They all have the same name - <using-directive>. if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) { Out << "using namespace "; - if (auto *Qual = UD->getQualifier()) - Qual->print(Out, PP); + UD->getQualifier().print(Out, PP); UD->getNominatedNamespaceAsWritten()->printName(Out); return Out.str(); } @@ -250,8 +273,7 @@ std::string printName(const ASTContext &Ctx, const NamedDecl &ND) { } // Print nested name qualifier if it was written in the source code. - if (auto *Qualifier = getQualifierLoc(ND).getNestedNameSpecifier()) - Qualifier->print(Out, PP); + getQualifierLoc(ND).getNestedNameSpecifier().print(Out, PP); // Print the name itself. ND.getDeclName().print(Out, PP); // Print template arguments. @@ -391,12 +413,13 @@ preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts, } std::string printType(const QualType QT, const DeclContext &CurContext, - const llvm::StringRef Placeholder) { + const llvm::StringRef Placeholder, bool FullyQualify) { std::string Result; llvm::raw_string_ostream OS(Result); PrintingPolicy PP(CurContext.getParentASTContext().getPrintingPolicy()); PP.SuppressTagKeyword = true; PP.SuppressUnwrittenScope = true; + PP.FullyQualifiedName = FullyQualify; class PrintCB : public PrintingCallbacks { public: @@ -439,6 +462,7 @@ QualType declaredType(const TypeDecl *D) { if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D)) if (const auto *Args = CTSD->getTemplateArgsAsWritten()) return Context.getTemplateSpecializationType( + ElaboratedTypeKeyword::None, TemplateName(CTSD->getSpecializedTemplate()), Args->arguments(), /*CanonicalArgs=*/{}); return Context.getTypeDeclType(D); @@ -664,13 +688,10 @@ std::string getQualification(ASTContext &Context, auto VisibleNamespaceDecls = getUsingNamespaceDirectives(DestContext, InsertionPoint); return getQualification( - Context, DestContext, ND->getDeclContext(), - [&](NestedNameSpecifier *NNS) { - const NamespaceDecl *NS = - dyn_cast_if_present<NamespaceDecl>(NNS->getAsNamespace()); - if (!NS) + Context, DestContext, ND->getDeclContext(), [&](const Decl *D) { + if (D->getKind() != Decl::Namespace) return false; - NS = NS->getCanonicalDecl(); + const auto *NS = cast<NamespaceDecl>(D)->getCanonicalDecl(); return llvm::any_of(VisibleNamespaceDecls, [NS](const NamespaceDecl *NSD) { return NSD->getCanonicalDecl() == NS; @@ -687,12 +708,11 @@ std::string getQualification(ASTContext &Context, (void)NS; } return getQualification( - Context, DestContext, ND->getDeclContext(), - [&](NestedNameSpecifier *NNS) { + Context, DestContext, ND->getDeclContext(), [&](const Decl *D) { return llvm::any_of(VisibleNamespaces, [&](llvm::StringRef Namespace) { std::string NS; llvm::raw_string_ostream OS(NS); - NNS->print(OS, Context.getPrintingPolicy()); + D->print(OS, Context.getPrintingPolicy()); return OS.str() == Namespace; }); }); diff --git a/clang-tools-extra/clangd/AST.h b/clang-tools-extra/clangd/AST.h index fb0722d..1538d12 100644 --- a/clang-tools-extra/clangd/AST.h +++ b/clang-tools-extra/clangd/AST.h @@ -135,7 +135,8 @@ preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts, /// Returns a QualType as string. The result doesn't contain unwritten scopes /// like anonymous/inline namespace. std::string printType(const QualType QT, const DeclContext &CurContext, - llvm::StringRef Placeholder = ""); + llvm::StringRef Placeholder = "", + bool FullyQualify = false); /// Indicates if \p D is a template instantiation implicitly generated by the /// compiler, e.g. diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 9c17b4c..16559e4 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1466,19 +1466,15 @@ bool allowIndex(CodeCompletionContext &CC) { auto Scope = CC.getCXXScopeSpecifier(); if (!Scope) return true; - NestedNameSpecifier *NameSpec = (*Scope)->getScopeRep(); - if (!NameSpec) - return true; // We only query the index when qualifier is a namespace. // If it's a class, we rely solely on sema completions. - switch (NameSpec->getKind()) { - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Namespace: + switch ((*Scope)->getScopeRep().getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::Namespace: return true; - case NestedNameSpecifier::Super: - case NestedNameSpecifier::TypeSpec: - // Unresolved inside a template. - case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Kind::MicrosoftSuper: + case NestedNameSpecifier::Kind::Type: return false; } llvm_unreachable("invalid NestedNameSpecifier kind"); @@ -2434,6 +2430,9 @@ CompletionItem CodeCompletion::render(const CodeCompleteOptions &Opts) const { } llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const CodeCompletion &C) { + OS << "Signature: " << "\"" << C.Signature << "\", " + << "SnippetSuffix: " << "\"" << C.SnippetSuffix << "\"" + << ", Rendered:"; // For now just lean on CompletionItem. return OS << C.render(CodeCompleteOptions()); } diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp index c6075e7..9a8d41d 100644 --- a/clang-tools-extra/clangd/DumpAST.cpp +++ b/clang-tools-extra/clangd/DumpAST.cpp @@ -147,17 +147,17 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> { } llvm_unreachable("Unhandled ArgKind enum"); } - std::string getKind(const NestedNameSpecifierLoc &NNSL) { - assert(NNSL.getNestedNameSpecifier()); - switch (NNSL.getNestedNameSpecifier()->getKind()) { + std::string getKind(NestedNameSpecifierLoc NNSL) { + switch (NNSL.getNestedNameSpecifier().getKind()) { + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); #define NNS_KIND(X) \ - case NestedNameSpecifier::X: \ + case NestedNameSpecifier::Kind::X: \ return #X - NNS_KIND(Identifier); NNS_KIND(Namespace); - NNS_KIND(TypeSpec); + NNS_KIND(Type); NNS_KIND(Global); - NNS_KIND(Super); + NNS_KIND(MicrosoftSuper); #undef NNS_KIND } llvm_unreachable("Unhandled SpecifierKind enum"); @@ -261,7 +261,7 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> { return TL.getType().getLocalQualifiers().getAsString( Ctx.getPrintingPolicy()); if (const auto *TT = dyn_cast<TagType>(TL.getTypePtr())) - return getDetail(TT->getDecl()); + return getDetail(TT->getOriginalDecl()); if (const auto *DT = dyn_cast<DeducedType>(TL.getTypePtr())) if (DT->isDeduced()) return DT->getDeducedType().getAsString(Ctx.getPrintingPolicy()); @@ -273,16 +273,11 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> { return getDetail(TT->getDecl()); return ""; } - std::string getDetail(const NestedNameSpecifierLoc &NNSL) { - const auto &NNS = *NNSL.getNestedNameSpecifier(); - switch (NNS.getKind()) { - case NestedNameSpecifier::Identifier: - return NNS.getAsIdentifier()->getName().str() + "::"; - case NestedNameSpecifier::Namespace: - return NNS.getAsNamespace()->getNameAsString() + "::"; - default: + std::string getDetail(NestedNameSpecifierLoc NNSL) { + NestedNameSpecifier NNS = NNSL.getNestedNameSpecifier(); + if (NNS.getKind() != NestedNameSpecifier::Kind::Namespace) return ""; - } + return NNS.getAsNamespaceAndPrefix().Namespace->getNameAsString() + "::"; } std::string getDetail(const CXXCtorInitializer *CCI) { if (FieldDecl *FD = CCI->getAnyMember()) @@ -346,8 +341,10 @@ public: return !D || isInjectedClassName(D) || traverseNode("declaration", D, [&] { Base::TraverseDecl(D); }); } - bool TraverseTypeLoc(TypeLoc TL) { - return !TL || traverseNode("type", TL, [&] { Base::TraverseTypeLoc(TL); }); + bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) { + return !TL || traverseNode("type", TL, [&] { + Base::TraverseTypeLoc(TL, TraverseQualifier); + }); } bool TraverseTemplateName(const TemplateName &TN) { return traverseNode("template name", TN, @@ -389,11 +386,11 @@ public: // This means we'd never see 'int' in 'const int'! Work around that here. // (The reason for the behavior is to avoid traversing the nested Type twice, // but we ignore TraverseType anyway). - bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QTL) { + bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QTL, bool TraverseQualifier) { return TraverseTypeLoc(QTL.getUnqualifiedLoc()); } // Uninteresting parts of the AST that don't have locations within them. - bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; } + bool TraverseNestedNameSpecifier(NestedNameSpecifier) { return true; } bool TraverseType(QualType) { return true; } // OpaqueValueExpr blocks traversal, we must explicitly traverse it. @@ -420,7 +417,7 @@ ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens, V.TraverseNestedNameSpecifierLoc( *const_cast<NestedNameSpecifierLoc *>(NNSL)); else if (const auto *NNS = N.get<NestedNameSpecifier>()) - V.TraverseNestedNameSpecifier(const_cast<NestedNameSpecifier *>(NNS)); + V.TraverseNestedNameSpecifier(*NNS); else if (const auto *TL = N.get<TypeLoc>()) V.TraverseTypeLoc(*const_cast<TypeLoc *>(TL)); else if (const auto *QT = N.get<QualType>()) diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index b108957..32018d1 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -366,19 +366,11 @@ public: Visitor(TargetFinder &Outer, RelSet Flags) : Outer(Outer), Flags(Flags) {} void VisitTagType(const TagType *TT) { - Outer.add(TT->getAsTagDecl(), Flags); - } - - void VisitElaboratedType(const ElaboratedType *ET) { - Outer.add(ET->desugar(), Flags); + Outer.add(cast<TagType>(TT)->getOriginalDecl(), Flags); } void VisitUsingType(const UsingType *ET) { - Outer.add(ET->getFoundDecl(), Flags); - } - - void VisitInjectedClassNameType(const InjectedClassNameType *ICNT) { - Outer.add(ICNT->getDecl(), Flags); + Outer.add(ET->getDecl(), Flags); } void VisitDecltypeType(const DecltypeType *DTT) { @@ -483,30 +475,27 @@ public: Visitor(*this, Flags).Visit(T.getTypePtr()); } - void add(const NestedNameSpecifier *NNS, RelSet Flags) { + void add(NestedNameSpecifier NNS, RelSet Flags) { if (!NNS) return; - debug(*NNS, Flags); - switch (NNS->getKind()) { - case NestedNameSpecifier::Namespace: - add(NNS->getAsNamespace(), Flags); - return; - case NestedNameSpecifier::Identifier: - if (Resolver) { - add(Resolver->resolveNestedNameSpecifierToType(NNS), Flags); - } + debug(NNS, Flags); + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Namespace: + add(NNS.getAsNamespaceAndPrefix().Namespace, Flags); return; - case NestedNameSpecifier::TypeSpec: - add(QualType(NNS->getAsType(), 0), Flags); + case NestedNameSpecifier::Kind::Type: + add(QualType(NNS.getAsType(), 0), Flags); return; - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: // This should be TUDecl, but we can't get a pointer to it! return; - case NestedNameSpecifier::Super: - add(NNS->getAsRecordDecl(), Flags); + case NestedNameSpecifier::Kind::MicrosoftSuper: + add(NNS.getAsMicrosoftSuper(), Flags); return; + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } - llvm_unreachable("unhandled NestedNameSpecifier::SpecifierKind"); + llvm_unreachable("unhandled NestedNameSpecifier::Kind"); } void add(const CXXCtorInitializer *CCI, RelSet Flags) { @@ -555,7 +544,7 @@ allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver) { else if (const NestedNameSpecifierLoc *NNSL = N.get<NestedNameSpecifierLoc>()) Finder.add(NNSL->getNestedNameSpecifier(), Flags); else if (const NestedNameSpecifier *NNS = N.get<NestedNameSpecifier>()) - Finder.add(NNS, Flags); + Finder.add(*NNS, Flags); else if (const TypeLoc *TL = N.get<TypeLoc>()) Finder.add(TL->getType(), Flags); else if (const QualType *QT = N.get<QualType>()) @@ -861,32 +850,25 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) { const HeuristicResolver *Resolver; llvm::SmallVector<ReferenceLoc> Refs; - void VisitElaboratedTypeLoc(ElaboratedTypeLoc L) { - // We only know about qualifier, rest if filled by inner locations. - size_t InitialSize = Refs.size(); - Visit(L.getNamedTypeLoc().getUnqualifiedLoc()); - size_t NewSize = Refs.size(); - // Add qualifier for the newly-added refs. - for (unsigned I = InitialSize; I < NewSize; ++I) { - ReferenceLoc *Ref = &Refs[I]; - // Fill in the qualifier. - assert(!Ref->Qualifier.hasQualifier() && "qualifier already set"); - Ref->Qualifier = L.getQualifierLoc(); - } + void VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc L) { + Refs.push_back(ReferenceLoc{L.getQualifierLoc(), + L.getLocalSourceRange().getBegin(), + /*IsDecl=*/false, + {L.getDecl()}}); } void VisitUsingTypeLoc(UsingTypeLoc L) { - Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(), + Refs.push_back(ReferenceLoc{L.getQualifierLoc(), L.getLocalSourceRange().getBegin(), /*IsDecl=*/false, - {L.getFoundDecl()}}); + {L.getDecl()}}); } void VisitTagTypeLoc(TagTypeLoc L) { - Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(), + Refs.push_back(ReferenceLoc{L.getQualifierLoc(), L.getNameLoc(), /*IsDecl=*/false, - {L.getDecl()}}); + {L.getOriginalDecl()}}); } void VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc L) { @@ -906,25 +888,18 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) { // 2. 'vector<int>' with mask 'Underlying'. // we want to return only #1 in this case. Refs.push_back(ReferenceLoc{ - NestedNameSpecifierLoc(), L.getTemplateNameLoc(), /*IsDecl=*/false, + L.getQualifierLoc(), L.getTemplateNameLoc(), /*IsDecl=*/false, explicitReferenceTargets(DynTypedNode::create(L.getType()), DeclRelation::Alias, Resolver)}); } void VisitDeducedTemplateSpecializationTypeLoc( DeducedTemplateSpecializationTypeLoc L) { Refs.push_back(ReferenceLoc{ - NestedNameSpecifierLoc(), L.getNameLoc(), /*IsDecl=*/false, + L.getQualifierLoc(), L.getNameLoc(), /*IsDecl=*/false, explicitReferenceTargets(DynTypedNode::create(L.getType()), DeclRelation::Alias, Resolver)}); } - void VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { - Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(), - TL.getNameLoc(), - /*IsDecl=*/false, - {TL.getDecl()}}); - } - void VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc L) { Refs.push_back( @@ -943,12 +918,12 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) { } void VisitTypedefTypeLoc(TypedefTypeLoc L) { - if (shouldSkipTypedef(L.getTypedefNameDecl())) + if (shouldSkipTypedef(L.getDecl())) return; - Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(), + Refs.push_back(ReferenceLoc{L.getQualifierLoc(), L.getNameLoc(), /*IsDecl=*/false, - {L.getTypedefNameDecl()}}); + {L.getDecl()}}); } void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc L) { @@ -980,17 +955,6 @@ public: return true; } - bool TraverseElaboratedTypeLoc(ElaboratedTypeLoc L) { - // ElaboratedTypeLoc will reports information for its inner type loc. - // Otherwise we loose information about inner types loc's qualifier. - TypeLoc Inner = L.getNamedTypeLoc().getUnqualifiedLoc(); - if (L.getBeginLoc() == Inner.getBeginLoc()) - return RecursiveASTVisitor::TraverseTypeLoc(Inner); - else - TypeLocsToSkip.insert(Inner.getBeginLoc()); - return RecursiveASTVisitor::TraverseElaboratedTypeLoc(L); - } - bool VisitStmt(Stmt *S) { visitNode(DynTypedNode::create(*S)); return true; @@ -1051,7 +1015,7 @@ public: return true; visitNode(DynTypedNode::create(L)); // Inner type is missing information about its qualifier, skip it. - if (auto TL = L.getTypeLoc()) + if (auto TL = L.getAsTypeLoc()) TypeLocsToSkip.insert(TL.getBeginLoc()); return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(L); } @@ -1092,12 +1056,21 @@ private: if (auto *S = N.get<Stmt>()) return refInStmt(S, Resolver); if (auto *NNSL = N.get<NestedNameSpecifierLoc>()) { - // (!) 'DeclRelation::Alias' ensures we do not loose namespace aliases. - return {ReferenceLoc{ - NNSL->getPrefix(), NNSL->getLocalBeginLoc(), false, - explicitReferenceTargets( - DynTypedNode::create(*NNSL->getNestedNameSpecifier()), - DeclRelation::Alias, Resolver)}}; + // (!) 'DeclRelation::Alias' ensures we do not lose namespace aliases. + NestedNameSpecifierLoc Qualifier; + SourceLocation NameLoc; + if (auto TL = NNSL->getAsTypeLoc()) { + Qualifier = TL.getPrefix(); + NameLoc = TL.getNonPrefixBeginLoc(); + } else { + Qualifier = NNSL->getAsNamespaceAndPrefix().Prefix; + NameLoc = NNSL->getLocalBeginLoc(); + } + return { + ReferenceLoc{Qualifier, NameLoc, false, + explicitReferenceTargets( + DynTypedNode::create(NNSL->getNestedNameSpecifier()), + DeclRelation::Alias, Resolver)}}; } if (const TypeLoc *TL = N.get<TypeLoc>()) return refInTypeLoc(*TL, Resolver); @@ -1210,8 +1183,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ReferenceLoc R) { OS << "}"; if (R.Qualifier) { OS << ", qualifier = '"; - R.Qualifier.getNestedNameSpecifier()->print(OS, - PrintingPolicy(LangOptions())); + R.Qualifier.getNestedNameSpecifier().print(OS, + PrintingPolicy(LangOptions())); OS << "'"; } if (R.IsDecl) diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 0afa902..a7cf45c 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -172,13 +172,14 @@ HoverInfo::PrintedType printType(QualType QT, ASTContext &ASTCtx, QT = QT->castAs<DecltypeType>()->getUnderlyingType(); HoverInfo::PrintedType Result; llvm::raw_string_ostream OS(Result.Type); - // Special case: if the outer type is a tag type without qualifiers, then - // include the tag for extra clarity. - // This isn't very idiomatic, so don't attempt it for complex cases, including - // pointers/references, template specializations, etc. + // Special case: if the outer type is a canonical tag type, then include the + // tag for extra clarity. This isn't very idiomatic, so don't attempt it for + // complex cases, including pointers/references, template specializations, + // etc. if (!QT.isNull() && !QT.hasQualifiers() && PP.SuppressTagKeyword) { - if (auto *TT = llvm::dyn_cast<TagType>(QT.getTypePtr())) - OS << TT->getDecl()->getKindName() << " "; + if (auto *TT = llvm::dyn_cast<TagType>(QT.getTypePtr()); + TT && TT->isCanonicalUnqualified()) + OS << TT->getOriginalDecl()->getKindName() << " "; } QT.print(OS, PP); @@ -454,7 +455,7 @@ std::optional<std::string> printExprValue(const Expr *E, // Compare to int64_t to avoid bit-width match requirements. int64_t Val = Constant.Val.getInt().getExtValue(); for (const EnumConstantDecl *ECD : - T->castAs<EnumType>()->getDecl()->enumerators()) + T->castAs<EnumType>()->getOriginalDecl()->enumerators()) if (ECD->getInitVal() == Val) return llvm::formatv("{0} ({1})", ECD->getNameAsString(), printHex(Constant.Val.getInt())) @@ -972,10 +973,11 @@ void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) { const auto &Ctx = ND.getASTContext(); if (auto *RD = llvm::dyn_cast<RecordDecl>(&ND)) { - if (auto Size = Ctx.getTypeSizeInCharsIfKnown(RD->getTypeForDecl())) + CanQualType RT = Ctx.getCanonicalTagType(RD); + if (auto Size = Ctx.getTypeSizeInCharsIfKnown(RT)) HI.Size = Size->getQuantity() * 8; if (!RD->isDependentType() && RD->isCompleteDefinition()) - HI.Align = Ctx.getTypeAlign(RD->getTypeForDecl()); + HI.Align = Ctx.getTypeAlign(RT); return; } diff --git a/clang-tools-extra/clangd/IncludeFixer.cpp b/clang-tools-extra/clangd/IncludeFixer.cpp index 50bc2bd..c27d960 100644 --- a/clang-tools-extra/clangd/IncludeFixer.cpp +++ b/clang-tools-extra/clangd/IncludeFixer.cpp @@ -173,7 +173,7 @@ std::vector<Fix> IncludeFixer::fix(DiagnosticsEngine::Level DiagLevel, // `enum x : int;' is not formally an incomplete type. // We may need a full definition anyway. if (auto * ET = llvm::dyn_cast<EnumType>(T)) - if (!ET->getDecl()->getDefinition()) + if (!ET->getOriginalDecl()->getDefinition()) return fixIncompleteType(*T); } } @@ -400,35 +400,35 @@ std::optional<CheapUnresolvedName> extractUnresolvedNameCheaply( CheapUnresolvedName Result; Result.Name = Unresolved.getAsString(); if (SS && SS->isNotEmpty()) { // "::" or "ns::" - if (auto *Nested = SS->getScopeRep()) { - if (Nested->getKind() == NestedNameSpecifier::Global) { - Result.ResolvedScope = ""; - } else if (const NamespaceBaseDecl *NSB = Nested->getAsNamespace()) { - if (const auto *NS = dyn_cast<NamespaceDecl>(NSB)) { - std::string SpecifiedNS = printNamespaceScope(*NS); - std::optional<std::string> Spelling = getSpelledSpecifier(*SS, SM); - - // Check the specifier spelled in the source. - // If the resolved scope doesn't end with the spelled scope, the - // resolved scope may come from a sema typo correction. For example, - // sema assumes that "clangd::" is a typo of "clang::" and uses - // "clang::" as the specified scope in: - // namespace clang { clangd::X; } - // In this case, we use the "typo" specifier as extra scope instead - // of using the scope assumed by sema. - if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) { - Result.ResolvedScope = std::move(SpecifiedNS); - } else { - Result.UnresolvedScope = std::move(*Spelling); - } + NestedNameSpecifier Nested = SS->getScopeRep(); + if (Nested.getKind() == NestedNameSpecifier::Kind::Global) { + Result.ResolvedScope = ""; + } else if (Nested.getKind() == NestedNameSpecifier::Kind::Namespace) { + const NamespaceBaseDecl *NSB = Nested.getAsNamespaceAndPrefix().Namespace; + if (const auto *NS = dyn_cast<NamespaceDecl>(NSB)) { + std::string SpecifiedNS = printNamespaceScope(*NS); + std::optional<std::string> Spelling = getSpelledSpecifier(*SS, SM); + + // Check the specifier spelled in the source. + // If the resolved scope doesn't end with the spelled scope, the + // resolved scope may come from a sema typo correction. For example, + // sema assumes that "clangd::" is a typo of "clang::" and uses + // "clang::" as the specified scope in: + // namespace clang { clangd::X; } + // In this case, we use the "typo" specifier as extra scope instead + // of using the scope assumed by sema. + if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) { + Result.ResolvedScope = std::move(SpecifiedNS); } else { - Result.ResolvedScope = printNamespaceScope(*cast<NamespaceAliasDecl>(NSB)->getNamespace()); + Result.UnresolvedScope = std::move(*Spelling); } } else { - // We don't fix symbols in scopes that are not top-level e.g. class - // members, as we don't collect includes for them. - return std::nullopt; + Result.ResolvedScope = printNamespaceScope(*cast<NamespaceAliasDecl>(NSB)->getNamespace()); } + } else { + // We don't fix symbols in scopes that are not top-level e.g. class + // members, as we don't collect includes for them. + return std::nullopt; } } diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index 197c62c..cd479e1 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -55,18 +55,24 @@ void stripLeadingUnderscores(StringRef &Name) { Name = Name.ltrim('_'); } // getDeclForType() returns the decl responsible for Type's spelling. // This is the inverse of ASTContext::getTypeDeclType(). -template <typename Ty, typename = decltype(((Ty *)nullptr)->getDecl())> -const NamedDecl *getDeclForTypeImpl(const Ty *T) { - return T->getDecl(); -} -const NamedDecl *getDeclForTypeImpl(const void *T) { return nullptr; } const NamedDecl *getDeclForType(const Type *T) { switch (T->getTypeClass()) { -#define ABSTRACT_TYPE(TY, BASE) -#define TYPE(TY, BASE) \ - case Type::TY: \ - return getDeclForTypeImpl(llvm::cast<TY##Type>(T)); -#include "clang/AST/TypeNodes.inc" + case Type::Enum: + case Type::Record: + case Type::InjectedClassName: + return cast<TagType>(T)->getOriginalDecl(); + case Type::TemplateSpecialization: + return cast<TemplateSpecializationType>(T) + ->getTemplateName() + .getAsTemplateDecl(/*IgnoreDeduced=*/true); + case Type::Typedef: + return cast<TypedefType>(T)->getDecl(); + case Type::UnresolvedUsing: + return cast<UnresolvedUsingType>(T)->getDecl(); + case Type::Using: + return cast<UsingType>(T)->getDecl(); + default: + return nullptr; } llvm_unreachable("Unknown TypeClass enum"); } @@ -81,8 +87,6 @@ llvm::StringRef getSimpleName(const NamedDecl &D) { return getSimpleName(D.getDeclName()); } llvm::StringRef getSimpleName(QualType T) { - if (const auto *ET = llvm::dyn_cast<ElaboratedType>(T)) - return getSimpleName(ET->getNamedType()); if (const auto *BT = llvm::dyn_cast<BuiltinType>(T)) { PrintingPolicy PP(LangOptions{}); PP.adjustForCPlusPlus(); diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp index 277cb87..06165df 100644 --- a/clang-tools-extra/clangd/Selection.cpp +++ b/clang-tools-extra/clangd/Selection.cpp @@ -62,7 +62,8 @@ void recordMetrics(const SelectionTree &S, const LangOptions &Lang) { } // Return the range covering a node and all its children. -SourceRange getSourceRange(const DynTypedNode &N) { +SourceRange getSourceRange(const DynTypedNode &N, + bool IncludeQualifier = false) { // MemberExprs to implicitly access anonymous fields should not claim any // tokens for themselves. Given: // struct A { struct { int b; }; }; @@ -80,7 +81,7 @@ SourceRange getSourceRange(const DynTypedNode &N) { ? getSourceRange(DynTypedNode::create(*ME->getBase())) : SourceRange(); } - return N.getSourceRange(); + return N.getSourceRange(IncludeQualifier); } // An IntervalSet maintains a set of disjoint subranges of an array. @@ -643,8 +644,9 @@ public: } return traverseNode(X, [&] { return Base::TraverseDecl(X); }); } - bool TraverseTypeLoc(TypeLoc X) { - return traverseNode(&X, [&] { return Base::TraverseTypeLoc(X); }); + bool TraverseTypeLoc(TypeLoc X, bool TraverseQualifier = true) { + return traverseNode( + &X, [&] { return Base::TraverseTypeLoc(X, TraverseQualifier); }); } bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &X) { return traverseNode(&X, @@ -690,7 +692,8 @@ public: // This means we'd never see 'int' in 'const int'! Work around that here. // (The reason for the behavior is to avoid traversing the nested Type twice, // but we ignore TraverseType anyway). - bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QX) { + bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QX, + bool TraverseQualifier = true) { return traverseNode<TypeLoc>( &QX, [&] { return TraverseTypeLoc(QX.getUnqualifiedLoc()); }); } @@ -698,7 +701,7 @@ public: return traverseNode(&PL, [&] { return Base::TraverseObjCProtocolLoc(PL); }); } // Uninteresting parts of the AST that don't have locations within them. - bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; } + bool TraverseNestedNameSpecifier(NestedNameSpecifier) { return true; } bool TraverseType(QualType) { return true; } // The DeclStmt for the loop variable claims to cover the whole range @@ -798,7 +801,7 @@ private: // An optimization for a common case: nodes outside macro expansions that // don't intersect the selection may be recursively skipped. bool canSafelySkipNode(const DynTypedNode &N) { - SourceRange S = getSourceRange(N); + SourceRange S = getSourceRange(N, /*IncludeQualifier=*/true); if (auto *TL = N.get<TypeLoc>()) { // FIXME: TypeLoc::getBeginLoc()/getEndLoc() are pretty fragile // heuristics. We should consider only pruning critical TypeLoc nodes, to diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp index e6d5cf7..2b151b1 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -1127,21 +1127,6 @@ public: return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L); } - // findExplicitReferences will walk nested-name-specifiers and - // find anything that can be resolved to a Decl. However, non-leaf - // components of nested-name-specifiers which are dependent names - // (kind "Identifier") cannot be resolved to a decl, so we visit - // them here. - bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Q) { - if (NestedNameSpecifier *NNS = Q.getNestedNameSpecifier()) { - if (NNS->getKind() == NestedNameSpecifier::Identifier) - H.addToken(Q.getLocalBeginLoc(), HighlightingKind::Type) - .addModifier(HighlightingModifier::DependentName) - .addModifier(HighlightingModifier::ClassScope); - } - return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(Q); - } - private: HighlightingsBuilder &H; }; diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 83a8b72..11ee510 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -1965,7 +1965,8 @@ std::vector<const CXXRecordDecl *> findRecordTypeAt(ParsedAST &AST, // Return the type most associated with an AST node. // This isn't precisely defined: we want "go to type" to do something useful. -static QualType typeForNode(const SelectionTree::Node *N) { +static QualType typeForNode(const ASTContext &Ctx, + const SelectionTree::Node *N) { // If we're looking at a namespace qualifier, walk up to what it's qualifying. // (If we're pointing at a *class* inside a NNS, N will be a TypeLoc). while (N && N->ASTNode.get<NestedNameSpecifierLoc>()) @@ -1999,10 +2000,13 @@ static QualType typeForNode(const SelectionTree::Node *N) { if (const Decl *D = N->ASTNode.get<Decl>()) { struct Visitor : ConstDeclVisitor<Visitor, QualType> { + const ASTContext &Ctx; + Visitor(const ASTContext &Ctx) : Ctx(Ctx) {} + QualType VisitValueDecl(const ValueDecl *D) { return D->getType(); } // Declaration of a type => that type. QualType VisitTypeDecl(const TypeDecl *D) { - return QualType(D->getTypeForDecl(), 0); + return Ctx.getTypeDeclType(D); } // Exception: alias declaration => the underlying type, not the alias. QualType VisitTypedefNameDecl(const TypedefNameDecl *D) { @@ -2012,7 +2016,7 @@ static QualType typeForNode(const SelectionTree::Node *N) { QualType VisitTemplateDecl(const TemplateDecl *D) { return Visit(D->getTemplatedDecl()); } - } V; + } V(Ctx); return V.Visit(D); } @@ -2156,7 +2160,8 @@ std::vector<LocatedSymbol> findType(ParsedAST &AST, Position Pos, // unique_ptr<unique_ptr<T>>. Let's *not* remove them, because it gives you some // information about the type you may have not known before // (since unique_ptr<unique_ptr<T>> != unique_ptr<T>). - for (const QualType& Type : unwrapFindType(typeForNode(N), AST.getHeuristicResolver())) + for (const QualType &Type : unwrapFindType( + typeForNode(AST.getASTContext(), N), AST.getHeuristicResolver())) llvm::copy(locateSymbolForType(AST, Type, Index), std::back_inserter(LocatedSymbols)); diff --git a/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp b/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp index 67fc451..f65c74f 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp @@ -115,13 +115,6 @@ private: const SourceManager &SM; }; -bool isFullyQualified(const NestedNameSpecifier *NNS) { - if (!NNS) - return false; - return NNS->getKind() == NestedNameSpecifier::Global || - isFullyQualified(NNS->getPrefix()); -} - struct InsertionPointData { // Location to insert the "using" statement. If invalid then the statement // should not be inserted at all (it already exists). @@ -167,18 +160,20 @@ findInsertionPoint(const Tweak::Selection &Inputs, for (auto &U : Usings) { // Only "upgrade" to fully qualified is all relevant using decls are fully // qualified. Otherwise trust what the user typed. - if (!isFullyQualified(U->getQualifier())) + if (!U->getQualifier().isFullyQualified()) AlwaysFullyQualify = false; if (SM.isBeforeInTranslationUnit(Inputs.Cursor, U->getUsingLoc())) // "Usings" is sorted, so we're done. break; - if (const auto *Namespace = dyn_cast_if_present<NamespaceDecl>( - U->getQualifier()->getAsNamespace())) { + if (NestedNameSpecifier Qualifier = U->getQualifier(); + Qualifier.getKind() == NestedNameSpecifier::Kind::Namespace) { + const auto *Namespace = + U->getQualifier().getAsNamespaceAndPrefix().Namespace; if (Namespace->getCanonicalDecl() == QualifierToRemove.getNestedNameSpecifier() - ->getAsNamespace() - ->getCanonicalDecl() && + .getAsNamespaceAndPrefix() + .Namespace->getCanonicalDecl() && U->getName() == Name) { return InsertionPointData(); } @@ -232,8 +227,9 @@ findInsertionPoint(const Tweak::Selection &Inputs, } bool isNamespaceForbidden(const Tweak::Selection &Inputs, - const NestedNameSpecifier &Namespace) { - const auto *NS = dyn_cast<NamespaceDecl>(Namespace.getAsNamespace()); + NestedNameSpecifier Namespace) { + const auto *NS = + dyn_cast<NamespaceDecl>(Namespace.getAsNamespaceAndPrefix().Namespace); if (!NS) return true; std::string NamespaceStr = printNamespaceScope(*NS); @@ -247,11 +243,11 @@ bool isNamespaceForbidden(const Tweak::Selection &Inputs, return false; } -std::string getNNSLAsString(NestedNameSpecifierLoc &NNSL, +std::string getNNSLAsString(NestedNameSpecifierLoc NNSL, const PrintingPolicy &Policy) { std::string Out; llvm::raw_string_ostream OutStream(Out); - NNSL.getNestedNameSpecifier()->print(OutStream, Policy); + NNSL.getNestedNameSpecifier().print(OutStream, Policy); return OutStream.str(); } @@ -276,16 +272,15 @@ bool AddUsing::prepare(const Selection &Inputs) { continue; } if (auto *T = Node->ASTNode.get<TypeLoc>()) { - if (T->getAs<ElaboratedTypeLoc>()) { + // Find the outermost TypeLoc. + if (Node->Parent->ASTNode.get<NestedNameSpecifierLoc>()) + continue; + if (isa<TagType, TemplateSpecializationType, TypedefType, UsingType, + UnresolvedUsingType>(T->getTypePtr())) break; - } - if (Node->Parent->ASTNode.get<TypeLoc>() || - Node->Parent->ASTNode.get<NestedNameSpecifierLoc>()) { - // Node is TypeLoc, but it's parent is either TypeLoc or - // NestedNameSpecifier. In both cases, we want to go up, to find - // the outermost TypeLoc. + // Find the outermost TypeLoc. + if (Node->Parent->ASTNode.get<TypeLoc>()) continue; - } } break; } @@ -307,32 +302,70 @@ bool AddUsing::prepare(const Selection &Inputs) { MustInsertAfterLoc = D->getDecl()->getBeginLoc(); } } else if (auto *T = Node->ASTNode.get<TypeLoc>()) { - if (auto E = T->getAs<ElaboratedTypeLoc>()) { - QualifierToRemove = E.getQualifierLoc(); - - SpelledNameRange = E.getSourceRange(); - if (auto T = E.getNamedTypeLoc().getAs<TemplateSpecializationTypeLoc>()) { - // Remove the template arguments from the name. - SpelledNameRange.setEnd(T.getLAngleLoc().getLocWithOffset(-1)); - } - - if (const auto *ET = E.getTypePtr()) { - if (const auto *TDT = - dyn_cast<TypedefType>(ET->getNamedType().getTypePtr())) { - MustInsertAfterLoc = TDT->getDecl()->getBeginLoc(); - } else if (auto *TD = ET->getAsTagDecl()) { - MustInsertAfterLoc = TD->getBeginLoc(); - } - } + switch (T->getTypeLocClass()) { + case TypeLoc::TemplateSpecialization: { + auto TL = T->castAs<TemplateSpecializationTypeLoc>(); + QualifierToRemove = TL.getQualifierLoc(); + if (!QualifierToRemove) + break; + SpelledNameRange = TL.getTemplateNameLoc(); + if (auto *TD = TL.getTypePtr()->getTemplateName().getAsTemplateDecl( + /*IgnoreDeduced=*/true)) + MustInsertAfterLoc = TD->getBeginLoc(); + break; + } + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: { + auto TL = T->castAs<TagTypeLoc>(); + QualifierToRemove = TL.getQualifierLoc(); + if (!QualifierToRemove) + break; + SpelledNameRange = TL.getNameLoc(); + MustInsertAfterLoc = TL.getOriginalDecl()->getBeginLoc(); + break; + } + case TypeLoc::Typedef: { + auto TL = T->castAs<TypedefTypeLoc>(); + QualifierToRemove = TL.getQualifierLoc(); + if (!QualifierToRemove) + break; + SpelledNameRange = TL.getNameLoc(); + MustInsertAfterLoc = TL.getDecl()->getBeginLoc(); + break; + } + case TypeLoc::UnresolvedUsing: { + auto TL = T->castAs<UnresolvedUsingTypeLoc>(); + QualifierToRemove = TL.getQualifierLoc(); + if (!QualifierToRemove) + break; + SpelledNameRange = TL.getNameLoc(); + MustInsertAfterLoc = TL.getDecl()->getBeginLoc(); + break; + } + case TypeLoc::Using: { + auto TL = T->castAs<UsingTypeLoc>(); + QualifierToRemove = TL.getQualifierLoc(); + if (!QualifierToRemove) + break; + SpelledNameRange = TL.getNameLoc(); + MustInsertAfterLoc = TL.getDecl()->getBeginLoc(); + break; + } + default: + break; } + if (QualifierToRemove) + SpelledNameRange.setBegin(QualifierToRemove.getBeginLoc()); } if (!QualifierToRemove || // FIXME: This only supports removing qualifiers that are made up of just // namespace names. If qualifier contains a type, we could take the // longest namespace prefix and remove that. - !QualifierToRemove.getNestedNameSpecifier()->getAsNamespace() || + QualifierToRemove.getNestedNameSpecifier().getKind() != + NestedNameSpecifier::Kind::Namespace || // Respect user config. - isNamespaceForbidden(Inputs, *QualifierToRemove.getNestedNameSpecifier())) + isNamespaceForbidden(Inputs, QualifierToRemove.getNestedNameSpecifier())) return false; // Macros are difficult. We only want to offer code action when what's spelled // under the cursor is a namespace qualifier. If it's a macro that expands to @@ -384,7 +417,7 @@ Expected<Tweak::Effect> AddUsing::apply(const Selection &Inputs) { llvm::raw_string_ostream UsingTextStream(UsingText); UsingTextStream << "using "; if (InsertionPoint->AlwaysFullyQualify && - !isFullyQualified(QualifierToRemove.getNestedNameSpecifier())) + !QualifierToRemove.getNestedNameSpecifier().isFullyQualified()) UsingTextStream << "::"; UsingTextStream << QualifierToSpell << SpelledName << ";" << InsertionPoint->Suffix; diff --git a/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp b/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp index cd07cbf..134ae89 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp @@ -362,7 +362,7 @@ struct NewFunction { SourceLocation DefinitionPoint; std::optional<SourceLocation> ForwardDeclarationPoint; const CXXRecordDecl *EnclosingClass = nullptr; - const NestedNameSpecifier *DefinitionQualifier = nullptr; + NestedNameSpecifier DefinitionQualifier = std::nullopt; const DeclContext *SemanticDC = nullptr; const DeclContext *SyntacticDC = nullptr; const DeclContext *ForwardDeclarationSyntacticDC = nullptr; @@ -455,13 +455,12 @@ std::string NewFunction::renderQualifiers() const { } std::string NewFunction::renderDeclarationName(FunctionDeclKind K) const { - if (DefinitionQualifier == nullptr || K != OutOfLineDefinition) { + if (!DefinitionQualifier || K != OutOfLineDefinition) return Name; - } std::string QualifierName; llvm::raw_string_ostream Oss(QualifierName); - DefinitionQualifier->print(Oss, *LangOpts); + DefinitionQualifier.print(Oss, *LangOpts); return llvm::formatv("{0}{1}", QualifierName, Name); } diff --git a/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp b/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp index 43cfc76..7e61696 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp @@ -116,7 +116,7 @@ bool PopulateSwitch::prepare(const Selection &Sel) { EnumT = Cond->getType().getCanonicalType()->getAsAdjusted<EnumType>(); if (!EnumT) return false; - EnumD = EnumT->getDecl(); + EnumD = EnumT->getOriginalDecl(); if (!EnumD || EnumD->isDependentType()) return false; diff --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp index d0bc3c4..76d46ba 100644 --- a/clang-tools-extra/clangd/unittests/ASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp @@ -421,7 +421,7 @@ TEST(ClangdAST, GetQualification) { { R"cpp( namespace ns1 { namespace ns2 { void Foo(); } } - void insert(); // ns2::Foo + void insert(); // ns1::ns2::Foo namespace ns1 { void insert(); // ns2::Foo namespace ns2 { @@ -429,7 +429,7 @@ TEST(ClangdAST, GetQualification) { } } )cpp", - {"ns2::", "ns2::", ""}, + {"ns1::ns2::", "ns2::", ""}, {"ns1::"}, }, { @@ -531,7 +531,8 @@ TEST(ClangdAST, PrintType) { ASSERT_EQ(InsertionPoints.size(), Case.Types.size()); for (size_t I = 0, E = InsertionPoints.size(); I != E; ++I) { const auto *DC = InsertionPoints[I]; - EXPECT_EQ(printType(AST.getASTContext().getTypeDeclType(TargetDecl), *DC), + EXPECT_EQ(printType(AST.getASTContext().getTypeDeclType(TargetDecl), *DC, + /*Placeholder=*/"", /*FullyQualify=*/true), Case.Types[I]); } } diff --git a/clang-tools-extra/clangd/unittests/DumpASTTests.cpp b/clang-tools-extra/clangd/unittests/DumpASTTests.cpp index cb2c17a..5c857d0 100644 --- a/clang-tools-extra/clangd/unittests/DumpASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/DumpASTTests.cpp @@ -72,15 +72,14 @@ declaration: Namespace - root expression: BinaryOperator - + expression: ImplicitCast - LValueToRValue expression: DeclRef - x - specifier: TypeSpec + specifier: Type type: Record - S expression: ImplicitCast - LValueToRValue expression: Member - x expression: CXXBindTemporary expression: CXXTemporaryObject - S - type: Elaborated + type: Record - S specifier: Namespace - root:: - type: Record - S )"}, {R"cpp( namespace root { @@ -104,14 +103,13 @@ declaration: Namespace - root expression: BinaryOperator - + expression: ImplicitCast - LValueToRValue expression: DeclRef - x - specifier: TypeSpec + specifier: Type type: Record - S expression: ImplicitCast - LValueToRValue expression: Member - x expression: CXXTemporaryObject - S - type: Elaborated + type: Record - S specifier: Namespace - root:: - type: Record - S )"}, {R"cpp( namespace root { @@ -138,7 +136,7 @@ declaration: Namespace - root type: Builtin - unsigned int statement: Return expression: DependentScopeDeclRef - value - specifier: TypeSpec + specifier: Type type: TemplateTypeParm - T )"}, {R"cpp( @@ -154,8 +152,7 @@ declaration: Var - root expression: DeclRef - operator+ expression: MaterializeTemporary - lvalue expression: CXXTemporaryObject - Foo - type: Elaborated - type: Record - Foo + type: Record - Foo expression: IntegerLiteral - 42 )"}, {R"cpp( diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp index 4d77f9d..20fd23e 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -992,7 +992,7 @@ TEST_F(TargetDeclTest, DependentTypes) { )cpp"; EXPECT_DECLS("DependentNameTypeLoc", "struct B"); - // Heuristic resolution of dependent type name which doesn't get a TypeLoc + // Heuristic resolution of dependent type name within a NestedNameSpecifierLoc Code = R"cpp( template <typename> struct A { struct B { struct C {}; }; }; @@ -1000,7 +1000,7 @@ TEST_F(TargetDeclTest, DependentTypes) { template <typename T> void foo(typename A<T>::[[B]]::C); )cpp"; - EXPECT_DECLS("NestedNameSpecifierLoc", "struct B"); + EXPECT_DECLS("DependentNameTypeLoc", "struct B"); // Heuristic resolution of dependent type name whose qualifier is also // dependent diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 3331164..6407349 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -2894,7 +2894,7 @@ TEST(Hover, All) { )cpp", [](HoverInfo &HI) { HI.Name = "this"; - HI.Definition = "const Foo<T> *"; + HI.Definition = "const ns::Foo<T> *"; }}, { R"cpp(// this expr for specialization class @@ -2910,7 +2910,7 @@ TEST(Hover, All) { )cpp", [](HoverInfo &HI) { HI.Name = "this"; - HI.Definition = "Foo<int> *"; + HI.Definition = "ns::Foo<int> *"; }}, { R"cpp(// this expr for partial specialization struct @@ -2926,7 +2926,7 @@ TEST(Hover, All) { )cpp", [](HoverInfo &HI) { HI.Name = "this"; - HI.Definition = "const Foo<int, F> *"; + HI.Definition = "const ns::Foo<int, F> *"; }}, { R"cpp( @@ -3046,8 +3046,8 @@ TEST(Hover, All) { HI.Kind = index::SymbolKind::Function; HI.NamespaceScope = ""; HI.Definition = "MyRect foobar()"; - HI.Type = {"MyRect ()", "MyRect ()"}; - HI.ReturnType = {"MyRect", "MyRect"}; + HI.Type = {"MyRect ()", "struct MyRect ()"}; + HI.ReturnType = {"MyRect", "struct MyRect"}; HI.Parameters.emplace(); }}, {R"cpp( diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp index e0cd955..99e728c 100644 --- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -1295,14 +1295,7 @@ TEST(TypeHints, NoQualifiers) { } } )cpp", - ExpectedHint{": S1", "x"}, - // FIXME: We want to suppress scope specifiers - // here because we are into the whole - // brevity thing, but the ElaboratedType - // printer does not honor the SuppressScope - // flag by design, so we need to extend the - // PrintingPolicy to support this use case. - ExpectedHint{": S2::Inner<int>", "y"}); + ExpectedHint{": S1", "x"}, ExpectedHint{": Inner<int>", "y"}); } TEST(TypeHints, Lambda) { diff --git a/clang-tools-extra/clangd/unittests/QualityTests.cpp b/clang-tools-extra/clangd/unittests/QualityTests.cpp index 619ea32..4954659 100644 --- a/clang-tools-extra/clangd/unittests/QualityTests.cpp +++ b/clang-tools-extra/clangd/unittests/QualityTests.cpp @@ -121,7 +121,9 @@ TEST(QualityTests, SymbolRelevanceSignalExtraction) { SymbolRelevanceSignals Relevance; Relevance.merge(CodeCompletionResult(&findDecl(AST, "deprecated"), - /*Priority=*/42, nullptr, false, + /*Priority=*/42, + /*Qualifier=*/std::nullopt, + /*QualifierIsInformative=*/false, /*Accessible=*/false)); EXPECT_EQ(Relevance.NameMatch, SymbolRelevanceSignals().NameMatch); EXPECT_TRUE(Relevance.Forbidden); @@ -487,13 +489,15 @@ TEST(QualityTests, ItemWithFixItsRankedDown) { auto AST = Header.build(); SymbolRelevanceSignals RelevanceWithFixIt; - RelevanceWithFixIt.merge(CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr, - false, true, {FixItHint{}})); + RelevanceWithFixIt.merge(CodeCompletionResult( + &findDecl(AST, "x"), /*Priority=*/0, /*Qualifier=*/std::nullopt, + /*QualifierIsInformative=*/false, /*Accessible=*/true, {FixItHint{}})); EXPECT_TRUE(RelevanceWithFixIt.NeedsFixIts); SymbolRelevanceSignals RelevanceWithoutFixIt; - RelevanceWithoutFixIt.merge( - CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr, false, true, {})); + RelevanceWithoutFixIt.merge(CodeCompletionResult( + &findDecl(AST, "x"), /*Priority=*/0, /*Qualifier=*/std::nullopt, + /*QualifierIsInformative=*/false, /*Accessible=*/true, {})); EXPECT_FALSE(RelevanceWithoutFixIt.NeedsFixIts); EXPECT_LT(RelevanceWithFixIt.evaluateHeuristics(), diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp index aaaf758..3df19d8 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -104,9 +104,9 @@ TEST(SelectionTest, CommonAncestor) { { R"cpp( template <typename T> - int x = [[T::^U::]]ccc(); + int x = T::[[^U]]::ccc(); )cpp", - "NestedNameSpecifierLoc", + "DependentNameTypeLoc", }, { R"cpp( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 8b636018..187aae2 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -186,6 +186,10 @@ Changes in existing checks <clang-tidy/checks/portability/template-virtual-member-function>` check to avoid false positives on pure virtual member functions. +- Improved :doc:`readability-container-size-empty + <clang-tidy/checks/readability/container-size-empty>` check by correctly + generating fix-it hints when size method is called from implicit ``this``. + - Improved :doc:`readability-identifier-naming <clang-tidy/checks/readability/identifier-naming>` check by ignoring declarations in system headers. diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index 49cc136..0cbf9a0 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -60,14 +60,10 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> { NamedDecl *getMemberProvider(QualType Base) { if (Base->isPointerType()) return getMemberProvider(Base->getPointeeType()); - // Unwrap the sugar ElaboratedType. - if (const auto *ElTy = dyn_cast<ElaboratedType>(Base)) - return getMemberProvider(ElTy->getNamedType()); - if (const auto *TT = dyn_cast<TypedefType>(Base)) return TT->getDecl(); if (const auto *UT = dyn_cast<UsingType>(Base)) - return UT->getFoundDecl(); + return UT->getDecl(); // A heuristic: to resolve a template type to **only** its template name. // We're only using this method for the base type of MemberExpr, in general // the template provides the member, and the critical case `unique_ptr<Foo>` @@ -135,16 +131,14 @@ public: } bool qualifierIsNamespaceOrNone(DeclRefExpr *DRE) { - const auto *Qual = DRE->getQualifier(); - if (!Qual) - return true; - switch (Qual->getKind()) { - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Global: + NestedNameSpecifier Qual = DRE->getQualifier(); + switch (Qual.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Namespace: + case NestedNameSpecifier::Kind::Global: return true; - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::Super: - case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Kind::Type: + case NestedNameSpecifier::Kind::MicrosoftSuper: return false; } llvm_unreachable("Unknown value for NestedNameSpecifierKind"); @@ -341,17 +335,17 @@ public: } bool VisitUsingTypeLoc(UsingTypeLoc TL) { - reportType(TL.getNameLoc(), TL.getFoundDecl()); + reportType(TL.getNameLoc(), TL.getDecl()); return true; } bool VisitTagTypeLoc(TagTypeLoc TTL) { - reportType(TTL.getNameLoc(), TTL.getDecl()); + reportType(TTL.getNameLoc(), TTL.getOriginalDecl()); return true; } bool VisitTypedefTypeLoc(TypedefTypeLoc TTL) { - reportType(TTL.getNameLoc(), TTL.getTypedefNameDecl()); + reportType(TTL.getNameLoc(), TTL.getDecl()); return true; } diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/copy-constructor-init.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/copy-constructor-init.cpp index b42d3fc..35314d1 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/copy-constructor-init.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/copy-constructor-init.cpp @@ -165,7 +165,6 @@ FROMMACRO class X15 : public CopyableAlias2 { X15(const X15 &other) {} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor - // CHECK-FIXES: X15(const X15 &other) : Copyable5(other) {} }; class X16 : public NonCopyable { diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp index 721c55b..5dd2387 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp @@ -69,14 +69,14 @@ template<typename T> T qux(T Generic) { async::Future<Units> PendingA = acquireUnits(); auto PendingB = acquireUnits(); - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable] + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'async::Future<Units>') [bugprone-unused-local-non-trivial-variable] async::Future<Units> MustBeUsed; // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: unused local variable 'MustBeUsed' of type 'async::Future<Units>' [bugprone-unused-local-non-trivial-variable] PendingA.get(); async::Future<T> TemplateType; // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'TemplateType' of type 'async::Future<T>' [bugprone-unused-local-non-trivial-variable] a::Future<T> AliasTemplateType; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'Future<T>') [bugprone-unused-local-non-trivial-variable] + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'async::Future<T>') [bugprone-unused-local-non-trivial-variable] [[maybe_unused]] async::Future<Units> MaybeUnused; return Generic; } @@ -86,7 +86,7 @@ async::Future<int> Global; int bar(int Num) { a::Future<Units> PendingA = acquireUnits(); a::Future<Units> PendingB = acquireUnits(); // not used at all, unused variable not fired because of destructor side effect - // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable] + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'async::Future<Units>') [bugprone-unused-local-non-trivial-variable] auto Num2 = PendingA.get(); auto Num3 = qux(Num); async::Ptr<a::Future<Units>> Shared = async::Ptr<a::Future<Units>>(acquireUnits()); diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/std-allocator-const.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/std-allocator-const.cpp index 732cf5d..a38594a 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/std-allocator-const.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/std-allocator-const.cpp @@ -43,25 +43,25 @@ template <class T> class allocator {}; void simple(const std::vector<const char> &v, std::deque<const short> *d) { - // CHECK-MESSAGES: [[#@LINE-1]]:24: warning: container using std::allocator<const T> is a deprecated libc++ extension; remove const for compatibility with other standard libraries - // CHECK-MESSAGES: [[#@LINE-2]]:52: warning: container + // CHECK-MESSAGES: [[#@LINE-1]]:19: warning: container using std::allocator<const T> is a deprecated libc++ extension; remove const for compatibility with other standard libraries + // CHECK-MESSAGES: [[#@LINE-2]]:47: warning: container std::list<const long> l; - // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container + // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container std::multiset<int *const> ms; - // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container + // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container std::set<const std::hash<int>> s; - // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container + // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container std::unordered_multiset<int *const> ums; - // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container + // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container std::unordered_set<const int> us; - // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container + // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container absl::flat_hash_set<const int> fhs; - // CHECK-MESSAGES: [[#@LINE-1]]:9: warning: container + // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container using my_vector = std::vector<const int>; - // CHECK-MESSAGES: [[#@LINE-1]]:26: warning: container + // CHECK-MESSAGES: [[#@LINE-1]]:21: warning: container my_vector v1; using my_vector2 = my_vector; @@ -76,7 +76,7 @@ void simple(const std::vector<const char> &v, std::deque<const short> *d) { template <class T> void temp1() { std::vector<const T> v; - // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container + // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container std::vector<T> neg1; std::forward_list<const T> neg2; @@ -87,7 +87,7 @@ template <class T> void temp2() { // Match std::vector<const dependent> for the uninstantiated temp2. std::vector<const T> v; - // CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container + // CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container std::vector<T> neg1; std::forward_list<const T> neg2; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp index 2fd0b222..b1e6867 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp @@ -895,3 +895,16 @@ namespace PR94454 { int operator""_ci() { return 0; } auto eq = 0_ci == 0; } + +namespace GH152387 { + +class foo : public std::string{ + void doit() { + if (!size()) { + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used to check for emptiness instead of 'size' + // CHECK-FIXES: if (empty()) { + } + } +}; + +} |