diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp --- a/clang-tools-extra/clangd/Selection.cpp +++ b/clang-tools-extra/clangd/Selection.cpp @@ -604,19 +604,11 @@ // don't intersect the selection may be recursively skipped. bool canSafelySkipNode(const DynTypedNode &N) { SourceRange S = N.getSourceRange(); - if (auto *TL = N.get()) { - // 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 (auto DT = TL->getAs()) - S.setEnd(DT.getUnderlyingExpr()->getEndLoc()); - } + if (auto *TL = N.get()) + // TypeLoc::getBeginLoc()/getEndLoc() are pretty fragile heuristics. + // We might consider only pruning critical TypeLoc nodes, to be more + // robust. + return false; if (!SelChecker.mayHit(S)) { dlog("{1}skip: {0}", printNodeToString(N, PrintPolicy), indent()); dlog("{1}skipped range = {0}", S.printToString(SM), indent(1)); diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -820,6 +820,24 @@ 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 diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -1991,6 +1991,34 @@ 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. diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -356,6 +356,22 @@ )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.