xref: /freebsd/contrib/llvm-project/clang/include/clang/Sema/SemaInternal.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===--- SemaInternal.h - Internal Sema Interfaces --------------*- C++ -*-===//
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 provides common API and #includes for the internal
10 // implementation of Sema.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_SEMA_SEMAINTERNAL_H
15 #define LLVM_CLANG_SEMA_SEMAINTERNAL_H
16 
17 #include "clang/AST/ASTContext.h"
18 #include "clang/Sema/Lookup.h"
19 #include "clang/Sema/Sema.h"
20 #include "clang/Sema/SemaDiagnostic.h"
21 
22 namespace clang {
23 
24 inline bool
FTIHasSingleVoidParameter(const DeclaratorChunk::FunctionTypeInfo & FTI)25 FTIHasSingleVoidParameter(const DeclaratorChunk::FunctionTypeInfo &FTI) {
26   return FTI.NumParams == 1 && !FTI.isVariadic &&
27          FTI.Params[0].Ident == nullptr && FTI.Params[0].Param &&
28          cast<ParmVarDecl>(FTI.Params[0].Param)->getType()->isVoidType();
29 }
30 
31 inline bool
FTIHasNonVoidParameters(const DeclaratorChunk::FunctionTypeInfo & FTI)32 FTIHasNonVoidParameters(const DeclaratorChunk::FunctionTypeInfo &FTI) {
33   // Assume FTI is well-formed.
34   return FTI.NumParams && !FTIHasSingleVoidParameter(FTI);
35 }
36 
37 // Helper function to check whether D's attributes match current CUDA mode.
38 // Decls with mismatched attributes and related diagnostics may have to be
39 // ignored during this CUDA compilation pass.
DeclAttrsMatchCUDAMode(const LangOptions & LangOpts,Decl * D)40 inline bool DeclAttrsMatchCUDAMode(const LangOptions &LangOpts, Decl *D) {
41   if (!LangOpts.CUDA || !D)
42     return true;
43   bool isDeviceSideDecl = D->hasAttr<CUDADeviceAttr>() ||
44                           D->hasAttr<CUDASharedAttr>() ||
45                           D->hasAttr<CUDAGlobalAttr>();
46   return isDeviceSideDecl == LangOpts.CUDAIsDevice;
47 }
48 
49 /// Return a DLL attribute from the declaration.
getDLLAttr(Decl * D)50 inline InheritableAttr *getDLLAttr(Decl *D) {
51   assert(!(D->hasAttr<DLLImportAttr>() && D->hasAttr<DLLExportAttr>()) &&
52          "A declaration cannot be both dllimport and dllexport.");
53   if (auto *Import = D->getAttr<DLLImportAttr>())
54     return Import;
55   if (auto *Export = D->getAttr<DLLExportAttr>())
56     return Export;
57   return nullptr;
58 }
59 
60 /// Retrieve the depth and index of a template parameter.
getDepthAndIndex(NamedDecl * ND)61 inline std::pair<unsigned, unsigned> getDepthAndIndex(NamedDecl *ND) {
62   if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
63     return std::make_pair(TTP->getDepth(), TTP->getIndex());
64 
65   if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
66     return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
67 
68   const auto *TTP = cast<TemplateTemplateParmDecl>(ND);
69   return std::make_pair(TTP->getDepth(), TTP->getIndex());
70 }
71 
72 /// Retrieve the depth and index of an unexpanded parameter pack.
73 inline std::pair<unsigned, unsigned>
getDepthAndIndex(UnexpandedParameterPack UPP)74 getDepthAndIndex(UnexpandedParameterPack UPP) {
75   if (const auto *TTP = UPP.first.dyn_cast<const TemplateTypeParmType *>())
76     return std::make_pair(TTP->getDepth(), TTP->getIndex());
77 
78   return getDepthAndIndex(UPP.first.get<NamedDecl *>());
79 }
80 
81 class TypoCorrectionConsumer : public VisibleDeclConsumer {
82   typedef SmallVector<TypoCorrection, 1> TypoResultList;
83   typedef llvm::StringMap<TypoResultList> TypoResultsMap;
84   typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
85 
86 public:
TypoCorrectionConsumer(Sema & SemaRef,const DeclarationNameInfo & TypoName,Sema::LookupNameKind LookupKind,Scope * S,CXXScopeSpec * SS,std::unique_ptr<CorrectionCandidateCallback> CCC,DeclContext * MemberContext,bool EnteringContext)87   TypoCorrectionConsumer(Sema &SemaRef,
88                          const DeclarationNameInfo &TypoName,
89                          Sema::LookupNameKind LookupKind,
90                          Scope *S, CXXScopeSpec *SS,
91                          std::unique_ptr<CorrectionCandidateCallback> CCC,
92                          DeclContext *MemberContext,
93                          bool EnteringContext)
94       : Typo(TypoName.getName().getAsIdentifierInfo()), CurrentTCIndex(0),
95         SavedTCIndex(0), SemaRef(SemaRef), S(S),
96         SS(SS ? std::make_unique<CXXScopeSpec>(*SS) : nullptr),
97         CorrectionValidator(std::move(CCC)), MemberContext(MemberContext),
98         Result(SemaRef, TypoName, LookupKind),
99         Namespaces(SemaRef.Context, SemaRef.CurContext, SS),
100         EnteringContext(EnteringContext), SearchNamespaces(false) {
101     Result.suppressDiagnostics();
102     // Arrange for ValidatedCorrections[0] to always be an empty correction.
103     ValidatedCorrections.push_back(TypoCorrection());
104   }
105 
includeHiddenDecls()106   bool includeHiddenDecls() const override { return true; }
107 
108   // Methods for adding potential corrections to the consumer.
109   void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
110                  bool InBaseClass) override;
111   void FoundName(StringRef Name);
112   void addKeywordResult(StringRef Keyword);
113   void addCorrection(TypoCorrection Correction);
114 
empty()115   bool empty() const {
116     return CorrectionResults.empty() && ValidatedCorrections.size() == 1;
117   }
118 
119   /// Return the list of TypoCorrections for the given identifier from
120   /// the set of corrections that have the closest edit distance, if any.
121   TypoResultList &operator[](StringRef Name) {
122     return CorrectionResults.begin()->second[Name];
123   }
124 
125   /// Return the edit distance of the corrections that have the
126   /// closest/best edit distance from the original typop.
getBestEditDistance(bool Normalized)127   unsigned getBestEditDistance(bool Normalized) {
128     if (CorrectionResults.empty())
129       return (std::numeric_limits<unsigned>::max)();
130 
131     unsigned BestED = CorrectionResults.begin()->first;
132     return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED;
133   }
134 
135   /// Set-up method to add to the consumer the set of namespaces to use
136   /// in performing corrections to nested name specifiers. This method also
137   /// implicitly adds all of the known classes in the current AST context to the
138   /// to the consumer for correcting nested name specifiers.
139   void
140   addNamespaces(const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces);
141 
142   /// Return the next typo correction that passes all internal filters
143   /// and is deemed valid by the consumer's CorrectionCandidateCallback,
144   /// starting with the corrections that have the closest edit distance. An
145   /// empty TypoCorrection is returned once no more viable corrections remain
146   /// in the consumer.
147   const TypoCorrection &getNextCorrection();
148 
149   /// Get the last correction returned by getNextCorrection().
getCurrentCorrection()150   const TypoCorrection &getCurrentCorrection() {
151     return CurrentTCIndex < ValidatedCorrections.size()
152                ? ValidatedCorrections[CurrentTCIndex]
153                : ValidatedCorrections[0];  // The empty correction.
154   }
155 
156   /// Return the next typo correction like getNextCorrection, but keep
157   /// the internal state pointed to the current correction (i.e. the next time
158   /// getNextCorrection is called, it will return the same correction returned
159   /// by peekNextcorrection).
peekNextCorrection()160   const TypoCorrection &peekNextCorrection() {
161     auto Current = CurrentTCIndex;
162     const TypoCorrection &TC = getNextCorrection();
163     CurrentTCIndex = Current;
164     return TC;
165   }
166 
167   /// In the case of deeply invalid expressions, `getNextCorrection()` will
168   /// never be called since the transform never makes progress. If we don't
169   /// detect this we risk trying to correct typos forever.
hasMadeAnyCorrectionProgress()170   bool hasMadeAnyCorrectionProgress() const { return CurrentTCIndex != 0; }
171 
172   /// Reset the consumer's position in the stream of viable corrections
173   /// (i.e. getNextCorrection() will return each of the previously returned
174   /// corrections in order before returning any new corrections).
resetCorrectionStream()175   void resetCorrectionStream() {
176     CurrentTCIndex = 0;
177   }
178 
179   /// Return whether the end of the stream of corrections has been
180   /// reached.
finished()181   bool finished() {
182     return CorrectionResults.empty() &&
183            CurrentTCIndex >= ValidatedCorrections.size();
184   }
185 
186   /// Save the current position in the correction stream (overwriting any
187   /// previously saved position).
saveCurrentPosition()188   void saveCurrentPosition() {
189     SavedTCIndex = CurrentTCIndex;
190   }
191 
192   /// Restore the saved position in the correction stream.
restoreSavedPosition()193   void restoreSavedPosition() {
194     CurrentTCIndex = SavedTCIndex;
195   }
196 
getContext()197   ASTContext &getContext() const { return SemaRef.Context; }
getLookupResult()198   const LookupResult &getLookupResult() const { return Result; }
199 
isAddressOfOperand()200   bool isAddressOfOperand() const { return CorrectionValidator->IsAddressOfOperand; }
getSS()201   const CXXScopeSpec *getSS() const { return SS.get(); }
getScope()202   Scope *getScope() const { return S; }
getCorrectionValidator()203   CorrectionCandidateCallback *getCorrectionValidator() const {
204     return CorrectionValidator.get();
205   }
206 
207 private:
208   class NamespaceSpecifierSet {
209     struct SpecifierInfo {
210       DeclContext* DeclCtx;
211       NestedNameSpecifier* NameSpecifier;
212       unsigned EditDistance;
213     };
214 
215     typedef SmallVector<DeclContext*, 4> DeclContextList;
216     typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList;
217 
218     ASTContext &Context;
219     DeclContextList CurContextChain;
220     std::string CurNameSpecifier;
221     SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers;
222     SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers;
223 
224     std::map<unsigned, SpecifierInfoList> DistanceMap;
225 
226     /// Helper for building the list of DeclContexts between the current
227     /// context and the top of the translation unit
228     static DeclContextList buildContextChain(DeclContext *Start);
229 
230     unsigned buildNestedNameSpecifier(DeclContextList &DeclChain,
231                                       NestedNameSpecifier *&NNS);
232 
233    public:
234     NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext,
235                           CXXScopeSpec *CurScopeSpec);
236 
237     /// Add the DeclContext (a namespace or record) to the set, computing
238     /// the corresponding NestedNameSpecifier and its distance in the process.
239     void addNameSpecifier(DeclContext *Ctx);
240 
241     /// Provides flat iteration over specifiers, sorted by distance.
242     class iterator
243         : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
244                                             SpecifierInfo> {
245       /// Always points to the last element in the distance map.
246       const std::map<unsigned, SpecifierInfoList>::iterator OuterBack;
247       /// Iterator on the distance map.
248       std::map<unsigned, SpecifierInfoList>::iterator Outer;
249       /// Iterator on an element in the distance map.
250       SpecifierInfoList::iterator Inner;
251 
252     public:
iterator(NamespaceSpecifierSet & Set,bool IsAtEnd)253       iterator(NamespaceSpecifierSet &Set, bool IsAtEnd)
254           : OuterBack(std::prev(Set.DistanceMap.end())),
255             Outer(Set.DistanceMap.begin()),
256             Inner(!IsAtEnd ? Outer->second.begin() : OuterBack->second.end()) {
257         assert(!Set.DistanceMap.empty());
258       }
259 
260       iterator &operator++() {
261         ++Inner;
262         if (Inner == Outer->second.end() && Outer != OuterBack) {
263           ++Outer;
264           Inner = Outer->second.begin();
265         }
266         return *this;
267       }
268 
269       SpecifierInfo &operator*() { return *Inner; }
270       bool operator==(const iterator &RHS) const { return Inner == RHS.Inner; }
271     };
272 
begin()273     iterator begin() { return iterator(*this, /*IsAtEnd=*/false); }
end()274     iterator end() { return iterator(*this, /*IsAtEnd=*/true); }
275   };
276 
277   void addName(StringRef Name, NamedDecl *ND,
278                NestedNameSpecifier *NNS = nullptr, bool isKeyword = false);
279 
280   /// Find any visible decls for the given typo correction candidate.
281   /// If none are found, it to the set of candidates for which qualified lookups
282   /// will be performed to find possible nested name specifier changes.
283   bool resolveCorrection(TypoCorrection &Candidate);
284 
285   /// Perform qualified lookups on the queued set of typo correction
286   /// candidates and add the nested name specifier changes to each candidate if
287   /// a lookup succeeds (at which point the candidate will be returned to the
288   /// main pool of potential corrections).
289   void performQualifiedLookups();
290 
291   /// The name written that is a typo in the source.
292   IdentifierInfo *Typo;
293 
294   /// The results found that have the smallest edit distance
295   /// found (so far) with the typo name.
296   ///
297   /// The pointer value being set to the current DeclContext indicates
298   /// whether there is a keyword with this name.
299   TypoEditDistanceMap CorrectionResults;
300 
301   SmallVector<TypoCorrection, 4> ValidatedCorrections;
302   size_t CurrentTCIndex;
303   size_t SavedTCIndex;
304 
305   Sema &SemaRef;
306   Scope *S;
307   std::unique_ptr<CXXScopeSpec> SS;
308   std::unique_ptr<CorrectionCandidateCallback> CorrectionValidator;
309   DeclContext *MemberContext;
310   LookupResult Result;
311   NamespaceSpecifierSet Namespaces;
312   SmallVector<TypoCorrection, 2> QualifiedResults;
313   bool EnteringContext;
314   bool SearchNamespaces;
315 };
316 
TypoExprState()317 inline Sema::TypoExprState::TypoExprState() {}
318 
TypoExprState(TypoExprState && other)319 inline Sema::TypoExprState::TypoExprState(TypoExprState &&other) noexcept {
320   *this = std::move(other);
321 }
322 
323 inline Sema::TypoExprState &Sema::TypoExprState::
324 operator=(Sema::TypoExprState &&other) noexcept {
325   Consumer = std::move(other.Consumer);
326   DiagHandler = std::move(other.DiagHandler);
327   RecoveryHandler = std::move(other.RecoveryHandler);
328   return *this;
329 }
330 
331 } // end namespace clang
332 
333 #endif
334