Skip to content

Commit 2b1a9bc

Browse files
committed
refactor: cleaned up watch expression formatter code
1 parent f3ff1ab commit 2b1a9bc

File tree

2 files changed

+74
-68
lines changed

2 files changed

+74
-68
lines changed

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1371,7 +1371,7 @@ export function setupExtension(context: vscode.ExtensionContext,
13711371
};
13721372

13731373
const addVariableToWatchCmd = async (args: any) => {
1374-
const expr = vars.getWatchExpressionCommandHandler(args);
1374+
const expr = await vars.getWatchExpressionCommandHandler(args);
13751375
if (!expr) {
13761376
return;
13771377
}

src/variables.ts

Lines changed: 73 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)