"move condition to match guard",
|edit| {
edit.target(if_expr.syntax().text_range());
- let then_only_expr = then_block.statements().next().is_none();
+ let then_only_expr = then_block.block().and_then(|it| it.statements().next()).is_none();
- match &then_block.expr() {
+ match &then_block.block().and_then(|it| it.expr()) {
Some(then_expr) if then_only_expr => {
edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text())
}
+use format_buf::format;
use hir::db::HirDatabase;
use ra_fmt::extract_trivial_expression;
use ra_syntax::{ast, AstNode};
ctx.build()
}
-fn build_match_expr(expr: ast::Expr, pat1: ast::Pat, arm1: ast::Block, arm2: ast::Block) -> String {
+fn build_match_expr(
+ expr: ast::Expr,
+ pat1: ast::Pat,
+ arm1: ast::BlockExpr,
+ arm2: ast::BlockExpr,
+) -> String {
let mut buf = String::new();
- buf.push_str(&format!("match {} {{\n", expr.syntax().text()));
- buf.push_str(&format!(" {} => {}\n", pat1.syntax().text(), format_arm(&arm1)));
- buf.push_str(&format!(" _ => {}\n", format_arm(&arm2)));
+ format!(buf, "match {} {{\n", expr.syntax().text());
+ format!(buf, " {} => {}\n", pat1.syntax().text(), format_arm(&arm1));
+ format!(buf, " _ => {}\n", format_arm(&arm2));
buf.push_str("}");
buf
}
-fn format_arm(block: &ast::Block) -> String {
+fn format_arm(block: &ast::BlockExpr) -> String {
match extract_trivial_expression(block) {
None => block.syntax().text().to_string(),
Some(e) => format!("{},", e.syntax().text()),
successors(token.prev_token(), |token| token.prev_token())
}
-pub fn extract_trivial_expression(block: &ast::Block) -> Option<ast::Expr> {
+pub fn extract_trivial_expression(expr: &ast::BlockExpr) -> Option<ast::Expr> {
+ let block = expr.block()?;
let expr = block.expr()?;
if expr.syntax().text().contains_char('\n') {
return None;
expr_id: crate::expr::ExprId,
) -> Option<Source<ast::Expr>> {
let source_map = self.body_source_map(db);
- let expr_syntax = source_map.expr_syntax(expr_id)?;
+ let expr_syntax = source_map.expr_syntax(expr_id)?.a()?;
let source = self.source(db);
- let node = expr_syntax.to_node(&source.ast.syntax());
- ast::Expr::cast(node).map(|ast| Source { file_id: source.file_id, ast })
+ let ast = expr_syntax.to_node(&source.ast.syntax());
+ Some(Source { file_id: source.file_id, ast })
}
}
self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner,
TypeAscriptionOwner,
},
- AstNode, AstPtr, SyntaxNodePtr,
+ AstNode, AstPtr,
};
use test_utils::tested_by;
/// file, so that we don't recompute types whenever some whitespace is typed.
#[derive(Default, Debug, Eq, PartialEq)]
pub struct BodySourceMap {
- expr_map: FxHashMap<SyntaxNodePtr, ExprId>,
- expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>,
+ expr_map: FxHashMap<ExprPtr, ExprId>,
+ expr_map_back: ArenaMap<ExprId, ExprPtr>,
pat_map: FxHashMap<PatPtr, PatId>,
pat_map_back: ArenaMap<PatId, PatPtr>,
field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
}
+type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>;
type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
impl Body {
}
impl BodySourceMap {
- pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<SyntaxNodePtr> {
+ pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprPtr> {
self.expr_map_back.get(expr).cloned()
}
- pub(crate) fn syntax_expr(&self, ptr: SyntaxNodePtr) -> Option<ExprId> {
- self.expr_map.get(&ptr).cloned()
- }
-
pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> {
- self.expr_map.get(&SyntaxNodePtr::new(node.syntax())).cloned()
+ self.expr_map.get(&Either::A(AstPtr::new(node))).cloned()
}
pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatPtr> {
current_file_id: file_id,
}
}
- fn alloc_expr(&mut self, expr: Expr, syntax_ptr: SyntaxNodePtr) -> ExprId {
+ fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
+ let ptr = Either::A(ptr);
let id = self.exprs.alloc(expr);
if self.current_file_id == self.original_file_id {
- self.source_map.expr_map.insert(syntax_ptr, id);
- self.source_map.expr_map_back.insert(id, syntax_ptr);
+ self.source_map.expr_map.insert(ptr, id);
+ self.source_map.expr_map_back.insert(id, ptr);
}
id
}
}
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
- let syntax_ptr = SyntaxNodePtr::new(expr.syntax());
+ let syntax_ptr = AstPtr::new(&expr);
match expr {
ast::Expr::IfExpr(e) => {
let then_branch = self.collect_block_opt(e.then_branch());
self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
}
ast::Expr::TryBlockExpr(e) => {
- let body = self.collect_block_opt(e.block());
+ let body = self.collect_block_opt(e.body());
self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
}
- ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()),
+ ast::Expr::BlockExpr(e) => self.collect_block(e),
ast::Expr::LoopExpr(e) => {
let body = self.collect_block_opt(e.loop_body());
self.alloc_expr(Expr::Loop { body }, syntax_ptr)
ast::Expr::ParenExpr(e) => {
let inner = self.collect_expr_opt(e.expr());
// make the paren expr point to the inner expression as well
- self.source_map.expr_map.insert(syntax_ptr, inner);
+ self.source_map.expr_map.insert(Either::A(syntax_ptr), inner);
inner
}
ast::Expr::ReturnExpr(e) => {
} else if let Some(nr) = field.name_ref() {
// field shorthand
let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(&nr)));
- self.source_map
- .expr_map
- .insert(SyntaxNodePtr::new(nr.syntax()), id);
- self.source_map
- .expr_map_back
- .insert(id, SyntaxNodePtr::new(nr.syntax()));
+ let ptr = Either::B(AstPtr::new(&field));
+ self.source_map.expr_map.insert(ptr, id);
+ self.source_map.expr_map_back.insert(id, ptr);
id
} else {
self.exprs.alloc(Expr::Missing)
}
}
- fn collect_block(&mut self, block: ast::Block) -> ExprId {
+ fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId {
+ let syntax_node_ptr = AstPtr::new(&expr.clone().into());
+ let block = match expr.block() {
+ Some(block) => block,
+ None => return self.alloc_expr(Expr::Missing, syntax_node_ptr),
+ };
let statements = block
.statements()
.map(|s| match s {
})
.collect();
let tail = block.expr().map(|e| self.collect_expr(e));
- self.alloc_expr(Expr::Block { statements, tail }, SyntaxNodePtr::new(block.syntax()))
+ self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr)
}
- fn collect_block_opt(&mut self, block: Option<ast::Block>) -> ExprId {
- if let Some(block) = block {
+ fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
+ if let Some(block) = expr {
self.collect_block(block)
} else {
self.exprs.alloc(Expr::Missing)
#[cfg(test)]
mod tests {
use ra_db::SourceDatabase;
- use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNodePtr};
+ use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
use test_utils::{assert_eq_text, extract_offset};
use crate::{mock::MockDatabase, source_binder::SourceAnalyzer};
let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None);
let scopes = analyzer.scopes();
- let expr_id =
- analyzer.body_source_map().syntax_expr(SyntaxNodePtr::new(marker.syntax())).unwrap();
+ let expr_id = analyzer.body_source_map().node_expr(&marker.into()).unwrap();
let scope = scopes.scope_for(expr_id);
let actual = scopes
-use rustc_hash::FxHashSet;
use std::sync::Arc;
-use ra_syntax::ast::{AstNode, RecordLit};
+use ra_syntax::ast::{self, AstNode};
+use rustc_hash::FxHashSet;
use super::{Expr, ExprId, RecordLitField};
use crate::{
ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution,
};
-use ra_syntax::ast;
pub(crate) struct ExprValidator<'a, 'b: 'a> {
func: Function,
let source_file = parse.tree();
if let Some(field_list_node) = source_map
.expr_syntax(id)
+ .and_then(|ptr| ptr.a())
.map(|ptr| ptr.to_node(source_file.syntax()))
- .and_then(RecordLit::cast)
+ .and_then(|expr| match expr {
+ ast::Expr::RecordLit(it) => Some(it),
+ _ => None,
+ })
.and_then(|lit| lit.record_field_list())
{
let field_list_ptr = AstPtr::new(&field_list_node);
let source_map = self.func.body_source_map(db);
let file_id = self.func.source(db).file_id;
- if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.cast::<ast::Expr>()) {
+ if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.a()) {
self.sink.push(MissingOkInTailExpr { file: file_id, expr });
}
}
node: &SyntaxNode,
) -> Option<ScopeId> {
node.ancestors()
- .map(|it| SyntaxNodePtr::new(&it))
- .filter_map(|ptr| source_map.syntax_expr(ptr))
+ .filter_map(ast::Expr::cast)
+ .filter_map(|it| source_map.node_expr(&it))
.find_map(|it| scopes.scope_for(it))
}
scopes
.scope_by_expr()
.iter()
- .filter_map(|(id, scope)| Some((source_map.expr_syntax(*id)?, scope)))
+ .filter_map(|(id, scope)| {
+ let ast_ptr = source_map.expr_syntax(*id)?.a()?;
+ Some((ast_ptr.syntax_node_ptr(), scope))
+ })
// find containing scope
.min_by_key(|(ptr, _scope)| {
(!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len())
let child_scopes = scopes
.scope_by_expr()
.iter()
- .filter_map(|(id, scope)| Some((source_map.expr_syntax(*id)?, scope)))
+ .filter_map(|(id, scope)| {
+ let ast_ptr = source_map.expr_syntax(*id)?.a()?;
+ Some((ast_ptr.syntax_node_ptr(), scope))
+ })
.map(|(ptr, scope)| (ptr.range(), scope))
.filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r);
for (expr, ty) in inference_result.type_of_expr.iter() {
let syntax_ptr = match body_source_map.expr_syntax(expr) {
- Some(sp) => sp,
+ Some(sp) => sp.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()),
None => continue,
};
types.push((syntax_ptr, ty));
fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> {
let block = ast::Block::cast(token.parent())?;
let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?;
- let expr = extract_trivial_expression(&block)?;
+ let expr = extract_trivial_expression(&block_expr)?;
let block_range = block_expr.syntax().text_range();
let mut buf = expr.syntax().text().to_string();
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ElseBranch {
- Block(ast::Block),
+ Block(ast::BlockExpr),
IfExpr(ast::IfExpr),
}
impl ast::IfExpr {
- pub fn then_branch(&self) -> Option<ast::Block> {
+ pub fn then_branch(&self) -> Option<ast::BlockExpr> {
self.blocks().nth(0)
}
pub fn else_branch(&self) -> Option<ElseBranch> {
Some(res)
}
- fn blocks(&self) -> AstChildren<ast::Block> {
+ fn blocks(&self) -> AstChildren<ast::BlockExpr> {
children(self)
}
}
}
}
impl TryBlockExpr {
- pub fn block(&self) -> Option<Block> {
+ pub fn body(&self) -> Option<BlockExpr> {
AstChildren::new(&self.syntax).next()
}
}
}
pub trait LoopBodyOwner: AstNode {
- fn loop_body(&self) -> Option<ast::Block> {
+ fn loop_body(&self) -> Option<ast::BlockExpr> {
child_opt(self)
}
}
traits: ["LoopBodyOwner"],
),
"TryBlockExpr": (
- options: ["Block"],
+ options: [["body", "BlockExpr"]],
),
"ForExpr": (
traits: ["LoopBodyOwner"],