Index: TODO =================================================================== diff -u -N -rbe40ed6447e73f71e90fe1510ec01787cc799e6b -rb3dcd6fec51f6d06fb5651a59fa238a8c15b9662 --- TODO (.../TODO) (revision be40ed6447e73f71e90fe1510ec01787cc799e6b) +++ TODO (.../TODO) (revision b3dcd6fec51f6d06fb5651a59fa238a8c15b9662) @@ -2310,8 +2310,14 @@ - use NsfCommandPreserve/NsfCommandRelease for tcd->aliasCmd as well. In case of epoched cmdPointers, refetch the cmd and it client data. -- add regression test +- added regression tests +- added flag to AliasGet() to leave optional error message if alias + data is removed +- some cleanup in NsfProcAliasMethod(): handle not existing alias data, + more careful refcounting + + TODO: - document value added replacements of Tcl functions Index: generic/nsf.c =================================================================== diff -u -N -r991f6b6fde382a9bb5c3c9232206988813a3eb37 -rb3dcd6fec51f6d06fb5651a59fa238a8c15b9662 --- generic/nsf.c (.../nsf.c) (revision 991f6b6fde382a9bb5c3c9232206988813a3eb37) +++ generic/nsf.c (.../nsf.c) (revision b3dcd6fec51f6d06fb5651a59fa238a8c15b9662) @@ -263,7 +263,8 @@ /* prototypes for alias management */ static int AliasDelete(Tcl_Interp *interp, Tcl_Obj *cmdName, CONST char *methodName, int withPer_object); -static Tcl_Obj *AliasGet(Tcl_Interp *interp, Tcl_Obj *cmdName, CONST char *methodName, int withPer_object); +static Tcl_Obj *AliasGet(Tcl_Interp *interp, Tcl_Obj *cmdName, CONST char *methodName, + int withPer_object, int leaveError); static int AliasDeleteObjectReference(Tcl_Interp *interp, Tcl_Command cmd); /* prototypes for (class) list handling */ @@ -12381,17 +12382,21 @@ if (Tcl_Command_cmdEpoch(tcd->aliasedCmd)) { NsfObject *defObject = tcd->class ? &(tcd->class->object) : tcd->object; Tcl_Obj **listElements, *entryObj, *targetObj; - int nrElements, withPer_object; + int result, nrElements, withPer_object; Tcl_Command cmd; - //int result, withFrame; + //int withFrame; /* * Get the targetObject. Currently, we can get it just via the * alias array. */ withPer_object = tcd->class ? 0 : 1; //withFrame = (tcd->objProc == NsfObjscopedMethod); - entryObj = AliasGet(interp, defObject->cmdName, methodName, withPer_object); + entryObj = AliasGet(interp, defObject->cmdName, methodName, withPer_object, 1); + if (entryObj == NULL) { + return TCL_ERROR; + } + INCR_REF_COUNT(entryObj); Tcl_ListObjGetElements(interp, entryObj, &nrElements, &listElements); targetObj = listElements[nrElements-1]; @@ -12406,8 +12411,10 @@ */ cmd = Tcl_GetCommandFromObj(interp, targetObj); if (cmd == NULL) { - return NsfPrintError(interp, "target \"%s\" of alias %s apparently disappeared", - ObjStr(targetObj), methodName); + result = NsfPrintError(interp, "target \"%s\" of alias %s apparently disappeared", + ObjStr(targetObj), methodName); + DECR_REF_COUNT(entryObj); + return result; } cmd = GetOriginalCommand(cmd); @@ -12475,6 +12482,9 @@ if (tcd->cmdName) {DECR_REF_COUNT(tcd->cmdName);} if (tcd->aliasedCmd) { Command *aliasedCmd = (Command *)(tcd->aliasedCmd); + + /*fprintf(stderr, "AliasCmdDeleteProc aliasedCmd %p epoch %d refCount %d\n", + aliasedCmd, Tcl_Command_cmdEpoch(tcd->aliasedCmd), aliasedCmd->refCount);*/ /* * Clear the aliasCmd from the imported-ref chain of the aliased * (or real) cmd. This widely resembles what happens in the @@ -13730,7 +13740,7 @@ entryObj = AliasGet(interp, defObject->cmdName, Tcl_GetCommandName(interp, cmd), - regObject != defObject ? 1 : withPer_object); + regObject != defObject ? 1 : withPer_object, 0); /* fprintf(stderr, "aliasGet %s -> %s/%s (%d) returned %p\n", ObjectName(defObject), methodName, Tcl_GetCommandName(interp, cmd), @@ -13772,27 +13782,22 @@ case InfomethodsubcmdDefinitionIdx: { NsfObject *subObject = NsfGetObjectFromCmdPtr(cmd); + assert(subObject); resultObj = Tcl_NewListObj(0, NULL); - /* we can make - create - or something similar to the other definition cmds - createChild - */ AppendMethodRegistration(interp, resultObj, "create", &(subObject->cl)->object, ObjStr(subObject->cmdName), cmd, 0, 0, 0); - /* - AppendMethodRegistration(interp, resultObj, "subobject", - object, methodName, cmd, 0, 0); - Tcl_ListObjAppendElement(interp, resultObj, subObject->cmdName);*/ - Tcl_SetObjResult(interp, resultObj); break; } } } else { - /* should never happen */ + /* + * Should never happen + * + * The warning is just a guess, so we don't raise an error here. + */ NsfLog(interp, NSF_LOG_WARN, "Could not obtain alias definition for %s. " "Maybe someone deleted the alias %s for object %s?", methodName, methodName, ObjectName(regObject)); @@ -13859,7 +13864,7 @@ *isObject = (resolvedProc == NsfObjDispatch); if (methodType == NSF_METHODTYPE_ALIAS) { - if (!(proc == NsfProcAliasMethod || AliasGet(interp, object->cmdName, methodName, withPer_object))) { + if (!(proc == NsfProcAliasMethod || AliasGet(interp, object->cmdName, methodName, withPer_object, 0))) { return 0; } } else { @@ -14263,13 +14268,17 @@ } static Tcl_Obj * -AliasGet(Tcl_Interp *interp, Tcl_Obj *cmdName, CONST char *methodName, int withPer_object) { +AliasGet(Tcl_Interp *interp, Tcl_Obj *cmdName, CONST char *methodName, int withPer_object, int leaveError) { Tcl_DString ds, *dsPtr = &ds; Tcl_Obj *obj = Tcl_GetVar2Ex(interp, NsfGlobalStrings[NSF_ALIAS_ARRAY], AliasIndex(dsPtr, cmdName, methodName, withPer_object), TCL_GLOBAL_ONLY); /*fprintf(stderr, "aliasGet methodName '%s' returns %p\n", methodName, obj);*/ Tcl_DStringFree(dsPtr); + if (obj == NULL && leaveError) { + NsfPrintError(interp, "Could not obtain alias definition for %s %s.", + ObjStr(cmdName), methodName); + } return obj; } @@ -14518,7 +14527,8 @@ newCmd = FindMethod(nsPtr, methodName); } - if (newObjProc) { + // TODO remove 1 in expr when decided xxxx + if (1 && newObjProc) { /* * Define the reference chain like for 'namespace import' to * obtain automatic deletes when the original command is deleted. @@ -14528,6 +14538,8 @@ refPtr->nextPtr = ((Command *) tcd->aliasedCmd)->importRefPtr; ((Command *) tcd->aliasedCmd)->importRefPtr = refPtr; tcd->aliasCmd = newCmd; + } else if (newObjProc) { + tcd->aliasCmd = newCmd; } if (newCmd) { Index: tests/alias.test =================================================================== diff -u -N -rbe40ed6447e73f71e90fe1510ec01787cc799e6b -rb3dcd6fec51f6d06fb5651a59fa238a8c15b9662 --- tests/alias.test (.../alias.test) (revision be40ed6447e73f71e90fe1510ec01787cc799e6b) +++ tests/alias.test (.../alias.test) (revision b3dcd6fec51f6d06fb5651a59fa238a8c15b9662) @@ -392,16 +392,23 @@ proc ::foo args { return [current]->[current method]} ? {info exists ::nsf::alias(::C,FOO,0)} 0 ::nsf::alias C FOO ::foo +::nsf::alias C FOO2 ::foo ? {info exists ::nsf::alias(::C,FOO,0)} 1 -? {C info methods -methodtype alias} FOO +? {lsort [C info methods -methodtype alias]} {FOO FOO2} # Rename target, such that alias points to an invalid item # Note that removing the target works differently (makes cleanup) # rename ::foo "" rename ::foo ::foo2 ? {info exists ::nsf::alias(::C,FOO,0)} 1 -? {C info methods -methodtype alias} FOO +? {lsort [C info methods -methodtype alias]} {FOO FOO2} ? {c FOO} {target "::foo" of alias FOO apparently disappeared} ? {C info method definition FOO} "::C public alias FOO ::foo" +unset ::nsf::alias(::C,FOO,0) +? {c FOO} {Could not obtain alias definition for ::C FOO.} +? {c FOO2} {target "::foo" of alias FOO2 apparently disappeared} +#rename ::foo2 ::foo +#? {c FOO} {Could not obtain alias definition for ::C FOO.} +#? {c FOO2} {::c->foo} # # Check resolving of namespace imported classes