From: Steve Naroff Date: Sun, 14 Oct 2007 00:58:41 +0000 (+0000) Subject: - Added Sema::AddFactoryMethodToGlobalPool and Sema::AddInstanceMethodToGlobalPool... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=58ff9e8f06a88b74c093d67983c9a1808da1001c;p=clang - Added Sema::AddFactoryMethodToGlobalPool and Sema::AddInstanceMethodToGlobalPool and DenseMaps. This will allow us to efficiently lookup a method from a selector given no type information (for the "id" data type). - Fixed some funky "} else {" indentation in Sema::ActOnAddMethodsToObjcDecl(). I'd prefer we stay away from this style...it wastes space and isn't any easier to read (from my perspective, at least:-) - Changed Parser::ParseObjCInterfaceDeclList() to only call Action::ActOnAddMethodsToObjcDecl() when it actually has methods to add (since most interface have methods, this is a very minor cleanup). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42957 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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 InstanceMethodPool; + llvm::DenseMap FactoryMethodPool; public: Sema(Preprocessor &pp, ASTContext &ctxt, std::vector &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(classDecl); @@ -1777,6 +1823,7 @@ void Sema::ActOnAddMethodsToObjcDecl(Scope* S, DeclTy *classDecl, for (unsigned i = 0; i < allNum; i++ ) { ObjcMethodDecl *Method = cast_or_null(static_cast(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. //===--------------------------------------------------------------------===//