Skip to content

[PATCH 6/7] [clang] improve NestedNameSpecifier #149748

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: users/mizvekov/name-qualification-refactor-5
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 17 additions & 36 deletions clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")) {
Expand All @@ -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");
Expand All @@ -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");
Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 5 additions & 5 deletions clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
29 changes: 12 additions & 17 deletions clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,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()) {
Expand All @@ -238,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());
Expand Down Expand Up @@ -289,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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,66 +64,65 @@ struct UnqualNameVisitor : public RecursiveASTVisitor<UnqualNameVisitor> {
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading
Loading