SemaInternal.h 13 KB

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