feat(query): Add is_getter, is_setter, is_constructor to all Function implementors (#1526)

---

<details open="true"><summary>Generated summary (powered by <a href="https://app.graphite.dev">Graphite</a>)</summary>

> # TL;DR
> This pull request adds new properties to the `ArrowFunction`, `FnDeclaration`, and `Function` interfaces in the Trustfall schema. It also adds implementation for resolving these properties in the `adapter.rs` and `properties.rs` files. Additionally, it adds a new method `function_scope_flag` to the `Vertex` struct in the `vertex.rs` file.
> 
> # What changed
> - Added new properties (`is_getter`, `is_setter`, `is_constructor`) to the `ArrowFunction`, `FnDeclaration`, and `Function` interfaces in the Trustfall schema.
> - Implemented the resolution of these properties in the `resolve_arrow_function_property`, `resolve_fn_declaration_property`, and `resolve_function_property` functions in the `properties.rs` file.
> - Added a new method `function_scope_flag` to the `Vertex` struct in the `vertex.rs` file.
> 
> # How to test
> 1. Run the test suite to ensure that all existing tests pass.
> 2. Add new tests to cover the newly added properties and the `function_scope_flag` method.
> 3. Run the test suite again and ensure that all tests pass.
> 
> # Why make this change
> - The new properties (`is_getter`, `is_setter`, `is_constructor`) provide additional information about functions in the Trustfall schema, allowing clients to query for these properties.
> - The `function_scope_flag` method in the `Vertex` struct provides a convenient way to access the scope flags of a function node, which can be useful for various analysis and processing tasks.
</details>
This commit is contained in:
u9g 2023-11-26 23:22:41 -05:00 committed by GitHub
parent 8251a343aa
commit 9a5bb008e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 1 deletions

View file

@ -86,6 +86,7 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> {
contexts,
property_name.as_ref(),
resolve_info,
self,
)
}
"AssignmentType" => super::properties::resolve_assignment_type_property(
@ -128,6 +129,7 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> {
contexts,
property_name.as_ref(),
resolve_info,
self,
)
}
"FnCallAST" | "FnCall" => super::properties::resolve_fn_call_property(
@ -139,6 +141,7 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> {
contexts,
property_name.as_ref(),
resolve_info,
self,
),
"ImportAST" | "Import" => super::properties::resolve_import_property(
contexts,

View file

@ -1,6 +1,7 @@
use std::convert::Into;
use oxc_ast::ast::{BindingPatternKind, Expression};
use oxc_semantic::ScopeFlags;
use trustfall::{
provider::{
field_property, resolve_property_with, ContextIterator, ContextOutcomeIterator, ResolveInfo,
@ -73,6 +74,7 @@ pub(super) fn resolve_arrow_function_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
_resolve_info: &ResolveInfo,
adapter: &'a Adapter<'b>,
) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> {
match property_name {
"is_async" => resolve_property_with(contexts, |v| v.function_is_async().into()),
@ -80,6 +82,15 @@ pub(super) fn resolve_arrow_function_property<'a, 'b: 'a>(
"as_constant_string" => resolve_property_with(contexts, |v| {
v.as_constant_string().map_or(FieldValue::Null, Into::into)
}),
"is_getter" => resolve_property_with(contexts, |v| {
v.function_scope_flag(adapter).contains(ScopeFlags::GetAccessor).into()
}),
"is_setter" => resolve_property_with(contexts, |v| {
v.function_scope_flag(adapter).contains(ScopeFlags::SetAccessor).into()
}),
"is_constructor" => resolve_property_with(contexts, |v| {
v.function_scope_flag(adapter).contains(ScopeFlags::Constructor).into()
}),
_ => {
unreachable!(
"attempted to read unexpected property '{property_name}' on type 'ArrowFunction'"
@ -264,6 +275,7 @@ pub(super) fn resolve_fn_declaration_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
_resolve_info: &ResolveInfo,
adapter: &'a Adapter<'b>,
) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> {
match property_name {
"name" => resolve_property_with(contexts, |v| {
@ -281,6 +293,15 @@ pub(super) fn resolve_fn_declaration_property<'a, 'b: 'a>(
"as_constant_string" => resolve_property_with(contexts, |v| {
v.as_constant_string().map_or(FieldValue::Null, Into::into)
}),
"is_getter" => resolve_property_with(contexts, |v| {
v.function_scope_flag(adapter).contains(ScopeFlags::GetAccessor).into()
}),
"is_setter" => resolve_property_with(contexts, |v| {
v.function_scope_flag(adapter).contains(ScopeFlags::SetAccessor).into()
}),
"is_constructor" => resolve_property_with(contexts, |v| {
v.function_scope_flag(adapter).contains(ScopeFlags::Constructor).into()
}),
_ => {
unreachable!(
"attempted to read unexpected property '{property_name}' on type 'FnDeclaration'"
@ -308,6 +329,7 @@ pub(super) fn resolve_function_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
_resolve_info: &ResolveInfo,
adapter: &'a Adapter<'b>,
) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> {
match property_name {
"is_async" => resolve_property_with(contexts, |v| v.function_is_async().into()),
@ -315,6 +337,15 @@ pub(super) fn resolve_function_property<'a, 'b: 'a>(
"as_constant_string" => resolve_property_with(contexts, |v| {
v.as_constant_string().map_or(FieldValue::Null, Into::into)
}),
"is_getter" => resolve_property_with(contexts, |v| {
v.function_scope_flag(adapter).contains(ScopeFlags::GetAccessor).into()
}),
"is_setter" => resolve_property_with(contexts, |v| {
v.function_scope_flag(adapter).contains(ScopeFlags::SetAccessor).into()
}),
"is_constructor" => resolve_property_with(contexts, |v| {
v.function_scope_flag(adapter).contains(ScopeFlags::Constructor).into()
}),
_ => {
unreachable!(
"attempted to read unexpected property '{property_name}' on type 'Function'"

View file

@ -661,6 +661,11 @@ type FunctionBodyAST implements HasSpan & ASTNode & FunctionBody {
interface Function implements Expression & HasSpan {
is_async: Boolean!
is_generator: Boolean!
is_getter: Boolean!
is_setter: Boolean!
is_constructor: Boolean!
"""
Does not include rest parameter if it exists.
"""
@ -832,6 +837,9 @@ interface ArrowFunction implements Function & HasSpan & Expression {
# Function
is_async: Boolean!
is_generator: Boolean!
is_getter: Boolean!
is_setter: Boolean!
is_constructor: Boolean!
"""
Does not include rest parameter if it exists.
"""
@ -860,6 +868,9 @@ type ArrowFunctionAST implements Function & HasSpan & ArrowFunction & ASTNode &
# Function
is_async: Boolean!
is_generator: Boolean!
is_getter: Boolean!
is_setter: Boolean!
is_constructor: Boolean!
"""
Does not include rest parameter if it exists.
"""
@ -900,6 +911,9 @@ interface FnDeclaration implements Function & HasSpan & Expression {
# Function
is_async: Boolean!
is_generator: Boolean!
is_getter: Boolean!
is_setter: Boolean!
is_constructor: Boolean!
"""
Does not include rest parameter if it exists.
"""
@ -933,6 +947,9 @@ type FnDeclarationAST implements Function & ASTNode & FnDeclaration & HasSpan &
# Function
is_async: Boolean!
is_generator: Boolean!
is_getter: Boolean!
is_setter: Boolean!
is_constructor: Boolean!
"""
Does not include rest parameter if it exists.
"""

View file

@ -4,7 +4,7 @@ use enum_as_inner::EnumAsInner;
use oxc_ast::ast::ArrayExpressionElement;
#[allow(clippy::wildcard_imports)]
use oxc_ast::{ast::*, AstKind};
use oxc_semantic::{AstNode, AstNodeId};
use oxc_semantic::{AstNode, AstNodeId, ScopeFlags};
use oxc_span::{GetSpan, Span};
use trustfall::provider::{Typename, VertexIterator};
use url::Url;
@ -278,6 +278,35 @@ impl<'a> Vertex<'a> {
}
}
pub fn function_scope_flag(&self, adapter: &Adapter<'_>) -> ScopeFlags {
let (wanted_node_hash, wanted_node_span) = match &self {
Vertex::ArrowFunction(data) => (calculate_hash(data.arrow_expression), data.arrow_expression.span),
Vertex::FnDeclaration(data) => (calculate_hash(data.function), data.function.span),
_ => unreachable!(
"'function_scope_flag' function should only ever be called with an ArrowFunction or FnDeclaration"
),
};
let found = adapter.semantic.nodes().iter().find(|x| {
let span = x.kind().span();
if span.start != wanted_node_span.start || span.end != wanted_node_span.end {
return false;
}
let hash_of_node = match x.kind() {
AstKind::ArrowExpression(ae) => calculate_hash(ae),
AstKind::Function(fn_) => calculate_hash(fn_),
_ => return false,
};
hash_of_node == wanted_node_hash
});
adapter.semantic.scopes().get_flags(
found.expect("an arrowexpression or function should always be in the ast if we can have the struct of it").scope_id(),
)
}
pub fn function_parameter(&self) -> VertexIterator<'a, Vertex<'a>> {
let parameter = match &self {
Vertex::ArrowFunction(data) => &data.arrow_expression.params.items,