//===--- SemaInternal.h - Internal Sema Interfaces --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file provides common API and #includes for the internal // implementation of Sema. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SEMA_SEMAINTERNAL_H #define LLVM_CLANG_SEMA_SEMAINTERNAL_H #include "clang/AST/ASTContext.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" namespace clang { inline PartialDiagnostic Sema::PDiag(unsigned DiagID) { return PartialDiagnostic(DiagID, Context.getDiagAllocator()); } inline bool FTIHasSingleVoidParameter(const DeclaratorChunk::FunctionTypeInfo &FTI) { return FTI.NumParams == 1 && !FTI.isVariadic && FTI.Params[0].Ident == nullptr && FTI.Params[0].Param && cast(FTI.Params[0].Param)->getType()->isVoidType(); } inline bool FTIHasNonVoidParameters(const DeclaratorChunk::FunctionTypeInfo &FTI) { // Assume FTI is well-formed. return FTI.NumParams && !FTIHasSingleVoidParameter(FTI); } // This requires the variable to be non-dependent and the initializer // to not be value dependent. inline bool IsVariableAConstantExpression(VarDecl *Var, ASTContext &Context) { const VarDecl *DefVD = nullptr; return !isa(Var) && Var->isUsableInConstantExpressions(Context) && Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE(); } // Helper function to check whether D's attributes match current CUDA mode. // Decls with mismatched attributes and related diagnostics may have to be // ignored during this CUDA compilation pass. inline bool DeclAttrsMatchCUDAMode(const LangOptions &LangOpts, Decl *D) { if (!LangOpts.CUDA || !D) return true; bool isDeviceSideDecl = D->hasAttr() || D->hasAttr() || D->hasAttr(); return isDeviceSideDecl == LangOpts.CUDAIsDevice; } // Directly mark a variable odr-used. Given a choice, prefer to use // MarkVariableReferenced since it does additional checks and then // calls MarkVarDeclODRUsed. // If the variable must be captured: // - if FunctionScopeIndexToStopAt is null, capture it in the CurContext // - else capture it in the DeclContext that maps to the // *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack. inline void MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, const unsigned *const FunctionScopeIndexToStopAt) { // Keep track of used but undefined variables. // FIXME: We shouldn't suppress this warning for static data members. if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && (!Var->isExternallyVisible() || Var->isInline() || SemaRef.isExternalWithNoLinkageType(Var)) && !(Var->isStaticDataMember() && Var->hasInit())) { SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()]; if (old.isInvalid()) old = Loc; } QualType CaptureType, DeclRefType; SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit, /*EllipsisLoc*/ SourceLocation(), /*BuildAndDiagnose*/ true, CaptureType, DeclRefType, FunctionScopeIndexToStopAt); Var->markUsed(SemaRef.Context); } /// Return a DLL attribute from the declaration. inline InheritableAttr *getDLLAttr(Decl *D) { assert(!(D->hasAttr() && D->hasAttr()) && "A declaration cannot be both dllimport and dllexport."); if (auto *Import = D->getAttr()) return Import; if (auto *Export = D->getAttr()) return Export; return nullptr; } /// Retrieve the depth and index of a template parameter. inline std::pair getDepthAndIndex(NamedDecl *ND) { if (const auto *TTP = dyn_cast(ND)) return std::make_pair(TTP->getDepth(), TTP->getIndex()); if (const auto *NTTP = dyn_cast(ND)) return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); const auto *TTP = cast(ND); return std::make_pair(TTP->getDepth(), TTP->getIndex()); } /// Retrieve the depth and index of an unexpanded parameter pack. inline std::pair getDepthAndIndex(UnexpandedParameterPack UPP) { if (const auto *TTP = UPP.first.dyn_cast()) return std::make_pair(TTP->getDepth(), TTP->getIndex()); return getDepthAndIndex(UPP.first.get()); } class TypoCorrectionConsumer : public VisibleDeclConsumer { typedef SmallVector TypoResultList; typedef llvm::StringMap TypoResultsMap; typedef std::map TypoEditDistanceMap; public: TypoCorrectionConsumer(Sema &SemaRef, const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, DeclContext *MemberContext, bool EnteringContext) : Typo(TypoName.getName().getAsIdentifierInfo()), CurrentTCIndex(0), SavedTCIndex(0), SemaRef(SemaRef), S(S), SS(SS ? llvm::make_unique(*SS) : nullptr), CorrectionValidator(std::move(CCC)), MemberContext(MemberContext), Result(SemaRef, TypoName, LookupKind), Namespaces(SemaRef.Context, SemaRef.CurContext, SS), EnteringContext(EnteringContext), SearchNamespaces(false) { Result.suppressDiagnostics(); // Arrange for ValidatedCorrections[0] to always be an empty correction. ValidatedCorrections.push_back(TypoCorrection()); } bool includeHiddenDecls() const override { return true; } // Methods for adding potential corrections to the consumer. void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass) override; void FoundName(StringRef Name); void addKeywordResult(StringRef Keyword); void addCorrection(TypoCorrection Correction); bool empty() const { return CorrectionResults.empty() && ValidatedCorrections.size() == 1; } /// Return the list of TypoCorrections for the given identifier from /// the set of corrections that have the closest edit distance, if any. TypoResultList &operator[](StringRef Name) { return CorrectionResults.begin()->second[Name]; } /// Return the edit distance of the corrections that have the /// closest/best edit distance from the original typop. unsigned getBestEditDistance(bool Normalized) { if (CorrectionResults.empty()) return (std::numeric_limits::max)(); unsigned BestED = CorrectionResults.begin()->first; return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED; } /// Set-up method to add to the consumer the set of namespaces to use /// in performing corrections to nested name specifiers. This method also /// implicitly adds all of the known classes in the current AST context to the /// to the consumer for correcting nested name specifiers. void addNamespaces(const llvm::MapVector &KnownNamespaces); /// Return the next typo correction that passes all internal filters /// and is deemed valid by the consumer's CorrectionCandidateCallback, /// starting with the corrections that have the closest edit distance. An /// empty TypoCorrection is returned once no more viable corrections remain /// in the consumer. const TypoCorrection &getNextCorrection(); /// Get the last correction returned by getNextCorrection(). const TypoCorrection &getCurrentCorrection() { return CurrentTCIndex < ValidatedCorrections.size() ? ValidatedCorrections[CurrentTCIndex] : ValidatedCorrections[0]; // The empty correction. } /// Return the next typo correction like getNextCorrection, but keep /// the internal state pointed to the current correction (i.e. the next time /// getNextCorrection is called, it will return the same correction returned /// by peekNextcorrection). const TypoCorrection &peekNextCorrection() { auto Current = CurrentTCIndex; const TypoCorrection &TC = getNextCorrection(); CurrentTCIndex = Current; return TC; } /// Reset the consumer's position in the stream of viable corrections /// (i.e. getNextCorrection() will return each of the previously returned /// corrections in order before returning any new corrections). void resetCorrectionStream() { CurrentTCIndex = 0; } /// Return whether the end of the stream of corrections has been /// reached. bool finished() { return CorrectionResults.empty() && CurrentTCIndex >= ValidatedCorrections.size(); } /// Save the current position in the correction stream (overwriting any /// previously saved position). void saveCurrentPosition() { SavedTCIndex = CurrentTCIndex; } /// Restore the saved position in the correction stream. void restoreSavedPosition() { CurrentTCIndex = SavedTCIndex; } ASTContext &getContext() const { return SemaRef.Context; } const LookupResult &getLookupResult() const { return Result; } bool isAddressOfOperand() const { return CorrectionValidator->IsAddressOfOperand; } const CXXScopeSpec *getSS() const { return SS.get(); } Scope *getScope() const { return S; } CorrectionCandidateCallback *getCorrectionValidator() const { return CorrectionValidator.get(); } private: class NamespaceSpecifierSet { struct SpecifierInfo { DeclContext* DeclCtx; NestedNameSpecifier* NameSpecifier; unsigned EditDistance; }; typedef SmallVector DeclContextList; typedef SmallVector SpecifierInfoList; ASTContext &Context; DeclContextList CurContextChain; std::string CurNameSpecifier; SmallVector CurContextIdentifiers; SmallVector CurNameSpecifierIdentifiers; std::map DistanceMap; /// Helper for building the list of DeclContexts between the current /// context and the top of the translation unit static DeclContextList buildContextChain(DeclContext *Start); unsigned buildNestedNameSpecifier(DeclContextList &DeclChain, NestedNameSpecifier *&NNS); public: NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext, CXXScopeSpec *CurScopeSpec); /// Add the DeclContext (a namespace or record) to the set, computing /// the corresponding NestedNameSpecifier and its distance in the process. void addNameSpecifier(DeclContext *Ctx); /// Provides flat iteration over specifiers, sorted by distance. class iterator : public llvm::iterator_facade_base { /// Always points to the last element in the distance map. const std::map::iterator OuterBack; /// Iterator on the distance map. std::map::iterator Outer; /// Iterator on an element in the distance map. SpecifierInfoList::iterator Inner; public: iterator(NamespaceSpecifierSet &Set, bool IsAtEnd) : OuterBack(std::prev(Set.DistanceMap.end())), Outer(Set.DistanceMap.begin()), Inner(!IsAtEnd ? Outer->second.begin() : OuterBack->second.end()) { assert(!Set.DistanceMap.empty()); } iterator &operator++() { ++Inner; if (Inner == Outer->second.end() && Outer != OuterBack) { ++Outer; Inner = Outer->second.begin(); } return *this; } SpecifierInfo &operator*() { return *Inner; } bool operator==(const iterator &RHS) const { return Inner == RHS.Inner; } }; iterator begin() { return iterator(*this, /*IsAtEnd=*/false); } iterator end() { return iterator(*this, /*IsAtEnd=*/true); } }; void addName(StringRef Name, NamedDecl *ND, NestedNameSpecifier *NNS = nullptr, bool isKeyword = false); /// Find any visible decls for the given typo correction candidate. /// If none are found, it to the set of candidates for which qualified lookups /// will be performed to find possible nested name specifier changes. bool resolveCorrection(TypoCorrection &Candidate); /// Perform qualified lookups on the queued set of typo correction /// candidates and add the nested name specifier changes to each candidate if /// a lookup succeeds (at which point the candidate will be returned to the /// main pool of potential corrections). void performQualifiedLookups(); /// The name written that is a typo in the source. IdentifierInfo *Typo; /// The results found that have the smallest edit distance /// found (so far) with the typo name. /// /// The pointer value being set to the current DeclContext indicates /// whether there is a keyword with this name. TypoEditDistanceMap CorrectionResults; SmallVector ValidatedCorrections; size_t CurrentTCIndex; size_t SavedTCIndex; Sema &SemaRef; Scope *S; std::unique_ptr SS; std::unique_ptr CorrectionValidator; DeclContext *MemberContext; LookupResult Result; NamespaceSpecifierSet Namespaces; SmallVector QualifiedResults; bool EnteringContext; bool SearchNamespaces; }; inline Sema::TypoExprState::TypoExprState() {} inline Sema::TypoExprState::TypoExprState(TypoExprState &&other) noexcept { *this = std::move(other); } inline Sema::TypoExprState &Sema::TypoExprState:: operator=(Sema::TypoExprState &&other) noexcept { Consumer = std::move(other.Consumer); DiagHandler = std::move(other.DiagHandler); RecoveryHandler = std::move(other.RecoveryHandler); return *this; } } // end namespace clang #endif