@@ -856,14 +856,54 @@ export abstract class Variable {
856856 type : effectiveType ,
857857 declaredType : debugVariable . type ,
858858 } ;
859+
860+ /* Value struct are not so interesting for us */
861+ if ( context . debug . isValueStruct ( debugVariable , effectiveType ) ) {
862+ if ( parent ) {
863+ if ( utils . isValueStructOrPointerType ( parent . type ) ) {
864+ const flagsMember = context . specialMemberRegistry . getFlagsMember (
865+ utils . getStructNameFromType ( parent . type ) ,
866+ debugVariable . name ) ;
867+ if ( flagsMember ) {
868+ return new FlagsMemberVariable ( flagsMember , args ) ;
869+ }
870+ }
871+ }
872+
873+ if ( effectiveType === 'bitmapword' ) {
874+ /* Show bitmapword as bitmask, not integer */
875+ return new BitmapwordVariable ( args ) ;
876+ }
877+
878+ return new RealVariable ( args ) ;
879+ }
859880
860- if ( context . debug . isValueStruct ( debugVariable , effectiveType )
861- || ! context . debug . isValidPointerType ( debugVariable ) ) {
881+ /*
882+ * Pointer types can be NULL or contain invalid pointers.
883+ * cppdbg do not recognize invalid pointers, but CodeLLDB - <invalid pointer>.
884+ */
885+ if ( ! context . debug . isValidPointerType ( debugVariable ) ) {
862886 /*
863887 * We are here if got scalar type or value struct (not pointer).
864888 * These types are not so interesting for us, so pass here to
865889 * quickly return usual variable.
866890 */
891+
892+ if ( context . debug . isNull ( debugVariable )
893+ && debugVariable . type . endsWith ( 'List *' ) ) {
894+ /*
895+ * Empty List is NIL == NULL == '0x0' Also 'endsWith'
896+ * covers cases like 'const List *'.
897+ *
898+ * Note that even if 'Bitmapset' also falls in this
899+ * variable category (NULL is meaningful), by design
900+ * do not create 'BitmapSetSpecialMember' for it,
901+ * because some runtime checks will end up in SEGFAULT.
902+ * Currently, there is no need for that, but take this
903+ * into account if you are planning to do this.
904+ */
905+ return new ListNodeVariable ( 'List' , args ) ;
906+ }
867907
868908 if ( context . debug . isNull ( debugVariable ) &&
869909 debugVariable . type . endsWith ( 'List *' ) ) {
@@ -881,26 +921,12 @@ export abstract class Variable {
881921 return new ListNodeVariable ( 'List' , args ) ;
882922 }
883923
884- if ( effectiveType === 'bitmapword' ) {
885- /* Show bitmapword as bitmask, not integer */
886- return new BitmapwordVariable ( args ) ;
887- }
888-
889924 if ( parent ) {
890- if ( utils . isValueStructOrPointerType ( parent . type ) ) {
891- const flagsMember = context . specialMemberRegistry . getFlagsMember (
892- utils . getStructNameFromType ( parent . type ) ,
893- debugVariable . name ) ;
894- if ( flagsMember ) {
895- return new FlagsMemberVariable ( flagsMember , args ) ;
896- }
897- }
898-
899925 /*
900926 * Flexible array members for now recognized as non-valid
901927 * pointers/scalars, but we actually can handle them.
902928 */
903- if ( debugVariable . type . endsWith ( '[]' ) ) {
929+ if ( utils . isFlexibleArrayMember ( debugVariable . type ) ) {
904930 const parentType = Variable . getRealType ( parent . type , context ) ;
905931 const specialMember = context . specialMemberRegistry
906932 . getArraySpecialMember ( parentType , debugVariable . name ) ;
@@ -931,6 +957,10 @@ export abstract class Variable {
931957 /*
932958 * PostgreSQL versions prior 16 do not have Bitmapset Node.
933959 * So handle Bitmapset (with Relids) here.
960+ *
961+ * NOTE: this check must be before general 'isNodeVar', because
962+ * NULL is valid value otherwise this will break assumption
963+ * that passed 'debugVariable' is not NULL
934964 */
935965 if ( BitmapSetSpecialMember . isBitmapsetType ( effectiveType ) ) {
936966 return new BitmapSetSpecialMember ( args ) ;
@@ -951,7 +981,7 @@ export abstract class Variable {
951981 return new HTABSpecialMember ( args ) ;
952982 }
953983
954- /* Simple hash table (simple hash ) */
984+ /* Simple hash table (lib/simplehash.h ) */
955985 if ( SimplehashMember . looksLikeSimpleHashTable ( effectiveType ) ) {
956986 const entry = context . hashTableTypes . findSimpleHashTableType ( effectiveType ) ;
957987 if ( entry ) {
@@ -1750,9 +1780,14 @@ export class NodeVariable extends RealVariable {
17501780 static async createNode ( variable : dap . DebugVariable , frameId : number ,
17511781 context : ExecContext , args : RealVariableArgs ) {
17521782 const getRealNodeTag = async ( ) => {
1753- const expr = `((Node*)(${ context . debug . getPointer ( variable ) } ))->type` ;
1783+ const expr = `((Node *)(${ context . debug . getPointer ( variable ) } ))->type` ;
17541784 const response = await context . debug . evaluate ( expr , frameId ) ;
1755- const realTag = response . result . replace ( 'T_' , '' ) ;
1785+ if ( ! response . result . startsWith ( 'T_' ) ) {
1786+ return ;
1787+ }
1788+
1789+ /* Do not use replace('T_', ''), because this 'T_' can be inside identifier */
1790+ const realTag = response . result . substring ( 2 ) ;
17561791 if ( ! context . nodeVarRegistry . isNodeTag ( realTag ) ) {
17571792 return ;
17581793 }
@@ -1783,23 +1818,24 @@ export class NodeVariable extends RealVariable {
17831818 return new BitmapSetSpecialMember ( args ) ;
17841819 }
17851820
1786- /* Expressions with it's representation */
1787- if ( context . nodeVarRegistry . exprs . has ( realTag ) ) {
1788- if ( realTag === 'TargetEntry' ) {
1789- return new TargetEntryVariable ( args ) ;
1790- }
1791-
1792- return new ExprNodeVariable ( realTag , args ) ;
1793- }
1794-
17951821 /* Display expressions in EquivalenceMember and RestrictInfo */
1822+ if ( realTag === 'TargetEntry' ) {
1823+ /* TargetEntry should be checked before 'exprs' - see class comment */
1824+ return new TargetEntryVariable ( args ) ;
1825+ }
1826+
17961827 if ( realTag === 'EquivalenceMember' ) {
17971828 return new DisplayExprReprVariable ( realTag , 'em_expr' , args ) ;
17981829 }
17991830
18001831 if ( realTag === 'RestrictInfo' ) {
18011832 return new DisplayExprReprVariable ( realTag , 'clause' , args ) ;
18021833 }
1834+
1835+ /* Expressions with it's representation */
1836+ if ( context . nodeVarRegistry . exprs . has ( realTag ) ) {
1837+ return new ExprNodeVariable ( realTag , args ) ;
1838+ }
18031839
18041840 /* Check this is a tag of 'Value' */
18051841 if ( realTag === 'String' ||
@@ -3533,13 +3569,11 @@ class DisplayExprReprVariable extends NodeVariable {
35333569}
35343570
35353571/**
3536- * Special case for 'TargetEntry' to display it's repr
3537- * in description.
3538- * It can not be moved to 'DisplayExprReprVariable' because
3539- * it is Expr and can be used in 'ExprVariable.
3540- * Also I do not want to move such logic to 'ExprVariable',
3541- * because repr evaluation is resource-intensive operation
3542- * and UI just blocks.
3572+ * Special case for 'TargetEntry' to display it's repr in description.
3573+ * It can not be moved to 'DisplayExprReprVariable' because it is Expr
3574+ * and can be used in 'ExprVariable'. Also I do not want to move such
3575+ * logic to 'ExprVariable', because repr evaluation is resource-intensive
3576+ * operation and UI just blocks.
35433577 */
35443578class TargetEntryVariable extends ExprNodeVariable {
35453579 constructor ( args : RealVariableArgs ) {
@@ -4856,6 +4890,7 @@ class HTABElementsMember extends Variable {
48564890
48574891 try {
48584892 await this . evaluateVoid ( expr ) ;
4893+ return memory ;
48594894 } catch ( err ) {
48604895 if ( ! ( err instanceof EvaluationError ) ) {
48614896 throw err ;
@@ -5023,7 +5058,8 @@ class SimplehashMember extends RealVariable {
50235058 /*
50245059 * Check this is last part of typename, i.e. not part of whole typename
50255060 */
5026- if ( type . length < index + '_hash' . length ) {
5061+ const endOfType = index + '_hash' . length ;
5062+ if ( type . length < endOfType ) {
50275063 /*
50285064 * I assume, every hash table object is a pointer type,
50295065 * not allocated on stack.
@@ -5036,7 +5072,7 @@ class SimplehashMember extends RealVariable {
50365072 * so typename actually ends with '_hash'.
50375073 * In real life only available continuation is space or star.
50385074 */
5039- const nextChar = type [ index + '_hash' . length ] ;
5075+ const nextChar = type [ endOfType ] ;
50405076 return nextChar === ' ' || nextChar === '*' ;
50415077 }
50425078
@@ -5508,7 +5544,6 @@ export class PgVariablesViewProvider implements vscode.TreeDataProvider<Variable
55085544 if ( config . nodetags ?. length ) {
55095545 logger . debug ( 'adding %i custom NodeTags' ) ;
55105546 try {
5511- /* TODO: add command to parse NodeTag files and find custom */
55125547 for ( const tag of config . nodetags ) {
55135548 nodeVars . nodeTags . add ( tag ) ;
55145549 }
0 commit comments