forked from OSchip/llvm-project
[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:
parent
343410d1cc
commit
d5c022d846
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue