Hi, It's possible by mistake to create a class with duplicate instance variable, the following patch checks and warms the user. I plan to do the same but for duplicate methods defined on a class.
Gwen
>From 892f5a7b77462e1005f555833ff2a2b75c07486d Mon Sep 17 00:00:00 2001 From: Gwenael Casaccio <[email protected]> Date: Fri, 29 Jul 2011 17:24:30 +0200 Subject: [PATCH] duplicate instance variables --- kernel/Behavior.st | 21 +++++++++-- kernel/SysExcept.st | 72 ++++++++++++++++++++++++++++++++++++++++ snprintfv/snprintfv/filament.h | 4 +- snprintfv/snprintfv/printf.h | 8 ++-- snprintfv/snprintfv/stream.h | 4 +- tests/untrusted.ok | 1 + 6 files changed, 98 insertions(+), 12 deletions(-) diff --git a/kernel/Behavior.st b/kernel/Behavior.st index 65603b3..1b93e63 100644 --- a/kernel/Behavior.st +++ b/kernel/Behavior.st @@ -79,6 +79,17 @@ method dictionary, and iterating over the class hierarchy.'> compileAllSubclasses ] + checkExistanceOfIVar: anArray [ + + | oldInstVarNames set | + KernelInitialized ifFalse: [ ^ self ]. + oldInstVarNames := self superclass ifNil: [ #() ] ifNotNil: [ self superclass allInstVarNames ]. + (oldInstVarNames includesAnyOf: anArray) ifTrue: [ DuplicateInstanceVariable behavior: self vars: anArray ]. + oldInstVarNames := Set new. + self allSubclassesDo: [ :each | oldInstVarNames addAll: each asClass instVarNames ]. + (oldInstVarNames includesAnyOf: anArray) ifTrue: [ DuplicateInstanceVariable behavior: self vars: anArray ]. + ] + instanceVariableNames: instVarNames [ "Set the instance variables for the receiver to be those in instVarNames" @@ -86,7 +97,9 @@ method dictionary, and iterating over the class hierarchy.'> <category: 'instance variables'> | variableArray oldInstVarNames oldSize removed changed added | variableArray := self parseInstanceVariableString: instVarNames. + [ self checkExistanceOfIVar: variableArray ] on: DuplicateInstanceVariable do: [ :each | each messageText printNl ]. variableArray := self subclassInstVarNames, variableArray. + oldInstVarNames := self allInstVarNames. "If instance variables change, update instance variables and @@ -1433,7 +1446,7 @@ method dictionary, and iterating over the class hierarchy.'> oldSuper := self superclass. newSuper == oldSuper ifFalse: [ [ newSuper includesBehavior: oldSuper ] whileFalse: [ - oldSuper := oldSuper superclass ] ]. + oldSuper := oldSuper superclass ] ]. "Make map for inherited instance variables." oldInstVars := self allInstVarNames. @@ -1446,9 +1459,9 @@ method dictionary, and iterating over the class hierarchy.'> oldInstVars from: oldSuper instSize + 1 to: oldInstVars size keysAndValuesDo: [ :index :var | - | map | - map := newInstVars findLast: [:each | each = var]. - map > 0 ifTrue: [instVarMap at: index put: map + newSuper instSize]]. + | map | + map := newInstVars findLast: [:each | each = var]. + map > 0 ifTrue: [instVarMap at: index put: map + newSuper instSize]]. "Fix up all subclasses." self allSubclassesDo: diff --git a/kernel/SysExcept.st b/kernel/SysExcept.st index 9660f7c..19baf8c 100644 --- a/kernel/SysExcept.st +++ b/kernel/SysExcept.st @@ -103,6 +103,78 @@ even though it is not to be considered an error.' ] +Warning subclass: DuplicateInstanceVariable [ + + DuplicateInstanceVariable class >> behavior: aBehavior vars: anArray [ + <category: 'instance creation'> + + ^ (self new) + behavior: aBehavior vars: anArray; + signal + ] + + | behavior array | + + behavior: aBehavior vars: anArray [ + <category: 'initialization'> + + behavior := aBehavior. + array := anArray + ] + + description [ + <category: 'description'> + + ^ 'Trying to add an instance variable which was defined on a superclass or a subclass' + ] + + checkSuperclasses [ + <category: 'private'> + + | oldInstVarNames result | + result := Set new. + oldInstVarNames := behavior superclass ifNil: [ #() ] ifNotNil: [ behavior superclass allInstVarNames ]. + oldInstVarNames do: [ :each | (array includes: each) ifTrue: [ result add: each ] ]. + ^ result + ] + + checkSubclasses [ + <category: 'private'> + + | oldInstVarNames result | + result := Set new. + oldInstVarNames := Set new. + behavior allSubclassesDo: [ :each | oldInstVarNames addAll: each asClass instVarNames ]. + oldInstVarNames do: [ :each | (array includes: each) ifTrue: [ result add: each ] ]. + ^ result + ] + + print: aSet1 with: aSet2 [ + <category: 'private'> + + | string | + string := behavior displayString. + aSet1 isEmpty ifFalse: [ string := string, ' redefines instance variables : #', aSet1 asArray displayString, ' already defined on superclasses' ]. + aSet2 isEmpty ifFalse: [ + aSet1 isEmpty ifFalse: [ string := string, ' and' ]. + string := string, ' redefines instance variables : #', aSet2 asArray displayString, ' already defined on subclasses' ]. + ^ string + ] + + messageText [ + <category: 'accessing'> + + ^ self print: self checkSuperclasses with: self checkSubclasses + ] + + defaultAction [ + <category: 'exception description'> + + self resignalAsUnhandled: self messageText + ] +] + + Exception subclass: Halt [ <category: 'Language-Exceptions'> diff --git a/snprintfv/snprintfv/filament.h b/snprintfv/snprintfv/filament.h index 4a91eb6..8a7ce6c 100644 --- a/snprintfv/snprintfv/filament.h +++ b/snprintfv/snprintfv/filament.h @@ -1,4 +1,4 @@ -#line 1 "../../../snprintfv/snprintfv/filament.in" +#line 1 "./filament.in" /* -*- Mode: C -*- */ /* filament.h --- a bit like a string but different =)O| @@ -118,7 +118,7 @@ extern char * fildelete (Filament *fil); extern void _fil_extend (Filament *fil, size_t len, boolean copy); -#line 61 "../../../snprintfv/snprintfv/filament.in" +#line 61 "./filament.in" /* Save the overhead of a function call in the great majority of cases. */ #define fil_maybe_extend(fil, len, copy) \ diff --git a/snprintfv/snprintfv/printf.h b/snprintfv/snprintfv/printf.h index 49a2e9f..1437dd5 100644 --- a/snprintfv/snprintfv/printf.h +++ b/snprintfv/snprintfv/printf.h @@ -1,4 +1,4 @@ -#line 1 "../../../snprintfv/snprintfv/printf.in" +#line 1 "./printf.in" /* -*- Mode: C -*- */ /* printf.in --- printf clone for argv arrays @@ -266,7 +266,7 @@ enum } \ } SNV_STMT_END -#line 269 "../../../snprintfv/snprintfv/printf.in" +#line 269 "./printf.in" /** * printf_generic_info: * @pinfo: the current state information for the format @@ -302,7 +302,7 @@ extern int printf_generic_info (struct printf_info *const pinfo, size_t n, int * extern int printf_generic (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args); -#line 270 "../../../snprintfv/snprintfv/printf.in" +#line 270 "./printf.in" /** * register_printf_function: * @spec: the character which will trigger @func, cast to an unsigned int. @@ -789,7 +789,7 @@ extern int snv_vasprintf (char **result, const char *format, va_list ap); extern int snv_asprintfv (char **result, const char *format, snv_constpointer const args[]); -#line 271 "../../../snprintfv/snprintfv/printf.in" +#line 271 "./printf.in" /* If you don't want to use snprintfv functions for *all* of your string formatting API, then define COMPILING_SNPRINTFV_C and use the snv_ diff --git a/snprintfv/snprintfv/stream.h b/snprintfv/snprintfv/stream.h index 496bd33..0bebce1 100644 --- a/snprintfv/snprintfv/stream.h +++ b/snprintfv/snprintfv/stream.h @@ -1,4 +1,4 @@ -#line 1 "../../../snprintfv/snprintfv/stream.in" +#line 1 "./stream.in" /* -*- Mode: C -*- */ /* stream.h --- customizable stream routines @@ -180,7 +180,7 @@ extern int stream_puts (char *s, STREAM *stream); extern int stream_get (STREAM *stream); -#line 88 "../../../snprintfv/snprintfv/stream.in" +#line 88 "./stream.in" #ifdef __cplusplus #if 0 /* This brace is so that emacs can still indent properly: */ diff --git a/tests/untrusted.ok b/tests/untrusted.ok index 8465e63..6fd3f09 100644 --- a/tests/untrusted.ok +++ b/tests/untrusted.ok @@ -1,3 +1,4 @@ +'A redefines instance variables : #(#a ) already defined on superclasses' Execution begins... returned value is true -- 1.7.4.1
_______________________________________________ help-smalltalk mailing list [email protected] https://lists.gnu.org/mailman/listinfo/help-smalltalk
