aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Parse/ParseObjc.cpp7
-rw-r--r--Sema/ASTStreamer.cpp1
-rw-r--r--Sema/Sema.h29
-rw-r--r--Sema/SemaDecl.cpp62
-rw-r--r--include/clang/Parse/Action.h2
5 files changed, 92 insertions, 9 deletions
diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp
index bfd6797c96..4236314fdf 100644
--- a/Parse/ParseObjc.cpp
+++ b/Parse/ParseObjc.cpp
@@ -266,9 +266,10 @@ void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl,
ParseDeclarationOrFunctionDefinition();
}
}
- /// Insert collected methods declarations into the @interface object.
- Actions.ActOnAddMethodsToObjcDecl(CurScope, interfaceDecl,
- &allMethods[0], allMethods.size());
+ if (allMethods.size())
+ /// Insert collected methods declarations into the @interface object.
+ Actions.ActOnAddMethodsToObjcDecl(CurScope, interfaceDecl,
+ &allMethods[0], allMethods.size());
}
/// Parse property attribute declarations.
diff --git a/Sema/ASTStreamer.cpp b/Sema/ASTStreamer.cpp
index b622d2887a..facd5bccaa 100644
--- a/Sema/ASTStreamer.cpp
+++ b/Sema/ASTStreamer.cpp
@@ -81,6 +81,7 @@ Decl *ASTStreamer::ReadTopLevelDecl() {
}
void ASTStreamer::PrintStats() const {
+ P.getActions().PrintStats();
}
//===----------------------------------------------------------------------===//
diff --git a/Sema/Sema.h b/Sema/Sema.h
index 511b43a1bb..94d22f0742 100644
--- a/Sema/Sema.h
+++ b/Sema/Sema.h
@@ -120,6 +120,27 @@ class Sema : public Action {
/// ObjcIdTypedef - built-in typedef for "id".
TypedefDecl *ObjcIdTypedef;
+
+ /// ObjCMethodList - a linked list of methods with different signatures.
+ struct ObjcMethodList {
+ ObjcMethodDecl *Method;
+ ObjcMethodList *Next;
+
+ ObjcMethodList() {
+ Method = 0;
+ Next = 0;
+ }
+ ObjcMethodList(ObjcMethodDecl *M, ObjcMethodList *C) {
+ Method = M;
+ Next = C;
+ }
+ };
+ /// Instance/Factory Method Pools - 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").
+ llvm::DenseMap<Selector, ObjcMethodList> InstanceMethodPool;
+ llvm::DenseMap<Selector, ObjcMethodList> FactoryMethodPool;
public:
Sema(Preprocessor &pp, ASTContext &ctxt, std::vector<Decl*> &prevInGroup);
@@ -259,6 +280,14 @@ private:
/// GetObjcIdType - Getter for the build-in "id" type.
QualType GetObjcIdType(SourceLocation Loc = SourceLocation());
+ /// 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);
+
+ /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
+ void AddFactoryMethodToGlobalPool(ObjcMethodDecl *Method);
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks: SemaStmt.cpp.
public:
diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp
index 472df150e8..ef99564dac 100644
--- a/Sema/SemaDecl.cpp
+++ b/Sema/SemaDecl.cpp
@@ -1754,6 +1754,52 @@ bool Sema:: MatchTwoMethodDeclarations(const ObjcMethodDecl *Method,
return true;
}
+void Sema::AddInstanceMethodToGlobalPool(ObjcMethodDecl *Method) {
+ ObjcMethodList &FirstMethod = InstanceMethodPool[Method->getSelector()];
+ if (!FirstMethod.Method) {
+ // Haven't seen a method with this selector name yet - add it.
+ FirstMethod.Method = Method;
+ FirstMethod.Next = 0;
+ } else {
+ // We've seen a method with this name, now check the type signature(s).
+ bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method);
+
+ for (ObjcMethodList *Next = FirstMethod.Next; !match && Next;
+ Next = Next->Next)
+ match = MatchTwoMethodDeclarations(Method, Next->Method);
+
+ if (!match) {
+ // We have a new signature for an existing method - add it.
+ // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
+ struct ObjcMethodList *OMI = new ObjcMethodList(Method, FirstMethod.Next);
+ FirstMethod.Next = OMI;
+ }
+ }
+}
+
+void Sema::AddFactoryMethodToGlobalPool(ObjcMethodDecl *Method) {
+ ObjcMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()];
+ if (!FirstMethod.Method) {
+ // Haven't seen a method with this selector name yet - add it.
+ FirstMethod.Method = Method;
+ FirstMethod.Next = 0;
+ } else {
+ // We've seen a method with this name, now check the type signature(s).
+ bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method);
+
+ for (ObjcMethodList *Next = FirstMethod.Next; !match && Next;
+ Next = Next->Next)
+ match = MatchTwoMethodDeclarations(Method, Next->Method);
+
+ if (!match) {
+ // We have a new signature for an existing method - add it.
+ // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
+ struct ObjcMethodList *OMI = new ObjcMethodList(Method, FirstMethod.Next);
+ FirstMethod.Next = OMI;
+ }
+ }
+}
+
void Sema::ActOnAddMethodsToObjcDecl(Scope* S, DeclTy *classDecl,
DeclTy **allMethods, unsigned allNum) {
Decl *ClassDecl = static_cast<Decl *>(classDecl);
@@ -1777,6 +1823,7 @@ void Sema::ActOnAddMethodsToObjcDecl(Scope* S, DeclTy *classDecl,
for (unsigned i = 0; i < allNum; i++ ) {
ObjcMethodDecl *Method =
cast_or_null<ObjcMethodDecl>(static_cast<Decl*>(allMethods[i]));
+
if (!Method) continue; // Already issued a diagnostic.
if (Method->isInstance()) {
if (checkDuplicateMethods) {
@@ -1786,16 +1833,17 @@ void Sema::ActOnAddMethodsToObjcDecl(Scope* S, DeclTy *classDecl,
Diag(Method->getLocation(), diag::error_duplicate_method_decl,
Method->getSelector().getName());
Diag(PrevMethod->getLocation(), diag::err_previous_declaration);
- }
- else {
+ } else {
insMethods.push_back(Method);
InsMap[Method->getSelector()] = Method;
}
}
else
insMethods.push_back(Method);
- }
- else {
+
+ /// The following allows us to typecheck messages to "id".
+ AddInstanceMethodToGlobalPool(Method);
+ } else {
if (checkDuplicateMethods) {
/// Check for class method of the same name with incompatible types
const ObjcMethodDecl *&PrevMethod = ClsMap[Method->getSelector()];
@@ -1803,14 +1851,16 @@ void Sema::ActOnAddMethodsToObjcDecl(Scope* S, DeclTy *classDecl,
Diag(Method->getLocation(), diag::error_duplicate_method_decl,
Method->getSelector().getName());
Diag(PrevMethod->getLocation(), diag::err_previous_declaration);
- }
- else {
+ } else {
clsMethods.push_back(Method);
ClsMap[Method->getSelector()] = Method;
}
}
else
clsMethods.push_back(Method);
+
+ /// The following allows us to typecheck messages to "id".
+ AddFactoryMethodToGlobalPool(Method);
}
}
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 509e0a2813..2113871f39 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -85,6 +85,8 @@ public:
virtual void DeleteExpr(ExprTy *E) {}
virtual void DeleteStmt(StmtTy *E) {}
+ /// Statistics.
+ virtual void PrintStats() const {}
//===--------------------------------------------------------------------===//
// Declaration Tracking Callbacks.
//===--------------------------------------------------------------------===//