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 
14 #include "clang/AST/ASTImporter.h"
15 #include "clang/AST/DeclLookups.h"
19 #include "clang/Frontend/ASTUnit.h"
26 #include "clang/Sema/Sema.h"
27 #include "llvm/Support/Debug.h"
28 #define DEBUG_TYPE "REPLCC"
29 
30 namespace clang {
31 
32 const 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 
44 public:
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 
62 private:
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.
74 protected:
76  std::vector<std::string> &Results;
77 
78 private:
79  Sema &S;
80 
81 public:
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.
89  virtual void handleDeclaration(const CodeCompletionResult &Result) {
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) {
106  case Sema::Ref_Related:
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.
120  virtual void handleKeyword(const CodeCompletionResult &Result) {
121  auto Prefix = S.getPreprocessor().getCodeCompletionFilter();
122  // Add keyword to the completion results only if we are in a type-aware
123  // situation.
124  if (!CCC.getBaseType().isNull() || !CCC.getPreferredType().isNull())
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.
132  virtual void handlePattern(const CodeCompletionResult &Result) {}
133 
134  /// Converts a Macro completion result to a completion string, and then stores
135  /// it in Results.
136  virtual void handleMacro(const CodeCompletionResult &Result) {}
137 };
138 
140 public:
142  std::vector<std::string> &Results)
144  void handleDeclaration(const CodeCompletionResult &Result) override {
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 
159  void handleKeyword(const CodeCompletionResult &Result) override {}
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 
212 public:
214  : ParentCI(ParentCI) {}
215 
216 protected:
217  void ExecuteAction() override;
218 };
219 
221  TranslationUnitDecl *ChildTUDeclCtxt;
222  ASTContext &ParentASTCtxt;
223  TranslationUnitDecl *ParentTUDeclCtxt;
224 
225  std::unique_ptr<ASTImporter> Importer;
226 
227 public:
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));
369  InterpCI->getFrontendOpts().Inputs[0] = FrontendInputFile(
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:185
IdentifierTable & Idents
Definition: ASTContext.h:647
void setExternalSource(IntrusiveRefCntPtr< ExternalASTSource > Source)
Attach an external AST source to the AST context.
Definition: ASTContext.cpp:947
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1076
void ExecuteAction() override
Implement the ExecuteAction interface by running Sema on the already-initialized AST consumer.
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:1550
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.
FrontendOptions & getFrontendOpts()
IntrusiveRefCntPtr< DiagnosticsEngine > getDiagnosticsPtr() const
ASTContext & getASTContext() const
SourceManager & getSourceManager() const
Return the current source manager.
FileManager & getFileManager() const
Return the current file manager to the caller.
std::shared_ptr< CompilerInvocation > getInvocationPtr()
LangOptions & getLangOpts()
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:1802
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:1557
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
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:3392
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.
CodeCompletionTUInfo & getCodeCompletionTUInfo() override
CodeCompletionAllocator & getAllocator() override
Retrieve the allocator that will be used to allocate code completion strings.
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:462
ReferenceCompareResult
ReferenceCompareResult - Expresses the result of comparing two types (cv1 T1 and cv2 T2) to determine...
Definition: Sema.h:8259
@ Ref_Incompatible
Ref_Incompatible - The two types are incompatible, so direct reference binding is not possible.
Definition: Sema.h:8262
@ Ref_Compatible
Ref_Compatible - The two types are reference-compatible.
Definition: Sema.h:8268
@ Ref_Related
Ref_Related - The two types are reference-related, which means that their unqualified forms (T1 and T...
Definition: Sema.h:8266
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:1881
const T * castAs() const
Member-template castAs<specific type>.
Definition: Type.h:8227
The JSON file list parser is used to communicate input to InstallAPI.
clang::CodeCompleteOptions getClangCompleteOpts()
const std::string CodeCompletionFileName
Definition: Format.h:5433
float __ovld __cnfn distance(float, float)
Returns the distance between p0 and p1.
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:8276