mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 22:00:10 +00:00
[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
This commit is contained in:
parent
9fdde69f72
commit
a42ce094d9
@ -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 @@ private:
|
||||
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();
|
||||
|
@ -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;
|
||||
|
@ -333,7 +333,10 @@ public:
|
||||
|
||||
/// 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>;
|
||||
|
@ -13429,6 +13429,7 @@ public:
|
||||
ArrayRef<IdentifierLocPair> Protocols);
|
||||
void CodeCompleteObjCProtocolDecl(Scope *S);
|
||||
void CodeCompleteObjCInterfaceDecl(Scope *S);
|
||||
void CodeCompleteObjCClassForwardDecl(Scope *S);
|
||||
void CodeCompleteObjCSuperclass(Scope *S,
|
||||
IdentifierInfo *ClassName,
|
||||
SourceLocation ClassNameLoc);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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!");
|
||||
}
|
||||
|
@ -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(),
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user