diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 24ceceeb69d0..77eda3b25c83 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1,12630 +1,12630 @@ //===--- Sema.h - Semantic Analysis & AST Building --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the Sema class, which performs semantic analysis and // builds ASTs. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SEMA_SEMA_H #define LLVM_CLANG_SEMA_SEMA_H #include "clang/AST/ASTConcept.h" #include "clang/AST/ASTFwd.h" #include "clang/AST/Attr.h" #include "clang/AST/Availability.h" #include "clang/AST/ComparisonCategories.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/LocInfoType.h" #include "clang/AST/MangleNumberingContext.h" #include "clang/AST/NSAPI.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/BitmaskEnum.h" #include "clang/Basic/ExpressionTraits.h" #include "clang/Basic/Module.h" #include "clang/Basic/OpenCLOptions.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/CleanupInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaConcept.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" #include #include #include #include #include namespace llvm { class APSInt; template struct DenseMapInfo; template class DenseSet; class SmallBitVector; struct InlineAsmIdentifierInfo; } namespace clang { class ADLResult; class ASTConsumer; class ASTContext; class ASTMutationListener; class ASTReader; class ASTWriter; class ArrayType; class ParsedAttr; class BindingDecl; class BlockDecl; class CapturedDecl; class CXXBasePath; class CXXBasePaths; class CXXBindTemporaryExpr; typedef SmallVector CXXCastPath; class CXXConstructorDecl; class CXXConversionDecl; class CXXDeleteExpr; class CXXDestructorDecl; class CXXFieldCollector; class CXXMemberCallExpr; class CXXMethodDecl; class CXXScopeSpec; class CXXTemporary; class CXXTryStmt; class CallExpr; class ClassTemplateDecl; class ClassTemplatePartialSpecializationDecl; class ClassTemplateSpecializationDecl; class VarTemplatePartialSpecializationDecl; class CodeCompleteConsumer; class CodeCompletionAllocator; class CodeCompletionTUInfo; class CodeCompletionResult; class CoroutineBodyStmt; class Decl; class DeclAccessPair; class DeclContext; class DeclRefExpr; class DeclaratorDecl; class DeducedTemplateArgument; class DependentDiagnostic; class DesignatedInitExpr; class Designation; class EnableIfAttr; class EnumConstantDecl; class Expr; class ExtVectorType; class FormatAttr; class FriendDecl; class FunctionDecl; class FunctionProtoType; class FunctionTemplateDecl; class ImplicitConversionSequence; typedef MutableArrayRef ConversionSequenceList; class InitListExpr; class InitializationKind; class InitializationSequence; class InitializedEntity; class IntegerLiteral; class LabelStmt; class LambdaExpr; class LangOptions; class LocalInstantiationScope; class LookupResult; class MacroInfo; typedef ArrayRef> ModuleIdPath; class ModuleLoader; class MultiLevelTemplateArgumentList; class NamedDecl; class ObjCCategoryDecl; class ObjCCategoryImplDecl; class ObjCCompatibleAliasDecl; class ObjCContainerDecl; class ObjCImplDecl; class ObjCImplementationDecl; class ObjCInterfaceDecl; class ObjCIvarDecl; template class ObjCList; class ObjCMessageExpr; class ObjCMethodDecl; class ObjCPropertyDecl; class ObjCProtocolDecl; class OMPThreadPrivateDecl; class OMPRequiresDecl; class OMPDeclareReductionDecl; class OMPDeclareSimdDecl; class OMPClause; struct OMPVarListLocTy; struct OverloadCandidate; enum class OverloadCandidateParamOrder : char; enum OverloadCandidateRewriteKind : unsigned; class OverloadCandidateSet; class OverloadExpr; class ParenListExpr; class ParmVarDecl; class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; class QualType; class StandardConversionSequence; class Stmt; class StringLiteral; class SwitchStmt; class TemplateArgument; class TemplateArgumentList; class TemplateArgumentLoc; class TemplateDecl; class TemplateInstantiationCallback; class TemplateParameterList; class TemplatePartialOrderingContext; class TemplateTemplateParmDecl; class Token; class TypeAliasDecl; class TypedefDecl; class TypedefNameDecl; class TypeLoc; class TypoCorrectionConsumer; class UnqualifiedId; class UnresolvedLookupExpr; class UnresolvedMemberExpr; class UnresolvedSetImpl; class UnresolvedSetIterator; class UsingDecl; class UsingShadowDecl; class ValueDecl; class VarDecl; class VarTemplateSpecializationDecl; class VisibilityAttr; class VisibleDeclConsumer; class IndirectFieldDecl; struct DeductionFailureInfo; class TemplateSpecCandidateSet; namespace sema { class AccessedEntity; class BlockScopeInfo; class Capture; class CapturedRegionScopeInfo; class CapturingScopeInfo; class CompoundScopeInfo; class DelayedDiagnostic; class DelayedDiagnosticPool; class FunctionScopeInfo; class LambdaScopeInfo; class PossiblyUnreachableDiag; class SemaPPCallbacks; class TemplateDeductionInfo; } namespace threadSafety { class BeforeSet; void threadSafetyCleanup(BeforeSet* Cache); } // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. typedef std::pair, SourceLocation> UnexpandedParameterPack; /// Describes whether we've seen any nullability information for the given /// file. struct FileNullability { /// The first pointer declarator (of any pointer kind) in the file that does /// not have a corresponding nullability annotation. SourceLocation PointerLoc; /// The end location for the first pointer declarator in the file. Used for /// placing fix-its. SourceLocation PointerEndLoc; /// Which kind of pointer declarator we saw. uint8_t PointerKind; /// Whether we saw any type nullability annotations in the given file. bool SawTypeNullability = false; }; /// A mapping from file IDs to a record of whether we've seen nullability /// information in that file. class FileNullabilityMap { /// A mapping from file IDs to the nullability information for each file ID. llvm::DenseMap Map; /// A single-element cache based on the file ID. struct { FileID File; FileNullability Nullability; } Cache; public: FileNullability &operator[](FileID file) { // Check the single-element cache. if (file == Cache.File) return Cache.Nullability; // It's not in the single-element cache; flush the cache if we have one. if (!Cache.File.isInvalid()) { Map[Cache.File] = Cache.Nullability; } // Pull this entry into the cache. Cache.File = file; Cache.Nullability = Map[file]; return Cache.Nullability; } }; /// Keeps track of expected type during expression parsing. The type is tied to /// a particular token, all functions that update or consume the type take a /// start location of the token they are looking at as a parameter. This allows /// to avoid updating the type on hot paths in the parser. class PreferredTypeBuilder { public: PreferredTypeBuilder() = default; explicit PreferredTypeBuilder(QualType Type) : Type(Type) {} void enterCondition(Sema &S, SourceLocation Tok); void enterReturn(Sema &S, SourceLocation Tok); void enterVariableInit(SourceLocation Tok, Decl *D); /// Computing a type for the function argument may require running /// overloading, so we postpone its computation until it is actually needed. /// /// Clients should be very careful when using this funciton, as it stores a /// function_ref, clients should make sure all calls to get() with the same /// location happen while function_ref is alive. void enterFunctionArgument(SourceLocation Tok, llvm::function_ref ComputeType); void enterParenExpr(SourceLocation Tok, SourceLocation LParLoc); void enterUnary(Sema &S, SourceLocation Tok, tok::TokenKind OpKind, SourceLocation OpLoc); void enterBinary(Sema &S, SourceLocation Tok, Expr *LHS, tok::TokenKind Op); void enterMemAccess(Sema &S, SourceLocation Tok, Expr *Base); void enterSubscript(Sema &S, SourceLocation Tok, Expr *LHS); /// Handles all type casts, including C-style cast, C++ casts, etc. void enterTypeCast(SourceLocation Tok, QualType CastType); QualType get(SourceLocation Tok) const { if (Tok != ExpectedLoc) return QualType(); if (!Type.isNull()) return Type; if (ComputeType) return ComputeType(); return QualType(); } private: /// Start position of a token for which we store expected type. SourceLocation ExpectedLoc; /// Expected type for a token starting at ExpectedLoc. QualType Type; /// A function to compute expected type at ExpectedLoc. It is only considered /// if Type is null. llvm::function_ref ComputeType; }; /// Sema - This implements semantic analysis and AST building for C. class Sema final { Sema(const Sema &) = delete; void operator=(const Sema &) = delete; /// A key method to reduce duplicate debug info from Sema. virtual void anchor(); ///Source of additional semantic information. ExternalSemaSource *ExternalSource; ///Whether Sema has generated a multiplexer and has to delete it. bool isMultiplexExternalSource; static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD); bool isVisibleSlow(const NamedDecl *D); /// Determine whether two declarations should be linked together, given that /// the old declaration might not be visible and the new declaration might /// not have external linkage. bool shouldLinkPossiblyHiddenDecl(const NamedDecl *Old, const NamedDecl *New) { if (isVisible(Old)) return true; // See comment in below overload for why it's safe to compute the linkage // of the new declaration here. if (New->isExternallyDeclarable()) { assert(Old->isExternallyDeclarable() && "should not have found a non-externally-declarable previous decl"); return true; } return false; } bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New); void setupImplicitSpecialMemberType(CXXMethodDecl *SpecialMem, QualType ResultTy, ArrayRef Args); public: /// The maximum alignment, same as in llvm::Value. We duplicate them here /// because that allows us not to duplicate the constants in clang code, /// which we must to since we can't directly use the llvm constants. /// The value is verified against llvm here: lib/CodeGen/CGDecl.cpp /// /// This is the greatest alignment value supported by load, store, and alloca /// instructions, and global values. static const unsigned MaxAlignmentExponent = 29; static const unsigned MaximumAlignment = 1u << MaxAlignmentExponent; typedef OpaquePtr DeclGroupPtrTy; typedef OpaquePtr TemplateTy; typedef OpaquePtr TypeTy; OpenCLOptions OpenCLFeatures; FPOptions CurFPFeatures; const LangOptions &LangOpts; Preprocessor &PP; ASTContext &Context; ASTConsumer &Consumer; DiagnosticsEngine &Diags; SourceManager &SourceMgr; /// Flag indicating whether or not to collect detailed statistics. bool CollectStats; /// Code-completion consumer. CodeCompleteConsumer *CodeCompleter; /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; /// Generally null except when we temporarily switch decl contexts, /// like in \see ActOnObjCTemporaryExitContainerContext. DeclContext *OriginalLexicalContext; /// VAListTagName - The declaration name corresponding to __va_list_tag. /// This is used as part of a hack to omit that class from ADL results. DeclarationName VAListTagName; bool MSStructPragmaOn; // True when \#pragma ms_struct on /// Controls member pointer representation format under the MS ABI. LangOptions::PragmaMSPointersToMembersKind MSPointerToMemberRepresentationMethod; /// Stack of active SEH __finally scopes. Can be empty. SmallVector CurrentSEHFinally; /// Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; /// Holds TypoExprs that are created from `createDelayedTypo`. This is used by /// `TransformTypos` in order to keep track of any TypoExprs that are created /// recursively during typo correction and wipe them away if the correction /// fails. llvm::SmallVector TypoExprs; /// pragma clang section kind enum PragmaClangSectionKind { PCSK_Invalid = 0, PCSK_BSS = 1, PCSK_Data = 2, PCSK_Rodata = 3, PCSK_Text = 4, PCSK_Relro = 5 }; enum PragmaClangSectionAction { PCSA_Set = 0, PCSA_Clear = 1 }; struct PragmaClangSection { std::string SectionName; bool Valid = false; SourceLocation PragmaLocation; void Act(SourceLocation PragmaLocation, PragmaClangSectionAction Action, StringLiteral* Name); }; PragmaClangSection PragmaClangBSSSection; PragmaClangSection PragmaClangDataSection; PragmaClangSection PragmaClangRodataSection; PragmaClangSection PragmaClangRelroSection; PragmaClangSection PragmaClangTextSection; enum PragmaMsStackAction { PSK_Reset = 0x0, // #pragma () PSK_Set = 0x1, // #pragma (value) PSK_Push = 0x2, // #pragma (push[, id]) PSK_Pop = 0x4, // #pragma (pop[, id]) PSK_Show = 0x8, // #pragma (show) -- only for "pack"! PSK_Push_Set = PSK_Push | PSK_Set, // #pragma (push[, id], value) PSK_Pop_Set = PSK_Pop | PSK_Set, // #pragma (pop[, id], value) }; template struct PragmaStack { struct Slot { llvm::StringRef StackSlotLabel; ValueType Value; SourceLocation PragmaLocation; SourceLocation PragmaPushLocation; Slot(llvm::StringRef StackSlotLabel, ValueType Value, SourceLocation PragmaLocation, SourceLocation PragmaPushLocation) : StackSlotLabel(StackSlotLabel), Value(Value), PragmaLocation(PragmaLocation), PragmaPushLocation(PragmaPushLocation) {} }; void Act(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, ValueType Value) { if (Action == PSK_Reset) { CurrentValue = DefaultValue; CurrentPragmaLocation = PragmaLocation; return; } if (Action & PSK_Push) Stack.emplace_back(StackSlotLabel, CurrentValue, CurrentPragmaLocation, PragmaLocation); else if (Action & PSK_Pop) { if (!StackSlotLabel.empty()) { // If we've got a label, try to find it and jump there. auto I = llvm::find_if(llvm::reverse(Stack), [&](const Slot &x) { return x.StackSlotLabel == StackSlotLabel; }); // If we found the label so pop from there. if (I != Stack.rend()) { CurrentValue = I->Value; CurrentPragmaLocation = I->PragmaLocation; Stack.erase(std::prev(I.base()), Stack.end()); } } else if (!Stack.empty()) { // We do not have a label, just pop the last entry. CurrentValue = Stack.back().Value; CurrentPragmaLocation = Stack.back().PragmaLocation; Stack.pop_back(); } } if (Action & PSK_Set) { CurrentValue = Value; CurrentPragmaLocation = PragmaLocation; } } // MSVC seems to add artificial slots to #pragma stacks on entering a C++ // method body to restore the stacks on exit, so it works like this: // // struct S { // #pragma (push, InternalPragmaSlot, ) // void Method {} // #pragma (pop, InternalPragmaSlot) // }; // // It works even with #pragma vtordisp, although MSVC doesn't support // #pragma vtordisp(push [, id], n) // syntax. // // Push / pop a named sentinel slot. void SentinelAction(PragmaMsStackAction Action, StringRef Label) { assert((Action == PSK_Push || Action == PSK_Pop) && "Can only push / pop #pragma stack sentinels!"); Act(CurrentPragmaLocation, Action, Label, CurrentValue); } // Constructors. explicit PragmaStack(const ValueType &Default) : DefaultValue(Default), CurrentValue(Default) {} bool hasValue() const { return CurrentValue != DefaultValue; } SmallVector Stack; ValueType DefaultValue; // Value used for PSK_Reset action. ValueType CurrentValue; SourceLocation CurrentPragmaLocation; }; // FIXME: We should serialize / deserialize these if they occur in a PCH (but // we shouldn't do so if they're in a module). /// Whether to insert vtordisps prior to virtual bases in the Microsoft /// C++ ABI. Possible values are 0, 1, and 2, which mean: /// /// 0: Suppress all vtordisps /// 1: Insert vtordisps in the presence of vbase overrides and non-trivial /// structors /// 2: Always insert vtordisps to support RTTI on partially constructed /// objects PragmaStack VtorDispStack; // #pragma pack. // Sentinel to represent when the stack is set to mac68k alignment. static const unsigned kMac68kAlignmentSentinel = ~0U; PragmaStack PackStack; // The current #pragma pack values and locations at each #include. struct PackIncludeState { unsigned CurrentValue; SourceLocation CurrentPragmaLocation; bool HasNonDefaultValue, ShouldWarnOnInclude; }; SmallVector PackIncludeStack; // Segment #pragmas. PragmaStack DataSegStack; PragmaStack BSSSegStack; PragmaStack ConstSegStack; PragmaStack CodeSegStack; // This stack tracks the current state of Sema.CurFPFeatures. PragmaStack FpPragmaStack; FPOptionsOverride CurFPFeatureOverrides() { FPOptionsOverride result; if (!FpPragmaStack.hasValue()) { result = FPOptionsOverride(); } else { result = FPOptionsOverride(FpPragmaStack.CurrentValue); } return result; } // RAII object to push / pop sentinel slots for all MS #pragma stacks. // Actions should be performed only if we enter / exit a C++ method body. class PragmaStackSentinelRAII { public: PragmaStackSentinelRAII(Sema &S, StringRef SlotLabel, bool ShouldAct); ~PragmaStackSentinelRAII(); private: Sema &S; StringRef SlotLabel; bool ShouldAct; }; /// A mapping that describes the nullability we've seen in each header file. FileNullabilityMap NullabilityMap; /// Last section used with #pragma init_seg. StringLiteral *CurInitSeg; SourceLocation CurInitSegLoc; /// VisContext - Manages the stack for \#pragma GCC visibility. void *VisContext; // Really a "PragmaVisStack*" /// This an attribute introduced by \#pragma clang attribute. struct PragmaAttributeEntry { SourceLocation Loc; ParsedAttr *Attribute; SmallVector MatchRules; bool IsUsed; }; /// A push'd group of PragmaAttributeEntries. struct PragmaAttributeGroup { /// The location of the push attribute. SourceLocation Loc; /// The namespace of this push group. const IdentifierInfo *Namespace; SmallVector Entries; }; SmallVector PragmaAttributeStack; /// The declaration that is currently receiving an attribute from the /// #pragma attribute stack. const Decl *PragmaAttributeCurrentTargetDecl; /// This represents the last location of a "#pragma clang optimize off" /// directive if such a directive has not been closed by an "on" yet. If /// optimizations are currently "on", this is set to an invalid location. SourceLocation OptimizeOffPragmaLocation; /// Flag indicating if Sema is building a recovery call expression. /// /// This flag is used to avoid building recovery call expressions /// if Sema is already doing so, which would cause infinite recursions. bool IsBuildingRecoveryCallExpr; /// Used to control the generation of ExprWithCleanups. CleanupInfo Cleanup; /// ExprCleanupObjects - This is the stack of objects requiring /// cleanup that are created by the current full expression. SmallVector ExprCleanupObjects; /// Store a set of either DeclRefExprs or MemberExprs that contain a reference /// to a variable (constant) that may or may not be odr-used in this Expr, and /// we won't know until all lvalue-to-rvalue and discarded value conversions /// have been applied to all subexpressions of the enclosing full expression. /// This is cleared at the end of each full expression. using MaybeODRUseExprSet = llvm::SetVector, llvm::SmallPtrSet>; MaybeODRUseExprSet MaybeODRUseExprs; std::unique_ptr CachedFunctionScope; /// Stack containing information about each of the nested /// function, block, and method scopes that are currently active. SmallVector FunctionScopes; /// The index of the first FunctionScope that corresponds to the current /// context. unsigned FunctionScopesStart = 0; ArrayRef getFunctionScopes() const { return llvm::makeArrayRef(FunctionScopes.begin() + FunctionScopesStart, FunctionScopes.end()); } /// Stack containing information needed when in C++2a an 'auto' is encountered /// in a function declaration parameter type specifier in order to invent a /// corresponding template parameter in the enclosing abbreviated function /// template. This information is also present in LambdaScopeInfo, stored in /// the FunctionScopes stack. SmallVector InventedParameterInfos; /// The index of the first InventedParameterInfo that refers to the current /// context. unsigned InventedParameterInfosStart = 0; ArrayRef getInventedParameterInfos() const { return llvm::makeArrayRef(InventedParameterInfos.begin() + InventedParameterInfosStart, InventedParameterInfos.end()); } typedef LazyVector ExtVectorDeclsType; /// ExtVectorDecls - This is a list all the extended vector types. This allows /// us to associate a raw vector type with one of the ext_vector type names. /// This is only necessary for issuing pretty diagnostics. ExtVectorDeclsType ExtVectorDecls; /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. std::unique_ptr FieldCollector; typedef llvm::SmallSetVector NamedDeclSetType; /// Set containing all declared private fields that are not used. NamedDeclSetType UnusedPrivateFields; /// Set containing all typedefs that are likely unused. llvm::SmallSetVector UnusedLocalTypedefNameCandidates; /// Delete-expressions to be analyzed at the end of translation unit /// /// This list contains class members, and locations of delete-expressions /// that could not be proven as to whether they mismatch with new-expression /// used in initializer of the field. typedef std::pair DeleteExprLoc; typedef llvm::SmallVector DeleteLocs; llvm::MapVector DeleteExprs; typedef llvm::SmallPtrSet RecordDeclSetTy; /// PureVirtualClassDiagSet - a set of class declarations which we have /// emitted a list of pure virtual functions. Used to prevent emitting the /// same list more than once. std::unique_ptr PureVirtualClassDiagSet; /// ParsingInitForAutoVars - a set of declarations with auto types for which /// we are currently parsing the initializer. llvm::SmallPtrSet ParsingInitForAutoVars; /// Look for a locally scoped extern "C" declaration by the given name. NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name); typedef LazyVector TentativeDefinitionsType; /// All the tentative definitions encountered in the TU. TentativeDefinitionsType TentativeDefinitions; /// All the external declarations encoutered and used in the TU. SmallVector ExternalDeclarations; typedef LazyVector UnusedFileScopedDeclsType; /// The set of file scoped decls seen so far that have not been used /// and must warn if not used. Only contains the first declaration. UnusedFileScopedDeclsType UnusedFileScopedDecls; typedef LazyVector DelegatingCtorDeclsType; /// All the delegating constructors seen so far in the file, used for /// cycle detection at the end of the TU. DelegatingCtorDeclsType DelegatingCtorDecls; /// All the overriding functions seen during a class definition /// that had their exception spec checks delayed, plus the overridden /// function. SmallVector, 2> DelayedOverridingExceptionSpecChecks; /// All the function redeclarations seen during a class definition that had /// their exception spec checks delayed, plus the prior declaration they /// should be checked against. Except during error recovery, the new decl /// should always be a friend declaration, as that's the only valid way to /// redeclare a special member before its class is complete. SmallVector, 2> DelayedEquivalentExceptionSpecChecks; typedef llvm::MapVector> LateParsedTemplateMapT; LateParsedTemplateMapT LateParsedTemplateMap; /// Callback to the parser to parse templated functions when needed. typedef void LateTemplateParserCB(void *P, LateParsedTemplate &LPT); typedef void LateTemplateParserCleanupCB(void *P); LateTemplateParserCB *LateTemplateParser; LateTemplateParserCleanupCB *LateTemplateParserCleanup; void *OpaqueParser; void SetLateTemplateParser(LateTemplateParserCB *LTP, LateTemplateParserCleanupCB *LTPCleanup, void *P) { LateTemplateParser = LTP; LateTemplateParserCleanup = LTPCleanup; OpaqueParser = P; } class DelayedDiagnostics; class DelayedDiagnosticsState { sema::DelayedDiagnosticPool *SavedPool; friend class Sema::DelayedDiagnostics; }; typedef DelayedDiagnosticsState ParsingDeclState; typedef DelayedDiagnosticsState ProcessingContextState; /// A class which encapsulates the logic for delaying diagnostics /// during parsing and other processing. class DelayedDiagnostics { /// The current pool of diagnostics into which delayed /// diagnostics should go. sema::DelayedDiagnosticPool *CurPool; public: DelayedDiagnostics() : CurPool(nullptr) {} /// Adds a delayed diagnostic. void add(const sema::DelayedDiagnostic &diag); // in DelayedDiagnostic.h /// Determines whether diagnostics should be delayed. bool shouldDelayDiagnostics() { return CurPool != nullptr; } /// Returns the current delayed-diagnostics pool. sema::DelayedDiagnosticPool *getCurrentPool() const { return CurPool; } /// Enter a new scope. Access and deprecation diagnostics will be /// collected in this pool. DelayedDiagnosticsState push(sema::DelayedDiagnosticPool &pool) { DelayedDiagnosticsState state; state.SavedPool = CurPool; CurPool = &pool; return state; } /// Leave a delayed-diagnostic state that was previously pushed. /// Do not emit any of the diagnostics. This is performed as part /// of the bookkeeping of popping a pool "properly". void popWithoutEmitting(DelayedDiagnosticsState state) { CurPool = state.SavedPool; } /// Enter a new scope where access and deprecation diagnostics are /// not delayed. DelayedDiagnosticsState pushUndelayed() { DelayedDiagnosticsState state; state.SavedPool = CurPool; CurPool = nullptr; return state; } /// Undo a previous pushUndelayed(). void popUndelayed(DelayedDiagnosticsState state) { assert(CurPool == nullptr); CurPool = state.SavedPool; } } DelayedDiagnostics; /// A RAII object to temporarily push a declaration context. class ContextRAII { private: Sema &S; DeclContext *SavedContext; ProcessingContextState SavedContextState; QualType SavedCXXThisTypeOverride; unsigned SavedFunctionScopesStart; unsigned SavedInventedParameterInfosStart; public: ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = true) : S(S), SavedContext(S.CurContext), SavedContextState(S.DelayedDiagnostics.pushUndelayed()), SavedCXXThisTypeOverride(S.CXXThisTypeOverride), SavedFunctionScopesStart(S.FunctionScopesStart), SavedInventedParameterInfosStart(S.InventedParameterInfosStart) { assert(ContextToPush && "pushing null context"); S.CurContext = ContextToPush; if (NewThisContext) S.CXXThisTypeOverride = QualType(); // Any saved FunctionScopes do not refer to this context. S.FunctionScopesStart = S.FunctionScopes.size(); S.InventedParameterInfosStart = S.InventedParameterInfos.size(); } void pop() { if (!SavedContext) return; S.CurContext = SavedContext; S.DelayedDiagnostics.popUndelayed(SavedContextState); S.CXXThisTypeOverride = SavedCXXThisTypeOverride; S.FunctionScopesStart = SavedFunctionScopesStart; S.InventedParameterInfosStart = SavedInventedParameterInfosStart; SavedContext = nullptr; } ~ContextRAII() { pop(); } }; /// Whether the AST is currently being rebuilt to correct immediate /// invocations. Immediate invocation candidates and references to consteval /// functions aren't tracked when this is set. bool RebuildingImmediateInvocation = false; /// Used to change context to isConstantEvaluated without pushing a heavy /// ExpressionEvaluationContextRecord object. bool isConstantEvaluatedOverride; bool isConstantEvaluated() { return ExprEvalContexts.back().isConstantEvaluated() || isConstantEvaluatedOverride; } /// RAII object to handle the state changes required to synthesize /// a function body. class SynthesizedFunctionScope { Sema &S; Sema::ContextRAII SavedContext; bool PushedCodeSynthesisContext = false; public: SynthesizedFunctionScope(Sema &S, DeclContext *DC) : S(S), SavedContext(S, DC) { S.PushFunctionScope(); S.PushExpressionEvaluationContext( Sema::ExpressionEvaluationContext::PotentiallyEvaluated); if (auto *FD = dyn_cast(DC)) FD->setWillHaveBody(true); else assert(isa(DC)); } void addContextNote(SourceLocation UseLoc) { assert(!PushedCodeSynthesisContext); Sema::CodeSynthesisContext Ctx; Ctx.Kind = Sema::CodeSynthesisContext::DefiningSynthesizedFunction; Ctx.PointOfInstantiation = UseLoc; Ctx.Entity = cast(S.CurContext); S.pushCodeSynthesisContext(Ctx); PushedCodeSynthesisContext = true; } ~SynthesizedFunctionScope() { if (PushedCodeSynthesisContext) S.popCodeSynthesisContext(); if (auto *FD = dyn_cast(S.CurContext)) FD->setWillHaveBody(false); S.PopExpressionEvaluationContext(); S.PopFunctionScopeInfo(); } }; /// WeakUndeclaredIdentifiers - Identifiers contained in /// \#pragma weak before declared. rare. may alias another /// identifier, declared or undeclared llvm::MapVector WeakUndeclaredIdentifiers; /// ExtnameUndeclaredIdentifiers - Identifiers contained in /// \#pragma redefine_extname before declared. Used in Solaris system headers /// to define functions that occur in multiple standards to call the version /// in the currently selected standard. llvm::DenseMap ExtnameUndeclaredIdentifiers; /// Load weak undeclared identifiers from the external source. void LoadExternalWeakUndeclaredIdentifiers(); /// WeakTopLevelDecl - Translation-unit scoped declarations generated by /// \#pragma weak during processing of other Decls. /// I couldn't figure out a clean way to generate these in-line, so /// we store them here and handle separately -- which is a hack. /// It would be best to refactor this. SmallVector WeakTopLevelDecl; IdentifierResolver IdResolver; /// Translation Unit Scope - useful to Objective-C actions that need /// to lookup file scope declarations in the "ordinary" C decl namespace. /// For example, user-defined classes, built-in "id" type, etc. Scope *TUScope; /// The C++ "std" namespace, where the standard library resides. LazyDeclPtr StdNamespace; /// The C++ "std::bad_alloc" class, which is defined by the C++ /// standard library. LazyDeclPtr StdBadAlloc; /// The C++ "std::align_val_t" enum class, which is defined by the C++ /// standard library. LazyDeclPtr StdAlignValT; /// The C++ "std::experimental" namespace, where the experimental parts /// of the standard library resides. NamespaceDecl *StdExperimentalNamespaceCache; /// The C++ "std::initializer_list" template, which is defined in /// \. ClassTemplateDecl *StdInitializerList; /// The C++ "std::coroutine_traits" template, which is defined in /// \ ClassTemplateDecl *StdCoroutineTraitsCache; /// The C++ "type_info" declaration, which is defined in \. RecordDecl *CXXTypeInfoDecl; /// The MSVC "_GUID" struct, which is defined in MSVC header files. RecordDecl *MSVCGuidDecl; /// Caches identifiers/selectors for NSFoundation APIs. std::unique_ptr NSAPIObj; /// The declaration of the Objective-C NSNumber class. ObjCInterfaceDecl *NSNumberDecl; /// The declaration of the Objective-C NSValue class. ObjCInterfaceDecl *NSValueDecl; /// Pointer to NSNumber type (NSNumber *). QualType NSNumberPointer; /// Pointer to NSValue type (NSValue *). QualType NSValuePointer; /// The Objective-C NSNumber methods used to create NSNumber literals. ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods]; /// The declaration of the Objective-C NSString class. ObjCInterfaceDecl *NSStringDecl; /// Pointer to NSString type (NSString *). QualType NSStringPointer; /// The declaration of the stringWithUTF8String: method. ObjCMethodDecl *StringWithUTF8StringMethod; /// The declaration of the valueWithBytes:objCType: method. ObjCMethodDecl *ValueWithBytesObjCTypeMethod; /// The declaration of the Objective-C NSArray class. ObjCInterfaceDecl *NSArrayDecl; /// The declaration of the arrayWithObjects:count: method. ObjCMethodDecl *ArrayWithObjectsMethod; /// The declaration of the Objective-C NSDictionary class. ObjCInterfaceDecl *NSDictionaryDecl; /// The declaration of the dictionaryWithObjects:forKeys:count: method. ObjCMethodDecl *DictionaryWithObjectsMethod; /// id type. QualType QIDNSCopying; /// will hold 'respondsToSelector:' Selector RespondsToSelectorSel; /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; /// A flag to indicate that we're in a context that permits abstract /// references to fields. This is really a bool AllowAbstractFieldReference; /// Describes how the expressions currently being parsed are /// evaluated at run-time, if at all. enum class ExpressionEvaluationContext { /// The current expression and its subexpressions occur within an /// unevaluated operand (C++11 [expr]p7), such as the subexpression of /// \c sizeof, where the type of the expression may be significant but /// no code will be generated to evaluate the value of the expression at /// run time. Unevaluated, /// The current expression occurs within a braced-init-list within /// an unevaluated operand. This is mostly like a regular unevaluated /// context, except that we still instantiate constexpr functions that are /// referenced here so that we can perform narrowing checks correctly. UnevaluatedList, /// The current expression occurs within a discarded statement. /// This behaves largely similarly to an unevaluated operand in preventing /// definitions from being required, but not in other ways. DiscardedStatement, /// The current expression occurs within an unevaluated /// operand that unconditionally permits abstract references to /// fields, such as a SIZE operator in MS-style inline assembly. UnevaluatedAbstract, /// The current context is "potentially evaluated" in C++11 terms, /// but the expression is evaluated at compile-time (like the values of /// cases in a switch statement). ConstantEvaluated, /// The current expression is potentially evaluated at run time, /// which means that code may be generated to evaluate the value of the /// expression at run time. PotentiallyEvaluated, /// The current expression is potentially evaluated, but any /// declarations referenced inside that expression are only used if /// in fact the current expression is used. /// /// This value is used when parsing default function arguments, for which /// we would like to provide diagnostics (e.g., passing non-POD arguments /// through varargs) but do not want to mark declarations as "referenced" /// until the default argument is used. PotentiallyEvaluatedIfUsed }; using ImmediateInvocationCandidate = llvm::PointerIntPair; /// Data structure used to record current or nested /// expression evaluation contexts. struct ExpressionEvaluationContextRecord { /// The expression evaluation context. ExpressionEvaluationContext Context; /// Whether the enclosing context needed a cleanup. CleanupInfo ParentCleanup; /// Whether we are in a decltype expression. bool IsDecltype; /// The number of active cleanup objects when we entered /// this expression evaluation context. unsigned NumCleanupObjects; /// The number of typos encountered during this expression evaluation /// context (i.e. the number of TypoExprs created). unsigned NumTypos; MaybeODRUseExprSet SavedMaybeODRUseExprs; /// The lambdas that are present within this context, if it /// is indeed an unevaluated context. SmallVector Lambdas; /// The declaration that provides context for lambda expressions /// and block literals if the normal declaration context does not /// suffice, e.g., in a default function argument. Decl *ManglingContextDecl; /// If we are processing a decltype type, a set of call expressions /// for which we have deferred checking the completeness of the return type. SmallVector DelayedDecltypeCalls; /// If we are processing a decltype type, a set of temporary binding /// expressions for which we have deferred checking the destructor. SmallVector DelayedDecltypeBinds; llvm::SmallPtrSet PossibleDerefs; /// Expressions appearing as the LHS of a volatile assignment in this /// context. We produce a warning for these when popping the context if /// they are not discarded-value expressions nor unevaluated operands. SmallVector VolatileAssignmentLHSs; /// Set of candidates for starting an immediate invocation. llvm::SmallVector ImmediateInvocationCandidates; /// Set of DeclRefExprs referencing a consteval function when used in a /// context not already known to be immediately invoked. llvm::SmallPtrSet ReferenceToConsteval; /// \brief Describes whether we are in an expression constext which we have /// to handle differently. enum ExpressionKind { EK_Decltype, EK_TemplateArgument, EK_Other } ExprContext; ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, CleanupInfo ParentCleanup, Decl *ManglingContextDecl, ExpressionKind ExprContext) : Context(Context), ParentCleanup(ParentCleanup), NumCleanupObjects(NumCleanupObjects), NumTypos(0), ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext) {} bool isUnevaluated() const { return Context == ExpressionEvaluationContext::Unevaluated || Context == ExpressionEvaluationContext::UnevaluatedAbstract || Context == ExpressionEvaluationContext::UnevaluatedList; } bool isConstantEvaluated() const { return Context == ExpressionEvaluationContext::ConstantEvaluated; } }; /// A stack of expression evaluation contexts. SmallVector ExprEvalContexts; /// Emit a warning for all pending noderef expressions that we recorded. void WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec); /// Compute the mangling number context for a lambda expression or /// block literal. Also return the extra mangling decl if any. /// /// \param DC - The DeclContext containing the lambda expression or /// block literal. std::tuple getCurrentMangleNumberContext(const DeclContext *DC); /// SpecialMemberOverloadResult - The overloading result for a special member /// function. /// /// This is basically a wrapper around PointerIntPair. The lowest bits of the /// integer are used to determine whether overload resolution succeeded. class SpecialMemberOverloadResult { public: enum Kind { NoMemberOrDeleted, Ambiguous, Success }; private: llvm::PointerIntPair Pair; public: SpecialMemberOverloadResult() : Pair() {} SpecialMemberOverloadResult(CXXMethodDecl *MD) : Pair(MD, MD->isDeleted() ? NoMemberOrDeleted : Success) {} CXXMethodDecl *getMethod() const { return Pair.getPointer(); } void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); } Kind getKind() const { return static_cast(Pair.getInt()); } void setKind(Kind K) { Pair.setInt(K); } }; class SpecialMemberOverloadResultEntry : public llvm::FastFoldingSetNode, public SpecialMemberOverloadResult { public: SpecialMemberOverloadResultEntry(const llvm::FoldingSetNodeID &ID) : FastFoldingSetNode(ID) {} }; /// A cache of special member function overload resolution results /// for C++ records. llvm::FoldingSet SpecialMemberCache; /// A cache of the flags available in enumerations with the flag_bits /// attribute. mutable llvm::DenseMap FlagBitsCache; /// The kind of translation unit we are processing. /// /// When we're processing a complete translation unit, Sema will perform /// end-of-translation-unit semantic tasks (such as creating /// initializers for tentative definitions in C) once parsing has /// completed. Modules and precompiled headers perform different kinds of /// checks. TranslationUnitKind TUKind; llvm::BumpPtrAllocator BumpAlloc; /// The number of SFINAE diagnostics that have been trapped. unsigned NumSFINAEErrors; typedef llvm::DenseMap> UnparsedDefaultArgInstantiationsMap; /// A mapping from parameters with unparsed default arguments to the /// set of instantiations of each parameter. /// /// This mapping is a temporary data structure used when parsing /// nested class templates or nested classes of class templates, /// where we might end up instantiating an inner class before the /// default arguments of its methods have been parsed. UnparsedDefaultArgInstantiationsMap UnparsedDefaultArgInstantiations; // Contains the locations of the beginning of unparsed default // argument locations. llvm::DenseMap UnparsedDefaultArgLocs; /// UndefinedInternals - all the used, undefined objects which require a /// definition in this translation unit. llvm::MapVector UndefinedButUsed; /// Determine if VD, which must be a variable or function, is an external /// symbol that nonetheless can't be referenced from outside this translation /// unit because its type has no linkage and it's not extern "C". bool isExternalWithNoLinkageType(ValueDecl *VD); /// Obtain a sorted list of functions that are undefined but ODR-used. void getUndefinedButUsed( SmallVectorImpl > &Undefined); /// Retrieves list of suspicious delete-expressions that will be checked at /// the end of translation unit. const llvm::MapVector & getMismatchingDeleteExpressions() const; typedef std::pair GlobalMethods; typedef llvm::DenseMap GlobalMethodPool; /// Method Pool - allows efficient lookup when typechecking messages to "id". /// We need to maintain a list, since selectors can have differing signatures /// across classes. In Cocoa, this happens to be extremely uncommon (only 1% /// of selectors are "overloaded"). /// At the head of the list it is recorded whether there were 0, 1, or >= 2 /// methods inside categories with a particular selector. GlobalMethodPool MethodPool; /// Method selectors used in a \@selector expression. Used for implementation /// of -Wselector. llvm::MapVector ReferencedSelectors; /// List of SourceLocations where 'self' is implicitly retained inside a /// block. llvm::SmallVector, 1> ImplicitlyRetainedSelfLocs; /// Kinds of C++ special members. enum CXXSpecialMember { CXXDefaultConstructor, CXXCopyConstructor, CXXMoveConstructor, CXXCopyAssignment, CXXMoveAssignment, CXXDestructor, CXXInvalid }; typedef llvm::PointerIntPair SpecialMemberDecl; /// The C++ special members which we are currently in the process of /// declaring. If this process recursively triggers the declaration of the /// same special member, we should act as if it is not yet declared. llvm::SmallPtrSet SpecialMembersBeingDeclared; /// Kinds of defaulted comparison operator functions. enum class DefaultedComparisonKind : unsigned char { /// This is not a defaultable comparison operator. None, /// This is an operator== that should be implemented as a series of /// subobject comparisons. Equal, /// This is an operator<=> that should be implemented as a series of /// subobject comparisons. ThreeWay, /// This is an operator!= that should be implemented as a rewrite in terms /// of a == comparison. NotEqual, /// This is an <, <=, >, or >= that should be implemented as a rewrite in /// terms of a <=> comparison. Relational, }; /// The function definitions which were renamed as part of typo-correction /// to match their respective declarations. We want to keep track of them /// to ensure that we don't emit a "redefinition" error if we encounter a /// correctly named definition after the renamed definition. llvm::SmallPtrSet TypoCorrectedFunctionDefinitions; /// Stack of types that correspond to the parameter entities that are /// currently being copy-initialized. Can be empty. llvm::SmallVector CurrentParameterCopyTypes; void ReadMethodPool(Selector Sel); void updateOutOfDateSelector(Selector Sel); /// Private Helper predicate to check for 'self'. bool isSelfExpr(Expr *RExpr); bool isSelfExpr(Expr *RExpr, const ObjCMethodDecl *Method); /// Cause the active diagnostic on the DiagosticsEngine to be /// emitted. This is closely coupled to the SemaDiagnosticBuilder class and /// should not be used elsewhere. void EmitCurrentDiagnostic(unsigned DiagID); /// Records and restores the CurFPFeatures state on entry/exit of compound /// statements. class FPFeaturesStateRAII { public: FPFeaturesStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.CurFPFeatures) { OldOverrides = S.FpPragmaStack.CurrentValue; } ~FPFeaturesStateRAII() { S.CurFPFeatures = OldFPFeaturesState; S.FpPragmaStack.CurrentValue = OldOverrides; } unsigned getOverrides() { return OldOverrides; } private: Sema& S; FPOptions OldFPFeaturesState; unsigned OldOverrides; }; void addImplicitTypedef(StringRef Name, QualType T); bool WarnedStackExhausted = false; public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind = TU_Complete, CodeCompleteConsumer *CompletionConsumer = nullptr); ~Sema(); /// Perform initialization that occurs after the parser has been /// initialized but before it parses anything. void Initialize(); const LangOptions &getLangOpts() const { return LangOpts; } OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; } FPOptions &getCurFPFeatures() { return CurFPFeatures; } DiagnosticsEngine &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } Preprocessor &getPreprocessor() const { return PP; } ASTContext &getASTContext() const { return Context; } ASTConsumer &getASTConsumer() const { return Consumer; } ASTMutationListener *getASTMutationListener() const; ExternalSemaSource* getExternalSource() const { return ExternalSource; } ///Registers an external source. If an external source already exists, /// creates a multiplex external source and appends to it. /// ///\param[in] E - A non-null external sema source. /// void addExternalSource(ExternalSemaSource *E); void PrintStats() const; /// Warn that the stack is nearly exhausted. void warnStackExhausted(SourceLocation Loc); /// Run some code with "sufficient" stack space. (Currently, at least 256K is /// guaranteed). Produces a warning if we're low on stack space and allocates /// more in that case. Use this in code that may recurse deeply (for example, /// in template instantiation) to avoid stack overflow. void runWithSufficientStackSpace(SourceLocation Loc, llvm::function_ref Fn); /// Helper class that creates diagnostics with optional /// template instantiation stacks. /// /// This class provides a wrapper around the basic DiagnosticBuilder /// class that emits diagnostics. SemaDiagnosticBuilder is /// responsible for emitting the diagnostic (as DiagnosticBuilder /// does) and, if the diagnostic comes from inside a template /// instantiation, printing the template instantiation stack as /// well. class SemaDiagnosticBuilder : public DiagnosticBuilder { Sema &SemaRef; unsigned DiagID; public: SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } // This is a cunning lie. DiagnosticBuilder actually performs move // construction in its copy constructor (but due to varied uses, it's not // possible to conveniently express this as actual move construction). So // the default copy ctor here is fine, because the base class disables the // source anyway, so the user-defined ~SemaDiagnosticBuilder is a safe no-op // in that case anwyay. SemaDiagnosticBuilder(const SemaDiagnosticBuilder&) = default; ~SemaDiagnosticBuilder() { // If we aren't active, there is nothing to do. if (!isActive()) return; // Otherwise, we need to emit the diagnostic. First flush the underlying // DiagnosticBuilder data, and clear the diagnostic builder itself so it // won't emit the diagnostic in its own destructor. // // This seems wasteful, in that as written the DiagnosticBuilder dtor will // do its own needless checks to see if the diagnostic needs to be // emitted. However, because we take care to ensure that the builder // objects never escape, a sufficiently smart compiler will be able to // eliminate that code. FlushCounts(); Clear(); // Dispatch to Sema to emit the diagnostic. SemaRef.EmitCurrentDiagnostic(DiagID); } /// Teach operator<< to produce an object of the correct type. template friend const SemaDiagnosticBuilder &operator<<( const SemaDiagnosticBuilder &Diag, const T &Value) { const DiagnosticBuilder &BaseDiag = Diag; BaseDiag << Value; return Diag; } }; /// Emit a diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { DiagnosticBuilder DB = Diags.Report(Loc, DiagID); return SemaDiagnosticBuilder(DB, *this, DiagID); } /// Emit a partial diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); /// Build a partial diagnostic. PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h bool findMacroSpelling(SourceLocation &loc, StringRef name); /// Get a string to suggest for zero-initialization of a type. std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const; std::string getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const; /// Calls \c Lexer::getLocForEndOfToken() SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0); /// Retrieve the module loader associated with the preprocessor. ModuleLoader &getModuleLoader() const; /// Invent a new identifier for parameters of abbreviated templates. IdentifierInfo * InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, unsigned Index); void emitAndClearUnusedLocalTypedefWarnings(); private: /// Function or variable declarations to be checked for whether the deferred /// diagnostics should be emitted. SmallVector DeclsToCheckForDeferredDiags; public: // Emit all deferred diagnostics. void emitDeferredDiags(); enum TUFragmentKind { /// The global module fragment, between 'module;' and a module-declaration. Global, /// A normal translation unit fragment. For a non-module unit, this is the /// entire translation unit. Otherwise, it runs from the module-declaration /// to the private-module-fragment (if any) or the end of the TU (if not). Normal, /// The private module fragment, between 'module :private;' and the end of /// the translation unit. Private }; void ActOnStartOfTranslationUnit(); void ActOnEndOfTranslationUnit(); void ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind); void CheckDelegatingCtorCycles(); Scope *getScopeForContext(DeclContext *Ctx); void PushFunctionScope(); void PushBlockScope(Scope *BlockScope, BlockDecl *Block); sema::LambdaScopeInfo *PushLambdaScope(); /// This is used to inform Sema what the current TemplateParameterDepth /// is during Parsing. Currently it is used to pass on the depth /// when parsing generic lambda 'auto' parameters. void RecordParsingTemplateParameterDepth(unsigned Depth); void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD, RecordDecl *RD, CapturedRegionKind K, unsigned OpenMPCaptureLevel = 0); /// Custom deleter to allow FunctionScopeInfos to be kept alive for a short /// time after they've been popped. class PoppedFunctionScopeDeleter { Sema *Self; public: explicit PoppedFunctionScopeDeleter(Sema *Self) : Self(Self) {} void operator()(sema::FunctionScopeInfo *Scope) const; }; using PoppedFunctionScopePtr = std::unique_ptr; PoppedFunctionScopePtr PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP = nullptr, const Decl *D = nullptr, QualType BlockType = QualType()); sema::FunctionScopeInfo *getCurFunction() const { return FunctionScopes.empty() ? nullptr : FunctionScopes.back(); } sema::FunctionScopeInfo *getEnclosingFunction() const; void setFunctionHasBranchIntoScope(); void setFunctionHasBranchProtectedScope(); void setFunctionHasIndirectGoto(); void PushCompoundScope(bool IsStmtExpr); void PopCompoundScope(); sema::CompoundScopeInfo &getCurCompoundScope() const; bool hasAnyUnrecoverableErrorsInThisFunction() const; /// Retrieve the current block, if any. sema::BlockScopeInfo *getCurBlock(); /// Get the innermost lambda enclosing the current location, if any. This /// looks through intervening non-lambda scopes such as local functions and /// blocks. sema::LambdaScopeInfo *getEnclosingLambda() const; /// Retrieve the current lambda scope info, if any. /// \param IgnoreNonLambdaCapturingScope true if should find the top-most /// lambda scope info ignoring all inner capturing scopes that are not /// lambda scopes. sema::LambdaScopeInfo * getCurLambda(bool IgnoreNonLambdaCapturingScope = false); /// Retrieve the current generic lambda info, if any. sema::LambdaScopeInfo *getCurGenericLambda(); /// Retrieve the current captured region, if any. sema::CapturedRegionScopeInfo *getCurCapturedRegion(); /// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls SmallVectorImpl &WeakTopLevelDecls() { return WeakTopLevelDecl; } /// Called before parsing a function declarator belonging to a function /// declaration. void ActOnStartFunctionDeclarationDeclarator(Declarator &D, unsigned TemplateParameterDepth); /// Called after parsing a function declarator belonging to a function /// declaration. void ActOnFinishFunctionDeclarationDeclarator(Declarator &D); void ActOnComment(SourceRange Comment); //===--------------------------------------------------------------------===// // Type Analysis / Processing: SemaType.cpp. // QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs, const DeclSpec *DS = nullptr); QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVRA, const DeclSpec *DS = nullptr); QualType BuildPointerType(QualType T, SourceLocation Loc, DeclarationName Entity); QualType BuildReferenceType(QualType T, bool LValueRef, SourceLocation Loc, DeclarationName Entity); QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, SourceRange Brackets, DeclarationName Entity); QualType BuildVectorType(QualType T, Expr *VecSize, SourceLocation AttrLoc); QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); QualType BuildMatrixType(QualType T, Expr *NumRows, Expr *NumColumns, SourceLocation AttrLoc); QualType BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace, SourceLocation AttrLoc); /// Same as above, but constructs the AddressSpace index if not provided. QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, SourceLocation AttrLoc); bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc); bool CheckFunctionReturnType(QualType T, SourceLocation Loc); /// Build a function type. /// /// This routine checks the function type according to C++ rules and /// under the assumption that the result type and parameter types have /// just been instantiated from a template. It therefore duplicates /// some of the behavior of GetTypeForDeclarator, but in a much /// simpler form that is only suitable for this narrow use case. /// /// \param T The return type of the function. /// /// \param ParamTypes The parameter types of the function. This array /// will be modified to account for adjustments to the types of the /// function parameters. /// /// \param Loc The location of the entity whose type involves this /// function type or, if there is no such entity, the location of the /// type that will have function type. /// /// \param Entity The name of the entity that involves the function /// type, if known. /// /// \param EPI Extra information about the function type. Usually this will /// be taken from an existing function with the same prototype. /// /// \returns A suitable function type, if there are no errors. The /// unqualified type will always be a FunctionProtoType. /// Otherwise, returns a NULL type. QualType BuildFunctionType(QualType T, MutableArrayRef ParamTypes, SourceLocation Loc, DeclarationName Entity, const FunctionProtoType::ExtProtoInfo &EPI); QualType BuildMemberPointerType(QualType T, QualType Class, SourceLocation Loc, DeclarationName Entity); QualType BuildBlockPointerType(QualType T, SourceLocation Loc, DeclarationName Entity); QualType BuildParenType(QualType T); QualType BuildAtomicType(QualType T, SourceLocation Loc); QualType BuildReadPipeType(QualType T, SourceLocation Loc); QualType BuildWritePipeType(QualType T, SourceLocation Loc); QualType BuildExtIntType(bool IsUnsigned, Expr *BitWidth, SourceLocation Loc); TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); /// Package the given type and TSI into a ParsedType. ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo); DeclarationNameInfo GetNameForDeclarator(Declarator &D); DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name); static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo = nullptr); CanThrowResult canThrow(const Stmt *E); /// Determine whether the callee of a particular function call can throw. /// E, D and Loc are all optional. static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D, SourceLocation Loc = SourceLocation()); const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT); void UpdateExceptionSpec(FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI); bool CheckSpecifiedExceptionType(QualType &T, SourceRange Range); bool CheckDistantExceptionSpec(QualType T); bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); bool CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); bool CheckEquivalentExceptionSpec( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); bool handlerCanCatch(QualType HandlerType, QualType ExceptionType); bool CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID, const PartialDiagnostic &NoThrowDiagID, const FunctionProtoType *Superset, SourceLocation SuperLoc, const FunctionProtoType *Subset, SourceLocation SubLoc); bool CheckParamExceptionSpec(const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID, const FunctionProtoType *Target, SourceLocation TargetLoc, const FunctionProtoType *Source, SourceLocation SourceLoc); TypeResult ActOnTypeName(Scope *S, Declarator &D); /// The parser has parsed the context-sensitive type 'instancetype' /// in an Objective-C message declaration. Return the appropriate type. ParsedType ActOnObjCInstanceType(SourceLocation Loc); /// Abstract class used to diagnose incomplete types. struct TypeDiagnoser { TypeDiagnoser() {} virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) = 0; virtual ~TypeDiagnoser() {} }; static int getPrintable(int I) { return I; } static unsigned getPrintable(unsigned I) { return I; } static bool getPrintable(bool B) { return B; } static const char * getPrintable(const char *S) { return S; } static StringRef getPrintable(StringRef S) { return S; } static const std::string &getPrintable(const std::string &S) { return S; } static const IdentifierInfo *getPrintable(const IdentifierInfo *II) { return II; } static DeclarationName getPrintable(DeclarationName N) { return N; } static QualType getPrintable(QualType T) { return T; } static SourceRange getPrintable(SourceRange R) { return R; } static SourceRange getPrintable(SourceLocation L) { return L; } static SourceRange getPrintable(const Expr *E) { return E->getSourceRange(); } static SourceRange getPrintable(TypeLoc TL) { return TL.getSourceRange();} template class BoundTypeDiagnoser : public TypeDiagnoser { protected: unsigned DiagID; std::tuple Args; template void emit(const SemaDiagnosticBuilder &DB, std::index_sequence) const { // Apply all tuple elements to the builder in order. bool Dummy[] = {false, (DB << getPrintable(std::get(Args)))...}; (void)Dummy; } public: BoundTypeDiagnoser(unsigned DiagID, const Ts &...Args) : TypeDiagnoser(), DiagID(DiagID), Args(Args...) { assert(DiagID != 0 && "no diagnostic for type diagnoser"); } void diagnose(Sema &S, SourceLocation Loc, QualType T) override { const SemaDiagnosticBuilder &DB = S.Diag(Loc, DiagID); emit(DB, std::index_sequence_for()); DB << T; } }; /// A derivative of BoundTypeDiagnoser for which the diagnostic's type /// parameter is preceded by a 0/1 enum that is 1 if the type is sizeless. /// For example, a diagnostic with no other parameters would generally have /// the form "...%select{incomplete|sizeless}0 type %1...". template class SizelessTypeDiagnoser : public BoundTypeDiagnoser { public: SizelessTypeDiagnoser(unsigned DiagID, const Ts &... Args) : BoundTypeDiagnoser(DiagID, Args...) {} void diagnose(Sema &S, SourceLocation Loc, QualType T) override { const SemaDiagnosticBuilder &DB = S.Diag(Loc, this->DiagID); this->emit(DB, std::index_sequence_for()); DB << T->isSizelessType() << T; } }; enum class CompleteTypeKind { /// Apply the normal rules for complete types. In particular, /// treat all sizeless types as incomplete. Normal, /// Relax the normal rules for complete types so that they include /// sizeless built-in types. AcceptSizeless, // FIXME: Eventually we should flip the default to Normal and opt in // to AcceptSizeless rather than opt out of it. Default = AcceptSizeless }; private: /// Methods for marking which expressions involve dereferencing a pointer /// marked with the 'noderef' attribute. Expressions are checked bottom up as /// they are parsed, meaning that a noderef pointer may not be accessed. For /// example, in `&*p` where `p` is a noderef pointer, we will first parse the /// `*p`, but need to check that `address of` is called on it. This requires /// keeping a container of all pending expressions and checking if the address /// of them are eventually taken. void CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E); void CheckAddressOfNoDeref(const Expr *E); void CheckMemberAccessOfNoDeref(const MemberExpr *E); bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T, CompleteTypeKind Kind, TypeDiagnoser *Diagnoser); struct ModuleScope { SourceLocation BeginLoc; clang::Module *Module = nullptr; bool ModuleInterface = false; bool ImplicitGlobalModuleFragment = false; VisibleModuleSet OuterVisibleModules; }; /// The modules we're currently parsing. llvm::SmallVector ModuleScopes; /// Namespace definitions that we will export when they finish. llvm::SmallPtrSet DeferredExportedNamespaces; /// Get the module whose scope we are currently within. Module *getCurrentModule() const { return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; } VisibleModuleSet VisibleModules; public: /// Get the module owning an entity. Module *getOwningModule(const Decl *Entity) { return Entity->getOwningModule(); } /// Make a merged definition of an existing hidden definition \p ND /// visible at the specified location. void makeMergedDefinitionVisible(NamedDecl *ND); bool isModuleVisible(const Module *M, bool ModulePrivate = false); /// Determine whether a declaration is visible to name lookup. bool isVisible(const NamedDecl *D) { return D->isUnconditionallyVisible() || isVisibleSlow(D); } /// Determine whether any declaration of an entity is visible. bool hasVisibleDeclaration(const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr) { return isVisible(D) || hasVisibleDeclarationSlow(D, Modules); } bool hasVisibleDeclarationSlow(const NamedDecl *D, llvm::SmallVectorImpl *Modules); bool hasVisibleMergedDefinition(NamedDecl *Def); bool hasMergedDefinitionInCurrentModule(NamedDecl *Def); /// Determine if \p D and \p Suggested have a structurally compatible /// layout as described in C11 6.2.7/1. bool hasStructuralCompatLayout(Decl *D, Decl *Suggested); /// Determine if \p D has a visible definition. If not, suggest a declaration /// that should be made visible to expose the definition. bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, bool OnlyNeedComplete = false); bool hasVisibleDefinition(const NamedDecl *D) { NamedDecl *Hidden; return hasVisibleDefinition(const_cast(D), &Hidden); } /// Determine if the template parameter \p D has a visible default argument. bool hasVisibleDefaultArgument(const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); /// Determine if there is a visible declaration of \p D that is an explicit /// specialization declaration for a specialization of a template. (For a /// member specialization, use hasVisibleMemberSpecialization.) bool hasVisibleExplicitSpecialization( const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); /// Determine if there is a visible declaration of \p D that is a member /// specialization declaration (as opposed to an instantiated declaration). bool hasVisibleMemberSpecialization( const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); /// Determine if \p A and \p B are equivalent internal linkage declarations /// from different modules, and thus an ambiguity error can be downgraded to /// an extension warning. bool isEquivalentInternalLinkageDeclaration(const NamedDecl *A, const NamedDecl *B); void diagnoseEquivalentInternalLinkageDeclarations( SourceLocation Loc, const NamedDecl *D, ArrayRef Equiv); bool isUsualDeallocationFunction(const CXXMethodDecl *FD); bool isCompleteType(SourceLocation Loc, QualType T, CompleteTypeKind Kind = CompleteTypeKind::Default) { return !RequireCompleteTypeImpl(Loc, T, Kind, nullptr); } bool RequireCompleteType(SourceLocation Loc, QualType T, CompleteTypeKind Kind, TypeDiagnoser &Diagnoser); bool RequireCompleteType(SourceLocation Loc, QualType T, CompleteTypeKind Kind, unsigned DiagID); bool RequireCompleteType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser) { return RequireCompleteType(Loc, T, CompleteTypeKind::Default, Diagnoser); } bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID) { return RequireCompleteType(Loc, T, CompleteTypeKind::Default, DiagID); } template bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteType(Loc, T, Diagnoser); } template bool RequireCompleteSizedType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &... Args) { SizelessTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteType(Loc, T, CompleteTypeKind::Normal, Diagnoser); } void completeExprArrayBound(Expr *E); bool RequireCompleteExprType(Expr *E, CompleteTypeKind Kind, TypeDiagnoser &Diagnoser); bool RequireCompleteExprType(Expr *E, unsigned DiagID); template bool RequireCompleteExprType(Expr *E, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteExprType(E, CompleteTypeKind::Default, Diagnoser); } template bool RequireCompleteSizedExprType(Expr *E, unsigned DiagID, const Ts &... Args) { SizelessTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteExprType(E, CompleteTypeKind::Normal, Diagnoser); } bool RequireLiteralType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID); template bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireLiteralType(Loc, T, Diagnoser); } QualType getElaboratedType(ElaboratedTypeKeyword Keyword, const CXXScopeSpec &SS, QualType T, TagDecl *OwnedTagDecl = nullptr); QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); /// If AsUnevaluated is false, E is treated as though it were an evaluated /// context, such as when building a type for decltype(auto). QualType BuildDecltypeType(Expr *E, SourceLocation Loc, bool AsUnevaluated = true); QualType BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // struct SkipBodyInfo { SkipBodyInfo() : ShouldSkip(false), CheckSameAsPrevious(false), Previous(nullptr), New(nullptr) {} bool ShouldSkip; bool CheckSameAsPrevious; NamedDecl *Previous; NamedDecl *New; }; DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr); void DiagnoseUseOfUnimplementedSelectors(); bool isSimpleTypeSpecifier(tok::TokenKind Kind) const; ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS = nullptr, bool isClassName = false, bool HasTrailingDot = false, ParsedType ObjectType = nullptr, bool IsCtorOrDtorName = false, bool WantNontrivialTypeSourceInfo = false, bool IsClassTemplateDeductionContext = true, IdentifierInfo **CorrectedII = nullptr); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); void DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, bool IsTemplateName = false); /// Attempt to behave like MSVC in situations where lookup of an unqualified /// type name has failed in a dependent context. In these situations, we /// automatically form a DependentTypeName that will retry lookup in a related /// scope during instantiation. ParsedType ActOnMSVCUnknownTypeName(const IdentifierInfo &II, SourceLocation NameLoc, bool IsTemplateTypeArg); /// Describes the result of the name lookup and resolution performed /// by \c ClassifyName(). enum NameClassificationKind { /// This name is not a type or template in this context, but might be /// something else. NC_Unknown, /// Classification failed; an error has been produced. NC_Error, /// The name has been typo-corrected to a keyword. NC_Keyword, /// The name was classified as a type. NC_Type, /// The name was classified as a specific non-type, non-template /// declaration. ActOnNameClassifiedAsNonType should be called to /// convert the declaration to an expression. NC_NonType, /// The name was classified as an ADL-only function name. /// ActOnNameClassifiedAsUndeclaredNonType should be called to convert the /// result to an expression. NC_UndeclaredNonType, /// The name denotes a member of a dependent type that could not be /// resolved. ActOnNameClassifiedAsDependentNonType should be called to /// convert the result to an expression. NC_DependentNonType, /// The name was classified as a non-type, and an expression representing /// that name has been formed. NC_ContextIndependentExpr, /// The name was classified as a template whose specializations are types. NC_TypeTemplate, /// The name was classified as a variable template name. NC_VarTemplate, /// The name was classified as a function template name. NC_FunctionTemplate, /// The name was classified as an ADL-only function template name. NC_UndeclaredTemplate, /// The name was classified as a concept name. NC_Concept, }; class NameClassification { NameClassificationKind Kind; union { ExprResult Expr; NamedDecl *NonTypeDecl; TemplateName Template; ParsedType Type; }; explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {} public: NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {} NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword) {} static NameClassification Error() { return NameClassification(NC_Error); } static NameClassification Unknown() { return NameClassification(NC_Unknown); } static NameClassification ContextIndependentExpr(ExprResult E) { NameClassification Result(NC_ContextIndependentExpr); Result.Expr = E; return Result; } static NameClassification NonType(NamedDecl *D) { NameClassification Result(NC_NonType); Result.NonTypeDecl = D; return Result; } static NameClassification UndeclaredNonType() { return NameClassification(NC_UndeclaredNonType); } static NameClassification DependentNonType() { return NameClassification(NC_DependentNonType); } static NameClassification TypeTemplate(TemplateName Name) { NameClassification Result(NC_TypeTemplate); Result.Template = Name; return Result; } static NameClassification VarTemplate(TemplateName Name) { NameClassification Result(NC_VarTemplate); Result.Template = Name; return Result; } static NameClassification FunctionTemplate(TemplateName Name) { NameClassification Result(NC_FunctionTemplate); Result.Template = Name; return Result; } static NameClassification Concept(TemplateName Name) { NameClassification Result(NC_Concept); Result.Template = Name; return Result; } static NameClassification UndeclaredTemplate(TemplateName Name) { NameClassification Result(NC_UndeclaredTemplate); Result.Template = Name; return Result; } NameClassificationKind getKind() const { return Kind; } ExprResult getExpression() const { assert(Kind == NC_ContextIndependentExpr); return Expr; } ParsedType getType() const { assert(Kind == NC_Type); return Type; } NamedDecl *getNonTypeDecl() const { assert(Kind == NC_NonType); return NonTypeDecl; } TemplateName getTemplateName() const { assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate || Kind == NC_VarTemplate || Kind == NC_Concept || Kind == NC_UndeclaredTemplate); return Template; } TemplateNameKind getTemplateNameKind() const { switch (Kind) { case NC_TypeTemplate: return TNK_Type_template; case NC_FunctionTemplate: return TNK_Function_template; case NC_VarTemplate: return TNK_Var_template; case NC_Concept: return TNK_Concept_template; case NC_UndeclaredTemplate: return TNK_Undeclared_template; default: llvm_unreachable("unsupported name classification."); } } }; /// Perform name lookup on the given name, classifying it based on /// the results of name lookup and the following token. /// /// This routine is used by the parser to resolve identifiers and help direct /// parsing. When the identifier cannot be found, this routine will attempt /// to correct the typo and classify based on the resulting name. /// /// \param S The scope in which we're performing name lookup. /// /// \param SS The nested-name-specifier that precedes the name. /// /// \param Name The identifier. If typo correction finds an alternative name, /// this pointer parameter will be updated accordingly. /// /// \param NameLoc The location of the identifier. /// /// \param NextToken The token following the identifier. Used to help /// disambiguate the name. /// /// \param CCC The correction callback, if typo correction is desired. NameClassification ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, const Token &NextToken, CorrectionCandidateCallback *CCC = nullptr); /// Act on the result of classifying a name as an undeclared (ADL-only) /// non-type declaration. ExprResult ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name, SourceLocation NameLoc); /// Act on the result of classifying a name as an undeclared member of a /// dependent base class. ExprResult ActOnNameClassifiedAsDependentNonType(const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, bool IsAddressOfOperand); /// Act on the result of classifying a name as a specific non-type /// declaration. ExprResult ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS, NamedDecl *Found, SourceLocation NameLoc, const Token &NextToken); /// Describes the detailed kind of a template name. Used in diagnostics. enum class TemplateNameKindForDiagnostics { ClassTemplate, FunctionTemplate, VarTemplate, AliasTemplate, TemplateTemplateParam, Concept, DependentTemplate }; TemplateNameKindForDiagnostics getTemplateNameKindForDiagnostics(TemplateName Name); /// Determine whether it's plausible that E was intended to be a /// template-name. bool mightBeIntendedToBeTemplateName(ExprResult E, bool &Dependent) { if (!getLangOpts().CPlusPlus || E.isInvalid()) return false; Dependent = false; if (auto *DRE = dyn_cast(E.get())) return !DRE->hasExplicitTemplateArgs(); if (auto *ME = dyn_cast(E.get())) return !ME->hasExplicitTemplateArgs(); Dependent = true; if (auto *DSDRE = dyn_cast(E.get())) return !DSDRE->hasExplicitTemplateArgs(); if (auto *DSME = dyn_cast(E.get())) return !DSME->hasExplicitTemplateArgs(); // Any additional cases recognized here should also be handled by // diagnoseExprIntendedAsTemplateName. return false; } void diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, SourceLocation Less, SourceLocation Greater); Decl *ActOnDeclarator(Scope *S, Declarator &D); NamedDecl *HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists); void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S); bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, SourceLocation Loc, bool IsTemplateId); void diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, SourceLocation FallbackLoc, SourceLocation ConstQualLoc = SourceLocation(), SourceLocation VolatileQualLoc = SourceLocation(), SourceLocation RestrictQualLoc = SourceLocation(), SourceLocation AtomicQualLoc = SourceLocation(), SourceLocation UnalignedQualLoc = SourceLocation()); static bool adjustContextForLocalExternDecl(DeclContext *&DC); void DiagnoseFunctionSpecifiers(const DeclSpec &DS); NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D, const LookupResult &R); NamedDecl *getShadowedDeclaration(const VarDecl *D, const LookupResult &R); void CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, const LookupResult &R); void CheckShadow(Scope *S, VarDecl *D); /// Warn if 'E', which is an expression that is about to be modified, refers /// to a shadowing declaration. void CheckShadowingDeclModification(Expr *E, SourceLocation Loc); void DiagnoseShadowingLambdaDecls(const sema::LambdaScopeInfo *LSI); private: /// Map of current shadowing declarations to shadowed declarations. Warn if /// it looks like the user is trying to modify the shadowing declaration. llvm::DenseMap ShadowingDecls; public: void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); void handleTagNumbering(const TagDecl *Tag, Scope *TagScope); void setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, TypedefNameDecl *NewTD); void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypeSourceInfo *TInfo, LookupResult &Previous); NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D, LookupResult &Previous, bool &Redeclaration); NamedDecl *ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope, ArrayRef Bindings = None); NamedDecl * ActOnDecompositionDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists); // Returns true if the variable declaration is a redeclaration bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); void CheckVariableDeclarationType(VarDecl *NewVD); bool DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, Expr *Init); void CheckCompleteVariableDeclaration(VarDecl *VD); void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD); void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope); bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); enum class CheckConstexprKind { /// Diagnose issues that are non-constant or that are extensions. Diagnose, /// Identify whether this function satisfies the formal rules for constexpr /// functions in the current lanugage mode (with no extensions). CheckValid }; bool CheckConstexprFunctionDefinition(const FunctionDecl *FD, CheckConstexprKind Kind); void DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD); void FindHiddenVirtualMethods(CXXMethodDecl *MD, SmallVectorImpl &OverloadedMethods); void NoteHiddenVirtualMethods(CXXMethodDecl *MD, SmallVectorImpl &OverloadedMethods); // Returns true if the function declaration is a redeclaration bool CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsMemberSpecialization); bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl); bool canFullyTypeCheckRedeclaration(ValueDecl *NewD, ValueDecl *OldD, QualType NewT, QualType OldT); void CheckMain(FunctionDecl *FD, const DeclSpec &D); void CheckMSVCRTEntryPoint(FunctionDecl *FD); Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition); void CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D); Decl *ActOnParamDeclarator(Scope *S, Declarator &D); ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, QualType T); ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc, SourceLocation NameLoc, IdentifierInfo *Name, QualType T, TypeSourceInfo *TSInfo, StorageClass SC); void ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, Expr *defarg); void ActOnParamUnparsedDefaultArgument(Decl *param, SourceLocation EqualLoc, SourceLocation ArgLoc); void ActOnParamDefaultArgumentError(Decl *param, SourceLocation EqualLoc); ExprResult ConvertParamDefaultArgument(const ParmVarDecl *Param, Expr *DefaultArg, SourceLocation EqualLoc); void SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, SourceLocation EqualLoc); // Contexts where using non-trivial C union types can be disallowed. This is // passed to err_non_trivial_c_union_in_invalid_context. enum NonTrivialCUnionContext { // Function parameter. NTCUC_FunctionParam, // Function return. NTCUC_FunctionReturn, // Default-initialized object. NTCUC_DefaultInitializedObject, // Variable with automatic storage duration. NTCUC_AutoVar, // Initializer expression that might copy from another object. NTCUC_CopyInit, // Assignment. NTCUC_Assignment, // Compound literal. NTCUC_CompoundLiteral, // Block capture. NTCUC_BlockCapture, // lvalue-to-rvalue conversion of volatile type. NTCUC_LValueToRValueVolatile, }; /// Emit diagnostics if the initializer or any of its explicit or /// implicitly-generated subexpressions require copying or /// default-initializing a type that is or contains a C union type that is /// non-trivial to copy or default-initialize. void checkNonTrivialCUnionInInitializer(const Expr *Init, SourceLocation Loc); // These flags are passed to checkNonTrivialCUnion. enum NonTrivialCUnionKind { NTCUK_Init = 0x1, NTCUK_Destruct = 0x2, NTCUK_Copy = 0x4, }; /// Emit diagnostics if a non-trivial C union type or a struct that contains /// a non-trivial C union is used in an invalid context. void checkNonTrivialCUnion(QualType QT, SourceLocation Loc, NonTrivialCUnionContext UseContext, unsigned NonTrivialKind); void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit); void ActOnUninitializedDecl(Decl *dcl); void ActOnInitializerError(Decl *Dcl); void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc); void ActOnCXXForRangeDecl(Decl *D); StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, IdentifierInfo *Ident, ParsedAttributes &Attrs, SourceLocation AttrEnd); void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); void CheckStaticLocalForDllExport(VarDecl *VD); void FinalizeDeclaration(Decl *D); DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, ArrayRef Group); DeclGroupPtrTy BuildDeclaratorGroup(MutableArrayRef Group); /// Should be called on all declarations that might have attached /// documentation comments. void ActOnDocumentableDecl(Decl *D); void ActOnDocumentableDecls(ArrayRef Group); void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls); void CheckForFunctionRedefinition( FunctionDecl *FD, const FunctionDecl *EffectiveDefinition = nullptr, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D, SkipBodyInfo *SkipBody = nullptr); void ActOnStartTrailingRequiresClause(Scope *S, Declarator &D); ExprResult ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr); void ActOnStartOfObjCMethodDef(Scope *S, Decl *D); bool isObjCMethodDecl(Decl *D) { return D && isa(D); } /// Determine whether we can delay parsing the body of a function or /// function template until it is used, assuming we don't care about emitting /// code for that function. /// /// This will be \c false if we may need the body of the function in the /// middle of parsing an expression (where it's impractical to switch to /// parsing a different function), for instance, if it's constexpr in C++11 /// or has an 'auto' return type in C++14. These cases are essentially bugs. bool canDelayFunctionBody(const Declarator &D); /// Determine whether we can skip parsing the body of a function /// definition, assuming we don't care about analyzing its body or emitting /// code for that function. /// /// This will be \c false only if we may need the body of the function in /// order to parse the rest of the program (for instance, if it is /// \c constexpr in C++11 or has an 'auto' return type in C++14). bool canSkipFunctionBody(Decl *D); void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); Decl *ActOnSkippedFunctionBody(Decl *Decl); void ActOnFinishInlineFunctionDef(FunctionDecl *D); /// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an /// attribute for which parsing is delayed. void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs); /// Diagnose any unused parameters in the given sequence of /// ParmVarDecl pointers. void DiagnoseUnusedParameters(ArrayRef Parameters); /// Diagnose whether the size of parameters or return value of a /// function or obj-c method definition is pass-by-value and larger than a /// specified threshold. void DiagnoseSizeOfParametersAndReturnValue(ArrayRef Parameters, QualType ReturnTy, NamedDecl *D); void DiagnoseInvalidJumps(Stmt *Body); Decl *ActOnFileScopeAsmDecl(Expr *expr, SourceLocation AsmLoc, SourceLocation RParenLoc); /// Handle a C++11 empty-declaration and attribute-declaration. Decl *ActOnEmptyDeclaration(Scope *S, const ParsedAttributesView &AttrList, SourceLocation SemiLoc); enum class ModuleDeclKind { Interface, ///< 'export module X;' Implementation, ///< 'module X;' }; /// The parser has processed a module-declaration that begins the definition /// of a module interface or implementation. DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path, bool IsFirstDecl); /// The parser has processed a global-module-fragment declaration that begins /// the definition of the global module fragment of the current module unit. /// \param ModuleLoc The location of the 'module' keyword. DeclGroupPtrTy ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc); /// The parser has processed a private-module-fragment declaration that begins /// the definition of the private module fragment of the current module unit. /// \param ModuleLoc The location of the 'module' keyword. /// \param PrivateLoc The location of the 'private' keyword. DeclGroupPtrTy ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, SourceLocation PrivateLoc); /// The parser has processed a module import declaration. /// /// \param StartLoc The location of the first token in the declaration. This /// could be the location of an '@', 'export', or 'import'. /// \param ExportLoc The location of the 'export' keyword, if any. /// \param ImportLoc The location of the 'import' keyword. /// \param Path The module access path. DeclResult ActOnModuleImport(SourceLocation StartLoc, SourceLocation ExportLoc, SourceLocation ImportLoc, ModuleIdPath Path); DeclResult ActOnModuleImport(SourceLocation StartLoc, SourceLocation ExportLoc, SourceLocation ImportLoc, Module *M, ModuleIdPath Path = {}); /// The parser has processed a module import translated from a /// #include or similar preprocessing directive. void ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod); void BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod); /// The parsed has entered a submodule. void ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod); /// The parser has left a submodule. void ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod); /// Create an implicit import of the given module at the given /// source location, for error recovery, if possible. /// /// This routine is typically used when an entity found by name lookup /// is actually hidden within a module that we know about but the user /// has forgotten to import. void createImplicitModuleImportForErrorRecovery(SourceLocation Loc, Module *Mod); /// Kinds of missing import. Note, the values of these enumerators correspond /// to %select values in diagnostics. enum class MissingImportKind { Declaration, Definition, DefaultArgument, ExplicitSpecialization, PartialSpecialization }; /// Diagnose that the specified declaration needs to be visible but /// isn't, and suggest a module import that would resolve the problem. void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, MissingImportKind MIK, bool Recover = true); void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, SourceLocation DeclLoc, ArrayRef Modules, MissingImportKind MIK, bool Recover); Decl *ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, SourceLocation LBraceLoc); Decl *ActOnFinishExportDecl(Scope *S, Decl *ExportDecl, SourceLocation RBraceLoc); /// We've found a use of a templated declaration that would trigger an /// implicit instantiation. Check that any relevant explicit specializations /// and partial specializations are visible, and diagnose if not. void checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); /// We've found a use of a template specialization that would select a /// partial specialization. Check that the partial specialization is visible, /// and diagnose if not. void checkPartialSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); /// Retrieve a suitable printing policy for diagnostics. PrintingPolicy getPrintingPolicy() const { return getPrintingPolicy(Context, PP); } /// Retrieve a suitable printing policy for diagnostics. static PrintingPolicy getPrintingPolicy(const ASTContext &Ctx, const Preprocessor &PP); /// Scope actions. void ActOnPopScope(SourceLocation Loc, Scope *S); void ActOnTranslationUnitScope(Scope *S); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, RecordDecl *&AnonRecord); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, MultiTemplateParamsArg TemplateParams, bool IsExplicitInstantiation, RecordDecl *&AnonRecord); Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, AccessSpecifier AS, RecordDecl *Record, const PrintingPolicy &Policy); Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record); /// Common ways to introduce type names without a tag for use in diagnostics. /// Keep in sync with err_tag_reference_non_tag. enum NonTagKind { NTK_NonStruct, NTK_NonClass, NTK_NonUnion, NTK_NonEnum, NTK_Typedef, NTK_TypeAlias, NTK_Template, NTK_TypeAliasTemplate, NTK_TemplateTemplateArgument, }; /// Given a non-tag type declaration, returns an enum useful for indicating /// what kind of non-tag type this is. NonTagKind getNonTagTypeDeclKind(const Decl *D, TagTypeKind TTK); bool isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, const IdentifierInfo *Name); enum TagUseKind { TUK_Reference, // Reference to a tag: 'struct foo *X;' TUK_Declaration, // Fwd decl of a tag: 'struct foo;' TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;' TUK_Friend // Friend declaration: 'friend struct foo;' }; Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, AccessSpecifier AS, SourceLocation ModulePrivateLoc, MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier, bool IsTemplateParamOrArg, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, MultiTemplateParamsArg TempParamLists); TypeResult ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation TagLoc, SourceLocation NameLoc); void ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, SmallVectorImpl &Decls); Decl *ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth); FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, InClassInitStyle InitStyle, AccessSpecifier AS); MSPropertyDecl *HandleMSProperty(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, InClassInitStyle InitStyle, AccessSpecifier AS, const ParsedAttr &MSPropertyAttr); FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitfieldWidth, InClassInitStyle InitStyle, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D = nullptr); bool CheckNontrivialField(FieldDecl *FD); void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM); enum TrivialABIHandling { /// The triviality of a method unaffected by "trivial_abi". TAH_IgnoreTrivialABI, /// The triviality of a method affected by "trivial_abi". TAH_ConsiderTrivialABI }; bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, TrivialABIHandling TAH = TAH_IgnoreTrivialABI, bool Diagnose = false); /// For a defaulted function, the kind of defaulted function that it is. class DefaultedFunctionKind { CXXSpecialMember SpecialMember : 8; DefaultedComparisonKind Comparison : 8; public: DefaultedFunctionKind() : SpecialMember(CXXInvalid), Comparison(DefaultedComparisonKind::None) { } DefaultedFunctionKind(CXXSpecialMember CSM) : SpecialMember(CSM), Comparison(DefaultedComparisonKind::None) {} DefaultedFunctionKind(DefaultedComparisonKind Comp) : SpecialMember(CXXInvalid), Comparison(Comp) {} bool isSpecialMember() const { return SpecialMember != CXXInvalid; } bool isComparison() const { return Comparison != DefaultedComparisonKind::None; } explicit operator bool() const { return isSpecialMember() || isComparison(); } CXXSpecialMember asSpecialMember() const { return SpecialMember; } DefaultedComparisonKind asComparison() const { return Comparison; } /// Get the index of this function kind for use in diagnostics. unsigned getDiagnosticIndex() const { static_assert(CXXInvalid > CXXDestructor, "invalid should have highest index"); static_assert((unsigned)DefaultedComparisonKind::None == 0, "none should be equal to zero"); return SpecialMember + (unsigned)Comparison; } }; DefaultedFunctionKind getDefaultedFunctionKind(const FunctionDecl *FD); CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD) { return getDefaultedFunctionKind(MD).asSpecialMember(); } DefaultedComparisonKind getDefaultedComparisonKind(const FunctionDecl *FD) { return getDefaultedFunctionKind(FD).asComparison(); } void ActOnLastBitfield(SourceLocation DeclStart, SmallVectorImpl &AllIvarDecls); Decl *ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, tok::ObjCKeywordKind visibility); // This is used for both record definitions and ObjC interface declarations. void ActOnFields(Scope *S, SourceLocation RecLoc, Decl *TagDecl, ArrayRef Fields, SourceLocation LBrac, SourceLocation RBrac, const ParsedAttributesView &AttrList); /// ActOnTagStartDefinition - Invoked when we have entered the /// scope of a tag's definition (e.g., for an enumeration, class, /// struct, or union). void ActOnTagStartDefinition(Scope *S, Decl *TagDecl); /// Perform ODR-like check for C/ObjC when merging tag types from modules. /// Differently from C++, actually parse the body and reject / error out /// in case of a structural mismatch. bool ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev, SkipBodyInfo &SkipBody); typedef void *SkippedDefinitionContext; /// Invoked when we enter a tag definition that we're skipping. SkippedDefinitionContext ActOnTagStartSkippedDefinition(Scope *S, Decl *TD); Decl *ActOnObjCContainerStartDefinition(Decl *IDecl); /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a /// C++ record definition's base-specifiers clause and are starting its /// member declarations. void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl, SourceLocation FinalLoc, bool IsFinalSpelledSealed, SourceLocation LBraceLoc); /// ActOnTagFinishDefinition - Invoked once we have finished parsing /// the definition of a tag (enumeration, class, struct, or union). void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl, SourceRange BraceRange); void ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context); void ActOnObjCContainerFinishDefinition(); /// Invoked when we must temporarily exit the objective-c container /// scope for parsing/looking-up C constructs. /// /// Must be followed by a call to \see ActOnObjCReenterContainerContext void ActOnObjCTemporaryExitContainerContext(DeclContext *DC); void ActOnObjCReenterContainerContext(DeclContext *DC); /// ActOnTagDefinitionError - Invoked when there was an unrecoverable /// error parsing the definition of a tag. void ActOnTagDefinitionError(Scope *S, Decl *TagDecl); EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, Expr *val); bool CheckEnumUnderlyingType(TypeSourceInfo *TI); bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, QualType EnumUnderlyingTy, bool IsFixed, const EnumDecl *Prev); /// Determine whether the body of an anonymous enumeration should be skipped. /// \param II The name of the first enumerator. SkipBodyInfo shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, SourceLocation IILoc); Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, const ParsedAttributesView &Attrs, SourceLocation EqualLoc, Expr *Val); void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, Decl *EnumDecl, ArrayRef Elements, Scope *S, const ParsedAttributesView &Attr); /// Set the current declaration context until it gets popped. void PushDeclContext(Scope *S, DeclContext *DC); void PopDeclContext(); /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. void EnterDeclaratorContext(Scope *S, DeclContext *DC); void ExitDeclaratorContext(Scope *S); /// Enter a template parameter scope, after it's been associated with a particular /// DeclContext. Causes lookup within the scope to chain through enclosing contexts /// in the correct order. void EnterTemplatedContext(Scope *S, DeclContext *DC); /// Push the parameters of D, which must be a function, into scope. void ActOnReenterFunctionContext(Scope* S, Decl* D); void ActOnExitFunctionContext(); DeclContext *getFunctionLevelDeclContext(); /// getCurFunctionDecl - If inside of a function body, this returns a pointer /// to the function decl for the function being parsed. If we're currently /// in a 'block', this returns the containing context. FunctionDecl *getCurFunctionDecl(); /// getCurMethodDecl - If inside of a method body, this returns a pointer to /// the method decl for the method being parsed. If we're currently /// in a 'block', this returns the containing context. ObjCMethodDecl *getCurMethodDecl(); /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method /// or C function we're in, otherwise return null. If we're currently /// in a 'block', this returns the containing context. NamedDecl *getCurFunctionOrMethodDecl(); /// Add this decl to the scope shadowed decl chains. void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. /// /// \param AllowInlineNamespace If \c true, allow the declaration to be in the /// enclosing namespace set of the context, rather than contained /// directly within it. bool isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S = nullptr, bool AllowInlineNamespace = false); /// Finds the scope corresponding to the given decl context, if it /// happens to be an enclosing scope. Otherwise return NULL. static Scope *getScopeForDeclContext(Scope *S, DeclContext *DC); /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, TypeSourceInfo *TInfo); bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New); /// Describes the kind of merge to perform for availability /// attributes (including "deprecated", "unavailable", and "availability"). enum AvailabilityMergeKind { /// Don't merge availability attributes at all. AMK_None, /// Merge availability attributes for a redeclaration, which requires /// an exact match. AMK_Redeclaration, /// Merge availability attributes for an override, which requires /// an exact match or a weakening of constraints. AMK_Override, /// Merge availability attributes for an implementation of /// a protocol requirement. AMK_ProtocolImplementation, }; /// Describes the kind of priority given to an availability attribute. /// /// The sum of priorities deteremines the final priority of the attribute. /// The final priority determines how the attribute will be merged. /// An attribute with a lower priority will always remove higher priority /// attributes for the specified platform when it is being applied. An /// attribute with a higher priority will not be applied if the declaration /// already has an availability attribute with a lower priority for the /// specified platform. The final prirority values are not expected to match /// the values in this enumeration, but instead should be treated as a plain /// integer value. This enumeration just names the priority weights that are /// used to calculate that final vaue. enum AvailabilityPriority : int { /// The availability attribute was specified explicitly next to the /// declaration. AP_Explicit = 0, /// The availability attribute was applied using '#pragma clang attribute'. AP_PragmaClangAttribute = 1, /// The availability attribute for a specific platform was inferred from /// an availability attribute for another platform. AP_InferredFromOtherPlatform = 2 }; /// Attribute merging methods. Return true if a new attribute was added. AvailabilityAttr * mergeAvailabilityAttr(NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform, bool Implicit, VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK, int Priority); TypeVisibilityAttr * mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI, TypeVisibilityAttr::VisibilityType Vis); VisibilityAttr *mergeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI, VisibilityAttr::VisibilityType Vis); UuidAttr *mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, StringRef UuidAsWritten, MSGuidDecl *GuidDecl); DLLImportAttr *mergeDLLImportAttr(Decl *D, const AttributeCommonInfo &CI); DLLExportAttr *mergeDLLExportAttr(Decl *D, const AttributeCommonInfo &CI); MSInheritanceAttr *mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI, bool BestCase, MSInheritanceModel Model); FormatAttr *mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI, IdentifierInfo *Format, int FormatIdx, int FirstArg); SectionAttr *mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI, StringRef Name); CodeSegAttr *mergeCodeSegAttr(Decl *D, const AttributeCommonInfo &CI, StringRef Name); AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, const AttributeCommonInfo &CI, const IdentifierInfo *Ident); MinSizeAttr *mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI); NoSpeculativeLoadHardeningAttr * mergeNoSpeculativeLoadHardeningAttr(Decl *D, const NoSpeculativeLoadHardeningAttr &AL); SpeculativeLoadHardeningAttr * mergeSpeculativeLoadHardeningAttr(Decl *D, const SpeculativeLoadHardeningAttr &AL); OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, const AttributeCommonInfo &CI); InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL); InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL); CommonAttr *mergeCommonAttr(Decl *D, const ParsedAttr &AL); CommonAttr *mergeCommonAttr(Decl *D, const CommonAttr &AL); WebAssemblyImportNameAttr *mergeImportNameAttr( Decl *D, const WebAssemblyImportNameAttr &AL); WebAssemblyImportModuleAttr *mergeImportModuleAttr( Decl *D, const WebAssemblyImportModuleAttr &AL); void mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK = AMK_Redeclaration); void MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, NamedDecl *&Old, Scope *S, bool MergeTypeWithOld); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, Scope *S, bool MergeTypeWithOld); void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old); void MergeVarDecl(VarDecl *New, LookupResult &Previous); void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld); void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old); bool checkVarDeclRedefinition(VarDecl *OldDefn, VarDecl *NewDefn); void notePreviousDefinition(const NamedDecl *Old, SourceLocation New); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S); // AssignmentAction - This is used by all the assignment diagnostic functions // to represent what is actually causing the operation enum AssignmentAction { AA_Assigning, AA_Passing, AA_Returning, AA_Converting, AA_Initializing, AA_Sending, AA_Casting, AA_Passing_CFAudited }; /// C++ Overloading. enum OverloadKind { /// This is a legitimate overload: the existing declarations are /// functions or function templates with different signatures. Ovl_Overload, /// This is not an overload because the signature exactly matches /// an existing declaration. Ovl_Match, /// This is not an overload because the lookup results contain a /// non-function. Ovl_NonFunction }; OverloadKind CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &OldDecls, NamedDecl *&OldDecl, bool IsForUsingDecl); bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl, bool ConsiderCudaAttrs = true, bool ConsiderRequiresClauses = true); enum class AllowedExplicit { /// Allow no explicit functions to be used. None, /// Allow explicit conversion functions but not explicit constructors. Conversions, /// Allow both explicit conversion functions and explicit constructors. All }; ImplicitConversionSequence TryImplicitConversion(Expr *From, QualType ToType, bool SuppressUserConversions, AllowedExplicit AllowExplicit, bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion); bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); bool IsFloatingPointPromotion(QualType FromType, QualType ToType); bool IsComplexPromotion(QualType FromType, QualType ToType); bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCWritebackConversion(QualType FromType, QualType ToType, QualType &ConvertedType); bool IsBlockPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType); bool FunctionParamTypesAreEqual(const FunctionProtoType *OldType, const FunctionProtoType *NewType, unsigned *ArgPos = nullptr); void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, QualType FromType, QualType ToType); void maybeExtendBlockObject(ExprResult &E); CastKind PrepareCastToObjCObjectPointer(ExprResult &E); bool CheckPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath& BasePath, bool IgnoreBaseAccess, bool Diagnose = true); bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType &ConvertedType); bool CheckMemberPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath &BasePath, bool IgnoreBaseAccess); bool IsQualificationConversion(QualType FromType, QualType ToType, bool CStyle, bool &ObjCLifetimeConversion); bool IsFunctionConversion(QualType FromType, QualType ToType, QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg); ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity, const VarDecl *NRVOCandidate, QualType ResultType, Expr *Value, bool AllowNRVO = true); bool CanPerformAggregateInitializationForOverloadResolution( const InitializedEntity &Entity, InitListExpr *From); bool CanPerformCopyInitialization(const InitializedEntity &Entity, ExprResult Init); ExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init, bool TopLevelOfInitList = false, bool AllowExplicit = false); ExprResult PerformObjectArgumentInitialization(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method); /// Check that the lifetime of the initializer (and its subobjects) is /// sufficient for initializing the entity, and perform lifetime extension /// (when permitted) if not. void checkInitializerLifetime(const InitializedEntity &Entity, Expr *Init); ExprResult PerformContextuallyConvertToBool(Expr *From); ExprResult PerformContextuallyConvertToObjCPointer(Expr *From); /// Contexts in which a converted constant expression is required. enum CCEKind { CCEK_CaseValue, ///< Expression in a case label. CCEK_Enumerator, ///< Enumerator value with fixed underlying type. CCEK_TemplateArg, ///< Value of a non-type template parameter. CCEK_NewExpr, ///< Constant expression in a noptr-new-declarator. CCEK_ConstexprIf, ///< Condition in a constexpr if statement. CCEK_ExplicitBool ///< Condition in an explicit(bool) specifier. }; ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, llvm::APSInt &Value, CCEKind CCE); ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, APValue &Value, CCEKind CCE); /// Abstract base class used to perform a contextual implicit /// conversion from an expression to any type passing a filter. class ContextualImplicitConverter { public: bool Suppress; bool SuppressConversion; ContextualImplicitConverter(bool Suppress = false, bool SuppressConversion = false) : Suppress(Suppress), SuppressConversion(SuppressConversion) {} /// Determine whether the specified type is a valid destination type /// for this conversion. virtual bool match(QualType T) = 0; /// Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. virtual SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) = 0; /// Emits a diagnostic when the expression has incomplete class type. virtual SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) = 0; /// Emits a diagnostic when the only matching conversion function /// is explicit. virtual SemaDiagnosticBuilder diagnoseExplicitConv( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; /// Emits a note for the explicit conversion function. virtual SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; /// Emits a diagnostic when there are multiple possible conversion /// functions. virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) = 0; /// Emits a note for one of the candidate conversions. virtual SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; /// Emits a diagnostic when we picked a conversion function /// (for cases when we are not allowed to pick a conversion function). virtual SemaDiagnosticBuilder diagnoseConversion( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; virtual ~ContextualImplicitConverter() {} }; class ICEConvertDiagnoser : public ContextualImplicitConverter { bool AllowScopedEnumerations; public: ICEConvertDiagnoser(bool AllowScopedEnumerations, bool Suppress, bool SuppressConversion) : ContextualImplicitConverter(Suppress, SuppressConversion), AllowScopedEnumerations(AllowScopedEnumerations) {} /// Match an integral or (possibly scoped) enumeration type. bool match(QualType T) override; SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) override { return diagnoseNotInt(S, Loc, T); } /// Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) = 0; }; /// Perform a contextual implicit conversion. ExprResult PerformContextualImplicitConversion( SourceLocation Loc, Expr *FromE, ContextualImplicitConverter &Converter); enum ObjCSubscriptKind { OS_Array, OS_Dictionary, OS_Error }; ObjCSubscriptKind CheckSubscriptingKind(Expr *FromE); // Note that LK_String is intentionally after the other literals, as // this is used for diagnostics logic. enum ObjCLiteralKind { LK_Array, LK_Dictionary, LK_Numeric, LK_Boxed, LK_String, LK_Block, LK_None }; ObjCLiteralKind CheckLiteralKind(Expr *FromE); ExprResult PerformObjectMemberConversion(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, NamedDecl *Member); // Members have to be NamespaceDecl* or TranslationUnitDecl*. // TODO: make this is a typesafe union. typedef llvm::SmallSetVector AssociatedNamespaceSet; typedef llvm::SmallSetVector AssociatedClassSet; using ADLCallKind = CallExpr::ADLCallKind; void AddOverloadCandidate(FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, bool AllowExplicit = true, bool AllowExplicitConversion = false, ADLCallKind IsADLCandidate = ADLCallKind::NotADL, ConversionSequenceList EarlyConversions = None, OverloadCandidateParamOrder PO = {}); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, ArrayRef Args, OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, bool SuppressUserConversions = false, bool PartialOverloading = false, bool FirstArgumentIsBase = false); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false, OverloadCandidateParamOrder PO = {}); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, ConversionSequenceList EarlyConversions = None, OverloadCandidateParamOrder PO = {}); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, OverloadCandidateParamOrder PO = {}); void AddTemplateOverloadCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, bool AllowExplicit = true, ADLCallKind IsADLCandidate = ADLCallKind::NotADL, OverloadCandidateParamOrder PO = {}); bool CheckNonDependentConversions( FunctionTemplateDecl *FunctionTemplate, ArrayRef ParamTypes, ArrayRef Args, OverloadCandidateSet &CandidateSet, ConversionSequenceList &Conversions, bool SuppressUserConversions, CXXRecordDecl *ActingContext = nullptr, QualType ObjectType = QualType(), Expr::Classification ObjectClassification = {}, OverloadCandidateParamOrder PO = {}); void AddConversionCandidate( CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, bool AllowExplicit, bool AllowResultConversion = true); void AddTemplateConversionCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, bool AllowExplicit, bool AllowResultConversion = true); void AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, Expr *Object, ArrayRef Args, OverloadCandidateSet& CandidateSet); void AddNonMemberOperatorCandidates( const UnresolvedSetImpl &Functions, ArrayRef Args, OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr); void AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, ArrayRef Args, OverloadCandidateSet &CandidateSet, OverloadCandidateParamOrder PO = {}); void AddBuiltinCandidate(QualType *ParamTys, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator = false, unsigned NumContextualBoolArguments = 0); void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, ArrayRef Args, OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, SourceLocation Loc, ArrayRef Args, TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); // Emit as a 'note' the specific overload candidate void NoteOverloadCandidate( NamedDecl *Found, FunctionDecl *Fn, OverloadCandidateRewriteKind RewriteKind = OverloadCandidateRewriteKind(), QualType DestType = QualType(), bool TakingAddress = false); // Emit as a series of 'note's all template and non-templates identified by // the expression Expr void NoteAllOverloadCandidates(Expr *E, QualType DestType = QualType(), bool TakingAddress = false); /// Check the enable_if expressions on the given function. Returns the first /// failing attribute, or NULL if they were all successful. EnableIfAttr *CheckEnableIf(FunctionDecl *Function, SourceLocation CallLoc, ArrayRef Args, bool MissingImplicitThis = false); /// Find the failed Boolean condition within a given Boolean /// constant expression, and describe it with a string. std::pair findFailedBooleanCondition(Expr *Cond); /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any /// non-ArgDependent DiagnoseIfAttrs. /// /// Argument-dependent diagnose_if attributes should be checked each time a /// function is used as a direct callee of a function call. /// /// Returns true if any errors were emitted. bool diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function, const Expr *ThisArg, ArrayRef Args, SourceLocation Loc); /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any /// ArgDependent DiagnoseIfAttrs. /// /// Argument-independent diagnose_if attributes should be checked on every use /// of a function. /// /// Returns true if any errors were emitted. bool diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND, SourceLocation Loc); /// Returns whether the given function's address can be taken or not, /// optionally emitting a diagnostic if the address can't be taken. /// /// Returns false if taking the address of the function is illegal. bool checkAddressOfFunctionIsAvailable(const FunctionDecl *Function, bool Complain = false, SourceLocation Loc = SourceLocation()); // [PossiblyAFunctionType] --> [Return] // NonFunctionType --> NonFunctionType // R (A) --> R(A) // R (*)(A) --> R (A) // R (&)(A) --> R (A) // R (S::*)(A) --> R (A) QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType); FunctionDecl * ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType, bool Complain, DeclAccessPair &Found, bool *pHadMultipleCandidates = nullptr); FunctionDecl * resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &FoundResult); bool resolveAndFixAddressOfSingleOverloadCandidate( ExprResult &SrcExpr, bool DoFunctionPointerConversion = false); FunctionDecl * ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, bool Complain = false, DeclAccessPair *Found = nullptr); bool ResolveAndFixSingleFunctionTemplateSpecialization( ExprResult &SrcExpr, bool DoFunctionPointerConverion = false, bool Complain = false, SourceRange OpRangeForComplaining = SourceRange(), QualType DestTypeForComplaining = QualType(), unsigned DiagIDForComplaining = 0); Expr *FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl, FunctionDecl *Fn); ExprResult FixOverloadedFunctionReference(ExprResult, DeclAccessPair FoundDecl, FunctionDecl *Fn); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, ArrayRef Args, OverloadCandidateSet &CandidateSet, bool PartialOverloading = false); // An enum used to represent the different possible results of building a // range-based for loop. enum ForRangeStatus { FRS_Success, FRS_NoViableFunction, FRS_DiagnosticIssued }; ForRangeStatus BuildForRangeBeginEndCall(SourceLocation Loc, SourceLocation RangeLoc, const DeclarationNameInfo &NameInfo, LookupResult &MemberLookup, OverloadCandidateSet *CandidateSet, Expr *Range, ExprResult *CallExpr); ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, Expr *ExecConfig, bool AllowTypoCorrection=true, bool CalleesAddressIsTaken=false); bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, MultiExprArg Args, SourceLocation RParenLoc, OverloadCandidateSet *CandidateSet, ExprResult *Result); ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, const UnresolvedSetImpl &Fns, Expr *input, bool RequiresADL = true); void LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet, OverloadedOperatorKind Op, const UnresolvedSetImpl &Fns, ArrayRef Args, bool RequiresADL = true); ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS, bool RequiresADL = true, bool AllowRewrittenCandidates = true, FunctionDecl *DefaultedFn = nullptr); ExprResult BuildSynthesizedThreeWayComparison(SourceLocation OpLoc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS, FunctionDecl *DefaultedFn); ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, SourceLocation RLoc, Expr *Base,Expr *Idx); ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc); ExprResult BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc); ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, bool *NoArrowOperatorFound = nullptr); /// CheckCallReturnType - Checks that a call expression's return type is /// complete. Returns true on failure. The location passed in is the location /// that best represents the call. bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, CallExpr *CE, FunctionDecl *FD); /// Helpers for dealing with blocks and functions. bool CheckParmsForFunctionDef(ArrayRef Parameters, bool CheckParameterNames); void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); Scope *getNonFieldDeclScope(Scope *S); /// \name Name lookup /// /// These routines provide name lookup that is used during semantic /// analysis to resolve the various kinds of names (identifiers, /// overloaded operator names, constructor names, etc.) into zero or /// more declarations within a particular scope. The major entry /// points are LookupName, which performs unqualified name lookup, /// and LookupQualifiedName, which performs qualified name lookup. /// /// All name lookup is performed based on some specific criteria, /// which specify what names will be visible to name lookup and how /// far name lookup should work. These criteria are important both /// for capturing language semantics (certain lookups will ignore /// certain names, for example) and for performance, since name /// lookup is often a bottleneck in the compilation of C++. Name /// lookup criteria is specified via the LookupCriteria enumeration. /// /// The results of name lookup can vary based on the kind of name /// lookup performed, the current language, and the translation /// unit. In C, for example, name lookup will either return nothing /// (no entity found) or a single declaration. In C++, name lookup /// can additionally refer to a set of overloaded functions or /// result in an ambiguity. All of the possible results of name /// lookup are captured by the LookupResult class, which provides /// the ability to distinguish among them. //@{ /// Describes the kind of name lookup to perform. enum LookupNameKind { /// Ordinary name lookup, which finds ordinary names (functions, /// variables, typedefs, etc.) in C and most kinds of names /// (functions, variables, members, types, etc.) in C++. LookupOrdinaryName = 0, /// Tag name lookup, which finds the names of enums, classes, /// structs, and unions. LookupTagName, /// Label name lookup. LookupLabel, /// Member name lookup, which finds the names of /// class/struct/union members. LookupMemberName, /// Look up of an operator name (e.g., operator+) for use with /// operator overloading. This lookup is similar to ordinary name /// lookup, but will ignore any declarations that are class members. LookupOperatorName, /// Look up a name following ~ in a destructor name. This is an ordinary /// lookup, but prefers tags to typedefs. LookupDestructorName, /// Look up of a name that precedes the '::' scope resolution /// operator in C++. This lookup completely ignores operator, object, /// function, and enumerator names (C++ [basic.lookup.qual]p1). LookupNestedNameSpecifierName, /// Look up a namespace name within a C++ using directive or /// namespace alias definition, ignoring non-namespace names (C++ /// [basic.lookup.udir]p1). LookupNamespaceName, /// Look up all declarations in a scope with the given name, /// including resolved using declarations. This is appropriate /// for checking redeclarations for a using declaration. LookupUsingDeclName, /// Look up an ordinary name that is going to be redeclared as a /// name with linkage. This lookup ignores any declarations that /// are outside of the current scope unless they have linkage. See /// C99 6.2.2p4-5 and C++ [basic.link]p6. LookupRedeclarationWithLinkage, /// Look up a friend of a local class. This lookup does not look /// outside the innermost non-class scope. See C++11 [class.friend]p11. LookupLocalFriendName, /// Look up the name of an Objective-C protocol. LookupObjCProtocolName, /// Look up implicit 'self' parameter of an objective-c method. LookupObjCImplicitSelfParam, /// Look up the name of an OpenMP user-defined reduction operation. LookupOMPReductionName, /// Look up the name of an OpenMP user-defined mapper. LookupOMPMapperName, /// Look up any declaration with any name. LookupAnyName }; /// Specifies whether (or how) name lookup is being performed for a /// redeclaration (vs. a reference). enum RedeclarationKind { /// The lookup is a reference to this name that is not for the /// purpose of redeclaring the name. NotForRedeclaration = 0, /// The lookup results will be used for redeclaration of a name, /// if an entity by that name already exists and is visible. ForVisibleRedeclaration, /// The lookup results will be used for redeclaration of a name /// with external linkage; non-visible lookup results with external linkage /// may also be found. ForExternalRedeclaration }; RedeclarationKind forRedeclarationInCurContext() { // A declaration with an owning module for linkage can never link against // anything that is not visible. We don't need to check linkage here; if // the context has internal linkage, redeclaration lookup won't find things // from other TUs, and we can't safely compute linkage yet in general. if (cast(CurContext) ->getOwningModuleForLinkage(/*IgnoreLinkage*/true)) return ForVisibleRedeclaration; return ForExternalRedeclaration; } /// The possible outcomes of name lookup for a literal operator. enum LiteralOperatorLookupResult { /// The lookup resulted in an error. LOLR_Error, /// The lookup found no match but no diagnostic was issued. LOLR_ErrorNoDiagnostic, /// The lookup found a single 'cooked' literal operator, which /// expects a normal literal to be built and passed to it. LOLR_Cooked, /// The lookup found a single 'raw' literal operator, which expects /// a string literal containing the spelling of the literal token. LOLR_Raw, /// The lookup found an overload set of literal operator templates, /// which expect the characters of the spelling of the literal token to be /// passed as a non-type template argument pack. LOLR_Template, /// The lookup found an overload set of literal operator templates, /// which expect the character type and characters of the spelling of the /// string literal token to be passed as template arguments. LOLR_StringTemplate }; SpecialMemberOverloadResult LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis); typedef std::function TypoDiagnosticGenerator; typedef std::function TypoRecoveryCallback; private: bool CppLookupName(LookupResult &R, Scope *S); struct TypoExprState { std::unique_ptr Consumer; TypoDiagnosticGenerator DiagHandler; TypoRecoveryCallback RecoveryHandler; TypoExprState(); TypoExprState(TypoExprState &&other) noexcept; TypoExprState &operator=(TypoExprState &&other) noexcept; }; /// The set of unhandled TypoExprs and their associated state. llvm::MapVector DelayedTypos; /// Creates a new TypoExpr AST node. TypoExpr *createDelayedTypo(std::unique_ptr TCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, SourceLocation TypoLoc); // The set of known/encountered (unique, canonicalized) NamespaceDecls. // // The boolean value will be true to indicate that the namespace was loaded // from an AST/PCH file, or false otherwise. llvm::MapVector KnownNamespaces; /// Whether we have already loaded known namespaces from an extenal /// source. bool LoadedExternalKnownNamespaces; /// Helper for CorrectTypo and CorrectTypoDelayed used to create and /// populate a new TypoCorrectionConsumer. Returns nullptr if typo correction /// should be skipped entirely. std::unique_ptr makeTypoCorrectionConsumer(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool ErrorRecovery); public: const TypoExprState &getTypoExprState(TypoExpr *TE) const; /// Clears the state of the given TypoExpr. void clearDelayedTypo(TypoExpr *TE); /// Look up a name, looking for a single declaration. Return /// null if the results were absent, ambiguous, or overloaded. /// /// It is preferable to use the elaborated form and explicitly handle /// ambiguity and overloaded. NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, SourceLocation Loc, LookupNameKind NameKind, RedeclarationKind Redecl = NotForRedeclaration); bool LookupBuiltin(LookupResult &R); bool LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, CXXScopeSpec &SS); bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation = false, bool EnteringContext = false); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl = NotForRedeclaration); bool LookupInSuper(LookupResult &R, CXXRecordDecl *Class); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, UnresolvedSetImpl &Functions); LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc, SourceLocation GnuLabelLoc = SourceLocation()); DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class); CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class); CXXConstructorDecl *LookupCopyingConstructor(CXXRecordDecl *Class, unsigned Quals); CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals); CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class, unsigned Quals); CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals); CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); bool checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Id); LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef ArgTys, bool AllowRaw, bool AllowTemplate, bool AllowStringTemplate, bool DiagnoseMissing); bool isKnownName(StringRef name); /// Status of the function emission on the CUDA/HIP/OpenMP host/device attrs. enum class FunctionEmissionStatus { Emitted, CUDADiscarded, // Discarded due to CUDA/HIP hostness OMPDiscarded, // Discarded due to OpenMP hostness TemplateDiscarded, // Discarded due to uninstantiated templates Unknown, }; FunctionEmissionStatus getEmissionStatus(FunctionDecl *Decl, bool Final = false); // Whether the callee should be ignored in CUDA/HIP/OpenMP host/device check. bool shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee); void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, ArrayRef Args, ADLResult &Functions); void LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true, bool LoadExternal = true); void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true, bool IncludeDependentBases = false, bool LoadExternal = true); enum CorrectTypoKind { CTK_NonError, // CorrectTypo used in a non error recovery situation. CTK_ErrorRecovery // CorrectTypo used in normal error recovery. }; TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, CorrectTypoKind Mode, DeclContext *MemberContext = nullptr, bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr, bool RecordFailure = true); TypoExpr *CorrectTypoDelayed(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode, DeclContext *MemberContext = nullptr, bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr); /// Process any TypoExprs in the given Expr and its children, /// generating diagnostics as appropriate and returning a new Expr if there /// were typos that were all successfully corrected and ExprError if one or /// more typos could not be corrected. /// /// \param E The Expr to check for TypoExprs. /// /// \param InitDecl A VarDecl to avoid because the Expr being corrected is its /// initializer. /// /// \param RecoverUncorrectedTypos If true, when typo correction fails, it /// will rebuild the given Expr with all TypoExprs degraded to RecoveryExprs. /// /// \param Filter A function applied to a newly rebuilt Expr to determine if /// it is an acceptable/usable result from a single combination of typo /// corrections. As long as the filter returns ExprError, different /// combinations of corrections will be tried until all are exhausted. ExprResult CorrectDelayedTyposInExpr( Expr *E, VarDecl *InitDecl = nullptr, bool RecoverUncorrectedTypos = false, llvm::function_ref Filter = [](Expr *E) -> ExprResult { return E; }); ExprResult CorrectDelayedTyposInExpr( ExprResult ER, VarDecl *InitDecl = nullptr, bool RecoverUncorrectedTypos = false, llvm::function_ref Filter = [](Expr *E) -> ExprResult { return E; }) { return ER.isInvalid() ? ER : CorrectDelayedTyposInExpr(ER.get(), InitDecl, RecoverUncorrectedTypos, Filter); } void diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, bool ErrorRecovery = true); void diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, const PartialDiagnostic &PrevNote, bool ErrorRecovery = true); void MarkTypoCorrectedFunctionDefinition(const NamedDecl *F); void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, ArrayRef Args, AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses); void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool AllowInlineNamespace); bool CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old); void DiagnoseAmbiguousLookup(LookupResult &Result); //@} /// Attempts to produce a RecoveryExpr after some AST node cannot be created. ExprResult CreateRecoveryExpr(SourceLocation Begin, SourceLocation End, ArrayRef SubExprs, QualType T = QualType()); ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, SourceLocation IdLoc, bool TypoCorrection = false); NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc); NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, Scope *S); void AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction( FunctionDecl *FD); void AddKnownFunctionAttributes(FunctionDecl *FD); // More parsing and symbol table subroutines. void ProcessPragmaWeak(Scope *S, Decl *D); // Decl attributes - this routine is the top level dispatcher. void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); // Helper for delayed processing of attributes. void ProcessDeclAttributeDelayed(Decl *D, const ParsedAttributesView &AttrList); void ProcessDeclAttributeList(Scope *S, Decl *D, const ParsedAttributesView &AL, bool IncludeCXX11Attributes = true); bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList); void checkUnusedDeclAttributes(Declarator &D); /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference /// type as valid. bool isValidPointerAttrType(QualType T, bool RefOkay = false); bool CheckRegparmAttr(const ParsedAttr &attr, unsigned &value); bool CheckCallingConvAttr(const ParsedAttr &attr, CallingConv &CC, const FunctionDecl *FD = nullptr); bool CheckAttrTarget(const ParsedAttr &CurrAttr); bool CheckAttrNoArgs(const ParsedAttr &CurrAttr); bool checkStringLiteralArgumentAttr(const ParsedAttr &Attr, unsigned ArgNum, StringRef &Str, SourceLocation *ArgLocation = nullptr); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); bool checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, MSInheritanceModel SemanticSpelling); void CheckAlignasUnderalignment(Decl *D); /// Adjust the calling convention of a method to be the ABI default if it /// wasn't specified explicitly. This handles method types formed from /// function type typedefs and typename template arguments. void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, SourceLocation Loc); // Check if there is an explicit attribute, but only look through parens. // The intent is to look for an attribute on the current declarator, but not // one that came from a typedef. bool hasExplicitCallingConv(QualType T); /// Get the outermost AttributedType node that sets a calling convention. /// Valid types should not have multiple attributes with different CCs. const AttributedType *getCallingConvAttributedType(QualType T) const; /// Stmt attributes - this routine is the top level dispatcher. StmtResult ProcessStmtAttributes(Stmt *Stmt, const ParsedAttributesView &Attrs, SourceRange Range); void WarnConflictingTypedMethods(ObjCMethodDecl *Method, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl); void CheckConflictingOverridingMethod(ObjCMethodDecl *Method, ObjCMethodDecl *Overridden, bool IsProtocolMethodDecl); /// WarnExactTypedMethods - This routine issues a warning if method /// implementation declaration matches exactly that of its declaration. void WarnExactTypedMethods(ObjCMethodDecl *Method, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl); typedef llvm::SmallPtrSet SelectorSet; /// CheckImplementationIvars - This routine checks if the instance variables /// listed in the implelementation match those listed in the interface. void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, ObjCIvarDecl **Fields, unsigned nIvars, SourceLocation Loc); /// ImplMethodsVsClassMethods - This is main routine to warn if any method /// remains unimplemented in the class or category \@implementation. void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool IncompleteImpl = false); /// DiagnoseUnimplementedProperties - This routine warns on those properties /// which must be implemented by this implementation. void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, bool SynthesizeProperties); /// Diagnose any null-resettable synthesized setters. void diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl); /// DefaultSynthesizeProperties - This routine default synthesizes all /// properties which must be synthesized in the class's \@implementation. void DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, ObjCInterfaceDecl *IDecl, SourceLocation AtEnd); void DefaultSynthesizeProperties(Scope *S, Decl *D, SourceLocation AtEnd); /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is /// an ivar synthesized for 'Method' and 'Method' is a property accessor /// declared in class 'IFace'. bool IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace, ObjCMethodDecl *Method, ObjCIvarDecl *IV); /// DiagnoseUnusedBackingIvarInAccessor - Issue an 'unused' warning if ivar which /// backs the property is not used in the property's accessor. void DiagnoseUnusedBackingIvarInAccessor(Scope *S, const ObjCImplementationDecl *ImplD); /// GetIvarBackingPropertyAccessor - If method is a property setter/getter and /// it property has a backing ivar, returns this ivar; otherwise, returns NULL. /// It also returns ivar's property on success. ObjCIvarDecl *GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method, const ObjCPropertyDecl *&PDecl) const; /// Called by ActOnProperty to handle \@property declarations in /// class extensions. ObjCPropertyDecl *HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, SourceLocation GetterNameLoc, Selector SetterSel, SourceLocation SetterNameLoc, const bool isReadWrite, unsigned &Attributes, const unsigned AttributesAsWritten, QualType T, TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind); /// Called by ActOnProperty and HandlePropertyInClassExtension to /// handle creating the ObjcPropertyDecl for a category or \@interface. ObjCPropertyDecl *CreatePropertyDecl(Scope *S, ObjCContainerDecl *CDecl, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, SourceLocation GetterNameLoc, Selector SetterSel, SourceLocation SetterNameLoc, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, QualType T, TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = nullptr); /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, ObjCInterfaceDecl* IDecl); void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D); void DiagnoseMissingDesignatedInitOverrides( const ObjCImplementationDecl *ImplD, const ObjCInterfaceDecl *IFD); void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); enum MethodMatchStrategy { MMS_loose, MMS_strict }; /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns /// true, or false, accordingly. bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, const ObjCMethodDecl *PrevMethod, MethodMatchStrategy strategy = MMS_strict); /// MatchAllMethodDeclarations - Check methods declaraed in interface or /// or protocol against those declared in their implementations. void MatchAllMethodDeclarations(const SelectorSet &InsMap, const SelectorSet &ClsMap, SelectorSet &InsMapSeen, SelectorSet &ClsMapSeen, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool &IncompleteImpl, bool ImmediateClass, bool WarnCategoryMethodImpl=false); /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in /// category matches with those implemented in its primary class and /// warns each time an exact match is found. void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); /// Add the given method to the list of globally-known methods. void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); /// Returns default addr space for method qualifiers. LangAS getDefaultCXXMethodAddrSpace() const; private: /// AddMethodToGlobalPool - Add an instance or factory method to the global /// pool. See descriptoin of AddInstanceMethodToGlobalPool. void AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance); /// LookupMethodInGlobalPool - Returns the instance or factory method and /// optionally warns if there are multiple signatures. ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass, bool instance); public: /// - Returns instance or factory methods in global method pool for /// given selector. It checks the desired kind first, if none is found, and /// parameter checkTheOther is set, it then checks the other kind. If no such /// method or only one method is found, function returns false; otherwise, it /// returns true. bool CollectMultipleMethodsInGlobalPool(Selector Sel, SmallVectorImpl& Methods, bool InstanceFirst, bool CheckTheOther, const ObjCObjectType *TypeBound = nullptr); bool AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, SourceRange R, bool receiverIdOrClass, SmallVectorImpl& Methods); void DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl &Methods, Selector Sel, SourceRange R, bool receiverIdOrClass); private: /// - Returns a selector which best matches given argument list or /// nullptr if none could be found ObjCMethodDecl *SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance, SmallVectorImpl& Methods); /// Record the typo correction failure and return an empty correction. TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc, bool RecordFailure = true) { if (RecordFailure) TypoCorrectionFailures[Typo].insert(TypoLoc); return TypoCorrection(); } public: /// AddInstanceMethodToGlobalPool - All instance methods in a translation /// unit are added to a global pool. This allows us to efficiently associate /// a selector with a method declaraation for purposes of typechecking /// messages sent to "id" (where the class of the object is unknown). void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { AddMethodToGlobalPool(Method, impl, /*instance*/true); } /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { AddMethodToGlobalPool(Method, impl, /*instance*/false); } /// AddAnyMethodToGlobalPool - Add any method, instance or factory to global /// pool. void AddAnyMethodToGlobalPool(Decl *D); /// LookupInstanceMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass=false) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, /*instance*/true); } /// LookupFactoryMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass=false) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, /*instance*/false); } const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel, QualType ObjectType=QualType()); /// LookupImplementedMethodInGlobalPool - Returns the method which has an /// implementation. ObjCMethodDecl *LookupImplementedMethodInGlobalPool(Selector Sel); /// CollectIvarsToConstructOrDestruct - Collect those ivars which require /// initialization. void CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, SmallVectorImpl &Ivars); //===--------------------------------------------------------------------===// // Statement Parsing Callbacks: SemaStmt.cpp. public: class FullExprArg { public: FullExprArg() : E(nullptr) { } FullExprArg(Sema &actions) : E(nullptr) { } ExprResult release() { return E; } Expr *get() const { return E; } Expr *operator->() { return E; } private: // FIXME: No need to make the entire Sema class a friend when it's just // Sema::MakeFullExpr that needs access to the constructor below. friend class Sema; explicit FullExprArg(Expr *expr) : E(expr) {} Expr *E; }; FullExprArg MakeFullExpr(Expr *Arg) { return MakeFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation()); } FullExprArg MakeFullExpr(Expr *Arg, SourceLocation CC) { return FullExprArg( ActOnFinishFullExpr(Arg, CC, /*DiscardedValue*/ false).get()); } FullExprArg MakeFullDiscardedValueExpr(Expr *Arg) { ExprResult FE = ActOnFinishFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation(), /*DiscardedValue*/ true); return FullExprArg(FE.get()); } StmtResult ActOnExprStmt(ExprResult Arg, bool DiscardedValue = true); StmtResult ActOnExprStmtError(); StmtResult ActOnNullStmt(SourceLocation SemiLoc, bool HasLeadingEmptyMacro = false); void ActOnStartOfCompoundStmt(bool IsStmtExpr); void ActOnFinishOfCompoundStmt(); StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef Elts, bool isStmtExpr); /// A RAII object to enter scope of a compound statement. class CompoundScopeRAII { public: CompoundScopeRAII(Sema &S, bool IsStmtExpr = false) : S(S) { S.ActOnStartOfCompoundStmt(IsStmtExpr); } ~CompoundScopeRAII() { S.ActOnFinishOfCompoundStmt(); } private: Sema &S; }; /// An RAII helper that pops function a function scope on exit. struct FunctionScopeRAII { Sema &S; bool Active; FunctionScopeRAII(Sema &S) : S(S), Active(true) {} ~FunctionScopeRAII() { if (Active) S.PopFunctionScopeInfo(); } void disable() { Active = false; } }; StmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, SourceLocation StartLoc, SourceLocation EndLoc); void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); StmtResult ActOnForEachLValueExpr(Expr *E); ExprResult ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val); StmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprResult LHS, SourceLocation DotDotDotLoc, ExprResult RHS, SourceLocation ColonLoc); void ActOnCaseStmtBody(Stmt *CaseStmt, Stmt *SubStmt); StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, Stmt *SubStmt, Scope *CurScope); StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt); StmtResult ActOnAttributedStmt(SourceLocation AttrLoc, ArrayRef Attrs, Stmt *SubStmt); class ConditionResult; StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, ConditionResult Cond, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, ConditionResult Cond, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Stmt *InitStmt, ConditionResult Cond); StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *Body); StmtResult ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond, Stmt *Body); StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation CondLParen, Expr *Cond, SourceLocation CondRParen); StmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *First, ConditionResult Second, FullExprArg Third, SourceLocation RParenLoc, Stmt *Body); ExprResult CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection); StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, Stmt *First, Expr *collection, SourceLocation RParenLoc); StmtResult FinishObjCForCollectionStmt(Stmt *ForCollection, Stmt *Body); enum BuildForRangeKind { /// Initial building of a for-range statement. BFRK_Build, /// Instantiation or recovery rebuild of a for-range statement. Don't /// attempt any typo-correction. BFRK_Rebuild, /// Determining whether a for-range statement could be built. Avoid any /// unnecessary or irreversible actions. BFRK_Check }; StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt, Stmt *LoopVar, SourceLocation ColonLoc, Expr *Collection, SourceLocation RParenLoc, BuildForRangeKind Kind); StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt, SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *Begin, Stmt *End, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc, BuildForRangeKind Kind); StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body); StmtResult ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, LabelDecl *TheDecl); StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, Expr *DestExp); StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope); void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, unsigned NumParams); typedef std::pair CapturedParamNameType; void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, ArrayRef Params, unsigned OpenMPCaptureLevel = 0); StmtResult ActOnCapturedRegionEnd(Stmt *S); void ActOnCapturedRegionError(); RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc, unsigned NumParams); enum CopyElisionSemanticsKind { CES_Strict = 0, CES_AllowParameters = 1, CES_AllowDifferentTypes = 2, CES_AllowExceptionVariables = 4, CES_FormerDefault = (CES_AllowParameters), CES_Default = (CES_AllowParameters | CES_AllowDifferentTypes), CES_AsIfByStdMove = (CES_AllowParameters | CES_AllowDifferentTypes | CES_AllowExceptionVariables), }; VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, CopyElisionSemanticsKind CESK); bool isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, CopyElisionSemanticsKind CESK); StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, Scope *CurScope); StmtResult BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg Constraints, MultiExprArg Exprs, Expr *AsmString, MultiExprArg Clobbers, unsigned NumLabels, SourceLocation RParenLoc); void FillInlineAsmIdentifierInfo(Expr *Res, llvm::InlineAsmIdentifierInfo &Info); ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool IsUnevaluatedContext); bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset, SourceLocation AsmLoc); ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member, SourceLocation AsmLoc); StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef AsmToks, StringRef AsmString, unsigned NumOutputs, unsigned NumInputs, ArrayRef Constraints, ArrayRef Clobbers, ArrayRef Exprs, SourceLocation EndLoc); LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName, SourceLocation Location, bool AlwaysCreate); VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, bool Invalid = false); Decl *ActOnObjCExceptionDecl(Scope *S, Declarator &D); StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, Decl *Parm, Stmt *Body); StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body); StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, MultiStmtArg Catch, Stmt *Finally); StmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw); StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, Scope *CurScope); ExprResult ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand); StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SynchExpr, Stmt *SynchBody); StmtResult ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body); VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id); Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl, Stmt *HandlerBlock); StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, ArrayRef Handlers); StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ? SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler); StmtResult ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Stmt *Block); void ActOnStartSEHFinallyBlock(); void ActOnAbortSEHFinallyBlock(); StmtResult ActOnFinishSEHFinallyBlock(SourceLocation Loc, Stmt *Block); StmtResult ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope); void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const; /// If it's a file scoped decl that must warn if not used, keep track /// of it. void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); /// DiagnoseUnusedExprResult - If the statement passed in is an expression /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S); void DiagnoseUnusedNestedTypedefs(const RecordDecl *D); void DiagnoseUnusedDecl(const NamedDecl *ND); /// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null /// statement as a \p Body, and it is located on the same line. /// /// This helps prevent bugs due to typos, such as: /// if (condition); /// do_stuff(); void DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body, unsigned DiagID); /// Warn if a for/while loop statement \p S, which is followed by /// \p PossibleBody, has a suspicious null statement as a body. void DiagnoseEmptyLoopBody(const Stmt *S, const Stmt *PossibleBody); /// Warn if a value is moved to itself. void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, SourceLocation OpLoc); /// Warn if we're implicitly casting from a _Nullable pointer type to a /// _Nonnull one. void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, SourceLocation Loc); /// Warn when implicitly casting 0 to nullptr. void diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E); ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { return DelayedDiagnostics.push(pool); } void PopParsingDeclaration(ParsingDeclState state, Decl *decl); typedef ProcessingContextState ParsingClassState; ParsingClassState PushParsingClass() { ParsingClassDepth++; return DelayedDiagnostics.pushUndelayed(); } void PopParsingClass(ParsingClassState state) { ParsingClassDepth--; DelayedDiagnostics.popUndelayed(state); } void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); void DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks = false, ObjCInterfaceDecl *ClassReceiver = nullptr); bool makeUnavailableInSystemHeader(SourceLocation loc, UnavailableAttr::ImplicitReason reason); /// Issue any -Wunguarded-availability warnings in \c FD void DiagnoseUnguardedAvailabilityViolations(Decl *FD); void handleDelayedAvailabilityCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid); bool DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, const ObjCInterfaceDecl *UnknownObjCClass = nullptr, bool ObjCPropertyAccess = false, bool AvoidPartialAvailabilityChecks = false, ObjCInterfaceDecl *ClassReciever = nullptr); void NoteDeletedFunction(FunctionDecl *FD); void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD); bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, SourceLocation Loc); void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ArrayRef Args); void PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, ExpressionEvaluationContextRecord::ExpressionKind Type = ExpressionEvaluationContextRecord::EK_Other); enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; void PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, ExpressionEvaluationContextRecord::ExpressionKind Type = ExpressionEvaluationContextRecord::EK_Other); void PopExpressionEvaluationContext(); void DiscardCleanupsInEvaluationContext(); ExprResult TransformToPotentiallyEvaluated(Expr *E); ExprResult HandleExprEvaluationContextForTypeof(Expr *E); ExprResult CheckUnevaluatedOperand(Expr *E); void CheckUnusedVolatileAssignment(Expr *E); ExprResult ActOnConstantExpression(ExprResult Res); // Functions for marking a declaration referenced. These functions also // contain the relevant logic for marking if a reference to a function or // variable is an odr-use (in the C++11 sense). There are separate variants // for expressions referring to a decl; these exist because odr-use marking // needs to be delayed for some constant variables when we build one of the // named expressions. // // MightBeOdrUse indicates whether the use could possibly be an odr-use, and // should usually be true. This only needs to be set to false if the lack of // odr-use cannot be determined from the current context (for instance, // because the name denotes a virtual function and was written without an // explicit nested-name-specifier). void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse); void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, bool MightBeOdrUse = true); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr); void MarkMemberReferenced(MemberExpr *E); void MarkFunctionParmPackReferenced(FunctionParmPackExpr *E); void MarkCaptureUsedInEnclosingContext(VarDecl *Capture, SourceLocation Loc, unsigned CapturingScopeIndex); ExprResult CheckLValueToRValueConversionOperand(Expr *E); void CleanupVarDeclMarking(); enum TryCaptureKind { TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef }; /// Try to capture the given variable. /// /// \param Var The variable to capture. /// /// \param Loc The location at which the capture occurs. /// /// \param Kind The kind of capture, which may be implicit (for either a /// block or a lambda), or explicit by-value or by-reference (for a lambda). /// /// \param EllipsisLoc The location of the ellipsis, if one is provided in /// an explicit lambda capture. /// /// \param BuildAndDiagnose Whether we are actually supposed to add the /// captures or diagnose errors. If false, this routine merely check whether /// the capture can occur without performing the capture itself or complaining /// if the variable cannot be captured. /// /// \param CaptureType Will be set to the type of the field used to capture /// this variable in the innermost block or lambda. Only valid when the /// variable can be captured. /// /// \param DeclRefType Will be set to the type of a reference to the capture /// from within the current scope. Only valid when the variable can be /// captured. /// /// \param FunctionScopeIndexToStopAt If non-null, it points to the index /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. /// This is useful when enclosing lambdas must speculatively capture /// variables that may or may not be used in certain specializations of /// a nested generic lambda. /// /// \returns true if an error occurred (i.e., the variable cannot be /// captured) and false if the capture succeeded. bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind, SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt); /// Try to capture the given variable. bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind = TryCapture_Implicit, SourceLocation EllipsisLoc = SourceLocation()); /// Checks if the variable must be captured. bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc); /// Given a variable, determine the type that a reference to that /// variable will have in the given scope. QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); /// Mark all of the declarations referenced within a particular AST node as /// referenced. Used when template instantiation instantiates a non-dependent /// type -- entities referenced by the type are now referenced. void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); void MarkDeclarationsReferencedInExpr(Expr *E, bool SkipLocalVariables = false); /// Try to recover by turning the given expression into a /// call. Returns true if recovery was attempted or an error was /// emitted; this may also leave the ExprResult invalid. bool tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain = false, bool (*IsPlausibleResult)(QualType) = nullptr); /// Figure out if an expression could be turned into a call. bool tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, UnresolvedSetImpl &NonTemplateOverloads); /// Try to convert an expression \p E to type \p Ty. Returns the result of the /// conversion. ExprResult tryConvertExprToType(Expr *E, QualType Ty); /// Conditionally issue a diagnostic based on the current /// evaluation context. /// /// \param Statement If Statement is non-null, delay reporting the /// diagnostic until the function body is parsed, and then do a basic /// reachability analysis to determine if the statement is reachable. /// If it is unreachable, the diagnostic will not be emitted. bool DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD); /// Similar, but diagnostic is only produced if all the specified statements /// are reachable. bool DiagRuntimeBehavior(SourceLocation Loc, ArrayRef Stmts, const PartialDiagnostic &PD); // Primary Expressions. SourceRange getExprRange(Expr *E) const; ExprResult ActOnIdExpression( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, CorrectionCandidateCallback *CCC = nullptr, bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr); void DecomposeUnqualifiedId(const UnqualifiedId &Id, TemplateArgumentListInfo &Buffer, DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *&TemplateArgs); bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CorrectionCandidateCallback &CCC, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, ArrayRef Args = None, TypoExpr **Out = nullptr); DeclResult LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S, IdentifierInfo *II); ExprResult BuildIvarRefExpr(Scope *S, SourceLocation Loc, ObjCIvarDecl *IV); ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S, IdentifierInfo *II, bool AllowBuiltinCreation=false); ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs); /// If \p D cannot be odr-used in the current expression evaluation context, /// return a reason explaining why. Otherwise, return NOUR_None. NonOdrUseReason getNonOdrUseReasonInCurrentContext(ValueDecl *D); DeclRefExpr *BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, SourceLocation Loc, const CXXScopeSpec *SS = nullptr); DeclRefExpr * BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS = nullptr, NamedDecl *FoundD = nullptr, SourceLocation TemplateKWLoc = SourceLocation(), const TemplateArgumentListInfo *TemplateArgs = nullptr); DeclRefExpr * BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, NestedNameSpecifierLoc NNS, NamedDecl *FoundD = nullptr, SourceLocation TemplateKWLoc = SourceLocation(), const TemplateArgumentListInfo *TemplateArgs = nullptr); ExprResult BuildAnonymousStructUnionMemberReference( const CXXScopeSpec &SS, SourceLocation nameLoc, IndirectFieldDecl *indirectField, DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_none), Expr *baseObjectExpr = nullptr, SourceLocation opLoc = SourceLocation()); ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, const Scope *S); ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, bool IsDefiniteInstance, const Scope *S); bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen); ExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI = nullptr); ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL, bool AcceptInvalidDecl = false); ExprResult BuildDeclarationNameExpr( const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr, bool AcceptInvalidDecl = false); ExprResult BuildLiteralOperatorCall(LookupResult &R, DeclarationNameInfo &SuffixInfo, ArrayRef Args, SourceLocation LitEndLoc, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr); ExprResult BuildPredefinedExpr(SourceLocation Loc, PredefinedExpr::IdentKind IK); ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); ExprResult BuildUniqueStableName(SourceLocation Loc, TypeSourceInfo *Operand); ExprResult BuildUniqueStableName(SourceLocation Loc, Expr *E); ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, SourceLocation RParen, ParsedType Ty); ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, SourceLocation RParen, Expr *E); bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr); ExprResult ActOnCharacterConstant(const Token &Tok, Scope *UDLScope = nullptr); ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E); ExprResult ActOnParenListExpr(SourceLocation L, SourceLocation R, MultiExprArg Val); /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). ExprResult ActOnStringLiteral(ArrayRef StringToks, Scope *UDLScope = nullptr); ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef ArgTypes, ArrayRef ArgExprs); ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef Types, ArrayRef Exprs); // Binary/Unary Operators. 'Tok' is the token for the operator. ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *InputExpr); ExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *Input); ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, Expr *Input); bool isQualifiedMemberAccess(Expr *E); QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc); ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, SourceRange R); ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind); ExprResult ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, bool IsType, void *TyOrEx, SourceRange ArgRange); ExprResult CheckPlaceholderExpr(Expr *E); bool CheckVecStepExpr(Expr *E); bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind); bool CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, SourceRange ExprRange, UnaryExprOrTypeTrait ExprKind); ExprResult ActOnSizeofParameterPackExpr(Scope *S, SourceLocation OpLoc, IdentifierInfo &Name, SourceLocation NameLoc, SourceLocation RParenLoc); ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, Expr *Input); ExprResult ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); ExprResult CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, Expr *ColumnIdx, SourceLocation RBLoc); ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, Expr *LowerBound, SourceLocation ColonLoc, Expr *Length, SourceLocation RBLoc); ExprResult ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, SourceLocation RParenLoc, ArrayRef Dims, ArrayRef Brackets); /// Data structure for iterator expression. struct OMPIteratorData { IdentifierInfo *DeclIdent = nullptr; SourceLocation DeclIdentLoc; ParsedType Type; OMPIteratorExpr::IteratorRange Range; SourceLocation AssignLoc; SourceLocation ColonLoc; SourceLocation SecColonLoc; }; ExprResult ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, SourceLocation LLoc, SourceLocation RLoc, ArrayRef Data); // This struct is for use by ActOnMemberAccess to allow // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after // changing the access operator from a '.' to a '->' (to see if that is the // change needed to fix an error about an unknown member, e.g. when the class // defines a custom operator->). struct ActOnMemberAccessExtraArgs { Scope *S; UnqualifiedId &Id; Decl *ObjCImpDecl; }; ExprResult BuildMemberReferenceExpr( Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, bool SuppressQualifierCheck = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, FieldDecl *Field, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo); ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, const CXXScopeSpec &SS, const LookupResult &R); ExprResult ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Member, Decl *ObjCImpDecl); MemberExpr * BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS, SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = nullptr); MemberExpr * BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = nullptr); void ActOnDefaultCtorInitializers(Decl *CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, const FunctionProtoType *Proto, ArrayRef Args, SourceLocation RParenLoc, bool ExecConfig = false); void CheckStaticArrayArgument(SourceLocation CallLoc, ParmVarDecl *Param, const Expr *ArgExpr); /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig = nullptr); ExprResult BuildCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig = nullptr, bool IsExecConfig = false); enum class AtomicArgumentOrder { API, AST }; ExprResult BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, SourceLocation RParenLoc, MultiExprArg Args, AtomicExpr::AtomicOp Op, AtomicArgumentOrder ArgOrder = AtomicArgumentOrder::API); ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, ArrayRef Arg, SourceLocation RParenLoc, Expr *Config = nullptr, bool IsExecConfig = false, ADLCallKind UsesADL = ADLCallKind::NotADL); ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, SourceLocation GGGLoc); ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, Declarator &D, ParsedType &Ty, SourceLocation RParenLoc, Expr *CastExpr); ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, SourceLocation RParenLoc, Expr *Op); CastKind PrepareScalarCast(ExprResult &src, QualType destType); /// Build an altivec or OpenCL literal. ExprResult BuildVectorLiteral(SourceLocation LParenLoc, SourceLocation RParenLoc, Expr *E, TypeSourceInfo *TInfo); ExprResult MaybeConvertParenListExprToParenExpr(Scope *S, Expr *ME); ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc, Expr *InitExpr); ExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, SourceLocation RParenLoc, Expr *LiteralExpr); ExprResult ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc); ExprResult BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc); ExprResult ActOnDesignatedInitializer(Designation &Desig, SourceLocation EqualOrColonLoc, bool GNUSyntax, ExprResult Init); private: static BinaryOperatorKind ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind); public: ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr); ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); void DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc); /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. ExprResult ActOnConditionalOp(SourceLocation QuestionLoc, SourceLocation ColonLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr); /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl); void ActOnStartStmtExpr(); ExprResult ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt, SourceLocation RPLoc); ExprResult BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, SourceLocation RPLoc, unsigned TemplateDepth); // Handle the final expression in a statement expression. ExprResult ActOnStmtExprResult(ExprResult E); void ActOnStmtExprError(); // __builtin_offsetof(type, identifier(.identifier|[expr])*) struct OffsetOfComponent { SourceLocation LocStart, LocEnd; bool isBrackets; // true if [expr], false if .ident union { IdentifierInfo *IdentInfo; Expr *E; } U; }; /// __builtin_offsetof(type, a.b[123][456].c) ExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, TypeSourceInfo *TInfo, ArrayRef Components, SourceLocation RParenLoc); ExprResult ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, ParsedType ParsedArgTy, ArrayRef Components, SourceLocation RParenLoc); // __builtin_choose_expr(constExpr, expr1, expr2) ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr, SourceLocation RPLoc); // __builtin_va_arg(expr, type) ExprResult ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty, SourceLocation RPLoc); ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E, TypeSourceInfo *TInfo, SourceLocation RPLoc); // __builtin_LINE(), __builtin_FUNCTION(), __builtin_FILE(), // __builtin_COLUMN() ExprResult ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind, SourceLocation BuiltinLoc, SourceLocation RPLoc); // Build a potentially resolved SourceLocExpr. ExprResult BuildSourceLocExpr(SourceLocExpr::IdentKind Kind, SourceLocation BuiltinLoc, SourceLocation RPLoc, DeclContext *ParentContext); // __null ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); bool CheckCaseExpression(Expr *E); /// Describes the result of an "if-exists" condition check. enum IfExistsResult { /// The symbol exists. IER_Exists, /// The symbol does not exist. IER_DoesNotExist, /// The name is a dependent name, so the results will differ /// from one instantiation to the next. IER_Dependent, /// An error occurred. IER_Error }; IfExistsResult CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, const DeclarationNameInfo &TargetNameInfo); IfExistsResult CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name); StmtResult BuildMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, NestedNameSpecifierLoc QualifierLoc, DeclarationNameInfo NameInfo, Stmt *Nested); StmtResult ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name, Stmt *Nested); //===------------------------- "Block" Extension ------------------------===// /// ActOnBlockStart - This callback is invoked when a block literal is /// started. void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); /// ActOnBlockArguments - This callback allows processing of block arguments. /// If there are no arguments, this is still invoked. void ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, Scope *CurScope); /// ActOnBlockError - If there is an error parsing a block, this callback /// is invoked to pop the information about the block from the action impl. void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); /// ActOnBlockStmtExpr - This is called when the body of a block statement /// literal was successfully completed. ^(int x){...} ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, Scope *CurScope); //===---------------------------- Clang Extensions ----------------------===// /// __builtin_convertvector(...) ExprResult ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc); //===---------------------------- OpenCL Features -----------------------===// /// __builtin_astype(...) ExprResult ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc); //===---------------------------- C++ Features --------------------------===// // Act on C++ namespaces Decl *ActOnStartNamespaceDef(Scope *S, SourceLocation InlineLoc, SourceLocation NamespaceLoc, SourceLocation IdentLoc, IdentifierInfo *Ident, SourceLocation LBrace, const ParsedAttributesView &AttrList, UsingDirectiveDecl *&UsingDecl); void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace); NamespaceDecl *getStdNamespace() const; NamespaceDecl *getOrCreateStdNamespace(); NamespaceDecl *lookupStdExperimentalNamespace(); CXXRecordDecl *getStdBadAlloc() const; EnumDecl *getStdAlignValT() const; private: // A cache representing if we've fully checked the various comparison category // types stored in ASTContext. The bit-index corresponds to the integer value // of a ComparisonCategoryType enumerator. llvm::SmallBitVector FullyCheckedComparisonCategories; ValueDecl *tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl, CXXScopeSpec &SS, ParsedType TemplateTypeTy, IdentifierInfo *MemberOrBase); public: enum class ComparisonCategoryUsage { /// The '<=>' operator was used in an expression and a builtin operator /// was selected. OperatorInExpression, /// A defaulted 'operator<=>' needed the comparison category. This /// typically only applies to 'std::strong_ordering', due to the implicit /// fallback return value. DefaultedOperator, }; /// Lookup the specified comparison category types in the standard /// library, an check the VarDecls possibly returned by the operator<=> /// builtins for that type. /// /// \return The type of the comparison category type corresponding to the /// specified Kind, or a null type if an error occurs QualType CheckComparisonCategoryType(ComparisonCategoryType Kind, SourceLocation Loc, ComparisonCategoryUsage Usage); /// Tests whether Ty is an instance of std::initializer_list and, if /// it is and Element is not NULL, assigns the element type to Element. bool isStdInitializerList(QualType Ty, QualType *Element); /// Looks for the std::initializer_list template and instantiates it /// with Element, or emits an error if it's not found. /// /// \returns The instantiated template, or null on error. QualType BuildStdInitializerList(QualType Element, SourceLocation Loc); /// Determine whether Ctor is an initializer-list constructor, as /// defined in [dcl.init.list]p2. bool isInitListConstructor(const FunctionDecl *Ctor); Decl *ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, SourceLocation NamespcLoc, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, const ParsedAttributesView &AttrList); void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); Decl *ActOnNamespaceAliasDef(Scope *CurScope, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident); void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, const LookupResult &PreviousDecls, UsingShadowDecl *&PrevShadow); UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, NamedDecl *Target, UsingShadowDecl *PrevDecl); bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, bool HasTypenameKeyword, const CXXScopeSpec &SS, SourceLocation NameLoc, const LookupResult &Previous); bool CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename, const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, SourceLocation NameLoc); NamedDecl *BuildUsingDeclaration( Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, bool HasTypenameKeyword, SourceLocation TypenameLoc, CXXScopeSpec &SS, DeclarationNameInfo NameInfo, SourceLocation EllipsisLoc, const ParsedAttributesView &AttrList, bool IsInstantiation); NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom, ArrayRef Expansions); bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); /// Given a derived-class using shadow declaration for a constructor and the /// correspnding base class constructor, find or create the implicit /// synthesized derived class constructor to use for this initialization. CXXConstructorDecl * findInheritingConstructor(SourceLocation Loc, CXXConstructorDecl *BaseCtor, ConstructorUsingShadowDecl *DerivedShadow); Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation TypenameLoc, CXXScopeSpec &SS, UnqualifiedId &Name, SourceLocation EllipsisLoc, const ParsedAttributesView &AttrList); Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, MultiTemplateParamsArg TemplateParams, SourceLocation UsingLoc, UnqualifiedId &Name, const ParsedAttributesView &AttrList, TypeResult Type, Decl *DeclFromDeclSpec); /// BuildCXXConstructExpr - Creates a complete call to a constructor, /// including handling of its default argument expressions. /// /// \param ConstructKind - a CXXConstructExpr::ConstructionKind ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, NamedDecl *FoundDecl, CXXConstructorDecl *Constructor, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); /// Build a CXXConstructExpr whose constructor has already been resolved if /// it denotes an inherited constructor. ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); // FIXME: Can we remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, NamedDecl *FoundDecl, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); ExprResult BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field); /// Instantiate or parse a C++ default argument expression as necessary. /// Return true on error. bool CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating /// the default expr if needed. ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); /// FinalizeVarWithDestructor - Prepare for calling destructor on the /// constructed variable. void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); /// Helper class that collects exception specifications for /// implicitly-declared special member functions. class ImplicitExceptionSpecification { // Pointer to allow copying Sema *Self; // We order exception specifications thus: // noexcept is the most restrictive, but is only used in C++11. // throw() comes next. // Then a throw(collected exceptions) // Finally no specification, which is expressed as noexcept(false). // throw(...) is used instead if any called function uses it. ExceptionSpecificationType ComputedEST; llvm::SmallPtrSet ExceptionsSeen; SmallVector Exceptions; void ClearExceptions() { ExceptionsSeen.clear(); Exceptions.clear(); } public: explicit ImplicitExceptionSpecification(Sema &Self) : Self(&Self), ComputedEST(EST_BasicNoexcept) { if (!Self.getLangOpts().CPlusPlus11) ComputedEST = EST_DynamicNone; } /// Get the computed exception specification type. ExceptionSpecificationType getExceptionSpecType() const { assert(!isComputedNoexcept(ComputedEST) && "noexcept(expr) should not be a possible result"); return ComputedEST; } /// The number of exceptions in the exception specification. unsigned size() const { return Exceptions.size(); } /// The set of exceptions in the exception specification. const QualType *data() const { return Exceptions.data(); } /// Integrate another called method into the collected data. void CalledDecl(SourceLocation CallLoc, const CXXMethodDecl *Method); /// Integrate an invoked expression into the collected data. void CalledExpr(Expr *E) { CalledStmt(E); } /// Integrate an invoked statement into the collected data. void CalledStmt(Stmt *S); /// Overwrite an EPI's exception specification with this /// computed exception specification. FunctionProtoType::ExceptionSpecInfo getExceptionSpec() const { FunctionProtoType::ExceptionSpecInfo ESI; ESI.Type = getExceptionSpecType(); if (ESI.Type == EST_Dynamic) { ESI.Exceptions = Exceptions; } else if (ESI.Type == EST_None) { /// C++11 [except.spec]p14: /// The exception-specification is noexcept(false) if the set of /// potential exceptions of the special member function contains "any" ESI.Type = EST_NoexceptFalse; ESI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(), tok::kw_false).get(); } return ESI; } }; /// Determine what sort of exception specification a defaulted /// copy constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); /// Determine what sort of exception specification a defaulted /// default constructor of a class will have, and whether the parameter /// will be const. ImplicitExceptionSpecification ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD); /// Determine what sort of exception specification a defaulted /// copy assignment operator of a class will have, and whether the /// parameter will be const. ImplicitExceptionSpecification ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD); /// Determine what sort of exception specification a defaulted move /// constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD); /// Determine what sort of exception specification a defaulted move /// assignment operator of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD); /// Determine what sort of exception specification a defaulted /// destructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD); /// Determine what sort of exception specification an inheriting /// constructor of a class will have. ImplicitExceptionSpecification ComputeInheritingCtorExceptionSpec(SourceLocation Loc, CXXConstructorDecl *CD); /// Evaluate the implicit exception specification for a defaulted /// special member function. void EvaluateImplicitExceptionSpec(SourceLocation Loc, FunctionDecl *FD); /// Check the given noexcept-specifier, convert its expression, and compute /// the appropriate ExceptionSpecificationType. ExprResult ActOnNoexceptSpec(SourceLocation NoexceptLoc, Expr *NoexceptExpr, ExceptionSpecificationType &EST); /// Check the given exception-specification and update the /// exception specification information with the results. void checkExceptionSpecification(bool IsTopLevel, ExceptionSpecificationType EST, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr, SmallVectorImpl &Exceptions, FunctionProtoType::ExceptionSpecInfo &ESI); /// Determine if we're in a case where we need to (incorrectly) eagerly /// parse an exception specification to work around a libstdc++ bug. bool isLibstdcxxEagerExceptionSpecHack(const Declarator &D); /// Add an exception-specification to the given member function /// (or member function template). The exception-specification was parsed /// after the method itself was declared. void actOnDelayedExceptionSpecification(Decl *Method, ExceptionSpecificationType EST, SourceRange SpecificationRange, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr); class InheritedConstructorInfo; /// Determine if a special member function should have a deleted /// definition when it is defaulted. bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, InheritedConstructorInfo *ICI = nullptr, bool Diagnose = false); /// Produce notes explaining why a defaulted function was defined as deleted. void DiagnoseDeletedDefaultedFunction(FunctionDecl *FD); /// Declare the implicit default constructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// default constructor will be added. /// /// \returns The implicitly-declared default constructor. CXXConstructorDecl *DeclareImplicitDefaultConstructor( CXXRecordDecl *ClassDecl); /// DefineImplicitDefaultConstructor - Checks for feasibility of /// defining this constructor as the default constructor. void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// Declare the implicit destructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// destructor will be added. /// /// \returns The implicitly-declared destructor. CXXDestructorDecl *DeclareImplicitDestructor(CXXRecordDecl *ClassDecl); /// DefineImplicitDestructor - Checks for feasibility of /// defining this destructor as the default destructor. void DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor); /// Build an exception spec for destructors that don't have one. /// /// C++11 says that user-defined destructors with no exception spec get one /// that looks as if the destructor was implicitly declared. void AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor); /// Define the specified inheriting constructor. void DefineInheritingConstructor(SourceLocation UseLoc, CXXConstructorDecl *Constructor); /// Declare the implicit copy constructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// copy constructor will be added. /// /// \returns The implicitly-declared copy constructor. CXXConstructorDecl *DeclareImplicitCopyConstructor(CXXRecordDecl *ClassDecl); /// DefineImplicitCopyConstructor - Checks for feasibility of /// defining this constructor as the copy constructor. void DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// Declare the implicit move constructor for the given class. /// /// \param ClassDecl The Class declaration into which the implicit /// move constructor will be added. /// /// \returns The implicitly-declared move constructor, or NULL if it wasn't /// declared. CXXConstructorDecl *DeclareImplicitMoveConstructor(CXXRecordDecl *ClassDecl); /// DefineImplicitMoveConstructor - Checks for feasibility of /// defining this constructor as the move constructor. void DefineImplicitMoveConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// Declare the implicit copy assignment operator for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// copy assignment operator will be added. /// /// \returns The implicitly-declared copy assignment operator. CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl); /// Defines an implicitly-declared copy assignment operator. void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); /// Declare the implicit move assignment operator for the given class. /// /// \param ClassDecl The Class declaration into which the implicit /// move assignment operator will be added. /// /// \returns The implicitly-declared move assignment operator, or NULL if it /// wasn't declared. CXXMethodDecl *DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl); /// Defines an implicitly-declared move assignment operator. void DefineImplicitMoveAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); /// Force the declaration of any implicitly-declared members of this /// class. void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class); /// Check a completed declaration of an implicit special member. void CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD); /// Determine whether the given function is an implicitly-deleted /// special member function. bool isImplicitlyDeleted(FunctionDecl *FD); /// Check whether 'this' shows up in the type of a static member /// function after the (naturally empty) cv-qualifier-seq would be. /// /// \returns true if an error occurred. bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method); /// Whether this' shows up in the exception specification of a static /// member function. bool checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method); /// Check whether 'this' shows up in the attributes of the given /// static member function. /// /// \returns true if an error occurred. bool checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method); /// MaybeBindToTemporary - If the passed in expression has a record type with /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise /// it simply returns the passed in expression. ExprResult MaybeBindToTemporary(Expr *E); /// Wrap the expression in a ConstantExpr if it is a potential immediate /// invocation. ExprResult CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl); bool CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, SourceLocation Loc, SmallVectorImpl &ConvertedArgs, bool AllowExplicit = false, bool IsListInitialization = false); ParsedType getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, IdentifierInfo &Name); ParsedType getConstructorName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, bool EnteringContext); ParsedType getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext); ParsedType getDestructorTypeForDecltype(const DeclSpec &DS, ParsedType ObjectType); // Checks that reinterpret casts don't have undefined behavior. void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, bool IsDereference, SourceRange Range); /// ActOnCXXNamedCast - Parse /// {dynamic,static,reinterpret,const,addrspace}_cast's. ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, Declarator &D, SourceLocation RAngleBracketLoc, SourceLocation LParenLoc, Expr *E, SourceLocation RParenLoc); ExprResult BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, TypeSourceInfo *Ty, Expr *E, SourceRange AngleBrackets, SourceRange Parens); ExprResult ActOnBuiltinBitCastExpr(SourceLocation KWLoc, Declarator &Dcl, ExprResult Operand, SourceLocation RParenLoc); ExprResult BuildBuiltinBitCastExpr(SourceLocation KWLoc, TypeSourceInfo *TSI, Expr *Operand, SourceLocation RParenLoc); ExprResult BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc); ExprResult BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *Operand, SourceLocation RParenLoc); /// ActOnCXXTypeid - Parse typeid( something ). ExprResult ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc); ExprResult BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc); ExprResult BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *Operand, SourceLocation RParenLoc); /// ActOnCXXUuidof - Parse __uuidof( something ). ExprResult ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc); /// Handle a C++1z fold-expression: ( expr op ... op expr ). ExprResult ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, tok::TokenKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc); ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc, Optional NumExpansions); ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, BinaryOperatorKind Operator); //// ActOnCXXThis - Parse 'this' pointer. ExprResult ActOnCXXThis(SourceLocation loc); /// Build a CXXThisExpr and mark it referenced in the current context. Expr *BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit); void MarkThisReferenced(CXXThisExpr *This); /// Try to retrieve the type of the 'this' pointer. /// /// \returns The type of 'this', if possible. Otherwise, returns a NULL type. QualType getCurrentThisType(); /// When non-NULL, the C++ 'this' expression is allowed despite the /// current context not being a non-static member function. In such cases, /// this provides the type used for 'this'. QualType CXXThisTypeOverride; /// RAII object used to temporarily allow the C++ 'this' expression /// to be used, with the given qualifiers on the current class type. class CXXThisScopeRAII { Sema &S; QualType OldCXXThisTypeOverride; bool Enabled; public: /// Introduce a new scope where 'this' may be allowed (when enabled), /// using the given declaration (which is either a class template or a /// class) along with the given qualifiers. /// along with the qualifiers placed on '*this'. CXXThisScopeRAII(Sema &S, Decl *ContextDecl, Qualifiers CXXThisTypeQuals, bool Enabled = true); ~CXXThisScopeRAII(); }; /// Make sure the value of 'this' is actually available in the current /// context, if it is a potentially evaluated context. /// /// \param Loc The location at which the capture of 'this' occurs. /// /// \param Explicit Whether 'this' is explicitly captured in a lambda /// capture list. /// /// \param FunctionScopeIndexToStopAt If non-null, it points to the index /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. /// This is useful when enclosing lambdas must speculatively capture /// 'this' that may or may not be used in certain specializations of /// a nested generic lambda (depending on whether the name resolves to /// a non-static member function or a static function). /// \return returns 'true' if failed, 'false' if success. bool CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false, bool BuildAndDiagnose = true, const unsigned *const FunctionScopeIndexToStopAt = nullptr, bool ByCopy = false); /// Determine whether the given type is the type of *this that is used /// outside of the body of a member function for a type that is currently /// being defined. bool isThisOutsideMemberFunctionBody(QualType BaseType); /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); /// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals. ExprResult ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); ExprResult ActOnObjCAvailabilityCheckExpr(llvm::ArrayRef AvailSpecs, SourceLocation AtLoc, SourceLocation RParen); /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. ExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc); //// ActOnCXXThrow - Parse throw expressions. ExprResult ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *expr); ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope); bool CheckCXXThrowOperand(SourceLocation ThrowLoc, QualType ThrowTy, Expr *E); /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). ExprResult ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenOrBraceLoc, MultiExprArg Exprs, SourceLocation RParenOrBraceLoc, bool ListInitialization); ExprResult BuildCXXTypeConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, MultiExprArg Exprs, SourceLocation RParenLoc, bool ListInitialization); /// ActOnCXXNew - Parsed a C++ 'new' expression. ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer); ExprResult BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, TypeSourceInfo *AllocTypeInfo, Optional ArraySize, SourceRange DirectInitRange, Expr *Initializer); /// Determine whether \p FD is an aligned allocation or deallocation /// function that is unavailable. bool isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const; /// Produce diagnostics if \p FD is an aligned allocation or deallocation /// function that is unavailable. void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD, SourceLocation Loc); bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R); /// The scope in which to find allocation functions. enum AllocationFunctionScope { /// Only look for allocation functions in the global scope. AFS_Global, /// Only look for allocation functions in the scope of the /// allocated class. AFS_Class, /// Look for allocation functions in both the global scope /// and in the scope of the allocated class. AFS_Both }; /// Finds the overloads of operator new and delete that are appropriate /// for the allocation. bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, AllocationFunctionScope NewScope, AllocationFunctionScope DeleteScope, QualType AllocType, bool IsArray, bool &PassAlignment, MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, FunctionDecl *&OperatorDelete, bool Diagnose = true); void DeclareGlobalNewDelete(); void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, ArrayRef Params); bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl* &Operator, bool Diagnose = true); FunctionDecl *FindUsualDeallocationFunction(SourceLocation StartLoc, bool CanProvideSize, bool Overaligned, DeclarationName Name); FunctionDecl *FindDeallocationFunctionForDestructor(SourceLocation StartLoc, CXXRecordDecl *RD); /// ActOnCXXDelete - Parsed a C++ 'delete' expression ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, Expr *Operand); void CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, SourceLocation DtorLoc); ExprResult ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation LParen, Expr *Operand, SourceLocation RParen); ExprResult BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen); /// Parsed one of the type trait support pseudo-functions. ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc); ExprResult BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc); /// ActOnArrayTypeTrait - Parsed one of the binary type trait support /// pseudo-functions. ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, ParsedType LhsTy, Expr *DimExpr, SourceLocation RParen); ExprResult BuildArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, TypeSourceInfo *TSInfo, Expr *DimExpr, SourceLocation RParen); /// ActOnExpressionTrait - Parsed one of the unary type trait support /// pseudo-functions. ExprResult ActOnExpressionTrait(ExpressionTrait OET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen); ExprResult BuildExpressionTrait(ExpressionTrait OET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen); ExprResult ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, ParsedType &ObjectType, bool &MayBePseudoDestructor); ExprResult BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, TypeSourceInfo *ScopeType, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType); ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, UnqualifiedId &SecondTypeName); ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation TildeLoc, const DeclSpec& DS); /// MaybeCreateExprWithCleanups - If the current full-expression /// requires any cleanups, surround it with a ExprWithCleanups node. /// Otherwise, just returns the passed-in expression. Expr *MaybeCreateExprWithCleanups(Expr *SubExpr); Stmt *MaybeCreateStmtWithCleanups(Stmt *SubStmt); ExprResult MaybeCreateExprWithCleanups(ExprResult SubExpr); MaterializeTemporaryExpr * CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary, bool BoundToLvalueReference); ExprResult ActOnFinishFullExpr(Expr *Expr, bool DiscardedValue) { return ActOnFinishFullExpr( Expr, Expr ? Expr->getExprLoc() : SourceLocation(), DiscardedValue); } ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC, bool DiscardedValue, bool IsConstexpr = false); StmtResult ActOnFinishFullStmt(Stmt *Stmt); // Marks SS invalid if it represents an incomplete type. bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); DeclContext *computeDeclContext(QualType T); DeclContext *computeDeclContext(const CXXScopeSpec &SS, bool EnteringContext = false); bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); /// The parser has parsed a global nested-name-specifier '::'. /// /// \param CCLoc The location of the '::'. /// /// \param SS The nested-name-specifier, which will be updated in-place /// to reflect the parsed nested-name-specifier. /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS); /// The parser has parsed a '__super' nested-name-specifier. /// /// \param SuperLoc The location of the '__super' keyword. /// /// \param ColonColonLoc The location of the '::'. /// /// \param SS The nested-name-specifier, which will be updated in-place /// to reflect the parsed nested-name-specifier. /// /// \returns true if an error occurred, false otherwise. bool ActOnSuperScopeSpecifier(SourceLocation SuperLoc, SourceLocation ColonColonLoc, CXXScopeSpec &SS); bool isAcceptableNestedNameSpecifier(const NamedDecl *SD, bool *CanCorrect = nullptr); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); /// Keeps information about an identifier in a nested-name-spec. /// struct NestedNameSpecInfo { /// The type of the object, if we're parsing nested-name-specifier in /// a member access expression. ParsedType ObjectType; /// The identifier preceding the '::'. IdentifierInfo *Identifier; /// The location of the identifier. SourceLocation IdentifierLoc; /// The location of the '::'. SourceLocation CCLoc; /// Creates info object for the most typical case. NestedNameSpecInfo(IdentifierInfo *II, SourceLocation IdLoc, SourceLocation ColonColonLoc, ParsedType ObjectType = ParsedType()) : ObjectType(ObjectType), Identifier(II), IdentifierLoc(IdLoc), CCLoc(ColonColonLoc) { } NestedNameSpecInfo(IdentifierInfo *II, SourceLocation IdLoc, SourceLocation ColonColonLoc, QualType ObjectType) : ObjectType(ParsedType::make(ObjectType)), Identifier(II), IdentifierLoc(IdLoc), CCLoc(ColonColonLoc) { } }; bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, NestedNameSpecInfo &IdInfo); bool BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, bool *IsCorrectedToColon = nullptr, bool OnlyNamespace = false); /// The parser has parsed a nested-name-specifier 'identifier::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// /// \param IdInfo Parser information about an identifier in the /// nested-name-spec. /// /// \param EnteringContext Whether we're entering the context nominated by /// this nested-name-specifier. /// /// \param SS The nested-name-specifier, which is both an input /// parameter (the nested-name-specifier before this type) and an /// output parameter (containing the full nested-name-specifier, /// including this new type). /// /// \param ErrorRecoveryLookup If true, then this method is called to improve /// error recovery. In this case do not emit error message. /// /// \param IsCorrectedToColon If not null, suggestions to replace '::' -> ':' /// are allowed. The bool value pointed by this parameter is set to 'true' /// if the identifier is treated as if it was followed by ':', not '::'. /// /// \param OnlyNamespace If true, only considers namespaces in lookup. /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, bool ErrorRecoveryLookup = false, bool *IsCorrectedToColon = nullptr, bool OnlyNamespace = false); ExprResult ActOnDecltypeExpression(Expr *E); bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, const DeclSpec &DS, SourceLocation ColonColonLoc); bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, NestedNameSpecInfo &IdInfo, bool EnteringContext); /// The parser has parsed a nested-name-specifier /// 'template[opt] template-name < template-args >::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// /// \param SS The nested-name-specifier, which is both an input /// parameter (the nested-name-specifier before this type) and an /// output parameter (containing the full nested-name-specifier, /// including this new type). /// /// \param TemplateKWLoc the location of the 'template' keyword, if any. /// \param TemplateName the template name. /// \param TemplateNameLoc The location of the template name. /// \param LAngleLoc The location of the opening angle bracket ('<'). /// \param TemplateArgs The template arguments. /// \param RAngleLoc The location of the closing angle bracket ('>'). /// \param CCLoc The location of the '::'. /// /// \param EnteringContext Whether we're entering the context of the /// nested-name-specifier. /// /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy TemplateName, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, SourceLocation CCLoc, bool EnteringContext); /// Given a C++ nested-name-specifier, produce an annotation value /// that the parser can use later to reconstruct the given /// nested-name-specifier. /// /// \param SS A nested-name-specifier. /// /// \returns A pointer containing all of the information in the /// nested-name-specifier \p SS. void *SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS); /// Given an annotation pointer for a nested-name-specifier, restore /// the nested-name-specifier structure. /// /// \param Annotation The annotation pointer, produced by /// \c SaveNestedNameSpecifierAnnotation(). /// /// \param AnnotationRange The source range corresponding to the annotation. /// /// \param SS The nested-name-specifier that will be updated with the contents /// of the annotation pointer. void RestoreNestedNameSpecifierAnnotation(void *Annotation, SourceRange AnnotationRange, CXXScopeSpec &SS); bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS); /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. /// Used to indicate that names should revert to being looked up in the /// defining scope. void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an /// initializer for the declaration 'Dcl'. /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a /// static data member of class X, names should be looked up in the scope of /// class X. void ActOnCXXEnterDeclInitializer(Scope *S, Decl *Dcl); /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an /// initializer for the declaration 'Dcl'. void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); /// Create a new lambda closure type. CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info, bool KnownDependent, LambdaCaptureDefault CaptureDefault); /// Start the definition of a lambda expression. CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, SourceLocation EndLoc, ArrayRef Params, ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause); /// Number lambda for linkage purposes if necessary. void handleLambdaNumbering( CXXRecordDecl *Class, CXXMethodDecl *Method, Optional> Mangling = None); /// Endow the lambda scope info with the relevant properties. void buildLambdaScope(sema::LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, bool ExplicitParams, bool ExplicitResultType, bool Mutable); /// Perform initialization analysis of the init-capture and perform /// any implicit conversions such as an lvalue-to-rvalue conversion if /// not being used to initialize a reference. ParsedType actOnLambdaInitCaptureInitialization( SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, IdentifierInfo *Id, LambdaCaptureInitKind InitKind, Expr *&Init) { return ParsedType::make(buildLambdaInitCaptureInitialization( Loc, ByRef, EllipsisLoc, None, Id, InitKind != LambdaCaptureInitKind::CopyInit, Init)); } QualType buildLambdaInitCaptureInitialization( SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, Optional NumExpansions, IdentifierInfo *Id, bool DirectInit, Expr *&Init); /// Create a dummy variable within the declcontext of the lambda's /// call operator, for name lookup purposes for a lambda init capture. /// /// CodeGen handles emission of lambda captures, ignoring these dummy /// variables appropriately. VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc, QualType InitCaptureType, SourceLocation EllipsisLoc, IdentifierInfo *Id, unsigned InitStyle, Expr *Init); /// Add an init-capture to a lambda scope. void addInitCapture(sema::LambdaScopeInfo *LSI, VarDecl *Var); /// Note that we have finished the explicit captures for the /// given lambda. void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); /// \brief This is called after parsing the explicit template parameter list /// on a lambda (if it exists) in C++2a. void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc, ArrayRef TParams, SourceLocation RAngleLoc); /// Introduce the lambda parameters into scope. void addLambdaParameters( ArrayRef Captures, CXXMethodDecl *CallOperator, Scope *CurScope); /// Deduce a block or lambda's return type based on the return /// statements present in the body. void deduceClosureReturnType(sema::CapturingScopeInfo &CSI); /// ActOnStartOfLambdaDefinition - This is called just before we start /// parsing the body of a lambda; it analyzes the explicit captures and /// arguments, and sets up various data-structures for the body of the /// lambda. void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope); /// ActOnLambdaError - If there is an error parsing a lambda, this callback /// is invoked to pop the information about the lambda. void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, bool IsInstantiation = false); /// ActOnLambdaExpr - This is called when the body of a lambda expression /// was successfully completed. ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope); /// Does copying/destroying the captured variable have side effects? bool CaptureHasSideEffects(const sema::Capture &From); /// Diagnose if an explicit lambda capture is unused. Returns true if a /// diagnostic is emitted. bool DiagnoseUnusedLambdaCapture(SourceRange CaptureRange, const sema::Capture &From); /// Build a FieldDecl suitable to hold the given capture. FieldDecl *BuildCaptureField(RecordDecl *RD, const sema::Capture &Capture); /// Initialize the given capture with a suitable expression. ExprResult BuildCaptureInit(const sema::Capture &Capture, SourceLocation ImplicitCaptureLoc, bool IsOpenMPMapping = false); /// Complete a lambda-expression having processed and attached the /// lambda body. ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, sema::LambdaScopeInfo *LSI); /// Get the return type to use for a lambda's conversion function(s) to /// function pointer type, given the type of the call operator. QualType getLambdaConversionFunctionResultType(const FunctionProtoType *CallOpType); /// Define the "body" of the conversion from a lambda object to a /// function pointer. /// /// This routine doesn't actually define a sensible body; rather, it fills /// in the initialization expression needed to copy the lambda object into /// the block, and IR generation actually generates the real body of the /// block pointer conversion. void DefineImplicitLambdaToFunctionPointerConversion( SourceLocation CurrentLoc, CXXConversionDecl *Conv); /// Define the "body" of the conversion from a lambda object to a /// block pointer. /// /// This routine doesn't actually define a sensible body; rather, it fills /// in the initialization expression needed to copy the lambda object into /// the block, and IR generation actually generates the real body of the /// block pointer conversion. void DefineImplicitLambdaToBlockPointerConversion(SourceLocation CurrentLoc, CXXConversionDecl *Conv); ExprResult BuildBlockForLambdaConversion(SourceLocation CurrentLocation, SourceLocation ConvLocation, CXXConversionDecl *Conv, Expr *Src); /// Check whether the given expression is a valid constraint expression. /// A diagnostic is emitted if it is not, false is returned, and /// PossibleNonPrimary will be set to true if the failure might be due to a /// non-primary expression being used as an atomic constraint. bool CheckConstraintExpression(const Expr *CE, Token NextToken = Token(), bool *PossibleNonPrimary = nullptr, bool IsTrailingRequiresClause = false); private: /// Caches pairs of template-like decls whose associated constraints were /// checked for subsumption and whether or not the first's constraints did in /// fact subsume the second's. llvm::DenseMap, bool> SubsumptionCache; /// Caches the normalized associated constraints of declarations (concepts or /// constrained declarations). If an error occurred while normalizing the /// associated constraints of the template or concept, nullptr will be cached /// here. llvm::DenseMap NormalizationCache; llvm::ContextualFoldingSet SatisfactionCache; public: const NormalizedConstraint * getNormalizedAssociatedConstraints( NamedDecl *ConstrainedDecl, ArrayRef AssociatedConstraints); /// \brief Check whether the given declaration's associated constraints are /// at least as constrained than another declaration's according to the /// partial ordering of constraints. /// /// \param Result If no error occurred, receives the result of true if D1 is /// at least constrained than D2, and false otherwise. /// /// \returns true if an error occurred, false otherwise. bool IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef AC1, NamedDecl *D2, ArrayRef AC2, bool &Result); /// If D1 was not at least as constrained as D2, but would've been if a pair /// of atomic constraints involved had been declared in a concept and not /// repeated in two separate places in code. /// \returns true if such a diagnostic was emitted, false otherwise. bool MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, ArrayRef AC1, NamedDecl *D2, ArrayRef AC2); /// \brief Check whether the given list of constraint expressions are /// satisfied (as if in a 'conjunction') given template arguments. /// \param Template the template-like entity that triggered the constraints /// check (either a concept or a constrained entity). /// \param ConstraintExprs a list of constraint expressions, treated as if /// they were 'AND'ed together. /// \param TemplateArgs the list of template arguments to substitute into the /// constraint expression. /// \param TemplateIDRange The source range of the template id that /// caused the constraints check. /// \param Satisfaction if true is returned, will contain details of the /// satisfaction, with enough information to diagnose an unsatisfied /// expression. /// \returns true if an error occurred and satisfaction could not be checked, /// false otherwise. bool CheckConstraintSatisfaction( const NamedDecl *Template, ArrayRef ConstraintExprs, ArrayRef TemplateArgs, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction); /// \brief Check whether the given non-dependent constraint expression is /// satisfied. Returns false and updates Satisfaction with the satisfaction /// verdict if successful, emits a diagnostic and returns true if an error /// occured and satisfaction could not be determined. /// /// \returns true if an error occurred, false otherwise. bool CheckConstraintSatisfaction(const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction); /// Check whether the given function decl's trailing requires clause is /// satisfied, if any. Returns false and updates Satisfaction with the /// satisfaction verdict if successful, emits a diagnostic and returns true if /// an error occured and satisfaction could not be determined. /// /// \returns true if an error occurred, false otherwise. bool CheckFunctionConstraints(const FunctionDecl *FD, ConstraintSatisfaction &Satisfaction, SourceLocation UsageLoc = SourceLocation()); /// \brief Ensure that the given template arguments satisfy the constraints /// associated with the given template, emitting a diagnostic if they do not. /// /// \param Template The template to which the template arguments are being /// provided. /// /// \param TemplateArgs The converted, canonicalized template arguments. /// /// \param TemplateIDRange The source range of the template id that /// caused the constraints check. /// /// \returns true if the constrains are not satisfied or could not be checked /// for satisfaction, false if the constraints are satisfied. bool EnsureTemplateArgumentListConstraints(TemplateDecl *Template, ArrayRef TemplateArgs, SourceRange TemplateIDRange); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied. /// \param First whether this is the first time an unsatisfied constraint is /// diagnosed for this error. void DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction &Satisfaction, bool First = true); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied. void DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction &Satisfaction, bool First = true); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied because it was ill-formed. void DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation DiagnosticLocation, StringRef Diagnostic); void DiagnoseRedeclarationConstraintMismatch(SourceLocation Old, SourceLocation New); // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef Strings); ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S); /// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the /// numeric literal expression. Type of the expression will be "NSNumber *" /// or "id" if NSNumber is unavailable. ExprResult BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number); ExprResult ActOnObjCBoolLiteral(SourceLocation AtLoc, SourceLocation ValueLoc, bool Value); ExprResult BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements); /// BuildObjCBoxedExpr - builds an ObjCBoxedExpr AST node for the /// '@' prefixed parenthesized expression. The type of the expression will /// either be "NSNumber *", "NSString *" or "NSValue *" depending on the type /// of ValueType, which is allowed to be a built-in numeric type, "char *", /// "const char *" or C structure with attribute 'objc_boxable'. ExprResult BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr); ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, Expr *IndexExpr, ObjCMethodDecl *getterMethod, ObjCMethodDecl *setterMethod); ExprResult BuildObjCDictionaryLiteral(SourceRange SR, MutableArrayRef Elements); ExprResult BuildObjCEncodeExpression(SourceLocation AtLoc, TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc); ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, CXXConversionDecl *Method, bool HadMultipleCandidates); ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation EncodeLoc, SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc); /// ParseObjCSelectorExpression - Build selector expression for \@selector ExprResult ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc, SourceLocation SelLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, bool WarnMultipleSelectors); /// ParseObjCProtocolExpression - Build protocol expression for \@protocol ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, SourceLocation AtLoc, SourceLocation ProtoLoc, SourceLocation LParenLoc, SourceLocation ProtoIdLoc, SourceLocation RParenLoc); //===--------------------------------------------------------------------===// // C++ Declarations // Decl *ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, Expr *LangStr, SourceLocation LBraceLoc); Decl *ActOnFinishLinkageSpecification(Scope *S, Decl *LinkageSpec, SourceLocation RBraceLoc); //===--------------------------------------------------------------------===// // C++ Classes // CXXRecordDecl *getCurrentClass(Scope *S, const CXXScopeSpec *SS); bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS = nullptr); bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS); bool ActOnAccessSpecifier(AccessSpecifier Access, SourceLocation ASLoc, SourceLocation ColonLoc, const ParsedAttributesView &Attrs); NamedDecl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, Expr *BitfieldWidth, const VirtSpecifiers &VS, InClassInitStyle InitStyle); void ActOnStartCXXInClassMemberInitializer(); void ActOnFinishCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc, Expr *Init); MemInitResult ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, SourceLocation LParenLoc, ArrayRef Args, SourceLocation RParenLoc, SourceLocation EllipsisLoc); MemInitResult ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, Expr *InitList, SourceLocation EllipsisLoc); MemInitResult BuildMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, Expr *Init, SourceLocation EllipsisLoc); MemInitResult BuildMemberInitializer(ValueDecl *Member, Expr *Init, SourceLocation IdLoc); MemInitResult BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Expr *Init, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc); MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, CXXRecordDecl *ClassDecl); bool SetDelegatingInitializer(CXXConstructorDecl *Constructor, CXXCtorInitializer *Initializer); bool SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, ArrayRef Initializers = None); void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, /// mark all the non-trivial destructors of its members and bases as /// referenced. void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, CXXRecordDecl *Record); /// Mark destructors of virtual bases of this class referenced. In the Itanium /// C++ ABI, this is done when emitting a destructor for any non-abstract /// class. In the Microsoft C++ ABI, this is done any time a class's /// destructor is referenced. void MarkVirtualBaseDestructorsReferenced( SourceLocation Location, CXXRecordDecl *ClassDecl, llvm::SmallPtrSetImpl *DirectVirtualBases = nullptr); /// Do semantic checks to allow the complete destructor variant to be emitted /// when the destructor is defined in another translation unit. In the Itanium /// C++ ABI, destructor variants are emitted together. In the MS C++ ABI, they /// can be emitted in separate TUs. To emit the complete variant, run a subset /// of the checks performed when emitting a regular destructor. void CheckCompleteDestructorVariant(SourceLocation CurrentLocation, CXXDestructorDecl *Dtor); /// The list of classes whose vtables have been used within /// this translation unit, and the source locations at which the /// first use occurred. typedef std::pair VTableUse; /// The list of vtables that are required but have not yet been /// materialized. SmallVector VTableUses; /// The set of classes whose vtables have been used within /// this translation unit, and a bit that will be true if the vtable is /// required to be emitted (otherwise, it should be emitted only if needed /// by code generation). llvm::DenseMap VTablesUsed; /// Load any externally-stored vtable uses. void LoadExternalVTableUses(); /// Note that the vtable for the given class was used at the /// given location. void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired = false); /// Mark the exception specifications of all virtual member functions /// in the given class as needed. void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, const CXXRecordDecl *RD); /// MarkVirtualMembersReferenced - Will mark all members of the given /// CXXRecordDecl referenced. void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD, bool ConstexprOnly = false); /// Define all of the vtables that have been used in this /// translation unit and reference any virtual members used by those /// vtables. /// /// \returns true if any work was done, false otherwise. bool DefineUsedVTables(); void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); void ActOnMemInitializers(Decl *ConstructorDecl, SourceLocation ColonLoc, ArrayRef MemInits, bool AnyErrors); /// Check class-level dllimport/dllexport attribute. The caller must /// ensure that referenceDLLExportedClassMethods is called some point later /// when all outer classes of Class are complete. void checkClassLevelDLLAttribute(CXXRecordDecl *Class); void checkClassLevelCodeSegAttribute(CXXRecordDecl *Class); void referenceDLLExportedClassMethods(); void propagateDLLAttrToBaseClassTemplate( CXXRecordDecl *Class, Attr *ClassAttr, ClassTemplateSpecializationDecl *BaseTemplateSpec, SourceLocation BaseLoc); /// Add gsl::Pointer attribute to std::container::iterator /// \param ND The declaration that introduces the name /// std::container::iterator. \param UnderlyingRecord The record named by ND. void inferGslPointerAttribute(NamedDecl *ND, CXXRecordDecl *UnderlyingRecord); /// Add [[gsl::Owner]] and [[gsl::Pointer]] attributes for std:: types. void inferGslOwnerPointerAttribute(CXXRecordDecl *Record); /// Add [[gsl::Pointer]] attributes for std:: types. void inferGslPointerAttribute(TypedefNameDecl *TD); void CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record); /// Check that the C++ class annoated with "trivial_abi" satisfies all the /// conditions that are needed for the attribute to have an effect. void checkIllFormedTrivialABIStruct(CXXRecordDecl &RD); void ActOnFinishCXXMemberSpecification(Scope *S, SourceLocation RLoc, Decl *TagDecl, SourceLocation LBrac, SourceLocation RBrac, const ParsedAttributesView &AttrList); void ActOnFinishCXXMemberDecls(); void ActOnFinishCXXNonNestedClass(); void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param); unsigned ActOnReenterTemplateScope(Decl *Template, llvm::function_ref EnterScope); void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record); void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param); void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record); void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnFinishDelayedMemberInitializers(Decl *Record); void MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, CachedTokens &Toks); void UnmarkAsLateParsedTemplate(FunctionDecl *FD); bool IsInsideALocalClassWithinATemplateFunction(); Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, Expr *AssertMessageExpr, SourceLocation RParenLoc); Decl *BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, StringLiteral *AssertMessageExpr, SourceLocation RParenLoc, bool Failed); FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart, SourceLocation FriendLoc, TypeSourceInfo *TSInfo); Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TemplateParams); NamedDecl *ActOnFriendFunctionDecl(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParams); QualType CheckConstructorDeclarator(Declarator &D, QualType R, StorageClass& SC); void CheckConstructor(CXXConstructorDecl *Constructor); QualType CheckDestructorDeclarator(Declarator &D, QualType R, StorageClass& SC); bool CheckDestructor(CXXDestructorDecl *Destructor); void CheckConversionDeclarator(Declarator &D, QualType &R, StorageClass& SC); Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion); void CheckDeductionGuideDeclarator(Declarator &D, QualType &R, StorageClass &SC); void CheckDeductionGuideTemplate(FunctionTemplateDecl *TD); void CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *MD); bool CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM); void CheckDelayedMemberExceptionSpecs(); bool CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *MD, DefaultedComparisonKind DCK); void DeclareImplicitEqualityComparison(CXXRecordDecl *RD, FunctionDecl *Spaceship); void DefineDefaultedComparison(SourceLocation Loc, FunctionDecl *FD, DefaultedComparisonKind DCK); //===--------------------------------------------------------------------===// // C++ Derived Classes // /// ActOnBaseSpecifier - Parsed a base specifier CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, TypeSourceInfo *TInfo, SourceLocation EllipsisLoc); BaseResult ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, ParsedAttributes &Attrs, bool Virtual, AccessSpecifier Access, ParsedType basetype, SourceLocation BaseLoc, SourceLocation EllipsisLoc); bool AttachBaseSpecifiers(CXXRecordDecl *Class, MutableArrayRef Bases); void ActOnBaseSpecifiers(Decl *ClassDecl, MutableArrayRef Bases); bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base); bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base, CXXBasePaths &Paths); // FIXME: I don't like this name. void BuildBasePathArray(const CXXBasePaths &Paths, CXXCastPath &BasePath); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, CXXCastPath *BasePath = nullptr, bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbiguousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, CXXCastPath *BasePath, bool IgnoreAccess = false); std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, const CXXMethodDecl *Old); /// CheckOverridingFunctionReturnType - Checks whether the return types are /// covariant, according to C++ [class.virtual]p5. bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, const CXXMethodDecl *Old); /// CheckOverridingFunctionExceptionSpec - Checks whether the exception /// spec is a subset of base spec. bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old); bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); /// CheckOverrideControl - Check C++11 override control semantics. void CheckOverrideControl(NamedDecl *D); /// DiagnoseAbsenceOfOverrideControl - Diagnose if 'override' keyword was /// not used in the declaration of an overriding method. void DiagnoseAbsenceOfOverrideControl(NamedDecl *D); /// CheckForFunctionMarkedFinal - Checks whether a virtual member function /// overrides a virtual member function marked 'final', according to /// C++11 [class.virtual]p4. bool CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, const CXXMethodDecl *Old); //===--------------------------------------------------------------------===// // C++ Access Control // enum AccessResult { AR_accessible, AR_inaccessible, AR_dependent, AR_delayed }; bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, NamedDecl *PrevMemberDecl, AccessSpecifier LexicalAS); AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, DeclAccessPair FoundDecl); AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, DeclAccessPair FoundDecl); AccessResult CheckAllocationAccess(SourceLocation OperatorLoc, SourceRange PlacementRange, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl, bool Diagnose = true); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, DeclAccessPair FoundDecl, const InitializedEntity &Entity, bool IsCopyBindingRefToTemp = false); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, DeclAccessPair FoundDecl, const InitializedEntity &Entity, const PartialDiagnostic &PDiag); AccessResult CheckDestructorAccess(SourceLocation Loc, CXXDestructorDecl *Dtor, const PartialDiagnostic &PDiag, QualType objectType = QualType()); AccessResult CheckFriendAccess(NamedDecl *D); AccessResult CheckMemberAccess(SourceLocation UseLoc, CXXRecordDecl *NamingClass, DeclAccessPair Found); AccessResult CheckStructuredBindingMemberAccess(SourceLocation UseLoc, CXXRecordDecl *DecomposedClass, DeclAccessPair Field); AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, Expr *ArgExpr, DeclAccessPair FoundDecl); AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, DeclAccessPair FoundDecl); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, QualType Base, QualType Derived, const CXXBasePath &Path, unsigned DiagID, bool ForceCheck = false, bool ForceUnprivileged = false); void CheckLookupAccess(const LookupResult &R); bool IsSimplyAccessible(NamedDecl *Decl, CXXRecordDecl *NamingClass, QualType BaseType); bool isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass, DeclAccessPair Found, QualType ObjectType, SourceLocation Loc, const PartialDiagnostic &Diag); bool isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass, DeclAccessPair Found, QualType ObjectType) { return isMemberAccessibleForDeletion(NamingClass, Found, ObjectType, SourceLocation(), PDiag()); } void HandleDependentAccessCheck(const DependentDiagnostic &DD, const MultiLevelTemplateArgumentList &TemplateArgs); void PerformDependentDiagnostics(const DeclContext *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); void HandleDelayedAccessCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); /// When true, access checking violations are treated as SFINAE /// failures rather than hard errors. bool AccessCheckingSFINAE; enum AbstractDiagSelID { AbstractNone = -1, AbstractReturnType, AbstractParamType, AbstractVariableType, AbstractFieldType, AbstractIvarType, AbstractSynthesizedIvarType, AbstractArrayType }; bool isAbstractType(SourceLocation Loc, QualType T); bool RequireNonAbstractType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); template bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireNonAbstractType(Loc, T, Diagnoser); } void DiagnoseAbstractType(const CXXRecordDecl *RD); //===--------------------------------------------------------------------===// // C++ Overloaded Operators [C++ 13.5] // bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // void FilterAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates = true, bool AllowDependent = true); bool hasAnyAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates = true, bool AllowDependent = true, bool AllowNonTemplateFunctions = false); /// Try to interpret the lookup result D as a template-name. /// /// \param D A declaration found by name lookup. /// \param AllowFunctionTemplates Whether function templates should be /// considered valid results. /// \param AllowDependent Whether unresolved using declarations (that might /// name templates) should be considered valid results. NamedDecl *getAsTemplateNameDecl(NamedDecl *D, bool AllowFunctionTemplates = true, bool AllowDependent = true); enum TemplateNameIsRequiredTag { TemplateNameIsRequired }; /// Whether and why a template name is required in this lookup. class RequiredTemplateKind { public: /// Template name is required if TemplateKWLoc is valid. RequiredTemplateKind(SourceLocation TemplateKWLoc = SourceLocation()) : TemplateKW(TemplateKWLoc) {} /// Template name is unconditionally required. RequiredTemplateKind(TemplateNameIsRequiredTag) : TemplateKW() {} SourceLocation getTemplateKeywordLoc() const { return TemplateKW.getValueOr(SourceLocation()); } bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } bool isRequired() const { return TemplateKW != SourceLocation(); } explicit operator bool() const { return isRequired(); } private: llvm::Optional TemplateKW; }; enum class AssumedTemplateKind { /// This is not assumed to be a template name. None, /// This is assumed to be a template name because lookup found nothing. FoundNothing, /// This is assumed to be a template name because lookup found one or more /// functions (but no function templates). FoundFunctions, }; bool LookupTemplateName( LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization, RequiredTemplateKind RequiredTemplate = SourceLocation(), AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true); TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool &MemberOfUnknownSpecialization, bool Disambiguation = false); /// Try to resolve an undeclared template name as a type template. /// /// Sets II to the identifier corresponding to the template name, and updates /// Name to a corresponding (typo-corrected) type template name and TNK to /// the corresponding kind, if possible. void ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &Name, TemplateNameKind &TNK, SourceLocation NameLoc, IdentifierInfo *&II); bool resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name, SourceLocation NameLoc, bool Diagnose = true); /// Determine whether a particular identifier might be the name in a C++1z /// deduction-guide declaration. bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name, SourceLocation NameLoc, ParsedTemplateTy *Template = nullptr); bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, TemplateTy &SuggestedTemplate, TemplateNameKind &SuggestedKind); bool DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, NamedDecl *Instantiation, bool InstantiatedFromMember, const NamedDecl *Pattern, const NamedDecl *PatternDef, TemplateSpecializationKind TSK, bool Complain = true); void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); NamedDecl *ActOnTypeParameter(Scope *S, bool Typename, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedType DefaultArg, bool HasTypeConstraint); bool ActOnTypeConstraint(const CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstraint, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); bool AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); bool AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI, SourceLocation Loc); QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); NamedDecl *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, unsigned Depth, unsigned Position, SourceLocation EqualLoc, Expr *DefaultArg); NamedDecl *ActOnTemplateTemplateParameter(Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params, SourceLocation EllipsisLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedTemplateArgument DefaultArg); TemplateParameterList * ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef Params, SourceLocation RAngleLoc, Expr *RequiresClause); /// The context in which we are checking a template parameter list. enum TemplateParamListContext { TPC_ClassTemplate, TPC_VarTemplate, TPC_FunctionTemplate, TPC_ClassTemplateMember, TPC_FriendClassTemplate, TPC_FriendFunctionTemplate, TPC_FriendFunctionTemplateDefinition, TPC_TypeAliasTemplate }; bool CheckTemplateParameterList(TemplateParameterList *NewParams, TemplateParameterList *OldParams, TemplateParamListContext TPC, SkipBodyInfo *SkipBody = nullptr); TemplateParameterList *MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef ParamLists, bool IsFriend, bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic = false); DeclResult CheckClassTemplate( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody = nullptr); TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, QualType NTTPType, SourceLocation Loc); /// Get a template argument mapping the given template parameter to itself, /// e.g. for X in \c template, this would return an expression template /// argument referencing X. TemplateArgumentLoc getIdentityTemplateArgumentLoc(NamedDecl *Param, SourceLocation Location); void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); ParsedTemplateArgument ActOnTemplateTypeArgument(TypeResult ParsedType); void NoteAllFoundTemplates(TemplateName Name); QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs); TypeResult ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy Template, IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, bool IsCtorOrDtorName = false, bool IsClassName = false); /// Parsed an elaborated-type-specifier that refers to a template-id, /// such as \c class T::template apply. TypeResult ActOnTagTemplateIdType(TagUseKind TUK, TypeSpecifierType TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy TemplateD, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc); DeclResult ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, bool IsPartialSpecialization); DeclResult CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation TemplateNameLoc, const TemplateArgumentListInfo &TemplateArgs); ExprResult CheckVarTemplateId(const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, VarTemplateDecl *Template, SourceLocation TemplateLoc, const TemplateArgumentListInfo *TemplateArgs); ExprResult CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs); void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc); ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, bool RequiresADL, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); TemplateNameKind ActOnTemplateName( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool AllowInjectedClassName = false); DeclResult ActOnClassTemplateSpecialization( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody = nullptr); bool CheckTemplatePartialSpecializationArgs(SourceLocation Loc, TemplateDecl *PrimaryTemplate, unsigned NumExplicitArgs, ArrayRef Args); void CheckTemplatePartialSpecialization( ClassTemplatePartialSpecializationDecl *Partial); void CheckTemplatePartialSpecialization( VarTemplatePartialSpecializationDecl *Partial); Decl *ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D); bool CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, TemplateSpecializationKind NewTSK, NamedDecl *PrevDecl, TemplateSpecializationKind PrevTSK, SourceLocation PrevPtOfInstantiation, bool &SuppressNew); bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, const TemplateArgumentListInfo &ExplicitTemplateArgs, LookupResult &Previous); bool CheckFunctionTemplateSpecialization( FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous, bool QualifiedFriend = false); bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); void CompleteMemberSpecialization(NamedDecl *Member, LookupResult &Previous); DeclResult ActOnExplicitInstantiation( Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, const ParsedAttributesView &Attr); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, Declarator &D); TemplateArgumentLoc SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, Decl *Param, SmallVectorImpl &Converted, bool &HasDefaultArg); /// Specifies the context in which a particular template /// argument is being checked. enum CheckTemplateArgumentKind { /// The template argument was specified in the code or was /// instantiated with some deduced template arguments. CTAK_Specified, /// The template argument was deduced via template argument /// deduction. CTAK_Deduced, /// The template argument was deduced from an array bound /// via template argument deduction. CTAK_DeducedFromArrayBound }; bool CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &Arg, NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, unsigned ArgumentPackIndex, SmallVectorImpl &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); /// Check that the given template arguments can be be provided to /// the given template, converting the arguments along the way. /// /// \param Template The template to which the template arguments are being /// provided. /// /// \param TemplateLoc The location of the template name in the source. /// /// \param TemplateArgs The list of template arguments. If the template is /// a template template parameter, this function may extend the set of /// template arguments to also include substituted, defaulted template /// arguments. /// /// \param PartialTemplateArgs True if the list of template arguments is /// intentionally partial, e.g., because we're checking just the initial /// set of template arguments. /// /// \param Converted Will receive the converted, canonicalized template /// arguments. /// /// \param UpdateArgsWithConversions If \c true, update \p TemplateArgs to /// contain the converted forms of the template arguments as written. /// Otherwise, \p TemplateArgs will not be modified. /// /// \param ConstraintsNotSatisfied If provided, and an error occured, will /// receive true if the cause for the error is the associated constraints of /// the template not being satisfied by the template arguments. /// /// \returns true if an error occurred, false otherwise. bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl &Converted, bool UpdateArgsWithConversions = true, bool *ConstraintsNotSatisfied = nullptr); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, SmallVectorImpl &Converted); bool CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *Arg); ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *Arg, TemplateArgument &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, TemplateParameterList *Params, TemplateArgumentLoc &Arg); ExprResult BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc); ExprResult BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc); /// Enumeration describing how template parameter lists are compared /// for equality. enum TemplateParameterListEqualKind { /// We are matching the template parameter lists of two templates /// that might be redeclarations. /// /// \code /// template struct X; /// template struct X; /// \endcode TPL_TemplateMatch, /// We are matching the template parameter lists of two template /// template parameters as part of matching the template parameter lists /// of two templates that might be redeclarations. /// /// \code /// template class TT> struct X; /// template class Other> struct X; /// \endcode TPL_TemplateTemplateParmMatch, /// We are matching the template parameter lists of a template /// template argument against the template parameter lists of a template /// template parameter. /// /// \code /// template class Metafun> struct X; /// template struct integer_c; /// X xic; /// \endcode TPL_TemplateTemplateArgumentMatch }; bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc = SourceLocation()); bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); /// Called when the parser has parsed a C++ typename /// specifier, e.g., "typename T::type". /// /// \param S The scope in which this typename type occurs. /// \param TypenameLoc the location of the 'typename' keyword /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). /// \param II the identifier we're retrieving (e.g., 'type' in the example). /// \param IdLoc the location of the identifier. TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc); /// Called when the parser has parsed a C++ typename /// specifier that ends in a template-id, e.g., /// "typename MetaFun::template apply". /// /// \param S The scope in which this typename type occurs. /// \param TypenameLoc the location of the 'typename' keyword /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). /// \param TemplateLoc the location of the 'template' keyword, if any. /// \param TemplateName The template name. /// \param TemplateII The identifier used to name the template. /// \param TemplateIILoc The location of the template name. /// \param LAngleLoc The location of the opening angle bracket ('<'). /// \param TemplateArgs The template arguments. /// \param RAngleLoc The location of the closing angle bracket ('>'). TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, SourceLocation TemplateLoc, TemplateTy TemplateName, IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc); QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, SourceLocation IILoc, TypeSourceInfo **TSI, bool DeducedTSTContext); QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, SourceLocation IILoc, bool DeducedTSTContext = true); TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, SourceLocation Loc, DeclarationName Name); bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); ExprResult RebuildExprInCurrentInstantiation(Expr *E); bool RebuildTemplateParamsInCurrentInstantiation( TemplateParameterList *Params); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgumentList &Args); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgument *Args, unsigned NumArgs); //===--------------------------------------------------------------------===// // C++ Concepts //===--------------------------------------------------------------------===// Decl *ActOnConceptDefinition( Scope *S, MultiTemplateParamsArg TemplateParameterLists, IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr); RequiresExprBodyDecl * ActOnStartRequiresExpr(SourceLocation RequiresKWLoc, ArrayRef LocalParameters, Scope *BodyScope); void ActOnFinishRequiresExpr(); concepts::Requirement *ActOnSimpleRequirement(Expr *E); concepts::Requirement *ActOnTypeRequirement( SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc, IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId); concepts::Requirement *ActOnCompoundRequirement(Expr *E, SourceLocation NoexceptLoc); concepts::Requirement * ActOnCompoundRequirement( Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstraint, unsigned Depth); concepts::Requirement *ActOnNestedRequirement(Expr *Constraint); concepts::ExprRequirement * BuildExprRequirement( Expr *E, bool IsSatisfied, SourceLocation NoexceptLoc, concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement); concepts::ExprRequirement * BuildExprRequirement( concepts::Requirement::SubstitutionDiagnostic *ExprSubstDiag, bool IsSatisfied, SourceLocation NoexceptLoc, concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement); concepts::TypeRequirement *BuildTypeRequirement(TypeSourceInfo *Type); concepts::TypeRequirement * BuildTypeRequirement( concepts::Requirement::SubstitutionDiagnostic *SubstDiag); concepts::NestedRequirement *BuildNestedRequirement(Expr *E); concepts::NestedRequirement * BuildNestedRequirement( concepts::Requirement::SubstitutionDiagnostic *SubstDiag); ExprResult ActOnRequiresExpr(SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, ArrayRef LocalParameters, ArrayRef Requirements, SourceLocation ClosingBraceLoc); //===--------------------------------------------------------------------===// // C++ Variadic Templates (C++0x [temp.variadic]) //===--------------------------------------------------------------------===// /// Determine whether an unexpanded parameter pack might be permitted in this /// location. Useful for error recovery. bool isUnexpandedParameterPackPermitted(); /// The context in which an unexpanded parameter pack is /// being diagnosed. /// /// Note that the values of this enumeration line up with the first /// argument to the \c err_unexpanded_parameter_pack diagnostic. enum UnexpandedParameterPackContext { /// An arbitrary expression. UPPC_Expression = 0, /// The base type of a class type. UPPC_BaseType, /// The type of an arbitrary declaration. UPPC_DeclarationType, /// The type of a data member. UPPC_DataMemberType, /// The size of a bit-field. UPPC_BitFieldWidth, /// The expression in a static assertion. UPPC_StaticAssertExpression, /// The fixed underlying type of an enumeration. UPPC_FixedUnderlyingType, /// The enumerator value. UPPC_EnumeratorValue, /// A using declaration. UPPC_UsingDeclaration, /// A friend declaration. UPPC_FriendDeclaration, /// A declaration qualifier. UPPC_DeclarationQualifier, /// An initializer. UPPC_Initializer, /// A default argument. UPPC_DefaultArgument, /// The type of a non-type template parameter. UPPC_NonTypeTemplateParameterType, /// The type of an exception. UPPC_ExceptionType, /// Partial specialization. UPPC_PartialSpecialization, /// Microsoft __if_exists. UPPC_IfExists, /// Microsoft __if_not_exists. UPPC_IfNotExists, /// Lambda expression. UPPC_Lambda, /// Block expression, UPPC_Block, /// A type constraint, UPPC_TypeConstraint }; /// Diagnose unexpanded parameter packs. /// /// \param Loc The location at which we should emit the diagnostic. /// /// \param UPPC The context in which we are diagnosing unexpanded /// parameter packs. /// /// \param Unexpanded the set of unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPacks(SourceLocation Loc, UnexpandedParameterPackContext UPPC, ArrayRef Unexpanded); /// If the given type contains an unexpanded parameter pack, /// diagnose the error. /// /// \param Loc The source location where a diagnostc should be emitted. /// /// \param T The type that is being checked for unexpanded parameter /// packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, UnexpandedParameterPackContext UPPC); /// If the given expression contains an unexpanded parameter /// pack, diagnose the error. /// /// \param E The expression that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(Expr *E, UnexpandedParameterPackContext UPPC = UPPC_Expression); /// If the given nested-name-specifier contains an unexpanded /// parameter pack, diagnose the error. /// /// \param SS The nested-name-specifier that is being checked for /// unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, UnexpandedParameterPackContext UPPC); /// If the given name contains an unexpanded parameter pack, /// diagnose the error. /// /// \param NameInfo The name (with source location information) that /// is being checked for unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, UnexpandedParameterPackContext UPPC); /// If the given template name contains an unexpanded parameter pack, /// diagnose the error. /// /// \param Loc The location of the template name. /// /// \param Template The template name that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TemplateName Template, UnexpandedParameterPackContext UPPC); /// If the given template argument contains an unexpanded parameter /// pack, diagnose the error. /// /// \param Arg The template argument that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, UnexpandedParameterPackContext UPPC); /// Collect the set of unexpanded parameter packs within the given /// template argument. /// /// \param Arg The template argument that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TemplateArgument Arg, SmallVectorImpl &Unexpanded); /// Collect the set of unexpanded parameter packs within the given /// template argument. /// /// \param Arg The template argument that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, SmallVectorImpl &Unexpanded); /// Collect the set of unexpanded parameter packs within the given /// type. /// /// \param T The type that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(QualType T, SmallVectorImpl &Unexpanded); /// Collect the set of unexpanded parameter packs within the given /// type. /// /// \param TL The type that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TypeLoc TL, SmallVectorImpl &Unexpanded); /// Collect the set of unexpanded parameter packs within the given /// nested-name-specifier. /// /// \param NNS The nested-name-specifier that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(NestedNameSpecifierLoc NNS, SmallVectorImpl &Unexpanded); /// Collect the set of unexpanded parameter packs within the given /// name. /// /// \param NameInfo The name that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, SmallVectorImpl &Unexpanded); /// Invoked when parsing a template argument followed by an /// ellipsis, which creates a pack expansion. /// /// \param Arg The template argument preceding the ellipsis, which /// may already be invalid. /// /// \param EllipsisLoc The location of the ellipsis. ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg, SourceLocation EllipsisLoc); /// Invoked when parsing a type followed by an ellipsis, which /// creates a pack expansion. /// /// \param Type The type preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); /// Construct a pack expansion type from the pattern of the pack /// expansion. TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc, Optional NumExpansions); /// Construct a pack expansion type from the pattern of the pack /// expansion. QualType CheckPackExpansion(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, Optional NumExpansions); /// Invoked when parsing an expression followed by an ellipsis, which /// creates a pack expansion. /// /// \param Pattern The expression preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. ExprResult ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc); /// Invoked when parsing an expression followed by an ellipsis, which /// creates a pack expansion. /// /// \param Pattern The expression preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. ExprResult CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, Optional NumExpansions); /// Determine whether we could expand a pack expansion with the /// given set of parameter packs into separate arguments by repeatedly /// transforming the pattern. /// /// \param EllipsisLoc The location of the ellipsis that identifies the /// pack expansion. /// /// \param PatternRange The source range that covers the entire pattern of /// the pack expansion. /// /// \param Unexpanded The set of unexpanded parameter packs within the /// pattern. /// /// \param ShouldExpand Will be set to \c true if the transformer should /// expand the corresponding pack expansions into separate arguments. When /// set, \c NumExpansions must also be set. /// /// \param RetainExpansion Whether the caller should add an unexpanded /// pack expansion after all of the expanded arguments. This is used /// when extending explicitly-specified template argument packs per /// C++0x [temp.arg.explicit]p9. /// /// \param NumExpansions The number of separate arguments that will be in /// the expanded form of the corresponding pack expansion. This is both an /// input and an output parameter, which can be set by the caller if the /// number of expansions is known a priori (e.g., due to a prior substitution) /// and will be set by the callee when the number of expansions is known. /// The callee must set this value when \c ShouldExpand is \c true; it may /// set this value in other cases. /// /// \returns true if an error occurred (e.g., because the parameter packs /// are to be instantiated with arguments of different lengths), false /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) /// must be set. bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand, bool &RetainExpansion, Optional &NumExpansions); /// Determine the number of arguments in the given pack expansion /// type. /// /// This routine assumes that the number of arguments in the expansion is /// consistent across all of the unexpanded parameter packs in its pattern. /// /// Returns an empty Optional if the type can't be expanded. Optional getNumArgumentsInExpansion(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs); /// Determine whether the given declarator contains any unexpanded /// parameter packs. /// /// This routine is used by the parser to disambiguate function declarators /// with an ellipsis prior to the ')', e.g., /// /// \code /// void f(T...); /// \endcode /// /// To determine whether we have an (unnamed) function parameter pack or /// a variadic function. /// /// \returns true if the declarator contains any unexpanded parameter packs, /// false otherwise. bool containsUnexpandedParameterPacks(Declarator &D); /// Returns the pattern of the pack expansion for a template argument. /// /// \param OrigLoc The template argument to expand. /// /// \param Ellipsis Will be set to the location of the ellipsis. /// /// \param NumExpansions Will be set to the number of expansions that will /// be generated from this pack expansion, if known a priori. TemplateArgumentLoc getTemplateArgumentPackExpansionPattern( TemplateArgumentLoc OrigLoc, SourceLocation &Ellipsis, Optional &NumExpansions) const; /// Given a template argument that contains an unexpanded parameter pack, but /// which has already been substituted, attempt to determine the number of /// elements that will be produced once this argument is fully-expanded. /// /// This is intended for use when transforming 'sizeof...(Arg)' in order to /// avoid actually expanding the pack where possible. Optional getFullyPackExpandedSize(TemplateArgument Arg); //===--------------------------------------------------------------------===// // C++ Template Argument Deduction (C++ [temp.deduct]) //===--------------------------------------------------------------------===// /// Adjust the type \p ArgFunctionType to match the calling convention, /// noreturn, and optionally the exception specification of \p FunctionType. /// Deduction often wants to ignore these properties when matching function /// types. QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType, bool AdjustExceptionSpec = false); /// Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of /// template argument deduction, as returned from /// DeduceTemplateArguments(). The separate TemplateDeductionInfo /// structure provides additional information about the results of /// template argument deduction, e.g., the deduced template argument /// list (if successful) or the specific template parameters or /// deduced arguments that were involved in the failure. enum TemplateDeductionResult { /// Template argument deduction was successful. TDK_Success = 0, /// The declaration was invalid; do nothing. TDK_Invalid, /// Template argument deduction exceeded the maximum template /// instantiation depth (which has already been diagnosed). TDK_InstantiationDepth, /// Template argument deduction did not deduce a value /// for every template parameter. TDK_Incomplete, /// Template argument deduction did not deduce a value for every /// expansion of an expanded template parameter pack. TDK_IncompletePack, /// Template argument deduction produced inconsistent /// deduced values for the given template parameter. TDK_Inconsistent, /// Template argument deduction failed due to inconsistent /// cv-qualifiers on a template parameter type that would /// otherwise be deduced, e.g., we tried to deduce T in "const T" /// but were given a non-const "X". TDK_Underqualified, /// Substitution of the deduced template argument values /// resulted in an error. TDK_SubstitutionFailure, /// After substituting deduced template arguments, a dependent /// parameter type did not match the corresponding argument. TDK_DeducedMismatch, /// After substituting deduced template arguments, an element of /// a dependent parameter type did not match the corresponding element /// of the corresponding argument (when deducing from an initializer list). TDK_DeducedMismatchNested, /// A non-depnedent component of the parameter did not match the /// corresponding component of the argument. TDK_NonDeducedMismatch, /// When performing template argument deduction for a function /// template, there were too many call arguments. TDK_TooManyArguments, /// When performing template argument deduction for a function /// template, there were too few call arguments. TDK_TooFewArguments, /// The explicitly-specified template arguments were not valid /// template arguments for the given template. TDK_InvalidExplicitArguments, /// Checking non-dependent argument conversions failed. TDK_NonDependentConversionFailure, /// The deduced arguments did not satisfy the constraints associated /// with the template. TDK_ConstraintsNotSatisfied, /// Deduction failed; that's all we know. TDK_MiscellaneousDeductionFailure, /// CUDA Target attributes do not match. TDK_CUDATargetMismatch }; TemplateDeductionResult DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, sema::TemplateDeductionInfo &Info); TemplateDeductionResult SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo &ExplicitTemplateArgs, SmallVectorImpl &Deduced, SmallVectorImpl &ParamTypes, QualType *FunctionType, sema::TemplateDeductionInfo &Info); /// brief A function argument from which we performed template argument // deduction for a call. struct OriginalCallArg { OriginalCallArg(QualType OriginalParamType, bool DecomposedParam, unsigned ArgIdx, QualType OriginalArgType) : OriginalParamType(OriginalParamType), DecomposedParam(DecomposedParam), ArgIdx(ArgIdx), OriginalArgType(OriginalArgType) {} QualType OriginalParamType; bool DecomposedParam; unsigned ArgIdx; QualType OriginalArgType; }; TemplateDeductionResult FinishTemplateArgumentDeduction( FunctionTemplateDecl *FunctionTemplate, SmallVectorImpl &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, SmallVectorImpl const *OriginalCallArgs = nullptr, bool PartialOverloading = false, llvm::function_ref CheckNonDependent = []{ return false; }); TemplateDeductionResult DeduceTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool PartialOverloading, llvm::function_ref)> CheckNonDependent); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool IsAddressOfFunction = false); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType ToType, CXXConversionDecl *&Specialization, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool IsAddressOfFunction = false); /// Substitute Replacement for \p auto in \p TypeWithAuto QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement); /// Substitute Replacement for auto in TypeWithAuto TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType Replacement); /// Completely replace the \c auto in \p TypeWithAuto by /// \p Replacement. This does not retain any \c auto type sugar. QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement); /// Result type of DeduceAutoType. enum DeduceAutoResult { DAR_Succeeded, DAR_Failed, DAR_FailedAlreadyDiagnosed }; DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result, Optional DependentDeductionDepth = None, bool IgnoreConstraints = false); DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result, Optional DependentDeductionDepth = None, bool IgnoreConstraints = false); void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, bool Diagnose = true); /// Declare implicit deduction guides for a class template if we've /// not already done so. void DeclareImplicitDeductionGuides(TemplateDecl *Template, SourceLocation Loc); QualType DeduceTemplateSpecializationFromInitializer( TypeSourceInfo *TInfo, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Init); QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, QualType Type, TypeSourceInfo *TSI, SourceRange Range, bool DirectInit, Expr *Init); TypeLoc getReturnTypeLoc(FunctionDecl *FD) const; bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, SourceLocation ReturnLoc, Expr *&RetExpr, AutoType *AT); FunctionTemplateDecl *getMoreSpecializedTemplate( FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2, bool Reversed = false); UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplateSpecCandidateSet &FailedCandidates, SourceLocation Loc, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &CandidateDiag, bool Complain = true, QualType TargetType = QualType()); ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( ClassTemplatePartialSpecializationDecl *PS1, ClassTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); bool isMoreSpecializedThanPrimary(ClassTemplatePartialSpecializationDecl *T, sema::TemplateDeductionInfo &Info); VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpecialization( VarTemplatePartialSpecializationDecl *PS1, VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); bool isMoreSpecializedThanPrimary(VarTemplatePartialSpecializationDecl *T, sema::TemplateDeductionInfo &Info); bool isTemplateTemplateParameterAtLeastAsSpecializedAs( TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc); void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used); void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used); void MarkDeducedTemplateParameters( const FunctionTemplateDecl *FunctionTemplate, llvm::SmallBitVector &Deduced) { return MarkDeducedTemplateParameters(Context, FunctionTemplate, Deduced); } static void MarkDeducedTemplateParameters(ASTContext &Ctx, const FunctionTemplateDecl *FunctionTemplate, llvm::SmallBitVector &Deduced); //===--------------------------------------------------------------------===// // C++ Template Instantiation // MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost = nullptr, bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr); /// A context in which code is being synthesized (where a source location /// alone is not sufficient to identify the context). This covers template /// instantiation and various forms of implicitly-generated functions. struct CodeSynthesisContext { /// The kind of template instantiation we are performing enum SynthesisKind { /// We are instantiating a template declaration. The entity is /// the declaration we're instantiating (e.g., a CXXRecordDecl). TemplateInstantiation, /// We are instantiating a default argument for a template /// parameter. The Entity is the template parameter whose argument is /// being instantiated, the Template is the template, and the /// TemplateArgs/NumTemplateArguments provide the template arguments as /// specified. DefaultTemplateArgumentInstantiation, /// We are instantiating a default argument for a function. /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs /// provides the template arguments as specified. DefaultFunctionArgumentInstantiation, /// We are substituting explicit template arguments provided for /// a function template. The entity is a FunctionTemplateDecl. ExplicitTemplateArgumentSubstitution, /// We are substituting template argument determined as part of /// template argument deduction for either a class template /// partial specialization or a function template. The /// Entity is either a {Class|Var}TemplatePartialSpecializationDecl or /// a TemplateDecl. DeducedTemplateArgumentSubstitution, /// We are substituting prior template arguments into a new /// template parameter. The template parameter itself is either a /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. PriorTemplateArgumentSubstitution, /// We are checking the validity of a default template argument that /// has been used when naming a template-id. DefaultTemplateArgumentChecking, /// We are computing the exception specification for a defaulted special /// member function. ExceptionSpecEvaluation, /// We are instantiating the exception specification for a function /// template which was deferred until it was needed. ExceptionSpecInstantiation, /// We are instantiating a requirement of a requires expression. RequirementInstantiation, /// We are checking the satisfaction of a nested requirement of a requires /// expression. NestedRequirementConstraintsCheck, /// We are declaring an implicit special member function. DeclaringSpecialMember, /// We are declaring an implicit 'operator==' for a defaulted /// 'operator<=>'. DeclaringImplicitEqualityComparison, /// We are defining a synthesized function (such as a defaulted special /// member). DefiningSynthesizedFunction, // We are checking the constraints associated with a constrained entity or // the constraint expression of a concept. This includes the checks that // atomic constraints have the type 'bool' and that they can be constant // evaluated. ConstraintsCheck, // We are substituting template arguments into a constraint expression. ConstraintSubstitution, // We are normalizing a constraint expression. ConstraintNormalization, // We are substituting into the parameter mapping of an atomic constraint // during normalization. ParameterMappingSubstitution, /// We are rewriting a comparison operator in terms of an operator<=>. RewritingOperatorAsSpaceship, /// We are initializing a structured binding. InitializingStructuredBinding, /// We are marking a class as __dllexport. MarkingClassDllexported, /// Added for Template instantiation observation. /// Memoization means we are _not_ instantiating a template because /// it is already instantiated (but we entered a context where we /// would have had to if it was not already instantiated). Memoization } Kind; /// Was the enclosing context a non-instantiation SFINAE context? bool SavedInNonInstantiationSFINAEContext; /// The point of instantiation or synthesis within the source code. SourceLocation PointOfInstantiation; /// The entity that is being synthesized. Decl *Entity; /// The template (or partial specialization) in which we are /// performing the instantiation, for substitutions of prior template /// arguments. NamedDecl *Template; /// The list of template arguments we are substituting, if they /// are not part of the entity. const TemplateArgument *TemplateArgs; // FIXME: Wrap this union around more members, or perhaps store the // kind-specific members in the RAII object owning the context. union { /// The number of template arguments in TemplateArgs. unsigned NumTemplateArgs; /// The special member being declared or defined. CXXSpecialMember SpecialMember; }; ArrayRef template_arguments() const { assert(Kind != DeclaringSpecialMember); return {TemplateArgs, NumTemplateArgs}; } /// The template deduction info object associated with the /// substitution or checking of explicit or deduced template arguments. sema::TemplateDeductionInfo *DeductionInfo; /// The source range that covers the construct that cause /// the instantiation, e.g., the template-id that causes a class /// template instantiation. SourceRange InstantiationRange; CodeSynthesisContext() : Kind(TemplateInstantiation), SavedInNonInstantiationSFINAEContext(false), Entity(nullptr), Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0), DeductionInfo(nullptr) {} /// Determines whether this template is an actual instantiation /// that should be counted toward the maximum instantiation depth. bool isInstantiationRecord() const; }; /// List of active code synthesis contexts. /// /// This vector is treated as a stack. As synthesis of one entity requires /// synthesis of another, additional contexts are pushed onto the stack. SmallVector CodeSynthesisContexts; /// Specializations whose definitions are currently being instantiated. llvm::DenseSet> InstantiatingSpecializations; /// Non-dependent types used in templates that have already been instantiated /// by some template instantiation. llvm::DenseSet InstantiatedNonDependentTypes; /// Extra modules inspected when performing a lookup during a template /// instantiation. Computed lazily. SmallVector CodeSynthesisContextLookupModules; /// Cache of additional modules that should be used for name lookup /// within the current template instantiation. Computed lazily; use /// getLookupModules() to get a complete set. llvm::DenseSet LookupModulesCache; /// Get the set of additional modules that should be checked during /// name lookup. A module and its imports become visible when instanting a /// template defined within it. llvm::DenseSet &getLookupModules(); /// Map from the most recent declaration of a namespace to the most /// recent visible declaration of that namespace. llvm::DenseMap VisibleNamespaceCache; /// Whether we are in a SFINAE context that is not associated with /// template instantiation. /// /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside /// of a template instantiation or template argument deduction. bool InNonInstantiationSFINAEContext; /// The number of \p CodeSynthesisContexts that are not template /// instantiations and, therefore, should not be counted as part of the /// instantiation depth. /// /// When the instantiation depth reaches the user-configurable limit /// \p LangOptions::InstantiationDepth we will abort instantiation. // FIXME: Should we have a similar limit for other forms of synthesis? unsigned NonInstantiationEntries; /// The depth of the context stack at the point when the most recent /// error or warning was produced. /// /// This value is used to suppress printing of redundant context stacks /// when there are multiple errors or warnings in the same instantiation. // FIXME: Does this belong in Sema? It's tough to implement it anywhere else. unsigned LastEmittedCodeSynthesisContextDepth = 0; /// The template instantiation callbacks to trace or track /// instantiations (objects can be chained). /// /// This callbacks is used to print, trace or track template /// instantiations as they are being constructed. std::vector> TemplateInstCallbacks; /// The current index into pack expansion arguments that will be /// used for substitution of parameter packs. /// /// The pack expansion index will be -1 to indicate that parameter packs /// should be instantiated as themselves. Otherwise, the index specifies /// which argument within the parameter pack will be used for substitution. int ArgumentPackSubstitutionIndex; /// RAII object used to change the argument pack substitution index /// within a \c Sema object. /// /// See \c ArgumentPackSubstitutionIndex for more information. class ArgumentPackSubstitutionIndexRAII { Sema &Self; int OldSubstitutionIndex; public: ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex) : Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) { Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex; } ~ArgumentPackSubstitutionIndexRAII() { Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex; } }; friend class ArgumentPackSubstitutionRAII; /// For each declaration that involved template argument deduction, the /// set of diagnostics that were suppressed during that template argument /// deduction. /// /// FIXME: Serialize this structure to the AST file. typedef llvm::DenseMap > SuppressedDiagnosticsMap; SuppressedDiagnosticsMap SuppressedDiagnostics; /// A stack object to be created when performing template /// instantiation. /// /// Construction of an object of type \c InstantiatingTemplate /// pushes the current instantiation onto the stack of active /// instantiations. If the size of this stack exceeds the maximum /// number of recursive template instantiations, construction /// produces an error and evaluates true. /// /// Destruction of this object will pop the named instantiation off /// the stack. struct InstantiatingTemplate { /// Note that we are instantiating a class template, /// function template, variable template, alias template, /// or a member thereof. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, SourceRange InstantiationRange = SourceRange()); struct ExceptionSpecification {}; /// Note that we are instantiating an exception specification /// of a function template. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionDecl *Entity, ExceptionSpecification, SourceRange InstantiationRange = SourceRange()); /// Note that we are instantiating a default argument in a /// template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateParameter Param, TemplateDecl *Template, ArrayRef TemplateArgs, SourceRange InstantiationRange = SourceRange()); /// Note that we are substituting either explicitly-specified or /// deduced template arguments during function template argument deduction. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionTemplateDecl *FunctionTemplate, ArrayRef TemplateArgs, CodeSynthesisContext::SynthesisKind Kind, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// Note that we are instantiating as part of template /// argument deduction for a class template declaration. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// Note that we are instantiating as part of template /// argument deduction for a class template partial /// specialization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplatePartialSpecializationDecl *PartialSpec, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// Note that we are instantiating as part of template /// argument deduction for a variable template partial /// specialization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, VarTemplatePartialSpecializationDecl *PartialSpec, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// Note that we are instantiating a default argument for a function /// parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange = SourceRange()); /// Note that we are substituting prior template arguments into a /// non-type parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, NonTypeTemplateParmDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); /// Note that we are substituting prior template arguments into a /// template template parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, TemplateTemplateParmDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); /// Note that we are checking the default template argument /// against the template parameter for a given template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, NamedDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); struct ConstraintsCheck {}; /// \brief Note that we are checking the constraints associated with some /// constrained entity (a concept declaration or a template with associated /// constraints). InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintsCheck, NamedDecl *Template, ArrayRef TemplateArgs, SourceRange InstantiationRange); struct ConstraintSubstitution {}; /// \brief Note that we are checking a constraint expression associated /// with a template declaration or as part of the satisfaction check of a /// concept. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintSubstitution, NamedDecl *Template, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange); struct ConstraintNormalization {}; /// \brief Note that we are normalizing a constraint expression. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintNormalization, NamedDecl *Template, SourceRange InstantiationRange); struct ParameterMappingSubstitution {}; /// \brief Note that we are subtituting into the parameter mapping of an /// atomic constraint during constraint normalization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParameterMappingSubstitution, NamedDecl *Template, SourceRange InstantiationRange); /// \brief Note that we are substituting template arguments into a part of /// a requirement of a requires expression. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, concepts::Requirement *Req, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are checking the satisfaction of the constraint /// expression inside of a nested requirement. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, concepts::NestedRequirement *Req, ConstraintsCheck, SourceRange InstantiationRange = SourceRange()); /// Note that we have finished instantiating this template. void Clear(); ~InstantiatingTemplate() { Clear(); } /// Determines whether we have exceeded the maximum /// recursive template instantiations. bool isInvalid() const { return Invalid; } /// Determine whether we are already instantiating this /// specialization in some surrounding active instantiation. bool isAlreadyInstantiating() const { return AlreadyInstantiating; } private: Sema &SemaRef; bool Invalid; bool AlreadyInstantiating; bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, SourceRange InstantiationRange); InstantiatingTemplate( Sema &SemaRef, CodeSynthesisContext::SynthesisKind Kind, SourceLocation PointOfInstantiation, SourceRange InstantiationRange, Decl *Entity, NamedDecl *Template = nullptr, ArrayRef TemplateArgs = None, sema::TemplateDeductionInfo *DeductionInfo = nullptr); InstantiatingTemplate(const InstantiatingTemplate&) = delete; InstantiatingTemplate& operator=(const InstantiatingTemplate&) = delete; }; void pushCodeSynthesisContext(CodeSynthesisContext Ctx); void popCodeSynthesisContext(); /// Determine whether we are currently performing template instantiation. bool inTemplateInstantiation() const { return CodeSynthesisContexts.size() > NonInstantiationEntries; } void PrintContextStack() { if (!CodeSynthesisContexts.empty() && CodeSynthesisContexts.size() != LastEmittedCodeSynthesisContextDepth) { PrintInstantiationStack(); LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size(); } if (PragmaAttributeCurrentTargetDecl) PrintPragmaAttributeInstantiationPoint(); } void PrintInstantiationStack(); void PrintPragmaAttributeInstantiationPoint(); /// Determines whether we are currently in a context where /// template argument substitution failures are not considered /// errors. /// /// \returns An empty \c Optional if we're not in a SFINAE context. /// Otherwise, contains a pointer that, if non-NULL, contains the nearest /// template-deduction context object, which can be used to capture /// diagnostics that will be suppressed. Optional isSFINAEContext() const; /// Determines whether we are currently in a context that /// is not evaluated as per C++ [expr] p5. bool isUnevaluatedContext() const { assert(!ExprEvalContexts.empty() && "Must be in an expression evaluation context"); return ExprEvalContexts.back().isUnevaluated(); } /// RAII class used to determine whether SFINAE has /// trapped any errors that occur during template argument /// deduction. class SFINAETrap { Sema &SemaRef; unsigned PrevSFINAEErrors; bool PrevInNonInstantiationSFINAEContext; bool PrevAccessCheckingSFINAE; bool PrevLastDiagnosticIgnored; public: explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), PrevInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext), PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE), PrevLastDiagnosticIgnored( SemaRef.getDiagnostics().isLastDiagnosticIgnored()) { if (!SemaRef.isSFINAEContext()) SemaRef.InNonInstantiationSFINAEContext = true; SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; } ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; SemaRef.InNonInstantiationSFINAEContext = PrevInNonInstantiationSFINAEContext; SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; SemaRef.getDiagnostics().setLastDiagnosticIgnored( PrevLastDiagnosticIgnored); } /// Determine whether any SFINAE errors have been trapped. bool hasErrorOccurred() const { return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; } }; /// RAII class used to indicate that we are performing provisional /// semantic analysis to determine the validity of a construct, so /// typo-correction and diagnostics in the immediate context (not within /// implicitly-instantiated templates) should be suppressed. class TentativeAnalysisScope { Sema &SemaRef; // FIXME: Using a SFINAETrap for this is a hack. SFINAETrap Trap; bool PrevDisableTypoCorrection; public: explicit TentativeAnalysisScope(Sema &SemaRef) : SemaRef(SemaRef), Trap(SemaRef, true), PrevDisableTypoCorrection(SemaRef.DisableTypoCorrection) { SemaRef.DisableTypoCorrection = true; } ~TentativeAnalysisScope() { SemaRef.DisableTypoCorrection = PrevDisableTypoCorrection; } }; /// The current instantiation scope used to store local /// variables. LocalInstantiationScope *CurrentInstantiationScope; /// Tracks whether we are in a context where typo correction is /// disabled. bool DisableTypoCorrection; /// The number of typos corrected by CorrectTypo. unsigned TyposCorrected; typedef llvm::SmallSet SrcLocSet; typedef llvm::DenseMap IdentifierSourceLocations; /// A cache containing identifiers for which typo correction failed and /// their locations, so that repeated attempts to correct an identifier in a /// given location are ignored if typo correction already failed for it. IdentifierSourceLocations TypoCorrectionFailures; /// Worker object for performing CFG-based warnings. sema::AnalysisBasedWarnings AnalysisWarnings; threadSafety::BeforeSet *ThreadSafetyDeclCache; /// An entity for which implicit template instantiation is required. /// /// The source location associated with the declaration is the first place in /// the source code where the declaration was "used". It is not necessarily /// the point of instantiation (which will be either before or after the /// namespace-scope declaration that triggered this implicit instantiation), /// However, it is the location that diagnostics should generally refer to, /// because users will need to know what code triggered the instantiation. typedef std::pair PendingImplicitInstantiation; /// The queue of implicit template instantiations that are required /// but have not yet been performed. std::deque PendingInstantiations; /// Queue of implicit template instantiations that cannot be performed /// eagerly. SmallVector LateParsedInstantiations; class GlobalEagerInstantiationScope { public: GlobalEagerInstantiationScope(Sema &S, bool Enabled) : S(S), Enabled(Enabled) { if (!Enabled) return; SavedPendingInstantiations.swap(S.PendingInstantiations); SavedVTableUses.swap(S.VTableUses); } void perform() { if (Enabled) { S.DefineUsedVTables(); S.PerformPendingInstantiations(); } } ~GlobalEagerInstantiationScope() { if (!Enabled) return; // Restore the set of pending vtables. assert(S.VTableUses.empty() && "VTableUses should be empty before it is discarded."); S.VTableUses.swap(SavedVTableUses); // Restore the set of pending implicit instantiations. if (S.TUKind != TU_Prefix || !S.LangOpts.PCHInstantiateTemplates) { assert(S.PendingInstantiations.empty() && "PendingInstantiations should be empty before it is discarded."); S.PendingInstantiations.swap(SavedPendingInstantiations); } else { // Template instantiations in the PCH may be delayed until the TU. S.PendingInstantiations.swap(SavedPendingInstantiations); S.PendingInstantiations.insert(S.PendingInstantiations.end(), SavedPendingInstantiations.begin(), SavedPendingInstantiations.end()); } } private: Sema &S; SmallVector SavedVTableUses; std::deque SavedPendingInstantiations; bool Enabled; }; /// The queue of implicit template instantiations that are required /// and must be performed within the current local scope. /// /// This queue is only used for member functions of local classes in /// templates, which must be instantiated in the same scope as their /// enclosing function, so that they can reference function-local /// types, static variables, enumerators, etc. std::deque PendingLocalImplicitInstantiations; class LocalEagerInstantiationScope { public: LocalEagerInstantiationScope(Sema &S) : S(S) { SavedPendingLocalImplicitInstantiations.swap( S.PendingLocalImplicitInstantiations); } void perform() { S.PerformPendingInstantiations(/*LocalOnly=*/true); } ~LocalEagerInstantiationScope() { assert(S.PendingLocalImplicitInstantiations.empty() && "there shouldn't be any pending local implicit instantiations"); SavedPendingLocalImplicitInstantiations.swap( S.PendingLocalImplicitInstantiations); } private: Sema &S; std::deque SavedPendingLocalImplicitInstantiations; }; /// A helper class for building up ExtParameterInfos. class ExtParameterInfoBuilder { SmallVector Infos; bool HasInteresting = false; public: /// Set the ExtParameterInfo for the parameter at the given index, /// void set(unsigned index, FunctionProtoType::ExtParameterInfo info) { assert(Infos.size() <= index); Infos.resize(index); Infos.push_back(info); if (!HasInteresting) HasInteresting = (info != FunctionProtoType::ExtParameterInfo()); } /// Return a pointer (suitable for setting in an ExtProtoInfo) to the /// ExtParameterInfo array we've built up. const FunctionProtoType::ExtParameterInfo * getPointerOrNull(unsigned numParams) { if (!HasInteresting) return nullptr; Infos.resize(numParams); return Infos.data(); } }; void PerformPendingInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity, bool AllowDeducedTST = false); QualType SubstType(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); TypeSourceInfo *SubstType(TypeLoc TL, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext, Qualifiers ThisTypeQuals); void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, const MultiLevelTemplateArgumentList &Args); bool SubstExceptionSpec(SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI, SmallVectorImpl &ExceptionStorage, const MultiLevelTemplateArgumentList &Args); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, Optional NumExpansions, bool ExpectParameterPack); bool SubstParmTypes(SourceLocation Loc, ArrayRef Params, const FunctionProtoType::ExtParameterInfo *ExtParamInfos, const MultiLevelTemplateArgumentList &TemplateArgs, SmallVectorImpl &ParamTypes, SmallVectorImpl *OutParams, ExtParameterInfoBuilder &ParamInfos); ExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); /// Substitute the given template arguments into a list of /// expressions, expanding pack expansions if required. /// /// \param Exprs The list of expressions to substitute into. /// /// \param IsCall Whether this is some form of call, in which case /// default arguments will be dropped. /// /// \param TemplateArgs The set of template arguments to substitute. /// /// \param Outputs Will receive all of the substituted arguments. /// /// \returns true if an error occurred, false otherwise. bool SubstExprs(ArrayRef Exprs, bool IsCall, const MultiLevelTemplateArgumentList &TemplateArgs, SmallVectorImpl &Outputs); StmtResult SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs); TemplateParameterList * SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); bool SubstTemplateArguments(ArrayRef Args, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateArgumentListInfo &Outputs); Decl *SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); /// Substitute the name and return type of a defaulted 'operator<=>' to form /// an implicit 'operator=='. FunctionDecl *SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD, FunctionDecl *Spaceship); ExprResult SubstInitializer(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit); bool SubstBaseSpecifiers(CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); bool InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK, bool Complain = true); bool InstantiateEnum(SourceLocation PointOfInstantiation, EnumDecl *Instantiation, EnumDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK); bool InstantiateInClassInitializer( SourceLocation PointOfInstantiation, FieldDecl *Instantiation, FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); struct LateInstantiatedAttribute { const Attr *TmplAttr; LocalInstantiationScope *Scope; Decl *NewDecl; LateInstantiatedAttribute(const Attr *A, LocalInstantiationScope *S, Decl *D) : TmplAttr(A), Scope(S), NewDecl(D) { } }; typedef SmallVector LateInstantiatedAttrVec; void InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Pattern, Decl *Inst, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); void InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Pattern, Decl *Inst, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); bool usesPartialOrExplicitSpecialization( SourceLocation Loc, ClassTemplateSpecializationDecl *ClassTemplateSpec); bool InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK, bool Complain = true); void InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK); void InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK); NestedNameSpecifierLoc SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, const MultiLevelTemplateArgumentList &TemplateArgs); DeclarationNameInfo SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, const MultiLevelTemplateArgumentList &TemplateArgs); TemplateName SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name, SourceLocation Loc, const MultiLevelTemplateArgumentList &TemplateArgs); bool Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, TemplateArgumentListInfo &Result, const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, FunctionDecl *Function); bool CheckInstantiatedFunctionTemplateConstraints( SourceLocation PointOfInstantiation, FunctionDecl *Decl, ArrayRef TemplateArgs, ConstraintSatisfaction &Satisfaction); FunctionDecl *InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD, const TemplateArgumentList *Args, SourceLocation Loc); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); VarTemplateSpecializationDecl *BuildVarTemplateInstantiation( VarTemplateDecl *VarTemplate, VarDecl *FromVar, const TemplateArgumentList &TemplateArgList, const TemplateArgumentListInfo &TemplateArgsInfo, SmallVectorImpl &Converted, SourceLocation PointOfInstantiation, void *InsertPos, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *StartingScope = nullptr); VarTemplateSpecializationDecl *CompleteVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, const MultiLevelTemplateArgumentList &TemplateArgs); void BuildVariableInstantiation(VarDecl *NewVar, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs, LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner, LocalInstantiationScope *StartingScope, bool InstantiatingVarTemplate = false, VarTemplateSpecializationDecl *PrevVTSD = nullptr); VarDecl *getVarTemplateSpecialization( VarTemplateDecl *VarTempl, const TemplateArgumentListInfo *TemplateArgs, const DeclarationNameInfo &MemberNameInfo, SourceLocation TemplateKWLoc); void InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); void InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, const MultiLevelTemplateArgumentList &TemplateArgs); NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, bool FindingInstantiatedContext = false); DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); // Objective-C declarations. enum ObjCContainerKind { OCK_None = -1, OCK_Interface = 0, OCK_Protocol, OCK_Category, OCK_ClassExtension, OCK_Implementation, OCK_CategoryImplementation }; ObjCContainerKind getObjCContainerKind() const; DeclResult actOnObjCTypeParam(Scope *S, ObjCTypeParamVariance variance, SourceLocation varianceLoc, unsigned index, IdentifierInfo *paramName, SourceLocation paramLoc, SourceLocation colonLoc, ParsedType typeBound); ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc, ArrayRef typeParams, SourceLocation rAngleLoc); void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList); Decl *ActOnStartClassInterface( Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *SuperName, SourceLocation SuperLoc, ArrayRef SuperTypeArgs, SourceRange SuperTypeArgsRange, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList); void ActOnSuperClassOfClassInterface(Scope *S, SourceLocation AtInterfaceLoc, ObjCInterfaceDecl *IDecl, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, ArrayRef SuperTypeArgs, SourceRange SuperTypeArgsRange); void ActOnTypedefedProtocols(SmallVectorImpl &ProtocolRefs, SmallVectorImpl &ProtocolLocs, IdentifierInfo *SuperName, SourceLocation SuperLoc); Decl *ActOnCompatibilityAlias( SourceLocation AtCompatibilityAliasLoc, IdentifierInfo *AliasName, SourceLocation AliasLocation, IdentifierInfo *ClassName, SourceLocation ClassLocation); bool CheckForwardProtocolDeclarationForCircularDependency( IdentifierInfo *PName, SourceLocation &PLoc, SourceLocation PrevLoc, const ObjCList &PList); Decl *ActOnStartProtocolInterface( SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, Decl *const *ProtoRefNames, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList); Decl *ActOnStartCategoryInterface( SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList); Decl *ActOnStartClassImplementation(SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc, const ParsedAttributesView &AttrList); Decl *ActOnStartCategoryImplementation(SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc, const ParsedAttributesView &AttrList); DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl, ArrayRef Decls); DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, IdentifierInfo **IdentList, SourceLocation *IdentLocs, ArrayRef TypeParamLists, unsigned NumElts); DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, ArrayRef IdentList, const ParsedAttributesView &attrList); void FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, ArrayRef ProtocolId, SmallVectorImpl &Protocols); void DiagnoseTypeArgsAndProtocols(IdentifierInfo *ProtocolId, SourceLocation ProtocolLoc, IdentifierInfo *TypeArgId, SourceLocation TypeArgLoc, bool SelectProtocolFirst = false); /// Given a list of identifiers (and their locations), resolve the /// names to either Objective-C protocol qualifiers or type /// arguments, as appropriate. void actOnObjCTypeArgsOrProtocolQualifiers( Scope *S, ParsedType baseType, SourceLocation lAngleLoc, ArrayRef identifiers, ArrayRef identifierLocs, SourceLocation rAngleLoc, SourceLocation &typeArgsLAngleLoc, SmallVectorImpl &typeArgs, SourceLocation &typeArgsRAngleLoc, SourceLocation &protocolLAngleLoc, SmallVectorImpl &protocols, SourceLocation &protocolRAngleLoc, bool warnOnIncompleteProtocols); /// Build a an Objective-C protocol-qualified 'id' type where no /// base type was specified. TypeResult actOnObjCProtocolQualifierType( SourceLocation lAngleLoc, ArrayRef protocols, ArrayRef protocolLocs, SourceLocation rAngleLoc); /// Build a specialized and/or protocol-qualified Objective-C type. TypeResult actOnObjCTypeArgsAndProtocolQualifiers( Scope *S, SourceLocation Loc, ParsedType BaseType, SourceLocation TypeArgsLAngleLoc, ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc); /// Build an Objective-C type parameter type. QualType BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc, bool FailOnError = false); /// Build an Objective-C object pointer type. QualType BuildObjCObjectType(QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc, bool FailOnError = false); /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \p PropertyTy. void CheckObjCPropertyAttributes(Decl *PropertyPtrTy, SourceLocation Loc, unsigned &Attributes, bool propertyInPrimaryClass); /// Process the specified property declaration and create decls for the /// setters and getters as needed. /// \param property The property declaration being processed void ProcessPropertyDecl(ObjCPropertyDecl *property); void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, const IdentifierInfo *Name, bool OverridingProtocolProperty); void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, ObjCInterfaceDecl *ID); Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods = None, ArrayRef allTUVars = None); Decl *ActOnProperty(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = nullptr); Decl *ActOnPropertyImplDecl(Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, bool ImplKind, IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar, SourceLocation PropertyIvarLoc, ObjCPropertyQueryKind QueryKind); enum ObjCSpecialMethodKind { OSMK_None, OSMK_Alloc, OSMK_New, OSMK_Copy, OSMK_RetainingInit, OSMK_NonRetainingInit }; struct ObjCArgInfo { IdentifierInfo *Name; SourceLocation NameLoc; // The Type is null if no type was specified, and the DeclSpec is invalid // in this case. ParsedType Type; ObjCDeclSpec DeclSpec; /// ArgAttrs - Attribute list for this argument. ParsedAttributesView ArgAttrs; }; Decl *ActOnMethodDeclaration( Scope *S, SourceLocation BeginLoc, // location of the + or -. SourceLocation EndLoc, // location of the ; or {. tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, ArrayRef SelectorLocs, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). ObjCArgInfo *ArgInfo, DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args const ParsedAttributesView &AttrList, tok::ObjCKeywordKind MethodImplKind, bool isVariadic, bool MethodDefinition); ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, const ObjCObjectPointerType *OPT, bool IsInstance); ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty, bool IsInstance); bool CheckARCMethodDecl(ObjCMethodDecl *method); bool inferObjCARCLifetime(ValueDecl *decl); void deduceOpenCLAddressSpace(ValueDecl *decl); ExprResult HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Expr *BaseExpr, SourceLocation OpLoc, DeclarationName MemberName, SourceLocation MemberLoc, SourceLocation SuperLoc, QualType SuperType, bool Super); ExprResult ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IdentifierInfo &propertyName, SourceLocation receiverNameLoc, SourceLocation propertyNameLoc); ObjCMethodDecl *tryCaptureObjCSelf(SourceLocation Loc); /// Describes the kind of message expression indicated by a message /// send that starts with an identifier. enum ObjCMessageKind { /// The message is sent to 'super'. ObjCSuperMessage, /// The message is an instance message. ObjCInstanceMessage, /// The message is a class message, and the identifier is a type /// name. ObjCClassMessage }; ObjCMessageKind getObjCMessageKind(Scope *S, IdentifierInfo *Name, SourceLocation NameLoc, bool IsSuper, bool HasTrailingDot, ParsedType &ReceiverType); ExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args, bool isImplicit = false); ExprResult BuildClassMessageImplicit(QualType ReceiverType, bool isSuperReceiver, SourceLocation Loc, Selector Sel, ObjCMethodDecl *Method, MultiExprArg Args); ExprResult ActOnClassMessage(Scope *S, ParsedType Receiver, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildInstanceMessage(Expr *Receiver, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args, bool isImplicit = false); ExprResult BuildInstanceMessageImplicit(Expr *Receiver, QualType ReceiverType, SourceLocation Loc, Selector Sel, ObjCMethodDecl *Method, MultiExprArg Args); ExprResult ActOnInstanceMessage(Scope *S, Expr *Receiver, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildObjCBridgedCast(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo, Expr *SubExpr); ExprResult ActOnObjCBridgedCast(Scope *S, SourceLocation LParenLoc, ObjCBridgeCastKind Kind, SourceLocation BridgeKeywordLoc, ParsedType Type, SourceLocation RParenLoc, Expr *SubExpr); void CheckTollFreeBridgeCast(QualType castType, Expr *castExpr); void CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr); bool CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr, CastKind &Kind); bool checkObjCBridgeRelatedComponents(SourceLocation Loc, QualType DestType, QualType SrcType, ObjCInterfaceDecl *&RelatedClass, ObjCMethodDecl *&ClassMethod, ObjCMethodDecl *&InstanceMethod, TypedefNameDecl *&TDNDecl, bool CfToNs, bool Diagnose = true); bool CheckObjCBridgeRelatedConversions(SourceLocation Loc, QualType DestType, QualType SrcType, Expr *&SrcExpr, bool Diagnose = true); bool CheckConversionToObjCLiteral(QualType DstType, Expr *&SrcExpr, bool Diagnose = true); bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); /// Check whether the given new method is a valid override of the /// given overridden method, and set any properties that should be inherited. void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, const ObjCMethodDecl *Overridden); /// Describes the compatibility of a result type with its method. enum ResultTypeCompatibilityKind { RTC_Compatible, RTC_Incompatible, RTC_Unknown }; void CheckObjCMethodDirectOverrides(ObjCMethodDecl *method, ObjCMethodDecl *overridden); void CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, ObjCInterfaceDecl *CurrentClass, ResultTypeCompatibilityKind RTC); enum PragmaOptionsAlignKind { POAK_Native, // #pragma options align=native POAK_Natural, // #pragma options align=natural POAK_Packed, // #pragma options align=packed POAK_Power, // #pragma options align=power POAK_Mac68k, // #pragma options align=mac68k POAK_Reset // #pragma options align=reset }; /// ActOnPragmaClangSection - Called on well formed \#pragma clang section void ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action, PragmaClangSectionKind SecKind, StringRef SecName); /// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align. void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc); /// ActOnPragmaPack - Called on well formed \#pragma pack(...). void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, StringRef SlotLabel, Expr *Alignment); enum class PragmaPackDiagnoseKind { NonDefaultStateAtInclude, ChangedStateAtExit }; void DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind, SourceLocation IncludeLoc); void DiagnoseUnterminatedPragmaPack(); /// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off]. void ActOnPragmaMSStruct(PragmaMSStructKind Kind); /// ActOnPragmaMSComment - Called on well formed /// \#pragma comment(kind, "arg"). void ActOnPragmaMSComment(SourceLocation CommentLoc, PragmaMSCommentKind Kind, StringRef Arg); /// ActOnPragmaMSPointersToMembers - called on well formed \#pragma /// pointers_to_members(representation method[, general purpose /// representation]). void ActOnPragmaMSPointersToMembers( LangOptions::PragmaMSPointersToMembersKind Kind, SourceLocation PragmaLoc); /// Called on well formed \#pragma vtordisp(). void ActOnPragmaMSVtorDisp(PragmaMsStackAction Action, SourceLocation PragmaLoc, MSVtorDispMode Value); enum PragmaSectionKind { PSK_DataSeg, PSK_BSSSeg, PSK_ConstSeg, PSK_CodeSeg, }; bool UnifySection(StringRef SectionName, int SectionFlags, DeclaratorDecl *TheDecl); bool UnifySection(StringRef SectionName, int SectionFlags, SourceLocation PragmaSectionLocation); /// Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg. void ActOnPragmaMSSeg(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, StringLiteral *SegmentName, llvm::StringRef PragmaName); /// Called on well formed \#pragma section(). void ActOnPragmaMSSection(SourceLocation PragmaLocation, int SectionFlags, StringLiteral *SegmentName); /// Called on well-formed \#pragma init_seg(). void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation, StringLiteral *SegmentName); /// Called on #pragma clang __debug dump II void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II); /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name, StringRef Value); /// Are precise floating point semantics currently enabled? bool isPreciseFPEnabled() { return !CurFPFeatures.getAllowFPReassociate() && !CurFPFeatures.getNoSignedZero() && !CurFPFeatures.getAllowReciprocal() && !CurFPFeatures.getAllowApproxFunc(); } /// ActOnPragmaFloatControl - Call on well-formed \#pragma float_control void ActOnPragmaFloatControl(SourceLocation Loc, PragmaMsStackAction Action, PragmaFloatControlKind Value); /// ActOnPragmaUnused - Called on well-formed '\#pragma unused'. void ActOnPragmaUnused(const Token &Identifier, Scope *curScope, SourceLocation PragmaLoc); /// ActOnPragmaVisibility - Called on well formed \#pragma GCC visibility... . void ActOnPragmaVisibility(const IdentifierInfo* VisType, SourceLocation PragmaLoc); NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, SourceLocation Loc); void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W); /// ActOnPragmaWeakID - Called on well formed \#pragma weak ident. void ActOnPragmaWeakID(IdentifierInfo* WeakName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc); /// ActOnPragmaRedefineExtname - Called on well formed /// \#pragma redefine_extname oldname newname. void ActOnPragmaRedefineExtname(IdentifierInfo* WeakName, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); /// ActOnPragmaWeakAlias - Called on well formed \#pragma weak ident = ident. void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); /// ActOnPragmaFPContract - Called on well formed /// \#pragma {STDC,OPENCL} FP_CONTRACT and /// \#pragma clang fp contract void ActOnPragmaFPContract(SourceLocation Loc, LangOptions::FPModeKind FPC); /// Called on well formed /// \#pragma clang fp reassociate void ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled); /// ActOnPragmaFenvAccess - Called on well formed /// \#pragma STDC FENV_ACCESS void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled); /// Called to set rounding mode for floating point operations. void setRoundingMode(SourceLocation Loc, llvm::RoundingMode); /// Called to set exception behavior for floating point operations. void setExceptionMode(SourceLocation Loc, LangOptions::FPExceptionModeKind); /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'. void AddAlignmentAttributesForRecord(RecordDecl *RD); /// AddMsStructLayoutForRecord - Adds ms_struct layout attribute to record. void AddMsStructLayoutForRecord(RecordDecl *RD); /// FreePackedContext - Deallocate and null out PackContext. void FreePackedContext(); /// PushNamespaceVisibilityAttr - Note that we've entered a /// namespace with a visibility attribute. void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, SourceLocation Loc); /// AddPushedVisibilityAttribute - If '\#pragma GCC visibility' was used, /// add an appropriate visibility attribute. void AddPushedVisibilityAttribute(Decl *RD); /// PopPragmaVisibility - Pop the top element of the visibility stack; used /// for '\#pragma GCC visibility' and visibility attributes on namespaces. void PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc); /// FreeVisContext - Deallocate and null out VisContext. void FreeVisContext(); /// AddCFAuditedAttribute - Check whether we're currently within /// '\#pragma clang arc_cf_code_audited' and, if so, consider adding /// the appropriate attribute. void AddCFAuditedAttribute(Decl *D); void ActOnPragmaAttributeAttribute(ParsedAttr &Attribute, SourceLocation PragmaLoc, attr::ParsedSubjectMatchRuleSet Rules); void ActOnPragmaAttributeEmptyPush(SourceLocation PragmaLoc, const IdentifierInfo *Namespace); /// Called on well-formed '\#pragma clang attribute pop'. void ActOnPragmaAttributePop(SourceLocation PragmaLoc, const IdentifierInfo *Namespace); /// Adds the attributes that have been specified using the /// '\#pragma clang attribute push' directives to the given declaration. void AddPragmaAttributes(Scope *S, Decl *D); void DiagnoseUnterminatedPragmaAttribute(); /// Called on well formed \#pragma clang optimize. void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc); /// Get the location for the currently active "\#pragma clang optimize /// off". If this location is invalid, then the state of the pragma is "on". SourceLocation getOptimizeOffPragmaLocation() const { return OptimizeOffPragmaLocation; } /// Only called on function definitions; if there is a pragma in scope /// with the effect of a range-based optnone, consider marking the function /// with attribute optnone. void AddRangeBasedOptnone(FunctionDecl *FD); /// Adds the 'optnone' attribute to the function declaration if there /// are no conflicts; Loc represents the location causing the 'optnone' /// attribute to be added (usually because of a pragma). void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc); /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, bool IsPackExpansion); void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, TypeSourceInfo *T, bool IsPackExpansion); /// AddAssumeAlignedAttr - Adds an assume_aligned attribute to a particular /// declaration. void AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, Expr *OE); /// AddAllocAlignAttr - Adds an alloc_align attribute to a particular /// declaration. void AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI, Expr *ParamExpr); /// AddAlignValueAttr - Adds an align_value attribute to a particular /// declaration. void AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E); /// AddLaunchBoundsAttr - Adds a launch_bounds attribute to a particular /// declaration. void AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI, Expr *MaxThreads, Expr *MinBlocks); /// AddModeAttr - Adds a mode attribute to a particular declaration. void AddModeAttr(Decl *D, const AttributeCommonInfo &CI, IdentifierInfo *Name, bool InInstantiation = false); void AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, ParameterABI ABI); enum class RetainOwnershipKind {NS, CF, OS}; void AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, RetainOwnershipKind K, bool IsTemplateInstantiation); /// addAMDGPUFlatWorkGroupSizeAttr - Adds an amdgpu_flat_work_group_size /// attribute to a particular declaration. void addAMDGPUFlatWorkGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI, Expr *Min, Expr *Max); /// addAMDGPUWavePersEUAttr - Adds an amdgpu_waves_per_eu attribute to a /// particular declaration. void addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI, Expr *Min, Expr *Max); bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type); //===--------------------------------------------------------------------===// // C++ Coroutines TS // bool ActOnCoroutineBodyStart(Scope *S, SourceLocation KwLoc, StringRef Keyword); ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E); ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E); StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E); ExprResult BuildResolvedCoawaitExpr(SourceLocation KwLoc, Expr *E, bool IsImplicit = false); ExprResult BuildUnresolvedCoawaitExpr(SourceLocation KwLoc, Expr *E, UnresolvedLookupExpr* Lookup); ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E); StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E, bool IsImplicit = false); StmtResult BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs); bool buildCoroutineParameterMoves(SourceLocation Loc); VarDecl *buildCoroutinePromise(SourceLocation Loc); void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body); ClassTemplateDecl *lookupCoroutineTraits(SourceLocation KwLoc, SourceLocation FuncLoc); /// Check that the expression co_await promise.final_suspend() shall not be /// potentially-throwing. bool checkFinalSuspendNoThrow(const Stmt *FinalSuspend); //===--------------------------------------------------------------------===// // OpenCL extensions. // private: std::string CurrOpenCLExtension; /// Extensions required by an OpenCL type. llvm::DenseMap> OpenCLTypeExtMap; /// Extensions required by an OpenCL declaration. llvm::DenseMap> OpenCLDeclExtMap; public: llvm::StringRef getCurrentOpenCLExtension() const { return CurrOpenCLExtension; } /// Check if a function declaration \p FD associates with any /// extensions present in OpenCLDeclExtMap and if so return the /// extension(s) name(s). std::string getOpenCLExtensionsFromDeclExtMap(FunctionDecl *FD); /// Check if a function type \p FT associates with any /// extensions present in OpenCLTypeExtMap and if so return the /// extension(s) name(s). std::string getOpenCLExtensionsFromTypeExtMap(FunctionType *FT); /// Find an extension in an appropriate extension map and return its name template std::string getOpenCLExtensionsFromExtMap(T* FT, MapT &Map); void setCurrentOpenCLExtension(llvm::StringRef Ext) { CurrOpenCLExtension = std::string(Ext); } /// Set OpenCL extensions for a type which can only be used when these /// OpenCL extensions are enabled. If \p Exts is empty, do nothing. /// \param Exts A space separated list of OpenCL extensions. void setOpenCLExtensionForType(QualType T, llvm::StringRef Exts); /// Set OpenCL extensions for a declaration which can only be /// used when these OpenCL extensions are enabled. If \p Exts is empty, do /// nothing. /// \param Exts A space separated list of OpenCL extensions. void setOpenCLExtensionForDecl(Decl *FD, llvm::StringRef Exts); /// Set current OpenCL extensions for a type which can only be used /// when these OpenCL extensions are enabled. If current OpenCL extension is /// empty, do nothing. void setCurrentOpenCLExtensionForType(QualType T); /// Set current OpenCL extensions for a declaration which /// can only be used when these OpenCL extensions are enabled. If current /// OpenCL extension is empty, do nothing. void setCurrentOpenCLExtensionForDecl(Decl *FD); bool isOpenCLDisabledDecl(Decl *FD); /// Check if type \p T corresponding to declaration specifier \p DS /// is disabled due to required OpenCL extensions being disabled. If so, /// emit diagnostics. /// \return true if type is disabled. bool checkOpenCLDisabledTypeDeclSpec(const DeclSpec &DS, QualType T); /// Check if declaration \p D used by expression \p E /// is disabled due to required OpenCL extensions being disabled. If so, /// emit diagnostics. /// \return true if type is disabled. bool checkOpenCLDisabledDecl(const NamedDecl &D, const Expr &E); //===--------------------------------------------------------------------===// // OpenMP directives and clauses. // private: void *VarDataSharingAttributesStack; /// Number of nested '#pragma omp declare target' directives. unsigned DeclareTargetNestingLevel = 0; /// Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind, bool StrictlyPositive = true); /// Returns OpenMP nesting level for current directive. unsigned getOpenMPNestingLevel() const; /// Adjusts the function scopes index for the target-based regions. void adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex, unsigned Level) const; /// Returns the number of scopes associated with the construct on the given /// OpenMP level. int getNumberOfConstructScopes(unsigned Level) const; /// Push new OpenMP function region for non-capturing function. void pushOpenMPFunctionRegion(); /// Pop OpenMP function region for non-capturing function. void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI); /// Checks if a type or a declaration is disabled due to the owning extension /// being disabled, and emits diagnostic messages if it is disabled. /// \param D type or declaration to be checked. /// \param DiagLoc source location for the diagnostic message. /// \param DiagInfo information to be emitted for the diagnostic message. /// \param SrcRange source range of the declaration. /// \param Map maps type or declaration to the extensions. /// \param Selector selects diagnostic message: 0 for type and 1 for /// declaration. /// \return true if the type or declaration is disabled. template bool checkOpenCLDisabledTypeOrDecl(T D, DiagLocT DiagLoc, DiagInfoT DiagInfo, MapT &Map, unsigned Selector = 0, SourceRange SrcRange = SourceRange()); /// Helper to keep information about the current `omp begin/end declare /// variant` nesting. struct OMPDeclareVariantScope { /// The associated OpenMP context selector. OMPTraitInfo *TI; /// The associated OpenMP context selector mangling. std::string NameSuffix; OMPDeclareVariantScope(OMPTraitInfo &TI); }; /// The current `omp begin/end declare variant` scopes. SmallVector OMPDeclareVariantScopes; /// The declarator \p D defines a function in the scope \p S which is nested /// in an `omp begin/end declare variant` scope. In this method we create a /// declaration for \p D and rename \p D according to the OpenMP context /// selector of the surrounding scope. FunctionDecl * ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(Scope *S, Declarator &D); /// Register \p FD as specialization of \p BaseFD in the current `omp /// begin/end declare variant` scope. void ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope( FunctionDecl *FD, FunctionDecl *BaseFD); public: /// Can we exit a scope at the moment. bool isInOpenMPDeclareVariantScope() { return !OMPDeclareVariantScopes.empty(); } /// Given the potential call expression \p Call, determine if there is a /// specialization via the OpenMP declare variant mechanism available. If /// there is, return the specialized call expression, otherwise return the /// original \p Call. ExprResult ActOnOpenMPCall(ExprResult Call, Scope *Scope, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig); /// Handle a `omp begin declare variant`. void ActOnOpenMPBeginDeclareVariant(SourceLocation Loc, OMPTraitInfo &TI); /// Handle a `omp end declare variant`. void ActOnOpenMPEndDeclareVariant(); /// Checks if the variant/multiversion functions are compatible. bool areMultiversionVariantFunctionsCompatible( const FunctionDecl *OldFD, const FunctionDecl *NewFD, const PartialDiagnostic &NoProtoDiagID, const PartialDiagnosticAt &NoteCausedDiagIDAt, const PartialDiagnosticAt &NoSupportDiagIDAt, const PartialDiagnosticAt &DiffDiagIDAt, bool TemplatesSupported, bool ConstexprSupported, bool CLinkageMayDiffer); /// Function tries to capture lambda's captured variables in the OpenMP region /// before the original lambda is captured. void tryCaptureOpenMPLambdas(ValueDecl *V); /// Return true if the provided declaration \a VD should be captured by /// reference. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. /// \param OpenMPCaptureLevel Capture level within an OpenMP construct. bool isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, unsigned OpenMPCaptureLevel) const; /// Check if the specified variable is used in one of the private /// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP /// constructs. VarDecl *isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo = false, unsigned StopAt = 0); ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, ExprObjectKind OK, SourceLocation Loc); /// If the current region is a loop-based region, mark the start of the loop /// construct. void startOpenMPLoop(); /// If the current region is a range loop-based region, mark the start of the /// loop construct. void startOpenMPCXXRangeFor(); /// Check if the specified variable is used in 'private' clause. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. OpenMPClauseKind isOpenMPPrivateDecl(ValueDecl *D, unsigned Level, unsigned CapLevel) const; /// Sets OpenMP capture kind (OMPC_private, OMPC_firstprivate, OMPC_map etc.) /// for \p FD based on DSA for the provided corresponding captured declaration /// \p D. void setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D, unsigned Level); /// Check if the specified variable is captured by 'target' directive. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. bool isOpenMPTargetCapturedDecl(const ValueDecl *D, unsigned Level, unsigned CaptureLevel) const; /// Check if the specified global variable must be captured by outer capture /// regions. /// \param Level Relative level of nested OpenMP construct for that /// the check is performed. bool isOpenMPGlobalCapturedDecl(ValueDecl *D, unsigned Level, unsigned CaptureLevel) const; ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); /// Called on start of new data sharing attribute block. void StartOpenMPDSABlock(OpenMPDirectiveKind K, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc); /// Start analysis of clauses. void StartOpenMPClause(OpenMPClauseKind K); /// End analysis of clauses. void EndOpenMPClause(); /// Called on end of data sharing attribute block. void EndOpenMPDSABlock(Stmt *CurDirective); /// Check if the current region is an OpenMP loop region and if it is, /// mark loop control variable, used in \p Init for loop initialization, as /// private by default. /// \param Init First part of the for loop. void ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init); // OpenMP directives and clauses. /// Called on correct id-expression from the '#pragma omp /// threadprivate'. ExprResult ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id, OpenMPDirectiveKind Kind); /// Called on well-formed '#pragma omp threadprivate'. DeclGroupPtrTy ActOnOpenMPThreadprivateDirective( SourceLocation Loc, ArrayRef VarList); /// Builds a new OpenMPThreadPrivateDecl and checks its correctness. OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef VarList); /// Called on well-formed '#pragma omp allocate'. DeclGroupPtrTy ActOnOpenMPAllocateDirective(SourceLocation Loc, ArrayRef VarList, ArrayRef Clauses, DeclContext *Owner = nullptr); /// Called on well-formed '#pragma omp requires'. DeclGroupPtrTy ActOnOpenMPRequiresDirective(SourceLocation Loc, ArrayRef ClauseList); /// Check restrictions on Requires directive OMPRequiresDecl *CheckOMPRequiresDecl(SourceLocation Loc, ArrayRef Clauses); /// Check if the specified type is allowed to be used in 'omp declare /// reduction' construct. QualType ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, TypeResult ParsedType); /// Called on start of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveStart( Scope *S, DeclContext *DC, DeclarationName Name, ArrayRef> ReductionTypes, AccessSpecifier AS, Decl *PrevDeclInScope = nullptr); /// Initialize declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D); /// Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner); /// Initialize declare reduction construct initializer. /// \return omp_priv variable. VarDecl *ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D); /// Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer, VarDecl *OmpPrivParm); /// Called at the end of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd( Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid); /// Check variable declaration in 'omp declare mapper' construct. TypeResult ActOnOpenMPDeclareMapperVarDecl(Scope *S, Declarator &D); /// Check if the specified type is allowed to be used in 'omp declare /// mapper' construct. QualType ActOnOpenMPDeclareMapperType(SourceLocation TyLoc, TypeResult ParsedType); /// Called on start of '#pragma omp declare mapper'. OMPDeclareMapperDecl *ActOnOpenMPDeclareMapperDirectiveStart( Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType, SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS, Decl *PrevDeclInScope = nullptr); /// Build the mapper variable of '#pragma omp declare mapper'. void ActOnOpenMPDeclareMapperDirectiveVarDecl(OMPDeclareMapperDecl *DMD, Scope *S, QualType MapperType, SourceLocation StartLoc, DeclarationName VN); /// Called at the end of '#pragma omp declare mapper'. DeclGroupPtrTy ActOnOpenMPDeclareMapperDirectiveEnd(OMPDeclareMapperDecl *D, Scope *S, ArrayRef ClauseList); /// Called on the start of target region i.e. '#pragma omp declare target'. bool ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc); /// Called at the end of target region i.e. '#pragme omp end declare target'. void ActOnFinishOpenMPDeclareTargetDirective(); /// Searches for the provided declaration name for OpenMP declare target /// directive. NamedDecl * lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id, NamedDeclSetType &SameDirectiveDecls); /// Called on correct id-expression from the '#pragma omp declare target'. void ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc, OMPDeclareTargetDeclAttr::MapTypeTy MT, OMPDeclareTargetDeclAttr::DevTypeTy DT); /// Check declaration inside target region. void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, SourceLocation IdLoc = SourceLocation()); /// Finishes analysis of the deferred functions calls that may be declared as /// host/nohost during device/host compilation. void finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, const FunctionDecl *Callee, SourceLocation Loc); /// Return true inside OpenMP declare target region. bool isInOpenMPDeclareTargetContext() const { return DeclareTargetNestingLevel > 0; } /// Return true inside OpenMP target region. bool isInOpenMPTargetExecutionDirective() const; /// Return the number of captured regions created for an OpenMP directive. static int getOpenMPCaptureLevels(OpenMPDirectiveKind Kind); /// Initialization of captured region for OpenMP region. void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); /// End of OpenMP region. /// /// \param S Statement associated with the current OpenMP region. /// \param Clauses List of clauses for the current OpenMP region. /// /// \returns Statement for finished OpenMP region. StmtResult ActOnOpenMPRegionEnd(StmtResult S, ArrayRef Clauses); StmtResult ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp parallel' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); using VarsWithInheritedDSAType = llvm::SmallDenseMap; /// Called on well-formed '\#pragma omp simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPSimdDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp for' after parsing /// of the associated statement. StmtResult ActOnOpenMPForDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp for simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPForSimdDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp sections' after parsing /// of the associated statement. StmtResult ActOnOpenMPSectionsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp section' after parsing of the /// associated statement. StmtResult ActOnOpenMPSectionDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp single' after parsing of the /// associated statement. StmtResult ActOnOpenMPSingleDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp master' after parsing of the /// associated statement. StmtResult ActOnOpenMPMasterDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp critical' after parsing of the /// associated statement. StmtResult ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp parallel for' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp parallel for simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp parallel master' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelMasterDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp parallel sections' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelSectionsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp task' after parsing of the /// associated statement. StmtResult ActOnOpenMPTaskDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp taskyield'. StmtResult ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp barrier'. StmtResult ActOnOpenMPBarrierDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp taskwait'. StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp taskgroup'. StmtResult ActOnOpenMPTaskgroupDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp flush'. StmtResult ActOnOpenMPFlushDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp depobj'. StmtResult ActOnOpenMPDepobjDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp scan'. StmtResult ActOnOpenMPScanDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp ordered' after parsing of the /// associated statement. StmtResult ActOnOpenMPOrderedDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp atomic' after parsing of the /// associated statement. StmtResult ActOnOpenMPAtomicDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target' after parsing of the /// associated statement. StmtResult ActOnOpenMPTargetDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target data' after parsing of /// the associated statement. StmtResult ActOnOpenMPTargetDataDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target enter data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetEnterDataDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AStmt); /// Called on well-formed '\#pragma omp target exit data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetExitDataDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AStmt); /// Called on well-formed '\#pragma omp target parallel' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams' after parsing of the /// associated statement. StmtResult ActOnOpenMPTeamsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp cancellation point'. StmtResult ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); /// Called on well-formed '\#pragma omp cancel'. StmtResult ActOnOpenMPCancelDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); /// Called on well-formed '\#pragma omp taskloop' after parsing of the /// associated statement. StmtResult ActOnOpenMPTaskLoopDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp taskloop simd' after parsing of /// the associated statement. StmtResult ActOnOpenMPTaskLoopSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp master taskloop' after parsing of the /// associated statement. StmtResult ActOnOpenMPMasterTaskLoopDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp master taskloop simd' after parsing of /// the associated statement. StmtResult ActOnOpenMPMasterTaskLoopSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp parallel master taskloop' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelMasterTaskLoopDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp parallel master taskloop simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelMasterTaskLoopSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp distribute' after parsing /// of the associated statement. StmtResult ActOnOpenMPDistributeDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target update'. StmtResult ActOnOpenMPTargetUpdateDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AStmt); /// Called on well-formed '\#pragma omp distribute parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp distribute parallel for simd' /// after parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp distribute simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target parallel for simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target simd' after parsing of /// the associated statement. StmtResult ActOnOpenMPTargetSimdDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute' after parsing of /// the associated statement. StmtResult ActOnOpenMPTeamsDistributeDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPTeamsDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute parallel for simd' /// after parsing of the associated statement. StmtResult ActOnOpenMPTeamsDistributeParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute parallel for' /// after parsing of the associated statement. StmtResult ActOnOpenMPTeamsDistributeParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams' after parsing of the /// associated statement. StmtResult ActOnOpenMPTargetTeamsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target teams distribute' after parsing /// of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute parallel for' /// after parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute parallel for /// simd' after parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Checks correctness of linear modifiers. bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, SourceLocation LinLoc); /// Checks that the specified declaration matches requirements for the linear /// decls. bool CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc, OpenMPLinearClauseKind LinKind, QualType Type, bool IsDeclareSimd = false); /// Called on well-formed '\#pragma omp declare simd' after parsing of /// the associated method/function. DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective( DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen, ArrayRef Uniforms, ArrayRef Aligneds, ArrayRef Alignments, ArrayRef Linears, ArrayRef LinModifiers, ArrayRef Steps, SourceRange SR); /// Checks '\#pragma omp declare variant' variant function and original /// functions after parsing of the associated method/function. /// \param DG Function declaration to which declare variant directive is /// applied to. /// \param VariantRef Expression that references the variant function, which /// must be used instead of the original one, specified in \p DG. /// \param TI The trait info object representing the match clause. /// \returns None, if the function/variant function are not compatible with /// the pragma, pair of original function/variant ref expression otherwise. Optional> checkOpenMPDeclareVariantFunction(DeclGroupPtrTy DG, Expr *VariantRef, OMPTraitInfo &TI, SourceRange SR); /// Called on well-formed '\#pragma omp declare variant' after parsing of /// the associated method/function. /// \param FD Function declaration to which declare variant directive is /// applied to. /// \param VariantRef Expression that references the variant function, which /// must be used instead of the original one, specified in \p DG. /// \param TI The context traits associated with the function variant. void ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, SourceRange SR); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'allocator' clause. OMPClause *ActOnOpenMPAllocatorClause(Expr *Allocator, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'if' clause. OMPClause *ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation NameModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// Called on well-formed 'final' clause. OMPClause *ActOnOpenMPFinalClause(Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'num_threads' clause. OMPClause *ActOnOpenMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'safelen' clause. OMPClause *ActOnOpenMPSafelenClause(Expr *Length, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'simdlen' clause. OMPClause *ActOnOpenMPSimdlenClause(Expr *Length, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'collapse' clause. OMPClause *ActOnOpenMPCollapseClause(Expr *NumForLoops, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'ordered' clause. OMPClause * ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc, SourceLocation LParenLoc = SourceLocation(), Expr *NumForLoops = nullptr); /// Called on well-formed 'grainsize' clause. OMPClause *ActOnOpenMPGrainsizeClause(Expr *Size, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'num_tasks' clause. OMPClause *ActOnOpenMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'hint' clause. OMPClause *ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'detach' clause. OMPClause *ActOnOpenMPDetachClause(Expr *Evt, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'default' clause. OMPClause *ActOnOpenMPDefaultClause(llvm::omp::DefaultKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'proc_bind' clause. OMPClause *ActOnOpenMPProcBindClause(llvm::omp::ProcBindKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'order' clause. OMPClause *ActOnOpenMPOrderClause(OpenMPOrderClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'update' clause. OMPClause *ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPSingleExprWithArgClause( OpenMPClauseKind Kind, ArrayRef Arguments, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, ArrayRef ArgumentsLoc, SourceLocation DelimLoc, SourceLocation EndLoc); /// Called on well-formed 'schedule' clause. OMPClause *ActOnOpenMPScheduleClause( OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'nowait' clause. OMPClause *ActOnOpenMPNowaitClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'untied' clause. OMPClause *ActOnOpenMPUntiedClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'mergeable' clause. OMPClause *ActOnOpenMPMergeableClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'read' clause. OMPClause *ActOnOpenMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'write' clause. OMPClause *ActOnOpenMPWriteClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'update' clause. OMPClause *ActOnOpenMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'capture' clause. OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'seq_cst' clause. OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'acq_rel' clause. OMPClause *ActOnOpenMPAcqRelClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'acquire' clause. OMPClause *ActOnOpenMPAcquireClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'release' clause. OMPClause *ActOnOpenMPReleaseClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'relaxed' clause. OMPClause *ActOnOpenMPRelaxedClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'destroy' clause. OMPClause *ActOnOpenMPDestroyClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'threads' clause. OMPClause *ActOnOpenMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'simd' clause. OMPClause *ActOnOpenMPSIMDClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'nogroup' clause. OMPClause *ActOnOpenMPNogroupClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'unified_address' clause. OMPClause *ActOnOpenMPUnifiedAddressClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'unified_address' clause. OMPClause *ActOnOpenMPUnifiedSharedMemoryClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'reverse_offload' clause. OMPClause *ActOnOpenMPReverseOffloadClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'dynamic_allocators' clause. OMPClause *ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'atomic_default_mem_order' clause. OMPClause *ActOnOpenMPAtomicDefaultMemOrderClause( OpenMPAtomicDefaultMemOrderClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef Vars, Expr *DepModOrTailExpr, const OMPVarListLocTy &Locs, SourceLocation ColonLoc, CXXScopeSpec &ReductionOrMapperIdScopeSpec, DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, ArrayRef MapTypeModifiers, ArrayRef MapTypeModifiersLoc, bool IsMapTypeImplicit, SourceLocation ExtraModifierLoc); /// Called on well-formed 'inclusive' clause. OMPClause *ActOnOpenMPInclusiveClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'exclusive' clause. OMPClause *ActOnOpenMPExclusiveClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'allocate' clause. OMPClause * ActOnOpenMPAllocateClause(Expr *Allocator, ArrayRef VarList, SourceLocation StartLoc, SourceLocation ColonLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'private' clause. OMPClause *ActOnOpenMPPrivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'firstprivate' clause. OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'lastprivate' clause. OMPClause *ActOnOpenMPLastprivateClause( ArrayRef VarList, OpenMPLastprivateModifier LPKind, SourceLocation LPKindLoc, SourceLocation ColonLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'shared' clause. OMPClause *ActOnOpenMPSharedClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'reduction' clause. OMPClause *ActOnOpenMPReductionClause( ArrayRef VarList, OpenMPReductionClauseModifier Modifier, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions = llvm::None); /// Called on well-formed 'task_reduction' clause. OMPClause *ActOnOpenMPTaskReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions = llvm::None); /// Called on well-formed 'in_reduction' clause. OMPClause *ActOnOpenMPInReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions = llvm::None); /// Called on well-formed 'linear' clause. OMPClause * ActOnOpenMPLinearClause(ArrayRef VarList, Expr *Step, SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind, SourceLocation LinLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// Called on well-formed 'aligned' clause. OMPClause *ActOnOpenMPAlignedClause(ArrayRef VarList, Expr *Alignment, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// Called on well-formed 'copyin' clause. OMPClause *ActOnOpenMPCopyinClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'copyprivate' clause. OMPClause *ActOnOpenMPCopyprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'flush' pseudo clause. OMPClause *ActOnOpenMPFlushClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'depobj' pseudo clause. OMPClause *ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'depend' clause. OMPClause * ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'device' clause. OMPClause *ActOnOpenMPDeviceClause(OpenMPDeviceClauseModifier Modifier, Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ModifierLoc, SourceLocation EndLoc); /// Called on well-formed 'map' clause. OMPClause * ActOnOpenMPMapClause(ArrayRef MapTypeModifiers, ArrayRef MapTypeModifiersLoc, CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef VarList, const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers = llvm::None); /// Called on well-formed 'num_teams' clause. OMPClause *ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'thread_limit' clause. OMPClause *ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'priority' clause. OMPClause *ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'dist_schedule' clause. OMPClause *ActOnOpenMPDistScheduleClause( OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); /// Called on well-formed 'defaultmap' clause. OMPClause *ActOnOpenMPDefaultmapClause( OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, SourceLocation KindLoc, SourceLocation EndLoc); /// Called on well-formed 'to' clause. OMPClause * ActOnOpenMPToClause(ArrayRef VarList, CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers = llvm::None); /// Called on well-formed 'from' clause. OMPClause *ActOnOpenMPFromClause( ArrayRef VarList, CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers = llvm::None); /// Called on well-formed 'use_device_ptr' clause. OMPClause *ActOnOpenMPUseDevicePtrClause(ArrayRef VarList, const OMPVarListLocTy &Locs); /// Called on well-formed 'use_device_addr' clause. OMPClause *ActOnOpenMPUseDeviceAddrClause(ArrayRef VarList, const OMPVarListLocTy &Locs); /// Called on well-formed 'is_device_ptr' clause. OMPClause *ActOnOpenMPIsDevicePtrClause(ArrayRef VarList, const OMPVarListLocTy &Locs); /// Called on well-formed 'nontemporal' clause. OMPClause *ActOnOpenMPNontemporalClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Data for list of allocators. struct UsesAllocatorsData { /// Allocator. Expr *Allocator = nullptr; /// Allocator traits. Expr *AllocatorTraits = nullptr; /// Locations of '(' and ')' symbols. SourceLocation LParenLoc, RParenLoc; }; /// Called on well-formed 'uses_allocators' clause. OMPClause *ActOnOpenMPUsesAllocatorClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef Data); /// Called on well-formed 'affinity' clause. OMPClause *ActOnOpenMPAffinityClause(SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, Expr *Modifier, ArrayRef Locators); /// The kind of conversion being performed. enum CheckedConversionKind { /// An implicit conversion. CCK_ImplicitConversion, /// A C-style cast. CCK_CStyleCast, /// A functional-style cast. CCK_FunctionalCast, /// A cast other than a C-style cast. CCK_OtherCast, /// A conversion for an operand of a builtin overloaded operator. CCK_ForBuiltinOverloadedOp }; static bool isCast(CheckedConversionKind CCK) { return CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast || CCK == CCK_OtherCast; } /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK, ExprValueKind VK = VK_RValue, const CXXCastPath *BasePath = nullptr, CheckedConversionKind CCK = CCK_ImplicitConversion); /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding /// to the conversion from scalar type ScalarTy to the Boolean type. static CastKind ScalarTypeToBooleanCastKind(QualType ScalarTy); /// IgnoredValueConversions - Given that an expression's result is /// syntactically ignored, perform any conversions that are /// required. ExprResult IgnoredValueConversions(Expr *E); // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). ExprResult UsualUnaryConversions(Expr *E); /// CallExprUnaryConversions - a special case of an unary conversion /// performed on a function designator of a call expression. ExprResult CallExprUnaryConversions(Expr *E); // DefaultFunctionArrayConversion - converts functions and arrays // to their respective pointers (C99 6.3.2.1). ExprResult DefaultFunctionArrayConversion(Expr *E, bool Diagnose = true); // DefaultFunctionArrayLvalueConversion - converts functions and // arrays to their respective pointers and performs the // lvalue-to-rvalue conversion. ExprResult DefaultFunctionArrayLvalueConversion(Expr *E, bool Diagnose = true); // DefaultLvalueConversion - performs lvalue-to-rvalue conversion on // the operand. This function is a no-op if the operand has a function type // or an array type. ExprResult DefaultLvalueConversion(Expr *E); // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that // do not have a prototype. Integer promotions are performed on each // argument, and arguments that have type float are promoted to double. ExprResult DefaultArgumentPromotion(Expr *E); /// If \p E is a prvalue denoting an unmaterialized temporary, materialize /// it as an xvalue. In C++98, the result will still be a prvalue, because /// we don't have xvalues there. ExprResult TemporaryMaterializationConversion(Expr *E); // Used for emitting the right warning by DefaultVariadicArgumentPromotion enum VariadicCallType { VariadicFunction, VariadicBlock, VariadicMethod, VariadicConstructor, VariadicDoesNotApply }; VariadicCallType getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr *Fn); // Used for determining in which context a type is allowed to be passed to a // vararg function. enum VarArgKind { VAK_Valid, VAK_ValidInCXX11, VAK_Undefined, VAK_MSVCUndefined, VAK_Invalid }; // Determines which VarArgKind fits an expression. VarArgKind isValidVarArgType(const QualType &Ty); /// Check to see if the given expression is a valid argument to a variadic /// function, issuing a diagnostic if not. void checkVariadicArgument(const Expr *E, VariadicCallType CT); /// Check to see if a given expression could have '.c_str()' called on it. bool hasCStrMethod(const Expr *E); /// GatherArgumentsForCall - Collector argument expressions for various /// form of call prototypes. bool GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, const FunctionProtoType *Proto, unsigned FirstParam, ArrayRef Args, SmallVectorImpl &AllArgs, VariadicCallType CallType = VariadicDoesNotApply, bool AllowExplicit = false, bool IsListInitialization = false); // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but // will create a runtime trap if the resulting type is not a POD type. ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, FunctionDecl *FDecl); /// Context in which we're performing a usual arithmetic conversion. enum ArithConvKind { /// An arithmetic operation. ACK_Arithmetic, /// A bitwise operation. ACK_BitwiseOp, /// A comparison. ACK_Comparison, /// A conditional (?:) operator. ACK_Conditional, /// A compound assignment expression. ACK_CompAssign, }; // UsualArithmeticConversions - performs the UsualUnaryConversions on it's // operands and then handles various conversions that are common to binary // operators (C99 6.3.1.8). If both operands aren't arithmetic, this // routine returns the first non-arithmetic type found. The client is // responsible for emitting appropriate error diagnostics. QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, ArithConvKind ACK); /// AssignConvertType - All of the 'assignment' semantic checks return this /// enum to indicate whether the assignment was allowed. These checks are /// done for simple assignments, as well as initialization, return from /// function, argument passing, etc. The query is phrased in terms of a /// source and destination type. enum AssignConvertType { /// Compatible - the types are compatible according to the standard. Compatible, /// PointerToInt - The assignment converts a pointer to an int, which we /// accept as an extension. PointerToInt, /// IntToPointer - The assignment converts an int to a pointer, which we /// accept as an extension. IntToPointer, /// FunctionVoidPointer - The assignment is between a function pointer and /// void*, which the standard doesn't allow, but we accept as an extension. FunctionVoidPointer, /// IncompatiblePointer - The assignment is between two pointers types that /// are not compatible, but we accept them as an extension. IncompatiblePointer, /// IncompatibleFunctionPointer - The assignment is between two function /// pointers types that are not compatible, but we accept them as an /// extension. IncompatibleFunctionPointer, /// IncompatiblePointerSign - The assignment is between two pointers types /// which point to integers which have a different sign, but are otherwise /// identical. This is a subset of the above, but broken out because it's by /// far the most common case of incompatible pointers. IncompatiblePointerSign, /// CompatiblePointerDiscardsQualifiers - The assignment discards /// c/v/r qualifiers, which we accept as an extension. CompatiblePointerDiscardsQualifiers, /// IncompatiblePointerDiscardsQualifiers - The assignment /// discards qualifiers that we don't permit to be discarded, /// like address spaces. IncompatiblePointerDiscardsQualifiers, /// IncompatibleNestedPointerAddressSpaceMismatch - The assignment /// changes address spaces in nested pointer types which is not allowed. /// For instance, converting __private int ** to __generic int ** is /// illegal even though __private could be converted to __generic. IncompatibleNestedPointerAddressSpaceMismatch, /// IncompatibleNestedPointerQualifiers - The assignment is between two /// nested pointer types, and the qualifiers other than the first two /// levels differ e.g. char ** -> const char **, but we accept them as an /// extension. IncompatibleNestedPointerQualifiers, /// IncompatibleVectors - The assignment is between two vector types that /// have the same size, which we accept as an extension. IncompatibleVectors, /// IntToBlockPointer - The assignment converts an int to a block /// pointer. We disallow this. IntToBlockPointer, /// IncompatibleBlockPointer - The assignment is between two block /// pointers types that are not compatible. IncompatibleBlockPointer, /// IncompatibleObjCQualifiedId - The assignment is between a qualified /// id type and something else (that is incompatible with it). For example, /// "id " = "Foo *", where "Foo *" doesn't implement the XXX protocol. IncompatibleObjCQualifiedId, /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an /// object with __weak qualifier. IncompatibleObjCWeakRef, /// Incompatible - We reject this conversion outright, it is invalid to /// represent it in the AST. Incompatible }; /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the /// assignment conversion type specified by ConvTy. This returns true if the /// conversion was invalid or false if the conversion was accepted. bool DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, Expr *SrcExpr, AssignmentAction Action, bool *Complained = nullptr); /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag /// enum. If AllowMask is true, then we also allow the complement of a valid /// value, to be used as a mask. bool IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, bool AllowMask) const; /// DiagnoseAssignmentEnum - Warn if assignment to enum is a constant /// integer not in the range of enum values. void DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, Expr *SrcExpr); /// CheckAssignmentConstraints - Perform type checking for assignment, /// argument passing, variable initialization, and function return values. /// C99 6.5.16. AssignConvertType CheckAssignmentConstraints(SourceLocation Loc, QualType LHSType, QualType RHSType); /// Check assignment constraints and optionally prepare for a conversion of /// the RHS to the LHS type. The conversion is prepared for if ConvertRHS /// is true. AssignConvertType CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, CastKind &Kind, bool ConvertRHS = true); /// Check assignment constraints for an assignment of RHS to LHSType. /// /// \param LHSType The destination type for the assignment. /// \param RHS The source expression for the assignment. /// \param Diagnose If \c true, diagnostics may be produced when checking /// for assignability. If a diagnostic is produced, \p RHS will be /// set to ExprError(). Note that this function may still return /// without producing a diagnostic, even for an invalid assignment. /// \param DiagnoseCFAudited If \c true, the target is a function parameter /// in an audited Core Foundation API and does not need to be checked /// for ARC retain issues. /// \param ConvertRHS If \c true, \p RHS will be updated to model the /// conversions necessary to perform the assignment. If \c false, /// \p Diagnose must also be \c false. AssignConvertType CheckSingleAssignmentConstraints( QualType LHSType, ExprResult &RHS, bool Diagnose = true, bool DiagnoseCFAudited = false, bool ConvertRHS = true); // If the lhs type is a transparent union, check whether we // can initialize the transparent union with the given expression. AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &RHS); bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit = false); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit, ImplicitConversionSequence& ICS); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence& ICS, AssignmentAction Action, CheckedConversionKind CCK = CCK_ImplicitConversion); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, CheckedConversionKind CCK); ExprResult PerformQualificationConversion( Expr *E, QualType Ty, ExprValueKind VK = VK_RValue, CheckedConversionKind CCK = CCK_ImplicitConversion); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). /// type checking binary operators (subroutines of CreateBuiltinBinOp). QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS); QualType InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS); QualType CheckPointerToMemberOperands( // C++ 5.5 ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, SourceLocation OpLoc, bool isIndirect); QualType CheckMultiplyDivideOperands( // C99 6.5.5 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool IsDivide); QualType CheckRemainderOperands( // C99 6.5.5 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign = false); QualType CheckAdditionOperands( // C99 6.5.6 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, QualType* CompLHSTy = nullptr); QualType CheckSubtractionOperands( // C99 6.5.6 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, QualType* CompLHSTy = nullptr); QualType CheckShiftOperands( // C99 6.5.7 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, bool IsCompAssign = false); void CheckPtrComparisonWithNullChar(ExprResult &E, ExprResult &NullE); QualType CheckCompareOperands( // C99 6.5.8/9 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); QualType CheckBitwiseOperands( // C99 6.5.[10...12] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); QualType CheckLogicalOperands( // C99 6.5.[13,14] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); // CheckAssignmentOperands is used for both simple and compound assignment. // For simple assignment, pass both expressions and a null converted type. // For compound assignment, pass both expressions and the converted type. QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType); ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opcode, Expr *Op); ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opcode, Expr *LHS, Expr *RHS); ExprResult checkPseudoObjectRValue(Expr *E); Expr *recreateSyntacticForm(PseudoObjectExpr *E); QualType CheckConditionalOperands( // C99 6.5.15 ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc); QualType CXXCheckConditionalOperands( // C++ 5.16 ExprResult &cond, ExprResult &lhs, ExprResult &rhs, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); QualType CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc); QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool ConvertArgs = true); QualType FindCompositePointerType(SourceLocation Loc, ExprResult &E1, ExprResult &E2, bool ConvertArgs = true) { Expr *E1Tmp = E1.get(), *E2Tmp = E2.get(); QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp, ConvertArgs); E1 = E1Tmp; E2 = E2Tmp; return Composite; } QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc); bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, SourceLocation QuestionLoc); void DiagnoseAlwaysNonNullPointer(Expr *E, Expr::NullPointerConstantKind NullType, bool IsEqual, SourceRange Range); /// type checking for vector binary operators. QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool AllowBothBool, bool AllowBoolConversion); QualType GetSignedVectorType(QualType V); QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc); /// Type checking for matrix binary operators. QualType CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign); QualType CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign); bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType); bool isLaxVectorConversion(QualType srcType, QualType destType); /// type checking declaration initializers (C99 6.7.8) bool CheckForConstantInitializer(Expr *e, QualType t); // type checking C++ declaration initializers (C++ [dcl.init]). /// ReferenceCompareResult - Expresses the result of comparing two /// types (cv1 T1 and cv2 T2) to determine their compatibility for the /// purposes of initialization by reference (C++ [dcl.init.ref]p4). enum ReferenceCompareResult { /// Ref_Incompatible - The two types are incompatible, so direct /// reference binding is not possible. Ref_Incompatible = 0, /// Ref_Related - The two types are reference-related, which means /// that their unqualified forms (T1 and T2) are either the same /// or T1 is a base class of T2. Ref_Related, /// Ref_Compatible - The two types are reference-compatible. Ref_Compatible }; // Fake up a scoped enumeration that still contextually converts to bool. struct ReferenceConversionsScope { /// The conversions that would be performed on an lvalue of type T2 when /// binding a reference of type T1 to it, as determined when evaluating /// whether T1 is reference-compatible with T2. enum ReferenceConversions { Qualification = 0x1, NestedQualification = 0x2, Function = 0x4, DerivedToBase = 0x8, ObjC = 0x10, ObjCLifetime = 0x20, LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ObjCLifetime) }; }; using ReferenceConversions = ReferenceConversionsScope::ReferenceConversions; ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2, ReferenceConversions *Conv = nullptr); ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, Expr *CastExpr, CastKind &CastKind, ExprValueKind &VK, CXXCastPath &Path); /// Force an expression with unknown-type to an expression of the /// given type. ExprResult forceUnknownAnyToType(Expr *E, QualType ToType); /// Type-check an expression that's being passed to an /// __unknown_anytype parameter. ExprResult checkUnknownAnyArg(SourceLocation callLoc, Expr *result, QualType ¶mType); // CheckVectorCast - check type constraints for vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size. // returns true if the cast is invalid bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, CastKind &Kind); /// Prepare `SplattedExpr` for a vector splat operation, adding /// implicit casts if necessary. ExprResult prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr); // CheckExtVectorCast - check type constraints for extended vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size, // or vectors and the element type of that vector. // returns the cast expr ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr, CastKind &Kind); ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, QualType Type, SourceLocation LParenLoc, Expr *CastExpr, SourceLocation RParenLoc); enum ARCConversionResult { ACR_okay, ACR_unbridged, ACR_error }; /// Checks for invalid conversions and casts between /// retainable pointers and other pointer kinds for ARC and Weak. ARCConversionResult CheckObjCConversion(SourceRange castRange, QualType castType, Expr *&op, CheckedConversionKind CCK, bool Diagnose = true, bool DiagnoseCFAudited = false, BinaryOperatorKind Opc = BO_PtrMemD ); Expr *stripARCUnbridgedCast(Expr *e); void diagnoseARCUnbridgedCast(Expr *e); bool CheckObjCARCUnavailableWeakConversion(QualType castType, QualType ExprType); /// checkRetainCycles - Check whether an Objective-C message send /// might create an obvious retain cycle. void checkRetainCycles(ObjCMessageExpr *msg); void checkRetainCycles(Expr *receiver, Expr *argument); void checkRetainCycles(VarDecl *Var, Expr *Init); /// checkUnsafeAssigns - Check whether +1 expr is being assigned /// to weak/__unsafe_unretained type. bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS); /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned /// to weak/__unsafe_unretained expression. void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS); /// CheckMessageArgumentTypes - Check types in an Obj-C message send. /// \param Method - May be null. /// \param [out] ReturnType - The return type of the send. /// \return true iff there were any incompatible types. bool CheckMessageArgumentTypes(const Expr *Receiver, QualType ReceiverType, MultiExprArg Args, Selector Sel, ArrayRef SelectorLocs, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, SourceRange RecRange, QualType &ReturnType, ExprValueKind &VK); /// Determine the result of a message send expression based on /// the type of the receiver, the method expected to receive the message, /// and the form of the message send. QualType getMessageSendResultType(const Expr *Receiver, QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage); /// If the given expression involves a message send to a method /// with a related result type, emit a note describing what happened. void EmitRelatedResultTypeNote(const Expr *E); /// Given that we had incompatible pointer types in a return /// statement, check whether we're in a method with a related result /// type, and if so, emit a note describing what happened. void EmitRelatedResultTypeNoteForReturn(QualType destType); class ConditionResult { Decl *ConditionVar; FullExprArg Condition; bool Invalid; bool HasKnownValue; bool KnownValue; friend class Sema; ConditionResult(Sema &S, Decl *ConditionVar, FullExprArg Condition, bool IsConstexpr) : ConditionVar(ConditionVar), Condition(Condition), Invalid(false), HasKnownValue(IsConstexpr && Condition.get() && !Condition.get()->isValueDependent()), KnownValue(HasKnownValue && !!Condition.get()->EvaluateKnownConstInt(S.Context)) {} explicit ConditionResult(bool Invalid) : ConditionVar(nullptr), Condition(nullptr), Invalid(Invalid), HasKnownValue(false), KnownValue(false) {} public: ConditionResult() : ConditionResult(false) {} bool isInvalid() const { return Invalid; } std::pair get() const { return std::make_pair(cast_or_null(ConditionVar), Condition.get()); } llvm::Optional getKnownValue() const { if (!HasKnownValue) return None; return KnownValue; } }; static ConditionResult ConditionError() { return ConditionResult(true); } enum class ConditionKind { Boolean, ///< A boolean condition, from 'if', 'while', 'for', or 'do'. ConstexprIf, ///< A constant boolean condition from 'if constexpr'. Switch ///< An integral condition for a 'switch' statement. }; ConditionResult ActOnCondition(Scope *S, SourceLocation Loc, Expr *SubExpr, ConditionKind CK); ConditionResult ActOnConditionVariable(Decl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK); DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); ExprResult CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK); ExprResult CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond); /// CheckBooleanCondition - Diagnose problems involving the use of /// the given expression as a boolean condition (e.g. in an if /// statement). Also performs the standard function and array /// decays, possibly changing the input variable. /// /// \param Loc - A location associated with the condition, e.g. the /// 'if' keyword. /// \return true iff there were any errors ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E, bool IsConstexpr = false); /// ActOnExplicitBoolSpecifier - Build an ExplicitSpecifier from an expression /// found in an explicit(bool) specifier. ExplicitSpecifier ActOnExplicitBoolSpecifier(Expr *E); /// tryResolveExplicitSpecifier - Attempt to resolve the explict specifier. /// Returns true if the explicit specifier is now resolved. bool tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec); /// DiagnoseAssignmentAsCondition - Given that an expression is /// being used as a boolean condition, warn if it's an assignment. void DiagnoseAssignmentAsCondition(Expr *E); /// Redundant parentheses over an equality comparison can indicate /// that the user intended an assignment used as condition. void DiagnoseEqualityWithExtraParens(ParenExpr *ParenE); /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. ExprResult CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr = false); /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit /// the specified diagnostic. void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, unsigned NewWidth, bool NewSign, SourceLocation Loc, unsigned DiagID); /// Checks that the Objective-C declaration is declared in the global scope. /// Emits an error and marks the declaration as invalid if it's not declared /// in the global scope. bool CheckObjCDeclScope(Decl *D); /// Abstract base class used for diagnosing integer constant /// expression violations. class VerifyICEDiagnoser { public: bool Suppress; VerifyICEDiagnoser(bool Suppress = false) : Suppress(Suppress) { } virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) =0; virtual void diagnoseFold(Sema &S, SourceLocation Loc, SourceRange SR); virtual ~VerifyICEDiagnoser() { } }; /// VerifyIntegerConstantExpression - Verifies that an expression is an ICE, /// and reports the appropriate diagnostics. Returns false on success. /// Can optionally return the value of the expression. ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, VerifyICEDiagnoser &Diagnoser, bool AllowFold = true); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, unsigned DiagID, bool AllowFold = true); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result = nullptr); /// VerifyBitField - verifies that a bit field expression is an ICE and has /// the correct width, and that the field type is valid. /// Returns false on success. /// Can optionally return whether the bit-field is of width 0 ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, bool IsMsStruct, Expr *BitWidth, bool *ZeroWidth = nullptr); private: unsigned ForceCUDAHostDeviceDepth = 0; public: /// Increments our count of the number of times we've seen a pragma forcing /// functions to be __host__ __device__. So long as this count is greater /// than zero, all functions encountered will be __host__ __device__. void PushForceCUDAHostDevice(); /// Decrements our count of the number of times we've seen a pragma forcing /// functions to be __host__ __device__. Returns false if the count is 0 /// before incrementing, so you can emit an error. bool PopForceCUDAHostDevice(); /// Diagnostics that are emitted only if we discover that the given function /// must be codegen'ed. Because handling these correctly adds overhead to /// compilation, this is currently only enabled for CUDA compilations. llvm::DenseMap, std::vector> DeviceDeferredDiags; /// A pair of a canonical FunctionDecl and a SourceLocation. When used as the /// key in a hashtable, both the FD and location are hashed. struct FunctionDeclAndLoc { CanonicalDeclPtr FD; SourceLocation Loc; }; /// FunctionDecls and SourceLocations for which CheckCUDACall has emitted a /// (maybe deferred) "bad call" diagnostic. We use this to avoid emitting the /// same deferred diag twice. llvm::DenseSet LocsWithCUDACallDiags; /// An inverse call graph, mapping known-emitted functions to one of their /// known-emitted callers (plus the location of the call). /// /// Functions that we can tell a priori must be emitted aren't added to this /// map. llvm::DenseMap, /* Caller = */ FunctionDeclAndLoc> DeviceKnownEmittedFns; /// Diagnostic builder for CUDA/OpenMP devices errors which may or may not be /// deferred. /// /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) /// which are not allowed to appear inside __device__ functions and are /// allowed to appear in __host__ __device__ functions only if the host+device /// function is never codegen'ed. /// /// To handle this, we use the notion of "deferred diagnostics", where we /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. /// /// This class lets you emit either a regular diagnostic, a deferred /// diagnostic, or no diagnostic at all, according to an argument you pass to /// its constructor, thus simplifying the process of creating these "maybe /// deferred" diagnostics. class DeviceDiagBuilder { public: enum Kind { /// Emit no diagnostics. K_Nop, /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). K_Immediate, /// Emit the diagnostic immediately, and, if it's a warning or error, also /// emit a call stack showing how this function can be reached by an a /// priori known-emitted function. K_ImmediateWithCallStack, /// Create a deferred diagnostic, which is emitted only if the function /// it's attached to is codegen'ed. Also emit a call stack as with /// K_ImmediateWithCallStack. K_Deferred }; DeviceDiagBuilder(Kind K, SourceLocation Loc, unsigned DiagID, FunctionDecl *Fn, Sema &S); DeviceDiagBuilder(DeviceDiagBuilder &&D); DeviceDiagBuilder(const DeviceDiagBuilder &) = default; ~DeviceDiagBuilder(); /// Convertible to bool: True if we immediately emitted an error, false if /// we didn't emit an error or we created a deferred error. /// /// Example usage: /// /// if (DeviceDiagBuilder(...) << foo << bar) /// return ExprError(); /// /// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably /// want to use these instead of creating a DeviceDiagBuilder yourself. operator bool() const { return ImmediateDiag.hasValue(); } template friend const DeviceDiagBuilder &operator<<(const DeviceDiagBuilder &Diag, const T &Value) { if (Diag.ImmediateDiag.hasValue()) *Diag.ImmediateDiag << Value; else if (Diag.PartialDiagId.hasValue()) Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second << Value; return Diag; } private: Sema &S; SourceLocation Loc; unsigned DiagID; FunctionDecl *Fn; bool ShowCallStack; // Invariant: At most one of these Optionals has a value. // FIXME: Switch these to a Variant once that exists. llvm::Optional ImmediateDiag; llvm::Optional PartialDiagId; }; /// Creates a DeviceDiagBuilder that emits the diagnostic if the current context /// is "used as device code". /// /// - If CurContext is a __host__ function, does not emit any diagnostics. /// - If CurContext is a __device__ or __global__ function, emits the /// diagnostics immediately. /// - If CurContext is a __host__ __device__ function and we are compiling for /// the device, creates a diagnostic which is emitted if and when we realize /// that the function will be codegen'ed. /// /// Example usage: /// /// // Variable-length arrays are not allowed in CUDA device code. /// if (CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget()) /// return ExprError(); /// // Otherwise, continue parsing as normal. DeviceDiagBuilder CUDADiagIfDeviceCode(SourceLocation Loc, unsigned DiagID); /// Creates a DeviceDiagBuilder that emits the diagnostic if the current context /// is "used as host code". /// /// Same as CUDADiagIfDeviceCode, with "host" and "device" switched. DeviceDiagBuilder CUDADiagIfHostCode(SourceLocation Loc, unsigned DiagID); /// Creates a DeviceDiagBuilder that emits the diagnostic if the current /// context is "used as device code". /// /// - If CurContext is a `declare target` function or it is known that the /// function is emitted for the device, emits the diagnostics immediately. /// - If CurContext is a non-`declare target` function and we are compiling /// for the device, creates a diagnostic which is emitted if and when we /// realize that the function will be codegen'ed. /// /// Example usage: /// /// // Variable-length arrays are not allowed in NVPTX device code. /// if (diagIfOpenMPDeviceCode(Loc, diag::err_vla_unsupported)) /// return ExprError(); /// // Otherwise, continue parsing as normal. DeviceDiagBuilder diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID); /// Creates a DeviceDiagBuilder that emits the diagnostic if the current /// context is "used as host code". /// /// - If CurContext is a `declare target` function or it is known that the /// function is emitted for the host, emits the diagnostics immediately. /// - If CurContext is a non-host function, just ignore it. /// /// Example usage: /// /// // Variable-length arrays are not allowed in NVPTX device code. /// if (diagIfOpenMPHostode(Loc, diag::err_vla_unsupported)) /// return ExprError(); /// // Otherwise, continue parsing as normal. DeviceDiagBuilder diagIfOpenMPHostCode(SourceLocation Loc, unsigned DiagID); DeviceDiagBuilder targetDiag(SourceLocation Loc, unsigned DiagID); /// Check if the expression is allowed to be used in expressions for the /// offloading devices. void checkDeviceDecl(const ValueDecl *D, SourceLocation Loc); enum CUDAFunctionTarget { CFT_Device, CFT_Global, CFT_Host, CFT_HostDevice, CFT_InvalidTarget }; /// Determines whether the given function is a CUDA device/host/kernel/etc. /// function. /// /// Use this rather than examining the function's attributes yourself -- you /// will get it wrong. Returns CFT_Host if D is null. CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D, bool IgnoreImplicitHDAttr = false); CUDAFunctionTarget IdentifyCUDATarget(const ParsedAttributesView &Attrs); /// Gets the CUDA target for the current context. CUDAFunctionTarget CurrentCUDATarget() { return IdentifyCUDATarget(dyn_cast(CurContext)); } static bool isCUDAImplicitHostDeviceFunction(const FunctionDecl *D); // CUDA function call preference. Must be ordered numerically from // worst to best. enum CUDAFunctionPreference { CFP_Never, // Invalid caller/callee combination. CFP_WrongSide, // Calls from host-device to host or device // function that do not match current compilation // mode. CFP_HostDevice, // Any calls to host/device functions. CFP_SameSide, // Calls from host-device to host or device // function matching current compilation mode. CFP_Native, // host-to-host or device-to-device calls. }; /// Identifies relative preference of a given Caller/Callee /// combination, based on their host/device attributes. /// \param Caller function which needs address of \p Callee. /// nullptr in case of global context. /// \param Callee target function /// /// \returns preference value for particular Caller/Callee combination. CUDAFunctionPreference IdentifyCUDAPreference(const FunctionDecl *Caller, const FunctionDecl *Callee); /// Determines whether Caller may invoke Callee, based on their CUDA /// host/device attributes. Returns false if the call is not allowed. /// /// Note: Will return true for CFP_WrongSide calls. These may appear in /// semantically correct CUDA programs, but only if they're never codegen'ed. bool IsAllowedCUDACall(const FunctionDecl *Caller, const FunctionDecl *Callee) { return IdentifyCUDAPreference(Caller, Callee) != CFP_Never; } /// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to FD, /// depending on FD and the current compilation settings. void maybeAddCUDAHostDeviceAttrs(FunctionDecl *FD, const LookupResult &Previous); /// May add implicit CUDAConstantAttr attribute to VD, depending on VD /// and current compilation settings. void MaybeAddCUDAConstantAttr(VarDecl *VD); public: /// Check whether we're allowed to call Callee from the current context. /// /// - If the call is never allowed in a semantically-correct program /// (CFP_Never), emits an error and returns false. /// /// - If the call is allowed in semantically-correct programs, but only if /// it's never codegen'ed (CFP_WrongSide), creates a deferred diagnostic to /// be emitted if and when the caller is codegen'ed, and returns true. /// /// Will only create deferred diagnostics for a given SourceLocation once, /// so you can safely call this multiple times without generating duplicate /// deferred errors. /// /// - Otherwise, returns true without emitting any diagnostics. bool CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee); /// Set __device__ or __host__ __device__ attributes on the given lambda /// operator() method. /// /// CUDA lambdas declared inside __device__ or __global__ functions inherit /// the __device__ attribute. Similarly, lambdas inside __host__ __device__ /// functions become __host__ __device__ themselves. void CUDASetLambdaAttrs(CXXMethodDecl *Method); /// Finds a function in \p Matches with highest calling priority /// from \p Caller context and erases all functions with lower /// calling priority. void EraseUnwantedCUDAMatches( const FunctionDecl *Caller, SmallVectorImpl> &Matches); /// Given a implicit special member, infer its CUDA target from the /// calls it needs to make to underlying base/field special members. /// \param ClassDecl the class for which the member is being created. /// \param CSM the kind of special member. /// \param MemberDecl the special member itself. /// \param ConstRHS true if this is a copy operation with a const object on /// its RHS. /// \param Diagnose true if this call should emit diagnostics. /// \return true if there was an error inferring. /// The result of this call is implicit CUDA target attribute(s) attached to /// the member declaration. bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, CXXSpecialMember CSM, CXXMethodDecl *MemberDecl, bool ConstRHS, bool Diagnose); /// \return true if \p CD can be considered empty according to CUDA /// (E.2.3.1 in CUDA 7.5 Programming guide). bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD); bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD); // \brief Checks that initializers of \p Var satisfy CUDA restrictions. In // case of error emits appropriate diagnostic and invalidates \p Var. // // \details CUDA allows only empty constructors as initializers for global // variables (see E.2.3.1, CUDA 7.5). The same restriction also applies to all // __shared__ variables whether they are local or not (they all are implicitly // static in CUDA). One exception is that CUDA allows constant initializers // for __constant__ and __device__ variables. void checkAllowedCUDAInitializer(VarDecl *VD); /// Check whether NewFD is a valid overload for CUDA. Emits /// diagnostics and invalidates NewFD if not. void checkCUDATargetOverload(FunctionDecl *NewFD, const LookupResult &Previous); /// Copies target attributes from the template TD to the function FD. void inheritCUDATargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD); /// Returns the name of the launch configuration function. This is the name /// of the function that will be called to configure kernel call, with the /// parameters specified via <<<>>>. std::string getCudaConfigureFuncName() const; /// \name Code completion //@{ /// Describes the context in which code completion occurs. enum ParserCompletionContext { /// Code completion occurs at top-level or namespace context. PCC_Namespace, /// Code completion occurs within a class, struct, or union. PCC_Class, /// Code completion occurs within an Objective-C interface, protocol, /// or category. PCC_ObjCInterface, /// Code completion occurs within an Objective-C implementation or /// category implementation PCC_ObjCImplementation, /// Code completion occurs within the list of instance variables /// in an Objective-C interface, protocol, category, or implementation. PCC_ObjCInstanceVariableList, /// Code completion occurs following one or more template /// headers. PCC_Template, /// Code completion occurs following one or more template /// headers within a class. PCC_MemberTemplate, /// Code completion occurs within an expression. PCC_Expression, /// Code completion occurs within a statement, which may /// also be an expression or a declaration. PCC_Statement, /// Code completion occurs at the beginning of the /// initialization statement (or expression) in a for loop. PCC_ForInit, /// Code completion occurs within the condition of an if, /// while, switch, or for statement. PCC_Condition, /// Code completion occurs within the body of a function on a /// recovery path, where we do not have a specific handle on our position /// in the grammar. PCC_RecoveryInFunction, /// Code completion occurs where only a type is permitted. PCC_Type, /// Code completion occurs in a parenthesized expression, which /// might also be a type cast. PCC_ParenthesizedExpression, /// Code completion occurs within a sequence of declaration /// specifiers within a function, method, or block. PCC_LocalDeclarationSpecifiers }; void CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path); void CodeCompleteOrdinaryName(Scope *S, ParserCompletionContext CompletionContext); void CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, bool AllowNonIdentifiers, bool AllowNestedNameSpecifiers); struct CodeCompleteExpressionData; void CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData &Data); void CodeCompleteExpression(Scope *S, QualType PreferredType, bool IsParenthesized = false); void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow, bool IsBaseExprStatement, QualType PreferredType); void CodeCompletePostfixExpression(Scope *S, ExprResult LHS, QualType PreferredType); void CodeCompleteTag(Scope *S, unsigned TagSpec); void CodeCompleteTypeQualifiers(DeclSpec &DS); void CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D, const VirtSpecifiers *VS = nullptr); void CodeCompleteBracketDeclarator(Scope *S); void CodeCompleteCase(Scope *S); /// Reports signatures for a call to CodeCompleteConsumer and returns the /// preferred type for the current argument. Returned type can be null. QualType ProduceCallSignatureHelp(Scope *S, Expr *Fn, ArrayRef Args, SourceLocation OpenParLoc); QualType ProduceConstructorSignatureHelp(Scope *S, QualType Type, SourceLocation Loc, ArrayRef Args, SourceLocation OpenParLoc); QualType ProduceCtorInitMemberSignatureHelp(Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, ArrayRef ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc); void CodeCompleteInitializer(Scope *S, Decl *D); /// Trigger code completion for a record of \p BaseType. \p InitExprs are /// expressions in the initializer list seen so far and \p D is the current /// Designation being parsed. void CodeCompleteDesignator(const QualType BaseType, llvm::ArrayRef InitExprs, const Designation &D); - void CodeCompleteAfterIf(Scope *S); + void CodeCompleteAfterIf(Scope *S, bool IsBracedThen); void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext, bool IsUsingDeclaration, QualType BaseType, QualType PreferredType); void CodeCompleteUsing(Scope *S); void CodeCompleteUsingDirective(Scope *S); void CodeCompleteNamespaceDecl(Scope *S); void CodeCompleteNamespaceAliasDecl(Scope *S); void CodeCompleteOperatorName(Scope *S); void CodeCompleteConstructorInitializer( Decl *Constructor, ArrayRef Initializers); void CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, bool AfterAmpersand); void CodeCompleteObjCAtDirective(Scope *S); void CodeCompleteObjCAtVisibility(Scope *S); void CodeCompleteObjCAtStatement(Scope *S); void CodeCompleteObjCAtExpression(Scope *S); void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); void CodeCompleteObjCPropertyGetter(Scope *S); void CodeCompleteObjCPropertySetter(Scope *S); void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, bool IsParameter); void CodeCompleteObjCMessageReceiver(Scope *S); void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, ArrayRef SelIdents, bool AtArgumentExpression); void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper = false); void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, ArrayRef SelIdents, bool AtArgumentExpression, ObjCInterfaceDecl *Super = nullptr); void CodeCompleteObjCForCollection(Scope *S, DeclGroupPtrTy IterationVar); void CodeCompleteObjCSelector(Scope *S, ArrayRef SelIdents); void CodeCompleteObjCProtocolReferences( ArrayRef Protocols); void CodeCompleteObjCProtocolDecl(Scope *S); void CodeCompleteObjCInterfaceDecl(Scope *S); void CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCImplementationDecl(Scope *S); void CodeCompleteObjCInterfaceCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCImplementationCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCPropertyDefinition(Scope *S); void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName); void CodeCompleteObjCMethodDecl(Scope *S, Optional IsInstanceMethod, ParsedType ReturnType); void CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, bool AtParameterName, ParsedType ReturnType, ArrayRef SelIdents); void CodeCompleteObjCClassPropertyRefExpr(Scope *S, IdentifierInfo &ClassName, SourceLocation ClassNameLoc, bool IsBaseExprStatement); void CodeCompletePreprocessorDirective(bool InConditional); void CodeCompleteInPreprocessorConditionalExclusion(Scope *S); void CodeCompletePreprocessorMacroName(bool IsDefinition); void CodeCompletePreprocessorExpression(); void CodeCompletePreprocessorMacroArgument(Scope *S, IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned Argument); void CodeCompleteIncludedFile(llvm::StringRef Dir, bool IsAngled); void CodeCompleteNaturalLanguage(); void CodeCompleteAvailabilityPlatformName(); void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, SmallVectorImpl &Results); //@} //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system public: SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, unsigned ByteNo) const; private: void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE=nullptr, bool AllowOnePastEnd=true, bool IndexNegated=false); void CheckArrayAccess(const Expr *E); // Used to grab the relevant information from a FormatAttr and a // FunctionDeclaration. struct FormatStringInfo { unsigned FormatIdx; unsigned FirstDataArg; bool HasVAListArg; }; static bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, FormatStringInfo *FSI); bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, const FunctionProtoType *Proto); bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc, ArrayRef Args); bool CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, const FunctionProtoType *Proto); bool CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto); void CheckConstructorCall(FunctionDecl *FDecl, ArrayRef Args, const FunctionProtoType *Proto, SourceLocation Loc); void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, const Expr *ThisArg, ArrayRef Args, bool IsMemberFunction, SourceLocation Loc, SourceRange Range, VariadicCallType CallType); bool CheckObjCString(Expr *Arg); ExprResult CheckOSLogFormatStringArg(Expr *Arg); ExprResult CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall); bool CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); void checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, CallExpr *TheCall); bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, unsigned MaxWidth); bool CheckNeonBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckARMCoprocessorImmediate(const TargetInfo &TI, const Expr *CoprocArg, bool WantCDE); bool CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); bool CheckMipsBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); bool SemaBuiltinVSX(CallExpr *TheCall); bool SemaBuiltinOSLogFormat(CallExpr *TheCall); public: // Used by C++ template instantiation. ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, SourceLocation BuiltinLoc, SourceLocation RParenLoc); private: bool SemaBuiltinPrefetch(CallExpr *TheCall); bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall); bool SemaBuiltinAssume(CallExpr *TheCall); bool SemaBuiltinAssumeAligned(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); bool SemaBuiltinSetjmp(CallExpr *TheCall); ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); ExprResult SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult); ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op); ExprResult SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, bool IsDelete); bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High, bool RangeIsError = true); bool SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, unsigned Multiple); bool SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum); bool SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, unsigned ArgBits); bool SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, unsigned ArgBits); bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum, unsigned ExpectedFieldNum, bool AllowName); bool SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall); // Matrix builtin handling. ExprResult SemaBuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult); ExprResult SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, ExprResult CallResult); ExprResult SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, ExprResult CallResult); public: enum FormatStringType { FST_Scanf, FST_Printf, FST_NSString, FST_Strftime, FST_Strfmon, FST_Kprintf, FST_FreeBSDKPrintf, FST_OSTrace, FST_OSLog, FST_Unknown }; static FormatStringType GetFormatStringType(const FormatAttr *Format); bool FormatStringHasSArg(const StringLiteral *FExpr); static bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx); private: bool CheckFormatArguments(const FormatAttr *Format, ArrayRef Args, bool IsCXXMember, VariadicCallType CallType, SourceLocation Loc, SourceRange Range, llvm::SmallBitVector &CheckedVarArgs); bool CheckFormatArguments(ArrayRef Args, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, VariadicCallType CallType, SourceLocation Loc, SourceRange range, llvm::SmallBitVector &CheckedVarArgs); void CheckAbsoluteValueFunction(const CallExpr *Call, const FunctionDecl *FDecl); void CheckMaxUnsignedZero(const CallExpr *Call, const FunctionDecl *FDecl); void CheckMemaccessArguments(const CallExpr *Call, unsigned BId, IdentifierInfo *FnName); void CheckStrlcpycatArguments(const CallExpr *Call, IdentifierInfo *FnName); void CheckStrncatArguments(const CallExpr *Call, IdentifierInfo *FnName); void CheckReturnValExpr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc, bool isObjCMethod = false, const AttrVec *Attrs = nullptr, const FunctionDecl *FD = nullptr); public: void CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS); private: void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); void CheckBoolLikeConversion(Expr *E, SourceLocation CC); void CheckForIntOverflow(Expr *E); void CheckUnsequencedOperations(const Expr *E); /// Perform semantic checks on a completed expression. This will either /// be a full-expression or a default argument expression. void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = SourceLocation(), bool IsConstexpr = false); void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, Expr *Init); /// Check if there is a field shadowing. void CheckShadowInheritedFields(const SourceLocation &Loc, DeclarationName FieldName, const CXXRecordDecl *RD, bool DeclIsField = true); /// Check if the given expression contains 'break' or 'continue' /// statement that produces control flow different from GCC. void CheckBreakContinueBinding(Expr *E); /// Check whether receiver is mutable ObjC container which /// attempts to add itself into the container void CheckObjCCircularContainer(ObjCMessageExpr *Message); void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE); void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, bool DeleteWasArrayForm); public: /// Register a magic integral constant to be used as a type tag. void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, uint64_t MagicValue, QualType Type, bool LayoutCompatible, bool MustBeNull); struct TypeTagData { TypeTagData() {} TypeTagData(QualType Type, bool LayoutCompatible, bool MustBeNull) : Type(Type), LayoutCompatible(LayoutCompatible), MustBeNull(MustBeNull) {} QualType Type; /// If true, \c Type should be compared with other expression's types for /// layout-compatibility. unsigned LayoutCompatible : 1; unsigned MustBeNull : 1; }; /// A pair of ArgumentKind identifier and magic value. This uniquely /// identifies the magic value. typedef std::pair TypeTagMagicValue; private: /// A map from magic value to type information. std::unique_ptr> TypeTagForDatatypeMagicValues; /// Peform checks on a call of a function with argument_with_type_tag /// or pointer_with_type_tag attributes. void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, const ArrayRef ExprArgs, SourceLocation CallSiteLoc); /// Check if we are taking the address of a packed field /// as this may be a problem if the pointer value is dereferenced. void CheckAddressOfPackedMember(Expr *rhs); /// The parser's current scope. /// /// The parser maintains this state here. Scope *CurScope; mutable IdentifierInfo *Ident_super; mutable IdentifierInfo *Ident___float128; /// Nullability type specifiers. IdentifierInfo *Ident__Nonnull = nullptr; IdentifierInfo *Ident__Nullable = nullptr; IdentifierInfo *Ident__Null_unspecified = nullptr; IdentifierInfo *Ident_NSError = nullptr; /// The handler for the FileChanged preprocessor events. /// /// Used for diagnostics that implement custom semantic analysis for #include /// directives, like -Wpragma-pack. sema::SemaPPCallbacks *SemaPPCallbackHandler; protected: friend class Parser; friend class InitializationSequence; friend class ASTReader; friend class ASTDeclReader; friend class ASTWriter; public: /// Retrieve the keyword associated IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability); /// The struct behind the CFErrorRef pointer. RecordDecl *CFError = nullptr; /// Retrieve the identifier "NSError". IdentifierInfo *getNSErrorIdent(); /// Retrieve the parser's current scope. /// /// This routine must only be used when it is certain that semantic analysis /// and the parser are in precisely the same context, which is not the case /// when, e.g., we are performing any kind of template instantiation. /// Therefore, the only safe places to use this scope are in the parser /// itself and in routines directly invoked from the parser and *never* from /// template substitution or instantiation. Scope *getCurScope() const { return CurScope; } void incrementMSManglingNumber() const { return CurScope->incrementMSManglingNumber(); } IdentifierInfo *getSuperIdentifier() const; IdentifierInfo *getFloat128Identifier() const; Decl *getObjCDeclContext() const; DeclContext *getCurLexicalContext() const { return OriginalLexicalContext ? OriginalLexicalContext : CurContext; } const DeclContext *getCurObjCLexicalContext() const { const DeclContext *DC = getCurLexicalContext(); // A category implicitly has the attribute of the interface. if (const ObjCCategoryDecl *CatD = dyn_cast(DC)) DC = CatD->getClassInterface(); return DC; } /// Determine the number of levels of enclosing template parameters. This is /// only usable while parsing. Note that this does not include dependent /// contexts in which no template parameters have yet been declared, such as /// in a terse function template or generic lambda before the first 'auto' is /// encountered. unsigned getTemplateDepth(Scope *S) const; /// To be used for checking whether the arguments being passed to /// function exceeds the number of parameters expected for it. static bool TooManyArguments(size_t NumParams, size_t NumArgs, bool PartialOverloading = false) { // We check whether we're just after a comma in code-completion. if (NumArgs > 0 && PartialOverloading) return NumArgs + 1 > NumParams; // If so, we view as an extra argument. return NumArgs > NumParams; } // Emitting members of dllexported classes is delayed until the class // (including field initializers) is fully parsed. SmallVector DelayedDllExportClasses; SmallVector DelayedDllExportMemberFunctions; private: int ParsingClassDepth = 0; class SavePendingParsedClassStateRAII { public: SavePendingParsedClassStateRAII(Sema &S) : S(S) { swapSavedState(); } ~SavePendingParsedClassStateRAII() { assert(S.DelayedOverridingExceptionSpecChecks.empty() && "there shouldn't be any pending delayed exception spec checks"); assert(S.DelayedEquivalentExceptionSpecChecks.empty() && "there shouldn't be any pending delayed exception spec checks"); swapSavedState(); } private: Sema &S; decltype(DelayedOverridingExceptionSpecChecks) SavedOverridingExceptionSpecChecks; decltype(DelayedEquivalentExceptionSpecChecks) SavedEquivalentExceptionSpecChecks; void swapSavedState() { SavedOverridingExceptionSpecChecks.swap( S.DelayedOverridingExceptionSpecChecks); SavedEquivalentExceptionSpecChecks.swap( S.DelayedEquivalentExceptionSpecChecks); } }; /// Helper class that collects misaligned member designations and /// their location info for delayed diagnostics. struct MisalignedMember { Expr *E; RecordDecl *RD; ValueDecl *MD; CharUnits Alignment; MisalignedMember() : E(), RD(), MD(), Alignment() {} MisalignedMember(Expr *E, RecordDecl *RD, ValueDecl *MD, CharUnits Alignment) : E(E), RD(RD), MD(MD), Alignment(Alignment) {} explicit MisalignedMember(Expr *E) : MisalignedMember(E, nullptr, nullptr, CharUnits()) {} bool operator==(const MisalignedMember &m) { return this->E == m.E; } }; /// Small set of gathered accesses to potentially misaligned members /// due to the packed attribute. SmallVector MisalignedMembers; /// Adds an expression to the set of gathered misaligned members. void AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, CharUnits Alignment); public: /// Diagnoses the current set of gathered accesses. This typically /// happens at full expression level. The set is cleared after emitting the /// diagnostics. void DiagnoseMisalignedMembers(); /// This function checks if the expression is in the sef of potentially /// misaligned members and it is converted to some pointer type T with lower /// or equal alignment requirements. If so it removes it. This is used when /// we do not want to diagnose such misaligned access (e.g. in conversions to /// void*). void DiscardMisalignedMemberAddress(const Type *T, Expr *E); /// This function calls Action when it determines that E designates a /// misaligned member due to the packed attribute. This is used to emit /// local diagnostics like in reference binding. void RefersToMemberWithReducedAlignment( Expr *E, llvm::function_ref Action); /// Describes the reason a calling convention specification was ignored, used /// for diagnostics. enum class CallingConventionIgnoredReason { ForThisTarget = 0, VariadicFunction, ConstructorDestructor, BuiltinFunction }; /// Creates a DeviceDiagBuilder that emits the diagnostic if the current /// context is "used as device code". /// /// - If CurLexicalContext is a kernel function or it is known that the /// function will be emitted for the device, emits the diagnostics /// immediately. /// - If CurLexicalContext is a function and we are compiling /// for the device, but we don't know that this function will be codegen'ed /// for devive yet, creates a diagnostic which is emitted if and when we /// realize that the function will be codegen'ed. /// /// Example usage: /// /// Diagnose __float128 type usage only from SYCL device code if the current /// target doesn't support it /// if (!S.Context.getTargetInfo().hasFloat128Type() && /// S.getLangOpts().SYCLIsDevice) /// SYCLDiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128"; DeviceDiagBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, unsigned DiagID); /// Check whether we're allowed to call Callee from the current context. /// /// - If the call is never allowed in a semantically-correct program /// emits an error and returns false. /// /// - If the call is allowed in semantically-correct programs, but only if /// it's never codegen'ed, creates a deferred diagnostic to be emitted if /// and when the caller is codegen'ed, and returns true. /// /// - Otherwise, returns true without emitting any diagnostics. /// /// Adds Callee to DeviceCallGraph if we don't know if its caller will be /// codegen'ed yet. bool checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee); }; /// RAII object that enters a new expression evaluation context. class EnterExpressionEvaluationContext { Sema &Actions; bool Entered = true; public: EnterExpressionEvaluationContext( Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = Sema::ExpressionEvaluationContextRecord::EK_Other, bool ShouldEnter = true) : Actions(Actions), Entered(ShouldEnter) { if (Entered) Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, ExprContext); } EnterExpressionEvaluationContext( Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Sema::ReuseLambdaContextDecl_t, Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = Sema::ExpressionEvaluationContextRecord::EK_Other) : Actions(Actions) { Actions.PushExpressionEvaluationContext( NewContext, Sema::ReuseLambdaContextDecl, ExprContext); } enum InitListTag { InitList }; EnterExpressionEvaluationContext(Sema &Actions, InitListTag, bool ShouldEnter = true) : Actions(Actions), Entered(false) { // In C++11 onwards, narrowing checks are performed on the contents of // braced-init-lists, even when they occur within unevaluated operands. // Therefore we still need to instantiate constexpr functions used in such // a context. if (ShouldEnter && Actions.isUnevaluatedContext() && Actions.getLangOpts().CPlusPlus11) { Actions.PushExpressionEvaluationContext( Sema::ExpressionEvaluationContext::UnevaluatedList); Entered = true; } } ~EnterExpressionEvaluationContext() { if (Entered) Actions.PopExpressionEvaluationContext(); } }; DeductionFailureInfo MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK, sema::TemplateDeductionInfo &Info); /// Contains a late templated function. /// Will be parsed at the end of the translation unit, used by Sema & Parser. struct LateParsedTemplate { CachedTokens Toks; /// The template function declaration to be late parsed. Decl *D; }; } // end namespace clang namespace llvm { // Hash a FunctionDeclAndLoc by looking at both its FunctionDecl and its // SourceLocation. template <> struct DenseMapInfo { using FunctionDeclAndLoc = clang::Sema::FunctionDeclAndLoc; using FDBaseInfo = DenseMapInfo>; static FunctionDeclAndLoc getEmptyKey() { return {FDBaseInfo::getEmptyKey(), clang::SourceLocation()}; } static FunctionDeclAndLoc getTombstoneKey() { return {FDBaseInfo::getTombstoneKey(), clang::SourceLocation()}; } static unsigned getHashValue(const FunctionDeclAndLoc &FDL) { return hash_combine(FDBaseInfo::getHashValue(FDL.FD), FDL.Loc.getRawEncoding()); } static bool isEqual(const FunctionDeclAndLoc &LHS, const FunctionDeclAndLoc &RHS) { return LHS.FD == RHS.FD && LHS.Loc == RHS.Loc; } }; } // namespace llvm #endif diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 773c31ff3aec..3299a059c437 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1,2528 +1,2530 @@ //===--- ParseStmt.cpp - Statement and Block Parser -----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the Statement and Block portions of the Parser // interface. // //===----------------------------------------------------------------------===// #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/Attributes.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Parse/LoopHint.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/TypoCorrection.h" using namespace clang; //===----------------------------------------------------------------------===// // C99 6.8: Statements and Blocks. //===----------------------------------------------------------------------===// /// Parse a standalone statement (for instance, as the body of an 'if', /// 'while', or 'for'). StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc, ParsedStmtContext StmtCtx) { StmtResult Res; // We may get back a null statement if we found a #pragma. Keep going until // we get an actual statement. do { StmtVector Stmts; Res = ParseStatementOrDeclaration(Stmts, StmtCtx, TrailingElseLoc); } while (!Res.isInvalid() && !Res.get()); return Res; } /// ParseStatementOrDeclaration - Read 'statement' or 'declaration'. /// StatementOrDeclaration: /// statement /// declaration /// /// statement: /// labeled-statement /// compound-statement /// expression-statement /// selection-statement /// iteration-statement /// jump-statement /// [C++] declaration-statement /// [C++] try-block /// [MS] seh-try-block /// [OBC] objc-throw-statement /// [OBC] objc-try-catch-statement /// [OBC] objc-synchronized-statement /// [GNU] asm-statement /// [OMP] openmp-construct [TODO] /// /// labeled-statement: /// identifier ':' statement /// 'case' constant-expression ':' statement /// 'default' ':' statement /// /// selection-statement: /// if-statement /// switch-statement /// /// iteration-statement: /// while-statement /// do-statement /// for-statement /// /// expression-statement: /// expression[opt] ';' /// /// jump-statement: /// 'goto' identifier ';' /// 'continue' ';' /// 'break' ';' /// 'return' expression[opt] ';' /// [GNU] 'goto' '*' expression ';' /// /// [OBC] objc-throw-statement: /// [OBC] '@' 'throw' expression ';' /// [OBC] '@' 'throw' ';' /// StmtResult Parser::ParseStatementOrDeclaration(StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc) { ParenBraceBracketBalancer BalancerRAIIObj(*this); ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true); if (!MaybeParseOpenCLUnrollHintAttribute(Attrs)) return StmtError(); StmtResult Res = ParseStatementOrDeclarationAfterAttributes( Stmts, StmtCtx, TrailingElseLoc, Attrs); MaybeDestroyTemplateIds(); assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) && "attributes on empty statement"); if (Attrs.empty() || Res.isInvalid()) return Res; return Actions.ProcessStmtAttributes(Res.get(), Attrs, Attrs.Range); } namespace { class StatementFilterCCC final : public CorrectionCandidateCallback { public: StatementFilterCCC(Token nextTok) : NextToken(nextTok) { WantTypeSpecifiers = nextTok.isOneOf(tok::l_paren, tok::less, tok::l_square, tok::identifier, tok::star, tok::amp); WantExpressionKeywords = nextTok.isOneOf(tok::l_paren, tok::identifier, tok::arrow, tok::period); WantRemainingKeywords = nextTok.isOneOf(tok::l_paren, tok::semi, tok::identifier, tok::l_brace); WantCXXNamedCasts = false; } bool ValidateCandidate(const TypoCorrection &candidate) override { if (FieldDecl *FD = candidate.getCorrectionDeclAs()) return !candidate.getCorrectionSpecifier() || isa(FD); if (NextToken.is(tok::equal)) return candidate.getCorrectionDeclAs(); if (NextToken.is(tok::period) && candidate.getCorrectionDeclAs()) return false; return CorrectionCandidateCallback::ValidateCandidate(candidate); } std::unique_ptr clone() override { return std::make_unique(*this); } private: Token NextToken; }; } StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) { const char *SemiError = nullptr; StmtResult Res; SourceLocation GNUAttributeLoc; // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), // or they directly 'return;' if not. Retry: tok::TokenKind Kind = Tok.getKind(); SourceLocation AtLoc; switch (Kind) { case tok::at: // May be a @try or @throw statement { ProhibitAttributes(Attrs); // TODO: is it correct? AtLoc = ConsumeToken(); // consume @ return ParseObjCAtStatement(AtLoc, StmtCtx); } case tok::code_completion: Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); cutOffParsing(); return StmtError(); case tok::identifier: { Token Next = NextToken(); if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement return ParseLabeledStatement(Attrs, StmtCtx); } // Look up the identifier, and typo-correct it to a keyword if it's not // found. if (Next.isNot(tok::coloncolon)) { // Try to limit which sets of keywords should be included in typo // correction based on what the next token is. StatementFilterCCC CCC(Next); if (TryAnnotateName(&CCC) == ANK_Error) { // Handle errors here by skipping up to the next semicolon or '}', and // eat the semicolon if that's what stopped us. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); return StmtError(); } // If the identifier was typo-corrected, try again. if (Tok.isNot(tok::identifier)) goto Retry; } // Fall through LLVM_FALLTHROUGH; } default: { if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && (GNUAttributeLoc.isValid() || isDeclarationStatement())) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl; if (GNUAttributeLoc.isValid()) { DeclStart = GNUAttributeLoc; Decl = ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, Attrs, &GNUAttributeLoc); } else { Decl = ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, Attrs); } if (Attrs.Range.getBegin().isValid()) DeclStart = Attrs.Range.getBegin(); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); } if (Tok.is(tok::r_brace)) { Diag(Tok, diag::err_expected_statement); return StmtError(); } return ParseExprStatement(StmtCtx); } case tok::kw___attribute: { GNUAttributeLoc = Tok.getLocation(); ParseGNUAttributes(Attrs); goto Retry; } case tok::kw_case: // C99 6.8.1: labeled-statement return ParseCaseStatement(StmtCtx); case tok::kw_default: // C99 6.8.1: labeled-statement return ParseDefaultStatement(StmtCtx); case tok::l_brace: // C99 6.8.2: compound-statement return ParseCompoundStatement(); case tok::semi: { // C99 6.8.3p3: expression[opt] ';' bool HasLeadingEmptyMacro = Tok.hasLeadingEmptyMacro(); return Actions.ActOnNullStmt(ConsumeToken(), HasLeadingEmptyMacro); } case tok::kw_if: // C99 6.8.4.1: if-statement return ParseIfStatement(TrailingElseLoc); case tok::kw_switch: // C99 6.8.4.2: switch-statement return ParseSwitchStatement(TrailingElseLoc); case tok::kw_while: // C99 6.8.5.1: while-statement return ParseWhileStatement(TrailingElseLoc); case tok::kw_do: // C99 6.8.5.2: do-statement Res = ParseDoStatement(); SemiError = "do/while"; break; case tok::kw_for: // C99 6.8.5.3: for-statement return ParseForStatement(TrailingElseLoc); case tok::kw_goto: // C99 6.8.6.1: goto-statement Res = ParseGotoStatement(); SemiError = "goto"; break; case tok::kw_continue: // C99 6.8.6.2: continue-statement Res = ParseContinueStatement(); SemiError = "continue"; break; case tok::kw_break: // C99 6.8.6.3: break-statement Res = ParseBreakStatement(); SemiError = "break"; break; case tok::kw_return: // C99 6.8.6.4: return-statement Res = ParseReturnStatement(); SemiError = "return"; break; case tok::kw_co_return: // C++ Coroutines: co_return statement Res = ParseReturnStatement(); SemiError = "co_return"; break; case tok::kw_asm: { ProhibitAttributes(Attrs); bool msAsm = false; Res = ParseAsmStatement(msAsm); Res = Actions.ActOnFinishFullStmt(Res.get()); if (msAsm) return Res; SemiError = "asm"; break; } case tok::kw___if_exists: case tok::kw___if_not_exists: ProhibitAttributes(Attrs); ParseMicrosoftIfExistsStatement(Stmts); // An __if_exists block is like a compound statement, but it doesn't create // a new scope. return StmtEmpty(); case tok::kw_try: // C++ 15: try-block return ParseCXXTryBlock(); case tok::kw___try: ProhibitAttributes(Attrs); // TODO: is it correct? return ParseSEHTryBlock(); case tok::kw___leave: Res = ParseSEHLeaveStatement(); SemiError = "__leave"; break; case tok::annot_pragma_vis: ProhibitAttributes(Attrs); HandlePragmaVisibility(); return StmtEmpty(); case tok::annot_pragma_pack: ProhibitAttributes(Attrs); HandlePragmaPack(); return StmtEmpty(); case tok::annot_pragma_msstruct: ProhibitAttributes(Attrs); HandlePragmaMSStruct(); return StmtEmpty(); case tok::annot_pragma_align: ProhibitAttributes(Attrs); HandlePragmaAlign(); return StmtEmpty(); case tok::annot_pragma_weak: ProhibitAttributes(Attrs); HandlePragmaWeak(); return StmtEmpty(); case tok::annot_pragma_weakalias: ProhibitAttributes(Attrs); HandlePragmaWeakAlias(); return StmtEmpty(); case tok::annot_pragma_redefine_extname: ProhibitAttributes(Attrs); HandlePragmaRedefineExtname(); return StmtEmpty(); case tok::annot_pragma_fp_contract: ProhibitAttributes(Attrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "fp_contract"; ConsumeAnnotationToken(); return StmtError(); case tok::annot_pragma_fp: ProhibitAttributes(Attrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "clang fp"; ConsumeAnnotationToken(); return StmtError(); case tok::annot_pragma_fenv_access: ProhibitAttributes(Attrs); HandlePragmaFEnvAccess(); return StmtEmpty(); case tok::annot_pragma_float_control: ProhibitAttributes(Attrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control"; ConsumeAnnotationToken(); return StmtError(); case tok::annot_pragma_opencl_extension: ProhibitAttributes(Attrs); HandlePragmaOpenCLExtension(); return StmtEmpty(); case tok::annot_pragma_captured: ProhibitAttributes(Attrs); return HandlePragmaCaptured(); case tok::annot_pragma_openmp: ProhibitAttributes(Attrs); return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx); case tok::annot_pragma_ms_pointers_to_members: ProhibitAttributes(Attrs); HandlePragmaMSPointersToMembers(); return StmtEmpty(); case tok::annot_pragma_ms_pragma: ProhibitAttributes(Attrs); HandlePragmaMSPragma(); return StmtEmpty(); case tok::annot_pragma_ms_vtordisp: ProhibitAttributes(Attrs); HandlePragmaMSVtorDisp(); return StmtEmpty(); case tok::annot_pragma_loop_hint: ProhibitAttributes(Attrs); return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, Attrs); case tok::annot_pragma_dump: HandlePragmaDump(); return StmtEmpty(); case tok::annot_pragma_attribute: HandlePragmaAttribute(); return StmtEmpty(); } // If we reached this code, the statement must end in a semicolon. if (!TryConsumeToken(tok::semi) && !Res.isInvalid()) { // If the result was valid, then we do want to diagnose this. Use // ExpectAndConsume to emit the diagnostic, even though we know it won't // succeed. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, SemiError); // Skip until we see a } or ;, but don't eat it. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); } return Res; } /// Parse an expression statement. StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) { // If a case keyword is missing, this is where it should be inserted. Token OldToken = Tok; ExprStatementTokLoc = Tok.getLocation(); // expression[opt] ';' ExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { // If the expression is invalid, skip ahead to the next semicolon or '}'. // Not doing this opens us up to the possibility of infinite loops if // ParseExpression does not consume any tokens. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); return Actions.ActOnExprStmtError(); } if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() && Actions.CheckCaseExpression(Expr.get())) { // If a constant expression is followed by a colon inside a switch block, // suggest a missing case keyword. Diag(OldToken, diag::err_expected_case_before_expression) << FixItHint::CreateInsertion(OldToken.getLocation(), "case "); // Recover parsing as a case statement. return ParseCaseStatement(StmtCtx, /*MissingCase=*/true, Expr); } // Otherwise, eat the semicolon. ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); return handleExprStmt(Expr, StmtCtx); } /// ParseSEHTryBlockCommon /// /// seh-try-block: /// '__try' compound-statement seh-handler /// /// seh-handler: /// seh-except-block /// seh-finally-block /// StmtResult Parser::ParseSEHTryBlock() { assert(Tok.is(tok::kw___try) && "Expected '__try'"); SourceLocation TryLoc = ConsumeToken(); if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); StmtResult TryBlock(ParseCompoundStatement( /*isStmtExpr=*/false, Scope::DeclScope | Scope::CompoundStmtScope | Scope::SEHTryScope)); if (TryBlock.isInvalid()) return TryBlock; StmtResult Handler; if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == getSEHExceptKeyword()) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHExceptBlock(Loc); } else if (Tok.is(tok::kw___finally)) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHFinallyBlock(Loc); } else { return StmtError(Diag(Tok, diag::err_seh_expected_handler)); } if(Handler.isInvalid()) return Handler; return Actions.ActOnSEHTryBlock(false /* IsCXXTry */, TryLoc, TryBlock.get(), Handler.get()); } /// ParseSEHExceptBlock - Handle __except /// /// seh-except-block: /// '__except' '(' seh-filter-expression ')' compound-statement /// StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { PoisonIdentifierRAIIObject raii(Ident__exception_code, false), raii2(Ident___exception_code, false), raii3(Ident_GetExceptionCode, false); if (ExpectAndConsume(tok::l_paren)) return StmtError(); ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope | Scope::SEHExceptScope); if (getLangOpts().Borland) { Ident__exception_info->setIsPoisoned(false); Ident___exception_info->setIsPoisoned(false); Ident_GetExceptionInfo->setIsPoisoned(false); } ExprResult FilterExpr; { ParseScopeFlags FilterScope(this, getCurScope()->getFlags() | Scope::SEHFilterScope); FilterExpr = Actions.CorrectDelayedTyposInExpr(ParseExpression()); } if (getLangOpts().Borland) { Ident__exception_info->setIsPoisoned(true); Ident___exception_info->setIsPoisoned(true); Ident_GetExceptionInfo->setIsPoisoned(true); } if(FilterExpr.isInvalid()) return StmtError(); if (ExpectAndConsume(tok::r_paren)) return StmtError(); if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); StmtResult Block(ParseCompoundStatement()); if(Block.isInvalid()) return Block; return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.get(), Block.get()); } /// ParseSEHFinallyBlock - Handle __finally /// /// seh-finally-block: /// '__finally' compound-statement /// StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyLoc) { PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false), raii2(Ident___abnormal_termination, false), raii3(Ident_AbnormalTermination, false); if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); ParseScope FinallyScope(this, 0); Actions.ActOnStartSEHFinallyBlock(); StmtResult Block(ParseCompoundStatement()); if(Block.isInvalid()) { Actions.ActOnAbortSEHFinallyBlock(); return Block; } return Actions.ActOnFinishSEHFinallyBlock(FinallyLoc, Block.get()); } /// Handle __leave /// /// seh-leave-statement: /// '__leave' ';' /// StmtResult Parser::ParseSEHLeaveStatement() { SourceLocation LeaveLoc = ConsumeToken(); // eat the '__leave'. return Actions.ActOnSEHLeaveStmt(LeaveLoc, getCurScope()); } /// ParseLabeledStatement - We have an identifier and a ':' after it. /// /// labeled-statement: /// identifier ':' statement /// [GNU] identifier ':' attributes[opt] statement /// StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs, ParsedStmtContext StmtCtx) { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); // The substatement is always a 'statement', not a 'declaration', but is // otherwise in the same context as the labeled-statement. StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; Token IdentTok = Tok; // Save the whole token. ConsumeToken(); // eat the identifier. assert(Tok.is(tok::colon) && "Not a label!"); // identifier ':' statement SourceLocation ColonLoc = ConsumeToken(); // Read label attributes, if present. StmtResult SubStmt; if (Tok.is(tok::kw___attribute)) { ParsedAttributesWithRange TempAttrs(AttrFactory); ParseGNUAttributes(TempAttrs); // In C++, GNU attributes only apply to the label if they are followed by a // semicolon, to disambiguate label attributes from attributes on a labeled // declaration. // // This doesn't quite match what GCC does; if the attribute list is empty // and followed by a semicolon, GCC will reject (it appears to parse the // attributes as part of a statement in that case). That looks like a bug. if (!getLangOpts().CPlusPlus || Tok.is(tok::semi)) attrs.takeAllFrom(TempAttrs); else if (isDeclarationStatement()) { StmtVector Stmts; // FIXME: We should do this whether or not we have a declaration // statement, but that doesn't work correctly (because ProhibitAttributes // can't handle GNU attributes), so only call it in the one case where // GNU attributes are allowed. SubStmt = ParseStatementOrDeclarationAfterAttributes(Stmts, StmtCtx, nullptr, TempAttrs); if (!TempAttrs.empty() && !SubStmt.isInvalid()) SubStmt = Actions.ProcessStmtAttributes(SubStmt.get(), TempAttrs, TempAttrs.Range); } else { Diag(Tok, diag::err_expected_after) << "__attribute__" << tok::semi; } } // If we've not parsed a statement yet, parse one now. if (!SubStmt.isInvalid() && !SubStmt.isUsable()) SubStmt = ParseStatement(nullptr, StmtCtx); // Broken substmt shouldn't prevent the label from being added to the AST. if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(), IdentTok.getLocation()); Actions.ProcessDeclAttributeList(Actions.CurScope, LD, attrs); attrs.clear(); return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc, SubStmt.get()); } /// ParseCaseStatement /// labeled-statement: /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, bool MissingCase, ExprResult Expr) { assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!"); // The substatement is always a 'statement', not a 'declaration', but is // otherwise in the same context as the labeled-statement. StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; // It is very very common for code to contain many case statements recursively // nested, as in (but usually without indentation): // case 1: // case 2: // case 3: // case 4: // case 5: etc. // // Parsing this naively works, but is both inefficient and can cause us to run // out of stack space in our recursive descent parser. As a special case, // flatten this recursion into an iterative loop. This is complex and gross, // but all the grossness is constrained to ParseCaseStatement (and some // weirdness in the actions), so this is just local grossness :). // TopLevelCase - This is the highest level we have parsed. 'case 1' in the // example above. StmtResult TopLevelCase(true); // DeepestParsedCaseStmt - This is the deepest statement we have parsed, which // gets updated each time a new case is parsed, and whose body is unset so // far. When parsing 'case 4', this is the 'case 3' node. Stmt *DeepestParsedCaseStmt = nullptr; // While we have case statements, eat and stack them. SourceLocation ColonLoc; do { SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() : ConsumeToken(); // eat the 'case'. ColonLoc = SourceLocation(); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCase(getCurScope()); cutOffParsing(); return StmtError(); } /// We don't want to treat 'case x : y' as a potential typo for 'case x::y'. /// Disable this form of error recovery while we're parsing the case /// expression. ColonProtectionRAIIObject ColonProtection(*this); ExprResult LHS; if (!MissingCase) { LHS = ParseCaseExpression(CaseLoc); if (LHS.isInvalid()) { // If constant-expression is parsed unsuccessfully, recover by skipping // current case statement (moving to the colon that ends it). if (!SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch)) return StmtError(); } } else { LHS = Expr; MissingCase = false; } // GNU case range extension. SourceLocation DotDotDotLoc; ExprResult RHS; if (TryConsumeToken(tok::ellipsis, DotDotDotLoc)) { Diag(DotDotDotLoc, diag::ext_gnu_case_range); RHS = ParseCaseExpression(CaseLoc); if (RHS.isInvalid()) { if (!SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch)) return StmtError(); } } ColonProtection.restore(); if (TryConsumeToken(tok::colon, ColonLoc)) { } else if (TryConsumeToken(tok::semi, ColonLoc) || TryConsumeToken(tok::coloncolon, ColonLoc)) { // Treat "case blah;" or "case blah::" as a typo for "case blah:". Diag(ColonLoc, diag::err_expected_after) << "'case'" << tok::colon << FixItHint::CreateReplacement(ColonLoc, ":"); } else { SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation); Diag(ExpectedLoc, diag::err_expected_after) << "'case'" << tok::colon << FixItHint::CreateInsertion(ExpectedLoc, ":"); ColonLoc = ExpectedLoc; } StmtResult Case = Actions.ActOnCaseStmt(CaseLoc, LHS, DotDotDotLoc, RHS, ColonLoc); // If we had a sema error parsing this case, then just ignore it and // continue parsing the sub-stmt. if (Case.isInvalid()) { if (TopLevelCase.isInvalid()) // No parsed case stmts. return ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx); // Otherwise, just don't add it as a nested case. } else { // If this is the first case statement we parsed, it becomes TopLevelCase. // Otherwise we link it into the current chain. Stmt *NextDeepest = Case.get(); if (TopLevelCase.isInvalid()) TopLevelCase = Case; else Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, Case.get()); DeepestParsedCaseStmt = NextDeepest; } // Handle all case statements. } while (Tok.is(tok::kw_case)); // If we found a non-case statement, start by parsing it. StmtResult SubStmt; if (Tok.isNot(tok::r_brace)) { SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx); } else { // Nicely diagnose the common error "switch (X) { case 4: }", which is // not valid. If ColonLoc doesn't point to a valid text location, there was // another parsing error, so avoid producing extra diagnostics. if (ColonLoc.isValid()) { SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); Diag(AfterColonLoc, diag::err_label_end_of_compound_statement) << FixItHint::CreateInsertion(AfterColonLoc, " ;"); } SubStmt = StmtError(); } // Install the body into the most deeply-nested case. if (DeepestParsedCaseStmt) { // Broken sub-stmt shouldn't prevent forming the case statement properly. if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(SourceLocation()); Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get()); } // Return the top level parsed statement tree. return TopLevelCase; } /// ParseDefaultStatement /// labeled-statement: /// 'default' ':' statement /// Note that this does not parse the 'statement' at the end. /// StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) { assert(Tok.is(tok::kw_default) && "Not a default stmt!"); // The substatement is always a 'statement', not a 'declaration', but is // otherwise in the same context as the labeled-statement. StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. SourceLocation ColonLoc; if (TryConsumeToken(tok::colon, ColonLoc)) { } else if (TryConsumeToken(tok::semi, ColonLoc)) { // Treat "default;" as a typo for "default:". Diag(ColonLoc, diag::err_expected_after) << "'default'" << tok::colon << FixItHint::CreateReplacement(ColonLoc, ":"); } else { SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation); Diag(ExpectedLoc, diag::err_expected_after) << "'default'" << tok::colon << FixItHint::CreateInsertion(ExpectedLoc, ":"); ColonLoc = ExpectedLoc; } StmtResult SubStmt; if (Tok.isNot(tok::r_brace)) { SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx); } else { // Diagnose the common error "switch (X) {... default: }", which is // not valid. SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc); Diag(AfterColonLoc, diag::err_label_end_of_compound_statement) << FixItHint::CreateInsertion(AfterColonLoc, " ;"); SubStmt = true; } // Broken sub-stmt shouldn't prevent forming the case statement properly. if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc, SubStmt.get(), getCurScope()); } StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { return ParseCompoundStatement(isStmtExpr, Scope::DeclScope | Scope::CompoundStmtScope); } /// ParseCompoundStatement - Parse a "{}" block. /// /// compound-statement: [C99 6.8.2] /// { block-item-list[opt] } /// [GNU] { label-declarations block-item-list } [TODO] /// /// block-item-list: /// block-item /// block-item-list block-item /// /// block-item: /// declaration /// [GNU] '__extension__' declaration /// statement /// /// [GNU] label-declarations: /// [GNU] label-declaration /// [GNU] label-declarations label-declaration /// /// [GNU] label-declaration: /// [GNU] '__label__' identifier-list ';' /// StmtResult Parser::ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags) { assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); // Enter a scope to hold everything within the compound stmt. Compound // statements can always hold declarations. ParseScope CompoundScope(this, ScopeFlags); // Parse the statements in the body. return ParseCompoundStatementBody(isStmtExpr); } /// Parse any pragmas at the start of the compound expression. We handle these /// separately since some pragmas (FP_CONTRACT) must appear before any C /// statement in the compound, but may be intermingled with other pragmas. void Parser::ParseCompoundStatementLeadingPragmas() { bool checkForPragmas = true; while (checkForPragmas) { switch (Tok.getKind()) { case tok::annot_pragma_vis: HandlePragmaVisibility(); break; case tok::annot_pragma_pack: HandlePragmaPack(); break; case tok::annot_pragma_msstruct: HandlePragmaMSStruct(); break; case tok::annot_pragma_align: HandlePragmaAlign(); break; case tok::annot_pragma_weak: HandlePragmaWeak(); break; case tok::annot_pragma_weakalias: HandlePragmaWeakAlias(); break; case tok::annot_pragma_redefine_extname: HandlePragmaRedefineExtname(); break; case tok::annot_pragma_opencl_extension: HandlePragmaOpenCLExtension(); break; case tok::annot_pragma_fp_contract: HandlePragmaFPContract(); break; case tok::annot_pragma_fp: HandlePragmaFP(); break; case tok::annot_pragma_fenv_access: HandlePragmaFEnvAccess(); break; case tok::annot_pragma_float_control: HandlePragmaFloatControl(); break; case tok::annot_pragma_ms_pointers_to_members: HandlePragmaMSPointersToMembers(); break; case tok::annot_pragma_ms_pragma: HandlePragmaMSPragma(); break; case tok::annot_pragma_ms_vtordisp: HandlePragmaMSVtorDisp(); break; case tok::annot_pragma_dump: HandlePragmaDump(); break; default: checkForPragmas = false; break; } } } /// Consume any extra semi-colons resulting in null statements, /// returning true if any tok::semi were consumed. bool Parser::ConsumeNullStmt(StmtVector &Stmts) { if (!Tok.is(tok::semi)) return false; SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc; while (Tok.is(tok::semi) && !Tok.hasLeadingEmptyMacro() && Tok.getLocation().isValid() && !Tok.getLocation().isMacroID()) { EndLoc = Tok.getLocation(); // Don't just ConsumeToken() this tok::semi, do store it in AST. StmtResult R = ParseStatementOrDeclaration(Stmts, ParsedStmtContext::SubStmt); if (R.isUsable()) Stmts.push_back(R.get()); } // Did not consume any extra semi. if (EndLoc.isInvalid()) return false; Diag(StartLoc, diag::warn_null_statement) << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); return true; } StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) { bool IsStmtExprResult = false; if ((StmtCtx & ParsedStmtContext::InStmtExpr) != ParsedStmtContext()) { // For GCC compatibility we skip past NullStmts. unsigned LookAhead = 0; while (GetLookAheadToken(LookAhead).is(tok::semi)) { ++LookAhead; } // Then look to see if the next two tokens close the statement expression; // if so, this expression statement is the last statement in a statment // expression. IsStmtExprResult = GetLookAheadToken(LookAhead).is(tok::r_brace) && GetLookAheadToken(LookAhead + 1).is(tok::r_paren); } if (IsStmtExprResult) E = Actions.ActOnStmtExprResult(E); return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult); } /// ParseCompoundStatementBody - Parse a sequence of statements and invoke the /// ActOnCompoundStmt action. This expects the '{' to be the current token, and /// consume the '}' at the end of the block. It does not manipulate the scope /// stack. StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), Tok.getLocation(), "in compound statement ('{}')"); // Record the state of the FPFeatures, restore on leaving the // compound statement. Sema::FPFeaturesStateRAII SaveFPContractState(Actions); InMessageExpressionRAIIObject InMessage(*this, false); BalancedDelimiterTracker T(*this, tok::l_brace); if (T.consumeOpen()) return StmtError(); Sema::CompoundScopeRAII CompoundScope(Actions, isStmtExpr); // Parse any pragmas at the beginning of the compound statement. ParseCompoundStatementLeadingPragmas(); StmtVector Stmts; // "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are // only allowed at the start of a compound stmt regardless of the language. while (Tok.is(tok::kw___label__)) { SourceLocation LabelLoc = ConsumeToken(); SmallVector DeclsInGroup; while (1) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; break; } IdentifierInfo *II = Tok.getIdentifierInfo(); SourceLocation IdLoc = ConsumeToken(); DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc)); if (!TryConsumeToken(tok::comma)) break; } DeclSpec DS(AttrFactory); DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation()); ExpectAndConsumeSemi(diag::err_expected_semi_declaration); if (R.isUsable()) Stmts.push_back(R.get()); } ParsedStmtContext SubStmtCtx = ParsedStmtContext::Compound | (isStmtExpr ? ParsedStmtContext::InStmtExpr : ParsedStmtContext()); while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { if (Tok.is(tok::annot_pragma_unused)) { HandlePragmaUnused(); continue; } if (ConsumeNullStmt(Stmts)) continue; StmtResult R; if (Tok.isNot(tok::kw___extension__)) { R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); } else { // __extension__ can start declarations and it can also be a unary // operator for expressions. Consume multiple __extension__ markers here // until we can determine which is which. // FIXME: This loses extension expressions in the AST! SourceLocation ExtLoc = ConsumeToken(); while (Tok.is(tok::kw___extension__)) ConsumeToken(); ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs, nullptr, /*MightBeObjCMessageSend*/ true); // If this is the start of a declaration, parse it as such. if (isDeclarationStatement()) { // __extension__ silences extension warnings in the subdeclaration. // FIXME: Save the __extension__ on the decl as a node somehow? ExtensionRAIIObject O(Diags); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Res = ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, attrs); R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd); } else { // Otherwise this was a unary __extension__ marker. ExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc)); if (Res.isInvalid()) { SkipUntil(tok::semi); continue; } // Eat the semicolon at the end of stmt and convert the expr into a // statement. ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); R = handleExprStmt(Res, SubStmtCtx); if (R.isUsable()) R = Actions.ProcessStmtAttributes(R.get(), attrs, attrs.Range); } } if (R.isUsable()) Stmts.push_back(R.get()); } SourceLocation CloseLoc = Tok.getLocation(); // We broke out of the while loop because we found a '}' or EOF. if (!T.consumeClose()) // Recover by creating a compound statement with what we parsed so far, // instead of dropping everything and returning StmtError(); CloseLoc = T.getCloseLocation(); return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc, Stmts, isStmtExpr); } /// ParseParenExprOrCondition: /// [C ] '(' expression ')' /// [C++] '(' condition ')' /// [C++1z] '(' init-statement[opt] condition ')' /// /// This function parses and performs error recovery on the specified condition /// or expression (depending on whether we're in C++ or C mode). This function /// goes out of its way to recover well. It returns true if there was a parser /// error (the right paren couldn't be found), which indicates that the caller /// should try to recover harder. It returns false if the condition is /// successfully parsed. Note that a successful parse can still have semantic /// errors in the condition. bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, Sema::ConditionResult &Cond, SourceLocation Loc, Sema::ConditionKind CK) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); if (getLangOpts().CPlusPlus) Cond = ParseCXXCondition(InitStmt, Loc, CK); else { ExprResult CondExpr = ParseExpression(); // If required, convert to a boolean value. if (CondExpr.isInvalid()) Cond = Sema::ConditionError(); else Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK); } // If the parser was confused by the condition and we don't have a ')', try to // recover by skipping ahead to a semi and bailing out. If condexp is // semantically invalid but we have well formed code, keep going. if (Cond.isInvalid() && Tok.isNot(tok::r_paren)) { SkipUntil(tok::semi); // Skipping may have stopped if it found the containing ')'. If so, we can // continue parsing the if statement. if (Tok.isNot(tok::r_paren)) return true; } // Otherwise the condition is valid or the rparen is present. T.consumeClose(); // Check for extraneous ')'s to catch things like "if (foo())) {". We know // that all callers are looking for a statement after the condition, so ")" // isn't valid. while (Tok.is(tok::r_paren)) { Diag(Tok, diag::err_extraneous_rparen_in_condition) << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeParen(); } return false; } namespace { enum MisleadingStatementKind { MSK_if, MSK_else, MSK_for, MSK_while }; struct MisleadingIndentationChecker { Parser &P; SourceLocation StmtLoc; SourceLocation PrevLoc; unsigned NumDirectives; MisleadingStatementKind Kind; bool ShouldSkip; MisleadingIndentationChecker(Parser &P, MisleadingStatementKind K, SourceLocation SL) : P(P), StmtLoc(SL), PrevLoc(P.getCurToken().getLocation()), NumDirectives(P.getPreprocessor().getNumDirectives()), Kind(K), ShouldSkip(P.getCurToken().is(tok::l_brace)) { if (!P.MisleadingIndentationElseLoc.isInvalid()) { StmtLoc = P.MisleadingIndentationElseLoc; P.MisleadingIndentationElseLoc = SourceLocation(); } if (Kind == MSK_else && !ShouldSkip) P.MisleadingIndentationElseLoc = SL; } /// Compute the column number will aligning tabs on TabStop (-ftabstop), this /// gives the visual indentation of the SourceLocation. static unsigned getVisualIndentation(SourceManager &SM, SourceLocation Loc) { unsigned TabStop = SM.getDiagnostics().getDiagnosticOptions().TabStop; unsigned ColNo = SM.getSpellingColumnNumber(Loc); if (ColNo == 0 || TabStop == 1) return ColNo; std::pair FIDAndOffset = SM.getDecomposedLoc(Loc); bool Invalid; StringRef BufData = SM.getBufferData(FIDAndOffset.first, &Invalid); if (Invalid) return 0; const char *EndPos = BufData.data() + FIDAndOffset.second; // FileOffset are 0-based and Column numbers are 1-based assert(FIDAndOffset.second + 1 >= ColNo && "Column number smaller than file offset?"); unsigned VisualColumn = 0; // Stored as 0-based column, here. // Loop from beginning of line up to Loc's file position, counting columns, // expanding tabs. for (const char *CurPos = EndPos - (ColNo - 1); CurPos != EndPos; ++CurPos) { if (*CurPos == '\t') // Advance visual column to next tabstop. VisualColumn += (TabStop - VisualColumn % TabStop); else VisualColumn++; } return VisualColumn + 1; } void Check() { Token Tok = P.getCurToken(); if (P.getActions().getDiagnostics().isIgnored( diag::warn_misleading_indentation, Tok.getLocation()) || ShouldSkip || NumDirectives != P.getPreprocessor().getNumDirectives() || Tok.isOneOf(tok::semi, tok::r_brace) || Tok.isAnnotation() || Tok.getLocation().isMacroID() || PrevLoc.isMacroID() || StmtLoc.isMacroID() || (Kind == MSK_else && P.MisleadingIndentationElseLoc.isInvalid())) { P.MisleadingIndentationElseLoc = SourceLocation(); return; } if (Kind == MSK_else) P.MisleadingIndentationElseLoc = SourceLocation(); SourceManager &SM = P.getPreprocessor().getSourceManager(); unsigned PrevColNum = getVisualIndentation(SM, PrevLoc); unsigned CurColNum = getVisualIndentation(SM, Tok.getLocation()); unsigned StmtColNum = getVisualIndentation(SM, StmtLoc); if (PrevColNum != 0 && CurColNum != 0 && StmtColNum != 0 && ((PrevColNum > StmtColNum && PrevColNum == CurColNum) || !Tok.isAtStartOfLine()) && SM.getPresumedLineNumber(StmtLoc) != SM.getPresumedLineNumber(Tok.getLocation()) && (Tok.isNot(tok::identifier) || P.getPreprocessor().LookAhead(0).isNot(tok::colon))) { P.Diag(Tok.getLocation(), diag::warn_misleading_indentation) << Kind; P.Diag(StmtLoc, diag::note_previous_statement); } } }; } /// ParseIfStatement /// if-statement: [C99 6.8.4.1] /// 'if' '(' expression ')' statement /// 'if' '(' expression ')' statement 'else' statement /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement /// StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. bool IsConstexpr = false; if (Tok.is(tok::kw_constexpr)) { Diag(Tok, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_constexpr_if : diag::ext_constexpr_if); IsConstexpr = true; ConsumeToken(); } if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "if"; SkipUntil(tok::semi); return StmtError(); } bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; // C99 6.8.4p3 - In C99, the if statement is a block. This is not // the case for C90. // // C++ 6.4p3: // A name introduced by a declaration in a condition is in scope from its // point of declaration until the end of the substatements controlled by the // condition. // C++ 3.3.2p4: // Names declared in the for-init-statement, and in the condition of if, // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX); // Parse the condition. StmtResult InitStmt; Sema::ConditionResult Cond; if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc, IsConstexpr ? Sema::ConditionKind::ConstexprIf : Sema::ConditionKind::Boolean)) return StmtError(); llvm::Optional ConstexprCondition; if (IsConstexpr) ConstexprCondition = Cond.getKnownValue(); + bool IsBracedThen = Tok.is(tok::l_brace); + // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. // // C++ 6.4p1: // The substatement in a selection-statement (each substatement, in the else // form of the if statement) implicitly defines a local scope. // // For C++ we create a scope for the condition and a new scope for // substatements because: // -When the 'then' scope exits, we want the condition declaration to still be // active for the 'else' scope too. // -Sema will detect name clashes by considering declarations of a // 'ControlScope' as part of its direct subscope. // -If we wanted the condition and substatement to be in the same scope, we // would have to notify ParseStatement not to create a new scope. It's // simpler to let it create a new scope. // - ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); + ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, IsBracedThen); MisleadingIndentationChecker MIChecker(*this, MSK_if, IfLoc); // Read the 'then' stmt. SourceLocation ThenStmtLoc = Tok.getLocation(); SourceLocation InnerStatementTrailingElseLoc; StmtResult ThenStmt; { EnterExpressionEvaluationContext PotentiallyDiscarded( Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr, Sema::ExpressionEvaluationContextRecord::EK_Other, /*ShouldEnter=*/ConstexprCondition && !*ConstexprCondition); ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc); } if (Tok.isNot(tok::kw_else)) MIChecker.Check(); // Pop the 'if' scope if needed. InnerScope.Exit(); // If it has an else, parse it. SourceLocation ElseLoc; SourceLocation ElseStmtLoc; StmtResult ElseStmt; if (Tok.is(tok::kw_else)) { if (TrailingElseLoc) *TrailingElseLoc = Tok.getLocation(); ElseLoc = ConsumeToken(); ElseStmtLoc = Tok.getLocation(); // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do // this if the body isn't a compound statement to avoid push/pop in common // cases. // // C++ 6.4p1: // The substatement in a selection-statement (each substatement, in the else // form of the if statement) implicitly defines a local scope. // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); MisleadingIndentationChecker MIChecker(*this, MSK_else, ElseLoc); EnterExpressionEvaluationContext PotentiallyDiscarded( Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr, Sema::ExpressionEvaluationContextRecord::EK_Other, /*ShouldEnter=*/ConstexprCondition && *ConstexprCondition); ElseStmt = ParseStatement(); if (ElseStmt.isUsable()) MIChecker.Check(); // Pop the 'else' scope if needed. InnerScope.Exit(); } else if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteAfterIf(getCurScope()); + Actions.CodeCompleteAfterIf(getCurScope(), IsBracedThen); cutOffParsing(); return StmtError(); } else if (InnerStatementTrailingElseLoc.isValid()) { Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else); } IfScope.Exit(); // If the then or else stmt is invalid and the other is valid (and present), // make turn the invalid one into a null stmt to avoid dropping the other // part. If both are invalid, return error. if ((ThenStmt.isInvalid() && ElseStmt.isInvalid()) || (ThenStmt.isInvalid() && ElseStmt.get() == nullptr) || (ThenStmt.get() == nullptr && ElseStmt.isInvalid())) { // Both invalid, or one is invalid and other is non-present: return error. return StmtError(); } // Now if either are invalid, replace with a ';'. if (ThenStmt.isInvalid()) ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc); if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); return Actions.ActOnIfStmt(IfLoc, IsConstexpr, InitStmt.get(), Cond, ThenStmt.get(), ElseLoc, ElseStmt.get()); } /// ParseSwitchStatement /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "switch"; SkipUntil(tok::semi); return StmtError(); } bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; // C99 6.8.4p3 - In C99, the switch statement is a block. This is // not the case for C90. Start the switch scope. // // C++ 6.4p3: // A name introduced by a declaration in a condition is in scope from its // point of declaration until the end of the substatements controlled by the // condition. // C++ 3.3.2p4: // Names declared in the for-init-statement, and in the condition of if, // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // unsigned ScopeFlags = Scope::SwitchScope; if (C99orCXX) ScopeFlags |= Scope::DeclScope | Scope::ControlScope; ParseScope SwitchScope(this, ScopeFlags); // Parse the condition. StmtResult InitStmt; Sema::ConditionResult Cond; if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc, Sema::ConditionKind::Switch)) return StmtError(); StmtResult Switch = Actions.ActOnStartOfSwitchStmt(SwitchLoc, InitStmt.get(), Cond); if (Switch.isInvalid()) { // Skip the switch body. // FIXME: This is not optimal recovery, but parsing the body is more // dangerous due to the presence of case and default statements, which // will have no place to connect back with the switch. if (Tok.is(tok::l_brace)) { ConsumeBrace(); SkipUntil(tok::r_brace); } else SkipUntil(tok::semi); return Switch; } // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. // // C++ 6.4p1: // The substatement in a selection-statement (each substatement, in the else // form of the if statement) implicitly defines a local scope. // // See comments in ParseIfStatement for why we create a scope for the // condition and a new scope for substatement in C++. // getCurScope()->AddFlags(Scope::BreakScope); ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); // We have incremented the mangling number for the SwitchScope and the // InnerScope, which is one too many. if (C99orCXX) getCurScope()->decrementMSManglingNumber(); // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); // Pop the scopes. InnerScope.Exit(); SwitchScope.Exit(); return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get()); } /// ParseWhileStatement /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_while) && "Not a while stmt!"); SourceLocation WhileLoc = Tok.getLocation(); ConsumeToken(); // eat the 'while'. if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "while"; SkipUntil(tok::semi); return StmtError(); } bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; // C99 6.8.5p5 - In C99, the while statement is a block. This is not // the case for C90. Start the loop scope. // // C++ 6.4p3: // A name introduced by a declaration in a condition is in scope from its // point of declaration until the end of the substatements controlled by the // condition. // C++ 3.3.2p4: // Names declared in the for-init-statement, and in the condition of if, // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // unsigned ScopeFlags; if (C99orCXX) ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope | Scope::ControlScope; else ScopeFlags = Scope::BreakScope | Scope::ContinueScope; ParseScope WhileScope(this, ScopeFlags); // Parse the condition. Sema::ConditionResult Cond; if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc, Sema::ConditionKind::Boolean)) return StmtError(); // C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. // // C++ 6.5p2: // The substatement in an iteration-statement implicitly defines a local scope // which is entered and exited each time through the loop. // // See comments in ParseIfStatement for why we create a scope for the // condition and a new scope for substatement in C++. // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); MisleadingIndentationChecker MIChecker(*this, MSK_while, WhileLoc); // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); if (Body.isUsable()) MIChecker.Check(); // Pop the body scope if needed. InnerScope.Exit(); WhileScope.Exit(); if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); return Actions.ActOnWhileStmt(WhileLoc, Cond, Body.get()); } /// ParseDoStatement /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' /// Note: this lets the caller parse the end ';'. StmtResult Parser::ParseDoStatement() { assert(Tok.is(tok::kw_do) && "Not a do stmt!"); SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. // C99 6.8.5p5 - In C99, the do statement is a block. This is not // the case for C90. Start the loop scope. unsigned ScopeFlags; if (getLangOpts().C99) ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope; else ScopeFlags = Scope::BreakScope | Scope::ContinueScope; ParseScope DoScope(this, ScopeFlags); // C99 6.8.5p5 - In C99, the body of the do statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. // // C++ 6.5p2: // The substatement in an iteration-statement implicitly defines a local scope // which is entered and exited each time through the loop. // bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); // Read the body statement. StmtResult Body(ParseStatement()); // Pop the body scope if needed. InnerScope.Exit(); if (Tok.isNot(tok::kw_while)) { if (!Body.isInvalid()) { Diag(Tok, diag::err_expected_while); Diag(DoLoc, diag::note_matching) << "'do'"; SkipUntil(tok::semi, StopBeforeMatch); } return StmtError(); } SourceLocation WhileLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "do/while"; SkipUntil(tok::semi, StopBeforeMatch); return StmtError(); } // Parse the parenthesized expression. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); // A do-while expression is not a condition, so can't have attributes. DiagnoseAndSkipCXX11Attributes(); ExprResult Cond = ParseExpression(); // Correct the typos in condition before closing the scope. if (Cond.isUsable()) Cond = Actions.CorrectDelayedTyposInExpr(Cond); T.consumeClose(); DoScope.Exit(); if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, T.getOpenLocation(), Cond.get(), T.getCloseLocation()); } bool Parser::isForRangeIdentifier() { assert(Tok.is(tok::identifier)); const Token &Next = NextToken(); if (Next.is(tok::colon)) return true; if (Next.isOneOf(tok::l_square, tok::kw_alignas)) { TentativeParsingAction PA(*this); ConsumeToken(); SkipCXX11Attributes(); bool Result = Tok.is(tok::colon); PA.Revert(); return Result; } return false; } /// ParseForStatement /// for-statement: [C99 6.8.5.3] /// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement /// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement /// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')' /// [C++] statement /// [C++0x] 'for' /// 'co_await'[opt] [Coroutines] /// '(' for-range-declaration ':' for-range-initializer ')' /// statement /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement /// [OBJC2] 'for' '(' expr 'in' expr ')' statement /// /// [C++] for-init-statement: /// [C++] expression-statement /// [C++] simple-declaration /// /// [C++0x] for-range-declaration: /// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator /// [C++0x] for-range-initializer: /// [C++0x] expression /// [C++0x] braced-init-list [TODO] StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_for) && "Not a for stmt!"); SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. SourceLocation CoawaitLoc; if (Tok.is(tok::kw_co_await)) CoawaitLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "for"; SkipUntil(tok::semi); return StmtError(); } bool C99orCXXorObjC = getLangOpts().C99 || getLangOpts().CPlusPlus || getLangOpts().ObjC; // C99 6.8.5p5 - In C99, the for statement is a block. This is not // the case for C90. Start the loop scope. // // C++ 6.4p3: // A name introduced by a declaration in a condition is in scope from its // point of declaration until the end of the substatements controlled by the // condition. // C++ 3.3.2p4: // Names declared in the for-init-statement, and in the condition of if, // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // C++ 6.5.3p1: // Names declared in the for-init-statement are in the same declarative-region // as those declared in the condition. // unsigned ScopeFlags = 0; if (C99orCXXorObjC) ScopeFlags = Scope::DeclScope | Scope::ControlScope; ParseScope ForScope(this, ScopeFlags); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ExprResult Value; bool ForEach = false; StmtResult FirstPart; Sema::ConditionResult SecondPart; ExprResult Collection; ForRangeInfo ForRangeInfo; FullExprArg ThirdPart(Actions); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), C99orCXXorObjC? Sema::PCC_ForInit : Sema::PCC_Expression); cutOffParsing(); return StmtError(); } ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); SourceLocation EmptyInitStmtSemiLoc; // Parse the first part of the for specifier. if (Tok.is(tok::semi)) { // for (; ProhibitAttributes(attrs); // no first part, eat the ';'. SourceLocation SemiLoc = Tok.getLocation(); if (!Tok.hasLeadingEmptyMacro() && !SemiLoc.isMacroID()) EmptyInitStmtSemiLoc = SemiLoc; ConsumeToken(); } else if (getLangOpts().CPlusPlus && Tok.is(tok::identifier) && isForRangeIdentifier()) { ProhibitAttributes(attrs); IdentifierInfo *Name = Tok.getIdentifierInfo(); SourceLocation Loc = ConsumeToken(); MaybeParseCXX11Attributes(attrs); ForRangeInfo.ColonLoc = ConsumeToken(); if (Tok.is(tok::l_brace)) ForRangeInfo.RangeExpr = ParseBraceInitializer(); else ForRangeInfo.RangeExpr = ParseExpression(); Diag(Loc, diag::err_for_range_identifier) << ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus17) ? FixItHint::CreateInsertion(Loc, "auto &&") : FixItHint()); ForRangeInfo.LoopVar = Actions.ActOnCXXForRangeIdentifier( getCurScope(), Loc, Name, attrs, attrs.Range.getEnd()); } else if (isForInitDeclaration()) { // for (int X = 4; ParenBraceBracketBalancer BalancerRAIIObj(*this); // Parse declaration, which eats the ';'. if (!C99orCXXorObjC) { // Use of C99-style for loops in C90 mode? Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); Diag(Tok, diag::warn_gcc_variable_decl_in_for_loop); } // In C++0x, "for (T NS:a" might not be a typo for :: bool MightBeForRangeStmt = getLangOpts().CPlusPlus; ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy DG = ParseSimpleDeclaration( DeclaratorContext::ForContext, DeclEnd, attrs, false, MightBeForRangeStmt ? &ForRangeInfo : nullptr); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (ForRangeInfo.ParsedForRangeDecl()) { Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_for_range : diag::ext_for_range); ForRangeInfo.LoopVar = FirstPart; FirstPart = StmtResult(); } else if (Tok.is(tok::semi)) { // for (int x = 4; ConsumeToken(); } else if ((ForEach = isTokIdentifier_in())) { Actions.ActOnForEachDeclStmt(DG); // ObjC: for (id x in expr) ConsumeToken(); // consume 'in' if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCForCollection(getCurScope(), DG); cutOffParsing(); return StmtError(); } Collection = ParseExpression(); } else { Diag(Tok, diag::err_expected_semi_for); } } else { ProhibitAttributes(attrs); Value = Actions.CorrectDelayedTyposInExpr(ParseExpression()); ForEach = isTokIdentifier_in(); // Turn the expression into a stmt. if (!Value.isInvalid()) { if (ForEach) FirstPart = Actions.ActOnForEachLValueExpr(Value.get()); else { // We already know this is not an init-statement within a for loop, so // if we are parsing a C++11 range-based for loop, we should treat this // expression statement as being a discarded value expression because // we will err below. This way we do not warn on an unused expression // that was an error in the first place, like with: for (expr : expr); bool IsRangeBasedFor = getLangOpts().CPlusPlus11 && !ForEach && Tok.is(tok::colon); FirstPart = Actions.ActOnExprStmt(Value, !IsRangeBasedFor); } } if (Tok.is(tok::semi)) { ConsumeToken(); } else if (ForEach) { ConsumeToken(); // consume 'in' if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr); cutOffParsing(); return StmtError(); } Collection = ParseExpression(); } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::colon) && FirstPart.get()) { // User tried to write the reasonable, but ill-formed, for-range-statement // for (expr : expr) { ... } Diag(Tok, diag::err_for_range_expected_decl) << FirstPart.get()->getSourceRange(); SkipUntil(tok::r_paren, StopBeforeMatch); SecondPart = Sema::ConditionError(); } else { if (!Value.isInvalid()) { Diag(Tok, diag::err_expected_semi_for); } else { // Skip until semicolon or rparen, don't consume it. SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); } } } // Parse the second part of the for specifier. getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope); if (!ForEach && !ForRangeInfo.ParsedForRangeDecl() && !SecondPart.isInvalid()) { // Parse the second part of the for specifier. if (Tok.is(tok::semi)) { // for (...;; // no second part. } else if (Tok.is(tok::r_paren)) { // missing both semicolons. } else { if (getLangOpts().CPlusPlus) { // C++2a: We've parsed an init-statement; we might have a // for-range-declaration next. bool MightBeForRangeStmt = !ForRangeInfo.ParsedForRangeDecl(); ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); SecondPart = ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean, MightBeForRangeStmt ? &ForRangeInfo : nullptr); if (ForRangeInfo.ParsedForRangeDecl()) { Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc() : ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_for_range_init_stmt : diag::ext_for_range_init_stmt) << (FirstPart.get() ? FirstPart.get()->getSourceRange() : SourceRange()); if (EmptyInitStmtSemiLoc.isValid()) { Diag(EmptyInitStmtSemiLoc, diag::warn_empty_init_statement) << /*for-loop*/ 2 << FixItHint::CreateRemoval(EmptyInitStmtSemiLoc); } } } else { ExprResult SecondExpr = ParseExpression(); if (SecondExpr.isInvalid()) SecondPart = Sema::ConditionError(); else SecondPart = Actions.ActOnCondition(getCurScope(), ForLoc, SecondExpr.get(), Sema::ConditionKind::Boolean); } } } // Parse the third part of the for statement. if (!ForEach && !ForRangeInfo.ParsedForRangeDecl()) { if (Tok.isNot(tok::semi)) { if (!SecondPart.isInvalid()) Diag(Tok, diag::err_expected_semi_for); else // Skip until semicolon or rparen, don't consume it. SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); } if (Tok.is(tok::semi)) { ConsumeToken(); } if (Tok.isNot(tok::r_paren)) { // for (...;...;) ExprResult Third = ParseExpression(); // FIXME: The C++11 standard doesn't actually say that this is a // discarded-value expression, but it clearly should be. ThirdPart = Actions.MakeFullDiscardedValueExpr(Third.get()); } } // Match the ')'. T.consumeClose(); // C++ Coroutines [stmt.iter]: // 'co_await' can only be used for a range-based for statement. if (CoawaitLoc.isValid() && !ForRangeInfo.ParsedForRangeDecl()) { Diag(CoawaitLoc, diag::err_for_co_await_not_range_for); CoawaitLoc = SourceLocation(); } // We need to perform most of the semantic analysis for a C++0x for-range // statememt before parsing the body, in order to be able to deduce the type // of an auto-typed loop variable. StmtResult ForRangeStmt; StmtResult ForEachStmt; if (ForRangeInfo.ParsedForRangeDecl()) { ExprResult CorrectedRange = Actions.CorrectDelayedTyposInExpr(ForRangeInfo.RangeExpr.get()); ForRangeStmt = Actions.ActOnCXXForRangeStmt( getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(), ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, CorrectedRange.get(), T.getCloseLocation(), Sema::BFRK_Build); // Similarly, we need to do the semantic analysis for a for-range // statement immediately in order to close over temporaries correctly. } else if (ForEach) { ForEachStmt = Actions.ActOnObjCForCollectionStmt(ForLoc, FirstPart.get(), Collection.get(), T.getCloseLocation()); } else { // In OpenMP loop region loop control variable must be captured and be // private. Perform analysis of first part (if any). if (getLangOpts().OpenMP && FirstPart.isUsable()) { Actions.ActOnOpenMPLoopInitialization(ForLoc, FirstPart.get()); } } // C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. // // C++ 6.5p2: // The substatement in an iteration-statement implicitly defines a local scope // which is entered and exited each time through the loop. // // See comments in ParseIfStatement for why we create a scope for // for-init-statement/condition and a new scope for substatement in C++. // ParseScope InnerScope(this, Scope::DeclScope, C99orCXXorObjC, Tok.is(tok::l_brace)); // The body of the for loop has the same local mangling number as the // for-init-statement. // It will only be incremented if the body contains other things that would // normally increment the mangling number (like a compound statement). if (C99orCXXorObjC) getCurScope()->decrementMSManglingNumber(); MisleadingIndentationChecker MIChecker(*this, MSK_for, ForLoc); // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); if (Body.isUsable()) MIChecker.Check(); // Pop the body scope if needed. InnerScope.Exit(); // Leave the for-scope. ForScope.Exit(); if (Body.isInvalid()) return StmtError(); if (ForEach) return Actions.FinishObjCForCollectionStmt(ForEachStmt.get(), Body.get()); if (ForRangeInfo.ParsedForRangeDecl()) return Actions.FinishCXXForRangeStmt(ForRangeStmt.get(), Body.get()); return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.get(), SecondPart, ThirdPart, T.getCloseLocation(), Body.get()); } /// ParseGotoStatement /// jump-statement: /// 'goto' identifier ';' /// [GNU] 'goto' '*' expression ';' /// /// Note: this lets the caller parse the end ';'. /// StmtResult Parser::ParseGotoStatement() { assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. StmtResult Res; if (Tok.is(tok::identifier)) { LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), Tok.getLocation()); Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), LD); ConsumeToken(); } else if (Tok.is(tok::star)) { // GNU indirect goto extension. Diag(Tok, diag::ext_gnu_indirect_goto); SourceLocation StarLoc = ConsumeToken(); ExprResult R(ParseExpression()); if (R.isInvalid()) { // Skip to the semicolon, but don't consume it. SkipUntil(tok::semi, StopBeforeMatch); return StmtError(); } Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.get()); } else { Diag(Tok, diag::err_expected) << tok::identifier; return StmtError(); } return Res; } /// ParseContinueStatement /// jump-statement: /// 'continue' ';' /// /// Note: this lets the caller parse the end ';'. /// StmtResult Parser::ParseContinueStatement() { SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. return Actions.ActOnContinueStmt(ContinueLoc, getCurScope()); } /// ParseBreakStatement /// jump-statement: /// 'break' ';' /// /// Note: this lets the caller parse the end ';'. /// StmtResult Parser::ParseBreakStatement() { SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. return Actions.ActOnBreakStmt(BreakLoc, getCurScope()); } /// ParseReturnStatement /// jump-statement: /// 'return' expression[opt] ';' /// 'return' braced-init-list ';' /// 'co_return' expression[opt] ';' /// 'co_return' braced-init-list ';' StmtResult Parser::ParseReturnStatement() { assert((Tok.is(tok::kw_return) || Tok.is(tok::kw_co_return)) && "Not a return stmt!"); bool IsCoreturn = Tok.is(tok::kw_co_return); SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. ExprResult R; if (Tok.isNot(tok::semi)) { if (!IsCoreturn) PreferredType.enterReturn(Actions, Tok.getLocation()); // FIXME: Code completion for co_return. if (Tok.is(tok::code_completion) && !IsCoreturn) { Actions.CodeCompleteExpression(getCurScope(), PreferredType.get(Tok.getLocation())); cutOffParsing(); return StmtError(); } if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus) { R = ParseInitializer(); if (R.isUsable()) Diag(R.get()->getBeginLoc(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_generalized_initializer_lists : diag::ext_generalized_initializer_lists) << R.get()->getSourceRange(); } else R = ParseExpression(); if (R.isInvalid()) { SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); return StmtError(); } } if (IsCoreturn) return Actions.ActOnCoreturnStmt(getCurScope(), ReturnLoc, R.get()); return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope()); } StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) { // Create temporary attribute list. ParsedAttributesWithRange TempAttrs(AttrFactory); SourceLocation StartLoc = Tok.getLocation(); // Get loop hints and consume annotated token. while (Tok.is(tok::annot_pragma_loop_hint)) { LoopHint Hint; if (!HandlePragmaLoopHint(Hint)) continue; ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.StateLoc, ArgsUnion(Hint.ValueExpr)}; TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr, Hint.PragmaNameLoc->Loc, ArgHints, 4, ParsedAttr::AS_Pragma); } // Get the next statement. MaybeParseCXX11Attributes(Attrs); StmtResult S = ParseStatementOrDeclarationAfterAttributes( Stmts, StmtCtx, TrailingElseLoc, Attrs); Attrs.takeAllFrom(TempAttrs); // Start of attribute range may already be set for some invalid input. // See PR46336. if (Attrs.Range.getBegin().isInvalid()) Attrs.Range.setBegin(StartLoc); return S; } Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); PrettyDeclStackTraceEntry CrashInfo(Actions.Context, Decl, LBraceLoc, "parsing function body"); // Save and reset current vtordisp stack if we have entered a C++ method body. bool IsCXXMethod = getLangOpts().CPlusPlus && Decl && isa(Decl); Sema::PragmaStackSentinelRAII PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod); // Do not enter a scope for the brace, as the arguments are in the same scope // (the function body) as the body itself. Instead, just read the statement // list and put it into a CompoundStmt for safe keeping. StmtResult FnBody(ParseCompoundStatementBody()); // If the function body could not be parsed, make a bogus compoundstmt. if (FnBody.isInvalid()) { Sema::CompoundScopeRAII CompoundScope(Actions); FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false); } BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, FnBody.get()); } /// ParseFunctionTryBlock - Parse a C++ function-try-block. /// /// function-try-block: /// 'try' ctor-initializer[opt] compound-statement handler-seq /// Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); PrettyDeclStackTraceEntry CrashInfo(Actions.Context, Decl, TryLoc, "parsing function try block"); // Constructor initializer list? if (Tok.is(tok::colon)) ParseConstructorInitializer(Decl); else Actions.ActOnDefaultCtorInitializers(Decl); // Save and reset current vtordisp stack if we have entered a C++ method body. bool IsCXXMethod = getLangOpts().CPlusPlus && Decl && isa(Decl); Sema::PragmaStackSentinelRAII PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod); SourceLocation LBraceLoc = Tok.getLocation(); StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc, /*FnTry*/true)); // If we failed to parse the try-catch, we just give the function an empty // compound statement as the body. if (FnBody.isInvalid()) { Sema::CompoundScopeRAII CompoundScope(Actions); FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false); } BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, FnBody.get()); } bool Parser::trySkippingFunctionBody() { assert(SkipFunctionBodies && "Should only be called when SkipFunctionBodies is enabled"); if (!PP.isCodeCompletionEnabled()) { SkipFunctionBody(); return true; } // We're in code-completion mode. Skip parsing for all function bodies unless // the body contains the code-completion point. TentativeParsingAction PA(*this); bool IsTryCatch = Tok.is(tok::kw_try); CachedTokens Toks; bool ErrorInPrologue = ConsumeAndStoreFunctionPrologue(Toks); if (llvm::any_of(Toks, [](const Token &Tok) { return Tok.is(tok::code_completion); })) { PA.Revert(); return false; } if (ErrorInPrologue) { PA.Commit(); SkipMalformedDecl(); return true; } if (!SkipUntil(tok::r_brace, StopAtCodeCompletion)) { PA.Revert(); return false; } while (IsTryCatch && Tok.is(tok::kw_catch)) { if (!SkipUntil(tok::l_brace, StopAtCodeCompletion) || !SkipUntil(tok::r_brace, StopAtCodeCompletion)) { PA.Revert(); return false; } } PA.Commit(); return true; } /// ParseCXXTryBlock - Parse a C++ try-block. /// /// try-block: /// 'try' compound-statement handler-seq /// StmtResult Parser::ParseCXXTryBlock() { assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); return ParseCXXTryBlockCommon(TryLoc); } /// ParseCXXTryBlockCommon - Parse the common part of try-block and /// function-try-block. /// /// try-block: /// 'try' compound-statement handler-seq /// /// function-try-block: /// 'try' ctor-initializer[opt] compound-statement handler-seq /// /// handler-seq: /// handler handler-seq[opt] /// /// [Borland] try-block: /// 'try' compound-statement seh-except-block /// 'try' compound-statement seh-finally-block /// StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); StmtResult TryBlock(ParseCompoundStatement( /*isStmtExpr=*/false, Scope::DeclScope | Scope::TryScope | Scope::CompoundStmtScope | (FnTry ? Scope::FnTryCatchScope : 0))); if (TryBlock.isInvalid()) return TryBlock; // Borland allows SEH-handlers with 'try' if ((Tok.is(tok::identifier) && Tok.getIdentifierInfo() == getSEHExceptKeyword()) || Tok.is(tok::kw___finally)) { // TODO: Factor into common return ParseSEHHandlerCommon(...) StmtResult Handler; if(Tok.getIdentifierInfo() == getSEHExceptKeyword()) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHExceptBlock(Loc); } else { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHFinallyBlock(Loc); } if(Handler.isInvalid()) return Handler; return Actions.ActOnSEHTryBlock(true /* IsCXXTry */, TryLoc, TryBlock.get(), Handler.get()); } else { StmtVector Handlers; // C++11 attributes can't appear here, despite this context seeming // statement-like. DiagnoseAndSkipCXX11Attributes(); if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); while (Tok.is(tok::kw_catch)) { StmtResult Handler(ParseCXXCatchBlock(FnTry)); if (!Handler.isInvalid()) Handlers.push_back(Handler.get()); } // Don't bother creating the full statement if we don't have any usable // handlers. if (Handlers.empty()) return StmtError(); return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.get(), Handlers); } } /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard /// /// handler: /// 'catch' '(' exception-declaration ')' compound-statement /// /// exception-declaration: /// attribute-specifier-seq[opt] type-specifier-seq declarator /// attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt] /// '...' /// StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) { assert(Tok.is(tok::kw_catch) && "Expected 'catch'"); SourceLocation CatchLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume()) return StmtError(); // C++ 3.3.2p3: // The name in a catch exception-declaration is local to the handler and // shall not be redeclared in the outermost block of the handler. ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope | Scope::CatchScope | (FnCatch ? Scope::FnTryCatchScope : 0)); // exception-declaration is equivalent to '...' or a parameter-declaration // without default arguments. Decl *ExceptionDecl = nullptr; if (Tok.isNot(tok::ellipsis)) { ParsedAttributesWithRange Attributes(AttrFactory); MaybeParseCXX11Attributes(Attributes); DeclSpec DS(AttrFactory); DS.takeAttributesFrom(Attributes); if (ParseCXXTypeSpecifierSeq(DS)) return StmtError(); Declarator ExDecl(DS, DeclaratorContext::CXXCatchContext); ParseDeclarator(ExDecl); ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl); } else ConsumeToken(); T.consumeClose(); if (T.getCloseLocation().isInvalid()) return StmtError(); if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? StmtResult Block(ParseCompoundStatement()); if (Block.isInvalid()) return Block; return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.get()); } void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { IfExistsCondition Result; if (ParseMicrosoftIfExistsCondition(Result)) return; // Handle dependent statements by parsing the braces as a compound statement. // This is not the same behavior as Visual C++, which don't treat this as a // compound statement, but for Clang's type checking we can't have anything // inside these braces escaping to the surrounding code. if (Result.Behavior == IEB_Dependent) { if (!Tok.is(tok::l_brace)) { Diag(Tok, diag::err_expected) << tok::l_brace; return; } StmtResult Compound = ParseCompoundStatement(); if (Compound.isInvalid()) return; StmtResult DepResult = Actions.ActOnMSDependentExistsStmt(Result.KeywordLoc, Result.IsIfExists, Result.SS, Result.Name, Compound.get()); if (DepResult.isUsable()) Stmts.push_back(DepResult.get()); return; } BalancedDelimiterTracker Braces(*this, tok::l_brace); if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected) << tok::l_brace; return; } switch (Result.Behavior) { case IEB_Parse: // Parse the statements below. break; case IEB_Dependent: llvm_unreachable("Dependent case handled above"); case IEB_Skip: Braces.skipToEnd(); return; } // Condition is true, parse the statements. while (Tok.isNot(tok::r_brace)) { StmtResult R = ParseStatementOrDeclaration(Stmts, ParsedStmtContext::Compound); if (R.isUsable()) Stmts.push_back(R.get()); } Braces.consumeClose(); } bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) { MaybeParseGNUAttributes(Attrs); if (Attrs.empty()) return true; if (Attrs.begin()->getKind() != ParsedAttr::AT_OpenCLUnrollHint) return true; if (!(Tok.is(tok::kw_for) || Tok.is(tok::kw_while) || Tok.is(tok::kw_do))) { Diag(Tok, diag::err_opencl_unroll_hint_on_non_loop); return false; } return true; } diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index a96ea1e69bcc..26d127e1262f 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -1,9339 +1,9344 @@ //===---------------- SemaCodeComplete.cpp - Code Completion ----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the code-completion semantic actions. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTConcept.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/QualTypeNames.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Specifiers.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include using namespace clang; using namespace sema; namespace { /// A container of code-completion results. class ResultBuilder { public: /// The type of a name-lookup filter, which can be provided to the /// name-lookup routines to specify which declarations should be included in /// the result set (when it returns true) and which declarations should be /// filtered out (returns false). typedef bool (ResultBuilder::*LookupFilter)(const NamedDecl *) const; typedef CodeCompletionResult Result; private: /// The actual results we have found. std::vector Results; /// A record of all of the declarations we have found and placed /// into the result set, used to ensure that no declaration ever gets into /// the result set twice. llvm::SmallPtrSet AllDeclsFound; typedef std::pair DeclIndexPair; /// An entry in the shadow map, which is optimized to store /// a single (declaration, index) mapping (the common case) but /// can also store a list of (declaration, index) mappings. class ShadowMapEntry { typedef SmallVector DeclIndexPairVector; /// Contains either the solitary NamedDecl * or a vector /// of (declaration, index) pairs. llvm::PointerUnion DeclOrVector; /// When the entry contains a single declaration, this is /// the index associated with that entry. unsigned SingleDeclIndex; public: ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) {} ShadowMapEntry(const ShadowMapEntry &) = delete; ShadowMapEntry(ShadowMapEntry &&Move) { *this = std::move(Move); } ShadowMapEntry &operator=(const ShadowMapEntry &) = delete; ShadowMapEntry &operator=(ShadowMapEntry &&Move) { SingleDeclIndex = Move.SingleDeclIndex; DeclOrVector = Move.DeclOrVector; Move.DeclOrVector = nullptr; return *this; } void Add(const NamedDecl *ND, unsigned Index) { if (DeclOrVector.isNull()) { // 0 - > 1 elements: just set the single element information. DeclOrVector = ND; SingleDeclIndex = Index; return; } if (const NamedDecl *PrevND = DeclOrVector.dyn_cast()) { // 1 -> 2 elements: create the vector of results and push in the // existing declaration. DeclIndexPairVector *Vec = new DeclIndexPairVector; Vec->push_back(DeclIndexPair(PrevND, SingleDeclIndex)); DeclOrVector = Vec; } // Add the new element to the end of the vector. DeclOrVector.get()->push_back( DeclIndexPair(ND, Index)); } ~ShadowMapEntry() { if (DeclIndexPairVector *Vec = DeclOrVector.dyn_cast()) { delete Vec; DeclOrVector = ((NamedDecl *)nullptr); } } // Iteration. class iterator; iterator begin() const; iterator end() const; }; /// A mapping from declaration names to the declarations that have /// this name within a particular scope and their index within the list of /// results. typedef llvm::DenseMap ShadowMap; /// The semantic analysis object for which results are being /// produced. Sema &SemaRef; /// The allocator used to allocate new code-completion strings. CodeCompletionAllocator &Allocator; CodeCompletionTUInfo &CCTUInfo; /// If non-NULL, a filter function used to remove any code-completion /// results that are not desirable. LookupFilter Filter; /// Whether we should allow declarations as /// nested-name-specifiers that would otherwise be filtered out. bool AllowNestedNameSpecifiers; /// If set, the type that we would prefer our resulting value /// declarations to have. /// /// Closely matching the preferred type gives a boost to a result's /// priority. CanQualType PreferredType; /// A list of shadow maps, which is used to model name hiding at /// different levels of, e.g., the inheritance hierarchy. std::list ShadowMaps; /// Overloaded C++ member functions found by SemaLookup. /// Used to determine when one overload is dominated by another. llvm::DenseMap, ShadowMapEntry> OverloadMap; /// If we're potentially referring to a C++ member function, the set /// of qualifiers applied to the object type. Qualifiers ObjectTypeQualifiers; /// The kind of the object expression, for rvalue/lvalue overloads. ExprValueKind ObjectKind; /// Whether the \p ObjectTypeQualifiers field is active. bool HasObjectTypeQualifiers; /// The selector that we prefer. Selector PreferredSelector; /// The completion context in which we are gathering results. CodeCompletionContext CompletionContext; /// If we are in an instance method definition, the \@implementation /// object. ObjCImplementationDecl *ObjCImplementation; void AdjustResultPriorityForDecl(Result &R); void MaybeAddConstructorResults(Result R); public: explicit ResultBuilder(Sema &SemaRef, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, const CodeCompletionContext &CompletionContext, LookupFilter Filter = nullptr) : SemaRef(SemaRef), Allocator(Allocator), CCTUInfo(CCTUInfo), Filter(Filter), AllowNestedNameSpecifiers(false), HasObjectTypeQualifiers(false), CompletionContext(CompletionContext), ObjCImplementation(nullptr) { // If this is an Objective-C instance method definition, dig out the // corresponding implementation. switch (CompletionContext.getKind()) { case CodeCompletionContext::CCC_Expression: case CodeCompletionContext::CCC_ObjCMessageReceiver: case CodeCompletionContext::CCC_ParenthesizedExpression: case CodeCompletionContext::CCC_Statement: case CodeCompletionContext::CCC_Recovery: if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) if (Method->isInstanceMethod()) if (ObjCInterfaceDecl *Interface = Method->getClassInterface()) ObjCImplementation = Interface->getImplementation(); break; default: break; } } /// Determine the priority for a reference to the given declaration. unsigned getBasePriority(const NamedDecl *D); /// Whether we should include code patterns in the completion /// results. bool includeCodePatterns() const { return SemaRef.CodeCompleter && SemaRef.CodeCompleter->includeCodePatterns(); } /// Set the filter used for code-completion results. void setFilter(LookupFilter Filter) { this->Filter = Filter; } Result *data() { return Results.empty() ? nullptr : &Results.front(); } unsigned size() const { return Results.size(); } bool empty() const { return Results.empty(); } /// Specify the preferred type. void setPreferredType(QualType T) { PreferredType = SemaRef.Context.getCanonicalType(T); } /// Set the cv-qualifiers on the object type, for us in filtering /// calls to member functions. /// /// When there are qualifiers in this set, they will be used to filter /// out member functions that aren't available (because there will be a /// cv-qualifier mismatch) or prefer functions with an exact qualifier /// match. void setObjectTypeQualifiers(Qualifiers Quals, ExprValueKind Kind) { ObjectTypeQualifiers = Quals; ObjectKind = Kind; HasObjectTypeQualifiers = true; } /// Set the preferred selector. /// /// When an Objective-C method declaration result is added, and that /// method's selector matches this preferred selector, we give that method /// a slight priority boost. void setPreferredSelector(Selector Sel) { PreferredSelector = Sel; } /// Retrieve the code-completion context for which results are /// being collected. const CodeCompletionContext &getCompletionContext() const { return CompletionContext; } /// Specify whether nested-name-specifiers are allowed. void allowNestedNameSpecifiers(bool Allow = true) { AllowNestedNameSpecifiers = Allow; } /// Return the semantic analysis object for which we are collecting /// code completion results. Sema &getSema() const { return SemaRef; } /// Retrieve the allocator used to allocate code completion strings. CodeCompletionAllocator &getAllocator() const { return Allocator; } CodeCompletionTUInfo &getCodeCompletionTUInfo() const { return CCTUInfo; } /// Determine whether the given declaration is at all interesting /// as a code-completion result. /// /// \param ND the declaration that we are inspecting. /// /// \param AsNestedNameSpecifier will be set true if this declaration is /// only interesting when it is a nested-name-specifier. bool isInterestingDecl(const NamedDecl *ND, bool &AsNestedNameSpecifier) const; /// Check whether the result is hidden by the Hiding declaration. /// /// \returns true if the result is hidden and cannot be found, false if /// the hidden result could still be found. When false, \p R may be /// modified to describe how the result can be found (e.g., via extra /// qualification). bool CheckHiddenResult(Result &R, DeclContext *CurContext, const NamedDecl *Hiding); /// Add a new result to this result set (if it isn't already in one /// of the shadow maps), or replace an existing result (for, e.g., a /// redeclaration). /// /// \param R the result to add (if it is unique). /// /// \param CurContext the context in which this result will be named. void MaybeAddResult(Result R, DeclContext *CurContext = nullptr); /// Add a new result to this result set, where we already know /// the hiding declaration (if any). /// /// \param R the result to add (if it is unique). /// /// \param CurContext the context in which this result will be named. /// /// \param Hiding the declaration that hides the result. /// /// \param InBaseClass whether the result was found in a base /// class of the searched context. void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding, bool InBaseClass); /// Add a new non-declaration result to this result set. void AddResult(Result R); /// Enter into a new scope. void EnterNewScope(); /// Exit from the current scope. void ExitScope(); /// Ignore this declaration, if it is seen again. void Ignore(const Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); } /// Add a visited context. void addVisitedContext(DeclContext *Ctx) { CompletionContext.addVisitedContext(Ctx); } /// \name Name lookup predicates /// /// These predicates can be passed to the name lookup functions to filter the /// results of name lookup. All of the predicates have the same type, so that /// //@{ bool IsOrdinaryName(const NamedDecl *ND) const; bool IsOrdinaryNonTypeName(const NamedDecl *ND) const; bool IsIntegralConstantValue(const NamedDecl *ND) const; bool IsOrdinaryNonValueName(const NamedDecl *ND) const; bool IsNestedNameSpecifier(const NamedDecl *ND) const; bool IsEnum(const NamedDecl *ND) const; bool IsClassOrStruct(const NamedDecl *ND) const; bool IsUnion(const NamedDecl *ND) const; bool IsNamespace(const NamedDecl *ND) const; bool IsNamespaceOrAlias(const NamedDecl *ND) const; bool IsType(const NamedDecl *ND) const; bool IsMember(const NamedDecl *ND) const; bool IsObjCIvar(const NamedDecl *ND) const; bool IsObjCMessageReceiver(const NamedDecl *ND) const; bool IsObjCMessageReceiverOrLambdaCapture(const NamedDecl *ND) const; bool IsObjCCollection(const NamedDecl *ND) const; bool IsImpossibleToSatisfy(const NamedDecl *ND) const; //@} }; } // namespace void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) { if (isa(S.CurContext)) { if (sema::BlockScopeInfo *BSI = S.getCurBlock()) { ComputeType = nullptr; Type = BSI->ReturnType; ExpectedLoc = Tok; } } else if (const auto *Function = dyn_cast(S.CurContext)) { ComputeType = nullptr; Type = Function->getReturnType(); ExpectedLoc = Tok; } else if (const auto *Method = dyn_cast(S.CurContext)) { ComputeType = nullptr; Type = Method->getReturnType(); ExpectedLoc = Tok; } } void PreferredTypeBuilder::enterVariableInit(SourceLocation Tok, Decl *D) { auto *VD = llvm::dyn_cast_or_null(D); ComputeType = nullptr; Type = VD ? VD->getType() : QualType(); ExpectedLoc = Tok; } void PreferredTypeBuilder::enterFunctionArgument( SourceLocation Tok, llvm::function_ref ComputeType) { this->ComputeType = ComputeType; Type = QualType(); ExpectedLoc = Tok; } void PreferredTypeBuilder::enterParenExpr(SourceLocation Tok, SourceLocation LParLoc) { // expected type for parenthesized expression does not change. if (ExpectedLoc == LParLoc) ExpectedLoc = Tok; } static QualType getPreferredTypeOfBinaryRHS(Sema &S, Expr *LHS, tok::TokenKind Op) { if (!LHS) return QualType(); QualType LHSType = LHS->getType(); if (LHSType->isPointerType()) { if (Op == tok::plus || Op == tok::plusequal || Op == tok::minusequal) return S.getASTContext().getPointerDiffType(); // Pointer difference is more common than subtracting an int from a pointer. if (Op == tok::minus) return LHSType; } switch (Op) { // No way to infer the type of RHS from LHS. case tok::comma: return QualType(); // Prefer the type of the left operand for all of these. // Arithmetic operations. case tok::plus: case tok::plusequal: case tok::minus: case tok::minusequal: case tok::percent: case tok::percentequal: case tok::slash: case tok::slashequal: case tok::star: case tok::starequal: // Assignment. case tok::equal: // Comparison operators. case tok::equalequal: case tok::exclaimequal: case tok::less: case tok::lessequal: case tok::greater: case tok::greaterequal: case tok::spaceship: return LHS->getType(); // Binary shifts are often overloaded, so don't try to guess those. case tok::greatergreater: case tok::greatergreaterequal: case tok::lessless: case tok::lesslessequal: if (LHSType->isIntegralOrEnumerationType()) return S.getASTContext().IntTy; return QualType(); // Logical operators, assume we want bool. case tok::ampamp: case tok::pipepipe: case tok::caretcaret: return S.getASTContext().BoolTy; // Operators often used for bit manipulation are typically used with the type // of the left argument. case tok::pipe: case tok::pipeequal: case tok::caret: case tok::caretequal: case tok::amp: case tok::ampequal: if (LHSType->isIntegralOrEnumerationType()) return LHSType; return QualType(); // RHS should be a pointer to a member of the 'LHS' type, but we can't give // any particular type here. case tok::periodstar: case tok::arrowstar: return QualType(); default: // FIXME(ibiryukov): handle the missing op, re-add the assertion. // assert(false && "unhandled binary op"); return QualType(); } } /// Get preferred type for an argument of an unary expression. \p ContextType is /// preferred type of the whole unary expression. static QualType getPreferredTypeOfUnaryArg(Sema &S, QualType ContextType, tok::TokenKind Op) { switch (Op) { case tok::exclaim: return S.getASTContext().BoolTy; case tok::amp: if (!ContextType.isNull() && ContextType->isPointerType()) return ContextType->getPointeeType(); return QualType(); case tok::star: if (ContextType.isNull()) return QualType(); return S.getASTContext().getPointerType(ContextType.getNonReferenceType()); case tok::plus: case tok::minus: case tok::tilde: case tok::minusminus: case tok::plusplus: if (ContextType.isNull()) return S.getASTContext().IntTy; // leave as is, these operators typically return the same type. return ContextType; case tok::kw___real: case tok::kw___imag: return QualType(); default: assert(false && "unhandled unary op"); return QualType(); } } void PreferredTypeBuilder::enterBinary(Sema &S, SourceLocation Tok, Expr *LHS, tok::TokenKind Op) { ComputeType = nullptr; Type = getPreferredTypeOfBinaryRHS(S, LHS, Op); ExpectedLoc = Tok; } void PreferredTypeBuilder::enterMemAccess(Sema &S, SourceLocation Tok, Expr *Base) { if (!Base) return; // Do we have expected type for Base? if (ExpectedLoc != Base->getBeginLoc()) return; // Keep the expected type, only update the location. ExpectedLoc = Tok; return; } void PreferredTypeBuilder::enterUnary(Sema &S, SourceLocation Tok, tok::TokenKind OpKind, SourceLocation OpLoc) { ComputeType = nullptr; Type = getPreferredTypeOfUnaryArg(S, this->get(OpLoc), OpKind); ExpectedLoc = Tok; } void PreferredTypeBuilder::enterSubscript(Sema &S, SourceLocation Tok, Expr *LHS) { ComputeType = nullptr; Type = S.getASTContext().IntTy; ExpectedLoc = Tok; } void PreferredTypeBuilder::enterTypeCast(SourceLocation Tok, QualType CastType) { ComputeType = nullptr; Type = !CastType.isNull() ? CastType.getCanonicalType() : QualType(); ExpectedLoc = Tok; } void PreferredTypeBuilder::enterCondition(Sema &S, SourceLocation Tok) { ComputeType = nullptr; Type = S.getASTContext().BoolTy; ExpectedLoc = Tok; } class ResultBuilder::ShadowMapEntry::iterator { llvm::PointerUnion DeclOrIterator; unsigned SingleDeclIndex; public: typedef DeclIndexPair value_type; typedef value_type reference; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; class pointer { DeclIndexPair Value; public: pointer(const DeclIndexPair &Value) : Value(Value) {} const DeclIndexPair *operator->() const { return &Value; } }; iterator() : DeclOrIterator((NamedDecl *)nullptr), SingleDeclIndex(0) {} iterator(const NamedDecl *SingleDecl, unsigned Index) : DeclOrIterator(SingleDecl), SingleDeclIndex(Index) {} iterator(const DeclIndexPair *Iterator) : DeclOrIterator(Iterator), SingleDeclIndex(0) {} iterator &operator++() { if (DeclOrIterator.is()) { DeclOrIterator = (NamedDecl *)nullptr; SingleDeclIndex = 0; return *this; } const DeclIndexPair *I = DeclOrIterator.get(); ++I; DeclOrIterator = I; return *this; } /*iterator operator++(int) { iterator tmp(*this); ++(*this); return tmp; }*/ reference operator*() const { if (const NamedDecl *ND = DeclOrIterator.dyn_cast()) return reference(ND, SingleDeclIndex); return *DeclOrIterator.get(); } pointer operator->() const { return pointer(**this); } friend bool operator==(const iterator &X, const iterator &Y) { return X.DeclOrIterator.getOpaqueValue() == Y.DeclOrIterator.getOpaqueValue() && X.SingleDeclIndex == Y.SingleDeclIndex; } friend bool operator!=(const iterator &X, const iterator &Y) { return !(X == Y); } }; ResultBuilder::ShadowMapEntry::iterator ResultBuilder::ShadowMapEntry::begin() const { if (DeclOrVector.isNull()) return iterator(); if (const NamedDecl *ND = DeclOrVector.dyn_cast()) return iterator(ND, SingleDeclIndex); return iterator(DeclOrVector.get()->begin()); } ResultBuilder::ShadowMapEntry::iterator ResultBuilder::ShadowMapEntry::end() const { if (DeclOrVector.is() || DeclOrVector.isNull()) return iterator(); return iterator(DeclOrVector.get()->end()); } /// Compute the qualification required to get from the current context /// (\p CurContext) to the target context (\p TargetContext). /// /// \param Context the AST context in which the qualification will be used. /// /// \param CurContext the context where an entity is being named, which is /// typically based on the current scope. /// /// \param TargetContext the context in which the named entity actually /// resides. /// /// \returns a nested name specifier that refers into the target context, or /// NULL if no qualification is needed. static NestedNameSpecifier * getRequiredQualification(ASTContext &Context, const DeclContext *CurContext, const DeclContext *TargetContext) { SmallVector TargetParents; for (const DeclContext *CommonAncestor = TargetContext; CommonAncestor && !CommonAncestor->Encloses(CurContext); CommonAncestor = CommonAncestor->getLookupParent()) { if (CommonAncestor->isTransparentContext() || CommonAncestor->isFunctionOrMethod()) continue; TargetParents.push_back(CommonAncestor); } NestedNameSpecifier *Result = nullptr; while (!TargetParents.empty()) { const DeclContext *Parent = TargetParents.pop_back_val(); if (const auto *Namespace = dyn_cast(Parent)) { if (!Namespace->getIdentifier()) continue; Result = NestedNameSpecifier::Create(Context, Result, Namespace); } else if (const auto *TD = dyn_cast(Parent)) Result = NestedNameSpecifier::Create( Context, Result, false, Context.getTypeDeclType(TD).getTypePtr()); } return Result; } // Some declarations have reserved names that we don't want to ever show. // Filter out names reserved for the implementation if they come from a // system header. static bool shouldIgnoreDueToReservedName(const NamedDecl *ND, Sema &SemaRef) { const IdentifierInfo *Id = ND->getIdentifier(); if (!Id) return false; // Ignore reserved names for compiler provided decls. if (Id->isReservedName() && ND->getLocation().isInvalid()) return true; // For system headers ignore only double-underscore names. // This allows for system headers providing private symbols with a single // underscore. if (Id->isReservedName(/*doubleUnderscoreOnly=*/true) && SemaRef.SourceMgr.isInSystemHeader( SemaRef.SourceMgr.getSpellingLoc(ND->getLocation()))) return true; return false; } bool ResultBuilder::isInterestingDecl(const NamedDecl *ND, bool &AsNestedNameSpecifier) const { AsNestedNameSpecifier = false; auto *Named = ND; ND = ND->getUnderlyingDecl(); // Skip unnamed entities. if (!ND->getDeclName()) return false; // Friend declarations and declarations introduced due to friends are never // added as results. if (ND->getFriendObjectKind() == Decl::FOK_Undeclared) return false; // Class template (partial) specializations are never added as results. if (isa(ND) || isa(ND)) return false; // Using declarations themselves are never added as results. if (isa(ND)) return false; if (shouldIgnoreDueToReservedName(ND, SemaRef)) return false; if (Filter == &ResultBuilder::IsNestedNameSpecifier || (isa(ND) && Filter != &ResultBuilder::IsNamespace && Filter != &ResultBuilder::IsNamespaceOrAlias && Filter != nullptr)) AsNestedNameSpecifier = true; // Filter out any unwanted results. if (Filter && !(this->*Filter)(Named)) { // Check whether it is interesting as a nested-name-specifier. if (AllowNestedNameSpecifiers && SemaRef.getLangOpts().CPlusPlus && IsNestedNameSpecifier(ND) && (Filter != &ResultBuilder::IsMember || (isa(ND) && cast(ND)->isInjectedClassName()))) { AsNestedNameSpecifier = true; return true; } return false; } // ... then it must be interesting! return true; } bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext, const NamedDecl *Hiding) { // In C, there is no way to refer to a hidden name. // FIXME: This isn't true; we can find a tag name hidden by an ordinary // name if we introduce the tag type. if (!SemaRef.getLangOpts().CPlusPlus) return true; const DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getRedeclContext(); // There is no way to qualify a name declared in a function or method. if (HiddenCtx->isFunctionOrMethod()) return true; if (HiddenCtx == Hiding->getDeclContext()->getRedeclContext()) return true; // We can refer to the result with the appropriate qualification. Do it. R.Hidden = true; R.QualifierIsInformative = false; if (!R.Qualifier) R.Qualifier = getRequiredQualification(SemaRef.Context, CurContext, R.Declaration->getDeclContext()); return false; } /// A simplified classification of types used to determine whether two /// types are "similar enough" when adjusting priorities. SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) { switch (T->getTypeClass()) { case Type::Builtin: switch (cast(T)->getKind()) { case BuiltinType::Void: return STC_Void; case BuiltinType::NullPtr: return STC_Pointer; case BuiltinType::Overload: case BuiltinType::Dependent: return STC_Other; case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: return STC_ObjectiveC; default: return STC_Arithmetic; } case Type::Complex: return STC_Arithmetic; case Type::Pointer: return STC_Pointer; case Type::BlockPointer: return STC_Block; case Type::LValueReference: case Type::RValueReference: return getSimplifiedTypeClass(T->getAs()->getPointeeType()); case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: return STC_Array; case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: return STC_Arithmetic; case Type::FunctionProto: case Type::FunctionNoProto: return STC_Function; case Type::Record: return STC_Record; case Type::Enum: return STC_Arithmetic; case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: return STC_ObjectiveC; default: return STC_Other; } } /// Get the type that a given expression will have if this declaration /// is used as an expression in its "typical" code-completion form. QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) { ND = ND->getUnderlyingDecl(); if (const auto *Type = dyn_cast(ND)) return C.getTypeDeclType(Type); if (const auto *Iface = dyn_cast(ND)) return C.getObjCInterfaceType(Iface); QualType T; if (const FunctionDecl *Function = ND->getAsFunction()) T = Function->getCallResultType(); else if (const auto *Method = dyn_cast(ND)) T = Method->getSendResultType(); else if (const auto *Enumerator = dyn_cast(ND)) T = C.getTypeDeclType(cast(Enumerator->getDeclContext())); else if (const auto *Property = dyn_cast(ND)) T = Property->getType(); else if (const auto *Value = dyn_cast(ND)) T = Value->getType(); if (T.isNull()) return QualType(); // Dig through references, function pointers, and block pointers to // get down to the likely type of an expression when the entity is // used. do { if (const auto *Ref = T->getAs()) { T = Ref->getPointeeType(); continue; } if (const auto *Pointer = T->getAs()) { if (Pointer->getPointeeType()->isFunctionType()) { T = Pointer->getPointeeType(); continue; } break; } if (const auto *Block = T->getAs()) { T = Block->getPointeeType(); continue; } if (const auto *Function = T->getAs()) { T = Function->getReturnType(); continue; } break; } while (true); return T; } unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) { if (!ND) return CCP_Unlikely; // Context-based decisions. const DeclContext *LexicalDC = ND->getLexicalDeclContext(); if (LexicalDC->isFunctionOrMethod()) { // _cmd is relatively rare if (const auto *ImplicitParam = dyn_cast(ND)) if (ImplicitParam->getIdentifier() && ImplicitParam->getIdentifier()->isStr("_cmd")) return CCP_ObjC_cmd; return CCP_LocalDeclaration; } const DeclContext *DC = ND->getDeclContext()->getRedeclContext(); if (DC->isRecord() || isa(DC)) { // Explicit destructor calls are very rare. if (isa(ND)) return CCP_Unlikely; // Explicit operator and conversion function calls are also very rare. auto DeclNameKind = ND->getDeclName().getNameKind(); if (DeclNameKind == DeclarationName::CXXOperatorName || DeclNameKind == DeclarationName::CXXLiteralOperatorName || DeclNameKind == DeclarationName::CXXConversionFunctionName) return CCP_Unlikely; return CCP_MemberDeclaration; } // Content-based decisions. if (isa(ND)) return CCP_Constant; // Use CCP_Type for type declarations unless we're in a statement, Objective-C // message receiver, or parenthesized expression context. There, it's as // likely that the user will want to write a type as other declarations. if ((isa(ND) || isa(ND)) && !(CompletionContext.getKind() == CodeCompletionContext::CCC_Statement || CompletionContext.getKind() == CodeCompletionContext::CCC_ObjCMessageReceiver || CompletionContext.getKind() == CodeCompletionContext::CCC_ParenthesizedExpression)) return CCP_Type; return CCP_Declaration; } void ResultBuilder::AdjustResultPriorityForDecl(Result &R) { // If this is an Objective-C method declaration whose selector matches our // preferred selector, give it a priority boost. if (!PreferredSelector.isNull()) if (const auto *Method = dyn_cast(R.Declaration)) if (PreferredSelector == Method->getSelector()) R.Priority += CCD_SelectorMatch; // If we have a preferred type, adjust the priority for results with exactly- // matching or nearly-matching types. if (!PreferredType.isNull()) { QualType T = getDeclUsageType(SemaRef.Context, R.Declaration); if (!T.isNull()) { CanQualType TC = SemaRef.Context.getCanonicalType(T); // Check for exactly-matching types (modulo qualifiers). if (SemaRef.Context.hasSameUnqualifiedType(PreferredType, TC)) R.Priority /= CCF_ExactTypeMatch; // Check for nearly-matching types, based on classification of each. else if ((getSimplifiedTypeClass(PreferredType) == getSimplifiedTypeClass(TC)) && !(PreferredType->isEnumeralType() && TC->isEnumeralType())) R.Priority /= CCF_SimilarTypeMatch; } } } static DeclContext::lookup_result getConstructors(ASTContext &Context, const CXXRecordDecl *Record) { QualType RecordTy = Context.getTypeDeclType(Record); DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(RecordTy)); return Record->lookup(ConstructorName); } void ResultBuilder::MaybeAddConstructorResults(Result R) { if (!SemaRef.getLangOpts().CPlusPlus || !R.Declaration || !CompletionContext.wantConstructorResults()) return; const NamedDecl *D = R.Declaration; const CXXRecordDecl *Record = nullptr; if (const ClassTemplateDecl *ClassTemplate = dyn_cast(D)) Record = ClassTemplate->getTemplatedDecl(); else if ((Record = dyn_cast(D))) { // Skip specializations and partial specializations. if (isa(Record)) return; } else { // There are no constructors here. return; } Record = Record->getDefinition(); if (!Record) return; for (NamedDecl *Ctor : getConstructors(SemaRef.Context, Record)) { R.Declaration = Ctor; R.CursorKind = getCursorKindForDecl(R.Declaration); Results.push_back(R); } } static bool isConstructor(const Decl *ND) { if (const auto *Tmpl = dyn_cast(ND)) ND = Tmpl->getTemplatedDecl(); return isa(ND); } void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { assert(!ShadowMaps.empty() && "Must enter into a results scope"); if (R.Kind != Result::RK_Declaration) { // For non-declaration results, just add the result. Results.push_back(R); return; } // Look through using declarations. if (const UsingShadowDecl *Using = dyn_cast(R.Declaration)) { CodeCompletionResult Result(Using->getTargetDecl(), getBasePriority(Using->getTargetDecl()), R.Qualifier); Result.ShadowDecl = Using; MaybeAddResult(Result, CurContext); return; } const Decl *CanonDecl = R.Declaration->getCanonicalDecl(); unsigned IDNS = CanonDecl->getIdentifierNamespace(); bool AsNestedNameSpecifier = false; if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier)) return; // C++ constructors are never found by name lookup. if (isConstructor(R.Declaration)) return; ShadowMap &SMap = ShadowMaps.back(); ShadowMapEntry::iterator I, IEnd; ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName()); if (NamePos != SMap.end()) { I = NamePos->second.begin(); IEnd = NamePos->second.end(); } for (; I != IEnd; ++I) { const NamedDecl *ND = I->first; unsigned Index = I->second; if (ND->getCanonicalDecl() == CanonDecl) { // This is a redeclaration. Always pick the newer declaration. Results[Index].Declaration = R.Declaration; // We're done. return; } } // This is a new declaration in this scope. However, check whether this // declaration name is hidden by a similarly-named declaration in an outer // scope. std::list::iterator SM, SMEnd = ShadowMaps.end(); --SMEnd; for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) { ShadowMapEntry::iterator I, IEnd; ShadowMap::iterator NamePos = SM->find(R.Declaration->getDeclName()); if (NamePos != SM->end()) { I = NamePos->second.begin(); IEnd = NamePos->second.end(); } for (; I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. if (I->first->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern | Decl::IDNS_ObjCProtocol))) continue; // Protocols are in distinct namespaces from everything else. if (((I->first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) || (IDNS & Decl::IDNS_ObjCProtocol)) && I->first->getIdentifierNamespace() != IDNS) continue; // The newly-added result is hidden by an entry in the shadow map. if (CheckHiddenResult(R, CurContext, I->first)) return; break; } } // Make sure that any given declaration only shows up in the result set once. if (!AllDeclsFound.insert(CanonDecl).second) return; // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. if (AsNestedNameSpecifier) { R.StartsNestedNameSpecifier = true; R.Priority = CCP_NestedNameSpecifier; } else AdjustResultPriorityForDecl(R); // If this result is supposed to have an informative qualifier, add one. if (R.QualifierIsInformative && !R.Qualifier && !R.StartsNestedNameSpecifier) { const DeclContext *Ctx = R.Declaration->getDeclContext(); if (const NamespaceDecl *Namespace = dyn_cast(Ctx)) R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, nullptr, Namespace); else if (const TagDecl *Tag = dyn_cast(Ctx)) R.Qualifier = NestedNameSpecifier::Create( SemaRef.Context, nullptr, false, SemaRef.Context.getTypeDeclType(Tag).getTypePtr()); else R.QualifierIsInformative = false; } // Insert this result into the set of results and into the current shadow // map. SMap[R.Declaration->getDeclName()].Add(R.Declaration, Results.size()); Results.push_back(R); if (!AsNestedNameSpecifier) MaybeAddConstructorResults(R); } static void setInBaseClass(ResultBuilder::Result &R) { R.Priority += CCD_InBaseClass; R.InBaseClass = true; } enum class OverloadCompare { BothViable, Dominates, Dominated }; // Will Candidate ever be called on the object, when overloaded with Incumbent? // Returns Dominates if Candidate is always called, Dominated if Incumbent is // always called, BothViable if either may be called dependending on arguments. // Precondition: must actually be overloads! static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate, const CXXMethodDecl &Incumbent, const Qualifiers &ObjectQuals, ExprValueKind ObjectKind) { // Base/derived shadowing is handled elsewhere. if (Candidate.getDeclContext() != Incumbent.getDeclContext()) return OverloadCompare::BothViable; if (Candidate.isVariadic() != Incumbent.isVariadic() || Candidate.getNumParams() != Incumbent.getNumParams() || Candidate.getMinRequiredArguments() != Incumbent.getMinRequiredArguments()) return OverloadCompare::BothViable; for (unsigned I = 0, E = Candidate.getNumParams(); I != E; ++I) if (Candidate.parameters()[I]->getType().getCanonicalType() != Incumbent.parameters()[I]->getType().getCanonicalType()) return OverloadCompare::BothViable; if (!llvm::empty(Candidate.specific_attrs()) || !llvm::empty(Incumbent.specific_attrs())) return OverloadCompare::BothViable; // At this point, we know calls can't pick one or the other based on // arguments, so one of the two must win. (Or both fail, handled elsewhere). RefQualifierKind CandidateRef = Candidate.getRefQualifier(); RefQualifierKind IncumbentRef = Incumbent.getRefQualifier(); if (CandidateRef != IncumbentRef) { // If the object kind is LValue/RValue, there's one acceptable ref-qualifier // and it can't be mixed with ref-unqualified overloads (in valid code). // For xvalue objects, we prefer the rvalue overload even if we have to // add qualifiers (which is rare, because const&& is rare). if (ObjectKind == clang::VK_XValue) return CandidateRef == RQ_RValue ? OverloadCompare::Dominates : OverloadCompare::Dominated; } // Now the ref qualifiers are the same (or we're in some invalid state). // So make some decision based on the qualifiers. Qualifiers CandidateQual = Candidate.getMethodQualifiers(); Qualifiers IncumbentQual = Incumbent.getMethodQualifiers(); bool CandidateSuperset = CandidateQual.compatiblyIncludes(IncumbentQual); bool IncumbentSuperset = IncumbentQual.compatiblyIncludes(CandidateQual); if (CandidateSuperset == IncumbentSuperset) return OverloadCompare::BothViable; return IncumbentSuperset ? OverloadCompare::Dominates : OverloadCompare::Dominated; } void ResultBuilder::AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding, bool InBaseClass = false) { if (R.Kind != Result::RK_Declaration) { // For non-declaration results, just add the result. Results.push_back(R); return; } // Look through using declarations. if (const auto *Using = dyn_cast(R.Declaration)) { CodeCompletionResult Result(Using->getTargetDecl(), getBasePriority(Using->getTargetDecl()), R.Qualifier); Result.ShadowDecl = Using; AddResult(Result, CurContext, Hiding); return; } bool AsNestedNameSpecifier = false; if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier)) return; // C++ constructors are never found by name lookup. if (isConstructor(R.Declaration)) return; if (Hiding && CheckHiddenResult(R, CurContext, Hiding)) return; // Make sure that any given declaration only shows up in the result set once. if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl()).second) return; // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. if (AsNestedNameSpecifier) { R.StartsNestedNameSpecifier = true; R.Priority = CCP_NestedNameSpecifier; } else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass && isa( R.Declaration->getDeclContext()->getRedeclContext())) R.QualifierIsInformative = true; // If this result is supposed to have an informative qualifier, add one. if (R.QualifierIsInformative && !R.Qualifier && !R.StartsNestedNameSpecifier) { const DeclContext *Ctx = R.Declaration->getDeclContext(); if (const auto *Namespace = dyn_cast(Ctx)) R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, nullptr, Namespace); else if (const auto *Tag = dyn_cast(Ctx)) R.Qualifier = NestedNameSpecifier::Create( SemaRef.Context, nullptr, false, SemaRef.Context.getTypeDeclType(Tag).getTypePtr()); else R.QualifierIsInformative = false; } // Adjust the priority if this result comes from a base class. if (InBaseClass) setInBaseClass(R); AdjustResultPriorityForDecl(R); if (HasObjectTypeQualifiers) if (const auto *Method = dyn_cast(R.Declaration)) if (Method->isInstance()) { Qualifiers MethodQuals = Method->getMethodQualifiers(); if (ObjectTypeQualifiers == MethodQuals) R.Priority += CCD_ObjectQualifierMatch; else if (ObjectTypeQualifiers - MethodQuals) { // The method cannot be invoked, because doing so would drop // qualifiers. return; } // Detect cases where a ref-qualified method cannot be invoked. switch (Method->getRefQualifier()) { case RQ_LValue: if (ObjectKind != VK_LValue && !MethodQuals.hasConst()) return; break; case RQ_RValue: if (ObjectKind == VK_LValue) return; break; case RQ_None: break; } /// Check whether this dominates another overloaded method, which should /// be suppressed (or vice versa). /// Motivating case is const_iterator begin() const vs iterator begin(). auto &OverloadSet = OverloadMap[std::make_pair( CurContext, Method->getDeclName().getAsOpaqueInteger())]; for (const DeclIndexPair Entry : OverloadSet) { Result &Incumbent = Results[Entry.second]; switch (compareOverloads(*Method, *cast(Incumbent.Declaration), ObjectTypeQualifiers, ObjectKind)) { case OverloadCompare::Dominates: // Replace the dominated overload with this one. // FIXME: if the overload dominates multiple incumbents then we // should remove all. But two overloads is by far the common case. Incumbent = std::move(R); return; case OverloadCompare::Dominated: // This overload can't be called, drop it. return; case OverloadCompare::BothViable: break; } } OverloadSet.Add(Method, Results.size()); } // Insert this result into the set of results. Results.push_back(R); if (!AsNestedNameSpecifier) MaybeAddConstructorResults(R); } void ResultBuilder::AddResult(Result R) { assert(R.Kind != Result::RK_Declaration && "Declaration results need more context"); Results.push_back(R); } /// Enter into a new scope. void ResultBuilder::EnterNewScope() { ShadowMaps.emplace_back(); } /// Exit from the current scope. void ResultBuilder::ExitScope() { ShadowMaps.pop_back(); } /// Determines whether this given declaration will be found by /// ordinary name lookup. bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const { ND = ND->getUnderlyingDecl(); // If name lookup finds a local extern declaration, then we are in a // context where it behaves like an ordinary name. unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern; if (SemaRef.getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member; else if (SemaRef.getLangOpts().ObjC) { if (isa(ND)) return true; } return ND->getIdentifierNamespace() & IDNS; } /// Determines whether this given declaration will be found by /// ordinary name lookup but is not a type name. bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const { ND = ND->getUnderlyingDecl(); if (isa(ND)) return false; // Objective-C interfaces names are not filtered by this method because they // can be used in a class property expression. We can still filter out // @class declarations though. if (const auto *ID = dyn_cast(ND)) { if (!ID->getDefinition()) return false; } unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern; if (SemaRef.getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member; else if (SemaRef.getLangOpts().ObjC) { if (isa(ND)) return true; } return ND->getIdentifierNamespace() & IDNS; } bool ResultBuilder::IsIntegralConstantValue(const NamedDecl *ND) const { if (!IsOrdinaryNonTypeName(ND)) return 0; if (const auto *VD = dyn_cast(ND->getUnderlyingDecl())) if (VD->getType()->isIntegralOrEnumerationType()) return true; return false; } /// Determines whether this given declaration will be found by /// ordinary name lookup. bool ResultBuilder::IsOrdinaryNonValueName(const NamedDecl *ND) const { ND = ND->getUnderlyingDecl(); unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern; if (SemaRef.getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace; return (ND->getIdentifierNamespace() & IDNS) && !isa(ND) && !isa(ND) && !isa(ND); } /// Determines whether the given declaration is suitable as the /// start of a C++ nested-name-specifier, e.g., a class or namespace. bool ResultBuilder::IsNestedNameSpecifier(const NamedDecl *ND) const { // Allow us to find class templates, too. if (const auto *ClassTemplate = dyn_cast(ND)) ND = ClassTemplate->getTemplatedDecl(); return SemaRef.isAcceptableNestedNameSpecifier(ND); } /// Determines whether the given declaration is an enumeration. bool ResultBuilder::IsEnum(const NamedDecl *ND) const { return isa(ND); } /// Determines whether the given declaration is a class or struct. bool ResultBuilder::IsClassOrStruct(const NamedDecl *ND) const { // Allow us to find class templates, too. if (const auto *ClassTemplate = dyn_cast(ND)) ND = ClassTemplate->getTemplatedDecl(); // For purposes of this check, interfaces match too. if (const auto *RD = dyn_cast(ND)) return RD->getTagKind() == TTK_Class || RD->getTagKind() == TTK_Struct || RD->getTagKind() == TTK_Interface; return false; } /// Determines whether the given declaration is a union. bool ResultBuilder::IsUnion(const NamedDecl *ND) const { // Allow us to find class templates, too. if (const auto *ClassTemplate = dyn_cast(ND)) ND = ClassTemplate->getTemplatedDecl(); if (const auto *RD = dyn_cast(ND)) return RD->getTagKind() == TTK_Union; return false; } /// Determines whether the given declaration is a namespace. bool ResultBuilder::IsNamespace(const NamedDecl *ND) const { return isa(ND); } /// Determines whether the given declaration is a namespace or /// namespace alias. bool ResultBuilder::IsNamespaceOrAlias(const NamedDecl *ND) const { return isa(ND->getUnderlyingDecl()); } /// Determines whether the given declaration is a type. bool ResultBuilder::IsType(const NamedDecl *ND) const { ND = ND->getUnderlyingDecl(); return isa(ND) || isa(ND); } /// Determines which members of a class should be visible via /// "." or "->". Only value declarations, nested name specifiers, and /// using declarations thereof should show up. bool ResultBuilder::IsMember(const NamedDecl *ND) const { ND = ND->getUnderlyingDecl(); return isa(ND) || isa(ND) || isa(ND); } static bool isObjCReceiverType(ASTContext &C, QualType T) { T = C.getCanonicalType(T); switch (T->getTypeClass()) { case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: return true; case Type::Builtin: switch (cast(T)->getKind()) { case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: return true; default: break; } return false; default: break; } if (!C.getLangOpts().CPlusPlus) return false; // FIXME: We could perform more analysis here to determine whether a // particular class type has any conversions to Objective-C types. For now, // just accept all class types. return T->isDependentType() || T->isRecordType(); } bool ResultBuilder::IsObjCMessageReceiver(const NamedDecl *ND) const { QualType T = getDeclUsageType(SemaRef.Context, ND); if (T.isNull()) return false; T = SemaRef.Context.getBaseElementType(T); return isObjCReceiverType(SemaRef.Context, T); } bool ResultBuilder::IsObjCMessageReceiverOrLambdaCapture( const NamedDecl *ND) const { if (IsObjCMessageReceiver(ND)) return true; const auto *Var = dyn_cast(ND); if (!Var) return false; return Var->hasLocalStorage() && !Var->hasAttr(); } bool ResultBuilder::IsObjCCollection(const NamedDecl *ND) const { if ((SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryName(ND)) || (!SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryNonTypeName(ND))) return false; QualType T = getDeclUsageType(SemaRef.Context, ND); if (T.isNull()) return false; T = SemaRef.Context.getBaseElementType(T); return T->isObjCObjectType() || T->isObjCObjectPointerType() || T->isObjCIdType() || (SemaRef.getLangOpts().CPlusPlus && T->isRecordType()); } bool ResultBuilder::IsImpossibleToSatisfy(const NamedDecl *ND) const { return false; } /// Determines whether the given declaration is an Objective-C /// instance variable. bool ResultBuilder::IsObjCIvar(const NamedDecl *ND) const { return isa(ND); } namespace { /// Visible declaration consumer that adds a code-completion result /// for each visible declaration. class CodeCompletionDeclConsumer : public VisibleDeclConsumer { ResultBuilder &Results; DeclContext *InitialLookupCtx; // NamingClass and BaseType are used for access-checking. See // Sema::IsSimplyAccessible for details. CXXRecordDecl *NamingClass; QualType BaseType; std::vector FixIts; public: CodeCompletionDeclConsumer( ResultBuilder &Results, DeclContext *InitialLookupCtx, QualType BaseType = QualType(), std::vector FixIts = std::vector()) : Results(Results), InitialLookupCtx(InitialLookupCtx), FixIts(std::move(FixIts)) { NamingClass = llvm::dyn_cast(InitialLookupCtx); // If BaseType was not provided explicitly, emulate implicit 'this->'. if (BaseType.isNull()) { auto ThisType = Results.getSema().getCurrentThisType(); if (!ThisType.isNull()) { assert(ThisType->isPointerType()); BaseType = ThisType->getPointeeType(); if (!NamingClass) NamingClass = BaseType->getAsCXXRecordDecl(); } } this->BaseType = BaseType; } void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass) override { ResultBuilder::Result Result(ND, Results.getBasePriority(ND), nullptr, false, IsAccessible(ND, Ctx), FixIts); Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass); } void EnteredContext(DeclContext *Ctx) override { Results.addVisitedContext(Ctx); } private: bool IsAccessible(NamedDecl *ND, DeclContext *Ctx) { // Naming class to use for access check. In most cases it was provided // explicitly (e.g. member access (lhs.foo) or qualified lookup (X::)), // for unqualified lookup we fallback to the \p Ctx in which we found the // member. auto *NamingClass = this->NamingClass; QualType BaseType = this->BaseType; if (auto *Cls = llvm::dyn_cast_or_null(Ctx)) { if (!NamingClass) NamingClass = Cls; // When we emulate implicit 'this->' in an unqualified lookup, we might // end up with an invalid naming class. In that case, we avoid emulating // 'this->' qualifier to satisfy preconditions of the access checking. if (NamingClass->getCanonicalDecl() != Cls->getCanonicalDecl() && !NamingClass->isDerivedFrom(Cls)) { NamingClass = Cls; BaseType = QualType(); } } else { // The decl was found outside the C++ class, so only ObjC access checks // apply. Those do not rely on NamingClass and BaseType, so we clear them // out. NamingClass = nullptr; BaseType = QualType(); } return Results.getSema().IsSimplyAccessible(ND, NamingClass, BaseType); } }; } // namespace /// Add type specifiers for the current language as keyword results. static void AddTypeSpecifierResults(const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompletionResult Result; Results.AddResult(Result("short", CCP_Type)); Results.AddResult(Result("long", CCP_Type)); Results.AddResult(Result("signed", CCP_Type)); Results.AddResult(Result("unsigned", CCP_Type)); Results.AddResult(Result("void", CCP_Type)); Results.AddResult(Result("char", CCP_Type)); Results.AddResult(Result("int", CCP_Type)); Results.AddResult(Result("float", CCP_Type)); Results.AddResult(Result("double", CCP_Type)); Results.AddResult(Result("enum", CCP_Type)); Results.AddResult(Result("struct", CCP_Type)); Results.AddResult(Result("union", CCP_Type)); Results.AddResult(Result("const", CCP_Type)); Results.AddResult(Result("volatile", CCP_Type)); if (LangOpts.C99) { // C99-specific Results.AddResult(Result("_Complex", CCP_Type)); Results.AddResult(Result("_Imaginary", CCP_Type)); Results.AddResult(Result("_Bool", CCP_Type)); Results.AddResult(Result("restrict", CCP_Type)); } CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); if (LangOpts.CPlusPlus) { // C++-specific Results.AddResult( Result("bool", CCP_Type + (LangOpts.ObjC ? CCD_bool_in_ObjC : 0))); Results.AddResult(Result("class", CCP_Type)); Results.AddResult(Result("wchar_t", CCP_Type)); // typename name Builder.AddTypedTextChunk("typename"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("name"); Results.AddResult(Result(Builder.TakeString())); if (LangOpts.CPlusPlus11) { Results.AddResult(Result("auto", CCP_Type)); Results.AddResult(Result("char16_t", CCP_Type)); Results.AddResult(Result("char32_t", CCP_Type)); Builder.AddTypedTextChunk("decltype"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); } } else Results.AddResult(Result("__auto_type", CCP_Type)); // GNU keywords if (LangOpts.GNUKeywords) { // FIXME: Enable when we actually support decimal floating point. // Results.AddResult(Result("_Decimal32")); // Results.AddResult(Result("_Decimal64")); // Results.AddResult(Result("_Decimal128")); Builder.AddTypedTextChunk("typeof"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); Builder.AddTypedTextChunk("typeof"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); } // Nullability Results.AddResult(Result("_Nonnull", CCP_Type)); Results.AddResult(Result("_Null_unspecified", CCP_Type)); Results.AddResult(Result("_Nullable", CCP_Type)); } static void AddStorageSpecifiers(Sema::ParserCompletionContext CCC, const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompletionResult Result; // Note: we don't suggest either "auto" or "register", because both // are pointless as storage specifiers. Elsewhere, we suggest "auto" // in C++0x as a type specifier. Results.AddResult(Result("extern")); Results.AddResult(Result("static")); if (LangOpts.CPlusPlus11) { CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); // alignas Builder.AddTypedTextChunk("alignas"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); Results.AddResult(Result("constexpr")); Results.AddResult(Result("thread_local")); } } static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC, const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompletionResult Result; switch (CCC) { case Sema::PCC_Class: case Sema::PCC_MemberTemplate: if (LangOpts.CPlusPlus) { Results.AddResult(Result("explicit")); Results.AddResult(Result("friend")); Results.AddResult(Result("mutable")); Results.AddResult(Result("virtual")); } LLVM_FALLTHROUGH; case Sema::PCC_ObjCInterface: case Sema::PCC_ObjCImplementation: case Sema::PCC_Namespace: case Sema::PCC_Template: if (LangOpts.CPlusPlus || LangOpts.C99) Results.AddResult(Result("inline")); break; case Sema::PCC_ObjCInstanceVariableList: case Sema::PCC_Expression: case Sema::PCC_Statement: case Sema::PCC_ForInit: case Sema::PCC_Condition: case Sema::PCC_RecoveryInFunction: case Sema::PCC_Type: case Sema::PCC_ParenthesizedExpression: case Sema::PCC_LocalDeclarationSpecifiers: break; } } static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt); static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt); static void AddObjCVisibilityResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt); static void AddObjCImplementationResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt); static void AddObjCInterfaceResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt); static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt); static void AddTypedefResult(ResultBuilder &Results) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Builder.AddTypedTextChunk("typedef"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("name"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(CodeCompletionResult(Builder.TakeString())); } // using name = type static void AddUsingAliasResult(CodeCompletionBuilder &Builder, ResultBuilder &Results) { Builder.AddTypedTextChunk("using"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("name"); Builder.AddChunk(CodeCompletionString::CK_Equal); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(CodeCompletionResult(Builder.TakeString())); } static bool WantTypesInContext(Sema::ParserCompletionContext CCC, const LangOptions &LangOpts) { switch (CCC) { case Sema::PCC_Namespace: case Sema::PCC_Class: case Sema::PCC_ObjCInstanceVariableList: case Sema::PCC_Template: case Sema::PCC_MemberTemplate: case Sema::PCC_Statement: case Sema::PCC_RecoveryInFunction: case Sema::PCC_Type: case Sema::PCC_ParenthesizedExpression: case Sema::PCC_LocalDeclarationSpecifiers: return true; case Sema::PCC_Expression: case Sema::PCC_Condition: return LangOpts.CPlusPlus; case Sema::PCC_ObjCInterface: case Sema::PCC_ObjCImplementation: return false; case Sema::PCC_ForInit: return LangOpts.CPlusPlus || LangOpts.ObjC || LangOpts.C99; } llvm_unreachable("Invalid ParserCompletionContext!"); } static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context, const Preprocessor &PP) { PrintingPolicy Policy = Sema::getPrintingPolicy(Context, PP); Policy.AnonymousTagLocations = false; Policy.SuppressStrongLifetime = true; Policy.SuppressUnwrittenScope = true; Policy.SuppressScope = true; return Policy; } /// Retrieve a printing policy suitable for code completion. static PrintingPolicy getCompletionPrintingPolicy(Sema &S) { return getCompletionPrintingPolicy(S.Context, S.PP); } /// Retrieve the string representation of the given type as a string /// that has the appropriate lifetime for code completion. /// /// This routine provides a fast path where we provide constant strings for /// common type names. static const char *GetCompletionTypeString(QualType T, ASTContext &Context, const PrintingPolicy &Policy, CodeCompletionAllocator &Allocator) { if (!T.getLocalQualifiers()) { // Built-in type names are constant strings. if (const BuiltinType *BT = dyn_cast(T)) return BT->getNameAsCString(Policy); // Anonymous tag types are constant strings. if (const TagType *TagT = dyn_cast(T)) if (TagDecl *Tag = TagT->getDecl()) if (!Tag->hasNameForLinkage()) { switch (Tag->getTagKind()) { case TTK_Struct: return "struct "; case TTK_Interface: return "__interface "; case TTK_Class: return "class "; case TTK_Union: return "union "; case TTK_Enum: return "enum "; } } } // Slow path: format the type as a string. std::string Result; T.getAsStringInternal(Result, Policy); return Allocator.CopyString(Result); } /// Add a completion for "this", if we're in a member function. static void addThisCompletion(Sema &S, ResultBuilder &Results) { QualType ThisTy = S.getCurrentThisType(); if (ThisTy.isNull()) return; CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); PrintingPolicy Policy = getCompletionPrintingPolicy(S); Builder.AddResultTypeChunk( GetCompletionTypeString(ThisTy, S.Context, Policy, Allocator)); Builder.AddTypedTextChunk("this"); Results.AddResult(CodeCompletionResult(Builder.TakeString())); } static void AddStaticAssertResult(CodeCompletionBuilder &Builder, ResultBuilder &Results, const LangOptions &LangOpts) { if (!LangOpts.CPlusPlus11) return; Builder.AddTypedTextChunk("static_assert"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_Comma); Builder.AddPlaceholderChunk("message"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(CodeCompletionResult(Builder.TakeString())); } static void AddOverrideResults(ResultBuilder &Results, const CodeCompletionContext &CCContext, CodeCompletionBuilder &Builder) { Sema &S = Results.getSema(); const auto *CR = llvm::dyn_cast(S.CurContext); // If not inside a class/struct/union return empty. if (!CR) return; // First store overrides within current class. // These are stored by name to make querying fast in the later step. llvm::StringMap> Overrides; for (auto *Method : CR->methods()) { if (!Method->isVirtual() || !Method->getIdentifier()) continue; Overrides[Method->getName()].push_back(Method); } for (const auto &Base : CR->bases()) { const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl(); if (!BR) continue; for (auto *Method : BR->methods()) { if (!Method->isVirtual() || !Method->getIdentifier()) continue; const auto it = Overrides.find(Method->getName()); bool IsOverriden = false; if (it != Overrides.end()) { for (auto *MD : it->second) { // If the method in current body is not an overload of this virtual // function, then it overrides this one. if (!S.IsOverload(MD, Method, false)) { IsOverriden = true; break; } } } if (!IsOverriden) { // Generates a new CodeCompletionResult by taking this function and // converting it into an override declaration with only one chunk in the // final CodeCompletionString as a TypedTextChunk. std::string OverrideSignature; llvm::raw_string_ostream OS(OverrideSignature); CodeCompletionResult CCR(Method, 0); PrintingPolicy Policy = getCompletionPrintingPolicy(S.getASTContext(), S.getPreprocessor()); auto *CCS = CCR.createCodeCompletionStringForOverride( S.getPreprocessor(), S.getASTContext(), Builder, /*IncludeBriefComments=*/false, CCContext, Policy); Results.AddResult(CodeCompletionResult(CCS, Method, CCP_CodePattern)); } } } } /// Add language constructs that show up for "ordinary" names. static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Sema &SemaRef, ResultBuilder &Results) { CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); typedef CodeCompletionResult Result; switch (CCC) { case Sema::PCC_Namespace: if (SemaRef.getLangOpts().CPlusPlus) { if (Results.includeCodePatterns()) { // namespace { declarations } Builder.AddTypedTextChunk("namespace"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("identifier"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddPlaceholderChunk("declarations"); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); } // namespace identifier = identifier ; Builder.AddTypedTextChunk("namespace"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("name"); Builder.AddChunk(CodeCompletionString::CK_Equal); Builder.AddPlaceholderChunk("namespace"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); // Using directives Builder.AddTypedTextChunk("using namespace"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("identifier"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); // asm(string-literal) Builder.AddTypedTextChunk("asm"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("string-literal"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); if (Results.includeCodePatterns()) { // Explicit template instantiation Builder.AddTypedTextChunk("template"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("declaration"); Results.AddResult(Result(Builder.TakeString())); } else { Results.AddResult(Result("template", CodeCompletionResult::RK_Keyword)); } } if (SemaRef.getLangOpts().ObjC) AddObjCTopLevelResults(Results, true); AddTypedefResult(Results); LLVM_FALLTHROUGH; case Sema::PCC_Class: if (SemaRef.getLangOpts().CPlusPlus) { // Using declaration Builder.AddTypedTextChunk("using"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("qualifier"); Builder.AddTextChunk("::"); Builder.AddPlaceholderChunk("name"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); if (SemaRef.getLangOpts().CPlusPlus11) AddUsingAliasResult(Builder, Results); // using typename qualifier::name (only in a dependent context) if (SemaRef.CurContext->isDependentContext()) { Builder.AddTypedTextChunk("using typename"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("qualifier"); Builder.AddTextChunk("::"); Builder.AddPlaceholderChunk("name"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); } AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts()); if (CCC == Sema::PCC_Class) { AddTypedefResult(Results); bool IsNotInheritanceScope = !(S->getFlags() & Scope::ClassInheritanceScope); // public: Builder.AddTypedTextChunk("public"); if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); // protected: Builder.AddTypedTextChunk("protected"); if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); // private: Builder.AddTypedTextChunk("private"); if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); // FIXME: This adds override results only if we are at the first word of // the declaration/definition. Also call this from other sides to have // more use-cases. AddOverrideResults(Results, CodeCompletionContext::CCC_ClassStructUnion, Builder); } } LLVM_FALLTHROUGH; case Sema::PCC_Template: case Sema::PCC_MemberTemplate: if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns()) { // template < parameters > Builder.AddTypedTextChunk("template"); Builder.AddChunk(CodeCompletionString::CK_LeftAngle); Builder.AddPlaceholderChunk("parameters"); Builder.AddChunk(CodeCompletionString::CK_RightAngle); Results.AddResult(Result(Builder.TakeString())); } else { Results.AddResult(Result("template", CodeCompletionResult::RK_Keyword)); } AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results); AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results); break; case Sema::PCC_ObjCInterface: AddObjCInterfaceResults(SemaRef.getLangOpts(), Results, true); AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results); AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results); break; case Sema::PCC_ObjCImplementation: AddObjCImplementationResults(SemaRef.getLangOpts(), Results, true); AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results); AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results); break; case Sema::PCC_ObjCInstanceVariableList: AddObjCVisibilityResults(SemaRef.getLangOpts(), Results, true); break; case Sema::PCC_RecoveryInFunction: case Sema::PCC_Statement: { if (SemaRef.getLangOpts().CPlusPlus11) AddUsingAliasResult(Builder, Results); AddTypedefResult(Results); if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns() && SemaRef.getLangOpts().CXXExceptions) { Builder.AddTypedTextChunk("try"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTextChunk("catch"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("declaration"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); } if (SemaRef.getLangOpts().ObjC) AddObjCStatementResults(Results, true); if (Results.includeCodePatterns()) { // if (condition) { statements } Builder.AddTypedTextChunk("if"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (SemaRef.getLangOpts().CPlusPlus) Builder.AddPlaceholderChunk("condition"); else Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); // switch (condition) { } Builder.AddTypedTextChunk("switch"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (SemaRef.getLangOpts().CPlusPlus) Builder.AddPlaceholderChunk("condition"); else Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddPlaceholderChunk("cases"); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); } // Switch-specific statements. if (SemaRef.getCurFunction() && !SemaRef.getCurFunction()->SwitchStack.empty()) { // case expression: Builder.AddTypedTextChunk("case"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); // default: Builder.AddTypedTextChunk("default"); Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); } if (Results.includeCodePatterns()) { /// while (condition) { statements } Builder.AddTypedTextChunk("while"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (SemaRef.getLangOpts().CPlusPlus) Builder.AddPlaceholderChunk("condition"); else Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); // do { statements } while ( expression ); Builder.AddTypedTextChunk("do"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Builder.AddTextChunk("while"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); // for ( for-init-statement ; condition ; expression ) { statements } Builder.AddTypedTextChunk("for"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (SemaRef.getLangOpts().CPlusPlus || SemaRef.getLangOpts().C99) Builder.AddPlaceholderChunk("init-statement"); else Builder.AddPlaceholderChunk("init-expression"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("condition"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("inc-expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); } if (S->getContinueParent()) { // continue ; Builder.AddTypedTextChunk("continue"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); } if (S->getBreakParent()) { // break ; Builder.AddTypedTextChunk("break"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); } // "return expression ;" or "return ;", depending on the return type. QualType ReturnType; if (const auto *Function = dyn_cast(SemaRef.CurContext)) ReturnType = Function->getReturnType(); else if (const auto *Method = dyn_cast(SemaRef.CurContext)) ReturnType = Method->getReturnType(); else if (SemaRef.getCurBlock() && !SemaRef.getCurBlock()->ReturnType.isNull()) ReturnType = SemaRef.getCurBlock()->ReturnType;; if (ReturnType.isNull() || ReturnType->isVoidType()) { Builder.AddTypedTextChunk("return"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); } else { assert(!ReturnType.isNull()); // "return expression ;" Builder.AddTypedTextChunk("return"); Builder.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); // When boolean, also add 'return true;' and 'return false;'. if (ReturnType->isBooleanType()) { Builder.AddTypedTextChunk("return true"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); Builder.AddTypedTextChunk("return false"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); } // For pointers, suggest 'return nullptr' in C++. if (SemaRef.getLangOpts().CPlusPlus11 && (ReturnType->isPointerType() || ReturnType->isMemberPointerType())) { Builder.AddTypedTextChunk("return nullptr"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); } } // goto identifier ; Builder.AddTypedTextChunk("goto"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("label"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); // Using directives Builder.AddTypedTextChunk("using namespace"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("identifier"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts()); } LLVM_FALLTHROUGH; // Fall through (for statement expressions). case Sema::PCC_ForInit: case Sema::PCC_Condition: AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results); // Fall through: conditions and statements can have expressions. LLVM_FALLTHROUGH; case Sema::PCC_ParenthesizedExpression: if (SemaRef.getLangOpts().ObjCAutoRefCount && CCC == Sema::PCC_ParenthesizedExpression) { // (__bridge ) Builder.AddTypedTextChunk("__bridge"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); // (__bridge_transfer ) Builder.AddTypedTextChunk("__bridge_transfer"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("Objective-C type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); // (__bridge_retained ) Builder.AddTypedTextChunk("__bridge_retained"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("CF type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); } // Fall through LLVM_FALLTHROUGH; case Sema::PCC_Expression: { if (SemaRef.getLangOpts().CPlusPlus) { // 'this', if we're in a non-static member function. addThisCompletion(SemaRef, Results); // true Builder.AddResultTypeChunk("bool"); Builder.AddTypedTextChunk("true"); Results.AddResult(Result(Builder.TakeString())); // false Builder.AddResultTypeChunk("bool"); Builder.AddTypedTextChunk("false"); Results.AddResult(Result(Builder.TakeString())); if (SemaRef.getLangOpts().RTTI) { // dynamic_cast < type-id > ( expression ) Builder.AddTypedTextChunk("dynamic_cast"); Builder.AddChunk(CodeCompletionString::CK_LeftAngle); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_RightAngle); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); } // static_cast < type-id > ( expression ) Builder.AddTypedTextChunk("static_cast"); Builder.AddChunk(CodeCompletionString::CK_LeftAngle); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_RightAngle); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); // reinterpret_cast < type-id > ( expression ) Builder.AddTypedTextChunk("reinterpret_cast"); Builder.AddChunk(CodeCompletionString::CK_LeftAngle); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_RightAngle); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); // const_cast < type-id > ( expression ) Builder.AddTypedTextChunk("const_cast"); Builder.AddChunk(CodeCompletionString::CK_LeftAngle); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_RightAngle); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); if (SemaRef.getLangOpts().RTTI) { // typeid ( expression-or-type ) Builder.AddResultTypeChunk("std::type_info"); Builder.AddTypedTextChunk("typeid"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression-or-type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); } // new T ( ... ) Builder.AddTypedTextChunk("new"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expressions"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); // new T [ ] ( ... ) Builder.AddTypedTextChunk("new"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_LeftBracket); Builder.AddPlaceholderChunk("size"); Builder.AddChunk(CodeCompletionString::CK_RightBracket); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expressions"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); // delete expression Builder.AddResultTypeChunk("void"); Builder.AddTypedTextChunk("delete"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); // delete [] expression Builder.AddResultTypeChunk("void"); Builder.AddTypedTextChunk("delete"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftBracket); Builder.AddChunk(CodeCompletionString::CK_RightBracket); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); if (SemaRef.getLangOpts().CXXExceptions) { // throw expression Builder.AddResultTypeChunk("void"); Builder.AddTypedTextChunk("throw"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); } // FIXME: Rethrow? if (SemaRef.getLangOpts().CPlusPlus11) { // nullptr Builder.AddResultTypeChunk("std::nullptr_t"); Builder.AddTypedTextChunk("nullptr"); Results.AddResult(Result(Builder.TakeString())); // alignof Builder.AddResultTypeChunk("size_t"); Builder.AddTypedTextChunk("alignof"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); // noexcept Builder.AddResultTypeChunk("bool"); Builder.AddTypedTextChunk("noexcept"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); // sizeof... expression Builder.AddResultTypeChunk("size_t"); Builder.AddTypedTextChunk("sizeof..."); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("parameter-pack"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); } } if (SemaRef.getLangOpts().ObjC) { // Add "super", if we're in an Objective-C class with a superclass. if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) { // The interface can be NULL. if (ObjCInterfaceDecl *ID = Method->getClassInterface()) if (ID->getSuperClass()) { std::string SuperType; SuperType = ID->getSuperClass()->getNameAsString(); if (Method->isInstanceMethod()) SuperType += " *"; Builder.AddResultTypeChunk(Allocator.CopyString(SuperType)); Builder.AddTypedTextChunk("super"); Results.AddResult(Result(Builder.TakeString())); } } AddObjCExpressionResults(Results, true); } if (SemaRef.getLangOpts().C11) { // _Alignof Builder.AddResultTypeChunk("size_t"); if (SemaRef.PP.isMacroDefined("alignof")) Builder.AddTypedTextChunk("alignof"); else Builder.AddTypedTextChunk("_Alignof"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); } // sizeof expression Builder.AddResultTypeChunk("size_t"); Builder.AddTypedTextChunk("sizeof"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression-or-type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); break; } case Sema::PCC_Type: case Sema::PCC_LocalDeclarationSpecifiers: break; } if (WantTypesInContext(CCC, SemaRef.getLangOpts())) AddTypeSpecifierResults(SemaRef.getLangOpts(), Results); if (SemaRef.getLangOpts().CPlusPlus && CCC != Sema::PCC_Type) Results.AddResult(Result("operator")); } /// If the given declaration has an associated type, add it as a result /// type chunk. static void AddResultTypeChunk(ASTContext &Context, const PrintingPolicy &Policy, const NamedDecl *ND, QualType BaseType, CodeCompletionBuilder &Result) { if (!ND) return; // Skip constructors and conversion functions, which have their return types // built into their names. if (isConstructor(ND) || isa(ND)) return; // Determine the type of the declaration (if it has a type). QualType T; if (const FunctionDecl *Function = ND->getAsFunction()) T = Function->getReturnType(); else if (const auto *Method = dyn_cast(ND)) { if (!BaseType.isNull()) T = Method->getSendResultType(BaseType); else T = Method->getReturnType(); } else if (const auto *Enumerator = dyn_cast(ND)) { T = Context.getTypeDeclType(cast(Enumerator->getDeclContext())); T = clang::TypeName::getFullyQualifiedType(T, Context); } else if (isa(ND)) { /* Do nothing: ignore unresolved using declarations*/ } else if (const auto *Ivar = dyn_cast(ND)) { if (!BaseType.isNull()) T = Ivar->getUsageType(BaseType); else T = Ivar->getType(); } else if (const auto *Value = dyn_cast(ND)) { T = Value->getType(); } else if (const auto *Property = dyn_cast(ND)) { if (!BaseType.isNull()) T = Property->getUsageType(BaseType); else T = Property->getType(); } if (T.isNull() || Context.hasSameType(T, Context.DependentTy)) return; Result.AddResultTypeChunk( GetCompletionTypeString(T, Context, Policy, Result.getAllocator())); } static void MaybeAddSentinel(Preprocessor &PP, const NamedDecl *FunctionOrMethod, CodeCompletionBuilder &Result) { if (SentinelAttr *Sentinel = FunctionOrMethod->getAttr()) if (Sentinel->getSentinel() == 0) { if (PP.getLangOpts().ObjC && PP.isMacroDefined("nil")) Result.AddTextChunk(", nil"); else if (PP.isMacroDefined("NULL")) Result.AddTextChunk(", NULL"); else Result.AddTextChunk(", (void*)0"); } } static std::string formatObjCParamQualifiers(unsigned ObjCQuals, QualType &Type) { std::string Result; if (ObjCQuals & Decl::OBJC_TQ_In) Result += "in "; else if (ObjCQuals & Decl::OBJC_TQ_Inout) Result += "inout "; else if (ObjCQuals & Decl::OBJC_TQ_Out) Result += "out "; if (ObjCQuals & Decl::OBJC_TQ_Bycopy) Result += "bycopy "; else if (ObjCQuals & Decl::OBJC_TQ_Byref) Result += "byref "; if (ObjCQuals & Decl::OBJC_TQ_Oneway) Result += "oneway "; if (ObjCQuals & Decl::OBJC_TQ_CSNullability) { if (auto nullability = AttributedType::stripOuterNullability(Type)) { switch (*nullability) { case NullabilityKind::NonNull: Result += "nonnull "; break; case NullabilityKind::Nullable: Result += "nullable "; break; case NullabilityKind::Unspecified: Result += "null_unspecified "; break; } } } return Result; } /// Tries to find the most appropriate type location for an Objective-C /// block placeholder. /// /// This function ignores things like typedefs and qualifiers in order to /// present the most relevant and accurate block placeholders in code completion /// results. static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo, FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, bool SuppressBlock = false) { if (!TSInfo) return; TypeLoc TL = TSInfo->getTypeLoc().getUnqualifiedLoc(); while (true) { // Look through typedefs. if (!SuppressBlock) { if (TypedefTypeLoc TypedefTL = TL.getAs()) { if (TypeSourceInfo *InnerTSInfo = TypedefTL.getTypedefNameDecl()->getTypeSourceInfo()) { TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc(); continue; } } // Look through qualified types if (QualifiedTypeLoc QualifiedTL = TL.getAs()) { TL = QualifiedTL.getUnqualifiedLoc(); continue; } if (AttributedTypeLoc AttrTL = TL.getAs()) { TL = AttrTL.getModifiedLoc(); continue; } } // Try to get the function prototype behind the block pointer type, // then we're done. if (BlockPointerTypeLoc BlockPtr = TL.getAs()) { TL = BlockPtr.getPointeeLoc().IgnoreParens(); Block = TL.getAs(); BlockProto = TL.getAs(); } break; } } static std::string formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, bool SuppressBlockName = false, bool SuppressBlock = false, Optional> ObjCSubsts = None); static std::string FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, bool SuppressName = false, bool SuppressBlock = false, Optional> ObjCSubsts = None) { // Params are unavailable in FunctionTypeLoc if the FunctionType is invalid. // It would be better to pass in the param Type, which is usually avaliable. // But this case is rare, so just pretend we fell back to int as elsewhere. if (!Param) return "int"; bool ObjCMethodParam = isa(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { // The argument for a dependent or non-block parameter is a placeholder // containing that parameter's type. std::string Result; if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName) Result = std::string(Param->getIdentifier()->getName()); QualType Type = Param->getType(); if (ObjCSubsts) Type = Type.substObjCTypeArgs(Param->getASTContext(), *ObjCSubsts, ObjCSubstitutionContext::Parameter); if (ObjCMethodParam) { Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type); Result += Type.getAsString(Policy) + ")"; if (Param->getIdentifier() && !SuppressName) Result += Param->getIdentifier()->getName(); } else { Type.getAsStringInternal(Result, Policy); } return Result; } // The argument for a block pointer parameter is a block literal with // the appropriate type. FunctionTypeLoc Block; FunctionProtoTypeLoc BlockProto; findTypeLocationForBlockDecl(Param->getTypeSourceInfo(), Block, BlockProto, SuppressBlock); // Try to retrieve the block type information from the property if this is a // parameter in a setter. if (!Block && ObjCMethodParam && cast(Param->getDeclContext())->isPropertyAccessor()) { if (const auto *PD = cast(Param->getDeclContext()) ->findPropertyDecl(/*CheckOverrides=*/false)) findTypeLocationForBlockDecl(PD->getTypeSourceInfo(), Block, BlockProto, SuppressBlock); } if (!Block) { // We were unable to find a FunctionProtoTypeLoc with parameter names // for the block; just use the parameter type as a placeholder. std::string Result; if (!ObjCMethodParam && Param->getIdentifier()) Result = std::string(Param->getIdentifier()->getName()); QualType Type = Param->getType().getUnqualifiedType(); if (ObjCMethodParam) { Result = Type.getAsString(Policy); std::string Quals = formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type); if (!Quals.empty()) Result = "(" + Quals + " " + Result + ")"; if (Result.back() != ')') Result += " "; if (Param->getIdentifier()) Result += Param->getIdentifier()->getName(); } else { Type.getAsStringInternal(Result, Policy); } return Result; } // We have the function prototype behind the block pointer type, as it was // written in the source. return formatBlockPlaceholder(Policy, Param, Block, BlockProto, /*SuppressBlockName=*/false, SuppressBlock, ObjCSubsts); } /// Returns a placeholder string that corresponds to an Objective-C block /// declaration. /// /// \param BlockDecl A declaration with an Objective-C block type. /// /// \param Block The most relevant type location for that block type. /// /// \param SuppressBlockName Determines whether or not the name of the block /// declaration is included in the resulting string. static std::string formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, bool SuppressBlockName, bool SuppressBlock, Optional> ObjCSubsts) { std::string Result; QualType ResultType = Block.getTypePtr()->getReturnType(); if (ObjCSubsts) ResultType = ResultType.substObjCTypeArgs(BlockDecl->getASTContext(), *ObjCSubsts, ObjCSubstitutionContext::Result); if (!ResultType->isVoidType() || SuppressBlock) ResultType.getAsStringInternal(Result, Policy); // Format the parameter list. std::string Params; if (!BlockProto || Block.getNumParams() == 0) { if (BlockProto && BlockProto.getTypePtr()->isVariadic()) Params = "(...)"; else Params = "(void)"; } else { Params += "("; for (unsigned I = 0, N = Block.getNumParams(); I != N; ++I) { if (I) Params += ", "; Params += FormatFunctionParameter(Policy, Block.getParam(I), /*SuppressName=*/false, /*SuppressBlock=*/true, ObjCSubsts); if (I == N - 1 && BlockProto.getTypePtr()->isVariadic()) Params += ", ..."; } Params += ")"; } if (SuppressBlock) { // Format as a parameter. Result = Result + " (^"; if (!SuppressBlockName && BlockDecl->getIdentifier()) Result += BlockDecl->getIdentifier()->getName(); Result += ")"; Result += Params; } else { // Format as a block literal argument. Result = '^' + Result; Result += Params; if (!SuppressBlockName && BlockDecl->getIdentifier()) Result += BlockDecl->getIdentifier()->getName(); } return Result; } static std::string GetDefaultValueString(const ParmVarDecl *Param, const SourceManager &SM, const LangOptions &LangOpts) { const SourceRange SrcRange = Param->getDefaultArgRange(); CharSourceRange CharSrcRange = CharSourceRange::getTokenRange(SrcRange); bool Invalid = CharSrcRange.isInvalid(); if (Invalid) return ""; StringRef srcText = Lexer::getSourceText(CharSrcRange, SM, LangOpts, &Invalid); if (Invalid) return ""; if (srcText.empty() || srcText == "=") { // Lexer can't determine the value. // This happens if the code is incorrect (for example class is forward // declared). return ""; } std::string DefValue(srcText.str()); // FIXME: remove this check if the Lexer::getSourceText value is fixed and // this value always has (or always does not have) '=' in front of it if (DefValue.at(0) != '=') { // If we don't have '=' in front of value. // Lexer returns built-in types values without '=' and user-defined types // values with it. return " = " + DefValue; } return " " + DefValue; } /// Add function parameter chunks to the given code completion string. static void AddFunctionParameterChunks(Preprocessor &PP, const PrintingPolicy &Policy, const FunctionDecl *Function, CodeCompletionBuilder &Result, unsigned Start = 0, bool InOptional = false) { bool FirstParameter = true; for (unsigned P = Start, N = Function->getNumParams(); P != N; ++P) { const ParmVarDecl *Param = Function->getParamDecl(P); if (Param->hasDefaultArg() && !InOptional) { // When we see an optional default argument, put that argument and // the remaining default arguments into a new, optional string. CodeCompletionBuilder Opt(Result.getAllocator(), Result.getCodeCompletionTUInfo()); if (!FirstParameter) Opt.AddChunk(CodeCompletionString::CK_Comma); AddFunctionParameterChunks(PP, Policy, Function, Opt, P, true); Result.AddOptionalChunk(Opt.TakeString()); break; } if (FirstParameter) FirstParameter = false; else Result.AddChunk(CodeCompletionString::CK_Comma); InOptional = false; // Format the placeholder string. std::string PlaceholderStr = FormatFunctionParameter(Policy, Param); if (Param->hasDefaultArg()) PlaceholderStr += GetDefaultValueString(Param, PP.getSourceManager(), PP.getLangOpts()); if (Function->isVariadic() && P == N - 1) PlaceholderStr += ", ..."; // Add the placeholder string. Result.AddPlaceholderChunk( Result.getAllocator().CopyString(PlaceholderStr)); } if (const auto *Proto = Function->getType()->getAs()) if (Proto->isVariadic()) { if (Proto->getNumParams() == 0) Result.AddPlaceholderChunk("..."); MaybeAddSentinel(PP, Function, Result); } } /// Add template parameter chunks to the given code completion string. static void AddTemplateParameterChunks( ASTContext &Context, const PrintingPolicy &Policy, const TemplateDecl *Template, CodeCompletionBuilder &Result, unsigned MaxParameters = 0, unsigned Start = 0, bool InDefaultArg = false) { bool FirstParameter = true; // Prefer to take the template parameter names from the first declaration of // the template. Template = cast(Template->getCanonicalDecl()); TemplateParameterList *Params = Template->getTemplateParameters(); TemplateParameterList::iterator PEnd = Params->end(); if (MaxParameters) PEnd = Params->begin() + MaxParameters; for (TemplateParameterList::iterator P = Params->begin() + Start; P != PEnd; ++P) { bool HasDefaultArg = false; std::string PlaceholderStr; if (TemplateTypeParmDecl *TTP = dyn_cast(*P)) { if (TTP->wasDeclaredWithTypename()) PlaceholderStr = "typename"; else if (const auto *TC = TTP->getTypeConstraint()) { llvm::raw_string_ostream OS(PlaceholderStr); TC->print(OS, Policy); OS.flush(); } else PlaceholderStr = "class"; if (TTP->getIdentifier()) { PlaceholderStr += ' '; PlaceholderStr += TTP->getIdentifier()->getName(); } HasDefaultArg = TTP->hasDefaultArgument(); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*P)) { if (NTTP->getIdentifier()) PlaceholderStr = std::string(NTTP->getIdentifier()->getName()); NTTP->getType().getAsStringInternal(PlaceholderStr, Policy); HasDefaultArg = NTTP->hasDefaultArgument(); } else { assert(isa(*P)); TemplateTemplateParmDecl *TTP = cast(*P); // Since putting the template argument list into the placeholder would // be very, very long, we just use an abbreviation. PlaceholderStr = "template<...> class"; if (TTP->getIdentifier()) { PlaceholderStr += ' '; PlaceholderStr += TTP->getIdentifier()->getName(); } HasDefaultArg = TTP->hasDefaultArgument(); } if (HasDefaultArg && !InDefaultArg) { // When we see an optional default argument, put that argument and // the remaining default arguments into a new, optional string. CodeCompletionBuilder Opt(Result.getAllocator(), Result.getCodeCompletionTUInfo()); if (!FirstParameter) Opt.AddChunk(CodeCompletionString::CK_Comma); AddTemplateParameterChunks(Context, Policy, Template, Opt, MaxParameters, P - Params->begin(), true); Result.AddOptionalChunk(Opt.TakeString()); break; } InDefaultArg = false; if (FirstParameter) FirstParameter = false; else Result.AddChunk(CodeCompletionString::CK_Comma); // Add the placeholder string. Result.AddPlaceholderChunk( Result.getAllocator().CopyString(PlaceholderStr)); } } /// Add a qualifier to the given code-completion string, if the /// provided nested-name-specifier is non-NULL. static void AddQualifierToCompletionString(CodeCompletionBuilder &Result, NestedNameSpecifier *Qualifier, bool QualifierIsInformative, ASTContext &Context, const PrintingPolicy &Policy) { if (!Qualifier) return; std::string PrintedNNS; { llvm::raw_string_ostream OS(PrintedNNS); Qualifier->print(OS, Policy); } if (QualifierIsInformative) Result.AddInformativeChunk(Result.getAllocator().CopyString(PrintedNNS)); else Result.AddTextChunk(Result.getAllocator().CopyString(PrintedNNS)); } static void AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, const FunctionDecl *Function) { const auto *Proto = Function->getType()->getAs(); if (!Proto || !Proto->getMethodQuals()) return; // FIXME: Add ref-qualifier! // Handle single qualifiers without copying if (Proto->getMethodQuals().hasOnlyConst()) { Result.AddInformativeChunk(" const"); return; } if (Proto->getMethodQuals().hasOnlyVolatile()) { Result.AddInformativeChunk(" volatile"); return; } if (Proto->getMethodQuals().hasOnlyRestrict()) { Result.AddInformativeChunk(" restrict"); return; } // Handle multiple qualifiers. std::string QualsStr; if (Proto->isConst()) QualsStr += " const"; if (Proto->isVolatile()) QualsStr += " volatile"; if (Proto->isRestrict()) QualsStr += " restrict"; Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr)); } /// Add the name of the given declaration static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, const NamedDecl *ND, CodeCompletionBuilder &Result) { DeclarationName Name = ND->getDeclName(); if (!Name) return; switch (Name.getNameKind()) { case DeclarationName::CXXOperatorName: { const char *OperatorName = nullptr; switch (Name.getCXXOverloadedOperator()) { case OO_None: case OO_Conditional: case NUM_OVERLOADED_OPERATORS: OperatorName = "operator"; break; #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \ case OO_##Name: \ OperatorName = "operator" Spelling; \ break; #define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly) #include "clang/Basic/OperatorKinds.def" case OO_New: OperatorName = "operator new"; break; case OO_Delete: OperatorName = "operator delete"; break; case OO_Array_New: OperatorName = "operator new[]"; break; case OO_Array_Delete: OperatorName = "operator delete[]"; break; case OO_Call: OperatorName = "operator()"; break; case OO_Subscript: OperatorName = "operator[]"; break; } Result.AddTypedTextChunk(OperatorName); break; } case DeclarationName::Identifier: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXLiteralOperatorName: Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); break; case DeclarationName::CXXDeductionGuideName: case DeclarationName::CXXUsingDirective: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: break; case DeclarationName::CXXConstructorName: { CXXRecordDecl *Record = nullptr; QualType Ty = Name.getCXXNameType(); if (const auto *RecordTy = Ty->getAs()) Record = cast(RecordTy->getDecl()); else if (const auto *InjectedTy = Ty->getAs()) Record = InjectedTy->getDecl(); else { Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); break; } Result.AddTypedTextChunk( Result.getAllocator().CopyString(Record->getNameAsString())); if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { Result.AddChunk(CodeCompletionString::CK_LeftAngle); AddTemplateParameterChunks(Context, Policy, Template, Result); Result.AddChunk(CodeCompletionString::CK_RightAngle); } break; } } } CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString( Sema &S, const CodeCompletionContext &CCContext, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) { return CreateCodeCompletionString(S.Context, S.PP, CCContext, Allocator, CCTUInfo, IncludeBriefComments); } CodeCompletionString *CodeCompletionResult::CreateCodeCompletionStringForMacro( Preprocessor &PP, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo) { assert(Kind == RK_Macro); CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability); const MacroInfo *MI = PP.getMacroInfo(Macro); Result.AddTypedTextChunk(Result.getAllocator().CopyString(Macro->getName())); if (!MI || !MI->isFunctionLike()) return Result.TakeString(); // Format a function-like macro with placeholders for the arguments. Result.AddChunk(CodeCompletionString::CK_LeftParen); MacroInfo::param_iterator A = MI->param_begin(), AEnd = MI->param_end(); // C99 variadic macros add __VA_ARGS__ at the end. Skip it. if (MI->isC99Varargs()) { --AEnd; if (A == AEnd) { Result.AddPlaceholderChunk("..."); } } for (MacroInfo::param_iterator A = MI->param_begin(); A != AEnd; ++A) { if (A != MI->param_begin()) Result.AddChunk(CodeCompletionString::CK_Comma); if (MI->isVariadic() && (A + 1) == AEnd) { SmallString<32> Arg = (*A)->getName(); if (MI->isC99Varargs()) Arg += ", ..."; else Arg += "..."; Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg)); break; } // Non-variadic macros are simple. Result.AddPlaceholderChunk( Result.getAllocator().CopyString((*A)->getName())); } Result.AddChunk(CodeCompletionString::CK_RightParen); return Result.TakeString(); } /// If possible, create a new code completion string for the given /// result. /// /// \returns Either a new, heap-allocated code completion string describing /// how to use this result, or NULL to indicate that the string or name of the /// result is all that is needed. CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString( ASTContext &Ctx, Preprocessor &PP, const CodeCompletionContext &CCContext, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) { if (Kind == RK_Macro) return CreateCodeCompletionStringForMacro(PP, Allocator, CCTUInfo); CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability); PrintingPolicy Policy = getCompletionPrintingPolicy(Ctx, PP); if (Kind == RK_Pattern) { Pattern->Priority = Priority; Pattern->Availability = Availability; if (Declaration) { Result.addParentContext(Declaration->getDeclContext()); Pattern->ParentName = Result.getParentName(); if (const RawComment *RC = getPatternCompletionComment(Ctx, Declaration)) { Result.addBriefComment(RC->getBriefText(Ctx)); Pattern->BriefComment = Result.getBriefComment(); } } return Pattern; } if (Kind == RK_Keyword) { Result.AddTypedTextChunk(Keyword); return Result.TakeString(); } assert(Kind == RK_Declaration && "Missed a result kind?"); return createCodeCompletionStringForDecl( PP, Ctx, Result, IncludeBriefComments, CCContext, Policy); } static void printOverrideString(const CodeCompletionString &CCS, std::string &BeforeName, std::string &NameAndSignature) { bool SeenTypedChunk = false; for (auto &Chunk : CCS) { if (Chunk.Kind == CodeCompletionString::CK_Optional) { assert(SeenTypedChunk && "optional parameter before name"); // Note that we put all chunks inside into NameAndSignature. printOverrideString(*Chunk.Optional, NameAndSignature, NameAndSignature); continue; } SeenTypedChunk |= Chunk.Kind == CodeCompletionString::CK_TypedText; if (SeenTypedChunk) NameAndSignature += Chunk.Text; else BeforeName += Chunk.Text; } } CodeCompletionString * CodeCompletionResult::createCodeCompletionStringForOverride( Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result, bool IncludeBriefComments, const CodeCompletionContext &CCContext, PrintingPolicy &Policy) { auto *CCS = createCodeCompletionStringForDecl(PP, Ctx, Result, /*IncludeBriefComments=*/false, CCContext, Policy); std::string BeforeName; std::string NameAndSignature; // For overrides all chunks go into the result, none are informative. printOverrideString(*CCS, BeforeName, NameAndSignature); NameAndSignature += " override"; Result.AddTextChunk(Result.getAllocator().CopyString(BeforeName)); Result.AddChunk(CodeCompletionString::CK_HorizontalSpace); Result.AddTypedTextChunk(Result.getAllocator().CopyString(NameAndSignature)); return Result.TakeString(); } // FIXME: Right now this works well with lambdas. Add support for other functor // types like std::function. static const NamedDecl *extractFunctorCallOperator(const NamedDecl *ND) { const auto *VD = dyn_cast(ND); if (!VD) return nullptr; const auto *RecordDecl = VD->getType()->getAsCXXRecordDecl(); if (!RecordDecl || !RecordDecl->isLambda()) return nullptr; return RecordDecl->getLambdaCallOperator(); } CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result, bool IncludeBriefComments, const CodeCompletionContext &CCContext, PrintingPolicy &Policy) { const NamedDecl *ND = Declaration; Result.addParentContext(ND->getDeclContext()); if (IncludeBriefComments) { // Add documentation comment, if it exists. if (const RawComment *RC = getCompletionComment(Ctx, Declaration)) { Result.addBriefComment(RC->getBriefText(Ctx)); } } if (StartsNestedNameSpecifier) { Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); Result.AddTextChunk("::"); return Result.TakeString(); } for (const auto *I : ND->specific_attrs()) Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation())); auto AddFunctionTypeAndResult = [&](const FunctionDecl *Function) { AddResultTypeChunk(Ctx, Policy, Function, CCContext.getBaseType(), Result); AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, Ctx, Policy); AddTypedNameChunk(Ctx, Policy, ND, Result); Result.AddChunk(CodeCompletionString::CK_LeftParen); AddFunctionParameterChunks(PP, Policy, Function, Result); Result.AddChunk(CodeCompletionString::CK_RightParen); AddFunctionTypeQualsToCompletionString(Result, Function); }; if (const auto *Function = dyn_cast(ND)) { AddFunctionTypeAndResult(Function); return Result.TakeString(); } if (const auto *CallOperator = dyn_cast_or_null(extractFunctorCallOperator(ND))) { AddFunctionTypeAndResult(CallOperator); return Result.TakeString(); } AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); if (const FunctionTemplateDecl *FunTmpl = dyn_cast(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, Ctx, Policy); FunctionDecl *Function = FunTmpl->getTemplatedDecl(); AddTypedNameChunk(Ctx, Policy, Function, Result); // Figure out which template parameters are deduced (or have default // arguments). llvm::SmallBitVector Deduced; Sema::MarkDeducedTemplateParameters(Ctx, FunTmpl, Deduced); unsigned LastDeducibleArgument; for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0; --LastDeducibleArgument) { if (!Deduced[LastDeducibleArgument - 1]) { // C++0x: Figure out if the template argument has a default. If so, // the user doesn't need to type this argument. // FIXME: We need to abstract template parameters better! bool HasDefaultArg = false; NamedDecl *Param = FunTmpl->getTemplateParameters()->getParam( LastDeducibleArgument - 1); if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) HasDefaultArg = TTP->hasDefaultArgument(); else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(Param)) HasDefaultArg = NTTP->hasDefaultArgument(); else { assert(isa(Param)); HasDefaultArg = cast(Param)->hasDefaultArgument(); } if (!HasDefaultArg) break; } } if (LastDeducibleArgument) { // Some of the function template arguments cannot be deduced from a // function call, so we introduce an explicit template argument list // containing all of the arguments up to the first deducible argument. Result.AddChunk(CodeCompletionString::CK_LeftAngle); AddTemplateParameterChunks(Ctx, Policy, FunTmpl, Result, LastDeducibleArgument); Result.AddChunk(CodeCompletionString::CK_RightAngle); } // Add the function parameters Result.AddChunk(CodeCompletionString::CK_LeftParen); AddFunctionParameterChunks(PP, Policy, Function, Result); Result.AddChunk(CodeCompletionString::CK_RightParen); AddFunctionTypeQualsToCompletionString(Result, Function); return Result.TakeString(); } if (const auto *Template = dyn_cast(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, Ctx, Policy); Result.AddTypedTextChunk( Result.getAllocator().CopyString(Template->getNameAsString())); Result.AddChunk(CodeCompletionString::CK_LeftAngle); AddTemplateParameterChunks(Ctx, Policy, Template, Result); Result.AddChunk(CodeCompletionString::CK_RightAngle); return Result.TakeString(); } if (const auto *Method = dyn_cast(ND)) { Selector Sel = Method->getSelector(); if (Sel.isUnarySelector()) { Result.AddTypedTextChunk( Result.getAllocator().CopyString(Sel.getNameForSlot(0))); return Result.TakeString(); } std::string SelName = Sel.getNameForSlot(0).str(); SelName += ':'; if (StartParameter == 0) Result.AddTypedTextChunk(Result.getAllocator().CopyString(SelName)); else { Result.AddInformativeChunk(Result.getAllocator().CopyString(SelName)); // If there is only one parameter, and we're past it, add an empty // typed-text chunk since there is nothing to type. if (Method->param_size() == 1) Result.AddTypedTextChunk(""); } unsigned Idx = 0; for (ObjCMethodDecl::param_const_iterator P = Method->param_begin(), PEnd = Method->param_end(); P != PEnd; (void)++P, ++Idx) { if (Idx > 0) { std::string Keyword; if (Idx > StartParameter) Result.AddChunk(CodeCompletionString::CK_HorizontalSpace); if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) Keyword += II->getName(); Keyword += ":"; if (Idx < StartParameter || AllParametersAreInformative) Result.AddInformativeChunk(Result.getAllocator().CopyString(Keyword)); else Result.AddTypedTextChunk(Result.getAllocator().CopyString(Keyword)); } // If we're before the starting parameter, skip the placeholder. if (Idx < StartParameter) continue; std::string Arg; QualType ParamType = (*P)->getType(); Optional> ObjCSubsts; if (!CCContext.getBaseType().isNull()) ObjCSubsts = CCContext.getBaseType()->getObjCSubstitutions(Method); if (ParamType->isBlockPointerType() && !DeclaringEntity) Arg = FormatFunctionParameter(Policy, *P, true, /*SuppressBlock=*/false, ObjCSubsts); else { if (ObjCSubsts) ParamType = ParamType.substObjCTypeArgs( Ctx, *ObjCSubsts, ObjCSubstitutionContext::Parameter); Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier(), ParamType); Arg += ParamType.getAsString(Policy) + ")"; if (IdentifierInfo *II = (*P)->getIdentifier()) if (DeclaringEntity || AllParametersAreInformative) Arg += II->getName(); } if (Method->isVariadic() && (P + 1) == PEnd) Arg += ", ..."; if (DeclaringEntity) Result.AddTextChunk(Result.getAllocator().CopyString(Arg)); else if (AllParametersAreInformative) Result.AddInformativeChunk(Result.getAllocator().CopyString(Arg)); else Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg)); } if (Method->isVariadic()) { if (Method->param_size() == 0) { if (DeclaringEntity) Result.AddTextChunk(", ..."); else if (AllParametersAreInformative) Result.AddInformativeChunk(", ..."); else Result.AddPlaceholderChunk(", ..."); } MaybeAddSentinel(PP, Method, Result); } return Result.TakeString(); } if (Qualifier) AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, Ctx, Policy); Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); return Result.TakeString(); } const RawComment *clang::getCompletionComment(const ASTContext &Ctx, const NamedDecl *ND) { if (!ND) return nullptr; if (auto *RC = Ctx.getRawCommentForAnyRedecl(ND)) return RC; // Try to find comment from a property for ObjC methods. const auto *M = dyn_cast(ND); if (!M) return nullptr; const ObjCPropertyDecl *PDecl = M->findPropertyDecl(); if (!PDecl) return nullptr; return Ctx.getRawCommentForAnyRedecl(PDecl); } const RawComment *clang::getPatternCompletionComment(const ASTContext &Ctx, const NamedDecl *ND) { const auto *M = dyn_cast_or_null(ND); if (!M || !M->isPropertyAccessor()) return nullptr; // Provide code completion comment for self.GetterName where // GetterName is the getter method for a property with name // different from the property name (declared via a property // getter attribute. const ObjCPropertyDecl *PDecl = M->findPropertyDecl(); if (!PDecl) return nullptr; if (PDecl->getGetterName() == M->getSelector() && PDecl->getIdentifier() != M->getIdentifier()) { if (auto *RC = Ctx.getRawCommentForAnyRedecl(M)) return RC; if (auto *RC = Ctx.getRawCommentForAnyRedecl(PDecl)) return RC; } return nullptr; } const RawComment *clang::getParameterComment( const ASTContext &Ctx, const CodeCompleteConsumer::OverloadCandidate &Result, unsigned ArgIndex) { auto FDecl = Result.getFunction(); if (!FDecl) return nullptr; if (ArgIndex < FDecl->getNumParams()) return Ctx.getRawCommentForAnyRedecl(FDecl->getParamDecl(ArgIndex)); return nullptr; } /// Add function overload parameter chunks to the given code completion /// string. static void AddOverloadParameterChunks(ASTContext &Context, const PrintingPolicy &Policy, const FunctionDecl *Function, const FunctionProtoType *Prototype, CodeCompletionBuilder &Result, unsigned CurrentArg, unsigned Start = 0, bool InOptional = false) { bool FirstParameter = true; unsigned NumParams = Function ? Function->getNumParams() : Prototype->getNumParams(); for (unsigned P = Start; P != NumParams; ++P) { if (Function && Function->getParamDecl(P)->hasDefaultArg() && !InOptional) { // When we see an optional default argument, put that argument and // the remaining default arguments into a new, optional string. CodeCompletionBuilder Opt(Result.getAllocator(), Result.getCodeCompletionTUInfo()); if (!FirstParameter) Opt.AddChunk(CodeCompletionString::CK_Comma); // Optional sections are nested. AddOverloadParameterChunks(Context, Policy, Function, Prototype, Opt, CurrentArg, P, /*InOptional=*/true); Result.AddOptionalChunk(Opt.TakeString()); return; } if (FirstParameter) FirstParameter = false; else Result.AddChunk(CodeCompletionString::CK_Comma); InOptional = false; // Format the placeholder string. std::string Placeholder; if (Function) { const ParmVarDecl *Param = Function->getParamDecl(P); Placeholder = FormatFunctionParameter(Policy, Param); if (Param->hasDefaultArg()) Placeholder += GetDefaultValueString(Param, Context.getSourceManager(), Context.getLangOpts()); } else { Placeholder = Prototype->getParamType(P).getAsString(Policy); } if (P == CurrentArg) Result.AddCurrentParameterChunk( Result.getAllocator().CopyString(Placeholder)); else Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Placeholder)); } if (Prototype && Prototype->isVariadic()) { CodeCompletionBuilder Opt(Result.getAllocator(), Result.getCodeCompletionTUInfo()); if (!FirstParameter) Opt.AddChunk(CodeCompletionString::CK_Comma); if (CurrentArg < NumParams) Opt.AddPlaceholderChunk("..."); else Opt.AddCurrentParameterChunk("..."); Result.AddOptionalChunk(Opt.TakeString()); } } CodeCompletionString * CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( unsigned CurrentArg, Sema &S, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) const { PrintingPolicy Policy = getCompletionPrintingPolicy(S); // Show signatures of constructors as they are declared: // vector(int n) rather than vector(int n) // This is less noisy without being less clear, and avoids tricky cases. Policy.SuppressTemplateArgsInCXXConstructors = true; // FIXME: Set priority, availability appropriately. CodeCompletionBuilder Result(Allocator, CCTUInfo, 1, CXAvailability_Available); FunctionDecl *FDecl = getFunction(); const FunctionProtoType *Proto = dyn_cast(getFunctionType()); if (!FDecl && !Proto) { // Function without a prototype. Just give the return type and a // highlighted ellipsis. const FunctionType *FT = getFunctionType(); Result.AddResultTypeChunk(Result.getAllocator().CopyString( FT->getReturnType().getAsString(Policy))); Result.AddChunk(CodeCompletionString::CK_LeftParen); Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "..."); Result.AddChunk(CodeCompletionString::CK_RightParen); return Result.TakeString(); } if (FDecl) { if (IncludeBriefComments) { if (auto RC = getParameterComment(S.getASTContext(), *this, CurrentArg)) Result.addBriefComment(RC->getBriefText(S.getASTContext())); } AddResultTypeChunk(S.Context, Policy, FDecl, QualType(), Result); std::string Name; llvm::raw_string_ostream OS(Name); FDecl->getDeclName().print(OS, Policy); Result.AddTextChunk(Result.getAllocator().CopyString(OS.str())); } else { Result.AddResultTypeChunk(Result.getAllocator().CopyString( Proto->getReturnType().getAsString(Policy))); } Result.AddChunk(CodeCompletionString::CK_LeftParen); AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, Result, CurrentArg); Result.AddChunk(CodeCompletionString::CK_RightParen); return Result.TakeString(); } unsigned clang::getMacroUsagePriority(StringRef MacroName, const LangOptions &LangOpts, bool PreferredTypeIsPointer) { unsigned Priority = CCP_Macro; // Treat the "nil", "Nil" and "NULL" macros as null pointer constants. if (MacroName.equals("nil") || MacroName.equals("NULL") || MacroName.equals("Nil")) { Priority = CCP_Constant; if (PreferredTypeIsPointer) Priority = Priority / CCF_SimilarTypeMatch; } // Treat "YES", "NO", "true", and "false" as constants. else if (MacroName.equals("YES") || MacroName.equals("NO") || MacroName.equals("true") || MacroName.equals("false")) Priority = CCP_Constant; // Treat "bool" as a type. else if (MacroName.equals("bool")) Priority = CCP_Type + (LangOpts.ObjC ? CCD_bool_in_ObjC : 0); return Priority; } CXCursorKind clang::getCursorKindForDecl(const Decl *D) { if (!D) return CXCursor_UnexposedDecl; switch (D->getKind()) { case Decl::Enum: return CXCursor_EnumDecl; case Decl::EnumConstant: return CXCursor_EnumConstantDecl; case Decl::Field: return CXCursor_FieldDecl; case Decl::Function: return CXCursor_FunctionDecl; case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; case Decl::ObjCCategoryImpl: return CXCursor_ObjCCategoryImplDecl; case Decl::ObjCImplementation: return CXCursor_ObjCImplementationDecl; case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl; case Decl::ObjCMethod: return cast(D)->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl; case Decl::CXXMethod: return CXCursor_CXXMethod; case Decl::CXXConstructor: return CXCursor_Constructor; case Decl::CXXDestructor: return CXCursor_Destructor; case Decl::CXXConversion: return CXCursor_ConversionFunction; case Decl::ObjCProperty: return CXCursor_ObjCPropertyDecl; case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; case Decl::ParmVar: return CXCursor_ParmDecl; case Decl::Typedef: return CXCursor_TypedefDecl; case Decl::TypeAlias: return CXCursor_TypeAliasDecl; case Decl::TypeAliasTemplate: return CXCursor_TypeAliasTemplateDecl; case Decl::Var: return CXCursor_VarDecl; case Decl::Namespace: return CXCursor_Namespace; case Decl::NamespaceAlias: return CXCursor_NamespaceAlias; case Decl::TemplateTypeParm: return CXCursor_TemplateTypeParameter; case Decl::NonTypeTemplateParm: return CXCursor_NonTypeTemplateParameter; case Decl::TemplateTemplateParm: return CXCursor_TemplateTemplateParameter; case Decl::FunctionTemplate: return CXCursor_FunctionTemplate; case Decl::ClassTemplate: return CXCursor_ClassTemplate; case Decl::AccessSpec: return CXCursor_CXXAccessSpecifier; case Decl::ClassTemplatePartialSpecialization: return CXCursor_ClassTemplatePartialSpecialization; case Decl::UsingDirective: return CXCursor_UsingDirective; case Decl::StaticAssert: return CXCursor_StaticAssert; case Decl::Friend: return CXCursor_FriendDecl; case Decl::TranslationUnit: return CXCursor_TranslationUnit; case Decl::Using: case Decl::UnresolvedUsingValue: case Decl::UnresolvedUsingTypename: return CXCursor_UsingDeclaration; case Decl::ObjCPropertyImpl: switch (cast(D)->getPropertyImplementation()) { case ObjCPropertyImplDecl::Dynamic: return CXCursor_ObjCDynamicDecl; case ObjCPropertyImplDecl::Synthesize: return CXCursor_ObjCSynthesizeDecl; } llvm_unreachable("Unexpected Kind!"); case Decl::Import: return CXCursor_ModuleImportDecl; case Decl::ObjCTypeParam: return CXCursor_TemplateTypeParameter; default: if (const auto *TD = dyn_cast(D)) { switch (TD->getTagKind()) { case TTK_Interface: // fall through case TTK_Struct: return CXCursor_StructDecl; case TTK_Class: return CXCursor_ClassDecl; case TTK_Union: return CXCursor_UnionDecl; case TTK_Enum: return CXCursor_EnumDecl; } } } return CXCursor_UnexposedDecl; } static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results, bool LoadExternal, bool IncludeUndefined, bool TargetTypeIsPointer = false) { typedef CodeCompletionResult Result; Results.EnterNewScope(); for (Preprocessor::macro_iterator M = PP.macro_begin(LoadExternal), MEnd = PP.macro_end(LoadExternal); M != MEnd; ++M) { auto MD = PP.getMacroDefinition(M->first); if (IncludeUndefined || MD) { MacroInfo *MI = MD.getMacroInfo(); if (MI && MI->isUsedForHeaderGuard()) continue; Results.AddResult( Result(M->first, MI, getMacroUsagePriority(M->first->getName(), PP.getLangOpts(), TargetTypeIsPointer))); } } Results.ExitScope(); } static void AddPrettyFunctionResults(const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompletionResult Result; Results.EnterNewScope(); Results.AddResult(Result("__PRETTY_FUNCTION__", CCP_Constant)); Results.AddResult(Result("__FUNCTION__", CCP_Constant)); if (LangOpts.C99 || LangOpts.CPlusPlus11) Results.AddResult(Result("__func__", CCP_Constant)); Results.ExitScope(); } static void HandleCodeCompleteResults(Sema *S, CodeCompleteConsumer *CodeCompleter, CodeCompletionContext Context, CodeCompletionResult *Results, unsigned NumResults) { if (CodeCompleter) CodeCompleter->ProcessCodeCompleteResults(*S, Context, Results, NumResults); } static CodeCompletionContext mapCodeCompletionContext(Sema &S, Sema::ParserCompletionContext PCC) { switch (PCC) { case Sema::PCC_Namespace: return CodeCompletionContext::CCC_TopLevel; case Sema::PCC_Class: return CodeCompletionContext::CCC_ClassStructUnion; case Sema::PCC_ObjCInterface: return CodeCompletionContext::CCC_ObjCInterface; case Sema::PCC_ObjCImplementation: return CodeCompletionContext::CCC_ObjCImplementation; case Sema::PCC_ObjCInstanceVariableList: return CodeCompletionContext::CCC_ObjCIvarList; case Sema::PCC_Template: case Sema::PCC_MemberTemplate: if (S.CurContext->isFileContext()) return CodeCompletionContext::CCC_TopLevel; if (S.CurContext->isRecord()) return CodeCompletionContext::CCC_ClassStructUnion; return CodeCompletionContext::CCC_Other; case Sema::PCC_RecoveryInFunction: return CodeCompletionContext::CCC_Recovery; case Sema::PCC_ForInit: if (S.getLangOpts().CPlusPlus || S.getLangOpts().C99 || S.getLangOpts().ObjC) return CodeCompletionContext::CCC_ParenthesizedExpression; else return CodeCompletionContext::CCC_Expression; case Sema::PCC_Expression: return CodeCompletionContext::CCC_Expression; case Sema::PCC_Condition: return CodeCompletionContext(CodeCompletionContext::CCC_Expression, S.getASTContext().BoolTy); case Sema::PCC_Statement: return CodeCompletionContext::CCC_Statement; case Sema::PCC_Type: return CodeCompletionContext::CCC_Type; case Sema::PCC_ParenthesizedExpression: return CodeCompletionContext::CCC_ParenthesizedExpression; case Sema::PCC_LocalDeclarationSpecifiers: return CodeCompletionContext::CCC_Type; } llvm_unreachable("Invalid ParserCompletionContext!"); } /// If we're in a C++ virtual member function, add completion results /// that invoke the functions we override, since it's common to invoke the /// overridden function as well as adding new functionality. /// /// \param S The semantic analysis object for which we are generating results. /// /// \param InContext This context in which the nested-name-specifier preceding /// the code-completion point static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, ResultBuilder &Results) { // Look through blocks. DeclContext *CurContext = S.CurContext; while (isa(CurContext)) CurContext = CurContext->getParent(); CXXMethodDecl *Method = dyn_cast(CurContext); if (!Method || !Method->isVirtual()) return; // We need to have names for all of the parameters, if we're going to // generate a forwarding call. for (auto P : Method->parameters()) if (!P->getDeclName()) return; PrintingPolicy Policy = getCompletionPrintingPolicy(S); for (const CXXMethodDecl *Overridden : Method->overridden_methods()) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl()) continue; // If we need a nested-name-specifier, add one now. if (!InContext) { NestedNameSpecifier *NNS = getRequiredQualification( S.Context, CurContext, Overridden->getDeclContext()); if (NNS) { std::string Str; llvm::raw_string_ostream OS(Str); NNS->print(OS, Policy); Builder.AddTextChunk(Results.getAllocator().CopyString(OS.str())); } } else if (!InContext->Equals(Overridden->getDeclContext())) continue; Builder.AddTypedTextChunk( Results.getAllocator().CopyString(Overridden->getNameAsString())); Builder.AddChunk(CodeCompletionString::CK_LeftParen); bool FirstParam = true; for (auto P : Method->parameters()) { if (FirstParam) FirstParam = false; else Builder.AddChunk(CodeCompletionString::CK_Comma); Builder.AddPlaceholderChunk( Results.getAllocator().CopyString(P->getIdentifier()->getName())); } Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(CodeCompletionResult( Builder.TakeString(), CCP_SuperCompletion, CXCursor_CXXMethod, CXAvailability_Available, Overridden)); Results.Ignore(Overridden); } } void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); typedef CodeCompletionResult Result; if (Path.empty()) { // Enumerate all top-level modules. SmallVector Modules; PP.getHeaderSearchInfo().collectAllModules(Modules); for (unsigned I = 0, N = Modules.size(); I != N; ++I) { Builder.AddTypedTextChunk( Builder.getAllocator().CopyString(Modules[I]->Name)); Results.AddResult(Result( Builder.TakeString(), CCP_Declaration, CXCursor_ModuleImportDecl, Modules[I]->isAvailable() ? CXAvailability_Available : CXAvailability_NotAvailable)); } } else if (getLangOpts().Modules) { // Load the named module. Module *Mod = PP.getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible, /*IsInclusionDirective=*/false); // Enumerate submodules. if (Mod) { for (Module::submodule_iterator Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); Sub != SubEnd; ++Sub) { Builder.AddTypedTextChunk( Builder.getAllocator().CopyString((*Sub)->Name)); Results.AddResult(Result( Builder.TakeString(), CCP_Declaration, CXCursor_ModuleImportDecl, (*Sub)->isAvailable() ? CXAvailability_Available : CXAvailability_NotAvailable)); } } } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteOrdinaryName(Scope *S, ParserCompletionContext CompletionContext) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), mapCodeCompletionContext(*this, CompletionContext)); Results.EnterNewScope(); // Determine how to filter results, e.g., so that the names of // values (functions, enumerators, function templates, etc.) are // only allowed where we can have an expression. switch (CompletionContext) { case PCC_Namespace: case PCC_Class: case PCC_ObjCInterface: case PCC_ObjCImplementation: case PCC_ObjCInstanceVariableList: case PCC_Template: case PCC_MemberTemplate: case PCC_Type: case PCC_LocalDeclarationSpecifiers: Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); break; case PCC_Statement: case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_ForInit: case PCC_Condition: if (WantTypesInContext(CompletionContext, getLangOpts())) Results.setFilter(&ResultBuilder::IsOrdinaryName); else Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName); if (getLangOpts().CPlusPlus) MaybeAddOverrideCalls(*this, /*InContext=*/nullptr, Results); break; case PCC_RecoveryInFunction: // Unfiltered break; } // If we are in a C++ non-static member function, check the qualifiers on // the member function to filter/prioritize the results list. auto ThisType = getCurrentThisType(); if (!ThisType.isNull()) Results.setObjectTypeQualifiers(ThisType->getPointeeType().getQualifiers(), VK_LValue); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); AddOrdinaryNameResults(CompletionContext, S, *this, Results); Results.ExitScope(); switch (CompletionContext) { case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_Statement: case PCC_RecoveryInFunction: if (S->getFnParent()) AddPrettyFunctionResults(getLangOpts(), Results); break; case PCC_Namespace: case PCC_Class: case PCC_ObjCInterface: case PCC_ObjCImplementation: case PCC_ObjCInstanceVariableList: case PCC_Template: case PCC_MemberTemplate: case PCC_ForInit: case PCC_Condition: case PCC_Type: case PCC_LocalDeclarationSpecifiers: break; } if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, CodeCompleter->loadExternal(), false); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper, ResultBuilder &Results); void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, bool AllowNonIdentifiers, bool AllowNestedNameSpecifiers) { typedef CodeCompletionResult Result; ResultBuilder Results( *this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), AllowNestedNameSpecifiers // FIXME: Try to separate codepath leading here to deduce whether we // need an existing symbol or a new one. ? CodeCompletionContext::CCC_SymbolOrNewName : CodeCompletionContext::CCC_NewName); Results.EnterNewScope(); // Type qualifiers can come after names. Results.AddResult(Result("const")); Results.AddResult(Result("volatile")); if (getLangOpts().C99) Results.AddResult(Result("restrict")); if (getLangOpts().CPlusPlus) { if (getLangOpts().CPlusPlus11 && (DS.getTypeSpecType() == DeclSpec::TST_class || DS.getTypeSpecType() == DeclSpec::TST_struct)) Results.AddResult("final"); if (AllowNonIdentifiers) { Results.AddResult(Result("operator")); } // Add nested-name-specifiers. if (AllowNestedNameSpecifiers) { Results.allowNestedNameSpecifiers(); Results.setFilter(&ResultBuilder::IsImpossibleToSatisfy); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); Results.setFilter(nullptr); } } Results.ExitScope(); // If we're in a context where we might have an expression (rather than a // declaration), and what we've seen so far is an Objective-C type that could // be a receiver of a class message, this may be a class message send with // the initial opening bracket '[' missing. Add appropriate completions. if (AllowNonIdentifiers && !AllowNestedNameSpecifiers && DS.getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier && DS.getTypeSpecType() == DeclSpec::TST_typename && DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified && DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && !DS.isTypeAltiVecVector() && S && (S->getFlags() & Scope::DeclScope) != 0 && (S->getFlags() & (Scope::ClassScope | Scope::TemplateParamScope | Scope::FunctionPrototypeScope | Scope::AtCatchScope)) == 0) { ParsedType T = DS.getRepAsType(); if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType()) AddClassMessageCompletions(*this, S, T, None, false, false, Results); } // Note that we intentionally suppress macro results here, since we do not // encourage using macros to produce the names of entities. HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } struct Sema::CodeCompleteExpressionData { CodeCompleteExpressionData(QualType PreferredType = QualType(), bool IsParenthesized = false) : PreferredType(PreferredType), IntegralConstantExpression(false), ObjCCollection(false), IsParenthesized(IsParenthesized) {} QualType PreferredType; bool IntegralConstantExpression; bool ObjCCollection; bool IsParenthesized; SmallVector IgnoreDecls; }; namespace { /// Information that allows to avoid completing redundant enumerators. struct CoveredEnumerators { llvm::SmallPtrSet Seen; NestedNameSpecifier *SuggestedQualifier = nullptr; }; } // namespace static void AddEnumerators(ResultBuilder &Results, ASTContext &Context, EnumDecl *Enum, DeclContext *CurContext, const CoveredEnumerators &Enumerators) { NestedNameSpecifier *Qualifier = Enumerators.SuggestedQualifier; if (Context.getLangOpts().CPlusPlus && !Qualifier && Enumerators.Seen.empty()) { // If there are no prior enumerators in C++, check whether we have to // qualify the names of the enumerators that we suggest, because they // may not be visible in this scope. Qualifier = getRequiredQualification(Context, CurContext, Enum); } Results.EnterNewScope(); for (auto *E : Enum->enumerators()) { if (Enumerators.Seen.count(E)) continue; CodeCompletionResult R(E, CCP_EnumInCase, Qualifier); Results.AddResult(R, CurContext, nullptr, false); } Results.ExitScope(); } /// Try to find a corresponding FunctionProtoType for function-like types (e.g. /// function pointers, std::function, etc). static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) { assert(!T.isNull()); // Try to extract first template argument from std::function<> and similar. // Note we only handle the sugared types, they closely match what users wrote. // We explicitly choose to not handle ClassTemplateSpecializationDecl. if (auto *Specialization = T->getAs()) { if (Specialization->getNumArgs() != 1) return nullptr; const TemplateArgument &Argument = Specialization->getArg(0); if (Argument.getKind() != TemplateArgument::Type) return nullptr; return Argument.getAsType()->getAs(); } // Handle other cases. if (T->isPointerType()) T = T->getPointeeType(); return T->getAs(); } /// Adds a pattern completion for a lambda expression with the specified /// parameter types and placeholders for parameter names. static void AddLambdaCompletion(ResultBuilder &Results, llvm::ArrayRef Parameters, const LangOptions &LangOpts) { if (!Results.includeCodePatterns()) return; CodeCompletionBuilder Completion(Results.getAllocator(), Results.getCodeCompletionTUInfo()); // []() {} Completion.AddChunk(CodeCompletionString::CK_LeftBracket); Completion.AddPlaceholderChunk("="); Completion.AddChunk(CodeCompletionString::CK_RightBracket); if (!Parameters.empty()) { Completion.AddChunk(CodeCompletionString::CK_LeftParen); bool First = true; for (auto Parameter : Parameters) { if (!First) Completion.AddChunk(CodeCompletionString::ChunkKind::CK_Comma); else First = false; constexpr llvm::StringLiteral NamePlaceholder = "!#!NAME_GOES_HERE!#!"; std::string Type = std::string(NamePlaceholder); Parameter.getAsStringInternal(Type, PrintingPolicy(LangOpts)); llvm::StringRef Prefix, Suffix; std::tie(Prefix, Suffix) = llvm::StringRef(Type).split(NamePlaceholder); Prefix = Prefix.rtrim(); Suffix = Suffix.ltrim(); Completion.AddTextChunk(Completion.getAllocator().CopyString(Prefix)); Completion.AddChunk(CodeCompletionString::CK_HorizontalSpace); Completion.AddPlaceholderChunk("parameter"); Completion.AddTextChunk(Completion.getAllocator().CopyString(Suffix)); }; Completion.AddChunk(CodeCompletionString::CK_RightParen); } Completion.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace); Completion.AddChunk(CodeCompletionString::CK_LeftBrace); Completion.AddChunk(CodeCompletionString::CK_HorizontalSpace); Completion.AddPlaceholderChunk("body"); Completion.AddChunk(CodeCompletionString::CK_HorizontalSpace); Completion.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Completion.TakeString()); } /// Perform code-completion in an expression context when we know what /// type we're looking for. void Sema::CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData &Data) { ResultBuilder Results( *this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext( Data.IsParenthesized ? CodeCompletionContext::CCC_ParenthesizedExpression : CodeCompletionContext::CCC_Expression, Data.PreferredType)); auto PCC = Data.IsParenthesized ? PCC_ParenthesizedExpression : PCC_Expression; if (Data.ObjCCollection) Results.setFilter(&ResultBuilder::IsObjCCollection); else if (Data.IntegralConstantExpression) Results.setFilter(&ResultBuilder::IsIntegralConstantValue); else if (WantTypesInContext(PCC, getLangOpts())) Results.setFilter(&ResultBuilder::IsOrdinaryName); else Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName); if (!Data.PreferredType.isNull()) Results.setPreferredType(Data.PreferredType.getNonReferenceType()); // Ignore any declarations that we were told that we don't care about. for (unsigned I = 0, N = Data.IgnoreDecls.size(); I != N; ++I) Results.Ignore(Data.IgnoreDecls[I]); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); Results.EnterNewScope(); AddOrdinaryNameResults(PCC, S, *this, Results); Results.ExitScope(); bool PreferredTypeIsPointer = false; if (!Data.PreferredType.isNull()) { PreferredTypeIsPointer = Data.PreferredType->isAnyPointerType() || Data.PreferredType->isMemberPointerType() || Data.PreferredType->isBlockPointerType(); if (Data.PreferredType->isEnumeralType()) { EnumDecl *Enum = Data.PreferredType->castAs()->getDecl(); if (auto *Def = Enum->getDefinition()) Enum = Def; // FIXME: collect covered enumerators in cases like: // if (x == my_enum::one) { ... } else if (x == ^) {} AddEnumerators(Results, Context, Enum, CurContext, CoveredEnumerators()); } } if (S->getFnParent() && !Data.ObjCCollection && !Data.IntegralConstantExpression) AddPrettyFunctionResults(getLangOpts(), Results); if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, CodeCompleter->loadExternal(), false, PreferredTypeIsPointer); // Complete a lambda expression when preferred type is a function. if (!Data.PreferredType.isNull() && getLangOpts().CPlusPlus11) { if (const FunctionProtoType *F = TryDeconstructFunctionLike(Data.PreferredType)) AddLambdaCompletion(Results, F->getParamTypes(), getLangOpts()); } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteExpression(Scope *S, QualType PreferredType, bool IsParenthesized) { return CodeCompleteExpression( S, CodeCompleteExpressionData(PreferredType, IsParenthesized)); } void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E, QualType PreferredType) { if (E.isInvalid()) CodeCompleteExpression(S, PreferredType); else if (getLangOpts().ObjC) CodeCompleteObjCInstanceMessage(S, E.get(), None, false); } /// The set of properties that have already been added, referenced by /// property name. typedef llvm::SmallPtrSet AddedPropertiesSet; /// Retrieve the container definition, if any? static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) { if (ObjCInterfaceDecl *Interface = dyn_cast(Container)) { if (Interface->hasDefinition()) return Interface->getDefinition(); return Interface; } if (ObjCProtocolDecl *Protocol = dyn_cast(Container)) { if (Protocol->hasDefinition()) return Protocol->getDefinition(); return Protocol; } return Container; } /// Adds a block invocation code completion result for the given block /// declaration \p BD. static void AddObjCBlockCall(ASTContext &Context, const PrintingPolicy &Policy, CodeCompletionBuilder &Builder, const NamedDecl *BD, const FunctionTypeLoc &BlockLoc, const FunctionProtoTypeLoc &BlockProtoLoc) { Builder.AddResultTypeChunk( GetCompletionTypeString(BlockLoc.getReturnLoc().getType(), Context, Policy, Builder.getAllocator())); AddTypedNameChunk(Context, Policy, BD, Builder); Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (BlockProtoLoc && BlockProtoLoc.getTypePtr()->isVariadic()) { Builder.AddPlaceholderChunk("..."); } else { for (unsigned I = 0, N = BlockLoc.getNumParams(); I != N; ++I) { if (I) Builder.AddChunk(CodeCompletionString::CK_Comma); // Format the placeholder string. std::string PlaceholderStr = FormatFunctionParameter(Policy, BlockLoc.getParam(I)); if (I == N - 1 && BlockProtoLoc && BlockProtoLoc.getTypePtr()->isVariadic()) PlaceholderStr += ", ..."; // Add the placeholder string. Builder.AddPlaceholderChunk( Builder.getAllocator().CopyString(PlaceholderStr)); } } Builder.AddChunk(CodeCompletionString::CK_RightParen); } static void AddObjCProperties(const CodeCompletionContext &CCContext, ObjCContainerDecl *Container, bool AllowCategories, bool AllowNullaryMethods, DeclContext *CurContext, AddedPropertiesSet &AddedProperties, ResultBuilder &Results, bool IsBaseExprStatement = false, bool IsClassProperty = false, bool InOriginalClass = true) { typedef CodeCompletionResult Result; // Retrieve the definition. Container = getContainerDef(Container); // Add properties in this container. const auto AddProperty = [&](const ObjCPropertyDecl *P) { if (!AddedProperties.insert(P->getIdentifier()).second) return; // FIXME: Provide block invocation completion for non-statement // expressions. if (!P->getType().getTypePtr()->isBlockPointerType() || !IsBaseExprStatement) { Result R = Result(P, Results.getBasePriority(P), nullptr); if (!InOriginalClass) setInBaseClass(R); Results.MaybeAddResult(R, CurContext); return; } // Block setter and invocation completion is provided only when we are able // to find the FunctionProtoTypeLoc with parameter names for the block. FunctionTypeLoc BlockLoc; FunctionProtoTypeLoc BlockProtoLoc; findTypeLocationForBlockDecl(P->getTypeSourceInfo(), BlockLoc, BlockProtoLoc); if (!BlockLoc) { Result R = Result(P, Results.getBasePriority(P), nullptr); if (!InOriginalClass) setInBaseClass(R); Results.MaybeAddResult(R, CurContext); return; } // The default completion result for block properties should be the block // invocation completion when the base expression is a statement. CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); AddObjCBlockCall(Container->getASTContext(), getCompletionPrintingPolicy(Results.getSema()), Builder, P, BlockLoc, BlockProtoLoc); Result R = Result(Builder.TakeString(), P, Results.getBasePriority(P)); if (!InOriginalClass) setInBaseClass(R); Results.MaybeAddResult(R, CurContext); // Provide additional block setter completion iff the base expression is a // statement and the block property is mutable. if (!P->isReadOnly()) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); AddResultTypeChunk(Container->getASTContext(), getCompletionPrintingPolicy(Results.getSema()), P, CCContext.getBaseType(), Builder); Builder.AddTypedTextChunk( Results.getAllocator().CopyString(P->getName())); Builder.AddChunk(CodeCompletionString::CK_Equal); std::string PlaceholderStr = formatBlockPlaceholder( getCompletionPrintingPolicy(Results.getSema()), P, BlockLoc, BlockProtoLoc, /*SuppressBlockName=*/true); // Add the placeholder string. Builder.AddPlaceholderChunk( Builder.getAllocator().CopyString(PlaceholderStr)); // When completing blocks properties that return void the default // property completion result should show up before the setter, // otherwise the setter completion should show up before the default // property completion, as we normally want to use the result of the // call. Result R = Result(Builder.TakeString(), P, Results.getBasePriority(P) + (BlockLoc.getTypePtr()->getReturnType()->isVoidType() ? CCD_BlockPropertySetter : -CCD_BlockPropertySetter)); if (!InOriginalClass) setInBaseClass(R); Results.MaybeAddResult(R, CurContext); } }; if (IsClassProperty) { for (const auto *P : Container->class_properties()) AddProperty(P); } else { for (const auto *P : Container->instance_properties()) AddProperty(P); } // Add nullary methods or implicit class properties if (AllowNullaryMethods) { ASTContext &Context = Container->getASTContext(); PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema()); // Adds a method result const auto AddMethod = [&](const ObjCMethodDecl *M) { IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0); if (!Name) return; if (!AddedProperties.insert(Name).second) return; CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); AddResultTypeChunk(Context, Policy, M, CCContext.getBaseType(), Builder); Builder.AddTypedTextChunk( Results.getAllocator().CopyString(Name->getName())); Result R = Result(Builder.TakeString(), M, CCP_MemberDeclaration + CCD_MethodAsProperty); if (!InOriginalClass) setInBaseClass(R); Results.MaybeAddResult(R, CurContext); }; if (IsClassProperty) { for (const auto *M : Container->methods()) { // Gather the class method that can be used as implicit property // getters. Methods with arguments or methods that return void aren't // added to the results as they can't be used as a getter. if (!M->getSelector().isUnarySelector() || M->getReturnType()->isVoidType() || M->isInstanceMethod()) continue; AddMethod(M); } } else { for (auto *M : Container->methods()) { if (M->getSelector().isUnarySelector()) AddMethod(M); } } } // Add properties in referenced protocols. if (ObjCProtocolDecl *Protocol = dyn_cast(Container)) { for (auto *P : Protocol->protocols()) AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods, CurContext, AddedProperties, Results, IsBaseExprStatement, IsClassProperty, /*InOriginalClass*/ false); } else if (ObjCInterfaceDecl *IFace = dyn_cast(Container)) { if (AllowCategories) { // Look through categories. for (auto *Cat : IFace->known_categories()) AddObjCProperties(CCContext, Cat, AllowCategories, AllowNullaryMethods, CurContext, AddedProperties, Results, IsBaseExprStatement, IsClassProperty, InOriginalClass); } // Look through protocols. for (auto *I : IFace->all_referenced_protocols()) AddObjCProperties(CCContext, I, AllowCategories, AllowNullaryMethods, CurContext, AddedProperties, Results, IsBaseExprStatement, IsClassProperty, /*InOriginalClass*/ false); // Look in the superclass. if (IFace->getSuperClass()) AddObjCProperties(CCContext, IFace->getSuperClass(), AllowCategories, AllowNullaryMethods, CurContext, AddedProperties, Results, IsBaseExprStatement, IsClassProperty, /*InOriginalClass*/ false); } else if (const auto *Category = dyn_cast(Container)) { // Look through protocols. for (auto *P : Category->protocols()) AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods, CurContext, AddedProperties, Results, IsBaseExprStatement, IsClassProperty, /*InOriginalClass*/ false); } } static void AddRecordMembersCompletionResults( Sema &SemaRef, ResultBuilder &Results, Scope *S, QualType BaseType, ExprValueKind BaseKind, RecordDecl *RD, Optional AccessOpFixIt) { // Indicate that we are performing a member access, and the cv-qualifiers // for the base object type. Results.setObjectTypeQualifiers(BaseType.getQualifiers(), BaseKind); // Access to a C/C++ class, struct, or union. Results.allowNestedNameSpecifiers(); std::vector FixIts; if (AccessOpFixIt) FixIts.emplace_back(AccessOpFixIt.getValue()); CodeCompletionDeclConsumer Consumer(Results, RD, BaseType, std::move(FixIts)); SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer, SemaRef.CodeCompleter->includeGlobals(), /*IncludeDependentBases=*/true, SemaRef.CodeCompleter->loadExternal()); if (SemaRef.getLangOpts().CPlusPlus) { if (!Results.empty()) { // The "template" keyword can follow "->" or "." in the grammar. // However, we only want to suggest the template keyword if something // is dependent. bool IsDependent = BaseType->isDependentType(); if (!IsDependent) { for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent()) if (DeclContext *Ctx = DepScope->getEntity()) { IsDependent = Ctx->isDependentContext(); break; } } if (IsDependent) Results.AddResult(CodeCompletionResult("template")); } } } // Returns the RecordDecl inside the BaseType, falling back to primary template // in case of specializations. Since we might not have a decl for the // instantiation/specialization yet, e.g. dependent code. static RecordDecl *getAsRecordDecl(const QualType BaseType) { if (auto *RD = BaseType->getAsRecordDecl()) return RD; if (const auto *TST = BaseType->getAs()) { if (const auto *TD = dyn_cast_or_null( TST->getTemplateName().getAsTemplateDecl())) { return TD->getTemplatedDecl(); } } return nullptr; } namespace { // Collects completion-relevant information about a concept-constrainted type T. // In particular, examines the constraint expressions to find members of T. // // The design is very simple: we walk down each constraint looking for // expressions of the form T.foo(). // If we're extra lucky, the return type is specified. // We don't do any clever handling of && or || in constraint expressions, we // take members from both branches. // // For example, given: // template concept X = requires (T t, string& s) { t.print(s); }; // template void foo(U u) { u.^ } // We want to suggest the inferred member function 'print(string)'. // We see that u has type U, so X holds. // X requires t.print(s) to be valid, where t has type U (substituted for T). // By looking at the CallExpr we find the signature of print(). // // While we tend to know in advance which kind of members (access via . -> ::) // we want, it's simpler just to gather them all and post-filter. // // FIXME: some of this machinery could be used for non-concept type-parms too, // enabling completion for type parameters based on other uses of that param. // // FIXME: there are other cases where a type can be constrained by a concept, // e.g. inside `if constexpr(ConceptSpecializationExpr) { ... }` class ConceptInfo { public: // Describes a likely member of a type, inferred by concept constraints. // Offered as a code completion for T. T-> and T:: contexts. struct Member { // Always non-null: we only handle members with ordinary identifier names. const IdentifierInfo *Name = nullptr; // Set for functions we've seen called. // We don't have the declared parameter types, only the actual types of // arguments we've seen. These are still valuable, as it's hard to render // a useful function completion with neither parameter types nor names! llvm::Optional> ArgTypes; // Whether this is accessed as T.member, T->member, or T::member. enum AccessOperator { Colons, Arrow, Dot, } Operator = Dot; // What's known about the type of a variable or return type of a function. const TypeConstraint *ResultType = nullptr; // FIXME: also track: // - kind of entity (function/variable/type), to expose structured results // - template args kinds/types, as a proxy for template params // For now we simply return these results as "pattern" strings. CodeCompletionString *render(Sema &S, CodeCompletionAllocator &Alloc, CodeCompletionTUInfo &Info) const { CodeCompletionBuilder B(Alloc, Info); // Result type if (ResultType) { std::string AsString; { llvm::raw_string_ostream OS(AsString); QualType ExactType = deduceType(*ResultType); if (!ExactType.isNull()) ExactType.print(OS, getCompletionPrintingPolicy(S)); else ResultType->print(OS, getCompletionPrintingPolicy(S)); } B.AddResultTypeChunk(Alloc.CopyString(AsString)); } // Member name B.AddTypedTextChunk(Alloc.CopyString(Name->getName())); // Function argument list if (ArgTypes) { B.AddChunk(clang::CodeCompletionString::CK_LeftParen); bool First = true; for (QualType Arg : *ArgTypes) { if (First) First = false; else { B.AddChunk(clang::CodeCompletionString::CK_Comma); B.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace); } B.AddPlaceholderChunk(Alloc.CopyString( Arg.getAsString(getCompletionPrintingPolicy(S)))); } B.AddChunk(clang::CodeCompletionString::CK_RightParen); } return B.TakeString(); } }; // BaseType is the type parameter T to infer members from. // T must be accessible within S, as we use it to find the template entity // that T is attached to in order to gather the relevant constraints. ConceptInfo(const TemplateTypeParmType &BaseType, Scope *S) { auto *TemplatedEntity = getTemplatedEntity(BaseType.getDecl(), S); for (const Expr *E : constraintsForTemplatedEntity(TemplatedEntity)) believe(E, &BaseType); } std::vector members() { std::vector Results; for (const auto &E : this->Results) Results.push_back(E.second); llvm::sort(Results, [](const Member &L, const Member &R) { return L.Name->getName() < R.Name->getName(); }); return Results; } private: // Infer members of T, given that the expression E (dependent on T) is true. void believe(const Expr *E, const TemplateTypeParmType *T) { if (!E || !T) return; if (auto *CSE = dyn_cast(E)) { // If the concept is // template concept CD = f(); // And the concept specialization is // CD // Then we're substituting T for B, so we want to make f() true // by adding members to B - i.e. believe(f(), B); // // For simplicity: // - we don't attempt to substitute int for A // - when T is used in other ways (like CD) we ignore it ConceptDecl *CD = CSE->getNamedConcept(); TemplateParameterList *Params = CD->getTemplateParameters(); unsigned Index = 0; for (const auto &Arg : CSE->getTemplateArguments()) { if (Index >= Params->size()) break; // Won't happen in valid code. if (isApprox(Arg, T)) { auto *TTPD = dyn_cast(Params->getParam(Index)); if (!TTPD) continue; // T was used as an argument, and bound to the parameter TT. auto *TT = cast(TTPD->getTypeForDecl()); // So now we know the constraint as a function of TT is true. believe(CD->getConstraintExpr(), TT); // (concepts themselves have no associated constraints to require) } ++Index; } } else if (auto *BO = dyn_cast(E)) { // For A && B, we can infer members from both branches. // For A || B, the union is still more useful than the intersection. if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { believe(BO->getLHS(), T); believe(BO->getRHS(), T); } } else if (auto *RE = dyn_cast(E)) { // A requires(){...} lets us infer members from each requirement. for (const concepts::Requirement *Req : RE->getRequirements()) { if (!Req->isDependent()) continue; // Can't tell us anything about T. // Now Req cannot a substitution-error: those aren't dependent. if (auto *TR = dyn_cast(Req)) { // Do a full traversal so we get `foo` from `typename T::foo::bar`. QualType AssertedType = TR->getType()->getType(); ValidVisitor(this, T).TraverseType(AssertedType); } else if (auto *ER = dyn_cast(Req)) { ValidVisitor Visitor(this, T); // If we have a type constraint on the value of the expression, // AND the whole outer expression describes a member, then we'll // be able to use the constraint to provide the return type. if (ER->getReturnTypeRequirement().isTypeConstraint()) { Visitor.OuterType = ER->getReturnTypeRequirement().getTypeConstraint(); Visitor.OuterExpr = ER->getExpr(); } Visitor.TraverseStmt(ER->getExpr()); } else if (auto *NR = dyn_cast(Req)) { believe(NR->getConstraintExpr(), T); } } } } // This visitor infers members of T based on traversing expressions/types // that involve T. It is invoked with code known to be valid for T. class ValidVisitor : public RecursiveASTVisitor { ConceptInfo *Outer; const TemplateTypeParmType *T; CallExpr *Caller = nullptr; Expr *Callee = nullptr; public: // If set, OuterExpr is constrained by OuterType. Expr *OuterExpr = nullptr; const TypeConstraint *OuterType = nullptr; ValidVisitor(ConceptInfo *Outer, const TemplateTypeParmType *T) : Outer(Outer), T(T) { assert(T); } // In T.foo or T->foo, `foo` is a member function/variable. bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) { const Type *Base = E->getBaseType().getTypePtr(); bool IsArrow = E->isArrow(); if (Base->isPointerType() && IsArrow) { IsArrow = false; Base = Base->getPointeeType().getTypePtr(); } if (isApprox(Base, T)) addValue(E, E->getMember(), IsArrow ? Member::Arrow : Member::Dot); return true; } // In T::foo, `foo` is a static member function/variable. bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { if (E->getQualifier() && isApprox(E->getQualifier()->getAsType(), T)) addValue(E, E->getDeclName(), Member::Colons); return true; } // In T::typename foo, `foo` is a type. bool VisitDependentNameType(DependentNameType *DNT) { const auto *Q = DNT->getQualifier(); if (Q && isApprox(Q->getAsType(), T)) addType(DNT->getIdentifier()); return true; } // In T::foo::bar, `foo` must be a type. // VisitNNS() doesn't exist, and TraverseNNS isn't always called :-( bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSL) { if (NNSL) { NestedNameSpecifier *NNS = NNSL.getNestedNameSpecifier(); const auto *Q = NNS->getPrefix(); if (Q && isApprox(Q->getAsType(), T)) addType(NNS->getAsIdentifier()); } // FIXME: also handle T::foo::bar return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(NNSL); } // FIXME also handle T::foo // Track the innermost caller/callee relationship so we can tell if a // nested expr is being called as a function. bool VisitCallExpr(CallExpr *CE) { Caller = CE; Callee = CE->getCallee(); return true; } private: void addResult(Member &&M) { auto R = Outer->Results.try_emplace(M.Name); Member &O = R.first->second; // Overwrite existing if the new member has more info. // The preference of . vs :: vs -> is fairly arbitrary. if (/*Inserted*/ R.second || std::make_tuple(M.ArgTypes.hasValue(), M.ResultType != nullptr, M.Operator) > std::make_tuple(O.ArgTypes.hasValue(), O.ResultType != nullptr, O.Operator)) O = std::move(M); } void addType(const IdentifierInfo *Name) { if (!Name) return; Member M; M.Name = Name; M.Operator = Member::Colons; addResult(std::move(M)); } void addValue(Expr *E, DeclarationName Name, Member::AccessOperator Operator) { if (!Name.isIdentifier()) return; Member Result; Result.Name = Name.getAsIdentifierInfo(); Result.Operator = Operator; // If this is the callee of an immediately-enclosing CallExpr, then // treat it as a method, otherwise it's a variable. if (Caller != nullptr && Callee == E) { Result.ArgTypes.emplace(); for (const auto *Arg : Caller->arguments()) Result.ArgTypes->push_back(Arg->getType()); if (Caller == OuterExpr) { Result.ResultType = OuterType; } } else { if (E == OuterExpr) Result.ResultType = OuterType; } addResult(std::move(Result)); } }; static bool isApprox(const TemplateArgument &Arg, const Type *T) { return Arg.getKind() == TemplateArgument::Type && isApprox(Arg.getAsType().getTypePtr(), T); } static bool isApprox(const Type *T1, const Type *T2) { return T1 && T2 && T1->getCanonicalTypeUnqualified() == T2->getCanonicalTypeUnqualified(); } // Returns the DeclContext immediately enclosed by the template parameter // scope. For primary templates, this is the templated (e.g.) CXXRecordDecl. // For specializations, this is e.g. ClassTemplatePartialSpecializationDecl. static DeclContext *getTemplatedEntity(const TemplateTypeParmDecl *D, Scope *S) { if (D == nullptr) return nullptr; Scope *Inner = nullptr; while (S) { if (S->isTemplateParamScope() && S->isDeclScope(D)) return Inner ? Inner->getEntity() : nullptr; Inner = S; S = S->getParent(); } return nullptr; } // Gets all the type constraint expressions that might apply to the type // variables associated with DC (as returned by getTemplatedEntity()). static SmallVector constraintsForTemplatedEntity(DeclContext *DC) { SmallVector Result; if (DC == nullptr) return Result; // Primary templates can have constraints. if (const auto *TD = cast(DC)->getDescribedTemplate()) TD->getAssociatedConstraints(Result); // Partial specializations may have constraints. if (const auto *CTPSD = dyn_cast(DC)) CTPSD->getAssociatedConstraints(Result); if (const auto *VTPSD = dyn_cast(DC)) VTPSD->getAssociatedConstraints(Result); return Result; } // Attempt to find the unique type satisfying a constraint. // This lets us show e.g. `int` instead of `std::same_as`. static QualType deduceType(const TypeConstraint &T) { // Assume a same_as return type constraint is std::same_as or equivalent. // In this case the return type is T. DeclarationName DN = T.getNamedConcept()->getDeclName(); if (DN.isIdentifier() && DN.getAsIdentifierInfo()->isStr("same_as")) if (const auto *Args = T.getTemplateArgsAsWritten()) if (Args->getNumTemplateArgs() == 1) { const auto &Arg = Args->arguments().front().getArgument(); if (Arg.getKind() == TemplateArgument::Type) return Arg.getAsType(); } return {}; } llvm::DenseMap Results; }; } // namespace void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow, bool IsBaseExprStatement, QualType PreferredType) { if (!Base || !CodeCompleter) return; ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow); if (ConvertedBase.isInvalid()) return; QualType ConvertedBaseType = ConvertedBase.get()->getType(); enum CodeCompletionContext::Kind contextKind; if (IsArrow) { if (const auto *Ptr = ConvertedBaseType->getAs()) ConvertedBaseType = Ptr->getPointeeType(); } if (IsArrow) { contextKind = CodeCompletionContext::CCC_ArrowMemberAccess; } else { if (ConvertedBaseType->isObjCObjectPointerType() || ConvertedBaseType->isObjCObjectOrInterfaceType()) { contextKind = CodeCompletionContext::CCC_ObjCPropertyAccess; } else { contextKind = CodeCompletionContext::CCC_DotMemberAccess; } } CodeCompletionContext CCContext(contextKind, ConvertedBaseType); CCContext.setPreferredType(PreferredType); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CCContext, &ResultBuilder::IsMember); auto DoCompletion = [&](Expr *Base, bool IsArrow, Optional AccessOpFixIt) -> bool { if (!Base) return false; ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow); if (ConvertedBase.isInvalid()) return false; Base = ConvertedBase.get(); QualType BaseType = Base->getType(); if (BaseType.isNull()) return false; ExprValueKind BaseKind = Base->getValueKind(); if (IsArrow) { if (const PointerType *Ptr = BaseType->getAs()) { BaseType = Ptr->getPointeeType(); BaseKind = VK_LValue; } else if (BaseType->isObjCObjectPointerType() || BaseType->isTemplateTypeParmType()) { // Both cases (dot/arrow) handled below. } else { return false; } } if (RecordDecl *RD = getAsRecordDecl(BaseType)) { AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind, RD, std::move(AccessOpFixIt)); } else if (const auto *TTPT = dyn_cast(BaseType.getTypePtr())) { auto Operator = IsArrow ? ConceptInfo::Member::Arrow : ConceptInfo::Member::Dot; for (const auto &R : ConceptInfo(*TTPT, S).members()) { if (R.Operator != Operator) continue; CodeCompletionResult Result( R.render(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo())); if (AccessOpFixIt) Result.FixIts.push_back(*AccessOpFixIt); Results.AddResult(std::move(Result)); } } else if (!IsArrow && BaseType->isObjCObjectPointerType()) { // Objective-C property reference. Bail if we're performing fix-it code // completion since Objective-C properties are normally backed by ivars, // most Objective-C fix-its here would have little value. if (AccessOpFixIt.hasValue()) { return false; } AddedPropertiesSet AddedProperties; if (const ObjCObjectPointerType *ObjCPtr = BaseType->getAsObjCInterfacePointerType()) { // Add property results based on our interface. assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true, /*AllowNullaryMethods=*/true, CurContext, AddedProperties, Results, IsBaseExprStatement); } // Add properties from the protocols in a qualified interface. for (auto *I : BaseType->castAs()->quals()) AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true, CurContext, AddedProperties, Results, IsBaseExprStatement, /*IsClassProperty*/ false, /*InOriginalClass*/ false); } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCObjectType())) { // Objective-C instance variable access. Bail if we're performing fix-it // code completion since Objective-C properties are normally backed by // ivars, most Objective-C fix-its here would have little value. if (AccessOpFixIt.hasValue()) { return false; } ObjCInterfaceDecl *Class = nullptr; if (const ObjCObjectPointerType *ObjCPtr = BaseType->getAs()) Class = ObjCPtr->getInterfaceDecl(); else Class = BaseType->castAs()->getInterface(); // Add all ivars from this class and its superclasses. if (Class) { CodeCompletionDeclConsumer Consumer(Results, Class, BaseType); Results.setFilter(&ResultBuilder::IsObjCIvar); LookupVisibleDecls( Class, LookupMemberName, Consumer, CodeCompleter->includeGlobals(), /*IncludeDependentBases=*/false, CodeCompleter->loadExternal()); } } // FIXME: How do we cope with isa? return true; }; Results.EnterNewScope(); bool CompletionSucceded = DoCompletion(Base, IsArrow, None); if (CodeCompleter->includeFixIts()) { const CharSourceRange OpRange = CharSourceRange::getTokenRange(OpLoc, OpLoc); CompletionSucceded |= DoCompletion( OtherOpBase, !IsArrow, FixItHint::CreateReplacement(OpRange, IsArrow ? "." : "->")); } Results.ExitScope(); if (!CompletionSucceded) return; // Hand off the results found for code completion. HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCClassPropertyRefExpr(Scope *S, IdentifierInfo &ClassName, SourceLocation ClassNameLoc, bool IsBaseExprStatement) { IdentifierInfo *ClassNamePtr = &ClassName; ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(ClassNamePtr, ClassNameLoc); if (!IFace) return; CodeCompletionContext CCContext( CodeCompletionContext::CCC_ObjCPropertyAccess); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CCContext, &ResultBuilder::IsMember); Results.EnterNewScope(); AddedPropertiesSet AddedProperties; AddObjCProperties(CCContext, IFace, true, /*AllowNullaryMethods=*/true, CurContext, AddedProperties, Results, IsBaseExprStatement, /*IsClassProperty=*/true); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { if (!CodeCompleter) return; ResultBuilder::LookupFilter Filter = nullptr; enum CodeCompletionContext::Kind ContextKind = CodeCompletionContext::CCC_Other; switch ((DeclSpec::TST)TagSpec) { case DeclSpec::TST_enum: Filter = &ResultBuilder::IsEnum; ContextKind = CodeCompletionContext::CCC_EnumTag; break; case DeclSpec::TST_union: Filter = &ResultBuilder::IsUnion; ContextKind = CodeCompletionContext::CCC_UnionTag; break; case DeclSpec::TST_struct: case DeclSpec::TST_class: case DeclSpec::TST_interface: Filter = &ResultBuilder::IsClassOrStruct; ContextKind = CodeCompletionContext::CCC_ClassOrStructTag; break; default: llvm_unreachable("Unknown type specifier kind in CodeCompleteTag"); } ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), ContextKind); CodeCompletionDeclConsumer Consumer(Results, CurContext); // First pass: look for tags. Results.setFilter(Filter); LookupVisibleDecls(S, LookupTagName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); if (CodeCompleter->includeGlobals()) { // Second pass: look for nested name specifiers. Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } static void AddTypeQualifierResults(DeclSpec &DS, ResultBuilder &Results, const LangOptions &LangOpts) { if (!(DS.getTypeQualifiers() & DeclSpec::TQ_const)) Results.AddResult("const"); if (!(DS.getTypeQualifiers() & DeclSpec::TQ_volatile)) Results.AddResult("volatile"); if (LangOpts.C99 && !(DS.getTypeQualifiers() & DeclSpec::TQ_restrict)) Results.AddResult("restrict"); if (LangOpts.C11 && !(DS.getTypeQualifiers() & DeclSpec::TQ_atomic)) Results.AddResult("_Atomic"); if (LangOpts.MSVCCompat && !(DS.getTypeQualifiers() & DeclSpec::TQ_unaligned)) Results.AddResult("__unaligned"); } void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_TypeQualifiers); Results.EnterNewScope(); AddTypeQualifierResults(DS, Results, LangOpts); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D, const VirtSpecifiers *VS) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_TypeQualifiers); Results.EnterNewScope(); AddTypeQualifierResults(DS, Results, LangOpts); if (LangOpts.CPlusPlus11) { Results.AddResult("noexcept"); if (D.getContext() == DeclaratorContext::MemberContext && !D.isCtorOrDtor() && !D.isStaticMember()) { if (!VS || !VS->isFinalSpecified()) Results.AddResult("final"); if (!VS || !VS->isOverrideSpecified()) Results.AddResult("override"); } } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteBracketDeclarator(Scope *S) { CodeCompleteExpression(S, QualType(getASTContext().getSizeType())); } void Sema::CodeCompleteCase(Scope *S) { if (getCurFunction()->SwitchStack.empty() || !CodeCompleter) return; SwitchStmt *Switch = getCurFunction()->SwitchStack.back().getPointer(); // Condition expression might be invalid, do not continue in this case. if (!Switch->getCond()) return; QualType type = Switch->getCond()->IgnoreImplicit()->getType(); if (!type->isEnumeralType()) { CodeCompleteExpressionData Data(type); Data.IntegralConstantExpression = true; CodeCompleteExpression(S, Data); return; } // Code-complete the cases of a switch statement over an enumeration type // by providing the list of EnumDecl *Enum = type->castAs()->getDecl(); if (EnumDecl *Def = Enum->getDefinition()) Enum = Def; // Determine which enumerators we have already seen in the switch statement. // FIXME: Ideally, we would also be able to look *past* the code-completion // token, in case we are code-completing in the middle of the switch and not // at the end. However, we aren't able to do so at the moment. CoveredEnumerators Enumerators; for (SwitchCase *SC = Switch->getSwitchCaseList(); SC; SC = SC->getNextSwitchCase()) { CaseStmt *Case = dyn_cast(SC); if (!Case) continue; Expr *CaseVal = Case->getLHS()->IgnoreParenCasts(); if (auto *DRE = dyn_cast(CaseVal)) if (auto *Enumerator = dyn_cast(DRE->getDecl())) { // We look into the AST of the case statement to determine which // enumerator was named. Alternatively, we could compute the value of // the integral constant expression, then compare it against the // values of each enumerator. However, value-based approach would not // work as well with C++ templates where enumerators declared within a // template are type- and value-dependent. Enumerators.Seen.insert(Enumerator); // If this is a qualified-id, keep track of the nested-name-specifier // so that we can reproduce it as part of code completion, e.g., // // switch (TagD.getKind()) { // case TagDecl::TK_enum: // break; // case XXX // // At the XXX, our completions are TagDecl::TK_union, // TagDecl::TK_struct, and TagDecl::TK_class, rather than TK_union, // TK_struct, and TK_class. Enumerators.SuggestedQualifier = DRE->getQualifier(); } } // Add any enumerators that have not yet been mentioned. ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Expression); AddEnumerators(Results, Context, Enum, CurContext, Enumerators); if (CodeCompleter->includeMacros()) { AddMacroResults(PP, Results, CodeCompleter->loadExternal(), false); } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } static bool anyNullArguments(ArrayRef Args) { if (Args.size() && !Args.data()) return true; for (unsigned I = 0; I != Args.size(); ++I) if (!Args[I]) return true; return false; } typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; static void mergeCandidatesWithResults( Sema &SemaRef, SmallVectorImpl &Results, OverloadCandidateSet &CandidateSet, SourceLocation Loc) { // Sort the overload candidate set by placing the best overloads first. llvm::stable_sort(CandidateSet, [&](const OverloadCandidate &X, const OverloadCandidate &Y) { return isBetterOverloadCandidate(SemaRef, X, Y, Loc, CandidateSet.getKind()); }); // Add the remaining viable overload candidates as code-completion results. for (OverloadCandidate &Candidate : CandidateSet) { if (Candidate.Function && Candidate.Function->isDeleted()) continue; if (Candidate.Viable) Results.push_back(ResultCandidate(Candidate.Function)); } } /// Get the type of the Nth parameter from a given set of overload /// candidates. static QualType getParamType(Sema &SemaRef, ArrayRef Candidates, unsigned N) { // Given the overloads 'Candidates' for a function call matching all arguments // up to N, return the type of the Nth parameter if it is the same for all // overload candidates. QualType ParamType; for (auto &Candidate : Candidates) { if (const auto *FType = Candidate.getFunctionType()) if (const auto *Proto = dyn_cast(FType)) if (N < Proto->getNumParams()) { if (ParamType.isNull()) ParamType = Proto->getParamType(N); else if (!SemaRef.Context.hasSameUnqualifiedType( ParamType.getNonReferenceType(), Proto->getParamType(N).getNonReferenceType())) // Otherwise return a default-constructed QualType. return QualType(); } } return ParamType; } static QualType ProduceSignatureHelp(Sema &SemaRef, Scope *S, MutableArrayRef Candidates, unsigned CurrentArg, SourceLocation OpenParLoc) { if (Candidates.empty()) return QualType(); SemaRef.CodeCompleter->ProcessOverloadCandidates( SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc); return getParamType(SemaRef, Candidates, CurrentArg); } QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn, ArrayRef Args, SourceLocation OpenParLoc) { if (!CodeCompleter) return QualType(); // FIXME: Provide support for variadic template functions. // Ignore type-dependent call expressions entirely. if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args) || Expr::hasAnyTypeDependentArguments(Args)) { return QualType(); } // Build an overload candidate set based on the functions we find. SourceLocation Loc = Fn->getExprLoc(); OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); SmallVector Results; Expr *NakedFn = Fn->IgnoreParenCasts(); if (auto ULE = dyn_cast(NakedFn)) AddOverloadedCallCandidates(ULE, Args, CandidateSet, /*PartialOverloading=*/true); else if (auto UME = dyn_cast(NakedFn)) { TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr; if (UME->hasExplicitTemplateArgs()) { UME->copyTemplateArgumentsInto(TemplateArgsBuffer); TemplateArgs = &TemplateArgsBuffer; } // Add the base as first argument (use a nullptr if the base is implicit). SmallVector ArgExprs( 1, UME->isImplicitAccess() ? nullptr : UME->getBase()); ArgExprs.append(Args.begin(), Args.end()); UnresolvedSet<8> Decls; Decls.append(UME->decls_begin(), UME->decls_end()); const bool FirstArgumentIsBase = !UME->isImplicitAccess() && UME->getBase(); AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs, /*SuppressUserConversions=*/false, /*PartialOverloading=*/true, FirstArgumentIsBase); } else { FunctionDecl *FD = nullptr; if (auto *MCE = dyn_cast(NakedFn)) FD = dyn_cast(MCE->getMemberDecl()); else if (auto *DRE = dyn_cast(NakedFn)) FD = dyn_cast(DRE->getDecl()); if (FD) { // We check whether it's a resolved function declaration. if (!getLangOpts().CPlusPlus || !FD->getType()->getAs()) Results.push_back(ResultCandidate(FD)); else AddOverloadCandidate(FD, DeclAccessPair::make(FD, FD->getAccess()), Args, CandidateSet, /*SuppressUserConversions=*/false, /*PartialOverloading=*/true); } else if (auto DC = NakedFn->getType()->getAsCXXRecordDecl()) { // If expression's type is CXXRecordDecl, it may overload the function // call operator, so we check if it does and add them as candidates. // A complete type is needed to lookup for member function call operators. if (isCompleteType(Loc, NakedFn->getType())) { DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); LookupResult R(*this, OpName, Loc, LookupOrdinaryName); LookupQualifiedName(R, DC); R.suppressDiagnostics(); SmallVector ArgExprs(1, NakedFn); ArgExprs.append(Args.begin(), Args.end()); AddFunctionCandidates(R.asUnresolvedSet(), ArgExprs, CandidateSet, /*ExplicitArgs=*/nullptr, /*SuppressUserConversions=*/false, /*PartialOverloading=*/true); } } else { // Lastly we check whether expression's type is function pointer or // function. QualType T = NakedFn->getType(); if (!T->getPointeeType().isNull()) T = T->getPointeeType(); if (auto FP = T->getAs()) { if (!TooManyArguments(FP->getNumParams(), Args.size(), /*PartialOverloading=*/true) || FP->isVariadic()) Results.push_back(ResultCandidate(FP)); } else if (auto FT = T->getAs()) // No prototype and declaration, it may be a K & R style function. Results.push_back(ResultCandidate(FT)); } } mergeCandidatesWithResults(*this, Results, CandidateSet, Loc); QualType ParamType = ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc); return !CandidateSet.empty() ? ParamType : QualType(); } QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type, SourceLocation Loc, ArrayRef Args, SourceLocation OpenParLoc) { if (!CodeCompleter) return QualType(); // A complete type is needed to lookup for constructors. CXXRecordDecl *RD = isCompleteType(Loc, Type) ? Type->getAsCXXRecordDecl() : nullptr; if (!RD) return Type; // FIXME: Provide support for member initializers. // FIXME: Provide support for variadic template constructors. OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); for (NamedDecl *C : LookupConstructors(RD)) { if (auto *FD = dyn_cast(C)) { AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args, CandidateSet, /*SuppressUserConversions=*/false, /*PartialOverloading=*/true, /*AllowExplicit*/ true); } else if (auto *FTD = dyn_cast(C)) { AddTemplateOverloadCandidate( FTD, DeclAccessPair::make(FTD, C->getAccess()), /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet, /*SuppressUserConversions=*/false, /*PartialOverloading=*/true); } } SmallVector Results; mergeCandidatesWithResults(*this, Results, CandidateSet, Loc); return ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc); } QualType Sema::ProduceCtorInitMemberSignatureHelp( Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, ArrayRef ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc) { if (!CodeCompleter) return QualType(); CXXConstructorDecl *Constructor = dyn_cast(ConstructorDecl); if (!Constructor) return QualType(); // FIXME: Add support for Base class constructors as well. if (ValueDecl *MemberDecl = tryLookupCtorInitMemberDecl( Constructor->getParent(), SS, TemplateTypeTy, II)) return ProduceConstructorSignatureHelp(getCurScope(), MemberDecl->getType(), MemberDecl->getLocation(), ArgExprs, OpenParLoc); return QualType(); } void Sema::CodeCompleteDesignator(const QualType BaseType, llvm::ArrayRef InitExprs, const Designation &D) { if (BaseType.isNull()) return; // FIXME: Handle nested designations, e.g. : .x.^ if (!D.empty()) return; const auto *RD = getAsRecordDecl(BaseType); if (!RD) return; if (const auto *CTSD = llvm::dyn_cast(RD)) { // Template might not be instantiated yet, fall back to primary template in // such cases. if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared) RD = CTSD->getSpecializedTemplate()->getTemplatedDecl(); } if (RD->fields().empty()) return; CodeCompletionContext CCC(CodeCompletionContext::CCC_DotMemberAccess, BaseType); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CCC); Results.EnterNewScope(); for (const auto *FD : RD->fields()) { // FIXME: Make use of previous designators to mark any fields before those // inaccessible, and also compute the next initializer priority. ResultBuilder::Result Result(FD, Results.getBasePriority(FD)); Results.AddResult(Result, CurContext, /*Hiding=*/nullptr); } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteInitializer(Scope *S, Decl *D) { ValueDecl *VD = dyn_cast_or_null(D); if (!VD) { CodeCompleteOrdinaryName(S, PCC_Expression); return; } CodeCompleteExpressionData Data; Data.PreferredType = VD->getType(); // Ignore VD to avoid completing the variable itself, e.g. in 'int foo = ^'. Data.IgnoreDecls.push_back(VD); CodeCompleteExpression(S, Data); } -void Sema::CodeCompleteAfterIf(Scope *S) { +void Sema::CodeCompleteAfterIf(Scope *S, bool IsBracedThen) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), mapCodeCompletionContext(*this, PCC_Statement)); Results.setFilter(&ResultBuilder::IsOrdinaryName); Results.EnterNewScope(); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); AddOrdinaryNameResults(PCC_Statement, S, *this, Results); // "else" block CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); + + auto AddElseBodyPattern = [&] { + if (IsBracedThen) { + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + } else { + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("statement"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); + } + }; Builder.AddTypedTextChunk("else"); - if (Results.includeCodePatterns()) { - Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); - Builder.AddChunk(CodeCompletionString::CK_LeftBrace); - Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); - Builder.AddPlaceholderChunk("statements"); - Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); - Builder.AddChunk(CodeCompletionString::CK_RightBrace); - } + if (Results.includeCodePatterns()) + AddElseBodyPattern(); Results.AddResult(Builder.TakeString()); // "else if" block Builder.AddTypedTextChunk("else if"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (getLangOpts().CPlusPlus) Builder.AddPlaceholderChunk("condition"); else Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); if (Results.includeCodePatterns()) { - Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); - Builder.AddChunk(CodeCompletionString::CK_LeftBrace); - Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); - Builder.AddPlaceholderChunk("statements"); - Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); - Builder.AddChunk(CodeCompletionString::CK_RightBrace); + AddElseBodyPattern(); } Results.AddResult(Builder.TakeString()); Results.ExitScope(); if (S->getFnParent()) AddPrettyFunctionResults(getLangOpts(), Results); if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, CodeCompleter->loadExternal(), false); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext, bool IsUsingDeclaration, QualType BaseType, QualType PreferredType) { if (SS.isEmpty() || !CodeCompleter) return; CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol, PreferredType); CC.setIsUsingDeclaration(IsUsingDeclaration); CC.setCXXScopeSpecifier(SS); // We want to keep the scope specifier even if it's invalid (e.g. the scope // "a::b::" is not corresponding to any context/namespace in the AST), since // it can be useful for global code completion which have information about // contexts/symbols that are not in the AST. if (SS.isInvalid()) { // As SS is invalid, we try to collect accessible contexts from the current // scope with a dummy lookup so that the completion consumer can try to // guess what the specified scope is. ResultBuilder DummyResults(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CC); if (!PreferredType.isNull()) DummyResults.setPreferredType(PreferredType); if (S->getEntity()) { CodeCompletionDeclConsumer Consumer(DummyResults, S->getEntity(), BaseType); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, /*IncludeGlobalScope=*/false, /*LoadExternal=*/false); } HandleCodeCompleteResults(this, CodeCompleter, DummyResults.getCompletionContext(), nullptr, 0); return; } // Always pretend to enter a context to ensure that a dependent type // resolves to a dependent record. DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true); // Try to instantiate any non-dependent declaration contexts before // we look in them. Bail out if we fail. NestedNameSpecifier *NNS = SS.getScopeRep(); if (NNS != nullptr && SS.isValid() && !NNS->isDependent()) { if (Ctx == nullptr || RequireCompleteDeclContext(SS, Ctx)) return; } ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CC); if (!PreferredType.isNull()) Results.setPreferredType(PreferredType); Results.EnterNewScope(); // The "template" keyword can follow "::" in the grammar, but only // put it into the grammar if the nested-name-specifier is dependent. // FIXME: results is always empty, this appears to be dead. if (!Results.empty() && NNS->isDependent()) Results.AddResult("template"); // If the scope is a concept-constrained type parameter, infer nested // members based on the constraints. if (const auto *TTPT = dyn_cast_or_null(NNS->getAsType())) { for (const auto &R : ConceptInfo(*TTPT, S).members()) { if (R.Operator != ConceptInfo::Member::Colons) continue; Results.AddResult(CodeCompletionResult( R.render(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo()))); } } // Add calls to overridden virtual functions, if there are any. // // FIXME: This isn't wonderful, because we don't know whether we're actually // in a context that permits expressions. This is a general issue with // qualified-id completions. if (Ctx && !EnteringContext) MaybeAddOverrideCalls(*this, Ctx, Results); Results.ExitScope(); if (Ctx && (CodeCompleter->includeNamespaceLevelDecls() || !Ctx->isFileContext())) { CodeCompletionDeclConsumer Consumer(Results, Ctx, BaseType); LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer, /*IncludeGlobalScope=*/true, /*IncludeDependentBases=*/true, CodeCompleter->loadExternal()); } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteUsing(Scope *S) { if (!CodeCompleter) return; // This can be both a using alias or using declaration, in the former we // expect a new name and a symbol in the latter case. CodeCompletionContext Context(CodeCompletionContext::CCC_SymbolOrNewName); Context.setIsUsingDeclaration(true); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), Context, &ResultBuilder::IsNestedNameSpecifier); Results.EnterNewScope(); // If we aren't in class scope, we could see the "namespace" keyword. if (!S->isClassScope()) Results.AddResult(CodeCompletionResult("namespace")); // After "using", we can see anything that would start a // nested-name-specifier. CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteUsingDirective(Scope *S) { if (!CodeCompleter) return; // After "using namespace", we expect to see a namespace name or namespace // alias. ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Namespace, &ResultBuilder::IsNamespaceOrAlias); Results.EnterNewScope(); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteNamespaceDecl(Scope *S) { if (!CodeCompleter) return; DeclContext *Ctx = S->getEntity(); if (!S->getParent()) Ctx = Context.getTranslationUnitDecl(); bool SuppressedGlobalResults = Ctx && !CodeCompleter->includeGlobals() && isa(Ctx); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), SuppressedGlobalResults ? CodeCompletionContext::CCC_Namespace : CodeCompletionContext::CCC_Other, &ResultBuilder::IsNamespace); if (Ctx && Ctx->isFileContext() && !SuppressedGlobalResults) { // We only want to see those namespaces that have already been defined // within this scope, because its likely that the user is creating an // extended namespace declaration. Keep track of the most recent // definition of each namespace. std::map OrigToLatest; for (DeclContext::specific_decl_iterator NS(Ctx->decls_begin()), NSEnd(Ctx->decls_end()); NS != NSEnd; ++NS) OrigToLatest[NS->getOriginalNamespace()] = *NS; // Add the most recent definition (or extended definition) of each // namespace to the list of results. Results.EnterNewScope(); for (std::map::iterator NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end(); NS != NSEnd; ++NS) Results.AddResult( CodeCompletionResult(NS->second, Results.getBasePriority(NS->second), nullptr), CurContext, nullptr, false); Results.ExitScope(); } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { if (!CodeCompleter) return; // After "namespace", we expect to see a namespace or alias. ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Namespace, &ResultBuilder::IsNamespaceOrAlias); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteOperatorName(Scope *S) { if (!CodeCompleter) return; typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Type, &ResultBuilder::IsType); Results.EnterNewScope(); // Add the names of overloadable operators. Note that OO_Conditional is not // actually overloadable. #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \ if (OO_##Name != OO_Conditional) \ Results.AddResult(Result(Spelling)); #include "clang/Basic/OperatorKinds.def" // Add any type names visible from the current scope Results.allowNestedNameSpecifiers(); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); // Add any type specifiers AddTypeSpecifierResults(getLangOpts(), Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteConstructorInitializer( Decl *ConstructorD, ArrayRef Initializers) { if (!ConstructorD) return; AdjustDeclIfTemplate(ConstructorD); auto *Constructor = dyn_cast(ConstructorD); if (!Constructor) return; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Symbol); Results.EnterNewScope(); // Fill in any already-initialized fields or base classes. llvm::SmallPtrSet InitializedFields; llvm::SmallPtrSet InitializedBases; for (unsigned I = 0, E = Initializers.size(); I != E; ++I) { if (Initializers[I]->isBaseInitializer()) InitializedBases.insert(Context.getCanonicalType( QualType(Initializers[I]->getBaseClass(), 0))); else InitializedFields.insert( cast(Initializers[I]->getAnyMember())); } // Add completions for base classes. PrintingPolicy Policy = getCompletionPrintingPolicy(*this); bool SawLastInitializer = Initializers.empty(); CXXRecordDecl *ClassDecl = Constructor->getParent(); auto GenerateCCS = [&](const NamedDecl *ND, const char *Name) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Builder.AddTypedTextChunk(Name); Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (const auto *Function = dyn_cast(ND)) AddFunctionParameterChunks(PP, Policy, Function, Builder); else if (const auto *FunTemplDecl = dyn_cast(ND)) AddFunctionParameterChunks(PP, Policy, FunTemplDecl->getTemplatedDecl(), Builder); Builder.AddChunk(CodeCompletionString::CK_RightParen); return Builder.TakeString(); }; auto AddDefaultCtorInit = [&](const char *Name, const char *Type, const NamedDecl *ND) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Builder.AddTypedTextChunk(Name); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk(Type); Builder.AddChunk(CodeCompletionString::CK_RightParen); if (ND) { auto CCR = CodeCompletionResult( Builder.TakeString(), ND, SawLastInitializer ? CCP_NextInitializer : CCP_MemberDeclaration); if (isa(ND)) CCR.CursorKind = CXCursor_MemberRef; return Results.AddResult(CCR); } return Results.AddResult(CodeCompletionResult( Builder.TakeString(), SawLastInitializer ? CCP_NextInitializer : CCP_MemberDeclaration)); }; auto AddCtorsWithName = [&](const CXXRecordDecl *RD, unsigned int Priority, const char *Name, const FieldDecl *FD) { if (!RD) return AddDefaultCtorInit(Name, FD ? Results.getAllocator().CopyString( FD->getType().getAsString(Policy)) : Name, FD); auto Ctors = getConstructors(Context, RD); if (Ctors.begin() == Ctors.end()) return AddDefaultCtorInit(Name, Name, RD); for (const NamedDecl *Ctor : Ctors) { auto CCR = CodeCompletionResult(GenerateCCS(Ctor, Name), RD, Priority); CCR.CursorKind = getCursorKindForDecl(Ctor); Results.AddResult(CCR); } }; auto AddBase = [&](const CXXBaseSpecifier &Base) { const char *BaseName = Results.getAllocator().CopyString(Base.getType().getAsString(Policy)); const auto *RD = Base.getType()->getAsCXXRecordDecl(); AddCtorsWithName( RD, SawLastInitializer ? CCP_NextInitializer : CCP_MemberDeclaration, BaseName, nullptr); }; auto AddField = [&](const FieldDecl *FD) { const char *FieldName = Results.getAllocator().CopyString(FD->getIdentifier()->getName()); const CXXRecordDecl *RD = FD->getType()->getAsCXXRecordDecl(); AddCtorsWithName( RD, SawLastInitializer ? CCP_NextInitializer : CCP_MemberDeclaration, FieldName, FD); }; for (const auto &Base : ClassDecl->bases()) { if (!InitializedBases.insert(Context.getCanonicalType(Base.getType())) .second) { SawLastInitializer = !Initializers.empty() && Initializers.back()->isBaseInitializer() && Context.hasSameUnqualifiedType( Base.getType(), QualType(Initializers.back()->getBaseClass(), 0)); continue; } AddBase(Base); SawLastInitializer = false; } // Add completions for virtual base classes. for (const auto &Base : ClassDecl->vbases()) { if (!InitializedBases.insert(Context.getCanonicalType(Base.getType())) .second) { SawLastInitializer = !Initializers.empty() && Initializers.back()->isBaseInitializer() && Context.hasSameUnqualifiedType( Base.getType(), QualType(Initializers.back()->getBaseClass(), 0)); continue; } AddBase(Base); SawLastInitializer = false; } // Add completions for members. for (auto *Field : ClassDecl->fields()) { if (!InitializedFields.insert(cast(Field->getCanonicalDecl())) .second) { SawLastInitializer = !Initializers.empty() && Initializers.back()->isAnyMemberInitializer() && Initializers.back()->getAnyMember() == Field; continue; } if (!Field->getDeclName()) continue; AddField(Field); SawLastInitializer = false; } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } /// Determine whether this scope denotes a namespace. static bool isNamespaceScope(Scope *S) { DeclContext *DC = S->getEntity(); if (!DC) return false; return DC->isFileContext(); } void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, bool AfterAmpersand) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); // Note what has already been captured. llvm::SmallPtrSet Known; bool IncludedThis = false; for (const auto &C : Intro.Captures) { if (C.Kind == LCK_This) { IncludedThis = true; continue; } Known.insert(C.Id); } // Look for other capturable variables. for (; S && !isNamespaceScope(S); S = S->getParent()) { for (const auto *D : S->decls()) { const auto *Var = dyn_cast(D); if (!Var || !Var->hasLocalStorage() || Var->hasAttr()) continue; if (Known.insert(Var->getIdentifier()).second) Results.AddResult(CodeCompletionResult(Var, CCP_LocalDeclaration), CurContext, nullptr, false); } } // Add 'this', if it would be valid. if (!IncludedThis && !AfterAmpersand && Intro.Default != LCD_ByCopy) addThisCompletion(*this, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } /// Macro that optionally prepends an "@" to the string literal passed in via /// Keyword, depending on whether NeedAt is true or false. #define OBJC_AT_KEYWORD_NAME(NeedAt, Keyword) ((NeedAt) ? "@" Keyword : Keyword) static void AddObjCImplementationResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; // Since we have an implementation, we can end it. Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "end"))); CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); if (LangOpts.ObjC) { // @dynamic Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "dynamic")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("property"); Results.AddResult(Result(Builder.TakeString())); // @synthesize Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "synthesize")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("property"); Results.AddResult(Result(Builder.TakeString())); } } static void AddObjCInterfaceResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; // Since we have an interface or protocol, we can end it. Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "end"))); if (LangOpts.ObjC) { // @property Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "property"))); // @required Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "required"))); // @optional Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "optional"))); } } static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); // @class name ; Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "class")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("name"); Results.AddResult(Result(Builder.TakeString())); if (Results.includeCodePatterns()) { // @interface name // FIXME: Could introduce the whole pattern, including superclasses and // such. Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "interface")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("class"); Results.AddResult(Result(Builder.TakeString())); // @protocol name Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "protocol")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("protocol"); Results.AddResult(Result(Builder.TakeString())); // @implementation name Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "implementation")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("class"); Results.AddResult(Result(Builder.TakeString())); } // @compatibility_alias name Builder.AddTypedTextChunk( OBJC_AT_KEYWORD_NAME(NeedAt, "compatibility_alias")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("alias"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("class"); Results.AddResult(Result(Builder.TakeString())); if (Results.getSema().getLangOpts().Modules) { // @import name Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "import")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("module"); Results.AddResult(Result(Builder.TakeString())); } } void Sema::CodeCompleteObjCAtDirective(Scope *S) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); if (isa(CurContext)) AddObjCImplementationResults(getLangOpts(), Results, false); else if (CurContext->isObjCContainer()) AddObjCInterfaceResults(getLangOpts(), Results, false); else AddObjCTopLevelResults(Results, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); // @encode ( type-name ) const char *EncodeType = "char[]"; if (Results.getSema().getLangOpts().CPlusPlus || Results.getSema().getLangOpts().ConstStrings) EncodeType = "const char[]"; Builder.AddResultTypeChunk(EncodeType); Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "encode")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("type-name"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); // @protocol ( protocol-name ) Builder.AddResultTypeChunk("Protocol *"); Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "protocol")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("protocol-name"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); // @selector ( selector ) Builder.AddResultTypeChunk("SEL"); Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "selector")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("selector"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); // @"string" Builder.AddResultTypeChunk("NSString *"); Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "\"")); Builder.AddPlaceholderChunk("string"); Builder.AddTextChunk("\""); Results.AddResult(Result(Builder.TakeString())); // @[objects, ...] Builder.AddResultTypeChunk("NSArray *"); Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "[")); Builder.AddPlaceholderChunk("objects, ..."); Builder.AddChunk(CodeCompletionString::CK_RightBracket); Results.AddResult(Result(Builder.TakeString())); // @{key : object, ...} Builder.AddResultTypeChunk("NSDictionary *"); Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "{")); Builder.AddPlaceholderChunk("key"); Builder.AddChunk(CodeCompletionString::CK_Colon); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("object, ..."); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); // @(expression) Builder.AddResultTypeChunk("id"); Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "(")); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); } static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); if (Results.includeCodePatterns()) { // @try { statements } @catch ( declaration ) { statements } @finally // { statements } Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "try")); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Builder.AddTextChunk("@catch"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("parameter"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Builder.AddTextChunk("@finally"); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); } // @throw Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "throw")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); if (Results.includeCodePatterns()) { // @synchronized ( expression ) { statements } Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "synchronized")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); } } static void AddObjCVisibilityResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "private"))); Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "protected"))); Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "public"))); if (LangOpts.ObjC) Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt, "package"))); } void Sema::CodeCompleteObjCAtVisibility(Scope *S) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); AddObjCVisibilityResults(getLangOpts(), Results, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCAtStatement(Scope *S) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); AddObjCStatementResults(Results, false); AddObjCExpressionResults(Results, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCAtExpression(Scope *S) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); AddObjCExpressionResults(Results, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } /// Determine whether the addition of the given flag to an Objective-C /// property's attributes will cause a conflict. static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) { // Check if we've already added this flag. if (Attributes & NewFlag) return true; Attributes |= NewFlag; // Check for collisions with "readonly". if ((Attributes & ObjCPropertyAttribute::kind_readonly) && (Attributes & ObjCPropertyAttribute::kind_readwrite)) return true; // Check for more than one of { assign, copy, retain, strong, weak }. unsigned AssignCopyRetMask = Attributes & (ObjCPropertyAttribute::kind_assign | ObjCPropertyAttribute::kind_unsafe_unretained | ObjCPropertyAttribute::kind_copy | ObjCPropertyAttribute::kind_retain | ObjCPropertyAttribute::kind_strong | ObjCPropertyAttribute::kind_weak); if (AssignCopyRetMask && AssignCopyRetMask != ObjCPropertyAttribute::kind_assign && AssignCopyRetMask != ObjCPropertyAttribute::kind_unsafe_unretained && AssignCopyRetMask != ObjCPropertyAttribute::kind_copy && AssignCopyRetMask != ObjCPropertyAttribute::kind_retain && AssignCopyRetMask != ObjCPropertyAttribute::kind_strong && AssignCopyRetMask != ObjCPropertyAttribute::kind_weak) return true; return false; } void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { if (!CodeCompleter) return; unsigned Attributes = ODS.getPropertyAttributes(); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_readonly)) Results.AddResult(CodeCompletionResult("readonly")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_assign)) Results.AddResult(CodeCompletionResult("assign")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_unsafe_unretained)) Results.AddResult(CodeCompletionResult("unsafe_unretained")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_readwrite)) Results.AddResult(CodeCompletionResult("readwrite")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_retain)) Results.AddResult(CodeCompletionResult("retain")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_strong)) Results.AddResult(CodeCompletionResult("strong")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_copy)) Results.AddResult(CodeCompletionResult("copy")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_nonatomic)) Results.AddResult(CodeCompletionResult("nonatomic")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_atomic)) Results.AddResult(CodeCompletionResult("atomic")); // Only suggest "weak" if we're compiling for ARC-with-weak-references or GC. if (getLangOpts().ObjCWeak || getLangOpts().getGC() != LangOptions::NonGC) if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_weak)) Results.AddResult(CodeCompletionResult("weak")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_setter)) { CodeCompletionBuilder Setter(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Setter.AddTypedTextChunk("setter"); Setter.AddTextChunk("="); Setter.AddPlaceholderChunk("method"); Results.AddResult(CodeCompletionResult(Setter.TakeString())); } if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_getter)) { CodeCompletionBuilder Getter(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Getter.AddTypedTextChunk("getter"); Getter.AddTextChunk("="); Getter.AddPlaceholderChunk("method"); Results.AddResult(CodeCompletionResult(Getter.TakeString())); } if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_nullability)) { Results.AddResult(CodeCompletionResult("nonnull")); Results.AddResult(CodeCompletionResult("nullable")); Results.AddResult(CodeCompletionResult("null_unspecified")); Results.AddResult(CodeCompletionResult("null_resettable")); } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } /// Describes the kind of Objective-C method that we want to find /// via code completion. enum ObjCMethodKind { MK_Any, ///< Any kind of method, provided it means other specified criteria. MK_ZeroArgSelector, ///< Zero-argument (unary) selector. MK_OneArgSelector ///< One-argument selector. }; static bool isAcceptableObjCSelector(Selector Sel, ObjCMethodKind WantKind, ArrayRef SelIdents, bool AllowSameLength = true) { unsigned NumSelIdents = SelIdents.size(); if (NumSelIdents > Sel.getNumArgs()) return false; switch (WantKind) { case MK_Any: break; case MK_ZeroArgSelector: return Sel.isUnarySelector(); case MK_OneArgSelector: return Sel.getNumArgs() == 1; } if (!AllowSameLength && NumSelIdents && NumSelIdents == Sel.getNumArgs()) return false; for (unsigned I = 0; I != NumSelIdents; ++I) if (SelIdents[I] != Sel.getIdentifierInfoForSlot(I)) return false; return true; } static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, ObjCMethodKind WantKind, ArrayRef SelIdents, bool AllowSameLength = true) { return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents, AllowSameLength); } /// A set of selectors, which is used to avoid introducing multiple /// completions with the same selector into the result set. typedef llvm::SmallPtrSet VisitedSelectorSet; /// Add all of the Objective-C methods in the given Objective-C /// container to the set of results. /// /// The container will be a class, protocol, category, or implementation of /// any of the above. This mether will recurse to include methods from /// the superclasses of classes along with their categories, protocols, and /// implementations. /// /// \param Container the container in which we'll look to find methods. /// /// \param WantInstanceMethods Whether to add instance methods (only); if /// false, this routine will add factory methods (only). /// /// \param CurContext the context in which we're performing the lookup that /// finds methods. /// /// \param AllowSameLength Whether we allow a method to be added to the list /// when it has the same number of parameters as we have selector identifiers. /// /// \param Results the structure into which we'll add results. static void AddObjCMethods(ObjCContainerDecl *Container, bool WantInstanceMethods, ObjCMethodKind WantKind, ArrayRef SelIdents, DeclContext *CurContext, VisitedSelectorSet &Selectors, bool AllowSameLength, ResultBuilder &Results, bool InOriginalClass = true, bool IsRootClass = false) { typedef CodeCompletionResult Result; Container = getContainerDef(Container); ObjCInterfaceDecl *IFace = dyn_cast(Container); IsRootClass = IsRootClass || (IFace && !IFace->getSuperClass()); for (ObjCMethodDecl *M : Container->methods()) { // The instance methods on the root class can be messaged via the // metaclass. if (M->isInstanceMethod() == WantInstanceMethods || (IsRootClass && !WantInstanceMethods)) { // Check whether the selector identifiers we've been given are a // subset of the identifiers for this particular method. if (!isAcceptableObjCMethod(M, WantKind, SelIdents, AllowSameLength)) continue; if (!Selectors.insert(M->getSelector()).second) continue; Result R = Result(M, Results.getBasePriority(M), nullptr); R.StartParameter = SelIdents.size(); R.AllParametersAreInformative = (WantKind != MK_Any); if (!InOriginalClass) setInBaseClass(R); Results.MaybeAddResult(R, CurContext); } } // Visit the protocols of protocols. if (const auto *Protocol = dyn_cast(Container)) { if (Protocol->hasDefinition()) { const ObjCList &Protocols = Protocol->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, false, IsRootClass); } } if (!IFace || !IFace->hasDefinition()) return; // Add methods in protocols. for (ObjCProtocolDecl *I : IFace->protocols()) AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, false, IsRootClass); // Add methods in categories. for (ObjCCategoryDecl *CatDecl : IFace->known_categories()) { AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, InOriginalClass, IsRootClass); // Add a categories protocol methods. const ObjCList &Protocols = CatDecl->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, false, IsRootClass); // Add methods in category implementations. if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation()) AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, InOriginalClass, IsRootClass); } // Add methods in superclass. // Avoid passing in IsRootClass since root classes won't have super classes. if (IFace->getSuperClass()) AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, /*IsRootClass=*/false); // Add methods in our implementation, if any. if (ObjCImplementationDecl *Impl = IFace->getImplementation()) AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, InOriginalClass, IsRootClass); } void Sema::CodeCompleteObjCPropertyGetter(Scope *S) { // Try to find the interface where getters might live. ObjCInterfaceDecl *Class = dyn_cast_or_null(CurContext); if (!Class) { if (ObjCCategoryDecl *Category = dyn_cast_or_null(CurContext)) Class = Category->getClassInterface(); if (!Class) return; } // Find all of the potential getters. ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); VisitedSelectorSet Selectors; AddObjCMethods(Class, true, MK_ZeroArgSelector, None, CurContext, Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCPropertySetter(Scope *S) { // Try to find the interface where setters might live. ObjCInterfaceDecl *Class = dyn_cast_or_null(CurContext); if (!Class) { if (ObjCCategoryDecl *Category = dyn_cast_or_null(CurContext)) Class = Category->getClassInterface(); if (!Class) return; } // Find all of the potential getters. ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); VisitedSelectorSet Selectors; AddObjCMethods(Class, true, MK_OneArgSelector, None, CurContext, Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, bool IsParameter) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Type); Results.EnterNewScope(); // Add context-sensitive, Objective-C parameter-passing keywords. bool AddedInOut = false; if ((DS.getObjCDeclQualifier() & (ObjCDeclSpec::DQ_In | ObjCDeclSpec::DQ_Inout)) == 0) { Results.AddResult("in"); Results.AddResult("inout"); AddedInOut = true; } if ((DS.getObjCDeclQualifier() & (ObjCDeclSpec::DQ_Out | ObjCDeclSpec::DQ_Inout)) == 0) { Results.AddResult("out"); if (!AddedInOut) Results.AddResult("inout"); } if ((DS.getObjCDeclQualifier() & (ObjCDeclSpec::DQ_Bycopy | ObjCDeclSpec::DQ_Byref | ObjCDeclSpec::DQ_Oneway)) == 0) { Results.AddResult("bycopy"); Results.AddResult("byref"); Results.AddResult("oneway"); } if ((DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability) == 0) { Results.AddResult("nonnull"); Results.AddResult("nullable"); Results.AddResult("null_unspecified"); } // If we're completing the return type of an Objective-C method and the // identifier IBAction refers to a macro, provide a completion item for // an action, e.g., // IBAction)<#selector#>:(id)sender if (DS.getObjCDeclQualifier() == 0 && !IsParameter && PP.isMacroDefined("IBAction")) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo(), CCP_CodePattern, CXAvailability_Available); Builder.AddTypedTextChunk("IBAction"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddPlaceholderChunk("selector"); Builder.AddChunk(CodeCompletionString::CK_Colon); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("id"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("sender"); Results.AddResult(CodeCompletionResult(Builder.TakeString())); } // If we're completing the return type, provide 'instancetype'. if (!IsParameter) { Results.AddResult(CodeCompletionResult("instancetype")); } // Add various builtin type names and specifiers. AddOrdinaryNameResults(PCC_Type, S, *this, Results); Results.ExitScope(); // Add the various type names Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, CodeCompleter->loadExternal(), false); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } /// When we have an expression with type "id", we may assume /// that it has some more-specific class type based on knowledge of /// common uses of Objective-C. This routine returns that class type, /// or NULL if no better result could be determined. static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { auto *Msg = dyn_cast_or_null(E); if (!Msg) return nullptr; Selector Sel = Msg->getSelector(); if (Sel.isNull()) return nullptr; IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0); if (!Id) return nullptr; ObjCMethodDecl *Method = Msg->getMethodDecl(); if (!Method) return nullptr; // Determine the class that we're sending the message to. ObjCInterfaceDecl *IFace = nullptr; switch (Msg->getReceiverKind()) { case ObjCMessageExpr::Class: if (const ObjCObjectType *ObjType = Msg->getClassReceiver()->getAs()) IFace = ObjType->getInterface(); break; case ObjCMessageExpr::Instance: { QualType T = Msg->getInstanceReceiver()->getType(); if (const ObjCObjectPointerType *Ptr = T->getAs()) IFace = Ptr->getInterfaceDecl(); break; } case ObjCMessageExpr::SuperInstance: case ObjCMessageExpr::SuperClass: break; } if (!IFace) return nullptr; ObjCInterfaceDecl *Super = IFace->getSuperClass(); if (Method->isInstanceMethod()) return llvm::StringSwitch(Id->getName()) .Case("retain", IFace) .Case("strong", IFace) .Case("autorelease", IFace) .Case("copy", IFace) .Case("copyWithZone", IFace) .Case("mutableCopy", IFace) .Case("mutableCopyWithZone", IFace) .Case("awakeFromCoder", IFace) .Case("replacementObjectFromCoder", IFace) .Case("class", IFace) .Case("classForCoder", IFace) .Case("superclass", Super) .Default(nullptr); return llvm::StringSwitch(Id->getName()) .Case("new", IFace) .Case("alloc", IFace) .Case("allocWithZone", IFace) .Case("class", IFace) .Case("superclass", Super) .Default(nullptr); } // Add a special completion for a message send to "super", which fills in the // most likely case of forwarding all of our arguments to the superclass // function. /// /// \param S The semantic analysis object. /// /// \param NeedSuperKeyword Whether we need to prefix this completion with /// the "super" keyword. Otherwise, we just need to provide the arguments. /// /// \param SelIdents The identifiers in the selector that have already been /// provided as arguments for a send to "super". /// /// \param Results The set of results to augment. /// /// \returns the Objective-C method declaration that would be invoked by /// this "super" completion. If NULL, no completion was added. static ObjCMethodDecl * AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword, ArrayRef SelIdents, ResultBuilder &Results) { ObjCMethodDecl *CurMethod = S.getCurMethodDecl(); if (!CurMethod) return nullptr; ObjCInterfaceDecl *Class = CurMethod->getClassInterface(); if (!Class) return nullptr; // Try to find a superclass method with the same selector. ObjCMethodDecl *SuperMethod = nullptr; while ((Class = Class->getSuperClass()) && !SuperMethod) { // Check in the class SuperMethod = Class->getMethod(CurMethod->getSelector(), CurMethod->isInstanceMethod()); // Check in categories or class extensions. if (!SuperMethod) { for (const auto *Cat : Class->known_categories()) { if ((SuperMethod = Cat->getMethod(CurMethod->getSelector(), CurMethod->isInstanceMethod()))) break; } } } if (!SuperMethod) return nullptr; // Check whether the superclass method has the same signature. if (CurMethod->param_size() != SuperMethod->param_size() || CurMethod->isVariadic() != SuperMethod->isVariadic()) return nullptr; for (ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin(), CurPEnd = CurMethod->param_end(), SuperP = SuperMethod->param_begin(); CurP != CurPEnd; ++CurP, ++SuperP) { // Make sure the parameter types are compatible. if (!S.Context.hasSameUnqualifiedType((*CurP)->getType(), (*SuperP)->getType())) return nullptr; // Make sure we have a parameter name to forward! if (!(*CurP)->getIdentifier()) return nullptr; } // We have a superclass method. Now, form the send-to-super completion. CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); // Give this completion a return type. AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod, Results.getCompletionContext().getBaseType(), Builder); // If we need the "super" keyword, add it (plus some spacing). if (NeedSuperKeyword) { Builder.AddTypedTextChunk("super"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); } Selector Sel = CurMethod->getSelector(); if (Sel.isUnarySelector()) { if (NeedSuperKeyword) Builder.AddTextChunk( Builder.getAllocator().CopyString(Sel.getNameForSlot(0))); else Builder.AddTypedTextChunk( Builder.getAllocator().CopyString(Sel.getNameForSlot(0))); } else { ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin(); for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I, ++CurP) { if (I > SelIdents.size()) Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); if (I < SelIdents.size()) Builder.AddInformativeChunk( Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":")); else if (NeedSuperKeyword || I > SelIdents.size()) { Builder.AddTextChunk( Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":")); Builder.AddPlaceholderChunk(Builder.getAllocator().CopyString( (*CurP)->getIdentifier()->getName())); } else { Builder.AddTypedTextChunk( Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":")); Builder.AddPlaceholderChunk(Builder.getAllocator().CopyString( (*CurP)->getIdentifier()->getName())); } } } Results.AddResult(CodeCompletionResult(Builder.TakeString(), SuperMethod, CCP_SuperCompletion)); return SuperMethod; } void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { typedef CodeCompletionResult Result; ResultBuilder Results( *this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCMessageReceiver, getLangOpts().CPlusPlus11 ? &ResultBuilder::IsObjCMessageReceiverOrLambdaCapture : &ResultBuilder::IsObjCMessageReceiver); CodeCompletionDeclConsumer Consumer(Results, CurContext); Results.EnterNewScope(); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, CodeCompleter->includeGlobals(), CodeCompleter->loadExternal()); // If we are in an Objective-C method inside a class that has a superclass, // add "super" as an option. if (ObjCMethodDecl *Method = getCurMethodDecl()) if (ObjCInterfaceDecl *Iface = Method->getClassInterface()) if (Iface->getSuperClass()) { Results.AddResult(Result("super")); AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, None, Results); } if (getLangOpts().CPlusPlus11) addThisCompletion(*this, Results); Results.ExitScope(); if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, CodeCompleter->loadExternal(), false); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, ArrayRef SelIdents, bool AtArgumentExpression) { ObjCInterfaceDecl *CDecl = nullptr; if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { // Figure out which interface we're in. CDecl = CurMethod->getClassInterface(); if (!CDecl) return; // Find the superclass of this class. CDecl = CDecl->getSuperClass(); if (!CDecl) return; if (CurMethod->isInstanceMethod()) { // We are inside an instance method, which means that the message // send [super ...] is actually calling an instance method on the // current object. return CodeCompleteObjCInstanceMessage(S, nullptr, SelIdents, AtArgumentExpression, CDecl); } // Fall through to send to the superclass in CDecl. } else { // "super" may be the name of a type or variable. Figure out which // it is. IdentifierInfo *Super = getSuperIdentifier(); NamedDecl *ND = LookupSingleName(S, Super, SuperLoc, LookupOrdinaryName); if ((CDecl = dyn_cast_or_null(ND))) { // "super" names an interface. Use it. } else if (TypeDecl *TD = dyn_cast_or_null(ND)) { if (const ObjCObjectType *Iface = Context.getTypeDeclType(TD)->getAs()) CDecl = Iface->getInterface(); } else if (ND && isa(ND)) { // "super" names an unresolved type; we can't be more specific. } else { // Assume that "super" names some kind of value and parse that way. CXXScopeSpec SS; SourceLocation TemplateKWLoc; UnqualifiedId id; id.setIdentifier(Super, SuperLoc); ExprResult SuperExpr = ActOnIdExpression(S, SS, TemplateKWLoc, id, /*HasTrailingLParen=*/false, /*IsAddressOfOperand=*/false); return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(), SelIdents, AtArgumentExpression); } // Fall through } ParsedType Receiver; if (CDecl) Receiver = ParsedType::make(Context.getObjCInterfaceType(CDecl)); return CodeCompleteObjCClassMessage(S, Receiver, SelIdents, AtArgumentExpression, /*IsSuper=*/true); } /// Given a set of code-completion results for the argument of a message /// send, determine the preferred type (if any) for that argument expression. static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results, unsigned NumSelIdents) { typedef CodeCompletionResult Result; ASTContext &Context = Results.getSema().Context; QualType PreferredType; unsigned BestPriority = CCP_Unlikely * 2; Result *ResultsData = Results.data(); for (unsigned I = 0, N = Results.size(); I != N; ++I) { Result &R = ResultsData[I]; if (R.Kind == Result::RK_Declaration && isa(R.Declaration)) { if (R.Priority <= BestPriority) { const ObjCMethodDecl *Method = cast(R.Declaration); if (NumSelIdents <= Method->param_size()) { QualType MyPreferredType = Method->parameters()[NumSelIdents - 1]->getType(); if (R.Priority < BestPriority || PreferredType.isNull()) { BestPriority = R.Priority; PreferredType = MyPreferredType; } else if (!Context.hasSameUnqualifiedType(PreferredType, MyPreferredType)) { PreferredType = QualType(); } } } } } return PreferredType; } static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper, ResultBuilder &Results) { typedef CodeCompletionResult Result; ObjCInterfaceDecl *CDecl = nullptr; // If the given name refers to an interface type, retrieve the // corresponding declaration. if (Receiver) { QualType T = SemaRef.GetTypeFromParser(Receiver, nullptr); if (!T.isNull()) if (const ObjCObjectType *Interface = T->getAs()) CDecl = Interface->getInterface(); } // Add all of the factory methods in this Objective-C class, its protocols, // superclasses, categories, implementation, etc. Results.EnterNewScope(); // If this is a send-to-super, try to add the special "super" send // completion. if (IsSuper) { if (ObjCMethodDecl *SuperMethod = AddSuperSendCompletion(SemaRef, false, SelIdents, Results)) Results.Ignore(SuperMethod); } // If we're inside an Objective-C method definition, prefer its selector to // others. if (ObjCMethodDecl *CurMethod = SemaRef.getCurMethodDecl()) Results.setPreferredSelector(CurMethod->getSelector()); VisitedSelectorSet Selectors; if (CDecl) AddObjCMethods(CDecl, false, MK_Any, SelIdents, SemaRef.CurContext, Selectors, AtArgumentExpression, Results); else { // We're messaging "id" as a type; provide all class/factory methods. // If we have an external source, load the entire class method // pool from the AST file. if (SemaRef.getExternalSource()) { for (uint32_t I = 0, N = SemaRef.getExternalSource()->GetNumExternalSelectors(); I != N; ++I) { Selector Sel = SemaRef.getExternalSource()->GetExternalSelector(I); if (Sel.isNull() || SemaRef.MethodPool.count(Sel)) continue; SemaRef.ReadMethodPool(Sel); } } for (Sema::GlobalMethodPool::iterator M = SemaRef.MethodPool.begin(), MEnd = SemaRef.MethodPool.end(); M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.second; MethList && MethList->getMethod(); MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; Result R(MethList->getMethod(), Results.getBasePriority(MethList->getMethod()), nullptr); R.StartParameter = SelIdents.size(); R.AllParametersAreInformative = false; Results.MaybeAddResult(R, SemaRef.CurContext); } } } Results.ExitScope(); } void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper) { QualType T = this->GetTypeFromParser(Receiver); ResultBuilder Results( *this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext(CodeCompletionContext::CCC_ObjCClassMessage, T, SelIdents)); AddClassMessageCompletions(*this, S, Receiver, SelIdents, AtArgumentExpression, IsSuper, Results); // If we're actually at the argument expression (rather than prior to the // selector), we're actually performing code completion for an expression. // Determine whether we have a single, best method. If so, we can // code-complete the expression using the corresponding parameter type as // our preferred type, improving completion results. if (AtArgumentExpression) { QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, SelIdents.size()); if (PreferredType.isNull()) CodeCompleteOrdinaryName(S, PCC_Expression); else CodeCompleteExpression(S, PreferredType); return; } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, ArrayRef SelIdents, bool AtArgumentExpression, ObjCInterfaceDecl *Super) { typedef CodeCompletionResult Result; Expr *RecExpr = static_cast(Receiver); // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. if (RecExpr) { ExprResult Conv = DefaultFunctionArrayLvalueConversion(RecExpr); if (Conv.isInvalid()) // conversion failed. bail. return; RecExpr = Conv.get(); } QualType ReceiverType = RecExpr ? RecExpr->getType() : Super ? Context.getObjCObjectPointerType( Context.getObjCInterfaceType(Super)) : Context.getObjCIdType(); // If we're messaging an expression with type "id" or "Class", check // whether we know something special about the receiver that allows // us to assume a more-specific receiver type. if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType()) { if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr)) { if (ReceiverType->isObjCClassType()) return CodeCompleteObjCClassMessage( S, ParsedType::make(Context.getObjCInterfaceType(IFace)), SelIdents, AtArgumentExpression, Super); ReceiverType = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(IFace)); } } else if (RecExpr && getLangOpts().CPlusPlus) { ExprResult Conv = PerformContextuallyConvertToObjCPointer(RecExpr); if (Conv.isUsable()) { RecExpr = Conv.get(); ReceiverType = RecExpr->getType(); } } // Build the set of methods we can see. ResultBuilder Results( *this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext(CodeCompletionContext::CCC_ObjCInstanceMessage, ReceiverType, SelIdents)); Results.EnterNewScope(); // If this is a send-to-super, try to add the special "super" send // completion. if (Super) { if (ObjCMethodDecl *SuperMethod = AddSuperSendCompletion(*this, false, SelIdents, Results)) Results.Ignore(SuperMethod); } // If we're inside an Objective-C method definition, prefer its selector to // others. if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) Results.setPreferredSelector(CurMethod->getSelector()); // Keep track of the selectors we've already added. VisitedSelectorSet Selectors; // Handle messages to Class. This really isn't a message to an instance // method, so we treat it the same way we would treat a message send to a // class method. if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMethod->getClassInterface()) AddObjCMethods(ClassDecl, false, MK_Any, SelIdents, CurContext, Selectors, AtArgumentExpression, Results); } } // Handle messages to a qualified ID ("id"). else if (const ObjCObjectPointerType *QualID = ReceiverType->getAsObjCQualifiedIdType()) { // Search protocols for instance methods. for (auto *I : QualID->quals()) AddObjCMethods(I, true, MK_Any, SelIdents, CurContext, Selectors, AtArgumentExpression, Results); } // Handle messages to a pointer to interface type. else if (const ObjCObjectPointerType *IFacePtr = ReceiverType->getAsObjCInterfacePointerType()) { // Search the class, its superclasses, etc., for instance methods. AddObjCMethods(IFacePtr->getInterfaceDecl(), true, MK_Any, SelIdents, CurContext, Selectors, AtArgumentExpression, Results); // Search protocols for instance methods. for (auto *I : IFacePtr->quals()) AddObjCMethods(I, true, MK_Any, SelIdents, CurContext, Selectors, AtArgumentExpression, Results); } // Handle messages to "id". else if (ReceiverType->isObjCIdType()) { // We're messaging "id", so provide all instance methods we know // about as code-completion results. // If we have an external source, load the entire class method // pool from the AST file. if (ExternalSource) { for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors(); I != N; ++I) { Selector Sel = ExternalSource->GetExternalSelector(I); if (Sel.isNull() || MethodPool.count(Sel)) continue; ReadMethodPool(Sel); } } for (GlobalMethodPool::iterator M = MethodPool.begin(), MEnd = MethodPool.end(); M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.first; MethList && MethList->getMethod(); MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; if (!Selectors.insert(MethList->getMethod()->getSelector()).second) continue; Result R(MethList->getMethod(), Results.getBasePriority(MethList->getMethod()), nullptr); R.StartParameter = SelIdents.size(); R.AllParametersAreInformative = false; Results.MaybeAddResult(R, CurContext); } } } Results.ExitScope(); // If we're actually at the argument expression (rather than prior to the // selector), we're actually performing code completion for an expression. // Determine whether we have a single, best method. If so, we can // code-complete the expression using the corresponding parameter type as // our preferred type, improving completion results. if (AtArgumentExpression) { QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, SelIdents.size()); if (PreferredType.isNull()) CodeCompleteOrdinaryName(S, PCC_Expression); else CodeCompleteExpression(S, PreferredType); return; } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCForCollection(Scope *S, DeclGroupPtrTy IterationVar) { CodeCompleteExpressionData Data; Data.ObjCCollection = true; if (IterationVar.getAsOpaquePtr()) { DeclGroupRef DG = IterationVar.get(); for (DeclGroupRef::iterator I = DG.begin(), End = DG.end(); I != End; ++I) { if (*I) Data.IgnoreDecls.push_back(*I); } } CodeCompleteExpression(S, Data); } void Sema::CodeCompleteObjCSelector(Scope *S, ArrayRef SelIdents) { // If we have an external source, load the entire class method // pool from the AST file. if (ExternalSource) { for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors(); I != N; ++I) { Selector Sel = ExternalSource->GetExternalSelector(I); if (Sel.isNull() || MethodPool.count(Sel)) continue; ReadMethodPool(Sel); } } ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_SelectorName); Results.EnterNewScope(); for (GlobalMethodPool::iterator M = MethodPool.begin(), MEnd = MethodPool.end(); M != MEnd; ++M) { Selector Sel = M->first; if (!isAcceptableObjCSelector(Sel, MK_Any, SelIdents)) continue; CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); if (Sel.isUnarySelector()) { Builder.AddTypedTextChunk( Builder.getAllocator().CopyString(Sel.getNameForSlot(0))); Results.AddResult(Builder.TakeString()); continue; } std::string Accumulator; for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I) { if (I == SelIdents.size()) { if (!Accumulator.empty()) { Builder.AddInformativeChunk( Builder.getAllocator().CopyString(Accumulator)); Accumulator.clear(); } } Accumulator += Sel.getNameForSlot(I); Accumulator += ':'; } Builder.AddTypedTextChunk(Builder.getAllocator().CopyString(Accumulator)); Results.AddResult(Builder.TakeString()); } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } /// Add all of the protocol declarations that we find in the given /// (translation unit) context. static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, bool OnlyForwardDeclarations, ResultBuilder &Results) { typedef CodeCompletionResult Result; for (const auto *D : Ctx->decls()) { // Record any protocols we find. if (const auto *Proto = dyn_cast(D)) if (!OnlyForwardDeclarations || !Proto->hasDefinition()) Results.AddResult( Result(Proto, Results.getBasePriority(Proto), nullptr), CurContext, nullptr, false); } } void Sema::CodeCompleteObjCProtocolReferences( ArrayRef Protocols) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCProtocolName); if (CodeCompleter->includeGlobals()) { Results.EnterNewScope(); // Tell the result set to ignore all of the protocols we have // already seen. // FIXME: This doesn't work when caching code-completion results. for (const IdentifierLocPair &Pair : Protocols) if (ObjCProtocolDecl *Protocol = LookupProtocol(Pair.first, Pair.second)) Results.Ignore(Protocol); // Add all protocols. AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, false, Results); Results.ExitScope(); } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCProtocolDecl(Scope *) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCProtocolName); if (CodeCompleter->includeGlobals()) { Results.EnterNewScope(); // Add all protocols. AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, true, Results); Results.ExitScope(); } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } /// Add all of the Objective-C interface declarations that we find in /// the given (translation unit) context. static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, bool OnlyForwardDeclarations, bool OnlyUnimplemented, ResultBuilder &Results) { typedef CodeCompletionResult Result; for (const auto *D : Ctx->decls()) { // Record any interfaces we find. if (const auto *Class = dyn_cast(D)) if ((!OnlyForwardDeclarations || !Class->hasDefinition()) && (!OnlyUnimplemented || !Class->getImplementation())) Results.AddResult( Result(Class, Results.getBasePriority(Class), nullptr), CurContext, nullptr, false); } } void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCInterfaceName); Results.EnterNewScope(); if (CodeCompleter->includeGlobals()) { // Add all classes. AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, false, Results); } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCInterfaceName); Results.EnterNewScope(); // Make sure that we ignore the class we're currently defining. NamedDecl *CurClass = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); if (CurClass && isa(CurClass)) Results.Ignore(CurClass); if (CodeCompleter->includeGlobals()) { // Add all classes. AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, false, Results); } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCImplementation); Results.EnterNewScope(); if (CodeCompleter->includeGlobals()) { // Add all unimplemented classes. AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, true, Results); } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCCategoryName); // Ignore any categories we find that have already been implemented by this // interface. llvm::SmallPtrSet CategoryNames; NamedDecl *CurClass = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); if (ObjCInterfaceDecl *Class = dyn_cast_or_null(CurClass)) { for (const auto *Cat : Class->visible_categories()) CategoryNames.insert(Cat->getIdentifier()); } // Add all of the categories we know about. Results.EnterNewScope(); TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); for (const auto *D : TU->decls()) if (const auto *Category = dyn_cast(D)) if (CategoryNames.insert(Category->getIdentifier()).second) Results.AddResult( Result(Category, Results.getBasePriority(Category), nullptr), CurContext, nullptr, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCImplementationCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { typedef CodeCompletionResult Result; // Find the corresponding interface. If we couldn't find the interface, the // program itself is ill-formed. However, we'll try to be helpful still by // providing the list of all of the categories we know about. NamedDecl *CurClass = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); ObjCInterfaceDecl *Class = dyn_cast_or_null(CurClass); if (!Class) return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCCategoryName); // Add all of the categories that have have corresponding interface // declarations in this class and any of its superclasses, except for // already-implemented categories in the class itself. llvm::SmallPtrSet CategoryNames; Results.EnterNewScope(); bool IgnoreImplemented = true; while (Class) { for (const auto *Cat : Class->visible_categories()) { if ((!IgnoreImplemented || !Cat->getImplementation()) && CategoryNames.insert(Cat->getIdentifier()).second) Results.AddResult(Result(Cat, Results.getBasePriority(Cat), nullptr), CurContext, nullptr, false); } Class = Class->getSuperClass(); IgnoreImplemented = false; } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { CodeCompletionContext CCContext(CodeCompletionContext::CCC_Other); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CCContext); // Figure out where this @synthesize lives. ObjCContainerDecl *Container = dyn_cast_or_null(CurContext); if (!Container || (!isa(Container) && !isa(Container))) return; // Ignore any properties that have already been implemented. Container = getContainerDef(Container); for (const auto *D : Container->decls()) if (const auto *PropertyImpl = dyn_cast(D)) Results.Ignore(PropertyImpl->getPropertyDecl()); // Add any properties that we find. AddedPropertiesSet AddedProperties; Results.EnterNewScope(); if (ObjCImplementationDecl *ClassImpl = dyn_cast(Container)) AddObjCProperties(CCContext, ClassImpl->getClassInterface(), false, /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); else AddObjCProperties(CCContext, cast(Container)->getCategoryDecl(), false, /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCPropertySynthesizeIvar( Scope *S, IdentifierInfo *PropertyName) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); // Figure out where this @synthesize lives. ObjCContainerDecl *Container = dyn_cast_or_null(CurContext); if (!Container || (!isa(Container) && !isa(Container))) return; // Figure out which interface we're looking into. ObjCInterfaceDecl *Class = nullptr; if (ObjCImplementationDecl *ClassImpl = dyn_cast(Container)) Class = ClassImpl->getClassInterface(); else Class = cast(Container) ->getCategoryDecl() ->getClassInterface(); // Determine the type of the property we're synthesizing. QualType PropertyType = Context.getObjCIdType(); if (Class) { if (ObjCPropertyDecl *Property = Class->FindPropertyDeclaration( PropertyName, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { PropertyType = Property->getType().getNonReferenceType().getUnqualifiedType(); // Give preference to ivars Results.setPreferredType(PropertyType); } } // Add all of the instance variables in this class and its superclasses. Results.EnterNewScope(); bool SawSimilarlyNamedIvar = false; std::string NameWithPrefix; NameWithPrefix += '_'; NameWithPrefix += PropertyName->getName(); std::string NameWithSuffix = PropertyName->getName().str(); NameWithSuffix += '_'; for (; Class; Class = Class->getSuperClass()) { for (ObjCIvarDecl *Ivar = Class->all_declared_ivar_begin(); Ivar; Ivar = Ivar->getNextIvar()) { Results.AddResult(Result(Ivar, Results.getBasePriority(Ivar), nullptr), CurContext, nullptr, false); // Determine whether we've seen an ivar with a name similar to the // property. if ((PropertyName == Ivar->getIdentifier() || NameWithPrefix == Ivar->getName() || NameWithSuffix == Ivar->getName())) { SawSimilarlyNamedIvar = true; // Reduce the priority of this result by one, to give it a slight // advantage over other results whose names don't match so closely. if (Results.size() && Results.data()[Results.size() - 1].Kind == CodeCompletionResult::RK_Declaration && Results.data()[Results.size() - 1].Declaration == Ivar) Results.data()[Results.size() - 1].Priority--; } } } if (!SawSimilarlyNamedIvar) { // Create ivar result _propName, that the user can use to synthesize // an ivar of the appropriate type. unsigned Priority = CCP_MemberDeclaration + 1; typedef CodeCompletionResult Result; CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo(), Priority, CXAvailability_Available); PrintingPolicy Policy = getCompletionPrintingPolicy(*this); Builder.AddResultTypeChunk( GetCompletionTypeString(PropertyType, Context, Policy, Allocator)); Builder.AddTypedTextChunk(Allocator.CopyString(NameWithPrefix)); Results.AddResult( Result(Builder.TakeString(), Priority, CXCursor_ObjCIvarDecl)); } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } // Mapping from selectors to the methods that implement that selector, along // with the "in original class" flag. typedef llvm::DenseMap> KnownMethodsMap; /// Find all of the methods that reside in the given container /// (and its superclasses, protocols, etc.) that meet the given /// criteria. Insert those methods into the map of known methods, /// indexed by selector so they can be easily found. static void FindImplementableMethods(ASTContext &Context, ObjCContainerDecl *Container, Optional WantInstanceMethods, QualType ReturnType, KnownMethodsMap &KnownMethods, bool InOriginalClass = true) { if (ObjCInterfaceDecl *IFace = dyn_cast(Container)) { // Make sure we have a definition; that's what we'll walk. if (!IFace->hasDefinition()) return; IFace = IFace->getDefinition(); Container = IFace; const ObjCList &Protocols = IFace->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, KnownMethods, InOriginalClass); // Add methods from any class extensions and categories. for (auto *Cat : IFace->visible_categories()) { FindImplementableMethods(Context, Cat, WantInstanceMethods, ReturnType, KnownMethods, false); } // Visit the superclass. if (IFace->getSuperClass()) FindImplementableMethods(Context, IFace->getSuperClass(), WantInstanceMethods, ReturnType, KnownMethods, false); } if (ObjCCategoryDecl *Category = dyn_cast(Container)) { // Recurse into protocols. const ObjCList &Protocols = Category->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, KnownMethods, InOriginalClass); // If this category is the original class, jump to the interface. if (InOriginalClass && Category->getClassInterface()) FindImplementableMethods(Context, Category->getClassInterface(), WantInstanceMethods, ReturnType, KnownMethods, false); } if (ObjCProtocolDecl *Protocol = dyn_cast(Container)) { // Make sure we have a definition; that's what we'll walk. if (!Protocol->hasDefinition()) return; Protocol = Protocol->getDefinition(); Container = Protocol; // Recurse into protocols. const ObjCList &Protocols = Protocol->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, KnownMethods, false); } // Add methods in this container. This operation occurs last because // we want the methods from this container to override any methods // we've previously seen with the same selector. for (auto *M : Container->methods()) { if (!WantInstanceMethods || M->isInstanceMethod() == *WantInstanceMethods) { if (!ReturnType.isNull() && !Context.hasSameUnqualifiedType(ReturnType, M->getReturnType())) continue; KnownMethods[M->getSelector()] = KnownMethodsMap::mapped_type(M, InOriginalClass); } } } /// Add the parenthesized return or parameter type chunk to a code /// completion string. static void AddObjCPassingTypeChunk(QualType Type, unsigned ObjCDeclQuals, ASTContext &Context, const PrintingPolicy &Policy, CodeCompletionBuilder &Builder) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); std::string Quals = formatObjCParamQualifiers(ObjCDeclQuals, Type); if (!Quals.empty()) Builder.AddTextChunk(Builder.getAllocator().CopyString(Quals)); Builder.AddTextChunk( GetCompletionTypeString(Type, Context, Policy, Builder.getAllocator())); Builder.AddChunk(CodeCompletionString::CK_RightParen); } /// Determine whether the given class is or inherits from a class by /// the given name. static bool InheritsFromClassNamed(ObjCInterfaceDecl *Class, StringRef Name) { if (!Class) return false; if (Class->getIdentifier() && Class->getIdentifier()->getName() == Name) return true; return InheritsFromClassNamed(Class->getSuperClass(), Name); } /// Add code completions for Objective-C Key-Value Coding (KVC) and /// Key-Value Observing (KVO). static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, bool IsInstanceMethod, QualType ReturnType, ASTContext &Context, VisitedSelectorSet &KnownSelectors, ResultBuilder &Results) { IdentifierInfo *PropName = Property->getIdentifier(); if (!PropName || PropName->getLength() == 0) return; PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema()); // Builder that will create each code completion. typedef CodeCompletionResult Result; CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); // The selector table. SelectorTable &Selectors = Context.Selectors; // The property name, copied into the code completion allocation region // on demand. struct KeyHolder { CodeCompletionAllocator &Allocator; StringRef Key; const char *CopiedKey; KeyHolder(CodeCompletionAllocator &Allocator, StringRef Key) : Allocator(Allocator), Key(Key), CopiedKey(nullptr) {} operator const char *() { if (CopiedKey) return CopiedKey; return CopiedKey = Allocator.CopyString(Key); } } Key(Allocator, PropName->getName()); // The uppercased name of the property name. std::string UpperKey = std::string(PropName->getName()); if (!UpperKey.empty()) UpperKey[0] = toUppercase(UpperKey[0]); bool ReturnTypeMatchesProperty = ReturnType.isNull() || Context.hasSameUnqualifiedType(ReturnType.getNonReferenceType(), Property->getType()); bool ReturnTypeMatchesVoid = ReturnType.isNull() || ReturnType->isVoidType(); // Add the normal accessor -(type)key. if (IsInstanceMethod && KnownSelectors.insert(Selectors.getNullarySelector(PropName)).second && ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) { if (ReturnType.isNull()) AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0, Context, Policy, Builder); Builder.AddTypedTextChunk(Key); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCInstanceMethodDecl)); } // If we have an integral or boolean property (or the user has provided // an integral or boolean return type), add the accessor -(type)isKey. if (IsInstanceMethod && ((!ReturnType.isNull() && (ReturnType->isIntegerType() || ReturnType->isBooleanType())) || (ReturnType.isNull() && (Property->getType()->isIntegerType() || Property->getType()->isBooleanType())))) { std::string SelectorName = (Twine("is") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("BOOL"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorId->getName())); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCInstanceMethodDecl)); } } // Add the normal mutator. if (IsInstanceMethod && ReturnTypeMatchesVoid && !Property->getSetterMethodDecl()) { std::string SelectorName = (Twine("set") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk( Allocator.CopyString(SelectorId->getName() + ":")); AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0, Context, Policy, Builder); Builder.AddTextChunk(Key); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCInstanceMethodDecl)); } } // Indexed and unordered accessors unsigned IndexedGetterPriority = CCP_CodePattern; unsigned IndexedSetterPriority = CCP_CodePattern; unsigned UnorderedGetterPriority = CCP_CodePattern; unsigned UnorderedSetterPriority = CCP_CodePattern; if (const auto *ObjCPointer = Property->getType()->getAs()) { if (ObjCInterfaceDecl *IFace = ObjCPointer->getInterfaceDecl()) { // If this interface type is not provably derived from a known // collection, penalize the corresponding completions. if (!InheritsFromClassNamed(IFace, "NSMutableArray")) { IndexedSetterPriority += CCD_ProbablyNotObjCCollection; if (!InheritsFromClassNamed(IFace, "NSArray")) IndexedGetterPriority += CCD_ProbablyNotObjCCollection; } if (!InheritsFromClassNamed(IFace, "NSMutableSet")) { UnorderedSetterPriority += CCD_ProbablyNotObjCCollection; if (!InheritsFromClassNamed(IFace, "NSSet")) UnorderedGetterPriority += CCD_ProbablyNotObjCCollection; } } } else { IndexedGetterPriority += CCD_ProbablyNotObjCCollection; IndexedSetterPriority += CCD_ProbablyNotObjCCollection; UnorderedGetterPriority += CCD_ProbablyNotObjCCollection; UnorderedSetterPriority += CCD_ProbablyNotObjCCollection; } // Add -(NSUInteger)countOf if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isIntegerType())) { std::string SelectorName = (Twine("countOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSUInteger"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorId->getName())); Results.AddResult( Result(Builder.TakeString(), std::min(IndexedGetterPriority, UnorderedGetterPriority), CXCursor_ObjCInstanceMethodDecl)); } } // Indexed getters // Add -(id)objectInKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { std::string SelectorName = (Twine("objectIn") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("id"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSUInteger"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("index"); Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // Add -(NSArray *)keyAtIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && (ReturnType.isNull() || (ReturnType->isObjCObjectPointerType() && ReturnType->castAs()->getInterfaceDecl() && ReturnType->castAs() ->getInterfaceDecl() ->getName() == "NSArray"))) { std::string SelectorName = (Twine(Property->getName()) + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSArray *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSIndexSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("indexes"); Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // Add -(void)getKey:(type **)buffer range:(NSRange)inRange if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("get") + UpperKey).str(); IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), &Context.Idents.get("range")}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); Builder.AddTextChunk(" **"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("buffer"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTypedTextChunk("range:"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSRange"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("inRange"); Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // Mutable indexed accessors // - (void)insertObject:(type *)object inKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("in") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorIds[2] = {&Context.Idents.get("insertObject"), &Context.Idents.get(SelectorName)}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk("insertObject:"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); Builder.AddTextChunk(" *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("object"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("NSUInteger"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("index"); Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // - (void)insertKey:(NSArray *)array atIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("insert") + UpperKey).str(); IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), &Context.Idents.get("atIndexes")}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSArray *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("array"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTypedTextChunk("atIndexes:"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("NSIndexSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("indexes"); Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // -(void)removeObjectFromKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSUInteger"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("index"); Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // -(void)removeKeyAtIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSIndexSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("indexes"); Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // - (void)replaceObjectInKeyAtIndex:(NSUInteger)index withObject:(id)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("replaceObjectIn") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), &Context.Idents.get("withObject")}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("NSUInteger"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("index"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTypedTextChunk("withObject:"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("id"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("object"); Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // - (void)replaceKeyAtIndexes:(NSIndexSet *)indexes withKey:(NSArray *)array if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName1 = (Twine("replace") + UpperKey + "AtIndexes").str(); std::string SelectorName2 = (Twine("with") + UpperKey).str(); IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName1), &Context.Idents.get(SelectorName2)}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName1 + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("NSIndexSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("indexes"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName2 + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSArray *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("array"); Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // Unordered getters // - (NSEnumerator *)enumeratorOfKey if (IsInstanceMethod && (ReturnType.isNull() || (ReturnType->isObjCObjectPointerType() && ReturnType->getAs()->getInterfaceDecl() && ReturnType->getAs() ->getInterfaceDecl() ->getName() == "NSEnumerator"))) { std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSEnumerator *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // - (type *)memberOfKey:(type *)object if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { std::string SelectorName = (Twine("memberOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); Builder.AddTextChunk(" *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (ReturnType.isNull()) { Builder.AddPlaceholderChunk("object-type"); Builder.AddTextChunk(" *"); } else { Builder.AddTextChunk(GetCompletionTypeString( ReturnType, Context, Policy, Builder.getAllocator())); } Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("object"); Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // Mutable unordered accessors // - (void)addKeyObject:(type *)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("add") + UpperKey + Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); Builder.AddTextChunk(" *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("object"); Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // - (void)addKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("add") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("objects"); Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // - (void)removeKeyObject:(type *)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey + Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); Builder.AddTextChunk(" *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("object"); Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // - (void)removeKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("objects"); Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // - (void)intersectKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("intersect") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("objects"); Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // Key-Value Observing // + (NSSet *)keyPathsForValuesAffectingKey if (!IsInstanceMethod && (ReturnType.isNull() || (ReturnType->isObjCObjectPointerType() && ReturnType->castAs()->getInterfaceDecl() && ReturnType->castAs() ->getInterfaceDecl() ->getName() == "NSSet"))) { std::string SelectorName = (Twine("keyPathsForValuesAffecting") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCClassMethodDecl)); } } // + (BOOL)automaticallyNotifiesObserversForKey if (!IsInstanceMethod && (ReturnType.isNull() || ReturnType->isIntegerType() || ReturnType->isBooleanType())) { std::string SelectorName = (Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("BOOL"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCClassMethodDecl)); } } } void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional IsInstanceMethod, ParsedType ReturnTy) { // Determine the return type of the method we're declaring, if // provided. QualType ReturnType = GetTypeFromParser(ReturnTy); Decl *IDecl = nullptr; if (CurContext->isObjCContainer()) { ObjCContainerDecl *OCD = dyn_cast(CurContext); IDecl = OCD; } // Determine where we should start searching for methods. ObjCContainerDecl *SearchDecl = nullptr; bool IsInImplementation = false; if (Decl *D = IDecl) { if (ObjCImplementationDecl *Impl = dyn_cast(D)) { SearchDecl = Impl->getClassInterface(); IsInImplementation = true; } else if (ObjCCategoryImplDecl *CatImpl = dyn_cast(D)) { SearchDecl = CatImpl->getCategoryDecl(); IsInImplementation = true; } else SearchDecl = dyn_cast(D); } if (!SearchDecl && S) { if (DeclContext *DC = S->getEntity()) SearchDecl = dyn_cast(DC); } if (!SearchDecl) { HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, nullptr, 0); return; } // Find all of the methods that we could declare/implement here. KnownMethodsMap KnownMethods; FindImplementableMethods(Context, SearchDecl, IsInstanceMethod, ReturnType, KnownMethods); // Add declarations or definitions for each of the known methods. typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); PrintingPolicy Policy = getCompletionPrintingPolicy(*this); for (KnownMethodsMap::iterator M = KnownMethods.begin(), MEnd = KnownMethods.end(); M != MEnd; ++M) { ObjCMethodDecl *Method = M->second.getPointer(); CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); // Add the '-'/'+' prefix if it wasn't provided yet. if (!IsInstanceMethod) { Builder.AddTextChunk(Method->isInstanceMethod() ? "-" : "+"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); } // If the result type was not already provided, add it to the // pattern as (type). if (ReturnType.isNull()) { QualType ResTy = Method->getSendResultType().stripObjCKindOfType(Context); AttributedType::stripOuterNullability(ResTy); AddObjCPassingTypeChunk(ResTy, Method->getObjCDeclQualifier(), Context, Policy, Builder); } Selector Sel = Method->getSelector(); if (Sel.isUnarySelector()) { // Unary selectors have no arguments. Builder.AddTypedTextChunk( Builder.getAllocator().CopyString(Sel.getNameForSlot(0))); } else { // Add all parameters to the pattern. unsigned I = 0; for (ObjCMethodDecl::param_iterator P = Method->param_begin(), PEnd = Method->param_end(); P != PEnd; (void)++P, ++I) { // Add the part of the selector name. if (I == 0) Builder.AddTypedTextChunk( Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":")); else if (I < Sel.getNumArgs()) { Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTypedTextChunk( Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":")); } else break; // Add the parameter type. QualType ParamType; if ((*P)->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) ParamType = (*P)->getType(); else ParamType = (*P)->getOriginalType(); ParamType = ParamType.substObjCTypeArgs( Context, {}, ObjCSubstitutionContext::Parameter); AttributedType::stripOuterNullability(ParamType); AddObjCPassingTypeChunk(ParamType, (*P)->getObjCDeclQualifier(), Context, Policy, Builder); if (IdentifierInfo *Id = (*P)->getIdentifier()) Builder.AddTextChunk( Builder.getAllocator().CopyString(Id->getName())); } } if (Method->isVariadic()) { if (Method->param_size() > 0) Builder.AddChunk(CodeCompletionString::CK_Comma); Builder.AddTextChunk("..."); } if (IsInImplementation && Results.includeCodePatterns()) { // We will be defining the method here, so add a compound statement. Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); if (!Method->getReturnType()->isVoidType()) { // If the result type is not void, add a return clause. Builder.AddTextChunk("return"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_SemiColon); } else Builder.AddPlaceholderChunk("statements"); Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddChunk(CodeCompletionString::CK_RightBrace); } unsigned Priority = CCP_CodePattern; auto R = Result(Builder.TakeString(), Method, Priority); if (!M->second.getInt()) setInBaseClass(R); Results.AddResult(std::move(R)); } // Add Key-Value-Coding and Key-Value-Observing accessor methods for all of // the properties in this class and its categories. if (Context.getLangOpts().ObjC) { SmallVector Containers; Containers.push_back(SearchDecl); VisitedSelectorSet KnownSelectors; for (KnownMethodsMap::iterator M = KnownMethods.begin(), MEnd = KnownMethods.end(); M != MEnd; ++M) KnownSelectors.insert(M->first); ObjCInterfaceDecl *IFace = dyn_cast(SearchDecl); if (!IFace) if (ObjCCategoryDecl *Category = dyn_cast(SearchDecl)) IFace = Category->getClassInterface(); if (IFace) for (auto *Cat : IFace->visible_categories()) Containers.push_back(Cat); if (IsInstanceMethod) { for (unsigned I = 0, N = Containers.size(); I != N; ++I) for (auto *P : Containers[I]->instance_properties()) AddObjCKeyValueCompletions(P, *IsInstanceMethod, ReturnType, Context, KnownSelectors, Results); } } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteObjCMethodDeclSelector( Scope *S, bool IsInstanceMethod, bool AtParameterName, ParsedType ReturnTy, ArrayRef SelIdents) { // If we have an external source, load the entire class method // pool from the AST file. if (ExternalSource) { for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors(); I != N; ++I) { Selector Sel = ExternalSource->GetExternalSelector(I); if (Sel.isNull() || MethodPool.count(Sel)) continue; ReadMethodPool(Sel); } } // Build the set of methods we can see. typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); if (ReturnTy) Results.setPreferredType(GetTypeFromParser(ReturnTy).getNonReferenceType()); Results.EnterNewScope(); for (GlobalMethodPool::iterator M = MethodPool.begin(), MEnd = MethodPool.end(); M != MEnd; ++M) { for (ObjCMethodList *MethList = IsInstanceMethod ? &M->second.first : &M->second.second; MethList && MethList->getMethod(); MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; if (AtParameterName) { // Suggest parameter names we've seen before. unsigned NumSelIdents = SelIdents.size(); if (NumSelIdents && NumSelIdents <= MethList->getMethod()->param_size()) { ParmVarDecl *Param = MethList->getMethod()->parameters()[NumSelIdents - 1]; if (Param->getIdentifier()) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( Param->getIdentifier()->getName())); Results.AddResult(Builder.TakeString()); } } continue; } Result R(MethList->getMethod(), Results.getBasePriority(MethList->getMethod()), nullptr); R.StartParameter = SelIdents.size(); R.AllParametersAreInformative = false; R.DeclaringEntity = true; Results.MaybeAddResult(R, CurContext); } } Results.ExitScope(); if (!AtParameterName && !SelIdents.empty() && SelIdents.front()->getName().startswith("init")) { for (const auto &M : PP.macros()) { if (M.first->getName() != "NS_DESIGNATED_INITIALIZER") continue; Results.EnterNewScope(); CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Builder.AddTypedTextChunk( Builder.getAllocator().CopyString(M.first->getName())); Results.AddResult(CodeCompletionResult(Builder.TakeString(), CCP_Macro, CXCursor_MacroDefinition)); Results.ExitScope(); } } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompletePreprocessorDirective(bool InConditional) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_PreprocessorDirective); Results.EnterNewScope(); // #if CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Builder.AddTypedTextChunk("if"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("condition"); Results.AddResult(Builder.TakeString()); // #ifdef Builder.AddTypedTextChunk("ifdef"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("macro"); Results.AddResult(Builder.TakeString()); // #ifndef Builder.AddTypedTextChunk("ifndef"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("macro"); Results.AddResult(Builder.TakeString()); if (InConditional) { // #elif Builder.AddTypedTextChunk("elif"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("condition"); Results.AddResult(Builder.TakeString()); // #else Builder.AddTypedTextChunk("else"); Results.AddResult(Builder.TakeString()); // #endif Builder.AddTypedTextChunk("endif"); Results.AddResult(Builder.TakeString()); } // #include "header" Builder.AddTypedTextChunk("include"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTextChunk("\""); Builder.AddPlaceholderChunk("header"); Builder.AddTextChunk("\""); Results.AddResult(Builder.TakeString()); // #include
Builder.AddTypedTextChunk("include"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTextChunk("<"); Builder.AddPlaceholderChunk("header"); Builder.AddTextChunk(">"); Results.AddResult(Builder.TakeString()); // #define Builder.AddTypedTextChunk("define"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("macro"); Results.AddResult(Builder.TakeString()); // #define () Builder.AddTypedTextChunk("define"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("macro"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("args"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Builder.TakeString()); // #undef Builder.AddTypedTextChunk("undef"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("macro"); Results.AddResult(Builder.TakeString()); // #line Builder.AddTypedTextChunk("line"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("number"); Results.AddResult(Builder.TakeString()); // #line "filename" Builder.AddTypedTextChunk("line"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("number"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTextChunk("\""); Builder.AddPlaceholderChunk("filename"); Builder.AddTextChunk("\""); Results.AddResult(Builder.TakeString()); // #error Builder.AddTypedTextChunk("error"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("message"); Results.AddResult(Builder.TakeString()); // #pragma Builder.AddTypedTextChunk("pragma"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("arguments"); Results.AddResult(Builder.TakeString()); if (getLangOpts().ObjC) { // #import "header" Builder.AddTypedTextChunk("import"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTextChunk("\""); Builder.AddPlaceholderChunk("header"); Builder.AddTextChunk("\""); Results.AddResult(Builder.TakeString()); // #import
Builder.AddTypedTextChunk("import"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTextChunk("<"); Builder.AddPlaceholderChunk("header"); Builder.AddTextChunk(">"); Results.AddResult(Builder.TakeString()); } // #include_next "header" Builder.AddTypedTextChunk("include_next"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTextChunk("\""); Builder.AddPlaceholderChunk("header"); Builder.AddTextChunk("\""); Results.AddResult(Builder.TakeString()); // #include_next
Builder.AddTypedTextChunk("include_next"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddTextChunk("<"); Builder.AddPlaceholderChunk("header"); Builder.AddTextChunk(">"); Results.AddResult(Builder.TakeString()); // #warning Builder.AddTypedTextChunk("warning"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("message"); Results.AddResult(Builder.TakeString()); // Note: #ident and #sccs are such crazy anachronisms that we don't provide // completions for them. And __include_macros is a Clang-internal extension // that we don't want to encourage anyone to use. // FIXME: we don't support #assert or #unassert, so don't suggest them. Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteInPreprocessorConditionalExclusion(Scope *S) { CodeCompleteOrdinaryName(S, S->getFnParent() ? Sema::PCC_RecoveryInFunction