clang 19.0.0git
CodeCompletion.cpp
Go to the documentation of this file.
1//===------ CodeCompletion.cpp - Code Completion for ClangRepl -------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the classes which performs code completion at the REPL.
10//
11//===----------------------------------------------------------------------===//
12
26#include "clang/Sema/Sema.h"
27#include "llvm/Support/Debug.h"
28#define DEBUG_TYPE "REPLCC"
29
30namespace clang {
31
32const std::string CodeCompletionFileName = "input_line_[Completion]";
33
36 Opts.IncludeCodePatterns = true;
37 Opts.IncludeMacros = true;
38 Opts.IncludeGlobals = true;
39 Opts.IncludeBriefComments = true;
40 return Opts;
41}
42
44public:
45 ReplCompletionConsumer(std::vector<std::string> &Results,
48 CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()),
49 CCTUInfo(CCAllocator), Results(Results), CC(CC) {}
50
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.
55 CodeCompletionResult *InResults,
56 unsigned NumResults) final;
57
58 CodeCompletionAllocator &getAllocator() override { return *CCAllocator; }
59
60 CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
61
62private:
63 std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
64 CodeCompletionTUInfo CCTUInfo;
65 std::vector<std::string> &Results;
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.
74protected:
76 std::vector<std::string> &Results;
77
78private:
79 Sema &S;
80
81public:
83 std::vector<std::string> &Results)
84 : CCC(CCC), Results(Results), S(S) {}
85
86 virtual ~CompletionContextHandler() = default;
87 /// Converts a Declaration completion result to a completion string, and then
88 /// stores it in Results.
90 auto PreferredType = CCC.getPreferredType();
91 if (PreferredType.isNull()) {
92 Results.push_back(Result.Declaration->getName().str());
93 return;
94 }
95
96 if (auto *VD = dyn_cast<VarDecl>(Result.Declaration)) {
97 auto ArgumentType = VD->getType();
98 if (PreferredType->isReferenceType()) {
99 QualType RT = PreferredType->castAs<ReferenceType>()->getPointeeType();
101 Sema::ReferenceCompareResult RefRelationship =
102 S.CompareReferenceRelationship(SourceLocation(), RT, ArgumentType,
103 &RefConv);
104 switch (RefRelationship) {
107 Results.push_back(VD->getName().str());
108 break;
110 break;
111 }
112 } else if (S.Context.hasSameType(ArgumentType, PreferredType)) {
113 Results.push_back(VD->getName().str());
114 }
115 }
116 }
117
118 /// Converts a Keyword completion result to a completion string, and then
119 /// stores it in Results.
121 auto Prefix = S.getPreprocessor().getCodeCompletionFilter();
122 // Add keyword to the completion results only if we are in a type-aware
123 // situation.
125 return;
126 if (StringRef(Result.Keyword).starts_with(Prefix))
127 Results.push_back(Result.Keyword);
128 }
129
130 /// Converts a Pattern completion result to a completion string, and then
131 /// stores it in Results.
133
134 /// Converts a Macro completion result to a completion string, and then stores
135 /// it in Results.
137};
138
140public:
142 std::vector<std::string> &Results)
145 auto *ID = Result.Declaration->getIdentifier();
146 if (!ID)
147 return;
148 if (!isa<CXXMethodDecl>(Result.Declaration))
149 return;
150 const auto *Fun = cast<CXXMethodDecl>(Result.Declaration);
151 if (Fun->getParent()->getCanonicalDecl() ==
153 LLVM_DEBUG(llvm::dbgs() << "[In HandleCodeCompleteDOT] Name : "
154 << ID->getName() << "\n");
155 Results.push_back(ID->getName().str());
156 }
157 }
158
160};
161
163 class Sema &S, CodeCompletionContext Context,
164 CodeCompletionResult *InResults, unsigned NumResults) {
165
166 auto Prefix = S.getPreprocessor().getCodeCompletionFilter();
167 CC.Prefix = Prefix;
168
169 std::unique_ptr<CompletionContextHandler> CCH;
170
171 // initialize fine-grained code completion handler based on the code
172 // completion context.
173 switch (Context.getKind()) {
175 CCH.reset(new DotMemberAccessHandler(S, Context, this->Results));
176 break;
177 default:
178 CCH.reset(new CompletionContextHandler(S, Context, this->Results));
179 };
180
181 for (unsigned I = 0; I < NumResults; I++) {
182 auto &Result = InResults[I];
183 switch (Result.Kind) {
185 if (Result.Hidden) {
186 break;
187 }
188 if (!Result.Declaration->getDeclName().isIdentifier() ||
189 !Result.Declaration->getName().starts_with(Prefix)) {
190 break;
191 }
192 CCH->handleDeclaration(Result);
193 break;
195 CCH->handleKeyword(Result);
196 break;
198 CCH->handleMacro(Result);
199 break;
201 CCH->handlePattern(Result);
202 break;
203 }
204 }
205
206 std::sort(Results.begin(), Results.end());
207}
208
210 const CompilerInstance *ParentCI;
211
212public:
214 : ParentCI(ParentCI) {}
215
216protected:
217 void ExecuteAction() override;
218};
219
221 TranslationUnitDecl *ChildTUDeclCtxt;
222 ASTContext &ParentASTCtxt;
223 TranslationUnitDecl *ParentTUDeclCtxt;
224
225 std::unique_ptr<ASTImporter> Importer;
226
227public:
228 ExternalSource(ASTContext &ChildASTCtxt, FileManager &ChildFM,
229 ASTContext &ParentASTCtxt, FileManager &ParentFM);
231 DeclarationName Name) override;
232 void
233 completeVisibleDeclsMap(const clang::DeclContext *childDeclContext) override;
234};
235
236// This method is intended to set up `ExternalASTSource` to the running
237// compiler instance before the super `ExecuteAction` triggers parsing
240 ExternalSource *myExternalSource =
242 ParentCI->getASTContext(), ParentCI->getFileManager());
244 myExternalSource);
245 CI.getASTContext().setExternalSource(astContextExternalSource);
247 true);
248
249 // Load all external decls into current context. Under the hood, it calls
250 // ExternalSource::completeVisibleDeclsMap, which make all decls on the redecl
251 // chain visible.
252 //
253 // This is crucial to code completion on dot members, since a bound variable
254 // before "." would be otherwise treated out-of-scope.
255 //
256 // clang-repl> Foo f1;
257 // clang-repl> f1.<tab>
260}
261
263 ASTContext &ParentASTCtxt, FileManager &ParentFM)
264 : ChildTUDeclCtxt(ChildASTCtxt.getTranslationUnitDecl()),
265 ParentASTCtxt(ParentASTCtxt),
266 ParentTUDeclCtxt(ParentASTCtxt.getTranslationUnitDecl()) {
267 ASTImporter *importer =
268 new ASTImporter(ChildASTCtxt, ChildFM, ParentASTCtxt, ParentFM,
269 /*MinimalImport : ON*/ true);
270 Importer.reset(importer);
271}
272
274 DeclarationName Name) {
275
276 IdentifierTable &ParentIdTable = ParentASTCtxt.Idents;
277
278 auto ParentDeclName =
279 DeclarationName(&(ParentIdTable.get(Name.getAsString())));
280
281 DeclContext::lookup_result lookup_result =
282 ParentTUDeclCtxt->lookup(ParentDeclName);
283
284 if (!lookup_result.empty()) {
285 return true;
286 }
287 return false;
288}
289
291 const DeclContext *ChildDeclContext) {
292 assert(ChildDeclContext && ChildDeclContext == ChildTUDeclCtxt &&
293 "No child decl context!");
294
295 if (!ChildDeclContext->hasExternalVisibleStorage())
296 return;
297
298 for (auto *DeclCtxt = ParentTUDeclCtxt; DeclCtxt != nullptr;
299 DeclCtxt = DeclCtxt->getPreviousDecl()) {
300 for (auto &IDeclContext : DeclCtxt->decls()) {
301 if (!llvm::isa<NamedDecl>(IDeclContext))
302 continue;
303
304 NamedDecl *Decl = llvm::cast<NamedDecl>(IDeclContext);
305
306 auto DeclOrErr = Importer->Import(Decl);
307 if (!DeclOrErr) {
308 // if an error happens, it usually means the decl has already been
309 // imported or the decl is a result of a failed import. But in our
310 // case, every import is fresh each time code completion is
311 // triggered. So Import usually doesn't fail. If it does, it just means
312 // the related decl can't be used in code completion and we can safely
313 // drop it.
314 llvm::consumeError(DeclOrErr.takeError());
315 continue;
316 }
317
318 if (!llvm::isa<NamedDecl>(*DeclOrErr))
319 continue;
320
321 NamedDecl *importedNamedDecl = llvm::cast<NamedDecl>(*DeclOrErr);
322
323 SetExternalVisibleDeclsForName(ChildDeclContext,
324 importedNamedDecl->getDeclName(),
325 importedNamedDecl);
326
327 if (!llvm::isa<CXXRecordDecl>(importedNamedDecl))
328 continue;
329
330 auto *Record = llvm::cast<CXXRecordDecl>(importedNamedDecl);
331
332 if (auto Err = Importer->ImportDefinition(Decl)) {
333 // the same as above
334 consumeError(std::move(Err));
335 continue;
336 }
337
338 Record->setHasLoadedFieldsFromExternalStorage(true);
339 LLVM_DEBUG(llvm::dbgs()
340 << "\nCXXRecrod : " << Record->getName() << " size(methods): "
341 << std::distance(Record->method_begin(), Record->method_end())
342 << " has def?: " << Record->hasDefinition()
343 << " # (methods): "
344 << std::distance(Record->getDefinition()->method_begin(),
345 Record->getDefinition()->method_end())
346 << "\n");
347 for (auto *Meth : Record->methods())
348 SetExternalVisibleDeclsForName(ChildDeclContext, Meth->getDeclName(),
349 Meth);
350 }
351 ChildDeclContext->setHasExternalLexicalStorage(false);
352 }
353}
354
356 llvm::StringRef Content, unsigned Line,
357 unsigned Col,
358 const CompilerInstance *ParentCI,
359 std::vector<std::string> &CCResults) {
360 auto DiagOpts = DiagnosticOptions();
361 auto consumer = ReplCompletionConsumer(CCResults, *this);
362
363 auto diag = InterpCI->getDiagnosticsPtr();
364 std::unique_ptr<ASTUnit> AU(ASTUnit::LoadFromCompilerInvocationAction(
365 InterpCI->getInvocationPtr(), std::make_shared<PCHContainerOperations>(),
366 diag));
371 auto Act = std::unique_ptr<IncrementalSyntaxOnlyAction>(
372 new IncrementalSyntaxOnlyAction(ParentCI));
373 std::unique_ptr<llvm::MemoryBuffer> MB =
374 llvm::MemoryBuffer::getMemBufferCopy(Content, CodeCompletionFileName);
376
377 RemappedFiles.push_back(std::make_pair(CodeCompletionFileName, MB.get()));
378 // we don't want the AU destructor to release the memory buffer that MB
379 // owns twice, because MB handles its resource on its own.
380 AU->setOwnsRemappedFileBuffers(false);
381 AU->CodeComplete(CodeCompletionFileName, 1, Col, RemappedFiles, false, false,
382 false, consumer,
383 std::make_shared<clang::PCHContainerOperations>(), *diag,
384 InterpCI->getLangOpts(), InterpCI->getSourceManager(),
385 InterpCI->getFileManager(), sd, tb, std::move(Act));
386}
387
388} // namespace clang
static char ID
Definition: Arena.cpp:183
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
llvm::MachO::Record Record
Definition: MachO.h:31
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1073
IdentifierTable & Idents
Definition: ASTContext.h:644
void setExternalSource(IntrusiveRefCntPtr< ExternalASTSource > Source)
Attach an external AST source to the AST context.
Definition: ASTContext.cpp:947
Imports selected nodes from one AST context into another context, merging AST nodes where appropriate...
Definition: ASTImporter.h:62
static ASTUnit * LoadFromCompilerInvocationAction(std::shared_ptr< CompilerInvocation > CI, std::shared_ptr< PCHContainerOperations > PCHContainerOps, IntrusiveRefCntPtr< DiagnosticsEngine > Diags, FrontendAction *Action=nullptr, ASTUnit *Unit=nullptr, bool Persistent=true, StringRef ResourceFilesPath=StringRef(), bool OnlyLocalDecls=false, CaptureDiagsKind CaptureDiagnostics=CaptureDiagsKind::None, unsigned PrecompilePreambleAfterNParses=0, bool CacheCodeCompletionResults=false, bool UserFilesAreVolatile=false, std::unique_ptr< ASTUnit > *ErrAST=nullptr)
Create an ASTUnit from a source file, via a CompilerInvocation object, by invoking the optionally pro...
Definition: ASTUnit.cpp:1549
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclCXX.h:523
Abstract interface for a consumer of code-completion information.
Options controlling the behavior of code completion.
unsigned IncludeCodePatterns
Show code patterns in code completion results.
unsigned IncludeMacros
Show macros in code completion results.
unsigned IncludeBriefComments
Show brief documentation comments in code completion results.
unsigned IncludeGlobals
Show top-level decls in code completion results.
An allocator used specifically for the purpose of code completion.
The context in which code completion occurred, so that the code-completion consumer can process the r...
@ CCC_DotMemberAccess
Code completion occurred on the right-hand side of a member access expression using the dot operator.
QualType getBaseType() const
Retrieve the type of the base object in a member-access expression.
QualType getPreferredType() const
Retrieve the type that this expression would prefer to have, e.g., if the expression is a variable in...
Captures a result of code completion.
@ RK_Pattern
Refers to a precomputed pattern.
@ RK_Declaration
Refers to a declaration.
@ RK_Keyword
Refers to a keyword or symbol.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
FileManager & getFileManager() const
Return the current file manager to the caller.
IntrusiveRefCntPtr< DiagnosticsEngine > getDiagnosticsPtr() const
ASTContext & getASTContext() const
FrontendOptions & getFrontendOpts()
std::shared_ptr< CompilerInvocation > getInvocationPtr()
LangOptions & getLangOpts()
SourceManager & getSourceManager() const
Return the current source manager.
The class CompletionContextHandler contains four interfaces, each of which handles one type of comple...
CompletionContextHandler(Sema &S, CodeCompletionContext CCC, std::vector< std::string > &Results)
std::vector< std::string > & Results
virtual void handleMacro(const CodeCompletionResult &Result)
Converts a Macro completion result to a completion string, and then stores it in Results.
virtual void handleDeclaration(const CodeCompletionResult &Result)
Converts a Declaration completion result to a completion string, and then stores it in Results.
virtual void handlePattern(const CodeCompletionResult &Result)
Converts a Pattern completion result to a completion string, and then stores it in Results.
virtual void handleKeyword(const CodeCompletionResult &Result)
Converts a Keyword completion result to a completion string, and then stores it in Results.
virtual ~CompletionContextHandler()=default
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1369
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1436
void setHasExternalVisibleStorage(bool ES=true) const
State whether this DeclContext has external storage for declarations visible in this context.
Definition: DeclBase.h:2655
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Definition: DeclBase.cpp:1786
bool hasExternalVisibleStorage() const
Whether this DeclContext has external storage containing additional declarations that are visible in ...
Definition: DeclBase.h:2649
lookups_range lookups() const
Definition: DeclLookups.h:75
void setHasExternalLexicalStorage(bool ES=true) const
State whether this DeclContext has external storage for declarations lexically in this context.
Definition: DeclBase.h:2643
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
Decl * getPreviousDecl()
Retrieve the previous declaration that declares the same entity as this declaration,...
Definition: DeclBase.h:1051
The name of a declaration.
Options for controlling the compiler diagnostics engine.
void handleDeclaration(const CodeCompletionResult &Result) override
Converts a Declaration completion result to a completion string, and then stores it in Results.
DotMemberAccessHandler(Sema &S, CodeCompletionContext CCC, std::vector< std::string > &Results)
void handleKeyword(const CodeCompletionResult &Result) override
Converts a Keyword completion result to a completion string, and then stores it in Results.
Abstract interface for external sources of AST nodes.
static DeclContextLookupResult SetExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name, ArrayRef< NamedDecl * > Decls)
Definition: DeclBase.cpp:1541
ExternalSource(ASTContext &ChildASTCtxt, FileManager &ChildFM, ASTContext &ParentASTCtxt, FileManager &ParentFM)
void completeVisibleDeclsMap(const clang::DeclContext *childDeclContext) override
Ensures that the table of all visible declarations inside this context is up to date.
bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) override
Find all declarations with the given name in the given context, and add them to the context by callin...
Implements support for file system lookup, file system caching, and directory search management.
Definition: FileManager.h:53
CompilerInstance & getCompilerInstance() const
virtual void ExecuteAction()=0
Callback to run the program action, using the initialized compiler instance.
An input file for the front end.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
Allocator for a cached set of global code completions.
Implements an efficient mapping from strings to IdentifierInfo nodes.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
IncrementalSyntaxOnlyAction(const CompilerInstance *ParentCI)
void ExecuteAction() override
Implement the ExecuteAction interface by running Sema on the already-initialized AST consumer.
This represents a decl that may have a name.
Definition: Decl.h:249
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:315
A (possibly-)qualified type.
Definition: Type.h:940
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:1007
Base for LValueReferenceType and RValueReferenceType.
Definition: Type.h:3380
ReplCompletionConsumer(std::vector< std::string > &Results, ReplCodeCompleter &CC)
void ProcessCodeCompleteResults(class Sema &S, CodeCompletionContext Context, CodeCompletionResult *InResults, unsigned NumResults) final
Process the finalized code-completion results.
CodeCompletionAllocator & getAllocator() override
Retrieve the allocator that will be used to allocate code completion strings.
CodeCompletionTUInfo & getCodeCompletionTUInfo() override
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:449
ReferenceCompareResult
ReferenceCompareResult - Expresses the result of comparing two types (cv1 T1 and cv2 T2) to determine...
Definition: Sema.h:8052
@ Ref_Incompatible
Ref_Incompatible - The two types are incompatible, so direct reference binding is not possible.
Definition: Sema.h:8055
@ Ref_Compatible
Ref_Compatible - The two types are reference-compatible.
Definition: Sema.h:8061
@ Ref_Related
Ref_Related - The two types are reference-related, which means that their unqualified forms (T1 and T...
Definition: Sema.h:8059
Encodes a location in the source.
The top declaration context.
Definition: Decl.h:84
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1871
const T * castAs() const
Member-template castAs<specific type>.
Definition: Type.h:8193
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
clang::CodeCompleteOptions getClangCompleteOpts()
const std::string CodeCompletionFileName
Definition: Format.h:5428
void codeComplete(CompilerInstance *InterpCI, llvm::StringRef Content, unsigned Line, unsigned Col, const CompilerInstance *ParentCI, std::vector< std::string > &CCResults)
ReferenceConversions
The conversions that would be performed on an lvalue of type T2 when binding a reference of type T1 t...
Definition: Sema.h:8069