Skip to content
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
33 changes: 24 additions & 9 deletions crates/hir/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,37 +106,52 @@ impl HirDisplay for InContainer<DataTy> {
match self.value {
DataTy::Builtin(ty_id) => match ty_id.lookup(f.db) {
BuiltinDataTy::Int { kind, signing } => {
if signing {
f.write_str("signed ")?;
}
match kind {
IntKind::Byte => f.write_str("byte"),
IntKind::ShortInt => f.write_str("shortint"),
IntKind::Int => f.write_str("int"),
IntKind::LongInt => f.write_str("longint"),
IntKind::Integer => f.write_str("integer"),
IntKind::Time => f.write_str("time"),
}?;
if signing {
f.write_str(" signed")?;
}
Ok(())
}
BuiltinDataTy::Vector { kind, signing, dimensions } => {
if signing {
f.write_str("signed ")?;
}
let mut wrote_head = false;
match kind {
VecKind::Bit => {
if !f.simplified_ty {
f.write_str("bit")?
f.write_str("bit")?;
wrote_head = true;
}
}
VecKind::Logic => {
if !f.simplified_ty {
f.write_str("logic")?
f.write_str("logic")?;
wrote_head = true;
}
}
VecKind::Reg => f.write_str("reg")?,
VecKind::Reg => {
f.write_str("reg")?;
wrote_head = true;
}
}
if signing {
if wrote_head {
f.write_str(" ")?;
}
f.write_str("signed")?;
wrote_head = true;
}
for dim in dimensions.iter().flatten() {
if wrote_head {
f.write_str(" ")?;
}
self.with_value(*dim).hir_fmt(f)?;
wrote_head = true;
}
Ok(())
}
Expand Down
29 changes: 27 additions & 2 deletions crates/hir/src/hir_def/aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ pub(crate) fn lower_struct_def(
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructSrc {
pub node: SyntaxNodePtr,
pub name: Option<SyntaxTokenPtr>,
}

impl IsSrc for StructSrc {
Expand All @@ -89,6 +90,18 @@ impl IsSrc for StructSrc {
}
}

impl IsNamedSrc for StructSrc {
#[inline]
fn name_kind(&self) -> Option<TokenKind> {
self.name.map(|name| name.kind())
}

#[inline]
fn name_range(&self) -> Option<TextRange> {
self.name.map(|name| name.range())
}
}

impl<'a> ToAstNode<'a, ast::StructUnionType<'a>> for StructSrc {
fn to_node(&self, tree: &'a syntax::SyntaxTree) -> Option<ast::StructUnionType<'a>> {
let mut node = self.node.to_node(tree)?;
Expand All @@ -101,16 +114,28 @@ impl<'a> ToAstNode<'a, ast::StructUnionType<'a>> for StructSrc {

impl From<ast::StructUnionType<'_>> for StructSrc {
fn from(node: ast::StructUnionType<'_>) -> Self {
StructSrc { node: AstNodeExt::to_ptr(&node) }
let syntax = node.syntax();
let name = struct_name_token(node).map(|name| SyntaxTokenPtr::from_token_in(syntax, name));
StructSrc { node: AstNodeExt::to_ptr(&node), name }
}
}

impl<'a> FromSourceAst<'a, ast::StructUnionType<'a>> for StructSrc {
fn from_source_ast(node: SourceAst<ast::StructUnionType<'a>>) -> Self {
StructSrc { node: AstNodeExt::to_ptr(&node.into_inner()) }
let node = node.into_inner();
let syntax = node.syntax();
let name = struct_name_token(node)
.and_then(|name| root_token_in(syntax, name).map(SyntaxTokenPtr::from_token));
StructSrc { node: AstNodeExt::to_ptr(&node), name }
}
}

fn struct_name_token(node: ast::StructUnionType<'_>) -> Option<syntax::SyntaxToken<'_>> {
let data_type = ast::DataType::StructUnionType(node);
let typedef = data_type.syntax().parent().and_then(ast::TypedefDeclaration::cast)?;
typedef.name()
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ClassMemberKind {
Property,
Expand Down
3 changes: 1 addition & 2 deletions crates/hir/src/hir_def/expr/data_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,7 @@ impl LowerExprCtx<'_> {
LogicType(_) => Either::Right(VecKind::Logic),
};

let signing = Self::lower_signing(ty.signing())
.unwrap_or(matches!(kind, Either::Left(IntKind::Time) | Either::Right(_)));
let signing = Self::lower_signing(ty.signing()).unwrap_or(matches!(kind, Either::Left(_)));

let dimensions = ty.dimensions().children().map(|dim| self.lower_dimension(dim)).collect();
match kind {
Expand Down
6 changes: 3 additions & 3 deletions crates/hir/src/hir_def/subroutine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use super::{
impl_lower_expr,
timing_control::{EventExpr, EventExprSrc},
},
lower_ident, lower_ident_opt,
lower_ident_opt,
module::{ModuleId, generate::GenerateBlockId},
stmt::{LowerStmt, Stmt, StmtId, StmtSrc, impl_lower_stmt},
typedef::{Typedef, TypedefId, TypedefSrc, lower_typedef_data_ty},
Expand Down Expand Up @@ -236,10 +236,10 @@ where

fn lower_name(name: ast::Name) -> Option<Ident> {
if let Some(id) = name.as_identifier_name().and_then(|n| n.identifier()) {
return lower_ident(Some(id));
return lower_ident_opt(Some(id));
}
if let Some(select) = name.as_identifier_select_name() {
return select.identifier().and_then(|tok| lower_ident(Some(tok)));
return select.identifier().and_then(|tok| lower_ident_opt(Some(tok)));
}
if let Some(scoped) = name.as_scoped_name() {
return lower_name(scoped.right());
Expand Down
1 change: 1 addition & 0 deletions crates/ide/src/code_action/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ impl<'a> CodeActionCtx<'a> {
) -> Option<Self> {
let parsed_file = sema.parse_file(file_id);
parsed_file.compilation_unit()?;

Some(Self { sema, file_id, range, diagnostics, parsed_file })
}

Expand Down
17 changes: 17 additions & 0 deletions crates/ide/src/code_action/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,53 @@ mod add_instance_parens;
mod add_missing_connections;
mod add_missing_parameters;
mod apply_de_morgan;
mod convert_always_block;
mod convert_literal_base;
mod convert_named_port_connections;
mod convert_ordered_connections;
mod convert_port_declarations;
mod expand_compound_assignment;
mod expand_postfix_inc_dec;
mod extract_variable;
mod insert_expected_token;
mod invert_if_else;
mod merge_nested_if;
mod pull_assignment_up;
mod reformat_number_literal;
mod remove_empty_port_connections;
mod remove_parentheses;
mod sort_named_instantiation_items;
mod split_declaration_declarators;
mod wrap_statement_in_begin_end;

pub(crate) fn all() -> &'static [Handler] {
&[
convert_literal_base::convert_literal_base,
reformat_number_literal::reformat_number_literal,
add_missing_connections::add_missing_connections,
add_missing_parameters::add_missing_parameters,
convert_ordered_connections::convert_ordered_ports,
convert_ordered_connections::convert_ordered_params,
convert_named_port_connections::convert_named_port_connection_shorthand,
remove_empty_port_connections::remove_empty_port_connections,
add_implicit_named_port_parens::add_implicit_named_port_parens,
add_instance_parens::add_instance_parens,
convert_always_block::convert_always_block,
convert_port_declarations::convert_port_declarations,
split_declaration_declarators::split_declaration_declarators,
sort_named_instantiation_items::sort_named_parameter_assignments,
sort_named_instantiation_items::sort_named_port_connections,
add_default_case_item::add_default_case_item,
invert_if_else::invert_if_else,
merge_nested_if::merge_nested_if,
wrap_statement_in_begin_end::unwrap_single_statement_block,
wrap_statement_in_begin_end::wrap_statement_in_begin_end,
remove_parentheses::remove_parentheses,
expand_postfix_inc_dec::expand_postfix_inc_dec,
expand_compound_assignment::expand_compound_assignment,
extract_variable::extract_variable,
pull_assignment_up::pull_assignment_up,
pull_assignment_up::pull_assignment_down,
apply_de_morgan::apply_de_morgan,
insert_expected_token::insert_expected_token,
]
Expand Down
12 changes: 12 additions & 0 deletions crates/ide/src/code_action/handlers/add_default_case_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ const ID: CodeActionId =
CodeActionId { name: "add_default_case_item", kind: CodeActionKind::Generate, repair: None };
const LABEL: &str = "Add default case item";

// Assist: add_default_case_item
//
// This adds a `default` item to a case statement that does not already have
// one.
//
// ```
// module top; always_comb case$0 (sel) 1'b0: y = a; endcase endmodule
// ```
// ->
// ```
// module top; always_comb case (sel) 1'b0: y = a; default: ; endcase endmodule
// ```
pub(super) fn add_default_case_item(
collector: &mut CodeActionCollector,
ctx: &CodeActionCtx,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ const ID: CodeActionId = CodeActionId {
};
const LABEL: &str = "Add explicit empty port connection";

// Assist: add_implicit_named_port_parens
//
// This makes an implicit named port connection explicit by adding empty
// parentheses.
//
// ```
// child u(.ready$0);
// ```
// ->
// ```
// child u(.ready());
// ```
pub(super) fn add_implicit_named_port_parens(
collector: &mut CodeActionCollector,
ctx: &CodeActionCtx,
Expand Down
11 changes: 11 additions & 0 deletions crates/ide/src/code_action/handlers/add_instance_parens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ const ID: CodeActionId = CodeActionId {
};
const LABEL: &str = "Add empty instance port list";

// Assist: add_instance_parens
//
// This adds an empty port list to an instance that is missing one.
//
// ```
// child u$0;
// ```
// ->
// ```
// child u();
// ```
pub(super) fn add_instance_parens(
collector: &mut CodeActionCollector,
ctx: &CodeActionCtx,
Expand Down
31 changes: 21 additions & 10 deletions crates/ide/src/code_action/handlers/add_missing_connections.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
use hir::{
base_db::source_db::SourceDb, container::InModule, db::HirDb,
hir_def::module::instantiation::PortConn,
hir_def::module::instantiation::PortConn, source_map::IsSrc,
};
use rustc_hash::FxHashSet;
use syntax::{
ast::{self, AstNode},
has_text_range::{HasTextRange, HasTextRangeIn},
has_text_range::HasTextRangeIn,
};
use utils::get::GetRef;
use utils::get::{Get, GetRef};

use crate::{
code_action::{
CodeActionCollector, CodeActionCtx, CodeActionId, CodeActionKind, RepairKind,
apply_missing_list_edit, missing_member_entry_text, port_names,
remaining_ordered_port_names,
},
module_resolution::resolve_instantiation_target,
module_resolution::resolve_hir_instantiation_target,
};

const ID: CodeActionId = CodeActionId {
Expand All @@ -25,6 +25,18 @@ const ID: CodeActionId = CodeActionId {
};
const LABEL: &str = "Fill connections";

// Assist: add_missing_connections
//
// This fills the missing port connections for an instance from the target
// module definition.
//
// ```
// child u($0.a(a));
// ```
// ->
// ```
// child u(.a(a), .b('0));
// ```
pub(super) fn add_missing_connections(
collector: &mut CodeActionCollector,
ctx: &CodeActionCtx,
Expand All @@ -36,14 +48,13 @@ pub(super) fn add_missing_connections(
let ast_instance = ctx.find_node_at_offset::<ast::HierarchicalInstance>()?;
let InModule { value: instance_id, module_id } =
sema.resolve_instance(file_id, ast_instance)?;
let module = db.module(module_id);
let (module, module_src_map) = db.module_with_source_map(module_id);
let instance = module.get(instance_id);
let open_paren = ast_instance.open_paren()?.text_range_in(ast_instance.syntax())?;
let close_paren = ast_instance.close_paren()?.text_range_in(ast_instance.syntax())?;

let instantiation = ast::HierarchyInstantiation::cast(ast_instance.syntax().parent()?)?;
let target_module_id =
resolve_instantiation_target(db, ctx.file_id(), instantiation).unique()?;
let instantiation = module.get(instance.parent);
let target_module_id = resolve_hir_instantiation_target(db, ctx.file_id(), instantiation)?;
let target_module = db.module(target_module_id);

let is_ordered = instance
Expand Down Expand Up @@ -83,8 +94,8 @@ pub(super) fn add_missing_connections(
.collect();

let text = sema.db.file_text(ctx.file_id());
let item_ranges = ast_instance.connections().children().filter_map(|conn| {
let range = conn.syntax().text_range()?;
let item_ranges = instance.connections.iter().filter_map(|conn_id| {
let range = module_src_map.get(*conn_id)?.range();
(!range.is_empty()).then_some(range)
});
apply_missing_list_edit(builder, &text, open_paren, close_paren, item_ranges, entries);
Expand Down
Loading
Loading