aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaCodeComplete.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-07-08 23:20:03 +0000
committerDouglas Gregor <dgregor@apple.com>2010-07-08 23:20:03 +0000
commit1f5537aaac1e775aff1d523f2cc59a9a3bd6c946 (patch)
treed61e423416f688e07af1f00b0d5a101f1569f212 /lib/Sema/SemaCodeComplete.cpp
parentcddc69fc3fe17b043a287a41e3706766c3d09a79 (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.cpp327
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());
+}