use cairo_lang_filesystem::ids::SpanInFile;
use cairo_lang_syntax::node::ast::{Attribute, TerminalIdentifier};
use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode};
use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
use cairo_language_common::CommonGroup;
use lsp_types::{Location, ReferenceParams};
use crate::lang::db::{AnalysisDatabase, LsSyntaxGroup};
use crate::lang::defs::SymbolSearch;
use crate::lang::lsp::{LsProtoGroup, ToCairo};
pub fn references(params: ReferenceParams, db: &AnalysisDatabase) -> Option<Vec<Location>> {
let include_declaration = params.context.include_declaration;
let file = db.file_for_url(¶ms.text_document_position.text_document.uri)?;
let position = params.text_document_position.position.to_cairo();
let node = db.find_identifier_at_position(file, position)?;
let resultants = db.get_node_resultants(node.as_syntax_node())?;
let locations: OrderedHashSet<_> = resultants
.iter()
.filter_map(|node| find_references(db, *node, include_declaration))
.flatten()
.collect();
Some(locations.into_iter().collect())
}
fn find_references<'db>(
db: &'db AnalysisDatabase,
syntax_node: SyntaxNode<'db>,
include_declaration: bool,
) -> Option<Vec<Location>> {
let identifier =
syntax_node.ancestors_with_self(db).find_map(|node| TerminalIdentifier::cast(db, node))?;
let symbol = SymbolSearch::find_definition(db, &identifier)?;
let def = symbol.def.clone();
Some(
symbol
.usages(db)
.include_declaration(include_declaration)
.originating_locations(db)
.filter(|loc| {
!is_in_derive_attribute(db, loc)
|| (include_declaration && Some(loc) == def.definition_originating_location(db).as_ref())
})
.filter_map(|loc| db.lsp_location( loc))
.collect(),
)
}
fn is_in_derive_attribute<'db>(
db: &'db AnalysisDatabase,
SpanInFile { file_id, span }: &SpanInFile<'db>,
) -> bool {
let Some(token) = db
.find_syntax_node_at_offset(*file_id, span.start)
.filter(|node| node.span(db) == *span)
else {
return false;
};
let maybe_attribute_name = token
.ancestor_of_type::<Attribute>(db)
.map(|attr| attr.attr(db).as_syntax_node().get_text(db));
maybe_attribute_name == Some("derive")
}