Skip to content

Implement code completion #21323

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions src/librustc/middle/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
_ => ()
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_) => { }
Expand Down
7 changes: 4 additions & 3 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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(..) => {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}

Expand Down
4 changes: 3 additions & 1 deletion src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,8 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
`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
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) -> ! {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_back/svh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ mod svh_visitor {
ExprIfLet(..) => unreachable!(),
ExprWhileLet(..) => unreachable!(),
ExprMac(..) => unreachable!(),
ExprCompletion(..) => unreachable!(),
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
13 changes: 13 additions & 0 deletions src/librustc_driver/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
_ => {}
}
}
ast::ExprCompletion(_) => return,
_ => {}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/save/span_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl<'a> SpanUtils<'a> {
let filemap = self.sess.codemap().new_filemap(String::from_str("<anon-dxr>"),
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
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_trans/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
17 changes: 17 additions & 0 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 3 additions & 2 deletions src/librustdoc/html/highlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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(..) => "",
};

Expand Down
2 changes: 2 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,8 @@ pub enum Expr_ {

ExprMac(Mac),

ExprCompletion(P<Expr>),

/// A struct literal expression.
ExprStruct(Path, Vec<Field>, Option<P<Expr>> /* base */),

Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,7 @@ pub fn noop_fold_expr<T: Folder>(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)),
Expand Down
15 changes: 14 additions & 1 deletion src/libsyntax/parse/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pub struct StringReader<'a> {
/// The last character to be read
pub curr: Option<char>,
pub filemap: Rc<codemap::FileMap>,
pub complete_at: Option<BytePos>,
/* cached: */
pub peek_tok: token::Token,
pub peek_span: Span,
Expand All @@ -83,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,
Expand Down Expand Up @@ -150,6 +160,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,
Expand All @@ -160,8 +171,10 @@ impl<'a> StringReader<'a> {
}

pub fn new<'b>(span_diagnostic: &'b SpanHandler,
filemap: Rc<codemap::FileMap>) -> StringReader<'b> {
filemap: Rc<codemap::FileMap>,
complete_at: Option<BytePos>) -> StringReader<'b> {
let mut sr = StringReader::new_raw(span_diagnostic, filemap);
sr.complete_at = complete_at;
sr.advance_token();
sr
}
Expand Down
14 changes: 12 additions & 2 deletions src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Option<(String, u32)>>,
/// Used to determine and report recursive mod inclusions
included_mod_stack: RefCell<Vec<Path>>,
pub node_id: Cell<ast::NodeId>,
Expand All @@ -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),
}
Expand All @@ -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),
}
Expand Down Expand Up @@ -285,7 +288,14 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
// 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()
}
Expand Down
20 changes: 17 additions & 3 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -2030,7 +2030,7 @@ impl<'a> Parser<'a> {
}
}

pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: Expr_) -> P<Expr> {
pub fn mk_expr(&self, lo: BytePos, hi: BytePos, node: Expr_) -> P<Expr> {
P(Expr {
id: ast::DUMMY_NODE_ID,
node: node,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -3942,12 +3951,17 @@ impl<'a> Parser<'a> {
stmts: &mut Vec<P<Stmt>>,
last_block_expr: &mut Option<P<Expr>>) {
// 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();
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/parse/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading