+fn highlight_references(
+ sema: &Semantics<RootDatabase>,
+ syntax: &SyntaxNode,
+ FilePosition { offset, file_id }: FilePosition,
+) -> Option<Vec<DocumentHighlight>> {
+ let def = references::find_def(sema, syntax, offset)?;
+ let usages = def.usages(sema).set_scope(Some(SearchScope::single_file(file_id))).all();
+
+ let declaration = match def {
+ Definition::ModuleDef(hir::ModuleDef::Module(module)) => {
+ Some(NavigationTarget::from_module_to_decl(sema.db, module))
+ }
+ def => def.try_to_nav(sema.db),
+ }
+ .filter(|decl| decl.file_id == file_id)
+ .and_then(|decl| {
+ let range = decl.focus_range?;
+ let access = references::decl_access(&def, syntax, range);
+ Some(DocumentHighlight { range, access })
+ });
+
+ let file_refs = usages.references.get(&file_id).map_or(&[][..], Vec::as_slice);
+ let mut res = Vec::with_capacity(file_refs.len() + 1);
+ res.extend(declaration);
+ res.extend(
+ file_refs
+ .iter()
+ .map(|&FileReference { access, range, .. }| DocumentHighlight { range, access }),
+ );
+ Some(res)
+}
+
+fn highlight_exit_points(token: SyntaxToken) -> Option<Vec<DocumentHighlight>> {
+ fn hl(body: Option<ast::Expr>) -> Option<Vec<DocumentHighlight>> {
+ let mut highlights = Vec::new();
+ let body = body?;
+ walk(body.syntax(), |node| {
+ match_ast! {
+ match node {
+ ast::ReturnExpr(expr) => if let Some(token) = expr.return_token() {
+ highlights.push(DocumentHighlight {
+ access: None,
+ range: token.text_range(),
+ });
+ },
+ ast::TryExpr(try_) => if let Some(token) = try_.question_mark_token() {
+ highlights.push(DocumentHighlight {
+ access: None,
+ range: token.text_range(),
+ });
+ },
+ ast::EffectExpr(effect) => if effect.async_token().is_some() {
+ return true;
+ },
+ ast::ClosureExpr(__) => return true,
+ ast::Item(__) => return true,
+ ast::Path(__) => return true,
+ _ => (),
+ }
+ }
+ false
+ });
+ let tail = match body {
+ ast::Expr::BlockExpr(b) => b.tail_expr(),
+ e => Some(e),
+ };
+ if let Some(tail) = tail {
+ highlights.push(DocumentHighlight { access: None, range: tail.syntax().text_range() });
+ }
+ Some(highlights)
+ }
+ for anc in token.ancestors() {
+ return match_ast! {
+ match anc {
+ ast::Fn(fn_) => hl(fn_.body().map(ast::Expr::BlockExpr)),
+ ast::ClosureExpr(closure) => hl(closure.body()),
+ ast::EffectExpr(effect) => if effect.async_token().is_some() {
+ None
+ } else {
+ continue;
+ },
+ _ => continue,
+ }
+ };
+ }