Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use emmylua_parser::{LuaAstNode, LuaAstToken, LuaExpr, LuaForRangeStat};
use emmylua_parser::{LuaAstToken, LuaExpr, LuaForRangeStat};

use crate::{
DbIndex, InferFailReason, LuaDeclId, LuaInferCache, LuaOperatorMetaMethod, LuaType,
Expand Down Expand Up @@ -79,7 +79,6 @@ pub fn infer_for_range_iter_expr_func(
}

let iter_func_expr = iter_exprs[0].clone();
let root = iter_func_expr.get_root();
let first_expr_type = infer_expr(db, cache, iter_func_expr)?;
let doc_function = match first_expr_type {
LuaType::DocFunction(func) => func,
Expand Down Expand Up @@ -150,7 +149,6 @@ pub fn infer_for_range_iter_expr_func(
db,
cache,
substitutor: &mut substitutor,
root,
call_expr: None,
};
let params = doc_function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ pub struct LuaDocParamInfo {
pub description: Option<String>,
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct LuaDocReturnInfo {
pub name: Option<String>,
pub type_ref: LuaType,
Expand Down
5 changes: 4 additions & 1 deletion crates/emmylua_code_analysis/src/db_index/type/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,10 @@ impl LuaFunctionType {
Some(owner_type) => {
// 一些类型不应该被视为 method
if let (LuaType::Ref(_) | LuaType::Def(_), _) = (owner_type, t)
&& (t.is_any() || t.is_table() || t.is_class_tpl())
&& (t.is_any()
|| t.is_table()
|| t.is_class_tpl()
|| t.is_str_tpl_ref())
{
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{collections::HashSet, ops::Deref, sync::Arc};

use emmylua_parser::{LuaAstNode, LuaCallExpr, LuaExpr};
use emmylua_parser::{LuaCallExpr, LuaExpr};
use internment::ArcIntern;

use crate::{
Expand Down Expand Up @@ -63,7 +63,6 @@ pub fn instantiate_func_generic(
db,
cache,
substitutor: &mut substitutor,
root: call_expr.get_root(),
call_expr: Some(call_expr.clone()),
};
if !generic_tpls.is_empty() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use emmylua_parser::{LuaCallExpr, LuaSyntaxNode};
use emmylua_parser::LuaCallExpr;

use crate::{DbIndex, LuaInferCache, TypeSubstitutor};

Expand All @@ -7,6 +7,5 @@ pub struct TplContext<'a> {
pub db: &'a DbIndex,
pub cache: &'a mut LuaInferCache,
pub substitutor: &'a mut TypeSubstitutor,
pub root: LuaSyntaxNode,
pub call_expr: Option<LuaCallExpr>,
}
28 changes: 25 additions & 3 deletions crates/emmylua_code_analysis/src/semantic/infer/infer_call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use super::{
};
use crate::{
CacheEntry, DbIndex, InFiled, LuaFunctionType, LuaGenericType, LuaInstanceType,
LuaOperatorMetaMethod, LuaOperatorOwner, LuaSignatureId, LuaType, LuaTypeDeclId, LuaUnionType,
LuaOperatorMetaMethod, LuaOperatorOwner, LuaSignature, LuaSignatureId, LuaType, LuaTypeDeclId,
LuaUnionType,
};
use crate::{
InferGuardRef,
Expand Down Expand Up @@ -179,6 +180,7 @@ fn infer_signature_doc_function(
if !signature.is_resolve_return() {
return Err(InferFailReason::UnResolveSignatureReturn(signature_id));
}
let is_generic = signature_is_generic(db, cache, &signature, &call_expr).unwrap_or(false);
let overloads = &signature.overloads;
if overloads.is_empty() {
let mut fake_doc_function = LuaFunctionType::new(
Expand All @@ -187,7 +189,7 @@ fn infer_signature_doc_function(
signature.get_type_params(),
signature.get_return_type(),
);
if signature.is_generic() {
if is_generic {
fake_doc_function = instantiate_func_generic(db, cache, &fake_doc_function, call_expr)?;
}

Expand All @@ -207,7 +209,7 @@ fn infer_signature_doc_function(
cache,
new_overloads,
call_expr.clone(),
signature.is_generic(),
is_generic,
args_count,
)
}
Expand Down Expand Up @@ -654,3 +656,23 @@ fn check_can_infer(

Ok(())
}

fn signature_is_generic(
db: &DbIndex,
cache: &mut LuaInferCache,
signature: &LuaSignature,
call_expr: &LuaCallExpr,
) -> Option<bool> {
if signature.is_generic() {
return Some(true);
}
let LuaExpr::IndexExpr(index_expr) = call_expr.get_prefix_expr()? else {
return None;
};
let prefix_type = infer_expr(db, cache, index_expr.get_prefix_expr()?).ok()?;
match prefix_type {
// 对于 Generic 直接认为是泛型
LuaType::Generic(_) => return Some(true),
_ => Some(prefix_type.contain_tpl()),
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -738,10 +738,6 @@ fn infer_generic_member(
let generic_params = generic_type.get_params();
let substitutor = TypeSubstitutor::from_type_array(generic_params.clone());

// TODO: this is just a hack to support inheritance from the generic objects
// like `---@class box<T>: T`. Should be rewritten: generic types should
// be passed to the called instantiate_type_generic() in some kind of a
// context.
if let LuaType::Ref(base_type_decl_id) = &base_type {
let result = infer_generic_members_from_super_generics(
db,
Expand Down
3 changes: 2 additions & 1 deletion crates/emmylua_code_analysis/src/semantic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ use crate::{LuaFunctionType, LuaMemberId, LuaMemberKey, LuaTypeOwner};
pub use generic::*;
pub use guard::{InferGuard, InferGuardRef};
pub use infer::InferFailReason;
pub use infer::infer_call_expr_func;
pub(crate) use infer::infer_expr;
pub use infer::infer_param;
pub(crate) use infer::{infer_call_expr_func, infer_expr};
use overload_resolve::resolve_signature;
pub use semantic_info::SemanticDeclLevel;
pub use type_check::{TypeCheckFailReason, TypeCheckResult};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub fn update_function_signature_info(
}
}
}
if let MarkedString::LanguageString(s) = &mut hover_builder.type_description {
if let MarkedString::LanguageString(s) = &mut hover_builder.primary {
s.value = format!("{} (+{} overloads)", s.value, overload_count);
}
}
Expand All @@ -78,7 +78,7 @@ fn build_vscode_completion_item(
.signature_overload
.and_then(|overloads| overloads.get(index).cloned())
})
.unwrap_or_else(|| hover_builder.type_description.clone());
.unwrap_or_else(|| hover_builder.primary.clone());

match type_description {
MarkedString::String(s) => {
Expand Down Expand Up @@ -138,7 +138,7 @@ fn build_other_completion_item(
.signature_overload
.and_then(|overloads| overloads.get(index).cloned())
})
.unwrap_or_else(|| hover_builder.type_description.clone());
.unwrap_or_else(|| hover_builder.primary.clone());

match type_description {
MarkedString::String(s) => {
Expand Down
1 change: 0 additions & 1 deletion crates/emmylua_ls/src/handlers/definition/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ use super::RegisterCapabilities;
use crate::context::ServerContextSnapshot;
use crate::handlers::definition::goto_path::goto_path;
use crate::util::find_ref_at;
pub use goto_function::extract_semantic_decl_from_signature;

pub async fn on_goto_definition_handler(
context: ServerContextSnapshot,
Expand Down
154 changes: 102 additions & 52 deletions crates/emmylua_ls/src/handlers/hover/build_hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ use emmylua_code_analysis::{
DbIndex, LuaCompilation, LuaDeclId, LuaDocument, LuaMemberId, LuaMemberKey, LuaSemanticDeclId,
LuaSignatureId, LuaType, LuaTypeDeclId, RenderLevel, SemanticInfo, SemanticModel,
};
use emmylua_parser::{LuaAssignStat, LuaAstNode, LuaExpr, LuaSyntaxToken};
use emmylua_parser::{
LuaAssignStat, LuaAstNode, LuaCallArgList, LuaExpr, LuaSyntaxKind, LuaSyntaxToken,
LuaTableExpr, LuaTableField,
};
use lsp_types::{Hover, HoverContents, MarkedString, MarkupContent};
use rowan::TextRange;

use crate::handlers::hover::{
find_origin::replace_semantic_type,
function_humanize::{hover_function_type, is_function},
hover_humanize::hover_humanize_type,
};
use crate::handlers::hover::function::{build_function_hover, is_function};
use crate::handlers::hover::hover_humanize::hover_humanize_type;

use super::{
find_origin::{find_decl_origin_owners, find_member_origin_owners},
Expand Down Expand Up @@ -139,32 +139,19 @@ fn build_decl_hover(
let mut semantic_decls =
find_decl_origin_owners(builder.compilation, builder.semantic_model, decl_id)
.get_types(builder.semantic_model);
replace_semantic_type(&mut semantic_decls, &typ);
// replace_semantic_type(&mut semantic_decls, &typ);
// 处理类型签名
if is_function(&typ) {
if is_completion {
let decl_semantic_id = LuaSemanticDeclId::LuaDecl(decl_id);
semantic_decls.retain(|(decl, _)| decl == &decl_semantic_id);
}
// 如果找到了那么需要将它移动到末尾, 因为尾部最优先显示
else if let Some(pos) = semantic_decls
.iter()
.position(|(_, origin_type)| origin_type == &typ)
{
let item = semantic_decls.remove(pos);
semantic_decls.push(item);
} else {
let semantic_decl = {
if let Some(semantic_decl) = semantic_decls.first() {
semantic_decl.0.clone()
} else {
LuaSemanticDeclId::LuaDecl(decl_id)
}
};
semantic_decls.push((semantic_decl, typ.clone()));
}
adjust_semantic_decls(
builder,
&mut semantic_decls,
&LuaSemanticDeclId::LuaDecl(decl_id),
&typ,
);

hover_function_type(builder, db, &semantic_decls);
// 处理函数类型
build_function_hover(builder, db, &semantic_decls);
// hover_function_type(builder, db, &semantic_decls);

if let Some((LuaSemanticDeclId::Member(member_id), _)) = semantic_decls
.iter()
Expand Down Expand Up @@ -231,37 +218,21 @@ fn build_member_hover(
find_member_origin_owners(builder.compilation, builder.semantic_model, member_id, true)
.get_types(builder.semantic_model);

replace_semantic_type(&mut semantic_decls, &typ);
let member_name = match member.get_key() {
LuaMemberKey::Name(name) => name.to_string(),
LuaMemberKey::Integer(i) => format!("[{}]", i),
_ => return None,
};

if is_function(&typ) {
if is_completion {
let member_semantic_id = LuaSemanticDeclId::Member(member_id);
semantic_decls.retain(|(decl, _)| decl == &member_semantic_id);
}
// 如果找到了那么需要将它移动到末尾, 因为尾部最优先显示
else if let Some(pos) = semantic_decls
.iter()
.position(|(_, origin_type)| origin_type == &typ)
{
let item = semantic_decls.remove(pos);
semantic_decls.push(item);
} else {
let semantic_decl = {
if let Some(semantic_decl) = semantic_decls.first() {
semantic_decl.0.clone()
} else {
LuaSemanticDeclId::Member(member_id)
}
};
semantic_decls.push((semantic_decl, typ.clone()));
}
adjust_semantic_decls(
builder,
&mut semantic_decls,
&LuaSemanticDeclId::Member(member_id),
&typ,
);

hover_function_type(builder, db, &semantic_decls);
build_function_hover(builder, db, &semantic_decls);

builder.set_location_path(Some(member));

Expand Down Expand Up @@ -414,3 +385,82 @@ pub fn get_hover_type(builder: &HoverBuilder, semantic_model: &SemanticModel) ->

None
}

#[allow(unused)]
fn adjust_semantic_decls(
builder: &mut HoverBuilder,
semantic_decls: &mut Vec<(LuaSemanticDeclId, LuaType)>,
current_semantic_decl_id: &LuaSemanticDeclId,
current_type: &LuaType,
) -> Option<()> {
if let Some(pos) = semantic_decls
.iter()
.position(|(_, typ)| current_type == typ)
{
let item = semantic_decls.remove(pos);
semantic_decls.push(item);
return Some(());
}
// semantic_decls 是追溯最初定义的结果, 不包含当前内容
let current_len = semantic_decls.len();
if current_len == 0 {
// 没有最初定义, 直接添加原始内容
semantic_decls.push((current_semantic_decl_id.clone(), current_type.clone()));
return Some(());
}
// 此时有最初定义, 证明当前内容的是派生的或者全部项实例化后联合的结果, 非常难以区分
// 如果当前定义是 LuaDecl 且追溯到了最初定义, 那么我们不需要添加
if let LuaSemanticDeclId::LuaDecl(_) = current_semantic_decl_id {
return Some(());
}

// 如果当前定义在最初定义组中存在, 那么我们也不需要添加.
// 具有一个难以解决的问题, 返回的`current_semantic_decl_id`为 member 时, 不一定是当前 token 指向的内容, 因此我们还需要再做一层判断,
// 如果是具有实际定义的, 我们仍然需要添加, 例如 signature.
if semantic_decls
.iter()
.any(|(decl, typ)| decl == current_semantic_decl_id && !typ.is_signature())
{
return Some(());
}

if has_add_to_semantic_decls(builder, current_semantic_decl_id).unwrap_or(true) {
semantic_decls.push((current_semantic_decl_id.clone(), current_type.clone()));
};

Some(())
}

fn has_add_to_semantic_decls(
builder: &mut HoverBuilder,
semantic_decl_id: &LuaSemanticDeclId,
) -> Option<bool> {
if let LuaSemanticDeclId::Member(member_id) = semantic_decl_id {
let semantic_model = if member_id.file_id == builder.semantic_model.get_file_id() {
builder.semantic_model
} else {
&builder.compilation.get_semantic_model(member_id.file_id)?
};

let root = semantic_model.get_root().syntax();
let current_node = member_id.get_syntax_id().to_node_from_root(root)?;
match member_id.get_syntax_id().get_kind() {
LuaSyntaxKind::TableFieldAssign => {
if LuaTableField::can_cast(current_node.kind().into()) {
let table_field = LuaTableField::cast(current_node.clone())?;
let parent = table_field.syntax().parent()?;
let table_expr = LuaTableExpr::cast(parent)?;
let table_type = semantic_model.infer_table_should_be(table_expr.clone())?;
if matches!(table_type, LuaType::Ref(_) | LuaType::Generic(_)) {
// 如果位于函数调用中, 则不添加
let is_in_call = table_expr.ancestors::<LuaCallArgList>().next().is_some();
return Some(!is_in_call);
}
}
}
_ => {}
};
}

Some(true)
}
1 change: 1 addition & 0 deletions crates/emmylua_ls/src/handlers/hover/find_origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ fn resolve_table_field_through_type_inference(
.and_then(|m| m.property_owner_id)
}

#[allow(unused)]
pub fn replace_semantic_type(
semantic_decls: &mut [(LuaSemanticDeclId, LuaType)],
origin_type: &LuaType,
Expand Down
Loading
Loading