Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add some clangd LSP extensions to the ClangdLanguageServer API #256

Merged
merged 1 commit into from
Feb 19, 2024
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
4 changes: 3 additions & 1 deletion bundles/org.eclipse.cdt.lsp/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ Export-Package: org.eclipse.cdt.lsp,
org.eclipse.cdt.lsp.editor,
org.eclipse.cdt.lsp.server,
org.eclipse.cdt.lsp.server.enable,
org.eclipse.cdt.lsp.services
org.eclipse.cdt.lsp.services,
org.eclipse.cdt.lsp.services.ast,
org.eclipse.cdt.lsp.services.symbolinfo
Bundle-Activator: org.eclipse.cdt.lsp.LspPlugin
Bundle-Vendor: %Bundle-Vendor
Require-Bundle: org.eclipse.ui,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,32 @@
*
* Contributors:
* Dominic Scharfe (COSEDA Technologies GmbH) - initial implementation
* Dietrich Travkin (Solunar GmbH) - extensions for AST and symbol info
*******************************************************************************/
package org.eclipse.cdt.lsp.services;

import java.util.concurrent.CompletableFuture;

import org.eclipse.cdt.lsp.services.ast.AstNode;
import org.eclipse.cdt.lsp.services.ast.AstParams;
import org.eclipse.cdt.lsp.services.symbolinfo.SymbolDetails;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
import org.eclipse.lsp4j.services.LanguageServer;

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

/**
* The switchSourceHeader request is sent from the client to the server to
* The <em>textDocument/switchSourceHeader</em> request is sent from the client to the server to
* <ul>
* <li>get the corresponding header if a source file was provided</li>
* <li>get the source file if a header was provided</li>
Expand All @@ -39,4 +47,31 @@ public interface ClangdLanguageServer extends LanguageServer {
*/
@JsonRequest(value = "textDocument/switchSourceHeader")
CompletableFuture<String> switchSourceHeader(TextDocumentIdentifier textDocument);

/**
* The <em>textDocument/ast</em> request is sent from the client to the server in order to get
* details about the program structure (so called abstract syntax tree or AST) in a C++ file.
* The structure can be requested for the whole file or for a certain range.
*
* @param astParameters request parameters containing the document identifier and requested documented range
* @return the abstract syntax tree root node (with child hierarchy) for the requested document and range
*
* @see https://clangd.llvm.org/extensions#ast
*/
@JsonRequest(value = "textDocument/ast")
CompletableFuture<AstNode> getAst(AstParams astParameters);

/**
* The <em>textDocument/symbolInfo</em> request is sent from the client to the server in order to access
* details about the element under the cursor. The response provides details like the element's name,
* its parent container's name, and some clangd-specific element IDs (e.g. the "unified symbol resolution"
* identifier).
*
* @param positionParameters request parameters containing the document identifier and the current cursor position
* @return the details about the symbol on the given position
*
* @see https://clangd.llvm.org/extensions#symbol-info-request
*/
@JsonRequest(value = "textDocument/symbolInfo")
CompletableFuture<SymbolDetails[]> getSymbolInfo(TextDocumentPositionParams positionParameters);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*******************************************************************************
* Copyright (c) 2024 Advantest Europe GmbH and others.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Dietrich Travkin (Solunar GmbH) - Initial implementation
*******************************************************************************/
package org.eclipse.cdt.lsp.services.ast;
ruspl-afed marked this conversation as resolved.
Show resolved Hide resolved

import java.util.Arrays;

import org.eclipse.cdt.lsp.services.ClangdLanguageServer;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.jsonrpc.util.Preconditions;
import org.eclipse.lsp4j.jsonrpc.util.ToStringBuilder;
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;

/**
* Return type for the <em>textDocument/ast</em> request.
* This class was generated by the <em>org.eclipse.lsp4j.generator</em> bundle
* using xtend (see {@link org.eclipse.lsp4j.generator.JsonRpcData JsonRpcData} and
* the <a href="https://github.com/eclipse-lsp4j/lsp4j/blob/main/documentation/jsonrpc.md">documentation</a>).
*
* @see {@link ClangdLanguageServer#getAst(AstParams)}
*/
public class AstNode {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I has a smell that cdt-lsp is providing these classes without using them. That's dead code in an exported package. @travkin79 could implement these classes in your custom plug-in where its used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could implement these classes in your custom plug-in where its used?

Forget my comment, I think it s to be implemented here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These classes are part of the extended ClangdLanguageServer interface. Without them, the code will not compile and LSP4J will not be able to parse the LS response. Removing these classes would mean to remove the new methods from the ClangdLanguageServer interface, i.e. removing the new clangd LSP extensions.


@NonNull
private String role;

@NonNull
private String kind;

private String detail;

private String arcana;

@NonNull
private Range range;

private AstNode[] children;

public AstNode() {

}

@NonNull
public String getRole() {
return role;
}

public void setRole(@NonNull final String role) {
this.role = Preconditions.<String>checkNotNull(role, "role"); //$NON-NLS-1$
}

@NonNull
public String getKind() {
return this.kind;
}

public void setKind(@NonNull final String kind) {
this.kind = Preconditions.<String>checkNotNull(kind, "kind"); //$NON-NLS-1$
}

public String getDetail() {
return detail;
}

public void setDetail(final String detail) {
this.detail = detail;
}

public String getArcana() {
return arcana;
}

public void setArcana(final String arcana) {
this.arcana = arcana;
}

@NonNull
public Range getRange() {
return range;
}

public void setRange(@NonNull final Range range) {
this.range = Preconditions.<Range>checkNotNull(range, "range"); //$NON-NLS-1$
}

public AstNode[] getChildren() {
return children;
}

public void setChildren(final AstNode[] children) {
this.children = children;
}

@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this);
b.add("role", this.role); //$NON-NLS-1$
b.add("kind", this.kind); //$NON-NLS-1$
b.add("detail", this.detail); //$NON-NLS-1$
b.add("arcana", this.arcana); //$NON-NLS-1$
b.add("range", this.range); //$NON-NLS-1$
b.add("children", this.children); //$NON-NLS-1$
return b.toString();
}

@Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AstNode other = (AstNode) obj;
if (this.role == null) {
if (other.role != null)
return false;
} else if (!this.role.equals(other.role))
return false;
if (this.kind == null) {
if (other.kind != null)
return false;
} else if (!this.kind.equals(other.kind))
return false;
if (this.detail == null) {
if (other.detail != null)
return false;
} else if (!this.detail.equals(other.detail))
return false;
if (this.arcana == null) {
if (other.arcana != null)
return false;
} else if (!this.arcana.equals(other.arcana))
return false;
if (this.range == null) {
if (other.range != null)
return false;
} else if (!this.range.equals(other.range))
return false;
if (this.children == null) {
if (other.children != null)
return false;
} else if (!Arrays.deepEquals(this.children, other.children))
return false;
return true;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.role == null) ? 0 : this.role.hashCode());
result = prime * result + ((this.kind == null) ? 0 : this.kind.hashCode());
result = prime * result + ((this.detail == null) ? 0 : this.detail.hashCode());
result = prime * result + ((this.arcana == null) ? 0 : this.arcana.hashCode());
result = prime * result + ((this.range == null) ? 0 : this.range.hashCode());
return prime * result + ((this.children == null) ? 0 : Arrays.deepHashCode(this.children));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*******************************************************************************
* Copyright (c) 2024 Advantest Europe GmbH and others.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Dietrich Travkin (Solunar GmbH) - Initial implementation
*******************************************************************************/
package org.eclipse.cdt.lsp.services.ast;
ruspl-afed marked this conversation as resolved.
Show resolved Hide resolved

import org.eclipse.cdt.lsp.services.ClangdLanguageServer;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.jsonrpc.util.Preconditions;
import org.eclipse.lsp4j.jsonrpc.util.ToStringBuilder;
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;

/**
* Parameter object type for the <em>textDocument/ast</em> request.
* This class was generated by the <em>org.eclipse.lsp4j.generator</em> bundle
* using xtend (see {@link org.eclipse.lsp4j.generator.JsonRpcData JsonRpcData} and
* the <a href="https://github.com/eclipse-lsp4j/lsp4j/blob/main/documentation/jsonrpc.md">documentation</a>).
*
* @see {@link ClangdLanguageServer#getAst(AstParams)}
*/
public class AstParams {

@NonNull
private TextDocumentIdentifier textDocument;

@NonNull
private Range range;

public AstParams() {
}

public AstParams(@NonNull final TextDocumentIdentifier textDocument, @NonNull final Range range) {
this.textDocument = Preconditions.<TextDocumentIdentifier>checkNotNull(textDocument, "textDocument"); //$NON-NLS-1$
this.range = Preconditions.<Range>checkNotNull(range, "range"); //$NON-NLS-1$
}

@NonNull
public TextDocumentIdentifier getTextDocument() {
return this.textDocument;
}

public void setTextDocument(@NonNull final TextDocumentIdentifier textDocument) {
this.textDocument = Preconditions.<TextDocumentIdentifier>checkNotNull(textDocument, "textDocument"); //$NON-NLS-1$
}

@NonNull
public Range getRange() {
return range;
}

public void setRange(@NonNull Range range) {
this.range = Preconditions.<Range>checkNotNull(range, "range"); //$NON-NLS-1$
}

@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this);
b.add("textDocument", getTextDocument()); //$NON-NLS-1$
b.add("range", getRange()); //$NON-NLS-1$
return b.toString();
}

@Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AstParams other = (AstParams) obj;
if (this.getTextDocument() == null) {
if (other.getTextDocument() != null)
return false;
} else if (!this.getTextDocument().equals(other.getTextDocument()))
return false;
if (this.range == null) {
if (other.range != null)
return false;
} else if (!this.range.equals(other.range))
return false;
return true;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.getTextDocument() == null) ? 0 : this.getTextDocument().hashCode());
return prime * result + ((this.range == null) ? 0 : this.range.hashCode());
}
}
Loading
Loading