Skip to content

Commit a42ce09

Browse files
committed
[clang][Sema] Add CodeCompletionContext::CCC_ObjCClassForwardDecl
- Use this new context in Sema to limit completions to seen ObjC class names - Use this new context in clangd to disable include insertions when completing ObjC forward decls Reviewed By: kadircet Differential Revision: https://reviews.llvm.org/D150978
1 parent 9fdde69 commit a42ce09

File tree

9 files changed

+72
-8
lines changed

9 files changed

+72
-8
lines changed

clang-tools-extra/clangd/CodeComplete.cpp

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,8 @@ struct CompletionCandidate {
214214
// Returns a token identifying the overload set this is part of.
215215
// 0 indicates it's not part of any overload set.
216216
size_t overloadSet(const CodeCompleteOptions &Opts, llvm::StringRef FileName,
217-
IncludeInserter *Inserter) const {
217+
IncludeInserter *Inserter,
218+
CodeCompletionContext::Kind CCContextKind) const {
218219
if (!Opts.BundleOverloads.value_or(false))
219220
return 0;
220221

@@ -223,7 +224,7 @@ struct CompletionCandidate {
223224
// bundle those, so we must resolve the header to be included here.
224225
std::string HeaderForHash;
225226
if (Inserter) {
226-
if (auto Header = headerToInsertIfAllowed(Opts)) {
227+
if (auto Header = headerToInsertIfAllowed(Opts, CCContextKind)) {
227228
if (auto HeaderFile = toHeaderFile(*Header, FileName)) {
228229
if (auto Spelled =
229230
Inserter->calculateIncludePath(*HeaderFile, FileName))
@@ -271,11 +272,21 @@ struct CompletionCandidate {
271272
return 0;
272273
}
273274

275+
bool contextAllowsHeaderInsertion(CodeCompletionContext::Kind Kind) const {
276+
// Explicitly disable insertions for forward declarations since they don't
277+
// reference the declaration.
278+
if (Kind == CodeCompletionContext::CCC_ObjCClassForwardDecl)
279+
return false;
280+
return true;
281+
}
282+
274283
// The best header to include if include insertion is allowed.
275284
std::optional<llvm::StringRef>
276-
headerToInsertIfAllowed(const CodeCompleteOptions &Opts) const {
285+
headerToInsertIfAllowed(const CodeCompleteOptions &Opts,
286+
CodeCompletionContext::Kind ContextKind) const {
277287
if (Opts.InsertIncludes == CodeCompleteOptions::NeverInsert ||
278-
RankedIncludeHeaders.empty())
288+
RankedIncludeHeaders.empty() ||
289+
!contextAllowsHeaderInsertion(ContextKind))
279290
return std::nullopt;
280291
if (SemaResult && SemaResult->Declaration) {
281292
// Avoid inserting new #include if the declaration is found in the current
@@ -401,7 +412,8 @@ struct CodeCompletionBuilder {
401412
std::move(*Spelled),
402413
Includes.shouldInsertInclude(*ResolvedDeclaring, *ResolvedInserted));
403414
};
404-
bool ShouldInsert = C.headerToInsertIfAllowed(Opts).has_value();
415+
bool ShouldInsert =
416+
C.headerToInsertIfAllowed(Opts, ContextKind).has_value();
405417
Symbol::IncludeDirective Directive = insertionDirective(Opts);
406418
// Calculate include paths and edits for all possible headers.
407419
for (const auto &Inc : C.RankedIncludeHeaders) {
@@ -780,6 +792,7 @@ bool contextAllowsIndex(enum CodeCompletionContext::Kind K) {
780792
case CodeCompletionContext::CCC_ObjCInterfaceName:
781793
case CodeCompletionContext::CCC_Symbol:
782794
case CodeCompletionContext::CCC_SymbolOrNewName:
795+
case CodeCompletionContext::CCC_ObjCClassForwardDecl:
783796
return true;
784797
case CodeCompletionContext::CCC_OtherWithMacros:
785798
case CodeCompletionContext::CCC_DotMemberAccess:
@@ -1422,6 +1435,10 @@ bool includeSymbolFromIndex(CodeCompletionContext::Kind Kind,
14221435
else if (Kind == CodeCompletionContext::CCC_ObjCProtocolName)
14231436
// Don't show anything else in ObjC protocol completions.
14241437
return false;
1438+
1439+
if (Kind == CodeCompletionContext::CCC_ObjCClassForwardDecl)
1440+
return Sym.SymInfo.Kind == index::SymbolKind::Class &&
1441+
Sym.SymInfo.Lang == index::SymbolLanguage::ObjC;
14251442
return true;
14261443
}
14271444

@@ -1832,8 +1849,8 @@ class CodeCompleteFlow {
18321849
assert(IdentifierResult);
18331850
C.Name = IdentifierResult->Name;
18341851
}
1835-
if (auto OverloadSet =
1836-
C.overloadSet(Opts, FileName, Inserter ? &*Inserter : nullptr)) {
1852+
if (auto OverloadSet = C.overloadSet(
1853+
Opts, FileName, Inserter ? &*Inserter : nullptr, CCContextKind)) {
18371854
auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size());
18381855
if (Ret.second)
18391856
Bundles.emplace_back();

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3434,6 +3434,20 @@ TEST(CompletionTest, ObjectiveCCategoryFromIndexIgnored) {
34343434
EXPECT_THAT(Results.Completions, IsEmpty());
34353435
}
34363436

3437+
TEST(CompletionTest, ObjectiveCForwardDeclFromIndex) {
3438+
Symbol FoodClass = objcClass("FoodClass");
3439+
FoodClass.IncludeHeaders.emplace_back("\"Foo.h\"", 2, Symbol::Import);
3440+
Symbol SymFood = objcProtocol("Food");
3441+
auto Results = completions("@class Foo^", {SymFood, FoodClass},
3442+
/*Opts=*/{}, "Foo.m");
3443+
3444+
// Should only give class names without any include insertion.
3445+
EXPECT_THAT(Results.Completions,
3446+
UnorderedElementsAre(AllOf(named("FoodClass"),
3447+
kind(CompletionItemKind::Class),
3448+
Not(insertInclude()))));
3449+
}
3450+
34373451
TEST(CompletionTest, CursorInSnippets) {
34383452
clangd::CodeCompleteOptions Options;
34393453
Options.EnableSnippets = true;

clang/include/clang/Sema/CodeCompleteConsumer.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,10 @@ class CodeCompletionContext {
333333

334334
/// An unknown context, in which we are recovering from a parsing
335335
/// error and don't know which completions we should give.
336-
CCC_Recovery
336+
CCC_Recovery,
337+
338+
/// Code completion in a @class forward declaration.
339+
CCC_ObjCClassForwardDecl
337340
};
338341

339342
using VisitedContextSet = llvm::SmallPtrSet<DeclContext *, 8>;

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13429,6 +13429,7 @@ class Sema final {
1342913429
ArrayRef<IdentifierLocPair> Protocols);
1343013430
void CodeCompleteObjCProtocolDecl(Scope *S);
1343113431
void CodeCompleteObjCInterfaceDecl(Scope *S);
13432+
void CodeCompleteObjCClassForwardDecl(Scope *S);
1343213433
void CodeCompleteObjCSuperclass(Scope *S,
1343313434
IdentifierInfo *ClassName,
1343413435
SourceLocation ClassNameLoc);

clang/lib/Frontend/ASTUnit.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ static uint64_t getDeclShowContexts(const NamedDecl *ND,
322322
if (ID->getDefinition())
323323
Contexts |= (1LL << CodeCompletionContext::CCC_Expression);
324324
Contexts |= (1LL << CodeCompletionContext::CCC_ObjCInterfaceName);
325+
Contexts |= (1LL << CodeCompletionContext::CCC_ObjCClassForwardDecl);
325326
}
326327

327328
// Deal with tag names.
@@ -2028,6 +2029,7 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context,
20282029
case CodeCompletionContext::CCC_IncludedFile:
20292030
case CodeCompletionContext::CCC_Attribute:
20302031
case CodeCompletionContext::CCC_NewName:
2032+
case CodeCompletionContext::CCC_ObjCClassForwardDecl:
20312033
// We're looking for nothing, or we're looking for names that cannot
20322034
// be hidden.
20332035
return;

clang/lib/Parse/ParseObjc.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
153153

154154
while (true) {
155155
MaybeSkipAttributes(tok::objc_class);
156+
if (Tok.is(tok::code_completion)) {
157+
cutOffParsing();
158+
Actions.CodeCompleteObjCClassForwardDecl(getCurScope());
159+
return Actions.ConvertDeclToDeclGroup(nullptr);
160+
}
156161
if (expectIdentifier()) {
157162
SkipUntil(tok::semi);
158163
return Actions.ConvertDeclToDeclGroup(nullptr);

clang/lib/Sema/CodeCompleteConsumer.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ bool CodeCompletionContext::wantConstructorResults() const {
8383
case CCC_ObjCCategoryName:
8484
case CCC_IncludedFile:
8585
case CCC_Attribute:
86+
case CCC_ObjCClassForwardDecl:
8687
return false;
8788
}
8889

@@ -166,6 +167,8 @@ StringRef clang::getCompletionKindString(CodeCompletionContext::Kind Kind) {
166167
return "Attribute";
167168
case CCKind::CCC_Recovery:
168169
return "Recovery";
170+
case CCKind::CCC_ObjCClassForwardDecl:
171+
return "ObjCClassForwardDecl";
169172
}
170173
llvm_unreachable("Invalid CodeCompletionContext::Kind!");
171174
}

clang/lib/Sema/SemaCodeComplete.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8460,6 +8460,24 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
84608460
Results.data(), Results.size());
84618461
}
84628462

8463+
void Sema::CodeCompleteObjCClassForwardDecl(Scope *S) {
8464+
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
8465+
CodeCompleter->getCodeCompletionTUInfo(),
8466+
CodeCompletionContext::CCC_ObjCClassForwardDecl);
8467+
Results.EnterNewScope();
8468+
8469+
if (CodeCompleter->includeGlobals()) {
8470+
// Add all classes.
8471+
AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false,
8472+
false, Results);
8473+
}
8474+
8475+
Results.ExitScope();
8476+
8477+
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
8478+
Results.data(), Results.size());
8479+
}
8480+
84638481
void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
84648482
SourceLocation ClassNameLoc) {
84658483
ResultBuilder Results(*this, CodeCompleter->getAllocator(),

clang/tools/libclang/CIndexCodeCompletion.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ static unsigned long long getContextsForContextKind(
537537
case CodeCompletionContext::CCC_Other:
538538
case CodeCompletionContext::CCC_ObjCInterface:
539539
case CodeCompletionContext::CCC_ObjCImplementation:
540+
case CodeCompletionContext::CCC_ObjCClassForwardDecl:
540541
case CodeCompletionContext::CCC_NewName:
541542
case CodeCompletionContext::CCC_MacroName:
542543
case CodeCompletionContext::CCC_PreprocessorExpression:

0 commit comments

Comments
 (0)