/* st-inherit.cc: fill in class and interface environments with inherited members */ #include #include "AST.h" #include "MethodDecl.h" #include "StringSet.h" #include "compiler.h" #include "decls.h" #include "errors.h" // Returns true if newThrows is a "subset" of oldThrows (j8.4.4) static bool throwsSubset(TreeNode *newThrows, TreeNode *oldThrows) { foriter (newExc, newThrows->allTypes(), TreeNode::TypeIter) { bool found = false; Decl *newExcDecl = (*newExc)->decl(); // Look for an exception in oldThrows that is a superclass of // newExc foriter (oldExc, oldThrows->allTypes(), TreeNode::TypeIter) // Is this right ? Or should it be isSubClass || isSuperInterface ? //if ((*oldExc)->isAssignableFromType((*newExc))) if (isSubClass(newExcDecl, (*oldExc)->decl())) { found = true; break; } if (!found) return false; } return true; } /* True if MEMBER would be hidden or overridden by a declaration in */ /* TO. */ static bool overriddenIn (Decl* member, Decl *to) { Environ *env = to->environ(); if (member->category() == Decl::Field) { Decl *current = env->lookupProper (member->name(), Decl::Field); // Only definitions in the destination environment override fields // If multiple definitions are inherited, a compile-time error // must be reported for any use (this is achieved by letting the // environment contain multiple copies of the field, which will // produce an ambiguous reference error in the name lookup) // But: multiple inheritances of the *same* field only count once return current != NULL && (current->container() == to || member == current); } else { foriter (d, env->lookupFirstProper (member->name(), Decl::Method), EnvironIter) { assert( d->category() == Decl::Method ); TypeNode *dtype = d->type(); TypeNode *mtype = member->type(); if (dtype->methodsConflict(mtype)) { // Note: member is overriden method, d is overriding method if (&*d == member) return true; // seeing the same thing twice bool isLocalDecl = d->container() == to; SourcePosn p = isLocalDecl ? d->source()->position() : to->source()->position(); Common::Modifiers dm = d->modifiers(); Common::Modifiers mm = member->modifiers(); // Note: if !isLocalDecl, then the method necessarily comes // from an interface (i.e. is abstract). If d is also abstract, // then all methods are inherited (j8.4.6.4). bool inheritAllAbstract = !isLocalDecl && (dm & Common::Abstract); if (!dtype->returnType()->typeIdent(mtype->returnType())) Error(p) << "overriding of " << member->errorName() << " changes return type" << endl; if (!dtype->paramTypes()->singleArgsIdent(mtype->paramTypes())) Error(p) << "overriding of " << member->errorName() << " changes 'single' argument declarations" << endl; #ifndef SGLOBAL_INFERENCE if ((dm & Common::Sglobal) != (mm & Common::Sglobal)) Error(p) << "overriding of " << member->errorName() << " adds/removes 'single'" << endl; #endif if ((dm & Common::Static) != (mm & Common::Static)) Error(p) << "overriding of " << member->errorName() << " adds/removes 'static'" << endl; // make sure d was a legal override/hide of member if (mm & Common::Final) Error(p) << "cannot override final " << member->errorName() << endl; if ((mm & Common::Public) && !(dm & Common::Public) || (mm & Common::Protected) && !(dm & (Common::Public | Common::Protected)) || !(mm & (Common::Public | Common::Protected)) && (dm & Common::Private)) Error(p) << "overriding of " << member->errorName() << " must provide at least as much access" << endl; if (!inheritAllAbstract && !throwsSubset(d->type()->throws(), member->type()->throws())) Error(p) << d->errorName() << " throws more exceptions than overriden " << member->errorName() << endl; // update overriding/hiding information for declarations of 'to' if (isLocalDecl) { member->overriders((MethodDecl *)&*d); switch (member->container()->category()) { case Decl::Class: d->overrides( member ); break; case Decl::Interface: assert( member->category() == Decl::Method ); d->implements( static_cast< MethodDecl * >( member ) ); break; } } return !inheritAllAbstract; } } return false; } } /* Given ClassDecls TO and FROM, add to *TO->environ() the members */ /* that TO inherits from FROM. */ void fillInInheritedMembers (Decl* to, Decl* from) { // make sure 'from' is filled in if (from->source() && !from->source()->absent()) from->source()->resolveInheritance(); foriter (member, from->environ()->allProperDecls(), EnvironIter) if ((member->category() & (Decl::Field | Decl::Method)) != 0 && ((member->modifiers() & Common::Private) == 0) && ! overriddenIn (&*member, to)) to->environ()->add (&*member); } /* Static analysis, phase 2b: fill in class and interface environments with inherited members */ void TreeNode::resolveInheritance() { undefined("resolveInheritance"); } void CompileUnitNode::resolveInheritance() { foriter (type, types()->allChildren(), ChildIter) (*type)->resolveInheritance(); } void TemplateDeclNode::resolveInheritance() { } static const StringSet abstractMethods(TreeNode *classNode) { Environ *classEnv = classNode->decl()->environ(); StringSet methods; // check for abstract methods foriter (member, classEnv->allProperDecls(), EnvironIter) if ((member->category() & Decl::Method) && (member->modifiers() & Common::Abstract)) methods.insert(member->errorName()); return methods; } void ClassDeclNode::resolveInheritance() { Decl* me = decl(); if (me->visits > 1) return; me->visits = 2; if (!(flags() & Immutable)) { fillInInheritedMembers(me, me->superClass()); foriter (interface, elements(me->interfaces()), ListIterator) fillInInheritedMembers(me, *interface); if (me->superClass()->modifiers() & Final) error() << "final or immutable class " << me->superClass()->errorName() << " cannot be extended" << endl; } if ((flags() & (Final | Abstract)) == (Final | Abstract)) error() << "a class cannot be final and abstract" << endl; if (!(flags() & Abstract)) { const StringSet methods = abstractMethods(this); if (!methods.empty()) { error() << me->errorName() << " has abstract methods: must be declared abstract" << endl; for (StringSet::const_iterator method = methods.begin(); method != methods.end(); ++method) message() << *method << " is abstract" << endl; } } } void InterfaceDeclNode::resolveInheritance() { Decl* me = decl(); if (me->visits > 1) return; me->visits = 2; foriter (interface, elements (me->interfaces()), ListIterator) fillInInheritedMembers(me, *interface); }