Skip to content

Commit

Permalink
[clang] Implement ElaboratedType sugaring for types written bare
Browse files Browse the repository at this point in the history
Without this patch, clang will not wrap in an ElaboratedType node types written
without a keyword and nested name qualifier, which goes against the intent that
we should produce an AST which retains enough details to recover how things are
written.

The lack of this sugar is incompatible with the intent of the type printer
default policy, which is to print types as written, but to fall back and print
them fully qualified when they are desugared.

An ElaboratedTypeLoc without keyword / NNS uses no storage by itself, but still
requires pointer alignment due to pre-existing bug in the TypeLoc buffer
handling.

Signed-off-by: Matheus Izvekov <mizvekov@gmail.com>

Differential Revision: https://reviews.llvm.org/D112374
  • Loading branch information
mizvekov committed Jul 13, 2022
1 parent ee88c0c commit bdc6974
Show file tree
Hide file tree
Showing 285 changed files with 2,348 additions and 2,139 deletions.
14 changes: 6 additions & 8 deletions clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
Expand Up @@ -567,14 +567,12 @@ void ChangeNamespaceTool::run(
if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
NestedNameSpecifierLoc NestedNameSpecifier =
Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
// This happens for friend declaration of a base class with injected class
// name.
if (!NestedNameSpecifier.getNestedNameSpecifier())
return;
const Type *SpecifierType =
NestedNameSpecifier.getNestedNameSpecifier()->getAsType();
if (SpecifierType && SpecifierType->isRecordType())
return;
// 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);
} else if (const auto *VarRef =
Expand Down
Expand Up @@ -215,7 +215,8 @@ void FindAllSymbols::registerMatchers(MatchFinder *MatchFinder) {
// Uses of most types: just look at what the typeLoc refers to.
MatchFinder->addMatcher(
typeLoc(isExpansionInMainFile(),
loc(qualType(hasDeclaration(Types.bind("use"))))),
loc(qualType(allOf(unless(elaboratedType()),
hasDeclaration(Types.bind("use")))))),
this);
// Uses of typedefs: these are often transparent to hasDeclaration, so we need
// to handle them explicitly.
Expand Down
10 changes: 5 additions & 5 deletions clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
Expand Up @@ -87,9 +87,9 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
const auto ConstantExpr = ignoringParenImpCasts(
anyOf(integerLiteral(), unaryOperator(hasUnaryOperand(IntegerExpr)),
binaryOperator(hasLHS(IntegerExpr), hasRHS(IntegerExpr))));
const auto IntegerCallExpr = ignoringParenImpCasts(
callExpr(anyOf(hasType(isInteger()), hasType(enumType())),
unless(isInTemplateInstantiation())));
const auto IntegerCallExpr = ignoringParenImpCasts(callExpr(
anyOf(hasType(isInteger()), hasType(hasCanonicalType(enumType()))),
unless(isInTemplateInstantiation())));
const auto SizeOfExpr = sizeOfExpr(hasArgumentOfType(
hasUnqualifiedDesugaredType(type().bind("sizeof-arg-type"))));
const auto SizeOfZero =
Expand Down Expand Up @@ -147,8 +147,8 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
const auto StructAddrOfExpr = unaryOperator(
hasOperatorName("&"), hasUnaryOperand(ignoringParenImpCasts(
hasType(hasCanonicalType(recordType())))));
const auto PointerToStructType =
hasUnqualifiedDesugaredType(pointerType(pointee(recordType())));
const auto PointerToStructType = hasUnqualifiedDesugaredType(
pointerType(pointee(hasCanonicalType(recordType()))));
const auto PointerToStructExpr = ignoringParenImpCasts(expr(
hasType(hasCanonicalType(PointerToStructType)), unless(cxxThisExpr())));

Expand Down
Expand Up @@ -67,10 +67,11 @@ void SmartPtrArrayMismatchCheck::registerMatchers(MatchFinder *Finder) {
auto FindConstructExpr =
cxxConstructExpr(
hasDeclaration(FindConstructor), argumentCountIs(1),
hasArgument(
0, cxxNewExpr(isArray(), hasType(pointerType(pointee(
equalsBoundNode(PointerTypeN)))))
.bind(NewExprN)))
hasArgument(0,
cxxNewExpr(isArray(),
hasType(hasCanonicalType(pointerType(
pointee(equalsBoundNode(PointerTypeN))))))
.bind(NewExprN)))
.bind(ConstructExprN);
Finder->addMatcher(FindConstructExpr, this);
}
Expand Down Expand Up @@ -101,7 +102,7 @@ void SmartPtrArrayMismatchCheck::check(const MatchFinder::MatchResult &Result) {
SourceRange TemplateArgumentRange = TSTypeLoc.getArgLoc(0)
.getTypeSourceInfo()
->getTypeLoc()
.getLocalSourceRange();
.getSourceRange();
D << TemplateArgumentRange;

if (isInSingleDeclStmt(VarOrField)) {
Expand Down
Expand Up @@ -130,7 +130,12 @@ 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.
if (SourceTypeAsWritten == DestTypeAsWritten) {
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) {
diag(CastExpr->getBeginLoc(), "redundant cast to the same type")
<< FixItHint::CreateRemoval(ReplaceRange);
return;
Expand Down
Expand Up @@ -36,7 +36,8 @@ void MultiwayPathsCoveredCheck::registerMatchers(MatchFinder *Finder) {
// otherwise the matcher does not work correctly, because it
// will not explicitly ignore enum conditions.
unless(ignoringImpCasts(
declRefExpr(hasType(enumType())).bind("enum-condition"))))))
declRefExpr(hasType(hasCanonicalType(enumType())))
.bind("enum-condition"))))))
.bind("switch"),
this);

Expand Down
13 changes: 7 additions & 6 deletions clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp
Expand Up @@ -21,12 +21,13 @@ void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) {
pointee(anyOf(isConstQualified(), ignoringParens(functionType()))))));

Finder->addMatcher(
valueDecl(
hasType(isConstQualified()),
hasType(typedefType(hasDeclaration(anyOf(
typedefDecl(NonConstAndNonFunctionPointerType).bind("typedef"),
typeAliasDecl(NonConstAndNonFunctionPointerType)
.bind("typeAlias"))))))
valueDecl(hasType(qualType(
isConstQualified(),
elaboratedType(namesType(typedefType(hasDeclaration(
anyOf(typedefDecl(NonConstAndNonFunctionPointerType)
.bind("typedef"),
typeAliasDecl(NonConstAndNonFunctionPointerType)
.bind("typeAlias")))))))))
.bind("decl"),
this);
}
Expand Down
Expand Up @@ -400,7 +400,7 @@ static bool canBeModified(ASTContext *Context, const Expr *E) {
return true;
if (const auto *Cast = Parents[0].get<ImplicitCastExpr>()) {
if ((Cast->getCastKind() == CK_NoOp &&
Cast->getType() == E->getType().withConst()) ||
Context->hasSameType(Cast->getType(), E->getType().withConst())) ||
(Cast->getCastKind() == CK_LValueToRValue &&
!Cast->getType().isNull() && Cast->getType()->isFundamentalType()))
return false;
Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
Expand Up @@ -48,7 +48,8 @@ AST_MATCHER(CXXRecordDecl, isMoveConstructible) {

static TypeMatcher notTemplateSpecConstRefType() {
return lValueReferenceType(
pointee(unless(templateSpecializationType()), isConstQualified()));
pointee(unless(elaboratedType(namesType(templateSpecializationType()))),
isConstQualified()));
}

static TypeMatcher nonConstValueType() {
Expand Down
34 changes: 18 additions & 16 deletions clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
Expand Up @@ -153,22 +153,24 @@ static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context,
// ((Base*)this)->operator=((Base)Other);
//
// So we are looking for a member call that fulfills:
if (match(traverse(TK_AsIs,
compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(
// - The object is an implicit cast of 'this' to a
// pointer to
// a base class.
onImplicitObjectArgument(implicitCastExpr(
hasImplicitDestinationType(
pointsTo(type(equalsNode(Base)))),
hasSourceExpression(cxxThisExpr()))),
// - The called method is the operator=.
callee(cxxMethodDecl(isCopyAssignmentOperator())),
// - The argument is (an implicit cast to a Base of)
// the argument taken by "Operator".
argumentCountIs(1),
hasArgument(0, declRefExpr(to(varDecl(
equalsNode(Param)))))))))),
if (match(traverse(
TK_AsIs,
compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(
// - The object is an implicit cast of 'this' to a
// pointer to
// a base class.
onImplicitObjectArgument(implicitCastExpr(
hasImplicitDestinationType(hasCanonicalType(pointsTo(
type(equalsNode(Base->getCanonicalTypeInternal()
.getTypePtr()))))),
hasSourceExpression(cxxThisExpr()))),
// - The called method is the operator=.
callee(cxxMethodDecl(isCopyAssignmentOperator())),
// - The argument is (an implicit cast to a Base of)
// the argument taken by "Operator".
argumentCountIs(1),
hasArgument(
0, declRefExpr(to(varDecl(equalsNode(Param)))))))))),
*Compound, *Context)
.empty())
return false;
Expand Down
Expand Up @@ -97,7 +97,9 @@ struct UnqualNameVisitor : public RecursiveASTVisitor<UnqualNameVisitor> {
if (TL.getQualifierLoc() &&
!TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()))
return false;
return TraverseTypeLoc(TL.getNamedTypeLoc(), true);
const auto *T = TL.getTypePtr();
return TraverseTypeLoc(TL.getNamedTypeLoc(),
T->getKeyword() != ETK_None || T->getQualifier());
}

bool VisitDeclRefExpr(DeclRefExpr *S) {
Expand Down
5 changes: 4 additions & 1 deletion clang-tools-extra/clangd/FindTarget.cpp
Expand Up @@ -950,7 +950,10 @@ class ExplicitReferenceCollector
// ElaboratedTypeLoc will reports information for its inner type loc.
// Otherwise we loose information about inner types loc's qualifier.
TypeLoc Inner = L.getNamedTypeLoc().getUnqualifiedLoc();
TypeLocsToSkip.insert(Inner.getBeginLoc());
if (L.getBeginLoc() == Inner.getBeginLoc())
return RecursiveASTVisitor::TraverseTypeLoc(Inner);
else
TypeLocsToSkip.insert(Inner.getBeginLoc());
return RecursiveASTVisitor::TraverseElaboratedTypeLoc(L);
}

Expand Down
20 changes: 10 additions & 10 deletions clang-tools-extra/clangd/unittests/ASTTests.cpp
Expand Up @@ -72,7 +72,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
template<typename T> class Foo {};
^auto v = Foo<X>();
)cpp",
"Foo<class X>",
"Foo<X>",
},
{
R"cpp( // auto on initializer list.
Expand All @@ -93,7 +93,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
return Foo();
}
)cpp",
"struct Foo",
"Foo",
},
{
R"cpp( // decltype in trailing return type
Expand All @@ -102,7 +102,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
return Foo();
}
)cpp",
"struct Foo",
"Foo",
},
{
R"cpp( // auto in function return type
Expand All @@ -111,7 +111,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
return Foo();
}
)cpp",
"struct Foo",
"Foo",
},
{
R"cpp( // auto& in function return type
Expand All @@ -121,7 +121,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
return x;
}
)cpp",
"struct Foo",
"Foo",
},
{
R"cpp( // auto* in function return type
Expand All @@ -131,7 +131,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
return x;
}
)cpp",
"struct Foo",
"Foo",
},
{
R"cpp( // const auto& in function return type
Expand All @@ -141,7 +141,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
return x;
}
)cpp",
"struct Foo",
"Foo",
},
{
R"cpp( // decltype(auto) in function return (value)
Expand All @@ -150,7 +150,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
return Foo();
}
)cpp",
"struct Foo",
"Foo",
},
{
R"cpp( // decltype(auto) in function return (ref)
Expand All @@ -160,7 +160,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
return (x);
}
)cpp",
"struct Foo &",
"Foo &",
},
{
R"cpp( // decltype(auto) in function return (const ref)
Expand All @@ -170,7 +170,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
return (x);
}
)cpp",
"const struct Foo &",
"const Foo &",
},
{
R"cpp( // auto on alias
Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clangd/unittests/DumpASTTests.cpp
Expand Up @@ -121,7 +121,8 @@ declaration: Var - root
expression: DeclRef - operator+
expression: MaterializeTemporary - lvalue
expression: CXXTemporaryObject - Foo
type: Record - Foo
type: Elaborated
type: Record - Foo
expression: IntegerLiteral - 42
)"},
{R"cpp(
Expand Down
11 changes: 6 additions & 5 deletions clang-tools-extra/clangd/unittests/FindTargetTests.cpp
Expand Up @@ -1612,13 +1612,14 @@ TEST_F(FindExplicitReferencesTest, All) {
{
R"cpp(
void foo() {
class {} $0^x;
int (*$1^fptr)(int $2^a, int) = nullptr;
$0^class {} $1^x;
int (*$2^fptr)(int $3^a, int) = nullptr;
}
)cpp",
"0: targets = {x}, decl\n"
"1: targets = {fptr}, decl\n"
"2: targets = {a}, decl\n"},
"0: targets = {}\n"
"1: targets = {x}, decl\n"
"2: targets = {fptr}, decl\n"
"3: targets = {a}, decl\n"},
// Namespace aliases should be handled properly.
{
R"cpp(
Expand Down

0 comments on commit bdc6974

Please sign in to comment.