summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaojian Wu <hokein.wu@gmail.com>2022-01-06 20:46:33 +0100
committerHaojian Wu <hokein.wu@gmail.com>2022-01-10 09:34:18 +0100
commit4a4b8e4f99e2a82286b0595d561a51e7ad1945d2 (patch)
tree7e105d44a88873edf6b9c6a84140556339ac343d
parent5c2e7c9ca043d92bed75b08e653fb47c384edd13 (diff)
downloadllvm-4a4b8e4f99e2a82286b0595d561a51e7ad1945d2.tar.gz
[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
-rw-r--r--clang-tools-extra/clangd/Selection.cpp15
-rw-r--r--clang-tools-extra/clangd/unittests/SelectionTests.cpp2
-rw-r--r--clang/include/clang/AST/TypeLoc.h31
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp4
-rw-r--r--clang/lib/Sema/SemaCXXScopeSpec.cpp3
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp3
-rw-r--r--clang/lib/Sema/SemaType.cpp5
-rw-r--r--clang/lib/Sema/TreeTransform.h6
-rw-r--r--clang/lib/Serialization/ASTReader.cpp3
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp3
-rw-r--r--clang/unittests/AST/SourceLocationTest.cpp29
11 files changed, 76 insertions, 28 deletions
diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp
index 7dc8a868ea00..7c6b8b3134fe 100644
--- a/clang-tools-extra/clangd/Selection.cpp
+++ b/clang-tools-extra/clangd/Selection.cpp
@@ -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; }; };
diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
index 9da111f684c3..7e19f07a2215 100644
--- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
@@ -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.
{
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 7a036836e8c4..9a43d34a9ec3 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -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 {
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 8ab1231e1bc1..c08a586604b1 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -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
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 8cecf6c6ab4f..4781d71080c9 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -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;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 454b2647cf34..4c6a96acdb91 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -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);
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 57825fe3d79b..f0bbbcf59c75 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -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);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 298a3f7a83d8..c105a0c26ab4 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -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;
}
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 724ea53463ca..b8ec5b2722a9 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -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) {
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 65a780e67510..40772bb7dd7f 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -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) {
diff --git a/clang/unittests/AST/SourceLocationTest.cpp b/clang/unittests/AST/SourceLocationTest.cpp
index c1565c8f4c30..832d3751362f 100644
--- a/clang/unittests/AST/SourceLocationTest.cpp
+++ b/clang/unittests/AST/SourceLocationTest.cpp
@@ -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"