[clang-tools-extra] a42ce09 - [clang][Sema] Add CodeCompletionContext::CCC_ObjCClassForwardDecl
David Goldman via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 27 13:26:21 PDT 2023
Author: David Goldman
Date: 2023-06-27T16:25:40-04:00
New Revision: a42ce094d90341f88a845740b2e5783060f23e3e
URL: https://github.com/llvm/llvm-project/commit/a42ce094d90341f88a845740b2e5783060f23e3e
DIFF: https://github.com/llvm/llvm-project/commit/a42ce094d90341f88a845740b2e5783060f23e3e.diff
LOG: [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
Added:
Modified:
clang-tools-extra/clangd/CodeComplete.cpp
clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
clang/include/clang/Sema/CodeCompleteConsumer.h
clang/include/clang/Sema/Sema.h
clang/lib/Frontend/ASTUnit.cpp
clang/lib/Parse/ParseObjc.cpp
clang/lib/Sema/CodeCompleteConsumer.cpp
clang/lib/Sema/SemaCodeComplete.cpp
clang/tools/libclang/CIndexCodeCompletion.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index f4f93a01ec90e..70f2634aa7763 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -214,7 +214,8 @@ struct CompletionCandidate {
// Returns a token identifying the overload set this is part of.
// 0 indicates it's not part of any overload set.
size_t overloadSet(const CodeCompleteOptions &Opts, llvm::StringRef FileName,
- IncludeInserter *Inserter) const {
+ IncludeInserter *Inserter,
+ CodeCompletionContext::Kind CCContextKind) const {
if (!Opts.BundleOverloads.value_or(false))
return 0;
@@ -223,7 +224,7 @@ struct CompletionCandidate {
// bundle those, so we must resolve the header to be included here.
std::string HeaderForHash;
if (Inserter) {
- if (auto Header = headerToInsertIfAllowed(Opts)) {
+ if (auto Header = headerToInsertIfAllowed(Opts, CCContextKind)) {
if (auto HeaderFile = toHeaderFile(*Header, FileName)) {
if (auto Spelled =
Inserter->calculateIncludePath(*HeaderFile, FileName))
@@ -271,11 +272,21 @@ struct CompletionCandidate {
return 0;
}
+ bool contextAllowsHeaderInsertion(CodeCompletionContext::Kind Kind) const {
+ // Explicitly disable insertions for forward declarations since they don't
+ // reference the declaration.
+ if (Kind == CodeCompletionContext::CCC_ObjCClassForwardDecl)
+ return false;
+ return true;
+ }
+
// The best header to include if include insertion is allowed.
std::optional<llvm::StringRef>
- headerToInsertIfAllowed(const CodeCompleteOptions &Opts) const {
+ headerToInsertIfAllowed(const CodeCompleteOptions &Opts,
+ CodeCompletionContext::Kind ContextKind) const {
if (Opts.InsertIncludes == CodeCompleteOptions::NeverInsert ||
- RankedIncludeHeaders.empty())
+ RankedIncludeHeaders.empty() ||
+ !contextAllowsHeaderInsertion(ContextKind))
return std::nullopt;
if (SemaResult && SemaResult->Declaration) {
// Avoid inserting new #include if the declaration is found in the current
@@ -401,7 +412,8 @@ struct CodeCompletionBuilder {
std::move(*Spelled),
Includes.shouldInsertInclude(*ResolvedDeclaring, *ResolvedInserted));
};
- bool ShouldInsert = C.headerToInsertIfAllowed(Opts).has_value();
+ bool ShouldInsert =
+ C.headerToInsertIfAllowed(Opts, ContextKind).has_value();
Symbol::IncludeDirective Directive = insertionDirective(Opts);
// Calculate include paths and edits for all possible headers.
for (const auto &Inc : C.RankedIncludeHeaders) {
@@ -780,6 +792,7 @@ bool contextAllowsIndex(enum CodeCompletionContext::Kind K) {
case CodeCompletionContext::CCC_ObjCInterfaceName:
case CodeCompletionContext::CCC_Symbol:
case CodeCompletionContext::CCC_SymbolOrNewName:
+ case CodeCompletionContext::CCC_ObjCClassForwardDecl:
return true;
case CodeCompletionContext::CCC_OtherWithMacros:
case CodeCompletionContext::CCC_DotMemberAccess:
@@ -1422,6 +1435,10 @@ bool includeSymbolFromIndex(CodeCompletionContext::Kind Kind,
else if (Kind == CodeCompletionContext::CCC_ObjCProtocolName)
// Don't show anything else in ObjC protocol completions.
return false;
+
+ if (Kind == CodeCompletionContext::CCC_ObjCClassForwardDecl)
+ return Sym.SymInfo.Kind == index::SymbolKind::Class &&
+ Sym.SymInfo.Lang == index::SymbolLanguage::ObjC;
return true;
}
@@ -1832,8 +1849,8 @@ class CodeCompleteFlow {
assert(IdentifierResult);
C.Name = IdentifierResult->Name;
}
- if (auto OverloadSet =
- C.overloadSet(Opts, FileName, Inserter ? &*Inserter : nullptr)) {
+ if (auto OverloadSet = C.overloadSet(
+ Opts, FileName, Inserter ? &*Inserter : nullptr, CCContextKind)) {
auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size());
if (Ret.second)
Bundles.emplace_back();
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index fc330a4b8fd3f..653408b57d927 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -3434,6 +3434,20 @@ TEST(CompletionTest, ObjectiveCCategoryFromIndexIgnored) {
EXPECT_THAT(Results.Completions, IsEmpty());
}
+TEST(CompletionTest, ObjectiveCForwardDeclFromIndex) {
+ Symbol FoodClass = objcClass("FoodClass");
+ FoodClass.IncludeHeaders.emplace_back("\"Foo.h\"", 2, Symbol::Import);
+ Symbol SymFood = objcProtocol("Food");
+ auto Results = completions("@class Foo^", {SymFood, FoodClass},
+ /*Opts=*/{}, "Foo.m");
+
+ // Should only give class names without any include insertion.
+ EXPECT_THAT(Results.Completions,
+ UnorderedElementsAre(AllOf(named("FoodClass"),
+ kind(CompletionItemKind::Class),
+ Not(insertInclude()))));
+}
+
TEST(CompletionTest, CursorInSnippets) {
clangd::CodeCompleteOptions Options;
Options.EnableSnippets = true;
diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h
index a2d523cd3e921..bb4b638050383 100644
--- a/clang/include/clang/Sema/CodeCompleteConsumer.h
+++ b/clang/include/clang/Sema/CodeCompleteConsumer.h
@@ -333,7 +333,10 @@ class CodeCompletionContext {
/// An unknown context, in which we are recovering from a parsing
/// error and don't know which completions we should give.
- CCC_Recovery
+ CCC_Recovery,
+
+ /// Code completion in a @class forward declaration.
+ CCC_ObjCClassForwardDecl
};
using VisitedContextSet = llvm::SmallPtrSet<DeclContext *, 8>;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 04ed1770ab6b4..55d1dcf6ee0c2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13429,6 +13429,7 @@ class Sema final {
ArrayRef<IdentifierLocPair> Protocols);
void CodeCompleteObjCProtocolDecl(Scope *S);
void CodeCompleteObjCInterfaceDecl(Scope *S);
+ void CodeCompleteObjCClassForwardDecl(Scope *S);
void CodeCompleteObjCSuperclass(Scope *S,
IdentifierInfo *ClassName,
SourceLocation ClassNameLoc);
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index a42df66148518..f6a74fcfbd08c 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -322,6 +322,7 @@ static uint64_t getDeclShowContexts(const NamedDecl *ND,
if (ID->getDefinition())
Contexts |= (1LL << CodeCompletionContext::CCC_Expression);
Contexts |= (1LL << CodeCompletionContext::CCC_ObjCInterfaceName);
+ Contexts |= (1LL << CodeCompletionContext::CCC_ObjCClassForwardDecl);
}
// Deal with tag names.
@@ -2028,6 +2029,7 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context,
case CodeCompletionContext::CCC_IncludedFile:
case CodeCompletionContext::CCC_Attribute:
case CodeCompletionContext::CCC_NewName:
+ case CodeCompletionContext::CCC_ObjCClassForwardDecl:
// We're looking for nothing, or we're looking for names that cannot
// be hidden.
return;
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index b21adb17c63ec..b30f0380621a1 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -153,6 +153,11 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
while (true) {
MaybeSkipAttributes(tok::objc_class);
+ if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
+ Actions.CodeCompleteObjCClassForwardDecl(getCurScope());
+ return Actions.ConvertDeclToDeclGroup(nullptr);
+ }
if (expectIdentifier()) {
SkipUntil(tok::semi);
return Actions.ConvertDeclToDeclGroup(nullptr);
diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp
index b91291cfea0b4..202417798712a 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -83,6 +83,7 @@ bool CodeCompletionContext::wantConstructorResults() const {
case CCC_ObjCCategoryName:
case CCC_IncludedFile:
case CCC_Attribute:
+ case CCC_ObjCClassForwardDecl:
return false;
}
@@ -166,6 +167,8 @@ StringRef clang::getCompletionKindString(CodeCompletionContext::Kind Kind) {
return "Attribute";
case CCKind::CCC_Recovery:
return "Recovery";
+ case CCKind::CCC_ObjCClassForwardDecl:
+ return "ObjCClassForwardDecl";
}
llvm_unreachable("Invalid CodeCompletionContext::Kind!");
}
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 8c166570265c1..b5d29b2e956c3 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -8460,6 +8460,24 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
Results.data(), Results.size());
}
+void Sema::CodeCompleteObjCClassForwardDecl(Scope *S) {
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
+ CodeCompletionContext::CCC_ObjCClassForwardDecl);
+ Results.EnterNewScope();
+
+ if (CodeCompleter->includeGlobals()) {
+ // Add all classes.
+ AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false,
+ false, Results);
+ }
+
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+ Results.data(), Results.size());
+}
+
void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
SourceLocation ClassNameLoc) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
diff --git a/clang/tools/libclang/CIndexCodeCompletion.cpp b/clang/tools/libclang/CIndexCodeCompletion.cpp
index d7df36dc7b85d..01bad3d625912 100644
--- a/clang/tools/libclang/CIndexCodeCompletion.cpp
+++ b/clang/tools/libclang/CIndexCodeCompletion.cpp
@@ -537,6 +537,7 @@ static unsigned long long getContextsForContextKind(
case CodeCompletionContext::CCC_Other:
case CodeCompletionContext::CCC_ObjCInterface:
case CodeCompletionContext::CCC_ObjCImplementation:
+ case CodeCompletionContext::CCC_ObjCClassForwardDecl:
case CodeCompletionContext::CCC_NewName:
case CodeCompletionContext::CCC_MacroName:
case CodeCompletionContext::CCC_PreprocessorExpression:
More information about the cfe-commits
mailing list