[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
This commit is contained in:
David Goldman 2020-10-16 14:14:37 -04:00
parent 343410d1cc
commit d5c022d846
4 changed files with 70 additions and 0 deletions

View File

@ -605,6 +605,10 @@ private:
bool canSafelySkipNode(const DynTypedNode &N) {
SourceRange S = N.getSourceRange();
if (auto *TL = N.get<TypeLoc>()) {
// FIXME: TypeLoc::getBeginLoc()/getEndLoc() are pretty fragile
// heuristics. We should consider only pruning critical TypeLoc nodes, to
// be more robust.
// DeclTypeTypeLoc::getSourceRange() is incomplete, which would lead to
// failing
// to descend into the child expression.
@ -616,6 +620,10 @@ private:
// rid of this patch.
if (auto DT = TL->getAs<DecltypeTypeLoc>())
S.setEnd(DT.getUnderlyingExpr()->getEndLoc());
// AttributedTypeLoc may point to the attribute's range, NOT the modified
// type's range.
if (auto AT = TL->getAs<AttributedTypeLoc>())
S = AT.getModifiedLoc().getSourceRange();
}
if (!SelChecker.mayHit(S)) {
dlog("{1}skip: {0}", printNodeToString(N, PrintPolicy), indent());

View File

@ -831,6 +831,24 @@ TEST_F(TargetDeclTest, ObjC) {
EXPECT_DECLS("ObjCPropertyRefExpr",
"@property(atomic, retain, readwrite) I *x");
Code = R"cpp(
@interface MYObject
@end
@interface Interface
@property(retain) [[MYObject]] *x;
@end
)cpp";
EXPECT_DECLS("ObjCInterfaceTypeLoc", "@interface MYObject");
Code = R"cpp(
@interface MYObject2
@end
@interface Interface
@property(retain, nonnull) [[MYObject2]] *x;
@end
)cpp";
EXPECT_DECLS("ObjCInterfaceTypeLoc", "@interface MYObject2");
Code = R"cpp(
@protocol Foo
@end

View File

@ -1991,6 +1991,34 @@ TEST(Hover, All) {
HI.NamespaceScope = "ObjC::"; // FIXME: fix it
HI.Definition = "char data";
}},
{
R"cpp(
@interface MYObject
@end
@interface Interface
@property(retain) [[MYOb^ject]] *x;
@end
)cpp",
[](HoverInfo &HI) {
HI.Name = "MYObject";
HI.Kind = index::SymbolKind::Class;
HI.NamespaceScope = "";
HI.Definition = "@interface MYObject\n@end";
}},
{
R"cpp(
@interface MYObject
@end
@interface Interface
- (void)doWith:([[MYOb^ject]] *)object;
@end
)cpp",
[](HoverInfo &HI) {
HI.Name = "MYObject";
HI.Kind = index::SymbolKind::Class;
HI.NamespaceScope = "";
HI.Definition = "@interface MYObject\n@end";
}},
};
// Create a tiny index, so tests above can verify documentation is fetched.

View File

@ -356,6 +356,22 @@ TEST(SelectionTest, CommonAncestor) {
)cpp",
"DeclRefExpr"},
// Objective-C nullability attributes.
{
R"cpp(
@interface I{}
@property(nullable) [[^I]] *x;
@end
)cpp",
"ObjCInterfaceTypeLoc"},
{
R"cpp(
@interface I{}
- (void)doSomething:(nonnull [[i^d]])argument;
@end
)cpp",
"TypedefTypeLoc"},
// Objective-C OpaqueValueExpr/PseudoObjectExpr has weird ASTs.
// Need to traverse the contents of the OpaqueValueExpr to the POE,
// and ensure we traverse only the syntactic form of the PseudoObjectExpr.