Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:37:04

0001 //===--- SemaInternal.h - Internal Sema Interfaces --------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file provides common API and #includes for the internal
0010 // implementation of Sema.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_SEMA_SEMAINTERNAL_H
0015 #define LLVM_CLANG_SEMA_SEMAINTERNAL_H
0016 
0017 #include "clang/AST/ASTContext.h"
0018 #include "clang/Sema/Lookup.h"
0019 #include "clang/Sema/Sema.h"
0020 #include "clang/Sema/SemaDiagnostic.h"
0021 
0022 namespace clang {
0023 
0024 inline bool
0025 FTIHasSingleVoidParameter(const DeclaratorChunk::FunctionTypeInfo &FTI) {
0026   return FTI.NumParams == 1 && !FTI.isVariadic &&
0027          FTI.Params[0].Ident == nullptr && FTI.Params[0].Param &&
0028          cast<ParmVarDecl>(FTI.Params[0].Param)->getType()->isVoidType();
0029 }
0030 
0031 inline bool
0032 FTIHasNonVoidParameters(const DeclaratorChunk::FunctionTypeInfo &FTI) {
0033   // Assume FTI is well-formed.
0034   return FTI.NumParams && !FTIHasSingleVoidParameter(FTI);
0035 }
0036 
0037 // Helper function to check whether D's attributes match current CUDA mode.
0038 // Decls with mismatched attributes and related diagnostics may have to be
0039 // ignored during this CUDA compilation pass.
0040 inline bool DeclAttrsMatchCUDAMode(const LangOptions &LangOpts, Decl *D) {
0041   if (!LangOpts.CUDA || !D)
0042     return true;
0043   bool isDeviceSideDecl = D->hasAttr<CUDADeviceAttr>() ||
0044                           D->hasAttr<CUDASharedAttr>() ||
0045                           D->hasAttr<CUDAGlobalAttr>();
0046   return isDeviceSideDecl == LangOpts.CUDAIsDevice;
0047 }
0048 
0049 /// Return a DLL attribute from the declaration.
0050 inline InheritableAttr *getDLLAttr(Decl *D) {
0051   assert(!(D->hasAttr<DLLImportAttr>() && D->hasAttr<DLLExportAttr>()) &&
0052          "A declaration cannot be both dllimport and dllexport.");
0053   if (auto *Import = D->getAttr<DLLImportAttr>())
0054     return Import;
0055   if (auto *Export = D->getAttr<DLLExportAttr>())
0056     return Export;
0057   return nullptr;
0058 }
0059 
0060 /// Retrieve the depth and index of a template parameter.
0061 inline std::pair<unsigned, unsigned> getDepthAndIndex(const NamedDecl *ND) {
0062   if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
0063     return std::make_pair(TTP->getDepth(), TTP->getIndex());
0064 
0065   if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
0066     return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
0067 
0068   const auto *TTP = cast<TemplateTemplateParmDecl>(ND);
0069   return std::make_pair(TTP->getDepth(), TTP->getIndex());
0070 }
0071 
0072 /// Retrieve the depth and index of an unexpanded parameter pack.
0073 inline std::pair<unsigned, unsigned>
0074 getDepthAndIndex(UnexpandedParameterPack UPP) {
0075   if (const auto *TTP = dyn_cast<const TemplateTypeParmType *>(UPP.first))
0076     return std::make_pair(TTP->getDepth(), TTP->getIndex());
0077 
0078   return getDepthAndIndex(cast<NamedDecl *>(UPP.first));
0079 }
0080 
0081 class TypoCorrectionConsumer : public VisibleDeclConsumer {
0082   typedef SmallVector<TypoCorrection, 1> TypoResultList;
0083   typedef llvm::StringMap<TypoResultList> TypoResultsMap;
0084   typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
0085 
0086 public:
0087   TypoCorrectionConsumer(Sema &SemaRef,
0088                          const DeclarationNameInfo &TypoName,
0089                          Sema::LookupNameKind LookupKind,
0090                          Scope *S, CXXScopeSpec *SS,
0091                          std::unique_ptr<CorrectionCandidateCallback> CCC,
0092                          DeclContext *MemberContext,
0093                          bool EnteringContext)
0094       : Typo(TypoName.getName().getAsIdentifierInfo()), CurrentTCIndex(0),
0095         SavedTCIndex(0), SemaRef(SemaRef), S(S),
0096         SS(SS ? std::make_unique<CXXScopeSpec>(*SS) : nullptr),
0097         CorrectionValidator(std::move(CCC)), MemberContext(MemberContext),
0098         Result(SemaRef, TypoName, LookupKind),
0099         Namespaces(SemaRef.Context, SemaRef.CurContext, SS),
0100         EnteringContext(EnteringContext), SearchNamespaces(false) {
0101     Result.suppressDiagnostics();
0102     // Arrange for ValidatedCorrections[0] to always be an empty correction.
0103     ValidatedCorrections.push_back(TypoCorrection());
0104   }
0105 
0106   bool includeHiddenDecls() const override { return true; }
0107 
0108   // Methods for adding potential corrections to the consumer.
0109   void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
0110                  bool InBaseClass) override;
0111   void FoundName(StringRef Name);
0112   void addKeywordResult(StringRef Keyword);
0113   void addCorrection(TypoCorrection Correction);
0114 
0115   bool empty() const {
0116     return CorrectionResults.empty() && ValidatedCorrections.size() == 1;
0117   }
0118 
0119   /// Return the list of TypoCorrections for the given identifier from
0120   /// the set of corrections that have the closest edit distance, if any.
0121   TypoResultList &operator[](StringRef Name) {
0122     return CorrectionResults.begin()->second[Name];
0123   }
0124 
0125   /// Return the edit distance of the corrections that have the
0126   /// closest/best edit distance from the original typop.
0127   unsigned getBestEditDistance(bool Normalized) {
0128     if (CorrectionResults.empty())
0129       return (std::numeric_limits<unsigned>::max)();
0130 
0131     unsigned BestED = CorrectionResults.begin()->first;
0132     return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED;
0133   }
0134 
0135   /// Set-up method to add to the consumer the set of namespaces to use
0136   /// in performing corrections to nested name specifiers. This method also
0137   /// implicitly adds all of the known classes in the current AST context to the
0138   /// to the consumer for correcting nested name specifiers.
0139   void
0140   addNamespaces(const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces);
0141 
0142   /// Return the next typo correction that passes all internal filters
0143   /// and is deemed valid by the consumer's CorrectionCandidateCallback,
0144   /// starting with the corrections that have the closest edit distance. An
0145   /// empty TypoCorrection is returned once no more viable corrections remain
0146   /// in the consumer.
0147   const TypoCorrection &getNextCorrection();
0148 
0149   /// Get the last correction returned by getNextCorrection().
0150   const TypoCorrection &getCurrentCorrection() {
0151     return CurrentTCIndex < ValidatedCorrections.size()
0152                ? ValidatedCorrections[CurrentTCIndex]
0153                : ValidatedCorrections[0];  // The empty correction.
0154   }
0155 
0156   /// Return the next typo correction like getNextCorrection, but keep
0157   /// the internal state pointed to the current correction (i.e. the next time
0158   /// getNextCorrection is called, it will return the same correction returned
0159   /// by peekNextcorrection).
0160   const TypoCorrection &peekNextCorrection() {
0161     auto Current = CurrentTCIndex;
0162     const TypoCorrection &TC = getNextCorrection();
0163     CurrentTCIndex = Current;
0164     return TC;
0165   }
0166 
0167   /// In the case of deeply invalid expressions, `getNextCorrection()` will
0168   /// never be called since the transform never makes progress. If we don't
0169   /// detect this we risk trying to correct typos forever.
0170   bool hasMadeAnyCorrectionProgress() const { return CurrentTCIndex != 0; }
0171 
0172   /// Reset the consumer's position in the stream of viable corrections
0173   /// (i.e. getNextCorrection() will return each of the previously returned
0174   /// corrections in order before returning any new corrections).
0175   void resetCorrectionStream() {
0176     CurrentTCIndex = 0;
0177   }
0178 
0179   /// Return whether the end of the stream of corrections has been
0180   /// reached.
0181   bool finished() {
0182     return CorrectionResults.empty() &&
0183            CurrentTCIndex >= ValidatedCorrections.size();
0184   }
0185 
0186   /// Save the current position in the correction stream (overwriting any
0187   /// previously saved position).
0188   void saveCurrentPosition() {
0189     SavedTCIndex = CurrentTCIndex;
0190   }
0191 
0192   /// Restore the saved position in the correction stream.
0193   void restoreSavedPosition() {
0194     CurrentTCIndex = SavedTCIndex;
0195   }
0196 
0197   ASTContext &getContext() const { return SemaRef.Context; }
0198   const LookupResult &getLookupResult() const { return Result; }
0199 
0200   bool isAddressOfOperand() const { return CorrectionValidator->IsAddressOfOperand; }
0201   const CXXScopeSpec *getSS() const { return SS.get(); }
0202   Scope *getScope() const { return S; }
0203   CorrectionCandidateCallback *getCorrectionValidator() const {
0204     return CorrectionValidator.get();
0205   }
0206 
0207 private:
0208   class NamespaceSpecifierSet {
0209     struct SpecifierInfo {
0210       DeclContext* DeclCtx;
0211       NestedNameSpecifier* NameSpecifier;
0212       unsigned EditDistance;
0213     };
0214 
0215     typedef SmallVector<DeclContext*, 4> DeclContextList;
0216     typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList;
0217 
0218     ASTContext &Context;
0219     DeclContextList CurContextChain;
0220     std::string CurNameSpecifier;
0221     SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers;
0222     SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers;
0223 
0224     std::map<unsigned, SpecifierInfoList> DistanceMap;
0225 
0226     /// Helper for building the list of DeclContexts between the current
0227     /// context and the top of the translation unit
0228     static DeclContextList buildContextChain(DeclContext *Start);
0229 
0230     unsigned buildNestedNameSpecifier(DeclContextList &DeclChain,
0231                                       NestedNameSpecifier *&NNS);
0232 
0233    public:
0234     NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext,
0235                           CXXScopeSpec *CurScopeSpec);
0236 
0237     /// Add the DeclContext (a namespace or record) to the set, computing
0238     /// the corresponding NestedNameSpecifier and its distance in the process.
0239     void addNameSpecifier(DeclContext *Ctx);
0240 
0241     /// Provides flat iteration over specifiers, sorted by distance.
0242     class iterator
0243         : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
0244                                             SpecifierInfo> {
0245       /// Always points to the last element in the distance map.
0246       const std::map<unsigned, SpecifierInfoList>::iterator OuterBack;
0247       /// Iterator on the distance map.
0248       std::map<unsigned, SpecifierInfoList>::iterator Outer;
0249       /// Iterator on an element in the distance map.
0250       SpecifierInfoList::iterator Inner;
0251 
0252     public:
0253       iterator(NamespaceSpecifierSet &Set, bool IsAtEnd)
0254           : OuterBack(std::prev(Set.DistanceMap.end())),
0255             Outer(Set.DistanceMap.begin()),
0256             Inner(!IsAtEnd ? Outer->second.begin() : OuterBack->second.end()) {
0257         assert(!Set.DistanceMap.empty());
0258       }
0259 
0260       iterator &operator++() {
0261         ++Inner;
0262         if (Inner == Outer->second.end() && Outer != OuterBack) {
0263           ++Outer;
0264           Inner = Outer->second.begin();
0265         }
0266         return *this;
0267       }
0268 
0269       SpecifierInfo &operator*() { return *Inner; }
0270       bool operator==(const iterator &RHS) const { return Inner == RHS.Inner; }
0271     };
0272 
0273     iterator begin() { return iterator(*this, /*IsAtEnd=*/false); }
0274     iterator end() { return iterator(*this, /*IsAtEnd=*/true); }
0275   };
0276 
0277   void addName(StringRef Name, NamedDecl *ND,
0278                NestedNameSpecifier *NNS = nullptr, bool isKeyword = false);
0279 
0280   /// Find any visible decls for the given typo correction candidate.
0281   /// If none are found, it to the set of candidates for which qualified lookups
0282   /// will be performed to find possible nested name specifier changes.
0283   bool resolveCorrection(TypoCorrection &Candidate);
0284 
0285   /// Perform qualified lookups on the queued set of typo correction
0286   /// candidates and add the nested name specifier changes to each candidate if
0287   /// a lookup succeeds (at which point the candidate will be returned to the
0288   /// main pool of potential corrections).
0289   void performQualifiedLookups();
0290 
0291   /// The name written that is a typo in the source.
0292   IdentifierInfo *Typo;
0293 
0294   /// The results found that have the smallest edit distance
0295   /// found (so far) with the typo name.
0296   ///
0297   /// The pointer value being set to the current DeclContext indicates
0298   /// whether there is a keyword with this name.
0299   TypoEditDistanceMap CorrectionResults;
0300 
0301   SmallVector<TypoCorrection, 4> ValidatedCorrections;
0302   size_t CurrentTCIndex;
0303   size_t SavedTCIndex;
0304 
0305   Sema &SemaRef;
0306   Scope *S;
0307   std::unique_ptr<CXXScopeSpec> SS;
0308   std::unique_ptr<CorrectionCandidateCallback> CorrectionValidator;
0309   DeclContext *MemberContext;
0310   LookupResult Result;
0311   NamespaceSpecifierSet Namespaces;
0312   SmallVector<TypoCorrection, 2> QualifiedResults;
0313   bool EnteringContext;
0314   bool SearchNamespaces;
0315 };
0316 
0317 inline Sema::TypoExprState::TypoExprState() {}
0318 
0319 inline Sema::TypoExprState::TypoExprState(TypoExprState &&other) noexcept {
0320   *this = std::move(other);
0321 }
0322 
0323 inline Sema::TypoExprState &Sema::TypoExprState::
0324 operator=(Sema::TypoExprState &&other) noexcept {
0325   Consumer = std::move(other.Consumer);
0326   DiagHandler = std::move(other.DiagHandler);
0327   RecoveryHandler = std::move(other.RecoveryHandler);
0328   return *this;
0329 }
0330 
0331 } // end namespace clang
0332 
0333 #endif