Skip to content

Commit 51ffc73

Browse files
authored
Add clangd extensions textDocument/symbolInfo and textDocument/ast (#256)
1 parent d5941b9 commit 51ffc73

File tree

6 files changed

+557
-2
lines changed

6 files changed

+557
-2
lines changed

Diff for: bundles/org.eclipse.cdt.lsp/META-INF/MANIFEST.MF

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ Export-Package: org.eclipse.cdt.lsp,
77
org.eclipse.cdt.lsp.editor,
88
org.eclipse.cdt.lsp.server,
99
org.eclipse.cdt.lsp.server.enable,
10-
org.eclipse.cdt.lsp.services
10+
org.eclipse.cdt.lsp.services,
11+
org.eclipse.cdt.lsp.services.ast,
12+
org.eclipse.cdt.lsp.services.symbolinfo
1113
Bundle-Activator: org.eclipse.cdt.lsp.LspPlugin
1214
Bundle-Vendor: %Bundle-Vendor
1315
Require-Bundle: org.eclipse.ui,

Diff for: bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ClangdLanguageServer.java

+36-1
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,32 @@
99
*
1010
* Contributors:
1111
* Dominic Scharfe (COSEDA Technologies GmbH) - initial implementation
12+
* Dietrich Travkin (Solunar GmbH) - extensions for AST and symbol info
1213
*******************************************************************************/
1314
package org.eclipse.cdt.lsp.services;
1415

1516
import java.util.concurrent.CompletableFuture;
1617

18+
import org.eclipse.cdt.lsp.services.ast.AstNode;
19+
import org.eclipse.cdt.lsp.services.ast.AstParams;
20+
import org.eclipse.cdt.lsp.services.symbolinfo.SymbolDetails;
1721
import org.eclipse.lsp4j.TextDocumentIdentifier;
22+
import org.eclipse.lsp4j.TextDocumentPositionParams;
1823
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
1924
import org.eclipse.lsp4j.services.LanguageServer;
2025

2126
/**
2227
* Interface extending the {@link LanguageServer} with clangd extensions.
28+
* More details about LSP usage and extension see the
29+
* <a href="https://github.com/eclipse-lsp4j/lsp4j/blob/main/documentation/jsonrpc.md">
30+
* org.eclipse.lsp4j project's documentation</a>.
2331
*
2432
* @see https://clangd.llvm.org/extensions
2533
*/
2634
public interface ClangdLanguageServer extends LanguageServer {
2735

2836
/**
29-
* The switchSourceHeader request is sent from the client to the server to
37+
* The <em>textDocument/switchSourceHeader</em> request is sent from the client to the server to
3038
* <ul>
3139
* <li>get the corresponding header if a source file was provided</li>
3240
* <li>get the source file if a header was provided</li>
@@ -39,4 +47,31 @@ public interface ClangdLanguageServer extends LanguageServer {
3947
*/
4048
@JsonRequest(value = "textDocument/switchSourceHeader")
4149
CompletableFuture<String> switchSourceHeader(TextDocumentIdentifier textDocument);
50+
51+
/**
52+
* The <em>textDocument/ast</em> request is sent from the client to the server in order to get
53+
* details about the program structure (so called abstract syntax tree or AST) in a C++ file.
54+
* The structure can be requested for the whole file or for a certain range.
55+
*
56+
* @param astParameters request parameters containing the document identifier and requested documented range
57+
* @return the abstract syntax tree root node (with child hierarchy) for the requested document and range
58+
*
59+
* @see https://clangd.llvm.org/extensions#ast
60+
*/
61+
@JsonRequest(value = "textDocument/ast")
62+
CompletableFuture<AstNode> getAst(AstParams astParameters);
63+
64+
/**
65+
* The <em>textDocument/symbolInfo</em> request is sent from the client to the server in order to access
66+
* details about the element under the cursor. The response provides details like the element's name,
67+
* its parent container's name, and some clangd-specific element IDs (e.g. the "unified symbol resolution"
68+
* identifier).
69+
*
70+
* @param positionParameters request parameters containing the document identifier and the current cursor position
71+
* @return the details about the symbol on the given position
72+
*
73+
* @see https://clangd.llvm.org/extensions#symbol-info-request
74+
*/
75+
@JsonRequest(value = "textDocument/symbolInfo")
76+
CompletableFuture<SymbolDetails[]> getSymbolInfo(TextDocumentPositionParams positionParameters);
4277
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Advantest Europe GmbH and others.
3+
* This program and the accompanying materials are made
4+
* available under the terms of the Eclipse Public License 2.0
5+
* which is available at https://www.eclipse.org/legal/epl-2.0/
6+
*
7+
* SPDX-License-Identifier: EPL-2.0
8+
*
9+
* Contributors:
10+
* Dietrich Travkin (Solunar GmbH) - Initial implementation
11+
*******************************************************************************/
12+
package org.eclipse.cdt.lsp.services.ast;
13+
14+
import java.util.Arrays;
15+
16+
import org.eclipse.cdt.lsp.services.ClangdLanguageServer;
17+
import org.eclipse.lsp4j.Range;
18+
import org.eclipse.lsp4j.jsonrpc.util.Preconditions;
19+
import org.eclipse.lsp4j.jsonrpc.util.ToStringBuilder;
20+
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
21+
22+
/**
23+
* Return type for the <em>textDocument/ast</em> request.
24+
* This class was generated by the <em>org.eclipse.lsp4j.generator</em> bundle
25+
* using xtend (see {@link org.eclipse.lsp4j.generator.JsonRpcData JsonRpcData} and
26+
* the <a href="https://github.com/eclipse-lsp4j/lsp4j/blob/main/documentation/jsonrpc.md">documentation</a>).
27+
*
28+
* @see {@link ClangdLanguageServer#getAst(AstParams)}
29+
*/
30+
public class AstNode {
31+
32+
@NonNull
33+
private String role;
34+
35+
@NonNull
36+
private String kind;
37+
38+
private String detail;
39+
40+
private String arcana;
41+
42+
@NonNull
43+
private Range range;
44+
45+
private AstNode[] children;
46+
47+
public AstNode() {
48+
49+
}
50+
51+
@NonNull
52+
public String getRole() {
53+
return role;
54+
}
55+
56+
public void setRole(@NonNull final String role) {
57+
this.role = Preconditions.<String>checkNotNull(role, "role"); //$NON-NLS-1$
58+
}
59+
60+
@NonNull
61+
public String getKind() {
62+
return this.kind;
63+
}
64+
65+
public void setKind(@NonNull final String kind) {
66+
this.kind = Preconditions.<String>checkNotNull(kind, "kind"); //$NON-NLS-1$
67+
}
68+
69+
public String getDetail() {
70+
return detail;
71+
}
72+
73+
public void setDetail(final String detail) {
74+
this.detail = detail;
75+
}
76+
77+
public String getArcana() {
78+
return arcana;
79+
}
80+
81+
public void setArcana(final String arcana) {
82+
this.arcana = arcana;
83+
}
84+
85+
@NonNull
86+
public Range getRange() {
87+
return range;
88+
}
89+
90+
public void setRange(@NonNull final Range range) {
91+
this.range = Preconditions.<Range>checkNotNull(range, "range"); //$NON-NLS-1$
92+
}
93+
94+
public AstNode[] getChildren() {
95+
return children;
96+
}
97+
98+
public void setChildren(final AstNode[] children) {
99+
this.children = children;
100+
}
101+
102+
@Override
103+
public String toString() {
104+
ToStringBuilder b = new ToStringBuilder(this);
105+
b.add("role", this.role); //$NON-NLS-1$
106+
b.add("kind", this.kind); //$NON-NLS-1$
107+
b.add("detail", this.detail); //$NON-NLS-1$
108+
b.add("arcana", this.arcana); //$NON-NLS-1$
109+
b.add("range", this.range); //$NON-NLS-1$
110+
b.add("children", this.children); //$NON-NLS-1$
111+
return b.toString();
112+
}
113+
114+
@Override
115+
public boolean equals(final Object obj) {
116+
if (this == obj)
117+
return true;
118+
if (obj == null)
119+
return false;
120+
if (getClass() != obj.getClass())
121+
return false;
122+
AstNode other = (AstNode) obj;
123+
if (this.role == null) {
124+
if (other.role != null)
125+
return false;
126+
} else if (!this.role.equals(other.role))
127+
return false;
128+
if (this.kind == null) {
129+
if (other.kind != null)
130+
return false;
131+
} else if (!this.kind.equals(other.kind))
132+
return false;
133+
if (this.detail == null) {
134+
if (other.detail != null)
135+
return false;
136+
} else if (!this.detail.equals(other.detail))
137+
return false;
138+
if (this.arcana == null) {
139+
if (other.arcana != null)
140+
return false;
141+
} else if (!this.arcana.equals(other.arcana))
142+
return false;
143+
if (this.range == null) {
144+
if (other.range != null)
145+
return false;
146+
} else if (!this.range.equals(other.range))
147+
return false;
148+
if (this.children == null) {
149+
if (other.children != null)
150+
return false;
151+
} else if (!Arrays.deepEquals(this.children, other.children))
152+
return false;
153+
return true;
154+
}
155+
156+
@Override
157+
public int hashCode() {
158+
final int prime = 31;
159+
int result = 1;
160+
result = prime * result + ((this.role == null) ? 0 : this.role.hashCode());
161+
result = prime * result + ((this.kind == null) ? 0 : this.kind.hashCode());
162+
result = prime * result + ((this.detail == null) ? 0 : this.detail.hashCode());
163+
result = prime * result + ((this.arcana == null) ? 0 : this.arcana.hashCode());
164+
result = prime * result + ((this.range == null) ? 0 : this.range.hashCode());
165+
return prime * result + ((this.children == null) ? 0 : Arrays.deepHashCode(this.children));
166+
}
167+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Advantest Europe GmbH and others.
3+
* This program and the accompanying materials are made
4+
* available under the terms of the Eclipse Public License 2.0
5+
* which is available at https://www.eclipse.org/legal/epl-2.0/
6+
*
7+
* SPDX-License-Identifier: EPL-2.0
8+
*
9+
* Contributors:
10+
* Dietrich Travkin (Solunar GmbH) - Initial implementation
11+
*******************************************************************************/
12+
package org.eclipse.cdt.lsp.services.ast;
13+
14+
import org.eclipse.cdt.lsp.services.ClangdLanguageServer;
15+
import org.eclipse.lsp4j.Range;
16+
import org.eclipse.lsp4j.TextDocumentIdentifier;
17+
import org.eclipse.lsp4j.jsonrpc.util.Preconditions;
18+
import org.eclipse.lsp4j.jsonrpc.util.ToStringBuilder;
19+
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
20+
21+
/**
22+
* Parameter object type for the <em>textDocument/ast</em> request.
23+
* This class was generated by the <em>org.eclipse.lsp4j.generator</em> bundle
24+
* using xtend (see {@link org.eclipse.lsp4j.generator.JsonRpcData JsonRpcData} and
25+
* the <a href="https://github.com/eclipse-lsp4j/lsp4j/blob/main/documentation/jsonrpc.md">documentation</a>).
26+
*
27+
* @see {@link ClangdLanguageServer#getAst(AstParams)}
28+
*/
29+
public class AstParams {
30+
31+
@NonNull
32+
private TextDocumentIdentifier textDocument;
33+
34+
@NonNull
35+
private Range range;
36+
37+
public AstParams() {
38+
}
39+
40+
public AstParams(@NonNull final TextDocumentIdentifier textDocument, @NonNull final Range range) {
41+
this.textDocument = Preconditions.<TextDocumentIdentifier>checkNotNull(textDocument, "textDocument"); //$NON-NLS-1$
42+
this.range = Preconditions.<Range>checkNotNull(range, "range"); //$NON-NLS-1$
43+
}
44+
45+
@NonNull
46+
public TextDocumentIdentifier getTextDocument() {
47+
return this.textDocument;
48+
}
49+
50+
public void setTextDocument(@NonNull final TextDocumentIdentifier textDocument) {
51+
this.textDocument = Preconditions.<TextDocumentIdentifier>checkNotNull(textDocument, "textDocument"); //$NON-NLS-1$
52+
}
53+
54+
@NonNull
55+
public Range getRange() {
56+
return range;
57+
}
58+
59+
public void setRange(@NonNull Range range) {
60+
this.range = Preconditions.<Range>checkNotNull(range, "range"); //$NON-NLS-1$
61+
}
62+
63+
@Override
64+
public String toString() {
65+
ToStringBuilder b = new ToStringBuilder(this);
66+
b.add("textDocument", getTextDocument()); //$NON-NLS-1$
67+
b.add("range", getRange()); //$NON-NLS-1$
68+
return b.toString();
69+
}
70+
71+
@Override
72+
public boolean equals(final Object obj) {
73+
if (this == obj)
74+
return true;
75+
if (obj == null)
76+
return false;
77+
if (getClass() != obj.getClass())
78+
return false;
79+
AstParams other = (AstParams) obj;
80+
if (this.getTextDocument() == null) {
81+
if (other.getTextDocument() != null)
82+
return false;
83+
} else if (!this.getTextDocument().equals(other.getTextDocument()))
84+
return false;
85+
if (this.range == null) {
86+
if (other.range != null)
87+
return false;
88+
} else if (!this.range.equals(other.range))
89+
return false;
90+
return true;
91+
}
92+
93+
@Override
94+
public int hashCode() {
95+
final int prime = 31;
96+
int result = 1;
97+
result = prime * result + ((this.getTextDocument() == null) ? 0 : this.getTextDocument().hashCode());
98+
return prime * result + ((this.range == null) ? 0 : this.range.hashCode());
99+
}
100+
}

0 commit comments

Comments
 (0)