Skip to content

Commit d5c022d

Browse files
committed
[clangd][ObjC] Support nullability annotations
Nullability annotations are implmented using attributes; previusly clangd would skip over AttributedTypeLoc since their location points to the attribute instead of the modified type. Also add some test cases for this. Differential Revision: https://reviews.llvm.org/D89579
1 parent 343410d commit d5c022d

File tree

4 files changed

+70
-0
lines changed

4 files changed

+70
-0
lines changed

clang-tools-extra/clangd/Selection.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,10 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
605605
bool canSafelySkipNode(const DynTypedNode &N) {
606606
SourceRange S = N.getSourceRange();
607607
if (auto *TL = N.get<TypeLoc>()) {
608+
// FIXME: TypeLoc::getBeginLoc()/getEndLoc() are pretty fragile
609+
// heuristics. We should consider only pruning critical TypeLoc nodes, to
610+
// be more robust.
611+
608612
// DeclTypeTypeLoc::getSourceRange() is incomplete, which would lead to
609613
// failing
610614
// to descend into the child expression.
@@ -616,6 +620,10 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
616620
// rid of this patch.
617621
if (auto DT = TL->getAs<DecltypeTypeLoc>())
618622
S.setEnd(DT.getUnderlyingExpr()->getEndLoc());
623+
// AttributedTypeLoc may point to the attribute's range, NOT the modified
624+
// type's range.
625+
if (auto AT = TL->getAs<AttributedTypeLoc>())
626+
S = AT.getModifiedLoc().getSourceRange();
619627
}
620628
if (!SelChecker.mayHit(S)) {
621629
dlog("{1}skip: {0}", printNodeToString(N, PrintPolicy), indent());

clang-tools-extra/clangd/unittests/FindTargetTests.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,24 @@ TEST_F(TargetDeclTest, ObjC) {
831831
EXPECT_DECLS("ObjCPropertyRefExpr",
832832
"@property(atomic, retain, readwrite) I *x");
833833

834+
Code = R"cpp(
835+
@interface MYObject
836+
@end
837+
@interface Interface
838+
@property(retain) [[MYObject]] *x;
839+
@end
840+
)cpp";
841+
EXPECT_DECLS("ObjCInterfaceTypeLoc", "@interface MYObject");
842+
843+
Code = R"cpp(
844+
@interface MYObject2
845+
@end
846+
@interface Interface
847+
@property(retain, nonnull) [[MYObject2]] *x;
848+
@end
849+
)cpp";
850+
EXPECT_DECLS("ObjCInterfaceTypeLoc", "@interface MYObject2");
851+
834852
Code = R"cpp(
835853
@protocol Foo
836854
@end

clang-tools-extra/clangd/unittests/HoverTests.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,6 +1991,34 @@ TEST(Hover, All) {
19911991
HI.NamespaceScope = "ObjC::"; // FIXME: fix it
19921992
HI.Definition = "char data";
19931993
}},
1994+
{
1995+
R"cpp(
1996+
@interface MYObject
1997+
@end
1998+
@interface Interface
1999+
@property(retain) [[MYOb^ject]] *x;
2000+
@end
2001+
)cpp",
2002+
[](HoverInfo &HI) {
2003+
HI.Name = "MYObject";
2004+
HI.Kind = index::SymbolKind::Class;
2005+
HI.NamespaceScope = "";
2006+
HI.Definition = "@interface MYObject\n@end";
2007+
}},
2008+
{
2009+
R"cpp(
2010+
@interface MYObject
2011+
@end
2012+
@interface Interface
2013+
- (void)doWith:([[MYOb^ject]] *)object;
2014+
@end
2015+
)cpp",
2016+
[](HoverInfo &HI) {
2017+
HI.Name = "MYObject";
2018+
HI.Kind = index::SymbolKind::Class;
2019+
HI.NamespaceScope = "";
2020+
HI.Definition = "@interface MYObject\n@end";
2021+
}},
19942022
};
19952023

19962024
// Create a tiny index, so tests above can verify documentation is fetched.

clang-tools-extra/clangd/unittests/SelectionTests.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,22 @@ TEST(SelectionTest, CommonAncestor) {
356356
)cpp",
357357
"DeclRefExpr"},
358358

359+
// Objective-C nullability attributes.
360+
{
361+
R"cpp(
362+
@interface I{}
363+
@property(nullable) [[^I]] *x;
364+
@end
365+
)cpp",
366+
"ObjCInterfaceTypeLoc"},
367+
{
368+
R"cpp(
369+
@interface I{}
370+
- (void)doSomething:(nonnull [[i^d]])argument;
371+
@end
372+
)cpp",
373+
"TypedefTypeLoc"},
374+
359375
// Objective-C OpaqueValueExpr/PseudoObjectExpr has weird ASTs.
360376
// Need to traverse the contents of the OpaqueValueExpr to the POE,
361377
// and ensure we traverse only the syntactic form of the PseudoObjectExpr.

0 commit comments

Comments
 (0)