@@ -971,10 +971,11 @@ export abstract class Variable {
971971
972972 /* NodeTag variables: Node, List, Bitmapset etc.. */
973973 if ( context . nodeVarRegistry . isNodeVar ( effectiveType ) ) {
974- const nodeTagVar = await NodeVariable . createNode ( debugVariable , frameId ,
974+ const nodeVar = await NodeVariable . createNode ( debugVariable , frameId ,
975975 context , logger , args ) ;
976- if ( nodeTagVar ) {
977- return nodeTagVar ;
976+ if ( nodeVar ) {
977+ await nodeVar . typeComputed
978+ return nodeVar ;
978979 }
979980 }
980981
@@ -1020,7 +1021,7 @@ export abstract class Variable {
10201021 *
10211022 * @returns Expression to be evaluated in 'Watch' view
10221023 */
1023- getWatchExpression ( ) : string | null {
1024+ async getWatchExpression ( ) : Promise < string | null > {
10241025 return null ;
10251026 }
10261027
@@ -1429,7 +1430,7 @@ export class RealVariable extends Variable {
14291430 return m ;
14301431 }
14311432
1432- getRealType ( ) {
1433+ getType ( ) {
14331434 return this . type ;
14341435 }
14351436
@@ -1541,65 +1542,76 @@ export class RealVariable extends Variable {
15411542 return num ;
15421543 }
15431544
1544- protected formatWatchExpression ( myType : string ) {
1545- /* TODO: needs refactoring */
1545+ protected async formatWatchExpression ( ) : Promise < string | null > {
1546+ if ( ! this . parent ) {
1547+ /* should not happen */
1548+ return null ;
1549+ }
1550+
1551+ const cast = this . type === this . declaredType
1552+ ? ''
1553+ : `(${ this . type } )`
15461554 if ( this . parent instanceof VariablesRoot ) {
1547- /* Top level variable */
1548- if ( this . debug . isValueStruct ( this , myType ) ) {
1549- /* No way to evaluate raw structs as they just lie on stack */
1555+ /* Top level variable needs to be just printed */
1556+ if ( this . debug . isValueStruct ( this ) ) {
15501557 return this . name ;
1551- } else if ( this . debug . isValidPointerType ( this ) ) {
1552- return `( ${ myType } ) ${ this . getPointer ( ) } ` ;
1558+ } else {
1559+ return `${ cast } ${ this . name } ` ;
15531560 }
1554- }
1555- else if ( this . parent instanceof ListElementsMember ||
1556- this . parent instanceof LinkedListElementsMember ) {
1557- /* Pointer element of List, not int/Oid/TransactionId... */
1561+ } else if ( this . parent instanceof ListElementsMember
1562+ || this . parent instanceof LinkedListElementsMember ) {
1563+ /*
1564+ * For arrays we do not know indexes of element, so everything
1565+ * we can do - is to return pointer (value) of non-scalar element.
1566+ */
15581567 if ( this . debug . isValidPointerType ( this ) ) {
1559- return `(${ myType } )${ this . getPointer ( ) } ` ;
1568+ return `(${ this . type } )${ this . getPointer ( ) } ` ;
15601569 }
15611570 } else if ( this . parent instanceof ArraySpecialMember ) {
1571+ /*
1572+ * I don't know index of array I'm in, so everything I
1573+ * can do is to return pointer to myself if it is a
1574+ * pointer array.
1575+ */
15621576 if ( this . debug . isValidPointerType ( this ) ) {
1563- return `(${ myType } )${ this . getPointer ( ) } `
1577+ return `(${ this . type } )${ this . getPointer ( ) } `
15641578 }
15651579 } else if ( this . parent instanceof RealVariable ) {
15661580 /* Member of real structure */
1567- const typeModifier = this . type === myType ? '' : `(${ myType } )` ;
15681581 if ( this . debug . isValueStruct ( this . parent ) ) {
1569- if ( this . debug . isFixedSizeArray ( this . parent )
1570- && this . debug . isValidPointerType ( this ) ) {
1571- return `(${ myType } )${ this . getPointer ( ) } ` ;
1572- } else {
1573- return `${ typeModifier } (${ this . parent . type } )${ this . parent . getPointer ( ) } .${ this . name } ` ;
1582+ /*
1583+ * If parent is a value struct, then his parent also
1584+ * can be value struct, so we can not get pointer of
1585+ * parent of parent - it also can be a value struct.
1586+ * So in such case just recursively get watch expression.
1587+ */
1588+ const base = await this . parent . formatWatchExpression ( ) ;
1589+ if ( ! base ) {
1590+ return null ;
15741591 }
1575- } else if ( this . debug . isValidPointerType ( this . parent ) ) {
1576- return `${ typeModifier } ((${ this . parent . getRealType ( ) } )${ this . parent . getPointer ( ) } )->${ this . name } ` ;
1592+
1593+ return `${ cast } ${ base } .${ this . name } ` ;
1594+ } else {
1595+ /* This is the most common case - watch member of some pointer type */
1596+ const parentExpr = `((${ this . parent . type } )${ this . parent . getPointer ( ) } )`
1597+ return `${ cast } ${ parentExpr } ->${ this . name } ` ;
15771598 }
15781599 } else {
15791600 /* Child of pseudo-member */
1580- if ( this . debug . isValueStruct ( this , myType ) ) {
1581- if ( ! this . parent ) {
1582- /* Should not happen */
1583- return this . name ;
1584- }
1585-
1586- if ( this . parent instanceof VariablesRoot ) {
1587- return this . name ;
1588- } else if ( this . debug . isValidPointerType ( this . parent ) ) {
1589- return `((${ this . parent . type } )${ this . parent . getPointer ( ) } )->${ this . name } `
1590- } else {
1591- return `((${ this . parent . type } )${ this . parent . getPointer ( ) } ).${ this . name } `
1592- }
1601+ if ( this . debug . isValueStruct ( this , this . type ) ) {
1602+ const parent = `((${ this . parent . type } )${ this . parent . getPointer ( ) } )` ;
1603+ const separator = this . debug . isValidPointerType ( this . parent ) ? '->' : '.' ;
1604+ return `${ parent } ${ separator } ${ this . name } ` ;
15931605 } else if ( this . debug . isValidPointerType ( this ) ) {
1594- return `(${ myType } )${ this . getPointer ( ) } `
1606+ return `(${ this . type } )${ this . getPointer ( ) } `
15951607 }
15961608 }
15971609
15981610 return null ;
15991611 }
16001612
1601- getWatchExpression ( ) {
1602- return this . formatWatchExpression ( this . type ) ;
1613+ async getWatchExpression ( ) {
1614+ return this . formatWatchExpression ( ) ;
16031615 }
16041616}
16051617
@@ -1627,23 +1639,12 @@ export class NodeVariable extends RealVariable {
16271639 */
16281640 realNodeTag : string ;
16291641
1630- /**
1631- * Real type of Node variable. May be equal to declared type if NodeTags
1632- * are equal.
1633- *
1634- * Evaluated lazily - use {@link getRealType getRealType()} function to
1635- * get value
1636- *
1637- * @example `OpExpr *' was `Node *'
1638- */
1639- realType ?: string ;
1640-
16411642 constructor ( realNodeTag : string , args : RealVariableArgs ) {
16421643 super ( args ) ;
16431644 this . realNodeTag = realNodeTag . replace ( 'T_' , '' ) ;
16441645 }
16451646
1646- protected computeRealType ( ) {
1647+ protected computeEffectiveType ( ) {
16471648 const tagFromType = utils . getStructNameFromType ( this . type ) ;
16481649 if ( tagFromType === this . realNodeTag ) {
16491650 return this . type ;
@@ -1661,12 +1662,14 @@ export class NodeVariable extends RealVariable {
16611662 return utils . substituteStructName ( type , this . realNodeTag ) ;
16621663 }
16631664
1664- getRealType ( ) : string {
1665- if ( ! this . realType ) {
1666- this . realType = this . computeRealType ( ) ;
1665+ typeComputed = false ;
1666+ getType ( ) : string {
1667+ if ( ! this . typeComputed ) {
1668+ this . type = this . computeEffectiveType ( ) ;
1669+ this . typeComputed = true ;
16671670 }
16681671
1669- return this . realType ;
1672+ return this . type ;
16701673 }
16711674
16721675 /**
@@ -1725,7 +1728,7 @@ export class NodeVariable extends RealVariable {
17251728 * We should substitute current type with target, because
17261729 * there may be qualifiers such `struct' or `const'
17271730 */
1728- const resultType = utils . substituteStructName ( this . getRealType ( ) , tag ) ;
1731+ const resultType = utils . substituteStructName ( this . getType ( ) , tag ) ;
17291732 return await this . castToType ( resultType ) ;
17301733 }
17311734
@@ -1854,9 +1857,12 @@ export class NodeVariable extends RealVariable {
18541857
18551858 return new NodeVariable ( realTag , args ) ;
18561859 }
1860+
1861+ async formatWatchExpression ( ) {
1862+ /* Make sure 'type' is correctly */
1863+ await this . getChildren ( ) ;
18571864
1858- getWatchExpression ( ) {
1859- return this . formatWatchExpression ( this . computeRealType ( ) ) ;
1865+ return super . formatWatchExpression ( ) ;
18601866 }
18611867}
18621868
@@ -3797,7 +3803,7 @@ export class ListNodeVariable extends NodeVariable {
37973803 }
37983804
37993805 getMemberExpression ( member : string ) {
3800- return `((${ this . getRealType ( ) } )${ this . getPointer ( ) } )->${ member } `
3806+ return `((${ this . getType ( ) } )${ this . getPointer ( ) } )->${ member } `
38013807 }
38023808
38033809 isEmpty ( ) {
@@ -3891,7 +3897,7 @@ export class ListNodeVariable extends NodeVariable {
38913897 return new LinkedListElementsMember ( this , info . member , info . type , this . context ) ;
38923898 }
38933899
3894- override computeRealType ( ) : string {
3900+ override computeEffectiveType ( ) : string {
38953901 const declaredTag = utils . getStructNameFromType ( this . type ) ;
38963902 if ( declaredTag !== 'List' ) {
38973903 return utils . substituteStructName ( this . type , 'List' ) ;
@@ -3900,7 +3906,7 @@ export class ListNodeVariable extends NodeVariable {
39003906 }
39013907
39023908 private async castToList ( ) {
3903- const realType = this . getRealType ( ) ;
3909+ const realType = this . getType ( ) ;
39043910 const castExpression = `(${ realType } ) (${ this . getPointer ( ) } )` ;
39053911 const response = await this . debug . evaluate ( castExpression , this . frameId ) ;
39063912 if ( ! Number . isInteger ( response . variablesReference ) ) {
@@ -4344,7 +4350,7 @@ class BitmapSetSpecialMember extends NodeVariable {
43444350
43454351 let type ;
43464352 if ( this . parent instanceof NodeVariable ) {
4347- type = this . parent . getRealType ( ) ;
4353+ type = this . parent . getType ( ) ;
43484354 } else {
43494355 type = this . parent . type ;
43504356 }
@@ -5430,8 +5436,8 @@ class FlagsMemberVariable extends RealVariable {
54305436 *
54315437 * @param variable Instance of variable user clicked on
54325438 */
5433- export function getWatchExpressionCommandHandler ( variable : any ) {
5439+ export async function getWatchExpressionCommandHandler ( variable : any ) {
54345440 return variable instanceof Variable
5435- ? variable . getWatchExpression ( )
5441+ ? await variable . getWatchExpression ( )
54365442 : null ;
54375443}
0 commit comments