diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-07-08 23:20:03 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-07-08 23:20:03 +0000 |
commit | 1f5537aaac1e775aff1d523f2cc59a9a3bd6c946 (patch) | |
tree | d61e423416f688e07af1f00b0d5a101f1569f212 /lib/Sema/SemaCodeComplete.cpp | |
parent | cddc69fc3fe17b043a287a41e3706766c3d09a79 (diff) |
Introduce a new code-completion point prior to an identifier in the
selector of an Objective-C method declaration, e.g., given
- (int)first:(int)x second:(int)y;
this code completion point triggers at the location of "second". It
will provide completions that fill out the method declaration for any
known method, anywhere in the translation unit.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107929 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaCodeComplete.cpp')
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 327 |
1 files changed, 195 insertions, 132 deletions
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 3e482532ca..8df9eace27 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -130,6 +130,8 @@ namespace { /// different levels of, e.g., the inheritance hierarchy. std::list<ShadowMap> ShadowMaps; + void AdjustResultPriorityForPreferredType(Result &R); + public: explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0) : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { } @@ -470,6 +472,134 @@ bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext, return false; } +enum SimplifiedTypeClass { + STC_Arithmetic, + STC_Array, + STC_Block, + STC_Function, + STC_ObjectiveC, + STC_Other, + STC_Pointer, + STC_Record, + STC_Void +}; + +/// \brief A simplified classification of types used to determine whether two +/// types are "similar enough" when adjusting priorities. +static SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T) { + switch (T->getTypeClass()) { + case Type::Builtin: + switch (cast<BuiltinType>(T)->getKind()) { + case BuiltinType::Void: + return STC_Void; + + case BuiltinType::NullPtr: + return STC_Pointer; + + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::UndeducedAuto: + return STC_Other; + + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + return STC_ObjectiveC; + + default: + return STC_Arithmetic; + } + return STC_Other; + + 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<ReferenceType>()->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; + } +} + +/// \brief Get the type that a given expression will have if this declaration +/// is used as an expression in its "typical" code-completion form. +static QualType getDeclUsageType(ASTContext &C, NamedDecl *ND) { + ND = cast<NamedDecl>(ND->getUnderlyingDecl()); + + if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) + return C.getTypeDeclType(Type); + if (ObjCInterfaceDecl *Iface = dyn_cast<ObjCInterfaceDecl>(ND)) + return C.getObjCInterfaceType(Iface); + + QualType T; + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) + T = Function->getResultType(); + else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) + T = Method->getResultType(); + else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) + T = FunTmpl->getTemplatedDecl()->getResultType(); + else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) + T = C.getTypeDeclType(cast<EnumDecl>(Enumerator->getDeclContext())); + else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND)) + T = Property->getType(); + else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND)) + T = Value->getType(); + else + return QualType(); + + return T.getNonReferenceType(); +} + +void ResultBuilder::AdjustResultPriorityForPreferredType(Result &R) { + QualType T = getDeclUsageType(SemaRef.Context, R.Declaration); + if (T.isNull()) + return; + + 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; +} + void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { assert(!ShadowMaps.empty() && "Must enter into a results scope"); @@ -554,8 +684,9 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { if (AsNestedNameSpecifier) { R.StartsNestedNameSpecifier = true; R.Priority = CCP_NestedNameSpecifier; - } - + } else if (!PreferredType.isNull()) + AdjustResultPriorityForPreferredType(R); + // If this result is supposed to have an informative qualifier, add one. if (R.QualifierIsInformative && !R.Qualifier && !R.StartsNestedNameSpecifier) { @@ -575,118 +706,6 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { Results.push_back(R); } -enum SimplifiedTypeClass { - STC_Arithmetic, - STC_Array, - STC_Block, - STC_Function, - STC_ObjectiveC, - STC_Other, - STC_Pointer, - STC_Record, - STC_Void -}; - -/// \brief A simplified classification of types used to determine whether two -/// types are "similar enough" when adjusting priorities. -static SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T) { - switch (T->getTypeClass()) { - case Type::Builtin: - switch (cast<BuiltinType>(T)->getKind()) { - case BuiltinType::Void: - return STC_Void; - - case BuiltinType::NullPtr: - return STC_Pointer; - - case BuiltinType::Overload: - case BuiltinType::Dependent: - case BuiltinType::UndeducedAuto: - return STC_Other; - - case BuiltinType::ObjCId: - case BuiltinType::ObjCClass: - case BuiltinType::ObjCSel: - return STC_ObjectiveC; - - default: - return STC_Arithmetic; - } - return STC_Other; - - 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<ReferenceType>()->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; - } -} - -/// \brief Get the type that a given expression will have if this declaration -/// is used as an expression in its "typical" code-completion form. -static QualType getDeclUsageType(ASTContext &C, NamedDecl *ND) { - ND = cast<NamedDecl>(ND->getUnderlyingDecl()); - - if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) - return C.getTypeDeclType(Type); - if (ObjCInterfaceDecl *Iface = dyn_cast<ObjCInterfaceDecl>(ND)) - return C.getObjCInterfaceType(Iface); - - QualType T; - if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) - T = Function->getResultType(); - else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) - T = Method->getResultType(); - else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) - T = FunTmpl->getTemplatedDecl()->getResultType(); - else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) - T = C.getTypeDeclType(cast<EnumDecl>(Enumerator->getDeclContext())); - else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND)) - T = Property->getType(); - else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND)) - T = Value->getType(); - else - return QualType(); - - return T.getNonReferenceType(); -} - void ResultBuilder::AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding, bool InBaseClass = false) { if (R.Kind != Result::RK_Declaration) { @@ -740,20 +759,8 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, if (InBaseClass) R.Priority += CCD_InBaseClass; - if (!PreferredType.isNull()) { - if (ValueDecl *Value = dyn_cast<ValueDecl>(R.Declaration)) { - CanQualType T = SemaRef.Context.getCanonicalType( - getDeclUsageType(SemaRef.Context, Value)); - // Check for exactly-matching types (modulo qualifiers). - if (SemaRef.Context.hasSameUnqualifiedType(PreferredType, T)) - R.Priority /= CCF_ExactTypeMatch; - // Check for nearly-matching types, based on classification of each. - else if ((getSimplifiedTypeClass(PreferredType) - == getSimplifiedTypeClass(T)) && - !(PreferredType->isEnumeralType() && T->isEnumeralType())) - R.Priority /= CCF_SimilarTypeMatch; - } - } + if (!PreferredType.isNull()) + AdjustResultPriorityForPreferredType(R); // Insert this result into the set of results. Results.push_back(R); @@ -1955,9 +1962,9 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) Keyword += II->getName().str(); Keyword += ":"; - if (Idx < StartParameter || AllParametersAreInformative) { + if (Idx < StartParameter || AllParametersAreInformative) Result->AddInformativeChunk(Keyword); - } else if (Idx == StartParameter) + else if (Idx == StartParameter) Result->AddTypedTextChunk(Keyword); else Result->AddTextChunk(Keyword); @@ -1972,14 +1979,18 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { Arg = "(" + Arg + ")"; if (IdentifierInfo *II = (*P)->getIdentifier()) Arg += II->getName().str(); - if (AllParametersAreInformative) + if (DeclaringEntity) + Result->AddTextChunk(Arg); + else if (AllParametersAreInformative) Result->AddInformativeChunk(Arg); else Result->AddPlaceholderChunk(Arg); } if (Method->isVariadic()) { - if (AllParametersAreInformative) + if (DeclaringEntity) + Result->AddTextChunk(", ..."); + else if (AllParametersAreInformative) Result->AddInformativeChunk(", ..."); else Result->AddPlaceholderChunk(", ..."); @@ -4133,3 +4144,55 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } + +void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, + bool IsInstanceMethod, + TypeTy *ReturnTy, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { + llvm::DenseMap<Selector, ObjCMethodList> &Pool + = IsInstanceMethod? InstanceMethodPool : FactoryMethodPool; + + // If we have an external source, load the entire class method + // pool from the PCH file. + if (ExternalSource) { + for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors(); + I != N; ++I) { + Selector Sel = ExternalSource->GetExternalSelector(I); + if (Sel.isNull() || InstanceMethodPool.count(Sel) || + FactoryMethodPool.count(Sel)) + continue; + + ReadMethodPool(Sel, IsInstanceMethod); + } + } + + // Build the set of methods we can see. + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + + if (ReturnTy) + Results.setPreferredType(GetTypeFromParser(ReturnTy).getNonReferenceType()); + + Results.EnterNewScope(); + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator M = Pool.begin(), + MEnd = Pool.end(); + M != MEnd; + ++M) { + for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method; + MethList = MethList->Next) { + if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, + NumSelIdents)) + continue; + + Result R(MethList->Method, 0); + R.StartParameter = NumSelIdents; + R.AllParametersAreInformative = false; + R.DeclaringEntity = true; + Results.MaybeAddResult(R, CurContext); + } + } + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} |