@@ -1098,6 +1098,50 @@ class SignatureHelpCollector final : public CodeCompleteConsumer {
1098
1098
const SymbolIndex *Index;
1099
1099
}; // SignatureHelpCollector
1100
1100
1101
+ // Used only for completion of C-style comments in function call (i.e.
1102
+ // /*foo=*/7). Similar to SignatureHelpCollector, but needs to do less work.
1103
+ class ParamNameCollector final : public CodeCompleteConsumer {
1104
+ public:
1105
+ ParamNameCollector (const clang::CodeCompleteOptions &CodeCompleteOpts,
1106
+ std::set<std::string> &ParamNames)
1107
+ : CodeCompleteConsumer(CodeCompleteOpts),
1108
+ Allocator (std::make_shared<clang::GlobalCodeCompletionAllocator>()),
1109
+ CCTUInfo(Allocator), ParamNames(ParamNames) {}
1110
+
1111
+ void ProcessOverloadCandidates (Sema &S, unsigned CurrentArg,
1112
+ OverloadCandidate *Candidates,
1113
+ unsigned NumCandidates,
1114
+ SourceLocation OpenParLoc) override {
1115
+ assert (CurrentArg <= (unsigned )std::numeric_limits<int >::max () &&
1116
+ " too many arguments" );
1117
+
1118
+ for (unsigned I = 0 ; I < NumCandidates; ++I) {
1119
+ OverloadCandidate Candidate = Candidates[I];
1120
+ auto *Func = Candidate.getFunction ();
1121
+ if (!Func || Func->getNumParams () <= CurrentArg)
1122
+ continue ;
1123
+ auto *PVD = Func->getParamDecl (CurrentArg);
1124
+ if (!PVD)
1125
+ continue ;
1126
+ auto *Ident = PVD->getIdentifier ();
1127
+ if (!Ident)
1128
+ continue ;
1129
+ auto Name = Ident->getName ();
1130
+ if (!Name.empty ())
1131
+ ParamNames.insert (Name.str ());
1132
+ }
1133
+ }
1134
+
1135
+ private:
1136
+ GlobalCodeCompletionAllocator &getAllocator () override { return *Allocator; }
1137
+
1138
+ CodeCompletionTUInfo &getCodeCompletionTUInfo () override { return CCTUInfo; }
1139
+
1140
+ std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
1141
+ CodeCompletionTUInfo CCTUInfo;
1142
+ std::set<std::string> &ParamNames;
1143
+ };
1144
+
1101
1145
struct SemaCompleteInput {
1102
1146
PathRef FileName;
1103
1147
size_t Offset;
@@ -1860,6 +1904,59 @@ CompletionPrefix guessCompletionPrefix(llvm::StringRef Content,
1860
1904
return Result;
1861
1905
}
1862
1906
1907
+ // Code complete the argument name on "/*" inside function call.
1908
+ // Offset should be pointing to the start of the comment, i.e.:
1909
+ // foo(^/*, rather than foo(/*^) where the cursor probably is.
1910
+ CodeCompleteResult codeCompleteComment (PathRef FileName, unsigned Offset,
1911
+ llvm::StringRef Prefix,
1912
+ const PreambleData *Preamble,
1913
+ const ParseInputs &ParseInput) {
1914
+ if (Preamble == nullptr ) // Can't run without Sema.
1915
+ return CodeCompleteResult ();
1916
+
1917
+ clang::CodeCompleteOptions Options;
1918
+ Options.IncludeGlobals = false ;
1919
+ Options.IncludeMacros = false ;
1920
+ Options.IncludeCodePatterns = false ;
1921
+ Options.IncludeBriefComments = false ;
1922
+ std::set<std::string> ParamNames;
1923
+ // We want to see signatures coming from newly introduced includes, hence a
1924
+ // full patch.
1925
+ semaCodeComplete (
1926
+ std::make_unique<ParamNameCollector>(Options, ParamNames), Options,
1927
+ {FileName, Offset, *Preamble,
1928
+ PreamblePatch::createFullPatch (FileName, ParseInput, *Preamble),
1929
+ ParseInput});
1930
+ if (ParamNames.empty ())
1931
+ return CodeCompleteResult ();
1932
+
1933
+ CodeCompleteResult Result;
1934
+ Result.Context = CodeCompletionContext::CCC_NaturalLanguage;
1935
+ for (llvm::StringRef Name : ParamNames) {
1936
+ if (!Name.startswith (Prefix))
1937
+ continue ;
1938
+ CodeCompletion Item;
1939
+ Item.Name = Name.str () + " =" ;
1940
+ Item.Kind = CompletionItemKind::Text;
1941
+ Result.Completions .push_back (Item);
1942
+ }
1943
+
1944
+ return Result;
1945
+ }
1946
+
1947
+ // If Offset is inside what looks like argument comment (e.g.
1948
+ // "/*^" or "/* foo^"), returns new offset pointing to the start of the /*
1949
+ // (place where semaCodeComplete should run).
1950
+ llvm::Optional<unsigned >
1951
+ maybeFunctionArgumentCommentStart (llvm::StringRef Content) {
1952
+ while (!Content.empty () && isAsciiIdentifierContinue (Content.back ()))
1953
+ Content = Content.drop_back ();
1954
+ Content = Content.rtrim ();
1955
+ if (Content.endswith (" /*" ))
1956
+ return Content.size () - 2 ;
1957
+ return None;
1958
+ }
1959
+
1863
1960
CodeCompleteResult codeComplete (PathRef FileName, Position Pos,
1864
1961
const PreambleData *Preamble,
1865
1962
const ParseInputs &ParseInput,
@@ -1870,6 +1967,19 @@ CodeCompleteResult codeComplete(PathRef FileName, Position Pos,
1870
1967
elog (" Code completion position was invalid {0}" , Offset.takeError ());
1871
1968
return CodeCompleteResult ();
1872
1969
}
1970
+
1971
+ auto Content = llvm::StringRef (ParseInput.Contents ).take_front (*Offset);
1972
+ if (auto OffsetBeforeComment = maybeFunctionArgumentCommentStart (Content)) {
1973
+ // We are doing code completion of a comment, where we currently only
1974
+ // support completing param names in function calls. To do this, we
1975
+ // require information from Sema, but Sema's comment completion stops at
1976
+ // parsing, so we must move back the position before running it, extract
1977
+ // information we need and construct completion items ourselves.
1978
+ auto CommentPrefix = Content.substr (*OffsetBeforeComment + 2 ).trim ();
1979
+ return codeCompleteComment (FileName, *OffsetBeforeComment, CommentPrefix,
1980
+ Preamble, ParseInput);
1981
+ }
1982
+
1873
1983
auto Flow = CodeCompleteFlow (
1874
1984
FileName, Preamble ? Preamble->Includes : IncludeStructure (),
1875
1985
SpecFuzzyFind, Opts);
@@ -2053,7 +2163,8 @@ bool allowImplicitCompletion(llvm::StringRef Content, unsigned Offset) {
2053
2163
Content = Content.substr (Pos + 1 );
2054
2164
2055
2165
// Complete after scope operators.
2056
- if (Content.endswith (" ." ) || Content.endswith (" ->" ) || Content.endswith (" ::" ))
2166
+ if (Content.endswith (" ." ) || Content.endswith (" ->" ) ||
2167
+ Content.endswith (" ::" ) || Content.endswith (" /*" ))
2057
2168
return true ;
2058
2169
// Complete after `#include <` and #include `<foo/`.
2059
2170
if ((Content.endswith (" <" ) || Content.endswith (" \" " ) ||
0 commit comments