From c6414c5ec31814bbc472a8b5dfeb38711500fc5f Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Mon, 9 Feb 2015 23:45:08 +0900 Subject: [PATCH 1/4] Parse --complete-at option --- src/librustc/session/config.rs | 2 ++ src/librustc/session/mod.rs | 3 +++ src/librustc_driver/driver.rs | 2 ++ src/librustc_driver/lib.rs | 13 +++++++++++++ src/librustc_trans/save/span_utils.rs | 2 +- src/librustdoc/html/highlight.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 6 +++++- src/libsyntax/parse/mod.rs | 14 ++++++++++++-- 8 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index cd664b7388cd8..d335531bfd4c3 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -807,6 +807,8 @@ pub fn rustc_optgroups() -> Vec { `everybody_loops` (all function bodies replaced with `loop {}`).", "TYPE"), opt::opt_u("", "show-span", "Show spans for compiler debugging", "expr|pat|ty"), + opt::opt_u("", "complete-at", "Give completions at the given position", + "FILENAME:BYTEPOS"), ]); opts } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index bd44dbe78f543..81c7b7a3b3a49 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -182,6 +182,9 @@ impl Session { pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap { &self.parse_sess.span_diagnostic.cm } + pub fn set_complete_at(&self, complete_at: Option<(String, u32)>) { + *self.parse_sess.complete_at.borrow_mut() = complete_at; + } // This exists to help with refactoring to eliminate impossible // cases later on pub fn impossible_case(&self, sp: Span, msg: &str) -> ! { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d82c160fdee9b..142da29996c85 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -346,6 +346,8 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) } }); + sess.set_complete_at(None); + if sess.opts.debugging_opts.ast_json_noexpand { println!("{}", json::as_json(&krate)); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index ef6e84d3a7641..aee2f7220f8ca 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -134,9 +134,22 @@ pub fn run_compiler<'a>(args: &[String], }; let mut sess = build_session(sopts, input_file_path, descriptions); + if sess.unstable_options() { sess.opts.show_span = matches.opt_str("show-span"); + + let complete_at = matches.opt_str("complete-at").and_then(|s| { + let parts: Vec<&str> = s.splitn(1, ':').collect(); + if let [filename, bytepos] = &*parts { + if let Ok(bytepos) = bytepos.parse() { + return Some((filename.to_string(), bytepos)); + } + } + None + }); + sess.set_complete_at(complete_at); } + let cfg = config::build_configuration(&sess); do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile)); diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index a724cdc0229d2..3cd8213eea845 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -86,7 +86,7 @@ impl<'a> SpanUtils<'a> { let filemap = self.sess.codemap().new_filemap(String::from_str(""), self.snippet(span)); let s = self.sess; - lexer::StringReader::new(s.diagnostic(), filemap) + lexer::StringReader::new(s.diagnostic(), filemap, None) } // Re-parses a path and returns the span for the last identifier in the path diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 6acd15379461c..fb41602057b5b 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -30,7 +30,7 @@ pub fn highlight(src: &str, class: Option<&str>, id: Option<&str>) -> String { let mut out = Vec::new(); doit(&sess, - lexer::StringReader::new(&sess.span_diagnostic, fm), + lexer::StringReader::new(&sess.span_diagnostic, fm, None), class, id, &mut out).unwrap(); diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index ecc39925a40c5..cc5897208e806 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -69,6 +69,7 @@ pub struct StringReader<'a> { /// The last character to be read pub curr: Option, pub filemap: Rc, + pub complete_at: Option, /* cached: */ pub peek_tok: token::Token, pub peek_span: Span, @@ -150,6 +151,7 @@ impl<'a> StringReader<'a> { col: CharPos(0), curr: Some('\n'), filemap: filemap, + complete_at: None, /* dummy values; not read */ peek_tok: token::Eof, peek_span: codemap::DUMMY_SP, @@ -160,8 +162,10 @@ impl<'a> StringReader<'a> { } pub fn new<'b>(span_diagnostic: &'b SpanHandler, - filemap: Rc) -> StringReader<'b> { + filemap: Rc, + complete_at: Option) -> StringReader<'b> { let mut sr = StringReader::new_raw(span_diagnostic, filemap); + sr.complete_at = complete_at; sr.advance_token(); sr } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 5f4cf9af5ee75..0ec1fb0cb27eb 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -11,7 +11,7 @@ //! The main parser interface use ast; -use codemap::{Span, CodeMap, FileMap}; +use codemap::{Span, CodeMap, FileMap, BytePos}; use diagnostic::{SpanHandler, mk_span_handler, default_handler, Auto}; use parse::attr::ParserAttr; use parse::parser::Parser; @@ -38,6 +38,7 @@ pub mod obsolete; /// Info about a parsing session. pub struct ParseSess { pub span_diagnostic: SpanHandler, // better be the same as the one in the reader! + pub complete_at: RefCell>, /// Used to determine and report recursive mod inclusions included_mod_stack: RefCell>, pub node_id: Cell, @@ -46,6 +47,7 @@ pub struct ParseSess { pub fn new_parse_sess() -> ParseSess { ParseSess { span_diagnostic: mk_span_handler(default_handler(Auto, None, true), CodeMap::new()), + complete_at: RefCell::new(None), included_mod_stack: RefCell::new(Vec::new()), node_id: Cell::new(1), } @@ -54,6 +56,7 @@ pub fn new_parse_sess() -> ParseSess { pub fn new_parse_sess_special_handler(sh: SpanHandler) -> ParseSess { ParseSess { span_diagnostic: sh, + complete_at: RefCell::new(None), included_mod_stack: RefCell::new(Vec::new()), node_id: Cell::new(1), } @@ -285,7 +288,14 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc) // it appears to me that the cfg doesn't matter here... indeed, // parsing tt's probably shouldn't require a parser at all. let cfg = Vec::new(); - let srdr = lexer::StringReader::new(&sess.span_diagnostic, filemap); + let complete_at = match *sess.complete_at.borrow() { + Some((ref filename, bytepos)) if filemap.name == *filename => { + Some(filemap.start_pos + BytePos(bytepos)) + } + _ => None + }; + let srdr = lexer::StringReader::new(&sess.span_diagnostic, filemap, + complete_at); let mut p1 = Parser::new(sess, cfg, box srdr); p1.parse_all_token_trees() } From c1ddcf2f6a3fa13765ca278ba41fa4c10439d8ee Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 10 Feb 2015 14:52:55 +0900 Subject: [PATCH 2/4] Add token::GenerateCompletion --- src/librustdoc/html/highlight.rs | 3 ++- src/libsyntax/parse/lexer/mod.rs | 9 +++++++++ src/libsyntax/parse/token.rs | 3 +++ src/libsyntax/print/pprust.rs | 10 ++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index fb41602057b5b..cbdbcb98602a1 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -171,7 +171,8 @@ fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader, token::Lifetime(..) => "lifetime", token::DocComment(..) => "doccomment", - token::Underscore | token::Eof | token::Interpolated(..) | + token::Underscore | token::Eof | token::GenerateCompletion | + token::Interpolated(..) | token::MatchNt(..) | token::SubstNt(..) => "", }; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index cc5897208e806..e21e86e261f33 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -84,6 +84,15 @@ impl<'a> Reader for StringReader<'a> { fn is_eof(&self) -> bool { self.curr.is_none() } /// Return the next token. EFFECT: advances the string_reader. fn next_token(&mut self) -> TokenAndSpan { + if let Some(pos) = self.complete_at { + if self.peek_span.lo >= pos { + self.complete_at = None; + return TokenAndSpan { + tok: token::GenerateCompletion, + sp: codemap::mk_sp(pos, pos), + } + } + } let ret_val = TokenAndSpan { tok: replace(&mut self.peek_tok, token::Underscore), sp: self.peek_span, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 45f4f044ea4d1..c403dc15025cb 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -161,6 +161,9 @@ pub enum Token { /// A macro variable with special meaning. SpecialVarNt(SpecialMacroVar), + /* For completion */ + GenerateCompletion, + // Junk. These carry no data because we don't really care about the data // they *would* carry, and don't really want to allocate a new ident for // them. Instead, users could extract that from the associated span. diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 583095e157427..6a4b6df8d9011 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -294,6 +294,16 @@ pub fn token_to_string(tok: &Token) -> String { token::SpecialVarNt(var) => format!("${}", var.as_str()), + // A proofreading mark is chosen, because the compiler is proofreading + // your code. + // + // U+2038 CARET or U+2041 CARET INSERTION POINT would be better, + // but both have poor font support. Neither are supported by + // Courier New, the default monospaced font on Windows, for example. + token::GenerateCompletion => { + "\u{B6}".to_string() // PILCROW SIGN + } + token::Interpolated(ref nt) => match *nt { token::NtExpr(ref e) => expr_to_string(&**e), token::NtMeta(ref e) => meta_item_to_string(&**e), From 0a0dc5a998573684365f27872b96f81cb68f3395 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 10 Feb 2015 23:18:31 +0900 Subject: [PATCH 3/4] Add ast::ExprCompletion --- src/librustc/middle/cfg/construct.rs | 1 + src/librustc/middle/dead.rs | 1 + src/librustc/middle/expr_use_visitor.rs | 4 ++-- src/librustc/middle/liveness.rs | 7 ++++--- src/librustc/middle/mem_categorization.rs | 3 ++- src/librustc/middle/ty.rs | 4 +++- src/librustc_back/svh.rs | 1 + src/librustc_privacy/lib.rs | 1 + src/librustc_trans/trans/debuginfo.rs | 3 ++- src/librustc_typeck/check/mod.rs | 17 +++++++++++++++++ src/libsyntax/ast.rs | 2 ++ src/libsyntax/fold.rs | 1 + src/libsyntax/parse/parser.rs | 20 +++++++++++++++++--- src/libsyntax/print/pprust.rs | 4 ++++ src/libsyntax/visit.rs | 3 +++ 15 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index d39b94a202e4a..39e49531e9384 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -436,6 +436,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { ast::ExprCast(ref e, _) | ast::ExprUnary(_, ref e) | ast::ExprParen(ref e) | + ast::ExprCompletion(ref e) | ast::ExprField(ref e, _) | ast::ExprTupField(ref e, _) => { self.straightline(expr, pred, Some(&**e).into_iter()) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index a157d5d712b58..95253688a7782 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -277,6 +277,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { ast::ExprTupField(ref lhs, idx) => { self.handle_tup_field_access(&**lhs, idx.node); } + ast::ExprCompletion(..) => return, _ => () } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 5cc7502b5128d..5904913b8b66d 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -421,8 +421,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { self.walk_adjustment(expr); match expr.node { - ast::ExprParen(ref subexpr) => { - self.walk_expr(&**subexpr) + ast::ExprParen(ref e) | ast::ExprCompletion(ref e) => { + self.walk_expr(&e) } ast::ExprPath(_) | ast::ExprQPath(_) => { } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index fcc5d70a7a564..6bd399750583d 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -505,7 +505,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { ast::ExprBlock(..) | ast::ExprAssign(..) | ast::ExprAssignOp(..) | ast::ExprMac(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) | ast::ExprInlineAsm(..) | ast::ExprBox(..) | - ast::ExprRange(..) => { + ast::ExprRange(..) | ast::ExprCompletion(..) => { visit::walk_expr(ir, expr); } } @@ -1189,7 +1189,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ast::ExprAddrOf(_, ref e) | ast::ExprCast(ref e, _) | ast::ExprUnary(_, ref e) | - ast::ExprParen(ref e) => { + ast::ExprParen(ref e) | + ast::ExprCompletion(ref e) => { self.propagate_through_expr(&**e, succ) } @@ -1468,7 +1469,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { ast::ExprBlock(..) | ast::ExprMac(..) | ast::ExprAddrOf(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) | ast::ExprClosure(..) | ast::ExprPath(..) | ast::ExprBox(..) | - ast::ExprRange(..) | ast::ExprQPath(..) => { + ast::ExprRange(..) | ast::ExprQPath(..) | ast::ExprCompletion(..) => { visit::walk_expr(this, expr); } ast::ExprIfLet(..) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 58492c817fd0b..072dda0c5f06b 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -548,7 +548,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) | ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) | ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | - ast::ExprInlineAsm(..) | ast::ExprBox(..) => { + ast::ExprInlineAsm(..) | ast::ExprBox(..) | + ast::ExprCompletion(..) => { Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 95f7ff5852440..9ff059033bc83 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4617,7 +4617,9 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { } } - ast::ExprParen(ref e) => expr_kind(tcx, &**e), + ast::ExprParen(ref e) | ast::ExprCompletion(ref e) => { + expr_kind(tcx, &e) + } ast::ExprMac(..) => { tcx.sess.span_bug( diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index c33d10bfbab39..0346c2d4f73fd 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -293,6 +293,7 @@ mod svh_visitor { ExprIfLet(..) => unreachable!(), ExprWhileLet(..) => unreachable!(), ExprMac(..) => unreachable!(), + ExprCompletion(..) => unreachable!(), } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index aa9b6c479bb78..d5afeb10f54a6 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -954,6 +954,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { _ => {} } } + ast::ExprCompletion(_) => return, _ => {} } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index c10ff753936b3..0cb0a84f7ab2a 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3491,7 +3491,8 @@ fn create_scope_map(cx: &CrateContext, ast::ExprAddrOf(_, ref sub_exp) | ast::ExprField(ref sub_exp, _) | ast::ExprTupField(ref sub_exp, _) | - ast::ExprParen(ref sub_exp) => + ast::ExprParen(ref sub_exp) | + ast::ExprCompletion(ref sub_exp) => walk_expr(cx, &**sub_exp, scope_stack, scope_map), ast::ExprBox(ref place, ref sub_expr) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9c0d6f7dae386..4773fb9a57fdb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3679,6 +3679,23 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lvalue_pref); fcx.write_ty(id, fcx.expr_ty(&**a)); } + ast::ExprCompletion(ref e) => { + fcx.write_ty(e.id, fcx.infcx().next_diverging_ty_var()); + fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); + if let ast::ExprField(ref base, _) = e.node { + check_expr_with_lvalue_pref(fcx, &base, lvalue_pref); + let expr_t = structurally_resolved_type(fcx, base.span, fcx.expr_ty(&base)); + match expr_t.sty { + ty::ty_struct(base_id, _) => { + let fields = ty::lookup_struct_fields(tcx, base_id); + for field in fields.iter() { + println!("{}", field.name); + } + } + _ => () + } + } + } ast::ExprAssign(ref lhs, ref rhs) => { check_expr_with_lvalue_pref(fcx, &**lhs, PreferMutLvalue); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8793f81b1996..47e580e47748d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -761,6 +761,8 @@ pub enum Expr_ { ExprMac(Mac), + ExprCompletion(P), + /// A struct literal expression. ExprStruct(Path, Vec, Option> /* base */), diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 8f1d15f6da885..1ff1ebdc9da12 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1388,6 +1388,7 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> expn_id: expn_id, }), ExprMac(mac) => ExprMac(folder.fold_mac(mac)), + ExprCompletion(expr) => ExprCompletion(folder.fold_expr(expr)), ExprStruct(path, fields, maybe_expr) => { ExprStruct(folder.fold_path(path), fields.move_map(|x| folder.fold_field(x)), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fd2f0685cab83..a3c7250e423d3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -22,7 +22,7 @@ use ast::{DeclLocal, DefaultBlock, DefaultReturn}; use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf}; use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain}; use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox}; -use ast::{ExprBreak, ExprCall, ExprCast}; +use ast::{ExprBreak, ExprCall, ExprCast, ExprCompletion}; use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex}; use ast::{ExprLit, ExprLoop, ExprMac, ExprRange}; use ast::{ExprMethodCall, ExprParen, ExprPath, ExprQPath}; @@ -2030,7 +2030,7 @@ impl<'a> Parser<'a> { } } - pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: Expr_) -> P { + pub fn mk_expr(&self, lo: BytePos, hi: BytePos, node: Expr_) -> P { P(Expr { id: ast::DUMMY_NODE_ID, node: node, @@ -2505,6 +2505,15 @@ impl<'a> Parser<'a> { self.abort_if_errors(); } + token::GenerateCompletion => { + // Important: do not bump + let sp = self.span; + let hi = self.last_span.hi; + let id = codemap::respan(sp, special_idents::invalid); + let field = self.mk_field(e, id); + e = self.mk_expr(lo, hi, + ExprCompletion(self.mk_expr(lo, hi, field))); + } _ => self.unexpected() } continue; @@ -3942,12 +3951,17 @@ impl<'a> Parser<'a> { stmts: &mut Vec>, last_block_expr: &mut Option>) { // expression without semicolon - if classify::expr_requires_semi_to_be_stmt(&*e) { + if classify::expr_requires_semi_to_be_stmt(&*e) && + self.token != token::GenerateCompletion { // Just check for errors and recover; do not eat semicolon yet. self.commit_stmt(&[], &[token::Semi, token::CloseDelim(token::Brace)]); } + if self.token == token::GenerateCompletion { + self.bump(); + } + match self.token { token::Semi => { self.bump(); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6a4b6df8d9011..0ad8608b3b3a7 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1943,6 +1943,10 @@ impl<'a> State<'a> { try!(self.pclose()); } ast::ExprMac(ref m) => try!(self.print_mac(m, token::Paren)), + ast::ExprCompletion(ref e) => { + try!(self.print_expr(&e)); + try!(word(&mut self.s, &token_to_string(&token::GenerateCompletion))); + } ast::ExprParen(ref e) => { try!(self.popen()); try!(self.print_expr(&**e)); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 21cb62b0a0c11..07207227e221d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -877,6 +877,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { walk_expr_opt(visitor, optional_expression) } ExprMac(ref mac) => visitor.visit_mac(mac), + ExprCompletion(ref subexpression) => { + visitor.visit_expr(&subexpression); + } ExprParen(ref subexpression) => { visitor.visit_expr(&**subexpression) } From 5f5b76dd4e99490fe99347905e65008aa3981739 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Wed, 11 Feb 2015 00:08:17 +0900 Subject: [PATCH 4/4] Add a test for code completion --- src/test/run-make/complete-at/Makefile | 6 ++++++ src/test/run-make/complete-at/input.rs | 21 +++++++++++++++++++++ src/test/run-make/complete-at/output | 2 ++ 3 files changed, 29 insertions(+) create mode 100644 src/test/run-make/complete-at/Makefile create mode 100644 src/test/run-make/complete-at/input.rs create mode 100644 src/test/run-make/complete-at/output diff --git a/src/test/run-make/complete-at/Makefile b/src/test/run-make/complete-at/Makefile new file mode 100644 index 0000000000000..2e9345ffafdce --- /dev/null +++ b/src/test/run-make/complete-at/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + $(RUSTC) -Z no-trans -Z unstable-options \ + --complete-at input.rs:583 input.rs > $(TMPDIR)/output + cmp output $(TMPDIR)/output diff --git a/src/test/run-make/complete-at/input.rs b/src/test/run-make/complete-at/input.rs new file mode 100644 index 0000000000000..b6b8062509a27 --- /dev/null +++ b/src/test/run-make/complete-at/input.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +struct Point { + x: i32, + y: i32, +} + +fn main() { + let p = Point { x: 0, y: 0 }; + p. +} diff --git a/src/test/run-make/complete-at/output b/src/test/run-make/complete-at/output new file mode 100644 index 0000000000000..b77b4eb1d946f --- /dev/null +++ b/src/test/run-make/complete-at/output @@ -0,0 +1,2 @@ +x +y