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

Prepare for variable refactorings #4679

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
30 changes: 30 additions & 0 deletions compiler/crates/common/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::fmt::Write;

use lsp_types::DiagnosticSeverity;
use lsp_types::DiagnosticTag;
use lsp_types::NumberOrString;
use serde::ser::SerializeMap;
use serde_json::Value;

Expand Down Expand Up @@ -64,6 +65,7 @@ impl Diagnostic {
tags: Vec<DiagnosticTag>,
) -> Self {
Self(Box::new(DiagnosticData {
code: None,
message: Box::new(message),
location,
related_information: Vec::new(),
Expand All @@ -88,6 +90,27 @@ impl Diagnostic {
) -> Self {
let data = message.get_data();
Self(Box::new(DiagnosticData {
code: None,
message: Box::new(message),
location,
tags: Vec::new(),
severity: DiagnosticSeverity::ERROR,
related_information: Vec::new(),
data,
machine_readable: BTreeMap::new(),
}))
}

/// Creates a new error Diagnostic with additional data and code
/// that can be used in IDE code actions
pub fn error_with_data_and_code<T: 'static + DiagnosticDisplay + WithDiagnosticData>(
code: i32,
message: T,
location: Location,
) -> Self {
let data = message.get_data();
Self(Box::new(DiagnosticData {
code: Some(NumberOrString::Number(code)),
message: Box::new(message),
location,
tags: Vec::new(),
Expand Down Expand Up @@ -167,6 +190,10 @@ impl Diagnostic {
self
}

pub fn code(&self) -> Option<NumberOrString> {
self.0.code.to_owned()
}

pub fn message(&self) -> &impl DiagnosticDisplay {
&self.0.message
}
Expand Down Expand Up @@ -276,6 +303,9 @@ where

#[derive(fmt::Debug)]
struct DiagnosticData {
/// The diagnostic's code. Can be omitted.
code: Option<NumberOrString>,

/// Human readable error message.
message: Box<dyn DiagnosticDisplay>,

Expand Down
4 changes: 2 additions & 2 deletions compiler/crates/relay-lsp/src/code_action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ pub(crate) fn on_code_action(
text_document: params.text_document,
position: params.range.start,
};
let (document, position_span) =
let (document, location) =
state.extract_executable_document_from_text(&text_document_position_params, 1)?;

let path = document.resolve((), position_span);
let path = document.resolve((), location.span());

let used_definition_names = get_definition_names(&definitions);
let result = get_code_actions(path, used_definition_names, uri, params.range)
Expand Down
4 changes: 2 additions & 2 deletions compiler/crates/relay-lsp/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1312,13 +1312,13 @@ pub fn on_completion(
params: <Completion as Request>::Params,
) -> LSPRuntimeResult<<Completion as Request>::Result> {
match state.extract_executable_document_from_text(&params.text_document_position, 0) {
Ok((document, position_span)) => {
Ok((document, location)) => {
let project_name = state
.extract_project_name_from_url(&params.text_document_position.text_document.uri)?;
let schema = &state.get_schema(&project_name)?;
let items = resolve_completion_items(
document,
position_span,
location.span(),
project_name,
schema,
state.get_schema_documentation(project_name.lookup()),
Expand Down
2 changes: 1 addition & 1 deletion compiler/crates/relay-lsp/src/diagnostic_reporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ impl DiagnosticReporter {
.collect::<Vec<_>>();

Diagnostic {
code: None,
code: diagnostic.code(),
data: get_diagnostics_data(diagnostic),
message: diagnostic.message().to_string(),
range: text_source.to_span_range(diagnostic.location().span()),
Expand Down
4 changes: 1 addition & 3 deletions compiler/crates/relay-lsp/src/find_field_usages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ use schema::Type;
use serde::Deserialize;
use serde::Serialize;

use crate::location::transform_relay_location_to_lsp_location;
use crate::server::GlobalState;
use crate::LSPRuntimeError;
use crate::LSPRuntimeResult;
Expand Down Expand Up @@ -80,13 +79,12 @@ pub fn on_find_field_usages(

let schema = state.get_schema(&schema_name)?;
let program = state.get_program(&schema_name)?;
let root_dir = &state.root_dir();

let ir_locations = get_usages(&program, &schema, type_name, field_name)?;
let lsp_locations = ir_locations
.into_iter()
.map(|(label, ir_location)| {
let lsp_location = transform_relay_location_to_lsp_location(root_dir, ir_location)?;
let lsp_location = state.get_lsp_location(ir_location)?;
Ok(FindFieldUsageResultItem {
location_uri: lsp_location.uri.to_string(),
location_range: lsp_location.range,
Expand Down
70 changes: 33 additions & 37 deletions compiler/crates/relay-lsp/src/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ use serde::Serialize;

use self::goto_docblock_definition::get_docblock_definition_description;
use self::goto_graphql_definition::get_graphql_definition_description;
use crate::location::transform_relay_location_to_lsp_location;
use crate::lsp_runtime_error::LSPRuntimeError;
use crate::lsp_runtime_error::LSPRuntimeResult;
use crate::server::GlobalState;
Expand Down Expand Up @@ -70,7 +69,7 @@ pub fn on_goto_definition(
state: &impl GlobalState,
params: <GotoDefinition as Request>::Params,
) -> LSPRuntimeResult<<GotoDefinition as Request>::Result> {
let (feature, position_span) =
let (feature, location) =
state.extract_feature_from_text(&params.text_document_position_params, 1)?;

let project_name = state
Expand All @@ -80,15 +79,14 @@ pub fn on_goto_definition(

let definition_description = match feature {
crate::Feature::GraphQLDocument(document) => {
get_graphql_definition_description(document, position_span, &schema)?
get_graphql_definition_description(document, location.span(), &schema)?
}
crate::Feature::DocblockIr(docblock_ir) => {
get_docblock_definition_description(&docblock_ir, position_span)?
get_docblock_definition_description(&docblock_ir, location.span())?
}
};

let extra_data_provider = state.get_extra_data_provider();
let root_dir = state.root_dir();

let goto_definition_response: GotoDefinitionResponse = match definition_description {
DefinitionDescription::FieldArgument {
Expand All @@ -100,14 +98,12 @@ pub fn on_goto_definition(
parent_type,
field_name,
argument_name,
&root_dir,
state,
)?,
DefinitionDescription::DirectiveArgument {
directive_name,
argument_name,
} => {
locate_directive_argument_definition(&schema, directive_name, argument_name, &root_dir)?
}
} => locate_directive_argument_definition(&schema, directive_name, argument_name, state)?,
DefinitionDescription::Field {
parent_type,
field_name,
Expand All @@ -117,20 +113,16 @@ pub fn on_goto_definition(
field_name,
extra_data_provider,
project_name,
&root_dir,
state,
)?,
DefinitionDescription::Fragment { fragment_name } => {
locate_fragment_definition(program, fragment_name, &root_dir)?
locate_fragment_definition(program, fragment_name, state)?
}
DefinitionDescription::Type { type_name } => {
locate_type_definition(extra_data_provider, project_name, type_name, &schema, state)?
}
DefinitionDescription::Type { type_name } => locate_type_definition(
extra_data_provider,
project_name,
type_name,
&schema,
&root_dir,
)?,
DefinitionDescription::Directive { directive_name } => {
locate_directive_definition(directive_name, &schema, &root_dir)?
locate_directive_definition(directive_name, &schema, state)?
}
};

Expand All @@ -148,30 +140,32 @@ pub fn on_goto_definition(
fn locate_fragment_definition(
program: graphql_ir::Program,
fragment_name: FragmentDefinitionName,
root_dir: &std::path::Path,
state: &impl GlobalState,
) -> Result<GotoDefinitionResponse, LSPRuntimeError> {
let fragment = program.fragment(fragment_name).ok_or_else(|| {
LSPRuntimeError::UnexpectedError(format!(
"Could not find fragment with name {}",
fragment_name
))
})?;
Ok(GotoDefinitionResponse::Scalar(
transform_relay_location_to_lsp_location(root_dir, fragment.name.location)?,
))

state
.get_lsp_location(fragment.name.location)
.map(GotoDefinitionResponse::Scalar)
}

fn locate_directive_definition(
directive_name: DirectiveName,
schema: &Arc<SDLSchema>,
root_dir: &std::path::Path,
state: &impl GlobalState,
) -> Result<GotoDefinitionResponse, LSPRuntimeError> {
let directive = schema.get_directive(directive_name);

directive
.map(|directive| directive.name.location)
.map(|schema_location| {
transform_relay_location_to_lsp_location(root_dir, schema_location)
state
.get_lsp_location(schema_location)
.map(GotoDefinitionResponse::Scalar)
})
.ok_or(LSPRuntimeError::ExpectedError)?
Expand All @@ -182,7 +176,7 @@ fn locate_type_definition(
project_name: StringKey,
type_name: StringKey,
schema: &Arc<SDLSchema>,
root_dir: &std::path::Path,
state: &impl GlobalState,
) -> Result<GotoDefinitionResponse, LSPRuntimeError> {
let provider_response = extra_data_provider.resolve_field_definition(
project_name.to_string(),
Expand Down Expand Up @@ -222,7 +216,8 @@ fn locate_type_definition(
Type::Object(object_id) => schema.object(object_id).name.location,
})
.map(|schema_location| {
transform_relay_location_to_lsp_location(root_dir, schema_location)
state
.get_lsp_location(schema_location)
.map(GotoDefinitionResponse::Scalar)
})
.ok_or(LSPRuntimeError::ExpectedError)?
Expand All @@ -235,7 +230,7 @@ fn locate_field_argument_definition(
parent_type: Type,
field_name: StringKey,
argument_name: ArgumentName,
root_dir: &std::path::Path,
state: &impl GlobalState,
) -> Result<GotoDefinitionResponse, LSPRuntimeError> {
let field = schema.field(schema.named_field(parent_type, field_name).ok_or_else(|| {
LSPRuntimeError::UnexpectedError(format!("Could not find field with name {}", field_name))
Expand All @@ -252,15 +247,16 @@ fn locate_field_argument_definition(
))
})?;

transform_relay_location_to_lsp_location(root_dir, argument.name.location)
.map(|location| Ok(GotoDefinitionResponse::Scalar(location)))?
state
.get_lsp_location(argument.name.location)
.map(GotoDefinitionResponse::Scalar)
}

fn locate_directive_argument_definition(
schema: &SDLSchema,
directive_name: DirectiveName,
argument_name: ArgumentName,
root_dir: &std::path::Path,
state: &impl GlobalState,
) -> LSPRuntimeResult<GotoDefinitionResponse> {
let directive =
schema
Expand All @@ -281,8 +277,9 @@ fn locate_directive_argument_definition(
))
})?;

transform_relay_location_to_lsp_location(root_dir, argument.name.location)
.map(|location| Ok(GotoDefinitionResponse::Scalar(location)))?
state
.get_lsp_location(argument.name.location)
.map(GotoDefinitionResponse::Scalar)
}

fn locate_field_definition(
Expand All @@ -291,7 +288,7 @@ fn locate_field_definition(
field_name: StringKey,
extra_data_provider: &dyn LSPExtraDataProvider,
project_name: StringKey,
root_dir: &std::path::Path,
state: &impl GlobalState,
) -> Result<GotoDefinitionResponse, LSPRuntimeError> {
let field = schema.field(schema.named_field(parent_type, field_name).ok_or_else(|| {
LSPRuntimeError::UnexpectedError(format!("Could not find field with name {}", field_name,))
Expand Down Expand Up @@ -334,10 +331,9 @@ fn locate_field_definition(
}
}

transform_relay_location_to_lsp_location(root_dir, field.name.location)
state
.get_lsp_location(field.name.location)
.map(GotoDefinitionResponse::Scalar)
// If the field does not exist in the schema, that's fine
.map_err(|_| LSPRuntimeError::ExpectedError)
}

fn get_location(path: &str, line: u64) -> Result<lsp_types::Location, LSPRuntimeError> {
Expand Down
4 changes: 2 additions & 2 deletions compiler/crates/relay-lsp/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ pub fn on_hover(
state: &impl GlobalState,
params: <HoverRequest as Request>::Params,
) -> LSPRuntimeResult<<HoverRequest as Request>::Result> {
let (document, position_span) =
let (document, location) =
state.extract_executable_document_from_text(&params.text_document_position_params, 1)?;

let resolution_path = document.resolve((), position_span);
let resolution_path = document.resolve((), location.span());

let project_name = state
.extract_project_name_from_url(&params.text_document_position_params.text_document.uri)?;
Expand Down
34 changes: 23 additions & 11 deletions compiler/crates/relay-lsp/src/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use std::path::PathBuf;
use common::Location;
use common::SourceLocationKey;
use common::TextSource;
use dashmap::DashMap;
use extract_graphql::JavaScriptSourceFeature;
use intern::Lookup;
use lsp_types::Url;

Expand All @@ -22,6 +24,7 @@ use crate::lsp_runtime_error::LSPRuntimeResult;
pub fn transform_relay_location_to_lsp_location(
root_dir: &Path,
location: Location,
synced_javascript_features: &DashMap<Url, Vec<JavaScriptSourceFeature>>,
) -> LSPRuntimeResult<lsp_types::Location> {
match location.source_location() {
SourceLocationKey::Standalone { path } => {
Expand All @@ -36,19 +39,28 @@ pub fn transform_relay_location_to_lsp_location(
Ok(lsp_types::Location { uri, range })
}
SourceLocationKey::Embedded { path, index } => {
let path_to_fragment = root_dir.join(PathBuf::from(path.lookup()));
let uri = get_uri(&path_to_fragment)?;
let file_path = root_dir.join(PathBuf::from(path.lookup()));
let uri = get_uri(&file_path)?;

let file_contents = get_file_contents(&path_to_fragment)?;
let features = match synced_javascript_features.get(&uri) {
Some(features) => Ok(features.clone()),
None => {
let file_contents = get_file_contents(&file_path)?;

let response = extract_graphql::extract(&file_contents);
let response_length = response.len();
let embedded_source = response.into_iter().nth(index.into()).ok_or_else(|| {
LSPRuntimeError::UnexpectedError(format!(
"File {:?} does not contain enough graphql literals: {} needed; {} found",
path_to_fragment, index, response_length
))
})?;
Ok(extract_graphql::extract(&file_contents))
}
}?;

let features_length = features.len();
let embedded_source = features
.into_iter()
.nth(index.try_into().unwrap())
.ok_or_else(|| {
LSPRuntimeError::UnexpectedError(format!(
"File {:?} does not contain enough graphql literals: {} needed; {} found",
file_path, index, features_length
))
})?;

let text_source = embedded_source.text_source();
let range = text_source.to_span_range(location.span());
Expand Down
Loading
Loading