[AST] Add more source information for DecltypeTypeLoc.

Adds the paren source location, and removes the hack in clangd.

Differential Revision: https://reviews.llvm.org/D116793
This commit is contained in:
Haojian Wu 2022-01-06 20:46:33 +01:00
parent 5c2e7c9ca0
commit 4a4b8e4f99
11 changed files with 76 additions and 28 deletions

View File

@ -60,21 +60,6 @@ void recordMetrics(const SelectionTree &S, const LangOptions &Lang) {
// Return the range covering a node and all its children.
SourceRange getSourceRange(const DynTypedNode &N) {
// DeclTypeTypeLoc::getSourceRange() is incomplete, which would lead to
// failing to descend into the child expression.
// decltype(2+2);
// ~~~~~~~~~~~~~ <-- correct range
// ~~~~~~~~ <-- range reported by getSourceRange()
// ~~~~~~~~~~~~ <-- range with this hack(i.e, missing closing paren)
// FIXME: Alter DecltypeTypeLoc to contain parentheses locations and get
// rid of this patch.
if (const auto *TL = N.get<TypeLoc>()) {
if (auto DT = TL->getAs<DecltypeTypeLoc>()) {
SourceRange S = DT.getSourceRange();
S.setEnd(DT.getUnderlyingExpr()->getEndLoc());
return S;
}
}
// MemberExprs to implicitly access anonymous fields should not claim any
// tokens for themselves. Given:
// struct A { struct { int b; }; };

View File

@ -390,7 +390,7 @@ TEST(SelectionTest, CommonAncestor) {
decltype([[^a]] + a) b;
)cpp",
"DeclRefExpr"},
{"[[decltype]]^(1) b;", "DecltypeTypeLoc"}, // Not the VarDecl.
{"[[decltype^(1)]] b;", "DecltypeTypeLoc"}, // Not the VarDecl.
// Objective-C nullability attributes.
{

View File

@ -1994,12 +1994,35 @@ public:
void initializeLocal(ASTContext &Context, SourceLocation Loc);
};
// FIXME: location of the 'decltype' and parens.
class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
DecltypeTypeLoc,
DecltypeType> {
// decltype(expression) abc;
// ~~~~~~~~ DecltypeLoc
// ~ RParenLoc
// FIXME: add LParenLoc, it is tricky to support due to the limitation of
// annotated-decltype token.
struct DecltypeTypeLocInfo {
SourceLocation DecltypeLoc;
SourceLocation RParenLoc;
};
class DecltypeTypeLoc
: public ConcreteTypeLoc<UnqualTypeLoc, DecltypeTypeLoc, DecltypeType,
DecltypeTypeLocInfo> {
public:
Expr *getUnderlyingExpr() const { return getTypePtr()->getUnderlyingExpr(); }
SourceLocation getDecltypeLoc() const { return getLocalData()->DecltypeLoc; }
void setDecltypeLoc(SourceLocation Loc) { getLocalData()->DecltypeLoc = Loc; }
SourceLocation getRParenLoc() const { return getLocalData()->RParenLoc; }
void setRParenLoc(SourceLocation Loc) { getLocalData()->RParenLoc = Loc; }
SourceRange getLocalSourceRange() const {
return SourceRange(getDecltypeLoc(), getRParenLoc());
}
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
setDecltypeLoc(Loc);
setRParenLoc(Loc);
}
};
struct UnaryTransformTypeLocInfo {

View File

@ -1007,6 +1007,9 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
if (Tok.is(tok::annot_decltype)) {
Result = getExprAnnotation(Tok);
EndLoc = Tok.getAnnotationEndLoc();
// Unfortunately, we don't know the LParen source location as the annotated
// token doesn't have it.
DS.setTypeofParensRange(SourceRange(SourceLocation(), EndLoc));
ConsumeAnnotationToken();
if (Result.isInvalid()) {
DS.SetTypeSpecError();
@ -1071,6 +1074,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
// Match the ')'
T.consumeClose();
DS.setTypeofParensRange(T.getRange());
if (T.getCloseLocation().isInvalid()) {
DS.SetTypeSpecError();
// FIXME: this should return the location of the last token

View File

@ -881,7 +881,8 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
TypeLocBuilder TLB;
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
ColonColonLoc);
return false;

View File

@ -7767,7 +7767,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
TypeLocBuilder TLB;
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T);
PseudoDestructorTypeStorage Destructed(DestructedTypeInfo);

View File

@ -5973,6 +5973,11 @@ namespace {
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
TL.setUnderlyingTInfo(TInfo);
}
void VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
TL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
TL.setRParenLoc(DS.getTypeofParensRange().getEnd());
}
void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
// FIXME: This holds only because we only have one unary transform.
assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);

View File

@ -6228,15 +6228,15 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
E.get() != T->getUnderlyingExpr()) {
Result = getDerived().RebuildDecltypeType(E.get(), TL.getNameLoc());
Result = getDerived().RebuildDecltypeType(E.get(), TL.getDecltypeLoc());
if (Result.isNull())
return QualType();
}
else E.get();
DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
NewTL.setDecltypeLoc(TL.getDecltypeLoc());
NewTL.setRParenLoc(TL.getRParenLoc());
return Result;
}

View File

@ -6628,7 +6628,8 @@ void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
}
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
TL.setNameLoc(readSourceLocation());
TL.setDecltypeLoc(readSourceLocation());
TL.setRParenLoc(readSourceLocation());
}
void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {

View File

@ -427,7 +427,8 @@ void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
}
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
Record.AddSourceLocation(TL.getNameLoc());
Record.AddSourceLocation(TL.getDecltypeLoc());
Record.AddSourceLocation(TL.getRParenLoc());
}
void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {

View File

@ -215,6 +215,33 @@ TEST(TypeLoc, LongRange) {
EXPECT_TRUE(Verifier.match("long a;", typeLoc()));
}
TEST(TypeLoc, DecltypeTypeLocRange) {
llvm::Annotations Code(R"(
$full1[[decltype(1)]] a;
struct A {struct B{};} var;
$full2[[decltype(var)]]::B c;
)");
auto AST = tooling::buildASTFromCodeWithArgs(Code.code(), /*Args=*/{});
ASTContext &Ctx = AST->getASTContext();
const auto &SM = Ctx.getSourceManager();
auto MatchedLocs = clang::ast_matchers::match(
typeLoc(loc(decltypeType())).bind("target"), Ctx);
ASSERT_EQ(MatchedLocs.size(), 2u);
auto verify = [&](SourceRange ActualRange,
const llvm::Annotations::Range &Expected) {
auto ActualCharRange =
Lexer::getAsCharRange(ActualRange, SM, Ctx.getLangOpts());
EXPECT_EQ(SM.getFileOffset(ActualCharRange.getBegin()), Expected.Begin);
EXPECT_EQ(SM.getFileOffset(ActualCharRange.getEnd()), Expected.End);
};
const auto *Target1 = MatchedLocs[0].getNodeAs<DecltypeTypeLoc>("target");
verify(Target1->getSourceRange(), Code.range("full1"));
const auto *Target2 = MatchedLocs[1].getNodeAs<DecltypeTypeLoc>("target");
verify(Target2->getSourceRange(), Code.range("full2"));
}
TEST(TypeLoc, LongDoubleRange) {
RangeVerifier<TypeLoc> Verifier;
Verifier.expectRange(1, 1, 1, 6);
@ -559,7 +586,7 @@ TEST(FriendDecl, FriendDecltypeLocation) {
TEST(FriendDecl, FriendDecltypeRange) {
RangeVerifier<FriendDecl> Verifier;
Verifier.expectRange(4, 1, 4, 8);
Verifier.expectRange(4, 1, 4, 22);
EXPECT_TRUE(Verifier.match("struct A;\n"
"A foo();\n"
"struct A {\n"