Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat(hover): show name of struct/message in hover documentation for fields/constants/functions #95

Merged
merged 2 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 58 additions & 5 deletions server/src/documentation/documentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ const DOC_TMPL = `${CODE_FENCE}\n{signature}\n${CODE_FENCE}\n{documentation}\n`
*/
export function generateDocFor(node: NamedNode): string | null {
const astNode = node.node

function renderOwnerPresentation(symbol: Fun | Constant | Field): string | null {
const owner = symbol.owner()
if (!owner) return null // not possible in correct code
return owner.kind() + " " + owner.name() + "\n"
}

function renderDataOwnerPresentation(symbol: Field): string | null {
const owner = symbol.dataOwner()
if (!owner) return null // not possible in correct code
return owner.kind() + " " + owner.name() + "\n"
}

switch (astNode.type) {
case "native_function": {
const func = new Fun(astNode, node.file)
Expand All @@ -37,14 +50,16 @@ export function generateDocFor(node: NamedNode): string | null {
case "storage_function": {
const func = new Fun(astNode, node.file)
const doc = extractCommentsDoc(node)
const ownerPresentation = renderOwnerPresentation(func)
if (!ownerPresentation) return null // not possible in correct code

const actualId = func.computeMethodId()
const actualIdPresentation = `Method ID: \`0x${actualId.toString(16)}\`\n\n`

const idPresentation = func.isGetMethod ? actualIdPresentation : ""

return defaultResult(
`${func.modifiers()}fun ${node.name()}${func.signaturePresentation()}`,
`${ownerPresentation}${func.modifiers()}fun ${node.name()}${func.signaturePresentation()}`,
idPresentation + doc,
)
}
Expand Down Expand Up @@ -104,8 +119,7 @@ export function generateDocFor(node: NamedNode): string | null {
const doc = extractCommentsDoc(node)
return defaultResult(`primitive ${node.name()}`, doc)
}
case "global_constant":
case "storage_constant": {
case "global_constant": {
const constant = new Constant(astNode, node.file)
const type = constant.typeNode()?.type()?.qualifiedName() ?? "unknown"
if (!type) return null
Expand All @@ -119,17 +133,56 @@ export function generateDocFor(node: NamedNode): string | null {
doc,
)
}
case "storage_variable":
case "storage_constant": {
const constant = new Constant(astNode, node.file)
const type = constant.typeNode()?.type()?.qualifiedName() ?? "unknown"
if (!type) return null

const ownerPresentation = renderOwnerPresentation(constant)
if (!ownerPresentation) return null // not possible in correct code

const value = constant.value()
if (!value) return null

const doc = extractCommentsDoc(node)
return defaultResult(
`${ownerPresentation}${constant.modifiers()}const ${node.name()}: ${type} = ${value.node.text}`,
doc,
)
}
case "storage_variable": {
const doc = extractCommentsDoc(node)
const field = new Field(node.node, node.file)

const ownerPresentation = renderOwnerPresentation(field)
if (!ownerPresentation) return null // not possible in correct code

const name = field.nameNode()
if (!name) return null

const type = TypeInferer.inferType(name)?.qualifiedName() ?? "unknown"

return defaultResult(
`${ownerPresentation}${node.name()}: ${type}${field.defaultValuePresentation()}`,
doc,
)
}
case "field": {
const doc = extractCommentsDoc(node)
const field = new Field(node.node, node.file)

const ownerPresentation = renderDataOwnerPresentation(field)
if (!ownerPresentation) return null // not possible in correct code

const name = field.nameNode()
if (!name) return null

const type = TypeInferer.inferType(name)?.qualifiedName() ?? "unknown"

return defaultResult(`${node.name()}: ${type}${field.defaultValuePresentation()}`, doc)
return defaultResult(
`${ownerPresentation}${node.name()}: ${type}${field.defaultValuePresentation()}`,
doc,
)
}
case "identifier": {
const parent = astNode.parent
Expand Down
88 changes: 1 addition & 87 deletions server/src/e2e/suite/testcases/documentation/basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -78,93 +78,6 @@ fun foo(<caret>param: Int) {
param: Int
```

========================================================================
Field declaration
========================================================================
primitive Int;

struct Foo {
field: Int;
}

fun foo() {
let f = Foo { <caret>field: 10 };
}
------------------------------------------------------------------------
```
field: Int
```

========================================================================
Field declaration 2
========================================================================
primitive Int;

struct Foo {
field: Int;
}

fun foo() {
let f = Foo { field: 10 };
f.<caret>field;
}
------------------------------------------------------------------------
```
field: Int
```

========================================================================
Field declaration with default value
========================================================================
primitive Int;

struct Foo {
field: Int = 0;
}

fun foo() {
let f = Foo { field: 10 };
f.<caret>field;
}
------------------------------------------------------------------------
```
field: Int = 0
```

========================================================================
Contract field declaration
========================================================================
primitive Int;

contract Foo {
field: Int;

fun foo() {
self.<caret>field;
}
}
------------------------------------------------------------------------
```
field: Int
```

========================================================================
Contract field declaration with default value
========================================================================
primitive Int;

contract Foo {
field: Int = 0;

fun foo() {
self.<caret>field;
}
}
------------------------------------------------------------------------
```
field: Int = 0
```

========================================================================
Constant declaration
========================================================================
Expand Down Expand Up @@ -194,6 +107,7 @@ contract Foo {
}
------------------------------------------------------------------------
```
contract Foo
const FOO: Int = 100
```

Expand Down
76 changes: 76 additions & 0 deletions server/src/e2e/suite/testcases/documentation/contracts.test
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ contract Foo {
}
------------------------------------------------------------------------
```
contract Foo
get fun foo()
```
Method ID: `0x103fc`
Expand All @@ -52,6 +53,81 @@ contract Foo {
}
------------------------------------------------------------------------
```
contract Foo
fun foo()
```
Some cool function

========================================================================
Contract field declaration
========================================================================
primitive Int;

contract Foo {
field: Int;

fun foo() {
self.<caret>field;
}
}
------------------------------------------------------------------------
```
contract Foo
field: Int
```

========================================================================
Contract field declaration with default value
========================================================================
primitive Int;

contract Foo {
field: Int = 0;

fun foo() {
self.<caret>field;
}
}
------------------------------------------------------------------------
```
contract Foo
field: Int = 0
```

========================================================================
Contract constant declaration with default value
========================================================================
primitive Int;

contract Foo {
const FOO: Int = 0;

fun foo() {
self.<caret>FOO;
}
}
------------------------------------------------------------------------
```
contract Foo
const FOO: Int = 0
```

========================================================================
Contract constant declaration from trait
========================================================================
primitive Int;

trait WithFoo {
const FOO: Int = 0;
}

contract Foo with WithFoo {
fun foo() {
self.<caret>FOO;
}
}
------------------------------------------------------------------------
```
trait WithFoo
const FOO: Int = 0
```
75 changes: 75 additions & 0 deletions server/src/e2e/suite/testcases/documentation/structs.test
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,78 @@ message(0x178d4519) Foo {
}
```
Some cool message

========================================================================
Field declaration
========================================================================
primitive Int;

struct Foo {
field: Int;
}

fun foo() {
let f = Foo { <caret>field: 10 };
}
------------------------------------------------------------------------
```
struct Foo
field: Int
```

========================================================================
Field declaration 2
========================================================================
primitive Int;

struct Foo {
field: Int;
}

fun foo() {
let f = Foo { field: 10 };
f.<caret>field;
}
------------------------------------------------------------------------
```
struct Foo
field: Int
```

========================================================================
Field declaration 3
========================================================================
primitive Int;

message Foo {
field: Int;
}

fun foo() {
let f = Foo { field: 10 };
f.<caret>field;
}
------------------------------------------------------------------------
```
message Foo
field: Int
```

========================================================================
Field declaration with default value
========================================================================
primitive Int;

struct Foo {
field: Int = 0;
}

fun foo() {
let f = Foo { field: 10 };
f.<caret>field;
}
------------------------------------------------------------------------
```
struct Foo
field: Int = 0
```
14 changes: 14 additions & 0 deletions server/src/e2e/suite/testcases/documentation/traits.test
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,17 @@ trait <caret>Foo with Other {
trait Foo with Other
```
Some cool trait

========================================================================
Trait field declaration
========================================================================
primitive Int;

trait Foo {
<caret>field: Int;
}
------------------------------------------------------------------------
```
trait Foo
field: Int
```
Loading