55// This file is dual-licensed: you can choose to license it under the University
66// of Illinois Open Source License or the GNU Lesser General Public License. See
77// LICENSE.TXT for details.
8- // ------------------------------------------------------------------------------
8+ //
9+ // ===----------------------------------------------------------------------===//
10+ //
11+ // This is mostly a copy of clang/lib/Interpreter/CodeCompletion.cpp
12+ // TODO: Replace with ReplCodeCompleter
13+ //
14+ // ===----------------------------------------------------------------------===//
915
1016#include " cling/Interpreter/ClingCodeCompleteConsumer.h"
1117
1218#include " clang/AST/ASTImporter.h"
1319#include " clang/AST/DeclLookups.h"
14- #include " clang/Basic/Diagnostic.h"
20+ #include " clang/AST/DeclarationName.h"
21+ #include " clang/AST/ExternalASTSource.h"
22+ #include " clang/Basic/IdentifierTable.h"
1523#include " clang/Frontend/ASTUnit.h"
1624#include " clang/Frontend/CompilerInstance.h"
1725#include " clang/Frontend/FrontendActions.h"
18- #include " clang/Lex/Preprocessor.h"
26+ #include " clang/Lex/PreprocessorOptions.h"
27+ #include " clang/Sema/CodeCompleteConsumer.h"
28+ #include " clang/Sema/CodeCompleteOptions.h"
1929#include " clang/Sema/Sema.h"
2030
2131namespace cling {
22- void ClingCodeCompleteConsumer::ProcessCodeCompleteResults (Sema &SemaRef,
23- CodeCompletionContext Context,
24- CodeCompletionResult *Results,
25- unsigned NumResults) {
26- std::stable_sort (Results, Results + NumResults);
27-
28- StringRef Filter = SemaRef.getPreprocessor ().getCodeCompletionFilter ();
29-
30- for (unsigned I = 0 ; I != NumResults; ++I) {
31- if (!Filter.empty () && isResultFilteredOut (Filter, Results[I]))
32- continue ;
33- switch (Results[I].Kind ) {
34- case CodeCompletionResult::RK_Declaration:
35- if (CodeCompletionString *CCS
36- = Results[I].CreateCodeCompletionString (SemaRef, Context,
37- getAllocator (),
38- m_CCTUInfo,
39- includeBriefComments ())) {
40- m_Completions.push_back (CCS ->getAsString ());
32+ const std::string CodeCompletionFileName = " input_line_[Completion]" ;
33+
34+ clang::CodeCompleteOptions getClangCompleteOpts () {
35+ clang::CodeCompleteOptions Opts;
36+ Opts.IncludeCodePatterns = true ;
37+ Opts.IncludeMacros = true ;
38+ Opts.IncludeGlobals = true ;
39+ Opts.IncludeBriefComments = true ;
40+ return Opts;
41+ }
42+
43+ // / Create a new printing code-completion consumer that prints its
44+ // / results to the given raw output stream.
45+ class ClingCompletionConsumer : public clang ::CodeCompleteConsumer {
46+ public:
47+ ClingCompletionConsumer (std::vector<std::string>& Results,
48+ ClingCodeCompleter& CC )
49+ : CodeCompleteConsumer(getClangCompleteOpts()),
50+ CCAllocator (std::make_shared<GlobalCodeCompletionAllocator>()),
51+ CCTUInfo(CCAllocator), Results(Results), CC(CC ) {}
52+
53+ // The entry of handling code completion. When the function is called, we
54+ // create a `Context`-based handler (see classes defined below) to handle
55+ // each completion result.
56+ void ProcessCodeCompleteResults (class Sema & S,
57+ CodeCompletionContext Context,
58+ CodeCompletionResult* InResults,
59+ unsigned NumResults) final ;
60+
61+ CodeCompletionAllocator& getAllocator () override { return *CCAllocator; }
62+
63+ CodeCompletionTUInfo& getCodeCompletionTUInfo () override {
64+ return CCTUInfo;
65+ }
66+
67+ private:
68+ std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
69+ CodeCompletionTUInfo CCTUInfo;
70+ std::vector<std::string>& Results;
71+ ClingCodeCompleter& CC ;
72+ };
73+
74+ // / The class CompletionContextHandler contains four interfaces, each of
75+ // / which handles one type of completion result.
76+ // / Its derived classes are used to create concrete handlers based on
77+ // / \c CodeCompletionContext.
78+ class CompletionContextHandler {
79+ protected:
80+ CodeCompletionContext CCC ;
81+ std::vector<std::string>& Results;
82+
83+ private:
84+ Sema& S;
85+
86+ public:
87+ CompletionContextHandler (Sema& S, CodeCompletionContext CCC ,
88+ std::vector<std::string>& Results)
89+ : CCC (CCC ), Results(Results), S(S) {}
90+
91+ virtual ~CompletionContextHandler () = default ;
92+ // / Converts a Declaration completion result to a completion string, and
93+ // / then stores it in Results.
94+ virtual void handleDeclaration (const CodeCompletionResult& Result) {
95+ auto PreferredType = CCC .getPreferredType ();
96+ if (PreferredType.isNull ()) {
97+ Results.push_back (Result.Declaration ->getName ().str ());
98+ return ;
99+ }
100+
101+ if (auto * VD = dyn_cast<VarDecl>(Result.Declaration )) {
102+ auto ArgumentType = VD ->getType ();
103+ if (PreferredType->isReferenceType ()) {
104+ QualType RT =
105+ PreferredType->castAs <ReferenceType>()->getPointeeType ();
106+ Sema::ReferenceConversions RefConv;
107+ Sema::ReferenceCompareResult RefRelationship =
108+ S.CompareReferenceRelationship (SourceLocation (), RT , ArgumentType,
109+ &RefConv);
110+ switch (RefRelationship) {
111+ case Sema::Ref_Compatible:
112+ case Sema::Ref_Related:
113+ Results.push_back (VD ->getName ().str ());
114+ break ;
115+ case Sema::Ref_Incompatible: break ;
41116 }
42- break ;
117+ } else if (S.Context .hasSameType (ArgumentType, PreferredType)) {
118+ Results.push_back (VD ->getName ().str ());
119+ }
120+ }
121+ }
43122
44- case CodeCompletionResult::RK_Keyword:
45- m_Completions.push_back (Results[I].Keyword );
46- break ;
123+ // / Converts a Keyword completion result to a completion string, and then
124+ // / stores it in Results.
125+ virtual void handleKeyword (const CodeCompletionResult& Result) {
126+ auto Prefix = S.getPreprocessor ().getCodeCompletionFilter ();
127+ // Add keyword to the completion results only if we are in a type-aware
128+ // situation.
129+ if (!CCC .getBaseType ().isNull () || !CCC .getPreferredType ().isNull ())
130+ return ;
131+ if (StringRef (Result.Keyword ).starts_with (Prefix))
132+ Results.push_back (Result.Keyword );
133+ }
47134
48- case CodeCompletionResult::RK_Macro:
49- if (CodeCompletionString *CCS
50- = Results[I].CreateCodeCompletionString (SemaRef, Context,
51- getAllocator (),
52- m_CCTUInfo,
53- includeBriefComments ())) {
54- m_Completions.push_back (CCS ->getAsString ());
135+ // / Converts a Pattern completion result to a completion string, and then
136+ // / stores it in Results.
137+ virtual void handlePattern (const CodeCompletionResult& Result) {}
138+
139+ // / Converts a Macro completion result to a completion string, and then
140+ // / stores it in Results.
141+ virtual void handleMacro (const CodeCompletionResult& Result) {}
142+ };
143+
144+ class DotMemberAccessHandler : public CompletionContextHandler {
145+ public:
146+ DotMemberAccessHandler (Sema& S, CodeCompletionContext CCC ,
147+ std::vector<std::string>& Results)
148+ : CompletionContextHandler(S, CCC , Results) {}
149+ void handleDeclaration (const CodeCompletionResult& Result) override {
150+ auto * ID = Result.Declaration ->getIdentifier ();
151+ if (!ID )
152+ return ;
153+ if (!isa<CXXMethodDecl>(Result.Declaration ))
154+ return ;
155+ const auto * Fun = cast<CXXMethodDecl>(Result.Declaration );
156+ if (Fun->getParent ()->getCanonicalDecl () ==
157+ CCC .getBaseType ()->getAsCXXRecordDecl ()->getCanonicalDecl ()) {
158+ Results.push_back (ID ->getName ().str ());
159+ }
160+ }
161+
162+ void handleKeyword (const CodeCompletionResult& Result) override {}
163+ };
164+
165+ void ClingCompletionConsumer::ProcessCodeCompleteResults (
166+ class Sema & S, CodeCompletionContext Context,
167+ CodeCompletionResult* InResults, unsigned NumResults) {
168+
169+ auto Prefix = S.getPreprocessor ().getCodeCompletionFilter ();
170+ CC .Prefix = Prefix;
171+
172+ std::unique_ptr<CompletionContextHandler> CCH ;
173+
174+ // initialize fine-grained code completion handler based on the code
175+ // completion context.
176+ switch (Context.getKind ()) {
177+ case CodeCompletionContext::CCC_DotMemberAccess:
178+ CCH .reset (new DotMemberAccessHandler (S, Context, this ->Results ));
179+ break ;
180+ default :
181+ CCH .reset (new CompletionContextHandler (S, Context, this ->Results ));
182+ };
183+
184+ for (unsigned I = 0 ; I < NumResults; I++) {
185+ auto & Result = InResults[I];
186+ switch (Result.Kind ) {
187+ case CodeCompletionResult::RK_Declaration:
188+ if (Result.Hidden ) {
189+ break ;
190+ }
191+ if (!Result.Declaration ->getDeclName ().isIdentifier () ||
192+ !Result.Declaration ->getName ().starts_with (Prefix)) {
193+ break ;
55194 }
195+ CCH ->handleDeclaration (Result);
56196 break ;
57-
197+ case CodeCompletionResult::RK_Keyword:
198+ CCH ->handleKeyword (Result);
199+ break ;
200+ case CodeCompletionResult::RK_Macro: CCH ->handleMacro (Result); break ;
58201 case CodeCompletionResult::RK_Pattern:
59- m_Completions. push_back (Results[I]. Pattern -> getAsString () );
202+ CCH -> handlePattern (Result );
60203 break ;
61204 }
62205 }
63- }
64206
65- bool ClingCodeCompleteConsumer::isResultFilteredOut (StringRef Filter,
66- CodeCompletionResult Result) {
67- switch (Result.Kind ) {
68- case CodeCompletionResult::RK_Declaration: {
69- return !(
70- Result.Declaration ->getIdentifier () &&
71- Result.Declaration ->getIdentifier ()->getName ().starts_with (Filter));
72- }
73- case CodeCompletionResult::RK_Keyword: {
74- return !((StringRef (Result.Keyword )).starts_with (Filter));
75- }
76- case CodeCompletionResult::RK_Macro: {
77- return !(Result.Macro ->getName ().starts_with (Filter));
78- }
79- case CodeCompletionResult::RK_Pattern: {
80- return !(
81- StringRef ((Result.Pattern ->getAsString ())).starts_with (Filter));
82- }
83- default : llvm_unreachable (" Unknown code completion result Kind." );
84- }
207+ std::sort (Results.begin (), Results.end ());
85208 }
86209
87210 // Code copied from: clang/lib/Interpreter/CodeCompletion.cpp
@@ -235,23 +358,18 @@ namespace cling {
235358 std::vector<std::string>& CCResults) {
236359 const std::string CodeCompletionFileName = " input_line_[Completion]" ;
237360 auto DiagOpts = DiagnosticOptions ();
238- auto consumer =
239- ClingCodeCompleteConsumer (ParentCI->getFrontendOpts ().CodeCompleteOpts ,
240- CCResults);
241- ;
361+ auto consumer = ClingCompletionConsumer (CCResults, *this );
242362
243363 auto diag = InterpCI->getDiagnosticsPtr ();
244- std::unique_ptr<clang::ASTUnit> AU (
245- clang::ASTUnit::LoadFromCompilerInvocationAction (
246- InterpCI->getInvocationPtr (),
247- std::make_shared<PCHContainerOperations>(), diag));
364+ std::unique_ptr<ASTUnit> AU (ASTUnit::LoadFromCompilerInvocationAction (
365+ InterpCI->getInvocationPtr (),
366+ std::make_shared<PCHContainerOperations>(), diag));
248367 llvm::SmallVector<clang::StoredDiagnostic, 8 > sd = {};
249368 llvm::SmallVector<const llvm::MemoryBuffer*, 1 > tb = {};
250369 InterpCI->getFrontendOpts ().Inputs [0 ] =
251370 FrontendInputFile (CodeCompletionFileName, Language::CXX ,
252371 InputKind::Source);
253- auto Act = std::unique_ptr<IncrementalSyntaxOnlyAction>(
254- new IncrementalSyntaxOnlyAction (ParentCI));
372+ auto Act = std::make_unique<IncrementalSyntaxOnlyAction>(ParentCI);
255373 std::unique_ptr<llvm::MemoryBuffer> MB =
256374 llvm::MemoryBuffer::getMemBufferCopy (Content, CodeCompletionFileName);
257375 llvm::SmallVector<ASTUnit::RemappedFile, 4 > RemappedFiles;
@@ -263,7 +381,7 @@ namespace cling {
263381 AU ->CodeComplete (CodeCompletionFileName, 1 , Col, RemappedFiles, false ,
264382 false , false , consumer,
265383 std::make_shared<clang::PCHContainerOperations>(), *diag,
266- InterpCI->getLangOpts (), InterpCI ->getSourceManager (),
267- InterpCI ->getFileManager (), sd, tb, std::move (Act));
384+ InterpCI->getLangOpts (), AU ->getSourceManager (),
385+ AU ->getFileManager (), sd, tb, std::move (Act));
268386 }
269387}
0 commit comments