massberg updated this revision to Diff 537161.
massberg added a comment.
Update code by resolving comments.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D154450/new/
https://reviews.llvm.org/D154450
Files:
clang-tools-extra/clangd/CodeComplete.cpp
clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -3961,26 +3961,51 @@
template<$tparam^A U>
int foo();
+ template<typename T>
+ int bar(T t) requires $expr^A<int>;
+
template<class T>
- concept b = $other^A<T> && $other^sizeof(T) % 2 == 0 || $other^A<T> && sizeof(T) == 1;
+ concept b = $expr^A && $expr^sizeof(T) % 2 == 0 || $expr^A && sizeof(T) == 1;
+
+ $toplevel^A auto i = 19;
- $other^A<T> auto i = 19;
+ template<$toplevel^A auto i> void constrainedNTTP();
)cpp");
TestTU TU;
TU.Code = Code.code().str();
TU.ExtraArgs = {"-std=c++20"};
- std::vector<Symbol> Syms = {conceptSym("same_as")};
+ auto Sym = conceptSym("same_as");
+ Sym.Signature = "<typename Tp, typename Up>";
+ Sym.CompletionSnippetSuffix = "<${1:typename Tp}, ${2:typename Up}>";
+ std::vector<Symbol> Syms = {Sym};
for (auto P : Code.points("tparam")) {
- ASSERT_THAT(completions(TU, P, Syms).Completions,
- AllOf(Contains(named("A")), Contains(named("same_as")),
- Contains(named("class")), Contains(named("typename"))))
+ ASSERT_THAT(
+ completions(TU, P, Syms).Completions,
+ AllOf(Contains(AllOf(named("A"), signature(""), snippetSuffix(""))),
+ Contains(AllOf(named("same_as"), signature("<typename Up>"),
+ snippetSuffix("<${2:typename Up}>"))),
+ Contains(named("class")), Contains(named("typename"))))
<< "Completing template parameter at position " << P;
}
- for (auto P : Code.points("other")) {
- EXPECT_THAT(completions(TU, P, Syms).Completions,
- AllOf(Contains(named("A")), Contains(named("same_as"))))
+ for (auto P : Code.points("toplevel")) {
+ EXPECT_THAT(
+ completions(TU, P, Syms).Completions,
+ AllOf(Contains(AllOf(named("A"), signature(""), snippetSuffix(""))),
+ Contains(AllOf(named("same_as"), signature("<typename Up>"),
+ snippetSuffix("<${2:typename Up}>")))))
+ << "Completing 'requires' expression at position " << P;
+ }
+
+ for (auto P : Code.points("expr")) {
+ EXPECT_THAT(
+ completions(TU, P, Syms).Completions,
+ AllOf(Contains(AllOf(named("A"), signature("<class T>"),
+ snippetSuffix("<${1:class T}>"))),
+ Contains(AllOf(
+ named("same_as"), signature("<typename Tp, typename Up>"),
+ snippetSuffix("<${1:typename Tp}, ${2:typename Up}>")))))
<< "Completing 'requires' expression at position " << P;
}
}
Index: clang-tools-extra/clangd/CodeComplete.cpp
===================================================================
--- clang-tools-extra/clangd/CodeComplete.cpp
+++ clang-tools-extra/clangd/CodeComplete.cpp
@@ -316,6 +316,15 @@
}
};
+// Remove the first template argument from Signature.
+// If Signature only contains a single argument an empty string is returned.
+std::string removeFirstTemplateArg(llvm::StringRef Signature) {
+ auto Rest = Signature.split(",").second;
+ if (Rest.empty())
+ return "";
+ return ("<" + Rest.ltrim()).str();
+}
+
// Assembles a code completion out of a bundle of >=1 completion candidates.
// Many of the expensive strings are only computed at this point, once we know
// the candidate bundle is going to be returned.
@@ -336,7 +345,7 @@
EnableFunctionArgSnippets(Opts.EnableFunctionArgSnippets),
IsUsingDeclaration(IsUsingDeclaration), NextTokenKind(NextTokenKind) {
Completion.Deprecated = true; // cleared by any non-deprecated overload.
- add(C, SemaCCS);
+ add(C, SemaCCS, ContextKind);
if (C.SemaResult) {
assert(ASTCtx);
Completion.Origin |= SymbolOrigin::AST;
@@ -443,21 +452,40 @@
});
}
- void add(const CompletionCandidate &C, CodeCompletionString *SemaCCS) {
+ void add(const CompletionCandidate &C, CodeCompletionString *SemaCCS,
+ CodeCompletionContext::Kind ContextKind) {
assert(bool(C.SemaResult) == bool(SemaCCS));
Bundled.emplace_back();
BundledEntry &S = Bundled.back();
+ bool IsConcept = false;
if (C.SemaResult) {
getSignature(*SemaCCS, &S.Signature, &S.SnippetSuffix, C.SemaResult->Kind,
C.SemaResult->CursorKind, &Completion.RequiredQualifier);
if (!C.SemaResult->FunctionCanBeCall)
S.SnippetSuffix.clear();
S.ReturnType = getReturnType(*SemaCCS);
+ if (C.SemaResult->Kind == CodeCompletionResult::RK_Declaration)
+ if (const auto *D = C.SemaResult->getDeclaration())
+ if (isa<ConceptDecl>(D))
+ IsConcept = true;
} else if (C.IndexResult) {
S.Signature = std::string(C.IndexResult->Signature);
S.SnippetSuffix = std::string(C.IndexResult->CompletionSnippetSuffix);
S.ReturnType = std::string(C.IndexResult->ReturnType);
+ if (C.IndexResult->SymInfo.Kind == index::SymbolKind::Concept)
+ IsConcept = true;
}
+
+ /// When a concept is used as a type-constraint (e.g. `Iterator auto x`),
+ /// and in some other contexts, its first type argument is not written.
+ /// Drop the parameter from the signature.
+ if (IsConcept && ContextKind == CodeCompletionContext::CCC_TopLevel) {
+ S.Signature = removeFirstTemplateArg(S.Signature);
+ // Dropping the first placeholder from the suffix will leave a $2
+ // with no $1.
+ S.SnippetSuffix = removeFirstTemplateArg(S.SnippetSuffix);
+ }
+
if (!Completion.Documentation) {
auto SetDoc = [&](llvm::StringRef Doc) {
if (!Doc.empty()) {
@@ -2020,7 +2048,7 @@
Item, SemaCCS, AccessibleScopes, *Inserter, FileName,
CCContextKind, Opts, IsUsingDeclaration, NextTokenKind);
else
- Builder->add(Item, SemaCCS);
+ Builder->add(Item, SemaCCS, CCContextKind);
}
return Builder->build();
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits