Skip to content

Commit

Permalink
[AST] Add more source information for DecltypeTypeLoc.
Browse files Browse the repository at this point in the history
Adds the paren source location, and removes the hack in clangd.

Differential Revision: https://reviews.llvm.org/D116793
  • Loading branch information
hokein committed Jan 10, 2022
1 parent 5c2e7c9 commit 4a4b8e4
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 28 deletions.
15 changes: 0 additions & 15 deletions clang-tools-extra/clangd/Selection.cpp
Expand Up @@ -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; }; };
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/unittests/SelectionTests.cpp
Expand Up @@ -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.
{
Expand Down
31 changes: 27 additions & 4 deletions clang/include/clang/AST/TypeLoc.h
Expand Up @@ -1994,12 +1994,35 @@ class TypeOfTypeLoc
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 {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Parse/ParseDeclCXX.cpp
Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaCXXScopeSpec.cpp
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaExprCXX.cpp
Expand Up @@ -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);

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaType.cpp
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Sema/TreeTransform.h
Expand Up @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Serialization/ASTReader.cpp
Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Expand Up @@ -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) {
Expand Down
29 changes: 28 additions & 1 deletion clang/unittests/AST/SourceLocationTest.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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"
Expand Down

0 comments on commit 4a4b8e4

Please sign in to comment.