diff options
Diffstat (limited to 'cpp/src')
-rw-r--r-- | cpp/src/slice2cs/Gen.cpp | 629 | ||||
-rw-r--r-- | cpp/src/slice2cs/Gen.h | 18 | ||||
-rw-r--r-- | cpp/src/slice2cs/Main.cpp | 2 |
3 files changed, 631 insertions, 18 deletions
diff --git a/cpp/src/slice2cs/Gen.cpp b/cpp/src/slice2cs/Gen.cpp index d075d8a7d47..cb182b01588 100644 --- a/cpp/src/slice2cs/Gen.cpp +++ b/cpp/src/slice2cs/Gen.cpp @@ -9,6 +9,7 @@ #include <IceUtil/DisableWarnings.h> #include <IceUtil/Functional.h> +#include <IceUtil/StringUtil.h> #include <Gen.h> #include <limits> #include <sys/stat.h> @@ -39,6 +40,7 @@ using IceUtilInternal::sb; using IceUtilInternal::eb; using IceUtilInternal::spar; using IceUtilInternal::epar; +using IceUtilInternal::trim; static string // Should be an anonymous namespace, but VC++ 6 can't handle that. sliceModeToIceMode(Operation::Mode opMode) @@ -70,19 +72,30 @@ sliceModeToIceMode(Operation::Mode opMode) return mode; } -static void -emitDeprecate(const ContainedPtr& p1, const ContainedPtr& p2, Output& out, const string& type) +static string +getDeprecateReason(const ContainedPtr& p1, const ContainedPtr& p2, const string& type) { - string deprecateMetadata; + string deprecateMetadata, deprecateReason; if(p1->findMetaData("deprecate", deprecateMetadata) || (p2 != 0 && p2->findMetaData("deprecate", deprecateMetadata))) { - string deprecateReason = "This " + type + " has been deprecated."; - if(deprecateMetadata.find("deprecate:") == 0 && deprecateMetadata.size() > 10) + deprecateReason = "This " + type + " has been deprecated."; + const string prefix = "deprecate:"; + if(deprecateMetadata.find(prefix) == 0 && deprecateMetadata.size() > prefix.size()) { - deprecateReason = deprecateMetadata.substr(10); + deprecateReason = deprecateMetadata.substr(prefix.size()); } - out << nl << "[System.Obsolete(\"" << deprecateReason << "\")]"; + } + return deprecateReason; +} + +static void +emitDeprecate(const ContainedPtr& p1, const ContainedPtr& p2, Output& out, const string& type) +{ + string reason = getDeprecateReason(p1, p2, type); + if(!reason.empty()) + { + out << nl << "[System.Obsolete(\"" << reason << "\")]"; } } @@ -1054,6 +1067,553 @@ Slice::CsVisitor::writeValue(const TypePtr& type) return "null"; } +string +Slice::CsVisitor::toCsIdent(const string& s) +{ + string::size_type pos = s.find('#'); + if(pos == string::npos) + { + return s; + } + + string result = s; + if(pos == 0) + { + return result.erase(0, 1); + } + + result[pos] = '.'; + return result; +} + +string +Slice::CsVisitor::editMarkup(const string& s) +{ + // + // Strip HTML markup and javadoc links--VS doesn't display them. + // + string result = s; + string::size_type pos = 0; + do + { + pos = result.find('<', pos); + if(pos != string::npos) + { + string::size_type endpos = result.find('>', pos); + if(endpos != string::npos) + { + result.erase(pos, endpos - pos + 1); + } + } + } + while(pos != string::npos); + + const string link = "{@link"; + pos = 0; + do + { + pos = result.find(link, pos); + if(pos != string::npos) + { + result.erase(pos, link.size() + 1); // erase following white space too + string::size_type endpos = result.find('}', pos); + if(endpos != string::npos) + { + string ident = result.substr(pos, endpos - pos); + result.erase(pos, endpos - pos + 1); + result.insert(pos, toCsIdent(ident)); + } + } + } + while(pos != string::npos); + + // + // Strip @see sections because VS does not display them. + // + static const string seeTag = "@see"; + pos = 0; + do + { + // + // Look for the next @ and delete up to that, or + // to the end of the string, if not found. + // + pos = result.find(seeTag, pos); + if(pos != string::npos) + { + string::size_type next = result.find('@', pos + seeTag.size()); + if(next != string::npos) + { + result.erase(pos, next - pos); + } + else + { + result.erase(pos, string::npos); + } + } + } while(pos != string::npos); + + // + // Replace @param, @return, and @throws with corresponding <param>, <returns>, and <exception> tags. + // + static const string paramTag = "@param"; + pos = 0; + do + { + pos = result.find(paramTag, pos); + if(pos != string::npos) + { + result.erase(pos, paramTag.size() + 1); + + string::size_type startIdent = result.find_first_not_of(" \t", pos); + if(startIdent != string::npos) + { + string::size_type endIdent = result.find_first_of(" \t", startIdent); + if(endIdent != string::npos) + { + string ident = result.substr(startIdent, endIdent - startIdent); + string::size_type endComment = result.find('@', endIdent); + string comment = result.substr(endIdent + 1, + endComment == string::npos ? endComment : endComment - endIdent - 1); + result.erase(startIdent, endComment == string::npos ? string::npos : endComment - startIdent); + string newComment = "<param name=\"" + ident + "\">" + comment + "</param>\n"; + result.insert(startIdent, newComment); + pos = startIdent + newComment.size(); + } + } + else + { + pos += paramTag.size(); + } + } + } while(pos != string::npos); + + static const string returnTag = "@return"; + pos = result.find(returnTag); + if(pos != string::npos) + { + result.erase(pos, returnTag.size() + 1); + string::size_type endComment = result.find('@', pos); + string comment = result.substr(pos, endComment == string::npos ? endComment : endComment - pos); + result.erase(pos, endComment == string::npos ? string::npos : endComment - pos); + string newComment = "<returns>" + comment + "</returns>\n"; + result.insert(pos, newComment); + pos = pos + newComment.size(); + } + + static const string throwsTag = "@throws"; + pos = 0; + do + { + pos = result.find(throwsTag, pos); + if(pos != string::npos) + { + result.erase(pos, throwsTag.size() + 1); + + string::size_type startIdent = result.find_first_not_of(" \t", pos); + if(startIdent != string::npos) + { + string::size_type endIdent = result.find_first_of(" \t", startIdent); + if(endIdent != string::npos) + { + string ident = result.substr(startIdent, endIdent - startIdent); + string::size_type endComment = result.find('@', endIdent); + string comment = result.substr(endIdent + 1, + endComment == string::npos ? endComment : endComment - endIdent - 1); + result.erase(startIdent, endComment == string::npos ? string::npos : endComment - startIdent); + string newComment = "<exception name=\"" + ident + "\">" + comment + "</exception>\n"; + result.insert(startIdent, newComment); + pos = startIdent + newComment.size(); + } + } + else + { + pos += throwsTag.size(); + } + } + } while(pos != string::npos); + + return result; +} + +StringList +Slice::CsVisitor::splitIntoLines(const string& comment) +{ + string s = editMarkup(comment); + StringList result; + string::size_type pos = 0; + string::size_type nextPos; + while((nextPos = s.find_first_of('\n', pos)) != string::npos) + { + result.push_back(string(s, pos, nextPos - pos)); + pos = nextPos + 1; + } + string lastLine = string(s, pos); + if(lastLine.find_first_not_of(" \t\n\r") != string::npos) + { + result.push_back(lastLine); + } + return result; +} + +void +Slice::CsVisitor::splitComment(const ContainedPtr& p, StringList& summaryLines, StringList& remarksLines) +{ + string s = p->comment(); + string summary; + unsigned int i; + for(i = 0; i < s.size(); ++i) + { + if(s[i] == '.' && (i + 1 >= s.size() || isspace(static_cast<unsigned char>(s[i + 1])))) + { + summary += '.'; + ++i; + break; + } + else + { + summary += s[i]; + } + } + summaryLines = splitIntoLines(summary); + + if(!summaryLines.empty()) + { + remarksLines = splitIntoLines(trim(s.substr(i))); + } +} + + +void +Slice::CsVisitor::writeDocComment(const ContainedPtr& p, const string& deprecateReason, const string& extraParam) +{ + StringList summaryLines; + StringList remarksLines; + splitComment(p, summaryLines, remarksLines); + + if(summaryLines.empty()) + { + if(!deprecateReason.empty()) + { + _out << nl << "///"; + _out << nl << "/// <summary>" << deprecateReason << "</summary>"; + _out << nl << "///"; + } + return; + } + + _out << nl << "/// <summary>"; + + for(StringList::const_iterator i = summaryLines.begin(); i != summaryLines.end(); ++i) + { + _out << nl << "/// " << *i; + } + + // + // We generate everything into the summary tag (despite what the MSDN doc says) because + // Visual Studio only shows the <summary> text and omits the <remarks> text. + // + + if(!deprecateReason.empty()) + { + _out << nl << "///"; + _out << nl << "/// <para>" << deprecateReason << "</para>"; + _out << nl << "///"; + } + + bool summaryClosed = false; + + if(!remarksLines.empty()) + { + StringList::const_iterator i; + for(i = remarksLines.begin(); i != remarksLines.end(); ++i) + { + // + // The first param, returns, or exception tag ends the description. + // + static const string paramTag = "<param"; + static const string returnsTag = "<returns"; + static const string exceptionTag = "<exception"; + + if(!summaryClosed && + (i->find(paramTag) != string::npos || + i->find(returnsTag) != string::npos || + i->find(exceptionTag) != string::npos)) + { + _out << nl << "/// </summary>"; + _out << nl << "/// " << *i; + summaryClosed = true; + } + else + { + _out << nl << "/// " << *i; + } + } + } + + if(!summaryClosed) + { + _out << nl << "/// </summary>"; + } + + if(!extraParam.empty()) + { + _out << nl << "/// " << extraParam; + } + + _out << nl; +} + +void +Slice::CsVisitor::writeDocCommentOp(const OperationPtr& p) +{ + ContainerPtr container = p->container(); + ContainedPtr contained = ContainedPtr::dynamicCast(container); + string deprecateReason = getDeprecateReason(p, contained, "operation"); + + StringList summaryLines; + StringList remarksLines; + splitComment(p, summaryLines, remarksLines); + + if(summaryLines.empty()) + { + if(!deprecateReason.empty()) + { + _out << nl << "///"; + _out << nl << "/// <summary>" << deprecateReason << "</summary>"; + _out << nl << "///"; + } + return; + } + + _out << nl << "/// <summary>"; + + // + // Output the leading comment block up until the first <param>, <returns>, or <exception> tag. + // + for(StringList::const_iterator i = summaryLines.begin(); i != summaryLines.end(); ++i) + { + _out << nl << "/// " << *i; + } + + bool done = false; + for(StringList::const_iterator i = remarksLines.begin(); i != remarksLines.end() && !done; ++i) + { + if(i->find("<param") != string::npos || + i->find("<returns") != string::npos || + i->find("<exception") != string::npos) + { + done = true; + } + else + { + _out << nl << "/// " << *i; + } + } + + if(!deprecateReason.empty()) + { + _out << nl << "/// <para>" << deprecateReason << "</para>"; + } + + _out << nl << "/// </summary>"; +} + +void +Slice::CsVisitor::writeDocCommentAsync(const OperationPtr& p, ParamDir paramType, const string& extraParam) +{ + ContainerPtr container = p->container(); + ClassDefPtr contained = ClassDefPtr::dynamicCast(container); + string deprecateReason = getDeprecateReason(p, contained, "operation"); + + StringList summaryLines; + StringList remarksLines; + splitComment(p, summaryLines, remarksLines); + + if(summaryLines.empty() && deprecateReason.empty()) + { + return; + } + + + if(paramType == OutParam) + { + _out << nl << "/// <summary>"; + _out << nl << "/// ice_response indicates that"; + _out << nl << "/// the operation completed successfully."; + _out << nl << "/// </summary>"; + + // + // Find the comment for the return value (if any) and rewrite that as a <param> comment. + // + static const string returnsTag = "<returns>"; + bool doneReturn = false; + bool foundReturn = false; + for(StringList::const_iterator i = remarksLines.begin(); i != remarksLines.end() && !doneReturn; ++i) + { + if(!foundReturn) + { + string::size_type pos = i->find(returnsTag); + if(pos != string::npos) + { + pos += returnsTag.size(); + foundReturn = true; + string::size_type endpos = i->find('<', pos); + if(endpos != string::npos) + { + _out << nl << "/// <param name=\"ret__\">(return value) " << i->substr(pos, endpos - pos); + } + else + { + _out << nl << "/// <param name=\"ret__\">(return value) " << i->substr(pos); + } + } + } + else + { + string::size_type pos = i->find('<'); + if(pos != string::npos) + { + _out << nl << "/// " << i->substr(0, pos) << "</param>"; + doneReturn = true; + } + else + { + _out << nl << "/// " << *i; + } + } + } + if(foundReturn && !doneReturn) + { + _out << "</param>"; + } + } + else + { + // + // Output the leading comment block up until the first tag. + // + _out << nl << "/// <summary>"; + for(StringList::const_iterator i = summaryLines.begin(); i != summaryLines.end(); ++i) + { + _out << nl << "/// " << *i; + } + + bool done = false; + for(StringList::const_iterator i = remarksLines.begin(); i != remarksLines.end() && !done; ++i) + { + string::size_type pos = i->find('<'); + done = true; + if(pos != string::npos) + { + if(pos != 0) + { + _out << nl << "/// " << i->substr(0, pos); + } + } + else + { + _out << nl << "/// " << *i; + } + } + _out << nl << "/// </summary>"; + } + + + // + // Write the comments for the parameters. + // + writeDocCommentParam(p, paramType); + + if(!extraParam.empty()) + { + _out << nl << "/// " << extraParam; + } + + if(paramType == InParam) + { + if(!deprecateReason.empty()) + { + _out << nl << "/// <para>" << deprecateReason << "</para>"; + } + } +} + +void +Slice::CsVisitor::writeDocCommentParam(const OperationPtr& p, ParamDir paramType) +{ + // + // Collect the names of the in- or -out parameters to be documented. + // + ParamDeclList tmp = p->parameters(); + vector<string> params; + for(ParamDeclList::const_iterator q = tmp.begin(); q != tmp.end(); ++q) + { + if((*q)->isOutParam() && paramType == OutParam) + { + params.push_back((*q)->name()); + } + else if(!(*q)->isOutParam() && paramType == InParam) + { + params.push_back((*q)->name()); + } + } + + // + // Print a comment for the callback parameter. + // + if(paramType == InParam) + { + _out << nl << "/// <param name=\"cb__\">The callback object for the operation.</param>"; + } + + // + // Print the comments for all the parameters that appear in the parameter list. + // + StringList summaryLines; + StringList remarksLines; + splitComment(p, summaryLines, remarksLines); + + const string paramTag = "<param"; + StringList::const_iterator i = remarksLines.begin(); + while(i != remarksLines.end()) + { + string line = *i++; + if(line.find(paramTag) != string::npos) + { + string::size_type paramNamePos = line.find('"', paramTag.length()); + if(paramNamePos != string::npos) + { + string::size_type paramNameEndPos = line.find('"', paramNamePos + 1); + string paramName = line.substr(paramNamePos + 1, paramNameEndPos - paramNamePos - 1); + if(std::find(params.begin(), params.end(), paramName) != params.end()) + { + _out << nl << "/// " << line; + StringList::const_iterator j; + if (i == remarksLines.end()) + { + break; + } + j = i++; + while(j != remarksLines.end()) + { + string::size_type endpos = j->find('>'); + if(endpos == string::npos) + { + i = j; + _out << nl << "/// " << *j++; + } + else + { + _out << nl << "/// " << *j++; + break; + } + } + } + } + } + } +} Slice::Gen::Gen(const string& base, const vector<string>& includePaths, const string& dir, bool impl, bool implTie, bool stream) @@ -1622,6 +2182,7 @@ Slice::Gen::TypesVisitor::visitOperation(const OperationPtr& p) _out << nl; } + writeDocComment(p, getDeprecateReason(p, classDef, "operation")); emitAttributes(p); if(!classDef->isInterface()) { @@ -1767,6 +2328,8 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) _out << sp; + writeDocComment(p, getDeprecateReason(p, 0, "type")); + emitDeprecate(p, 0, _out, "type"); emitAttributes(p); @@ -3083,7 +3646,9 @@ Slice::Gen::OpsVisitor::writeOperations(const ClassDefPtr& p, bool noCurrent) opIntfName += "NC"; } - _out << sp << nl << "public interface " << name << opIntfName << '_'; + _out << sp; + writeDocComment(p, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class")); + _out << nl << "public interface " << name << opIntfName << '_'; if((bases.size() == 1 && bases.front()->isAbstract()) || bases.size() > 1) { _out << " : "; @@ -3137,6 +3702,21 @@ Slice::Gen::OpsVisitor::writeOperations(const ClassDefPtr& p, bool noCurrent) _out << sp; + string deprecateReason = getDeprecateReason(*r, p, "operation"); + string extraCurrent; + if(!noCurrent && !p->isLocal()) + { + extraCurrent = "<param name=\"current__\">The Current object for the invocation.</param>"; + } + if(amd) + { + writeDocCommentAsync(*r, InParam, extraCurrent); + } + else + { + writeDocComment(*r, deprecateReason, extraCurrent); + } + emitDeprecate(op, p, _out, "operation"); emitAttributes(op); @@ -3185,7 +3765,9 @@ Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p) string name = p->name(); ClassList bases = p->bases(); - _out << sp << nl << "public sealed class " << name << "PrxHelper : Ice.ObjectPrxHelperBase, " << name << "Prx"; + _out << sp; + writeDocComment(p, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class")); + _out << nl << "public sealed class " << name << "PrxHelper : Ice.ObjectPrxHelperBase, " << name << "Prx"; _out << sb; OperationList ops = p->allOperations(); @@ -3206,7 +3788,11 @@ Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p) vector<string> params = getParams(op); vector<string> args = getArgs(op); - _out << sp << nl << "public " << retS << " " << opName << spar << params << epar; + string deprecateReason = getDeprecateReason(op, p, "operation"); + + _out << sp; + writeDocComment(op, deprecateReason); + _out << nl << "public " << retS << " " << opName << spar << params << epar; _out << sb; _out << nl; if(ret) @@ -3216,7 +3802,10 @@ Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p) _out << opName << spar << args << "null" << "false" << epar << ';'; _out << eb; - _out << sp << nl << "public " << retS << " " << opName << spar << params + _out << sp; + writeDocComment(op, deprecateReason, + "<param name=\"context__\">The Context map to send with the invocation.</param>"); + _out << nl << "public " << retS << " " << opName << spar << params << "_System.Collections.Generic.Dictionary<string, string> context__" << epar; _out << sb; _out << nl; @@ -3308,12 +3897,15 @@ Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p) // context parameter // _out << sp; + writeDocCommentAsync(op, InParam); _out << nl << "public bool " << opName << "_async" << spar << paramsAMI << epar; _out << sb; _out << nl << "return " << opName << "_async" << spar << argsAMI << "null" << "false" << epar << ';'; _out << eb; _out << sp; + writeDocCommentAsync(op, InParam, + "<param name=\"ctx__\">The Context map to send with the invocation.</param>"); _out << nl << "public bool " << opName << "_async" << spar << paramsAMI << "_System.Collections.Generic.Dictionary<string, string> ctx__" << epar; _out << sb; @@ -4562,10 +5154,12 @@ Slice::Gen::AsyncVisitor::visitOperation(const OperationPtr& p) vector<string> paramsInvoke = getParamsAsync(p, false); + writeDocCommentOp(p); _out << sp << nl << "public abstract class AMI_" << cl->name() << '_' << name << " : IceInternal.OutgoingAsync"; _out << sb; _out << sp; + writeDocCommentAsync(p, OutParam); _out << nl << "public abstract void ice_response" << spar << params << epar << ';'; _out << sp << nl << "public bool invoke__" << spar << "Ice.ObjectPrx prx__" @@ -4715,10 +5309,17 @@ Slice::Gen::AsyncVisitor::visitOperation(const OperationPtr& p) vector<string> paramsAMD = getParamsAsyncCB(p); - _out << sp << nl << "public interface " << classNameAMD << '_' << name; + _out << sp; + writeDocCommentOp(p); + _out << nl << "public interface " << classNameAMD << '_' << name; _out << sb; - _out << sp << nl << "void ice_response" << spar << paramsAMD << epar << ';'; - _out << sp << nl << "void ice_exception(_System.Exception ex);"; + _out << sp; + writeDocCommentAsync(p, OutParam); + _out << nl << "void ice_response" << spar << paramsAMD << epar << ';'; + _out << sp << nl << "/// ice_exception indicates to the Ice run time that"; + _out << nl << "/// the operation completed with an exception."; + _out << nl << "/// <param name=\"ex\">The exception to be raised.</param>"; + _out << nl << "void ice_exception(_System.Exception ex);"; _out << eb; TypePtr ret = p->returnType(); diff --git a/cpp/src/slice2cs/Gen.h b/cpp/src/slice2cs/Gen.h index 3bb6c266a92..f61f731f4a7 100644 --- a/cpp/src/slice2cs/Gen.h +++ b/cpp/src/slice2cs/Gen.h @@ -35,9 +35,21 @@ protected: virtual std::vector<std::string> getArgsAsyncCB(const OperationPtr&); void emitAttributes(const ContainedPtr&); - ::std::string getParamAttributes(const ParamDeclPtr&); + std::string getParamAttributes(const ParamDeclPtr&); - ::std::string writeValue(const TypePtr&); + std::string writeValue(const TypePtr&); + + std::string toCsIdent(const std::string&); + std::string editMarkup(const std::string&); + StringList splitIntoLines(const std::string&); + void splitComment(const ContainedPtr&, StringList&, StringList&); + StringList getSummary(const ContainedPtr&); + void writeDocComment(const ContainedPtr&, const std::string&, const std::string& = ""); + void writeDocCommentOp(const OperationPtr&); + + enum ParamDir { InParam, OutParam }; + void writeDocCommentAsync(const OperationPtr&, ParamDir, const std::string& = ""); + void writeDocCommentParam(const OperationPtr&, ParamDir); ::IceUtilInternal::Output& _out; }; @@ -232,7 +244,7 @@ private: private: - typedef ::std::set< ::std::string> NameSet; + typedef std::set<std::string> NameSet; void writeInheritedOperationsWithOpNames(const ClassDefPtr&, NameSet&); }; diff --git a/cpp/src/slice2cs/Main.cpp b/cpp/src/slice2cs/Main.cpp index f702e62719e..bbe3de14cab 100644 --- a/cpp/src/slice2cs/Main.cpp +++ b/cpp/src/slice2cs/Main.cpp @@ -218,7 +218,7 @@ compile(int argc, char* argv[]) else { Preprocessor icecpp(argv[0], *i, cppArgs); - FILE* cppHandle = icecpp.preprocess(false); + FILE* cppHandle = icecpp.preprocess(true); if(cppHandle == 0) { |