diff options
Diffstat (limited to 'cpp/src/Slice/ObjCUtil.cpp')
-rw-r--r-- | cpp/src/Slice/ObjCUtil.cpp | 1204 |
1 files changed, 1204 insertions, 0 deletions
diff --git a/cpp/src/Slice/ObjCUtil.cpp b/cpp/src/Slice/ObjCUtil.cpp new file mode 100644 index 00000000000..cc3abd3b08b --- /dev/null +++ b/cpp/src/Slice/ObjCUtil.cpp @@ -0,0 +1,1204 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <Slice/ObjCUtil.h> +#include <Slice/Util.h> +#include <IceUtil/Functional.h> +#include <IceUtil/StringUtil.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <direct.h> +#endif + +#ifndef _WIN32 +#include <unistd.h> +#endif + +using namespace std; +using namespace Slice; +using namespace IceUtil; +using namespace IceUtilInternal; + +Slice::ObjCGenerator::ModuleMap Slice::ObjCGenerator::_modules; + +static string +lookupKwd(const string& name, int baseType, bool mangleCasts = false) +{ + // + // All lists in this method *must* be kept in case-insensitive + // alphabetical order. + // + static string keywordList[] = + { + "auto", "BOOL", "break", "bycopy", "byref", "case", "char", "const", "continue", + "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", + "id", "if", "IMP", "in", "inline", "inout", "int", "long", "nil", "NO", "oneway", "out", + "register", "return", "SEL", "self", "short", "signed", "sizeof", "static", "struct", "super", "switch", + "typedef", "union", "unsigned", "void", "volatile", "while", "YES" + }; + + static string nsObjectList[] = + { + "autorelease", "class", "classForCoder", "copy", "dealloc", "description", "hash", "init", "isa", + "isProxy", "mutableCopy", "release", "retain", "retainCount", "superclass", "zone" + }; + static string nsExceptionList[] = + { + "callStackReturnAddresses", "name", "raise", "reason", "reserved", "userInfo", + }; + + bool found = binary_search(&keywordList[0], + &keywordList[sizeof(keywordList) / sizeof(*keywordList)], + name, + Slice::CICompare()); + if(!found) + { + switch(baseType) + { + case BaseTypeNone: + break; + + case BaseTypeException: + found = binary_search(&nsExceptionList[0], + &nsExceptionList[sizeof(nsExceptionList) / sizeof(*nsExceptionList)], + name, + Slice::CICompare()); + if(found) + { + break; + } + + case BaseTypeObject: + found = binary_search(&nsObjectList[0], + &nsObjectList[sizeof(nsObjectList) / sizeof(*nsObjectList)], + name, + Slice::CICompare()); + break; + } + } + if(found || (mangleCasts && (name == "checkedCast" || name == "uncheckedCast"))) + { + return name + "_"; + } + return name; +} + +bool +Slice::ObjCGenerator::addModule(const ModulePtr& m, const string& name) +{ + string scoped = m->scoped(); + ModuleMap::const_iterator i = _modules.find(scoped); + if(i != _modules.end()) + { + if(i->second.name != name) + { + return false; + } + } + else + { + ModulePrefix mp; + mp.m = m; + mp.name = name; + _modules[scoped] = mp; + } + return true; +} + +Slice::ObjCGenerator::ModulePrefix +Slice::ObjCGenerator::modulePrefix(const ModulePtr& m) +{ + return _modules[m->scoped()]; +} + +string +Slice::ObjCGenerator::moduleName(const ModulePtr& m) +{ + return _modules[m->scoped()].name; +} + +ModulePtr +Slice::ObjCGenerator::findModule(const ContainedPtr& cont, int baseTypes, bool mangleCasts) +{ + ModulePtr m = ModulePtr::dynamicCast(cont); + ContainerPtr container = cont->container(); + while(container && !m) + { + ContainedPtr contained = ContainedPtr::dynamicCast(container); + container = contained->container(); + m = ModulePtr::dynamicCast(contained); + } + assert(m); + return m; +} + +// +// If the passed name is a scoped name, return the identical scoped +// name, but with all components that are Objective-C keywords +// replaced by their prefixed version; otherwise, if the passed name +// is not scoped, but an Objective-C keyword, return the prefixed +// name; otherwise, check if the name is one of the method names of +// baseTypes; if so, returned the prefixed name; otherwise, return the +// name unchanged. +// +string +Slice::ObjCGenerator::fixId(const string& name, int baseTypes, bool mangleCasts) +{ + if(name.empty()) + { + return name; + } + return lookupKwd(name, baseTypes, mangleCasts); +} + +string +Slice::ObjCGenerator::fixId(const ContainedPtr& cont, int baseTypes, bool mangleCasts) +{ + return fixId(cont->name(), baseTypes, mangleCasts); +} + +string +Slice::ObjCGenerator::fixName(const ContainedPtr& cont, int baseTypes, bool mangleCasts) +{ + return moduleName(findModule(cont, baseTypes, mangleCasts)) + cont->name(); +} + +string +Slice::ObjCGenerator::typeToString(const TypePtr& type) +{ + if(!type) + { + return "void"; + } + + static const char* builtinTable[] = + { + "ICEByte", + "BOOL", + "ICEShort", + "ICEInt", + "ICELong", + "ICEFloat", + "ICEDouble", + "NSString", + "ICEObject", + "id<ICEObjectPrx>", + "id" // Dummy--we don't support Slice local Object + }; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + return builtinTable[builtin->kind()]; + } + + ProxyPtr proxy = ProxyPtr::dynamicCast(type); + if(proxy) + { + string mName = moduleName(findModule(proxy->_class())); + return "id<" + mName + (proxy->_class()->name()) + "Prx>"; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + return fixName(seq); + } + + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(d) + { + return fixName(d); + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl && cl->isInterface()) + { + return "ICEObject"; + } + + ContainedPtr contained = ContainedPtr::dynamicCast(type); + if(contained) + { + return fixName(contained); + } + + return "???"; +} + +string +Slice::ObjCGenerator::inTypeToString(const TypePtr& type, bool optional, bool autoreleasing, bool reference) +{ + string s; + if(optional) + { + s = "id"; + } + else + { + s = typeToString(type); + if(mapsToPointerType(type)) + { + s += "*"; + } + } + if(autoreleasing && !isValueType(type)) + { + s += " ICE_AUTORELEASING_QUALIFIER"; + } + if(reference) + { + s += "*"; + } + return s; +} + +string +Slice::ObjCGenerator::outTypeToString(const TypePtr& type, bool optional, bool autoreleasing, bool reference) +{ + if(!type) + { + return "void"; + } + + string s; + if(optional) + { + s = "id"; + } + else + { + SequencePtr seq = SequencePtr::dynamicCast(type); + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(isString(type)) + { + s = "NSMutableString"; + } + else if(seq) + { + string prefix = moduleName(findModule(seq)); + s = prefix + "Mutable" + seq->name(); + } + else if(d) + { + string prefix = moduleName(findModule(d)); + s = prefix + "Mutable" + d->name(); + } + else + { + s = typeToString(type); + } + if(mapsToPointerType(type)) + { + s += "*"; + } + } + if(autoreleasing && !isValueType(type)) + { + s += " ICE_AUTORELEASING_QUALIFIER"; + } + if(reference) + { + s += "*"; + } + return s; +} + +string +Slice::ObjCGenerator::typeToObjCTypeString(const TypePtr& type) +{ + ProxyPtr proxy = ProxyPtr::dynamicCast(type); + if(proxy) + { + return moduleName(findModule(proxy->_class())) + (proxy->_class()->name()) + "Prx"; + } + else + { + return typeToString(type); + } +} + +bool +Slice::ObjCGenerator::isValueType(const TypePtr& type) +{ + if(!type) + { + return true; + } + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + { + return false; + break; + } + default: + { + return true; + break; + } + } + } + if(EnumPtr::dynamicCast(type)) + { + return true; + } + return false; +} + +bool +Slice::ObjCGenerator::isString(const TypePtr& type) +{ + if(!type) + { + return false; + } + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + return builtin && builtin->kind() == Builtin::KindString; +} +bool +Slice::ObjCGenerator::isClass(const TypePtr& type) +{ + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + return builtin->kind() == Builtin::KindObject; + } + return ClassDeclPtr::dynamicCast(type); +} + +bool +Slice::ObjCGenerator::mapsToPointerType(const TypePtr& type) +{ + if(isValueType(type)) + { + return false; + } + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + return builtin->kind() != Builtin::KindObjectProxy; + } + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl && cl->isInterface()) + { + return true; + } + return !ProxyPtr::dynamicCast(type); +} + +string +Slice::ObjCGenerator::getBuiltinName(const BuiltinPtr& builtin) +{ + switch(builtin->kind()) + { + case Builtin::KindByte: + { + return "Byte"; + } + case Builtin::KindBool: + { + return "Bool"; + } + case Builtin::KindShort: + { + return "Short"; + } + case Builtin::KindInt: + { + return "Int"; + } + case Builtin::KindLong: + { + return "Long"; + } + case Builtin::KindFloat: + { + return "Float"; + } + case Builtin::KindDouble: + { + return "Double"; + } + case Builtin::KindString: + { + return "String"; + } + case Builtin::KindObject: + { + return "Object"; + } + case Builtin::KindObjectProxy: + { + return "Proxy"; + } + default: + { + assert(false); + } + } + return "NO__SUCH__TYPE"; +} + +string +Slice::ObjCGenerator::getOptionalHelperGetter(const TypePtr& type) +{ + if(isValueType(type)) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + return "get" + getBuiltinName(builtin); + } + if(EnumPtr::dynamicCast(type)) + { + return "getInt"; + } + } + return "get"; +} + +// +// Split a scoped name into its components and return the components as a list of (unscoped) identifiers. +// +StringList +Slice::ObjCGenerator::splitScopedName(const string& scoped) +{ + assert(scoped[0] == ':'); + StringList ids; + string::size_type next = 0; + string::size_type pos; + while((pos = scoped.find("::", next)) != string::npos) + { + pos += 2; + if(pos != scoped.size()) + { + string::size_type endpos = scoped.find("::", pos); + if(endpos != string::npos) + { + ids.push_back(scoped.substr(pos, endpos - pos)); + } + } + next = pos; + } + if(next != scoped.size()) + { + ids.push_back(scoped.substr(next)); + } + else + { + ids.push_back(""); + } + + return ids; +} + +string +Slice::ObjCGenerator::getOptionalFormat(const TypePtr& type) +{ + BuiltinPtr bp = BuiltinPtr::dynamicCast(type); + if(bp) + { + switch(bp->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + { + return "ICEOptionalFormatF1"; + } + case Builtin::KindShort: + { + return "ICEOptionalFormatF2"; + } + case Builtin::KindInt: + case Builtin::KindFloat: + { + return "ICEOptionalFormatF4"; + } + case Builtin::KindLong: + case Builtin::KindDouble: + { + return "ICEOptionalFormatF8"; + } + case Builtin::KindString: + { + return "ICEOptionalFormatVSize"; + } + case Builtin::KindObject: + { + return "ICEOptionalFormatClass"; + } + case Builtin::KindObjectProxy: + { + return "ICEOptionalFormatFSize"; + } + case Builtin::KindLocalObject: + { + assert(false); + break; + } + } + } + + if(EnumPtr::dynamicCast(type)) + { + return "ICEOptionalFormatSize"; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + return seq->type()->isVariableLength() ? "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize"; + } + + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(d) + { + return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ? + "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize"; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + return st->isVariableLength() ? "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize"; + } + + if(ProxyPtr::dynamicCast(type)) + { + return "ICEOptionalFormatFSize"; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + assert(cl); + return "ICEOptionalFormatClass"; +} + +void +Slice::ObjCGenerator::writeMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param, + bool marshal, bool autoreleased) const +{ + string stream = marshal ? "os_" : "is_"; + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + + if(builtin) + { + string name; + if(builtin->kind() == Builtin::KindObject) + { + if(marshal) + { + out << nl << "[" << stream << " writeObject:" << param << "];"; + } + else + { + if(autoreleased) + { + out << nl << "[" << stream << " readObject:&" << param << "];"; + } + else + { + out << nl << "[" << stream << " newObject:&" << param << "];"; + } + } + } + else if(builtin->kind() == Builtin::KindObjectProxy) + { + if(marshal) + { + out << nl << "[" << stream << " writeProxy:" << param << "];"; + } + else + { + if(autoreleased) + { + out << nl << param << " = [" << stream << " readProxy:[ICEObjectPrx class]];"; + } + else + { + out << nl << param << " = [" << stream << " newProxy:[ICEObjectPrx class]];"; + } + } + } + else + { + if(marshal) + { + out << nl << "[" << stream << " write" << getBuiltinName(builtin) << ":" << param << "];"; + } + else + { + if(autoreleased || isValueType(builtin)) + { + out << nl << param << " = [" << stream << " read" << getBuiltinName(builtin) << "];"; + } + else + { + out << nl << param << " = [" << stream << " new" << getBuiltinName(builtin) << "];"; + } + } + } + return; + } + + ProxyPtr prx = ProxyPtr::dynamicCast(type); + if(prx) + { + if(marshal) + { + out << nl << "[" << stream << " writeProxy:(id<ICEObjectPrx>)" << param << "];"; + } + else + { + string name = moduleName(findModule(prx->_class())) + prx->_class()->name() + "Prx"; + out << nl << param << " = (id<" << name << ">)[" << stream; + if(autoreleased) + { + out << " readProxy:"; + } + else + { + out << " newProxy:"; + } + // + // We use objc_getClass to get the proxy class instead of [name class]. This is to avoid + // a warning if the proxy is forward declared. + // + if(prx->_class()->definition()) + { + out << "[" << name << " class]];"; + } + else + { + out << "objc_getClass(\"" << name << "\")];"; + } + } + return; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl) + { + if(marshal) + { + // Cast avoids warning for forward-declared classes. + out << nl << "[" << stream << " writeObject:(ICEObject*)" << param << "];"; + } + else + { + if(autoreleased) + { + out << nl << "[" << stream << " " << "readObject:(ICEObject**)&" << param; + } + else + { + out << nl << "[" << stream << " " << "newObject:(ICEObject**)&" << param; + } + + if(cl->isInterface()) + { + out << "];"; + } + else + { + string name = moduleName(findModule(cl)) + cl->name(); + if(cl->definition()) + { + out << " expectedType:[" << name << " class]];"; + } + else + { + out << " expectedType:objc_getClass(\"" << name << "\")];"; + } + } + } + return; + } + + EnumPtr en = EnumPtr::dynamicCast(type); + if(en) + { + if(marshal) + { + out << nl << "[" << stream << " writeEnumerator:" << param << " min:" << en->minValue() + << " max:" << en->maxValue() << "];"; + } + else + { + out << nl << param << " = " << "[" << stream << " readEnumerator:" << en->minValue() + << " max:" << en->maxValue() << "];"; + } + return; + } + + ContainedPtr c = ContainedPtr::dynamicCast(type); + assert(c); + string name = moduleName(findModule(c)) + c->name() + "Helper"; + if(marshal) + { + out << nl << "[" + name << " write:" << param << " stream:" << stream << "];"; + } + else + { + if(autoreleased) + { + out << nl << param << " = [" << name << " read:" << stream << "];"; + } + else + { + out << nl << param << " = [" << name << " readRetained:" << stream << "];"; + } + } +} + +void +Slice::ObjCGenerator::writeOptMemberMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param, + bool marshal) const +{ + string stream = marshal ? "os_" : "is_"; + string optionalHelper; + string helper; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + if(builtin->kind() == Builtin::KindObjectProxy) + { + optionalHelper = "ICEVarLengthOptionalHelper"; + helper = "[ICEProxyHelper class]"; + } + else + { + writeMarshalUnmarshalCode(out, type, param, marshal, false); + return; + } + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl) + { + writeMarshalUnmarshalCode(out, type, param, marshal, false); + return; + } + + EnumPtr en = EnumPtr::dynamicCast(type); + if(en) + { + writeMarshalUnmarshalCode(out, type, param, marshal, false); + return; + } + + ProxyPtr prx = ProxyPtr::dynamicCast(type); + if(prx) + { + optionalHelper = "ICEVarLengthOptionalHelper"; + helper = "objc_getClass(\"" + moduleName(findModule(prx->_class())) + prx->_class()->name() + "PrxHelper\")"; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + if(st->isVariableLength()) + { + optionalHelper = "ICEVarLengthOptionalHelper"; + } + else + { + optionalHelper = "ICEFixedLengthOptionalHelper"; + } + helper = "[" + typeToString(st) + "Helper class]"; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + TypePtr element = seq->type(); + if(element->isVariableLength()) + { + optionalHelper = "ICEVarLengthOptionalHelper"; + } + else if(element->minWireSize() == 1) + { + writeMarshalUnmarshalCode(out, type, param, marshal, false); + return; + } + else + { + optionalHelper = "ICEFixedSequenceOptionalHelper"; + } + helper = "[" + moduleName(findModule(seq)) + seq->name() + "Helper class]"; + } + + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(d) + { + if(d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) + { + optionalHelper = "ICEVarLengthOptionalHelper"; + } + else + { + optionalHelper = "ICEFixedDictionaryOptionalHelper"; + } + helper = "[" + moduleName(findModule(d)) + d->name() + "Helper class]"; + } + + out << nl; + if(marshal) + { + out << "[" << optionalHelper << " write:" << param << " stream:" << stream << " helper:" << helper << "];"; + } + else + { + out << param << " = [" << optionalHelper << " readRetained:" << stream << " helper:" << helper << "];"; + } + +} + +void +Slice::ObjCGenerator::writeOptParamMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param, + int tag, bool marshal) const +{ + string helper; + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + ProxyPtr proxy = ProxyPtr::dynamicCast(type); + if(builtin) + { + helper = "ICE" + getBuiltinName(builtin) + "Helper"; + } + else if(proxy) + { + helper = moduleName(findModule(proxy->_class())) + (proxy->_class()->name()) + "PrxHelper"; + } + else + { + helper = typeToString(type) + "Helper"; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl) + { + out << nl; + if(marshal) + { + out << "[" << helper << " writeOpt:" << param << " stream:os_ tag:" << tag << "];"; + } + else + { + out << "[" << helper << " readOpt:&" << param << " stream:is_ tag:" << tag << "];"; + } + return; + } + + out << nl; + if(marshal) + { + out << "[" << helper << " writeOpt:" << param << " stream:os_ tag:" << tag << "];"; + } + else + { + out << param << " = [" << helper << " readOpt:is_ tag:" << tag << "];"; + } +} + +void +Slice::ObjCGenerator::validateMetaData(const UnitPtr& u) +{ + MetaDataVisitor visitor; + u->visit(&visitor, true); +} + +const string Slice::ObjCGenerator::MetaDataVisitor::_objcPrefix = "objc:"; +const string Slice::ObjCGenerator::MetaDataVisitor::_msg = "ignoring invalid metadata"; + +Slice::ObjCGenerator::MetaDataVisitor::MetaDataVisitor() +{ +} + +bool +Slice::ObjCGenerator::MetaDataVisitor::visitUnitStart(const UnitPtr& p) +{ + // + // Validate global metadata in the top-level file and all included files. + // + StringList files = p->allFiles(); + + for(StringList::iterator q = files.begin(); q != files.end(); ++q) + { + string file = *q; + DefinitionContextPtr dc = p->findDefinitionContext(file); + assert(dc); + StringList globalMetaData = dc->getMetaData(); + int headerDir = 0; + for(StringList::const_iterator r = globalMetaData.begin(); r != globalMetaData.end(); ++r) + { + string s = *r; + if(_history.count(s) == 0) + { + if(s.find(_objcPrefix) == 0) + { + static const string objcHeaderDirPrefix = "objc:header-dir:"; + if(s.find(objcHeaderDirPrefix) == 0 && s.size() > objcHeaderDirPrefix.size()) + { + headerDir++; + if(headerDir > 1) + { + ostringstream ostr; + ostr << "ignoring invalid global metadata `" << s + << "': directive can appear only once per file"; + emitWarning(file, -1, ostr.str()); + _history.insert(s); + } + continue; + } + ostringstream ostr; + ostr << "ignoring invalid global metadata `" << s << "'"; + emitWarning(file, -1, ostr.str()); + } + _history.insert(s); + } + } + } + + return true; +} + +bool +Slice::ObjCGenerator::MetaDataVisitor::visitModuleStart(const ModulePtr& p) +{ + validate(p); + return true; +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitModuleEnd(const ModulePtr&) +{ +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitClassDecl(const ClassDeclPtr& p) +{ + validate(p); +} + +bool +Slice::ObjCGenerator::MetaDataVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + validate(p); + return true; +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitClassDefEnd(const ClassDefPtr&) +{ +} + +bool +Slice::ObjCGenerator::MetaDataVisitor::visitExceptionStart(const ExceptionPtr& p) +{ + validate(p); + return true; +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitExceptionEnd(const ExceptionPtr&) +{ +} + +bool +Slice::ObjCGenerator::MetaDataVisitor::visitStructStart(const StructPtr& p) +{ + validate(p); + return true; +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitStructEnd(const StructPtr&) +{ +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitOperation(const OperationPtr& p) +{ + if(p->hasMetaData("UserException")) + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container()); + if(!cl->isLocal()) + { + ostringstream os; + os << "ignoring invalid metadata `UserException': directive applies only to local operations " + << ": warning: metadata directive `UserException' applies only to local operations " + << "but enclosing " << (cl->isInterface() ? "interface" : "class") << "`" << cl->name() + << "' is not local"; + emitWarning(p->file(), p->line(), os.str()); + } + } + validate(p); +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitParamDecl(const ParamDeclPtr& p) +{ + validate(p); +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitDataMember(const DataMemberPtr& p) +{ + validate(p); +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitSequence(const SequencePtr& p) +{ + validate(p); +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitDictionary(const DictionaryPtr& p) +{ + validate(p); +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitEnum(const EnumPtr& p) +{ + validate(p); +} + +void +Slice::ObjCGenerator::MetaDataVisitor::visitConst(const ConstPtr& p) +{ + validate(p); +} + +void +Slice::ObjCGenerator::MetaDataVisitor::validate(const ContainedPtr& cont) +{ + ModulePtr m = ModulePtr::dynamicCast(cont); + if(m) + { + bool error = false; + bool foundPrefix = false; + + StringList meta = getMetaData(m); + StringList::const_iterator p; + + for(p = meta.begin(); p != meta.end(); ++p) + { + const string prefix = "prefix:"; + string name; + if(p->substr(_objcPrefix.size(), prefix.size()) == prefix) + { + foundPrefix = true; + name = trim(p->substr(_objcPrefix.size() + prefix.size())); + if(name.empty()) + { + if(_history.count(*p) == 0) + { + string file = m->definitionContext()->filename(); + ostringstream os; + os << _msg << " `" << *p << "'" << endl; + emitWarning(file, m->line(), os.str()); + _history.insert(*p); + } + error = true; + } + else + { + if(!addModule(m, name)) + { + modulePrefixError(m, *p); + } + } + } + else + { + if(_history.count(*p) == 0) + { + string file = m->definitionContext()->filename(); + ostringstream os; + os << _msg << " `" << *p << "'" << endl; + emitWarning(file, m->line(), os.str()); + _history.insert(*p); + } + error = true; + } + } + + if(!error && !foundPrefix) + { + StringList names = splitScopedName(m->scoped()); + string name; + for(StringList::const_iterator i = names.begin(); i != names.end(); ++i) + { + name += *i; + } + if(!addModule(m, name)) + { + modulePrefixError(m, ""); + } + } + } +} + +StringList +Slice::ObjCGenerator::MetaDataVisitor::getMetaData(const ContainedPtr& cont) +{ + StringList ret; + StringList localMetaData = cont->getMetaData(); + StringList::const_iterator p; + + for(p = localMetaData.begin(); p != localMetaData.end(); ++p) + { + if(p->find(_objcPrefix) != string::npos) + { + ret.push_back(*p); + } + } + + return ret; +} + +void +Slice::ObjCGenerator::MetaDataVisitor::modulePrefixError(const ModulePtr& m, const string& metadata) +{ + string file = m->definitionContext()->filename(); + string line = m->line(); + ModulePrefix mp = modulePrefix(m); + string old_file = mp.m->definitionContext()->filename(); + string old_line = mp.m->line(); + ostringstream os; + if(!metadata.empty()) + { + os << _msg << " `" << metadata << "': "; + } + os << "inconsistent module prefix previously defined "; + if(old_file != file) + { + os << "in " << old_file << ":"; + } + else + { + os << "at line "; + } + os << line; + os << " as `" << mp.name << "'" << endl; + emitWarning(file, line, os.str()); +} + |