1212
1313#include " clang/Interpreter/CodeCompletion.h"
1414#include " clang/AST/ASTImporter.h"
15+ #include " clang/AST/DeclLookups.h"
1516#include " clang/AST/DeclarationName.h"
1617#include " clang/AST/ExternalASTSource.h"
1718#include " clang/Basic/IdentifierTable.h"
2324#include " clang/Sema/CodeCompleteConsumer.h"
2425#include " clang/Sema/CodeCompleteOptions.h"
2526#include " clang/Sema/Sema.h"
27+ #include " llvm/Support/Debug.h"
28+ #define DEBUG_TYPE " REPLCC"
2629
2730namespace clang {
2831
@@ -39,11 +42,15 @@ clang::CodeCompleteOptions getClangCompleteOpts() {
3942
4043class ReplCompletionConsumer : public CodeCompleteConsumer {
4144public:
42- ReplCompletionConsumer (std::vector<std::string> &Results)
45+ ReplCompletionConsumer (std::vector<std::string> &Results,
46+ ReplCodeCompleter &CC)
4347 : CodeCompleteConsumer(getClangCompleteOpts()),
4448 CCAllocator (std::make_shared<GlobalCodeCompletionAllocator>()),
45- CCTUInfo(CCAllocator), Results(Results){};
49+ CCTUInfo(CCAllocator), Results(Results), CC(CC) {}
4650
51+ // The entry of handling code completion. When the function is called, we
52+ // create a `Context`-based handler (see classes defined below) to handle each
53+ // completion result.
4754 void ProcessCodeCompleteResults (class Sema &S, CodeCompletionContext Context,
4855 CodeCompletionResult *InResults,
4956 unsigned NumResults) final ;
@@ -56,26 +63,146 @@ class ReplCompletionConsumer : public CodeCompleteConsumer {
5663 std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
5764 CodeCompletionTUInfo CCTUInfo;
5865 std::vector<std::string> &Results;
66+ ReplCodeCompleter &CC;
67+ };
68+
69+ // / The class CompletionContextHandler contains four interfaces, each of
70+ // / which handles one type of completion result.
71+ // / Its derived classes are used to create concrete handlers based on
72+ // / \c CodeCompletionContext.
73+ class CompletionContextHandler {
74+ protected:
75+ CodeCompletionContext CCC;
76+ std::vector<std::string> &Results;
77+
78+ private:
79+ Sema &S;
80+
81+ public:
82+ CompletionContextHandler (Sema &S, CodeCompletionContext CCC,
83+ std::vector<std::string> &Results)
84+ : CCC(CCC), Results(Results), S(S) {}
85+
86+ // / Converts a Declaration completion result to a completion string, and then
87+ // / stores it in Results.
88+ virtual void handleDeclaration (const CodeCompletionResult &Result) {
89+ auto PreferredType = CCC.getPreferredType ();
90+ if (PreferredType.isNull ()) {
91+ Results.push_back (Result.Declaration ->getName ().str ());
92+ return ;
93+ }
94+
95+ if (auto *VD = dyn_cast<VarDecl>(Result.Declaration )) {
96+ auto ArgumentType = VD->getType ();
97+ if (PreferredType->isReferenceType ()) {
98+ QualType RT = PreferredType->castAs <ReferenceType>()->getPointeeType ();
99+ Sema::ReferenceConversions RefConv;
100+ Sema::ReferenceCompareResult RefRelationship =
101+ S.CompareReferenceRelationship (SourceLocation (), RT, ArgumentType,
102+ &RefConv);
103+ switch (RefRelationship) {
104+ case Sema::Ref_Compatible:
105+ case Sema::Ref_Related:
106+ Results.push_back (VD->getName ().str ());
107+ break ;
108+ case Sema::Ref_Incompatible:
109+ break ;
110+ }
111+ } else if (S.Context .hasSameType (ArgumentType, PreferredType)) {
112+ Results.push_back (VD->getName ().str ());
113+ }
114+ }
115+ }
116+
117+ // / Converts a Keyword completion result to a completion string, and then
118+ // / stores it in Results.
119+ virtual void handleKeyword (const CodeCompletionResult &Result) {
120+ auto Prefix = S.getPreprocessor ().getCodeCompletionFilter ();
121+ // Add keyword to the completion results only if we are in a type-aware
122+ // situation.
123+ if (!CCC.getBaseType ().isNull () || !CCC.getPreferredType ().isNull ())
124+ return ;
125+ if (StringRef (Result.Keyword ).startswith (Prefix))
126+ Results.push_back (Result.Keyword );
127+ }
128+
129+ // / Converts a Pattern completion result to a completion string, and then
130+ // / stores it in Results.
131+ virtual void handlePattern (const CodeCompletionResult &Result) {}
132+
133+ // / Converts a Macro completion result to a completion string, and then stores
134+ // / it in Results.
135+ virtual void handleMacro (const CodeCompletionResult &Result) {}
136+ };
137+
138+ class DotMemberAccessHandler : public CompletionContextHandler {
139+ public:
140+ DotMemberAccessHandler (Sema &S, CodeCompletionContext CCC,
141+ std::vector<std::string> &Results)
142+ : CompletionContextHandler(S, CCC, Results) {}
143+ void handleDeclaration (const CodeCompletionResult &Result) override {
144+ auto *ID = Result.Declaration ->getIdentifier ();
145+ if (!ID)
146+ return ;
147+ if (!isa<CXXMethodDecl>(Result.Declaration ))
148+ return ;
149+ const auto *Fun = cast<CXXMethodDecl>(Result.Declaration );
150+ if (Fun->getParent ()->getCanonicalDecl () ==
151+ CCC.getBaseType ()->getAsCXXRecordDecl ()->getCanonicalDecl ()) {
152+ LLVM_DEBUG (llvm::dbgs () << " [In HandleCodeCompleteDOT] Name : "
153+ << ID->getName () << " \n " );
154+ Results.push_back (ID->getName ().str ());
155+ }
156+ }
157+
158+ void handleKeyword (const CodeCompletionResult &Result) override {}
59159};
60160
61161void ReplCompletionConsumer::ProcessCodeCompleteResults (
62162 class Sema &S, CodeCompletionContext Context,
63163 CodeCompletionResult *InResults, unsigned NumResults) {
64- for (unsigned I = 0 ; I < NumResults; ++I) {
164+
165+ auto Prefix = S.getPreprocessor ().getCodeCompletionFilter ();
166+ CC.Prefix = Prefix;
167+
168+ std::unique_ptr<CompletionContextHandler> CCH;
169+
170+ // initialize fine-grained code completion handler based on the code
171+ // completion context.
172+ switch (Context.getKind ()) {
173+ case CodeCompletionContext::CCC_DotMemberAccess:
174+ CCH.reset (new DotMemberAccessHandler (S, Context, this ->Results ));
175+ break ;
176+ default :
177+ CCH.reset (new CompletionContextHandler (S, Context, this ->Results ));
178+ };
179+
180+ for (unsigned I = 0 ; I < NumResults; I++) {
65181 auto &Result = InResults[I];
66182 switch (Result.Kind ) {
67183 case CodeCompletionResult::RK_Declaration:
68- if (auto *ID = Result.Declaration ->getIdentifier ()) {
69- Results.push_back (ID->getName ().str ());
184+ if (Result.Hidden ) {
185+ break ;
186+ }
187+ if (!Result.Declaration ->getDeclName ().isIdentifier () ||
188+ !Result.Declaration ->getName ().startswith (Prefix)) {
189+ break ;
70190 }
191+ CCH->handleDeclaration (Result);
71192 break ;
72193 case CodeCompletionResult::RK_Keyword:
73- Results. push_back (Result. Keyword );
194+ CCH-> handleKeyword (Result);
74195 break ;
75- default :
196+ case CodeCompletionResult::RK_Macro:
197+ CCH->handleMacro (Result);
198+ break ;
199+ case CodeCompletionResult::RK_Pattern:
200+ CCH->handlePattern (Result);
76201 break ;
77202 }
78203 }
204+
205+ std::sort (Results.begin (), Results.end ());
79206}
80207
81208class IncrementalSyntaxOnlyAction : public SyntaxOnlyAction {
@@ -118,6 +245,16 @@ void IncrementalSyntaxOnlyAction::ExecuteAction() {
118245 CI.getASTContext ().getTranslationUnitDecl ()->setHasExternalVisibleStorage (
119246 true );
120247
248+ // Load all external decls into current context. Under the hood, it calls
249+ // ExternalSource::completeVisibleDeclsMap, which make all decls on the redecl
250+ // chain visible.
251+ //
252+ // This is crucial to code completion on dot members, since a bound variable
253+ // before "." would be otherwise treated out-of-scope.
254+ //
255+ // clang-repl> Foo f1;
256+ // clang-repl> f1.<tab>
257+ CI.getASTContext ().getTranslationUnitDecl ()->lookups ();
121258 SyntaxOnlyAction::ExecuteAction ();
122259}
123260
@@ -134,6 +271,7 @@ ExternalSource::ExternalSource(ASTContext &ChildASTCtxt, FileManager &ChildFM,
134271
135272bool ExternalSource::FindExternalVisibleDeclsByName (const DeclContext *DC,
136273 DeclarationName Name) {
274+
137275 IdentifierTable &ParentIdTable = ParentASTCtxt.Idents ;
138276
139277 auto ParentDeclName =
@@ -159,29 +297,67 @@ void ExternalSource::completeVisibleDeclsMap(
159297 for (auto *DeclCtxt = ParentTUDeclCtxt; DeclCtxt != nullptr ;
160298 DeclCtxt = DeclCtxt->getPreviousDecl ()) {
161299 for (auto &IDeclContext : DeclCtxt->decls ()) {
162- if (NamedDecl *Decl = llvm::dyn_cast<NamedDecl>(IDeclContext)) {
163- if (auto DeclOrErr = Importer->Import (Decl)) {
164- if (NamedDecl *importedNamedDecl =
165- llvm::dyn_cast<NamedDecl>(*DeclOrErr)) {
166- SetExternalVisibleDeclsForName (ChildDeclContext,
167- importedNamedDecl->getDeclName (),
168- importedNamedDecl);
169- }
170-
171- } else {
172- llvm::consumeError (DeclOrErr.takeError ());
173- }
300+ if (!llvm::isa<NamedDecl>(IDeclContext))
301+ continue ;
302+
303+ NamedDecl *Decl = llvm::cast<NamedDecl>(IDeclContext);
304+
305+ auto DeclOrErr = Importer->Import (Decl);
306+ if (!DeclOrErr) {
307+ // if an error happens, it usually means the decl has already been
308+ // imported or the decl is a result of a failed import. But in our
309+ // case, every import is fresh each time code completion is
310+ // triggered. So Import usually doesn't fail. If it does, it just means
311+ // the related decl can't be used in code completion and we can safely
312+ // drop it.
313+ llvm::consumeError (DeclOrErr.takeError ());
314+ continue ;
174315 }
316+
317+ if (!llvm::isa<NamedDecl>(*DeclOrErr))
318+ continue ;
319+
320+ NamedDecl *importedNamedDecl = llvm::cast<NamedDecl>(*DeclOrErr);
321+
322+ SetExternalVisibleDeclsForName (ChildDeclContext,
323+ importedNamedDecl->getDeclName (),
324+ importedNamedDecl);
325+
326+ if (!llvm::isa<CXXRecordDecl>(importedNamedDecl))
327+ continue ;
328+
329+ auto *Record = llvm::cast<CXXRecordDecl>(importedNamedDecl);
330+
331+ if (auto Err = Importer->ImportDefinition (Decl)) {
332+ // the same as above
333+ consumeError (std::move (Err));
334+ continue ;
335+ }
336+
337+ Record->setHasLoadedFieldsFromExternalStorage (true );
338+ LLVM_DEBUG (llvm::dbgs ()
339+ << " \n CXXRecrod : " << Record->getName () << " size(methods): "
340+ << std::distance (Record->method_begin (), Record->method_end ())
341+ << " has def?: " << Record->hasDefinition ()
342+ << " # (methods): "
343+ << std::distance (Record->getDefinition ()->method_begin (),
344+ Record->getDefinition ()->method_end ())
345+ << " \n " );
346+ for (auto *Meth : Record->methods ())
347+ SetExternalVisibleDeclsForName (ChildDeclContext, Meth->getDeclName (),
348+ Meth);
175349 }
176350 ChildDeclContext->setHasExternalLexicalStorage (false );
177351 }
178352}
179353
180- void codeComplete (CompilerInstance *InterpCI, llvm::StringRef Content,
181- unsigned Line, unsigned Col, const CompilerInstance *ParentCI,
182- std::vector<std::string> &CCResults) {
354+ void ReplCodeCompleter::codeComplete (CompilerInstance *InterpCI,
355+ llvm::StringRef Content, unsigned Line,
356+ unsigned Col,
357+ const CompilerInstance *ParentCI,
358+ std::vector<std::string> &CCResults) {
183359 auto DiagOpts = DiagnosticOptions ();
184- auto consumer = ReplCompletionConsumer (CCResults);
360+ auto consumer = ReplCompletionConsumer (CCResults, * this );
185361
186362 auto diag = InterpCI->getDiagnosticsPtr ();
187363 std::unique_ptr<ASTUnit> AU (ASTUnit::LoadFromCompilerInvocationAction (
0 commit comments