@@ -35,6 +35,7 @@ import * as toolboxItems from '../toolbox/items';
3535import { getClassData } from './utils/python' ;
3636import { FunctionData } from './utils/python_json_types' ;
3737import { findConnectedBlocksOfType } from './utils/find_connected_blocks' ;
38+ import { makeLegalName } from './utils/validator' ;
3839import { NONCOPYABLE_BLOCK } from './noncopyable_block' ;
3940import { BLOCK_NAME as MRC_GET_PARAMETER_BLOCK_NAME } from './mrc_get_parameter' ;
4041import * as paramContainer from './mrc_param_container'
@@ -293,10 +294,23 @@ const CLASS_METHOD_DEF = {
293294 // When the user changes the method name on the block, clear the mrcPythonMethodName field.
294295 this . mrcPythonMethodName = '' ;
295296
296- // Strip leading and trailing whitespace.
297- name = name . trim ( ) ;
297+ if ( this . isInFlyout ) {
298+ // Flyouts can have multiple methods with identical names.
299+ return name ;
300+ }
301+
302+ const otherNames : string [ ] = [ ] ;
303+ this . workspace . getBlocksByType ( BLOCK_NAME )
304+ . filter ( block => block . id !== this . id )
305+ . forEach ( ( block ) => {
306+ otherNames . push ( block . getFieldValue ( FIELD_METHOD_NAME ) ) ;
307+ const classMethodDefBlock = block as ClassMethodDefBlock ;
308+ if ( classMethodDefBlock . mrcPythonMethodName ) {
309+ otherNames . push ( classMethodDefBlock . mrcPythonMethodName ) ;
310+ }
311+ } ) ;
298312
299- const legalName = findLegalMethodName ( name , this ) ;
313+ const legalName = makeLegalName ( name , otherNames , /* mustBeValidPythonIdentifier */ true ) ;
300314 const oldName = nameField . getValue ( ) ;
301315 if ( oldName && oldName !== name && oldName !== legalName ) {
302316 // Rename any callers.
@@ -374,61 +388,6 @@ const CLASS_METHOD_DEF = {
374388 } ,
375389} ;
376390
377- /**
378- * Ensure two identically-named methods don't exist.
379- * Take the proposed method name, and return a legal name i.e. one that
380- * is not empty and doesn't collide with other methods.
381- *
382- * @param name Proposed method name.
383- * @param block Block to disambiguate.
384- * @returns Non-colliding name.
385- */
386- function findLegalMethodName ( name : string , block : ClassMethodDefBlock ) : string {
387- if ( block . isInFlyout ) {
388- // Flyouts can have multiple methods called 'my_method'.
389- return name ;
390- }
391- name = name || 'unnamed' ;
392- while ( isMethodNameUsed ( name , block . workspace , block ) ) {
393- // Collision with another method.
394- const r = name . match ( / ^ ( .* ?) ( \d + ) $ / ) ;
395- if ( ! r ) {
396- name += '2' ;
397- } else {
398- name = r [ 1 ] + ( parseInt ( r [ 2 ] ) + 1 ) ;
399- }
400- }
401- return name ;
402- }
403-
404- /**
405- * Return if the given name is already a method name.
406- *
407- * @param name The questionable name.
408- * @param workspace The workspace to scan for collisions.
409- * @param opt_exclude Optional block to exclude from comparisons (one doesn't
410- * want to collide with oneself).
411- * @returns True if the name is used, otherwise return false.
412- */
413- function isMethodNameUsed (
414- name : string , workspace : Blockly . Workspace , opt_exclude ?: Blockly . Block ) : boolean {
415- const nameLowerCase = name . toLowerCase ( ) ;
416- for ( const block of workspace . getBlocksByType ( BLOCK_NAME ) ) {
417- if ( block === opt_exclude ) {
418- continue ;
419- }
420- if ( nameLowerCase === block . getFieldValue ( FIELD_METHOD_NAME ) . toLowerCase ( ) ) {
421- return true ;
422- }
423- const classMethodDefBlock = block as ClassMethodDefBlock ;
424- if ( classMethodDefBlock . mrcPythonMethodName &&
425- nameLowerCase === classMethodDefBlock . mrcPythonMethodName . toLowerCase ( ) ) {
426- return true ;
427- }
428- }
429- return false ;
430- }
431-
432391export const setup = function ( ) {
433392 Blockly . Blocks [ BLOCK_NAME ] = CLASS_METHOD_DEF ;
434393} ;
0 commit comments