This PR refactors the 'errors' part of libsyntax into its own crate (librustc_errors). This is the first part of a few refactorings to simplify error reporting and potentially support more output formats (like a standardized JSON output and possibly an --explain mode that can work with the user's code), though this PR stands on its own and doesn't assume further changes.
As part of separating out the errors crate, I have also refactored the code position portion of codemap into its own crate (libsyntax_pos). While it's helpful to have the common code positions in a separate crate for the new errors crate, this may also enable further simplifications in the future.
panic_abort panic_unwind unwind
RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
- rustc_data_structures rustc_platform_intrinsics \
+ rustc_data_structures rustc_platform_intrinsics rustc_errors \
rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \
rustc_const_eval rustc_const_math rustc_incremental
-HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros \
+HOST_CRATES := syntax syntax_ext syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \
flate arena graphviz rbml log serialize
TOOLS := compiletest rustdoc rustc rustbook error_index_generator
DEPS_term := std
DEPS_test := std getopts term native:rust_test_helpers
-DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode
-DEPS_syntax_ext := syntax fmt_macros
+DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos
+DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros
+DEPS_syntax_pos := serialize
DEPS_rustc_const_math := std syntax log serialize
DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \
- rustc_back graphviz
+ rustc_back graphviz syntax_pos
DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \
log graphviz rustc_llvm rustc_back rustc_data_structures\
- rustc_const_math
+ rustc_const_math syntax_pos rustc_errors
DEPS_rustc_back := std syntax flate log libc
-DEPS_rustc_borrowck := rustc log graphviz syntax rustc_mir
+DEPS_rustc_borrowck := rustc log graphviz syntax syntax_pos rustc_errors rustc_mir
DEPS_rustc_data_structures := std log serialize
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
rustc_trans rustc_privacy rustc_lint rustc_plugin \
rustc_metadata syntax_ext rustc_passes rustc_save_analysis rustc_const_eval \
- rustc_incremental
-DEPS_rustc_lint := rustc log syntax rustc_const_eval
+ rustc_incremental syntax_pos rustc_errors
+DEPS_rustc_errors := log libc serialize syntax_pos
+DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
-DEPS_rustc_metadata := rustc syntax rbml rustc_const_math
-DEPS_rustc_passes := syntax rustc core rustc_const_eval
-DEPS_rustc_mir := rustc syntax rustc_const_math rustc_const_eval rustc_bitflags
-DEPS_rustc_resolve := arena rustc log syntax
+DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math
+DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors
+DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags
+DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors
DEPS_rustc_platform_intrinsics := std
-DEPS_rustc_plugin := rustc rustc_metadata syntax
-DEPS_rustc_privacy := rustc log syntax
+DEPS_rustc_plugin := rustc rustc_metadata syntax syntax_pos rustc_errors
+DEPS_rustc_privacy := rustc log syntax syntax_pos
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
log syntax serialize rustc_llvm rustc_platform_intrinsics \
- rustc_const_math rustc_const_eval rustc_incremental
-DEPS_rustc_incremental := rbml rustc serialize rustc_data_structures
-DEPS_rustc_save_analysis := rustc log syntax serialize
-DEPS_rustc_typeck := rustc syntax rustc_platform_intrinsics rustc_const_math \
- rustc_const_eval
+ rustc_const_math rustc_const_eval rustc_incremental rustc_errors syntax_pos
+DEPS_rustc_incremental := rbml rustc syntax_pos serialize rustc_data_structures
+DEPS_rustc_save_analysis := rustc log syntax syntax_pos serialize
+DEPS_rustc_typeck := rustc syntax syntax_pos rustc_platform_intrinsics rustc_const_math \
+ rustc_const_eval rustc_errors
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
- test rustc_lint rustc_const_eval
+ test rustc_lint rustc_const_eval syntax_pos
TOOL_DEPS_compiletest := test getopts log serialize
extern crate rustc;
extern crate rustc_plugin;
-use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ast::TokenTree;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder; // trait for expr_usize
+use syntax_pos::Span;
use rustc_plugin::Registry;
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
use syntax::ast;
use syntax::ast::Name;
use syntax::codemap;
-use syntax::codemap::Pos;
use syntax::parse::token::{self, BinOpToken, DelimToken, Lit, Token};
use syntax::parse::lexer::TokenAndSpan;
+use syntax_pos::Pos;
fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
fn id() -> token::Token {
lo -= surrogate_pairs_pos.binary_search(&(lo as usize)).unwrap_or_else(|x| x) as u32;
hi -= surrogate_pairs_pos.binary_search(&(hi as usize)).unwrap_or_else(|x| x) as u32;
- let sp = codemap::Span {
- lo: codemap::BytePos(lo),
- hi: codemap::BytePos(hi),
- expn_id: codemap::NO_EXPANSION
+ let sp = syntax_pos::Span {
+ lo: syntax_pos::BytePos(lo),
+ hi: syntax_pos::BytePos(hi),
+ expn_id: syntax_pos::NO_EXPANSION
};
TokenAndSpan {
rustc_bitflags = { path = "../librustc_bitflags" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
rustc_llvm = { path = "../librustc_llvm" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
+syntax_pos = { path "../libsyntax_pos" }
\ No newline at end of file
use syntax::ast::MetaItemKind;
use syntax::attr::ThinAttributesExt;
use hir;
-use syntax::codemap::{respan, Span, Spanned};
+use syntax_pos::Span;
+use syntax::codemap::{respan, Spanned};
use syntax::ptr::P;
use syntax::parse::token::keywords;
use syntax::util::move_map::MoveMap;
use syntax::abi::Abi;
use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
use syntax::attr::ThinAttributesExt;
-use syntax::codemap::{Span, Spanned};
+use syntax::codemap::Spanned;
+use syntax_pos::Span;
use hir::*;
use std::cmp;
use syntax::ast::*;
use syntax::attr::{ThinAttributes, ThinAttributesExt};
use syntax::ptr::P;
-use syntax::codemap::{respan, Spanned, Span};
+use syntax::codemap::{respan, Spanned};
use syntax::parse::token;
use syntax::std_inject;
use syntax::visit::{self, Visitor};
+use syntax_pos::Span;
pub struct LoweringContext<'a> {
crate_root: Option<&'static str>,
use syntax::ast::{Attribute, Name, NodeId};
use syntax::attr::ThinAttributesExt;
use hir as ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use hir::intravisit::FnKind;
/// An FnLikeNode is a Node that is like a fn, in that it has a decl
use middle::cstore::InlinedItem;
use std::iter::repeat;
use syntax::ast::{NodeId, CRATE_NODE_ID};
-use syntax::codemap::Span;
+use syntax_pos::Span;
/// A Visitor that walks over the HIR and collects Nodes into a HIR map
pub struct NodeCollector<'ast> {
use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, };
use syntax::attr::ThinAttributesExt;
-use syntax::codemap::{Span, Spanned};
+use syntax::codemap::Spanned;
use syntax::visit;
+use syntax_pos::Span;
use hir::*;
use hir::fold::Folder;
use hir::def_id::DefId;
use util::nodemap::{NodeMap, FnvHashSet};
-use syntax::codemap::{self, mk_sp, respan, Span, Spanned, ExpnId};
+use syntax_pos::{mk_sp, Span, ExpnId};
+use syntax::codemap::{self, respan, Spanned};
use syntax::abi::Abi;
use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, TokenTree, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
use ty::TyCtxt;
use util::nodemap::FnvHashMap;
use syntax::ast;
-use syntax::codemap::{Span, Spanned, DUMMY_SP};
+use syntax::codemap::Spanned;
+use syntax_pos::{Span, DUMMY_SP};
use std::iter::{Enumerate, ExactSizeIterator};
use syntax::abi::Abi;
use syntax::ast;
-use syntax::codemap::{self, CodeMap, BytePos, Spanned};
-use syntax::errors;
+use syntax::codemap::{CodeMap, Spanned};
use syntax::parse::token::{self, keywords, BinOpToken};
use syntax::parse::lexer::comments;
use syntax::print::pp::{self, break_offset, word, space, hardbreak};
use syntax::print::pp::Breaks::{Consistent, Inconsistent};
use syntax::print::pprust::{self as ast_pp, PrintState};
use syntax::ptr::P;
+use syntax_pos::{self, BytePos};
+use errors;
use hir;
use hir::{Crate, PatKind, RegionTyParamBound, SelfKind, TraitTyParamBound, TraitBoundModifier};
self.end() // close the head-box
}
- pub fn bclose_(&mut self, span: codemap::Span, indented: usize) -> io::Result<()> {
+ pub fn bclose_(&mut self, span: syntax_pos::Span, indented: usize) -> io::Result<()> {
self.bclose_maybe_open(span, indented, true)
}
pub fn bclose_maybe_open(&mut self,
- span: codemap::Span,
+ span: syntax_pos::Span,
indented: usize,
close_box: bool)
-> io::Result<()> {
}
Ok(())
}
- pub fn bclose(&mut self, span: codemap::Span) -> io::Result<()> {
+ pub fn bclose(&mut self, span: syntax_pos::Span) -> io::Result<()> {
self.bclose_(span, indent_unit)
}
mut get_span: G)
-> io::Result<()>
where F: FnMut(&mut State, &T) -> io::Result<()>,
- G: FnMut(&T) -> codemap::Span
+ G: FnMut(&T) -> syntax_pos::Span
{
self.rbox(0, b)?;
let len = elts.len();
enum_definition: &hir::EnumDef,
generics: &hir::Generics,
name: ast::Name,
- span: codemap::Span,
+ span: syntax_pos::Span,
visibility: &hir::Visibility)
-> io::Result<()> {
self.head(&visibility_qualified(visibility, "enum"))?;
pub fn print_variants(&mut self,
variants: &[hir::Variant],
- span: codemap::Span)
+ span: syntax_pos::Span)
-> io::Result<()> {
self.bopen()?;
for v in variants {
struct_def: &hir::VariantData,
generics: &hir::Generics,
name: ast::Name,
- span: codemap::Span,
+ span: syntax_pos::Span,
print_finalizer: bool)
-> io::Result<()> {
self.print_name(name)?;
}
pub fn maybe_print_trailing_comment(&mut self,
- span: codemap::Span,
+ span: syntax_pos::Span,
next_pos: Option<BytePos>)
-> io::Result<()> {
let cm = match self.cm {
use traits::PredicateObligations;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
#[derive(Clone)]
pub struct CombineFields<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
use std::char::from_u32;
use std::fmt;
use syntax::ast;
-use syntax::errors::{DiagnosticBuilder, check_old_skool};
-use syntax::codemap::{self, Pos, Span};
use syntax::parse::token;
use syntax::ptr::P;
+use syntax_pos::{self, Pos, Span};
+use errors::{DiagnosticBuilder, check_old_skool};
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn note_and_explain_region(self,
fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime {
hir::Lifetime { id: ast::DUMMY_NODE_ID,
- span: codemap::DUMMY_SP,
+ span: syntax_pos::DUMMY_SP,
name: name }
}
use ty::{self, TyCtxt, Binder, TypeFoldable};
use ty::error::TypeError;
use ty::relate::{Relate, RelateResult, TypeRelation};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use util::nodemap::{FnvHashMap, FnvHashSet};
pub struct HrMatchResult<U> {
use std::cell::{Cell, RefCell, Ref, RefMut};
use std::fmt;
use syntax::ast;
-use syntax::codemap;
-use syntax::codemap::{Span, DUMMY_SP};
-use syntax::errors::DiagnosticBuilder;
+use errors::DiagnosticBuilder;
+use syntax_pos::{self, Span, DUMMY_SP};
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
use self::combine::CombineFields;
-> UnitResult<'tcx>
{
self.probe(|_| {
- let origin = TypeOrigin::Misc(codemap::DUMMY_SP);
+ let origin = TypeOrigin::Misc(syntax_pos::DUMMY_SP);
let trace = TypeTrace::types(origin, true, a, b);
self.sub(true, trace, &a, &b).map(|_| ())
})
pub fn dummy(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> TypeTrace<'tcx> {
TypeTrace {
- origin: TypeOrigin::Misc(codemap::DUMMY_SP),
+ origin: TypeOrigin::Misc(syntax_pos::DUMMY_SP),
values: Types(ExpectedFound {
expected: tcx.types.err,
found: tcx.types.err,
Coercion(a) => a,
EarlyBoundRegion(a, _) => a,
LateBoundRegion(a, _, _) => a,
- BoundRegionInCoherence(_) => codemap::DUMMY_SP,
+ BoundRegionInCoherence(_) => syntax_pos::DUMMY_SP,
UpvarRegion(_, a) => a
}
}
use self::UndoEntry::*;
use hir::def_id::{DefId};
use ty::{self, Ty};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use std::cmp::min;
use std::marker::PhantomData;
extern crate serialize;
extern crate collections;
extern crate rustc_const_math;
+extern crate rustc_errors as errors;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
+#[macro_use] extern crate syntax_pos;
#[macro_use] #[no_link] extern crate rustc_bitflags;
extern crate serialize as rustc_serialize; // used by deriving
use std::default::Default as StdDefault;
use std::mem;
use syntax::attr::{self, AttrMetaMethods};
-use syntax::codemap::Span;
-use syntax::errors::DiagnosticBuilder;
use syntax::parse::token::InternedString;
use syntax::ast;
use syntax::attr::ThinAttributesExt;
+use syntax_pos::Span;
+use errors::DiagnosticBuilder;
use hir;
use hir::intravisit as hir_visit;
use hir::intravisit::{IdVisitor, IdVisitingOperation};
use std::hash;
use std::ascii::AsciiExt;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use hir::intravisit::FnKind;
use syntax::visit as ast_visit;
use syntax::ast;
use hir::def::Def;
use ty::{Ty, TyCtxt};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use hir as ast;
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
use std::path::PathBuf;
use syntax::ast;
use syntax::attr;
-use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::parse::token::InternedString;
+use syntax_pos::Span;
use rustc_back::target::Target;
use hir;
use hir::intravisit::{IdVisitor, IdVisitingOperation, Visitor};
use std::collections::HashSet;
use syntax::{ast, codemap};
use syntax::attr;
+use syntax_pos;
// Any local node that may call something in its body block should be
// explored. For example, if it's a live NodeItem that is a
impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
fn visit_variant_data(&mut self, def: &hir::VariantData, _: ast::Name,
- _: &hir::Generics, _: ast::NodeId, _: codemap::Span) {
+ _: &hir::Generics, _: ast::NodeId, _: syntax_pos::Span) {
let has_extern_repr = self.struct_has_extern_repr;
let inherited_pub_visibility = self.inherited_pub_visibility;
let live_fields = def.fields().iter().filter(|f| {
fn warn_dead_code(&mut self,
id: ast::NodeId,
- span: codemap::Span,
+ span: syntax_pos::Span,
name: ast::Name,
node_type: &str) {
let name = name.as_str();
use ty::MethodCall;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use hir;
use hir::intravisit;
use hir::intravisit::{FnKind, Visitor};
use session::{config, Session};
use syntax::ast::NodeId;
use syntax::attr;
-use syntax::codemap::Span;
use syntax::entry::EntryPointType;
+use syntax_pos::Span;
use hir::{Item, ItemFn};
use hir::intravisit::Visitor;
use syntax::ast;
use syntax::ptr::P;
-use syntax::codemap::Span;
+use syntax_pos::Span;
///////////////////////////////////////////////////////////////////////////
// The Delegate trait
use syntax::abi::Abi::RustIntrinsic;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use hir::intravisit::{self, Visitor, FnKind};
use hir;
use std::io;
use std::rc::Rc;
use syntax::ast::{self, NodeId};
-use syntax::codemap::{BytePos, original_sp, Span};
+use syntax::codemap::original_sp;
use syntax::parse::token::keywords;
use syntax::ptr::P;
+use syntax_pos::{BytePos, Span};
use hir::Expr;
use hir;
use hir::pat_util::EnumerateAndAdjustIterator;
use hir;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use std::fmt;
use std::rc::Rc;
use std::collections::hash_map::Entry;
use std::fmt;
use std::mem;
-use syntax::codemap::{self, Span};
+use syntax::codemap;
use syntax::ast::{self, NodeId};
+use syntax_pos::Span;
use hir;
use hir::intravisit::{self, Visitor, FnKind};
use std::fmt;
use std::mem::replace;
use syntax::ast;
-use syntax::codemap::Span;
use syntax::parse::token::keywords;
+use syntax_pos::Span;
use util::nodemap::NodeMap;
use rustc_data_structures::fnv::FnvHashSet;
use ty::{self, TyCtxt};
use middle::privacy::AccessLevels;
use syntax::parse::token::InternedString;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
use syntax::ast;
use syntax::ast::{NodeId, Attribute};
use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version};
use middle::lang_items;
use syntax::ast;
-use syntax::codemap::Span;
use syntax::parse::token::InternedString;
+use syntax_pos::Span;
use hir::intravisit::Visitor;
use hir::intravisit;
use hir;
use std::{iter, u32};
use std::ops::{Index, IndexMut};
use syntax::ast::{self, Name};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use super::cache::Cache;
use rustc_const_math::ConstUsize;
use rustc_data_structures::tuple_slice::TupleSlice;
use rustc_data_structures::indexed_vec::Idx;
-use syntax::codemap::Span;
+use syntax_pos::Span;
// # The MIR Visitor
//
use syntax::ast::{self, IntTy, UintTy};
use syntax::attr;
use syntax::attr::AttrMetaMethods;
-use syntax::errors::{ColorConfig, Handler};
use syntax::parse;
use syntax::parse::token::InternedString;
use syntax::feature_gate::UnstableFeatures;
+use errors::{ColorConfig, Handler};
+
use getopts;
use std::collections::HashMap;
use std::env;
use middle::cstore::DummyCrateStore;
use session::config::{build_configuration, build_session_options};
use session::build_session;
-
+ use errors;
use std::rc::Rc;
use getopts::{getopts, OptGroup};
use syntax::attr;
use syntax::attr::AttrMetaMethods;
- use syntax::diagnostics;
fn optgroups() -> Vec<OptGroup> {
super::rustc_optgroups().into_iter()
Ok(m) => m,
Err(f) => panic!("test_switch_implies_cfg_test: {}", f)
};
- let registry = diagnostics::registry::Registry::new(&[]);
+ let registry = errors::registry::Registry::new(&[]);
let sessopts = build_session_options(matches);
let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore));
let cfg = build_configuration(&sess);
panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
}
};
- let registry = diagnostics::registry::Registry::new(&[]);
+ let registry = errors::registry::Registry::new(&[]);
let sessopts = build_session_options(matches);
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
let matches = getopts(&[
"-Awarnings".to_string()
], &optgroups()).unwrap();
- let registry = diagnostics::registry::Registry::new(&[]);
+ let registry = errors::registry::Registry::new(&[]);
let sessopts = build_session_options(&matches);
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
"-Awarnings".to_string(),
"-Dwarnings".to_string()
], &optgroups()).unwrap();
- let registry = diagnostics::registry::Registry::new(&[]);
+ let registry = errors::registry::Registry::new(&[]);
let sessopts = build_session_options(&matches);
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
let matches = getopts(&[
"-Adead_code".to_string()
], &optgroups()).unwrap();
- let registry = diagnostics::registry::Registry::new(&[]);
+ let registry = errors::registry::Registry::new(&[]);
let sessopts = build_session_options(&matches);
let sess = build_session(sessopts, &dep_graph, None, registry,
Rc::new(DummyCrateStore));
use mir::transform as mir_pass;
use syntax::ast::{NodeId, NodeIdAssigner, Name};
-use syntax::codemap::{Span, MultiSpan};
-use syntax::errors::{self, DiagnosticBuilder};
-use syntax::errors::emitter::{Emitter, BasicEmitter, EmitterWriter};
-use syntax::errors::json::JsonEmitter;
-use syntax::diagnostics;
+use errors::{self, DiagnosticBuilder};
+use errors::emitter::{Emitter, BasicEmitter, EmitterWriter};
+use syntax::json::JsonEmitter;
use syntax::feature_gate;
use syntax::parse;
use syntax::parse::ParseSess;
use syntax::parse::token;
use syntax::{ast, codemap};
use syntax::feature_gate::AttributeType;
+use syntax_pos::{Span, MultiSpan};
use rustc_back::target::Target;
use llvm;
pub fn build_session(sopts: config::Options,
dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
- registry: diagnostics::registry::Registry,
+ registry: errors::registry::Registry,
cstore: Rc<for<'a> CrateStore<'a>>)
-> Session {
build_session_with_codemap(sopts,
pub fn build_session_with_codemap(sopts: config::Options,
dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
- registry: diagnostics::registry::Registry,
+ registry: errors::registry::Registry,
cstore: Rc<for<'a> CrateStore<'a>>,
codemap: Rc<codemap::CodeMap>)
-> Session {
let emitter: Box<Emitter> = match sopts.error_format {
config::ErrorOutputType::HumanReadable(color_config) => {
- Box::new(EmitterWriter::stderr(color_config, Some(registry), codemap.clone()))
+ Box::new(EmitterWriter::stderr(color_config,
+ Some(registry),
+ codemap.clone(),
+ errors::snippet::FormatMode::EnvironmentSelected))
}
config::ErrorOutputType::Json => {
Box::new(JsonEmitter::stderr(Some(registry), codemap.clone()))
use ty::subst::TypeSpace;
use ty::{self, Ty, TyCtxt};
use infer::{InferCtxt, TypeOrigin};
-use syntax::codemap::DUMMY_SP;
+use syntax_pos::DUMMY_SP;
#[derive(Copy, Clone)]
struct InferIsLocal(bool);
use std::fmt;
use syntax::ast;
use syntax::attr::{AttributeMethods, AttrMetaMethods};
-use syntax::codemap::Span;
-use syntax::errors::DiagnosticBuilder;
+use syntax_pos::Span;
+use errors::DiagnosticBuilder;
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct TraitErrorKey<'tcx> {
use std::rc::Rc;
use syntax::ast;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
pub use self::error_reporting::TraitErrorKey;
pub use self::coherence::orphan_check;
use ty::subst::{Subst, Substs};
use traits::{self, ProjectionMode, ObligationCause, Normalized};
use ty::{self, TyCtxt};
-use syntax::codemap::DUMMY_SP;
+use syntax_pos::DUMMY_SP;
pub mod specialization_graph;
use infer::InferCtxt;
use ty::subst::{Subst, Substs};
use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use util::common::ErrorReported;
use util::nodemap::FnvHashSet;
use ty::LvaluePreference::{NoPreference};
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use hir;
use std::cell::Cell;
use std::fmt;
- use syntax::codemap;
+ use syntax_pos;
/// Marker types used for the scoped TLS slot.
/// The type context cannot be used directly because the scoped TLS
*const ThreadLocalInterners)>> = Cell::new(None)
}
- fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result {
+ fn span_debug(span: syntax_pos::Span, f: &mut fmt::Formatter) -> fmt::Result {
with(|tcx| {
write!(f, "{}", tcx.sess.codemap().span_to_string(span))
})
pub fn enter_global<'gcx, F, R>(gcx: GlobalCtxt<'gcx>, f: F) -> R
where F: for<'a> FnOnce(TyCtxt<'a, 'gcx, 'gcx>) -> R
{
- codemap::SPAN_DEBUG.with(|span_dbg| {
+ syntax_pos::SPAN_DEBUG.with(|span_dbg| {
let original_span_debug = span_dbg.get();
span_dbg.set(span_debug);
let result = enter(&gcx, &gcx.global_interners, f);
use std::fmt;
use syntax::abi;
use syntax::ast::{self, Name};
-use syntax::codemap::Span;
-use syntax::errors::DiagnosticBuilder;
+use errors::DiagnosticBuilder;
+use syntax_pos::Span;
use hir;
use syntax::ast::{FloatTy, IntTy, UintTy};
use syntax::attr;
-use syntax::codemap::DUMMY_SP;
+use syntax_pos::DUMMY_SP;
use std::cmp;
use std::fmt;
use std::vec::IntoIter;
use syntax::ast::{self, CrateNum, Name, NodeId};
use syntax::attr::{self, AttrMetaMethods};
-use syntax::codemap::{DUMMY_SP, Span};
use syntax::parse::token::InternedString;
+use syntax_pos::{DUMMY_SP, Span};
use rustc_const_math::ConstInt;
use std::iter::IntoIterator;
use std::slice::Iter;
use std::vec::{Vec, IntoIter};
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
///////////////////////////////////////////////////////////////////////////
use std::hash::{Hash, SipHasher, Hasher};
use syntax::ast::{self, Name};
use syntax::attr::{self, SignedInt, UnsignedInt};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use hir;
use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use std::iter::once;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use util::common::ErrorReported;
/// Returns the set of obligations needed to make `ty` well-formed.
[dependencies]
log = { path = "../liblog" }
syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
graphviz = { path = "../libgraphviz" }
rustc = { path = "../librustc" }
rustc_data_structures = { path = "../librustc_data_structures" }
use rustc::middle::region;
use rustc::ty::{self, TyCtxt};
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir;
use std::rc::Rc;
use std::mem;
use std::rc::Rc;
use syntax::ast;
-use syntax::codemap::{Span, DUMMY_SP};
use syntax::attr::AttrMetaMethods;
+use syntax_pos::{Span, DUMMY_SP};
#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum Fragment {
use std::rc::Rc;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir::{self, PatKind};
struct GatherMoveInfo<'tcx> {
use rustc::ty;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
type R = Result<(),()>;
use rustc::ty::{self, TyCtxt};
use syntax::ast;
-use syntax::codemap::Span;
use syntax::ast::NodeId;
+use syntax_pos::Span;
use rustc::hir;
use rustc::hir::Expr;
use rustc::hir::intravisit;
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
use rustc::ty;
use syntax::ast;
-use syntax::codemap;
-use syntax::errors::DiagnosticBuilder;
+use syntax_pos;
+use errors::DiagnosticBuilder;
use rustc::hir;
pub struct MoveErrorCollector<'tcx> {
#[derive(Clone)]
pub struct MoveSpanAndPath {
- pub span: codemap::Span,
+ pub span: syntax_pos::Span,
pub name: ast::Name,
}
}
fn note_move_destination(mut err: DiagnosticBuilder,
- move_to_span: codemap::Span,
+ move_to_span: syntax_pos::Span,
pat_name: ast::Name,
is_first_note: bool) -> DiagnosticBuilder {
if is_first_note {
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::ty;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use borrowck::ToInteriorKind;
use syntax::abi::{Abi};
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir};
use rustc::middle::lang_items;
use rustc::util::nodemap::FnvHashMap;
use rustc_data_structures::indexed_vec::Idx;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use std::fmt;
use std::u32;
use syntax::ast::{self, MetaItem};
use syntax::attr::AttrMetaMethods;
-use syntax::codemap::{Span, DUMMY_SP};
use syntax::ptr::P;
+use syntax_pos::{Span, DUMMY_SP};
use rustc::hir;
use rustc::hir::intravisit::{FnKind};
use std::rc::Rc;
use syntax::ast;
use syntax::attr::AttrMetaMethods;
-use syntax::codemap::{MultiSpan, Span};
-use syntax::errors::DiagnosticBuilder;
+use syntax_pos::{MultiSpan, Span};
+use errors::DiagnosticBuilder;
use rustc::hir;
use rustc::hir::{FnDecl, Block};
use std::rc::Rc;
use std::usize;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir;
use rustc::hir::intravisit::IdRange;
#![feature(question_mark)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
+extern crate syntax_pos;
+extern crate rustc_errors as errors;
// for "clarity", rename the graphviz crate to dot; graphviz within `borrowck`
// refers to the borrowck-specific graphviz adapter traits.
rustc_const_math = { path = "../librustc_const_math" }
syntax = { path = "../libsyntax" }
graphviz = { path = "../libgraphviz" }
+syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
use rustc_back::slice;
use syntax::ast::{self, DUMMY_NODE_ID, NodeId};
-use syntax::codemap::{Span, Spanned, DUMMY_SP};
+use syntax::codemap::Spanned;
+use syntax_pos::{Span, DUMMY_SP};
use rustc::hir::fold::{Folder, noop_fold_pat};
use rustc::hir::print::pat_to_string;
use syntax::ptr::P;
use rustc::hir::{Expr, PatKind};
use rustc::hir;
use rustc::hir::intravisit::FnKind;
-use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::codemap;
use syntax::attr::IntType;
+use syntax_pos::{self, Span};
use std::borrow::Cow;
use std::cmp::Ordering;
let field_pats =
try!(fields.iter()
.map(|field| Ok(codemap::Spanned {
- span: codemap::DUMMY_SP,
+ span: syntax_pos::DUMMY_SP,
node: hir::FieldPat {
name: field.name.node,
pat: try!(const_expr_to_pat(tcx, &field.expr,
extern crate rustc_back;
extern crate rustc_const_math;
extern crate graphviz;
-
+extern crate syntax_pos;
extern crate serialize as rustc_serialize; // used by deriving
// NB: This module needs to be declared first so diagnostics are
rustc_back = { path = "../librustc_back" }
rustc_borrowck = { path = "../librustc_borrowck" }
rustc_const_eval = { path = "../librustc_const_eval" }
+rustc_errors = { path = "../librustc_errors" }
rustc_lint = { path = "../librustc_lint" }
rustc_llvm = { path = "../librustc_llvm" }
rustc_mir = { path = "../librustc_mir" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
syntax_ext = { path = "../libsyntax_ext" }
+syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
extern crate rustc_back;
extern crate rustc_borrowck;
extern crate rustc_const_eval;
+extern crate rustc_errors as errors;
extern crate rustc_passes;
extern crate rustc_lint;
extern crate rustc_plugin;
#[macro_use]
extern crate syntax;
extern crate syntax_ext;
+extern crate syntax_pos;
use driver::CompileController;
use pretty::{PpMode, UserIdentifiedItem};
use rustc::session::early_error;
-use syntax::{ast, errors, diagnostics};
-use syntax::codemap::{CodeMap, FileLoader, RealFileLoader, MultiSpan};
-use syntax::errors::emitter::Emitter;
+use syntax::{ast, json};
+use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
use syntax::feature_gate::{GatedCfg, UnstableFeatures};
use syntax::parse::{self, PResult, token};
+use syntax_pos::MultiSpan;
+use errors::emitter::Emitter;
#[cfg(test)]
pub mod test;
fn early_callback(&mut self,
_: &getopts::Matches,
_: &config::Options,
- _: &diagnostics::registry::Registry,
+ _: &errors::registry::Registry,
_: ErrorOutputType)
-> Compilation {
Compilation::Continue
_: &config::Options,
_: &Option<PathBuf>,
_: &Option<PathBuf>,
- _: &diagnostics::registry::Registry)
+ _: &errors::registry::Registry)
-> Option<(Input, Option<PathBuf>)> {
None
}
pub struct RustcDefaultCalls;
fn handle_explain(code: &str,
- descriptions: &diagnostics::registry::Registry,
+ descriptions: &errors::registry::Registry,
output: ErrorOutputType) {
let normalised = if code.starts_with("E") {
code.to_string()
config::ErrorOutputType::HumanReadable(color_config) => {
Box::new(errors::emitter::BasicEmitter::stderr(color_config))
}
- config::ErrorOutputType::Json => Box::new(errors::json::JsonEmitter::basic()),
+ config::ErrorOutputType::Json => Box::new(json::JsonEmitter::basic()),
};
let mut saw_invalid_predicate = false;
fn early_callback(&mut self,
matches: &getopts::Matches,
sopts: &config::Options,
- descriptions: &diagnostics::registry::Registry,
+ descriptions: &errors::registry::Registry,
output: ErrorOutputType)
-> Compilation {
if let Some(ref code) = matches.opt_str("explain") {
sopts: &config::Options,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
- descriptions: &diagnostics::registry::Registry)
+ descriptions: &errors::registry::Registry)
-> Option<(Input, Option<PathBuf>)> {
match matches.free.len() {
0 => {
panic!();
}
-pub fn diagnostics_registry() -> diagnostics::registry::Registry {
- use syntax::diagnostics::registry::Registry;
+pub fn diagnostics_registry() -> errors::registry::Registry {
+ use errors::registry::Registry;
let mut all_errors = Vec::new();
all_errors.extend_from_slice(&rustc::DIAGNOSTICS);
use rustc_mir::graphviz::write_mir_graphviz;
use syntax::ast::{self, BlockCheckMode};
-use syntax::codemap;
use syntax::fold::{self, Folder};
use syntax::print::{pp, pprust};
use syntax::print::pprust::PrintState;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;
+use syntax_pos;
use graphviz as dot;
stmts: vec![],
rules: rules,
id: ast::DUMMY_NODE_ID,
- span: codemap::DUMMY_SP,
+ span: syntax_pos::DUMMY_SP,
})
}
let loop_expr = P(ast::Expr {
node: ast::ExprKind::Loop(empty_block, None),
id: ast::DUMMY_NODE_ID,
- span: codemap::DUMMY_SP,
+ span: syntax_pos::DUMMY_SP,
attrs: None,
});
use std::rc::Rc;
use syntax::ast;
use syntax::abi::Abi;
-use syntax::codemap::{CodeMap, DUMMY_SP};
-use syntax::errors;
-use syntax::errors::emitter::{CoreEmitter, Emitter};
-use syntax::errors::{Level, RenderSpan};
+use syntax::codemap::CodeMap;
+use errors;
+use errors::emitter::{CoreEmitter, Emitter};
+use errors::{Level, RenderSpan};
use syntax::parse::token;
use syntax::feature_gate::UnstableFeatures;
+use syntax_pos::DUMMY_SP;
use rustc::hir;
--- /dev/null
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_errors"
+version = "0.0.0"
+
+[lib]
+name = "rustc_errors"
+path = "lib.rs"
+crate-type = ["dylib"]
+
+[dependencies]
+log = { path = "../liblog" }
+serialize = { path = "../libserialize" }
+syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
--- /dev/null
+// Copyright 2012-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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use self::Destination::*;
+
+use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, Span, MultiSpan, LineInfo};
+use registry;
+
+use check_old_skool;
+use {Level, RenderSpan, CodeSuggestion, DiagnosticBuilder, CodeMapper};
+use RenderSpan::*;
+use Level::*;
+use snippet::{RenderedLineKind, SnippetData, Style, FormatMode};
+
+use std::{cmp, fmt};
+use std::io::prelude::*;
+use std::io;
+use std::rc::Rc;
+use term;
+
+/// Emitter trait for emitting errors. Do not implement this directly:
+/// implement `CoreEmitter` instead.
+pub trait Emitter {
+ /// Emit a standalone diagnostic message.
+ fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level);
+
+ /// Emit a structured diagnostic.
+ fn emit_struct(&mut self, db: &DiagnosticBuilder);
+}
+
+pub trait CoreEmitter {
+ fn emit_message(&mut self,
+ rsp: &RenderSpan,
+ msg: &str,
+ code: Option<&str>,
+ lvl: Level,
+ is_header: bool,
+ show_snippet: bool);
+}
+
+impl<T: CoreEmitter> Emitter for T {
+ fn emit(&mut self,
+ msp: &MultiSpan,
+ msg: &str,
+ code: Option<&str>,
+ lvl: Level) {
+ self.emit_message(&FullSpan(msp.clone()),
+ msg,
+ code,
+ lvl,
+ true,
+ true);
+ }
+
+ fn emit_struct(&mut self, db: &DiagnosticBuilder) {
+ let old_school = check_old_skool();
+ let db_span = FullSpan(db.span.clone());
+ self.emit_message(&FullSpan(db.span.clone()),
+ &db.message,
+ db.code.as_ref().map(|s| &**s),
+ db.level,
+ true,
+ true);
+ for child in &db.children {
+ let render_span = child.render_span
+ .clone()
+ .unwrap_or_else(
+ || FullSpan(child.span.clone()));
+
+ if !old_school {
+ self.emit_message(&render_span,
+ &child.message,
+ None,
+ child.level,
+ false,
+ true);
+ } else {
+ let (render_span, show_snippet) = match render_span.span().primary_span() {
+ None => (db_span.clone(), false),
+ _ => (render_span, true)
+ };
+ self.emit_message(&render_span,
+ &child.message,
+ None,
+ child.level,
+ false,
+ show_snippet);
+ }
+ }
+ }
+}
+
+/// maximum number of lines we will print for each error; arbitrary.
+pub const MAX_HIGHLIGHT_LINES: usize = 6;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ColorConfig {
+ Auto,
+ Always,
+ Never,
+}
+
+impl ColorConfig {
+ fn use_color(&self) -> bool {
+ match *self {
+ ColorConfig::Always => true,
+ ColorConfig::Never => false,
+ ColorConfig::Auto => stderr_isatty(),
+ }
+ }
+}
+
+/// A basic emitter for when we don't have access to a codemap or registry. Used
+/// for reporting very early errors, etc.
+pub struct BasicEmitter {
+ dst: Destination,
+}
+
+impl CoreEmitter for BasicEmitter {
+ fn emit_message(&mut self,
+ _rsp: &RenderSpan,
+ msg: &str,
+ code: Option<&str>,
+ lvl: Level,
+ _is_header: bool,
+ _show_snippet: bool) {
+ // we ignore the span as we have no access to a codemap at this point
+ if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) {
+ panic!("failed to print diagnostics: {:?}", e);
+ }
+ }
+}
+
+impl BasicEmitter {
+ pub fn stderr(color_config: ColorConfig) -> BasicEmitter {
+ if color_config.use_color() {
+ let dst = Destination::from_stderr();
+ BasicEmitter { dst: dst }
+ } else {
+ BasicEmitter { dst: Raw(Box::new(io::stderr())) }
+ }
+ }
+}
+
+pub struct EmitterWriter {
+ dst: Destination,
+ registry: Option<registry::Registry>,
+ cm: Rc<CodeMapper>,
+
+ /// Is this the first error emitted thus far? If not, we emit a
+ /// `\n` before the top-level errors.
+ first: bool,
+
+ // For now, allow an old-school mode while we transition
+ format_mode: FormatMode
+}
+
+impl CoreEmitter for EmitterWriter {
+ fn emit_message(&mut self,
+ rsp: &RenderSpan,
+ msg: &str,
+ code: Option<&str>,
+ lvl: Level,
+ is_header: bool,
+ show_snippet: bool) {
+ match self.emit_message_(rsp, msg, code, lvl, is_header, show_snippet) {
+ Ok(()) => { }
+ Err(e) => panic!("failed to emit error: {}", e)
+ }
+ }
+}
+
+/// Do not use this for messages that end in `\n` – use `println_maybe_styled` instead. See
+/// `EmitterWriter::print_maybe_styled` for details.
+macro_rules! print_maybe_styled {
+ ($dst: expr, $style: expr, $($arg: tt)*) => {
+ $dst.print_maybe_styled(format_args!($($arg)*), $style, false)
+ }
+}
+
+macro_rules! println_maybe_styled {
+ ($dst: expr, $style: expr, $($arg: tt)*) => {
+ $dst.print_maybe_styled(format_args!($($arg)*), $style, true)
+ }
+}
+
+impl EmitterWriter {
+ pub fn stderr(color_config: ColorConfig,
+ registry: Option<registry::Registry>,
+ code_map: Rc<CodeMapper>,
+ format_mode: FormatMode)
+ -> EmitterWriter {
+ if color_config.use_color() {
+ let dst = Destination::from_stderr();
+ EmitterWriter { dst: dst,
+ registry: registry,
+ cm: code_map,
+ first: true,
+ format_mode: format_mode.clone() }
+ } else {
+ EmitterWriter { dst: Raw(Box::new(io::stderr())),
+ registry: registry,
+ cm: code_map,
+ first: true,
+ format_mode: format_mode.clone() }
+ }
+ }
+
+ pub fn new(dst: Box<Write + Send>,
+ registry: Option<registry::Registry>,
+ code_map: Rc<CodeMapper>,
+ format_mode: FormatMode)
+ -> EmitterWriter {
+ EmitterWriter { dst: Raw(dst),
+ registry: registry,
+ cm: code_map,
+ first: true,
+ format_mode: format_mode.clone() }
+ }
+
+ fn emit_message_(&mut self,
+ rsp: &RenderSpan,
+ msg: &str,
+ code: Option<&str>,
+ lvl: Level,
+ is_header: bool,
+ show_snippet: bool)
+ -> io::Result<()> {
+ let old_school = match self.format_mode {
+ FormatMode::NewErrorFormat => false,
+ FormatMode::OriginalErrorFormat => true,
+ FormatMode::EnvironmentSelected => check_old_skool()
+ };
+
+ if is_header {
+ if self.first {
+ self.first = false;
+ } else {
+ if !old_school {
+ write!(self.dst, "\n")?;
+ }
+ }
+ }
+
+ match code {
+ Some(code) if self.registry.as_ref()
+ .and_then(|registry| registry.find_description(code))
+ .is_some() => {
+ let code_with_explain = String::from("--explain ") + code;
+ if old_school {
+ let loc = match rsp.span().primary_span() {
+ Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
+ Some(ps) => self.cm.span_to_string(ps),
+ None => "".to_string()
+ };
+ print_diagnostic(&mut self.dst, &loc, lvl, msg, Some(code))?
+ }
+ else {
+ print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))?
+ }
+ }
+ _ => {
+ if old_school {
+ let loc = match rsp.span().primary_span() {
+ Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
+ Some(ps) => self.cm.span_to_string(ps),
+ None => "".to_string()
+ };
+ print_diagnostic(&mut self.dst, &loc, lvl, msg, code)?
+ }
+ else {
+ print_diagnostic(&mut self.dst, "", lvl, msg, code)?
+ }
+ }
+ }
+
+ if !show_snippet {
+ return Ok(());
+ }
+
+ // Watch out for various nasty special spans; don't try to
+ // print any filename or anything for those.
+ match rsp.span().primary_span() {
+ Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => {
+ return Ok(());
+ }
+ _ => { }
+ }
+
+ // Otherwise, print out the snippet etc as needed.
+ match *rsp {
+ FullSpan(ref msp) => {
+ self.highlight_lines(msp, lvl)?;
+ if let Some(primary_span) = msp.primary_span() {
+ self.print_macro_backtrace(primary_span)?;
+ }
+ }
+ Suggestion(ref suggestion) => {
+ self.highlight_suggestion(suggestion)?;
+ if let Some(primary_span) = rsp.span().primary_span() {
+ self.print_macro_backtrace(primary_span)?;
+ }
+ }
+ }
+ if old_school {
+ match code {
+ Some(code) if self.registry.as_ref()
+ .and_then(|registry| registry.find_description(code))
+ .is_some() => {
+ let loc = match rsp.span().primary_span() {
+ Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
+ Some(ps) => self.cm.span_to_string(ps),
+ None => "".to_string()
+ };
+ let msg = "run `rustc --explain ".to_string() + &code.to_string() +
+ "` to see a detailed explanation";
+ print_diagnostic(&mut self.dst, &loc, Level::Help, &msg,
+ None)?
+ }
+ _ => ()
+ }
+ }
+ Ok(())
+ }
+
+ fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()>
+ {
+ use std::borrow::Borrow;
+
+ let primary_span = suggestion.msp.primary_span().unwrap();
+ let lines = self.cm.span_to_lines(primary_span).unwrap();
+ assert!(!lines.lines.is_empty());
+
+ let complete = suggestion.splice_lines(self.cm.borrow());
+ let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES);
+ let display_lines = &lines.lines[..line_count];
+
+ let fm = &*lines.file;
+ // Calculate the widest number to format evenly
+ let max_digits = line_num_max_digits(display_lines.last().unwrap());
+
+ // print the suggestion without any line numbers, but leave
+ // space for them. This helps with lining up with previous
+ // snippets from the actual error being reported.
+ let mut lines = complete.lines();
+ for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
+ write!(&mut self.dst, "{0}:{1:2$} {3}\n",
+ fm.name, "", max_digits, line)?;
+ }
+
+ // if we elided some lines, add an ellipsis
+ if let Some(_) = lines.next() {
+ write!(&mut self.dst, "{0:1$} {0:2$} ...\n",
+ "", fm.name.len(), max_digits)?;
+ }
+
+ Ok(())
+ }
+
+ pub fn highlight_lines(&mut self,
+ msp: &MultiSpan,
+ lvl: Level)
+ -> io::Result<()>
+ {
+ let old_school = match self.format_mode {
+ FormatMode::NewErrorFormat => false,
+ FormatMode::OriginalErrorFormat => true,
+ FormatMode::EnvironmentSelected => check_old_skool()
+ };
+
+ let mut snippet_data = SnippetData::new(self.cm.clone(),
+ msp.primary_span(),
+ self.format_mode.clone());
+ if old_school {
+ let mut output_vec = vec![];
+
+ for span_label in msp.span_labels() {
+ let mut snippet_data = SnippetData::new(self.cm.clone(),
+ Some(span_label.span),
+ self.format_mode.clone());
+
+ snippet_data.push(span_label.span,
+ span_label.is_primary,
+ span_label.label);
+ if span_label.is_primary {
+ output_vec.insert(0, snippet_data);
+ }
+ else {
+ output_vec.push(snippet_data);
+ }
+ }
+
+ for snippet_data in output_vec.iter() {
+ let rendered_lines = snippet_data.render_lines();
+ for rendered_line in &rendered_lines {
+ for styled_string in &rendered_line.text {
+ self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
+ write!(&mut self.dst, "{}", styled_string.text)?;
+ self.dst.reset_attrs()?;
+ }
+ write!(&mut self.dst, "\n")?;
+ }
+ }
+ }
+ else {
+ for span_label in msp.span_labels() {
+ snippet_data.push(span_label.span,
+ span_label.is_primary,
+ span_label.label);
+ }
+ let rendered_lines = snippet_data.render_lines();
+ for rendered_line in &rendered_lines {
+ for styled_string in &rendered_line.text {
+ self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
+ write!(&mut self.dst, "{}", styled_string.text)?;
+ self.dst.reset_attrs()?;
+ }
+ write!(&mut self.dst, "\n")?;
+ }
+ }
+ Ok(())
+ }
+
+ fn print_macro_backtrace(&mut self,
+ sp: Span)
+ -> io::Result<()> {
+ for trace in self.cm.macro_backtrace(sp) {
+ let mut diag_string =
+ format!("in this expansion of {}", trace.macro_decl_name);
+ if let Some(def_site_span) = trace.def_site_span {
+ diag_string.push_str(
+ &format!(" (defined in {})",
+ self.cm.span_to_filename(def_site_span)));
+ }
+ let snippet = self.cm.span_to_string(trace.call_site);
+ print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?;
+ }
+ Ok(())
+ }
+}
+
+fn line_num_max_digits(line: &LineInfo) -> usize {
+ let mut max_line_num = line.line_index + 1;
+ let mut digits = 0;
+ while max_line_num > 0 {
+ max_line_num /= 10;
+ digits += 1;
+ }
+ digits
+}
+
+fn print_diagnostic(dst: &mut Destination,
+ topic: &str,
+ lvl: Level,
+ msg: &str,
+ code: Option<&str>)
+ -> io::Result<()> {
+ if !topic.is_empty() {
+ let old_school = check_old_skool();
+ if !old_school {
+ write!(dst, "{}: ", topic)?;
+ }
+ else {
+ write!(dst, "{} ", topic)?;
+ }
+ dst.reset_attrs()?;
+ }
+ dst.start_attr(term::Attr::Bold)?;
+ dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
+ write!(dst, "{}", lvl.to_string())?;
+ dst.reset_attrs()?;
+ write!(dst, ": ")?;
+ dst.start_attr(term::Attr::Bold)?;
+ write!(dst, "{}", msg)?;
+
+ if let Some(code) = code {
+ let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
+ print_maybe_styled!(dst, style, " [{}]", code.clone())?;
+ }
+
+ dst.reset_attrs()?;
+ write!(dst, "\n")?;
+ Ok(())
+}
+
+#[cfg(unix)]
+fn stderr_isatty() -> bool {
+ use libc;
+ unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
+}
+#[cfg(windows)]
+fn stderr_isatty() -> bool {
+ type DWORD = u32;
+ type BOOL = i32;
+ type HANDLE = *mut u8;
+ const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
+ extern "system" {
+ fn GetStdHandle(which: DWORD) -> HANDLE;
+ fn GetConsoleMode(hConsoleHandle: HANDLE,
+ lpMode: *mut DWORD) -> BOOL;
+ }
+ unsafe {
+ let handle = GetStdHandle(STD_ERROR_HANDLE);
+ let mut out = 0;
+ GetConsoleMode(handle, &mut out) != 0
+ }
+}
+
+enum Destination {
+ Terminal(Box<term::StderrTerminal>),
+ Raw(Box<Write + Send>),
+}
+
+impl Destination {
+ fn from_stderr() -> Destination {
+ match term::stderr() {
+ Some(t) => Terminal(t),
+ None => Raw(Box::new(io::stderr())),
+ }
+ }
+
+ fn apply_style(&mut self,
+ lvl: Level,
+ _kind: &RenderedLineKind,
+ style: Style)
+ -> io::Result<()> {
+ match style {
+ Style::FileNameStyle |
+ Style::LineAndColumn => {
+ }
+ Style::LineNumber => {
+ self.start_attr(term::Attr::Bold)?;
+ self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
+ }
+ Style::Quotation => {
+ }
+ Style::OldSkoolNote => {
+ self.start_attr(term::Attr::Bold)?;
+ self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))?;
+ }
+ Style::OldSkoolNoteText => {
+ self.start_attr(term::Attr::Bold)?;
+ }
+ Style::UnderlinePrimary | Style::LabelPrimary => {
+ self.start_attr(term::Attr::Bold)?;
+ self.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
+ }
+ Style::UnderlineSecondary | Style::LabelSecondary => {
+ self.start_attr(term::Attr::Bold)?;
+ self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
+ }
+ Style::NoStyle => {
+ }
+ }
+ Ok(())
+ }
+
+ fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> {
+ match *self {
+ Terminal(ref mut t) => { t.attr(attr)?; }
+ Raw(_) => { }
+ }
+ Ok(())
+ }
+
+ fn reset_attrs(&mut self) -> io::Result<()> {
+ match *self {
+ Terminal(ref mut t) => { t.reset()?; }
+ Raw(_) => { }
+ }
+ Ok(())
+ }
+
+ fn print_maybe_styled(&mut self,
+ args: fmt::Arguments,
+ color: term::Attr,
+ print_newline_at_end: bool)
+ -> io::Result<()> {
+ match *self {
+ Terminal(ref mut t) => {
+ t.attr(color)?;
+ // If `msg` ends in a newline, we need to reset the color before
+ // the newline. We're making the assumption that we end up writing
+ // to a `LineBufferedWriter`, which means that emitting the reset
+ // after the newline ends up buffering the reset until we print
+ // another line or exit. Buffering the reset is a problem if we're
+ // sharing the terminal with any other programs (e.g. other rustc
+ // instances via `make -jN`).
+ //
+ // Note that if `msg` contains any internal newlines, this will
+ // result in the `LineBufferedWriter` flushing twice instead of
+ // once, which still leaves the opportunity for interleaved output
+ // to be miscolored. We assume this is rare enough that we don't
+ // have to worry about it.
+ t.write_fmt(args)?;
+ t.reset()?;
+ if print_newline_at_end {
+ t.write_all(b"\n")
+ } else {
+ Ok(())
+ }
+ }
+ Raw(ref mut w) => {
+ w.write_fmt(args)?;
+ if print_newline_at_end {
+ w.write_all(b"\n")
+ } else {
+ Ok(())
+ }
+ }
+ }
+ }
+}
+
+impl Write for Destination {
+ fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
+ match *self {
+ Terminal(ref mut t) => t.write(bytes),
+ Raw(ref mut w) => w.write(bytes),
+ }
+ }
+ fn flush(&mut self) -> io::Result<()> {
+ match *self {
+ Terminal(ref mut t) => t.flush(),
+ Raw(ref mut w) => w.flush(),
+ }
+ }
+}
--- /dev/null
+// Copyright 2012-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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "rustc_errors"]
+#![unstable(feature = "rustc_private", issue = "27812")]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+ html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
+
+#![feature(custom_attribute)]
+#![allow(unused_attributes)]
+#![feature(rustc_private)]
+#![feature(staged_api)]
+#![feature(question_mark)]
+#![feature(range_contains)]
+#![feature(libc)]
+#![feature(unicode)]
+
+extern crate serialize;
+extern crate term;
+#[macro_use] extern crate log;
+#[macro_use] extern crate libc;
+extern crate rustc_unicode;
+extern crate serialize as rustc_serialize; // used by deriving
+extern crate syntax_pos;
+
+pub use emitter::ColorConfig;
+
+use self::Level::*;
+use self::RenderSpan::*;
+
+use emitter::{Emitter, EmitterWriter};
+
+use std::cell::{RefCell, Cell};
+use std::{error, fmt};
+use std::rc::Rc;
+use std::thread::panicking;
+
+pub mod emitter;
+pub mod snippet;
+pub mod registry;
+
+use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION };
+use syntax_pos::{MacroBacktrace};
+
+#[derive(Clone)]
+pub enum RenderSpan {
+ /// A FullSpan renders with both with an initial line for the
+ /// message, prefixed by file:linenum, followed by a summary of
+ /// the source code covered by the span.
+ FullSpan(MultiSpan),
+
+ /// A suggestion renders with both with an initial line for the
+ /// message, prefixed by file:linenum, followed by a summary
+ /// of hypothetical source code, where each `String` is spliced
+ /// into the lines in place of the code covered by each span.
+ Suggestion(CodeSuggestion),
+}
+
+#[derive(Clone)]
+pub struct CodeSuggestion {
+ pub msp: MultiSpan,
+ pub substitutes: Vec<String>,
+}
+
+pub trait CodeMapper {
+ fn lookup_char_pos(&self, pos: BytePos) -> Loc;
+ fn span_to_lines(&self, sp: Span) -> FileLinesResult;
+ fn span_to_string(&self, sp: Span) -> String;
+ fn span_to_filename(&self, sp: Span) -> FileName;
+ fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
+}
+
+impl RenderSpan {
+ fn span(&self) -> &MultiSpan {
+ match *self {
+ FullSpan(ref msp) |
+ Suggestion(CodeSuggestion { ref msp, .. }) =>
+ msp
+ }
+ }
+}
+
+impl CodeSuggestion {
+ /// Returns the assembled code suggestion.
+ pub fn splice_lines(&self, cm: &CodeMapper) -> String {
+ use syntax_pos::{CharPos, Loc, Pos};
+
+ fn push_trailing(buf: &mut String, line_opt: Option<&str>,
+ lo: &Loc, hi_opt: Option<&Loc>) {
+ let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi|hi.col.to_usize()));
+ if let Some(line) = line_opt {
+ if line.len() > lo {
+ buf.push_str(match hi_opt {
+ Some(hi) => &line[lo..hi],
+ None => &line[lo..],
+ });
+ }
+ if let None = hi_opt {
+ buf.push('\n');
+ }
+ }
+ }
+
+ let mut primary_spans = self.msp.primary_spans().to_owned();
+
+ assert_eq!(primary_spans.len(), self.substitutes.len());
+ if primary_spans.is_empty() {
+ return format!("");
+ }
+
+ // Assumption: all spans are in the same file, and all spans
+ // are disjoint. Sort in ascending order.
+ primary_spans.sort_by_key(|sp| sp.lo);
+
+ // Find the bounding span.
+ let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap();
+ let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap();
+ let bounding_span = Span { lo: lo, hi: hi, expn_id: NO_EXPANSION };
+ let lines = cm.span_to_lines(bounding_span).unwrap();
+ assert!(!lines.lines.is_empty());
+
+ // To build up the result, we do this for each span:
+ // - push the line segment trailing the previous span
+ // (at the beginning a "phantom" span pointing at the start of the line)
+ // - push lines between the previous and current span (if any)
+ // - if the previous and current span are not on the same line
+ // push the line segment leading up to the current span
+ // - splice in the span substitution
+ //
+ // Finally push the trailing line segment of the last span
+ let fm = &lines.file;
+ let mut prev_hi = cm.lookup_char_pos(bounding_span.lo);
+ prev_hi.col = CharPos::from_usize(0);
+
+ let mut prev_line = fm.get_line(lines.lines[0].line_index);
+ let mut buf = String::new();
+
+ for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) {
+ let cur_lo = cm.lookup_char_pos(sp.lo);
+ if prev_hi.line == cur_lo.line {
+ push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo));
+ } else {
+ push_trailing(&mut buf, prev_line, &prev_hi, None);
+ // push lines between the previous and current span (if any)
+ for idx in prev_hi.line..(cur_lo.line - 1) {
+ if let Some(line) = fm.get_line(idx) {
+ buf.push_str(line);
+ buf.push('\n');
+ }
+ }
+ if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
+ buf.push_str(&cur_line[.. cur_lo.col.to_usize()]);
+ }
+ }
+ buf.push_str(substitute);
+ prev_hi = cm.lookup_char_pos(sp.hi);
+ prev_line = fm.get_line(prev_hi.line - 1);
+ }
+ push_trailing(&mut buf, prev_line, &prev_hi, None);
+ // remove trailing newline
+ buf.pop();
+ buf
+ }
+}
+
+/// Used as a return value to signify a fatal error occurred. (It is also
+/// used as the argument to panic at the moment, but that will eventually
+/// not be true.)
+#[derive(Copy, Clone, Debug)]
+#[must_use]
+pub struct FatalError;
+
+impl fmt::Display for FatalError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(f, "parser fatal error")
+ }
+}
+
+impl error::Error for FatalError {
+ fn description(&self) -> &str {
+ "The parser has encountered a fatal error"
+ }
+}
+
+/// Signifies that the compiler died with an explicit call to `.bug`
+/// or `.span_bug` rather than a failed assertion, etc.
+#[derive(Copy, Clone, Debug)]
+pub struct ExplicitBug;
+
+impl fmt::Display for ExplicitBug {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(f, "parser internal bug")
+ }
+}
+
+impl error::Error for ExplicitBug {
+ fn description(&self) -> &str {
+ "The parser has encountered an internal bug"
+ }
+}
+
+/// Used for emitting structured error messages and other diagnostic information.
+#[must_use]
+#[derive(Clone)]
+pub struct DiagnosticBuilder<'a> {
+ handler: &'a Handler,
+ pub level: Level,
+ pub message: String,
+ pub code: Option<String>,
+ pub span: MultiSpan,
+ pub children: Vec<SubDiagnostic>,
+}
+
+/// For example a note attached to an error.
+#[derive(Clone)]
+pub struct SubDiagnostic {
+ pub level: Level,
+ pub message: String,
+ pub span: MultiSpan,
+ pub render_span: Option<RenderSpan>,
+}
+
+impl<'a> DiagnosticBuilder<'a> {
+ /// Emit the diagnostic.
+ pub fn emit(&mut self) {
+ if self.cancelled() {
+ return;
+ }
+
+ self.handler.emit.borrow_mut().emit_struct(&self);
+ self.cancel();
+ self.handler.panic_if_treat_err_as_bug();
+
+ // if self.is_fatal() {
+ // panic!(FatalError);
+ // }
+ }
+
+ /// Cancel the diagnostic (a structured diagnostic must either be emitted or
+ /// cancelled or it will panic when dropped).
+ /// BEWARE: if this DiagnosticBuilder is an error, then creating it will
+ /// bump the error count on the Handler and cancelling it won't undo that.
+ /// If you want to decrement the error count you should use `Handler::cancel`.
+ pub fn cancel(&mut self) {
+ self.level = Level::Cancelled;
+ }
+
+ pub fn cancelled(&self) -> bool {
+ self.level == Level::Cancelled
+ }
+
+ pub fn is_fatal(&self) -> bool {
+ self.level == Level::Fatal
+ }
+
+ /// Add a span/label to be included in the resulting snippet.
+ /// This is pushed onto the `MultiSpan` that was created when the
+ /// diagnostic was first built. If you don't call this function at
+ /// all, and you just supplied a `Span` to create the diagnostic,
+ /// then the snippet will just include that `Span`, which is
+ /// called the primary span.
+ pub fn span_label(&mut self, span: Span, label: &fmt::Display)
+ -> &mut DiagnosticBuilder<'a> {
+ self.span.push_span_label(span, format!("{}", label));
+ self
+ }
+
+ pub fn note_expected_found(&mut self,
+ label: &fmt::Display,
+ expected: &fmt::Display,
+ found: &fmt::Display)
+ -> &mut DiagnosticBuilder<'a>
+ {
+ // For now, just attach these as notes
+ self.note(&format!("expected {} `{}`", label, expected));
+ self.note(&format!(" found {} `{}`", label, found));
+ self
+ }
+
+ pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
+ self.sub(Level::Note, msg, MultiSpan::new(), None);
+ self
+ }
+ pub fn span_note<S: Into<MultiSpan>>(&mut self,
+ sp: S,
+ msg: &str)
+ -> &mut DiagnosticBuilder<'a> {
+ self.sub(Level::Note, msg, sp.into(), None);
+ self
+ }
+ pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
+ self.sub(Level::Warning, msg, MultiSpan::new(), None);
+ self
+ }
+ pub fn span_warn<S: Into<MultiSpan>>(&mut self,
+ sp: S,
+ msg: &str)
+ -> &mut DiagnosticBuilder<'a> {
+ self.sub(Level::Warning, msg, sp.into(), None);
+ self
+ }
+ pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> {
+ self.sub(Level::Help, msg, MultiSpan::new(), None);
+ self
+ }
+ pub fn span_help<S: Into<MultiSpan>>(&mut self,
+ sp: S,
+ msg: &str)
+ -> &mut DiagnosticBuilder<'a> {
+ self.sub(Level::Help, msg, sp.into(), None);
+ self
+ }
+ /// Prints out a message with a suggested edit of the code.
+ ///
+ /// See `diagnostic::RenderSpan::Suggestion` for more information.
+ pub fn span_suggestion<S: Into<MultiSpan>>(&mut self,
+ sp: S,
+ msg: &str,
+ suggestion: String)
+ -> &mut DiagnosticBuilder<'a> {
+ self.sub(Level::Help, msg, MultiSpan::new(), Some(Suggestion(CodeSuggestion {
+ msp: sp.into(),
+ substitutes: vec![suggestion],
+ })));
+ self
+ }
+
+ pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
+ self.span = sp.into();
+ self
+ }
+
+ pub fn code(&mut self, s: String) -> &mut Self {
+ self.code = Some(s);
+ self
+ }
+
+ pub fn message(&self) -> &str {
+ &self.message
+ }
+
+ pub fn level(&self) -> Level {
+ self.level
+ }
+
+ /// Convenience function for internal use, clients should use one of the
+ /// struct_* methods on Handler.
+ fn new(handler: &'a Handler,
+ level: Level,
+ message: &str) -> DiagnosticBuilder<'a> {
+ DiagnosticBuilder {
+ handler: handler,
+ level: level,
+ message: message.to_owned(),
+ code: None,
+ span: MultiSpan::new(),
+ children: vec![],
+ }
+ }
+
+ /// Convenience function for internal use, clients should use one of the
+ /// public methods above.
+ fn sub(&mut self,
+ level: Level,
+ message: &str,
+ span: MultiSpan,
+ render_span: Option<RenderSpan>) {
+ let sub = SubDiagnostic {
+ level: level,
+ message: message.to_owned(),
+ span: span,
+ render_span: render_span,
+ };
+ self.children.push(sub);
+ }
+}
+
+impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.message.fmt(f)
+ }
+}
+
+/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or
+/// we emit a bug.
+impl<'a> Drop for DiagnosticBuilder<'a> {
+ fn drop(&mut self) {
+ if !panicking() && !self.cancelled() {
+ self.handler.emit.borrow_mut().emit(&MultiSpan::new(),
+ "Error constructed but not emitted",
+ None,
+ Bug);
+ panic!();
+ }
+ }
+}
+
+/// A handler deals with errors; certain errors
+/// (fatal, bug, unimpl) may cause immediate exit,
+/// others log errors for later reporting.
+pub struct Handler {
+ err_count: Cell<usize>,
+ emit: RefCell<Box<Emitter>>,
+ pub can_emit_warnings: bool,
+ treat_err_as_bug: bool,
+ continue_after_error: Cell<bool>,
+ delayed_span_bug: RefCell<Option<(MultiSpan, String)>>,
+}
+
+impl Handler {
+ pub fn with_tty_emitter(color_config: ColorConfig,
+ registry: Option<registry::Registry>,
+ can_emit_warnings: bool,
+ treat_err_as_bug: bool,
+ cm: Rc<CodeMapper>)
+ -> Handler {
+ let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm,
+ snippet::FormatMode::EnvironmentSelected));
+ Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter)
+ }
+
+ pub fn with_emitter(can_emit_warnings: bool,
+ treat_err_as_bug: bool,
+ e: Box<Emitter>) -> Handler {
+ Handler {
+ err_count: Cell::new(0),
+ emit: RefCell::new(e),
+ can_emit_warnings: can_emit_warnings,
+ treat_err_as_bug: treat_err_as_bug,
+ continue_after_error: Cell::new(true),
+ delayed_span_bug: RefCell::new(None),
+ }
+ }
+
+ pub fn set_continue_after_error(&self, continue_after_error: bool) {
+ self.continue_after_error.set(continue_after_error);
+ }
+
+ pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
+ DiagnosticBuilder::new(self, Level::Cancelled, "")
+ }
+
+ pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
+ sp: S,
+ msg: &str)
+ -> DiagnosticBuilder<'a> {
+ let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
+ result.set_span(sp);
+ if !self.can_emit_warnings {
+ result.cancel();
+ }
+ result
+ }
+ pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
+ sp: S,
+ msg: &str,
+ code: &str)
+ -> DiagnosticBuilder<'a> {
+ let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
+ result.set_span(sp);
+ result.code(code.to_owned());
+ if !self.can_emit_warnings {
+ result.cancel();
+ }
+ result
+ }
+ pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
+ let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
+ if !self.can_emit_warnings {
+ result.cancel();
+ }
+ result
+ }
+ pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
+ sp: S,
+ msg: &str)
+ -> DiagnosticBuilder<'a> {
+ self.bump_err_count();
+ let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
+ result.set_span(sp);
+ result
+ }
+ pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
+ sp: S,
+ msg: &str,
+ code: &str)
+ -> DiagnosticBuilder<'a> {
+ self.bump_err_count();
+ let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
+ result.set_span(sp);
+ result.code(code.to_owned());
+ result
+ }
+ pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
+ self.bump_err_count();
+ DiagnosticBuilder::new(self, Level::Error, msg)
+ }
+ pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
+ sp: S,
+ msg: &str)
+ -> DiagnosticBuilder<'a> {
+ self.bump_err_count();
+ let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
+ result.set_span(sp);
+ result
+ }
+ pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
+ sp: S,
+ msg: &str,
+ code: &str)
+ -> DiagnosticBuilder<'a> {
+ self.bump_err_count();
+ let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
+ result.set_span(sp);
+ result.code(code.to_owned());
+ result
+ }
+ pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
+ self.bump_err_count();
+ DiagnosticBuilder::new(self, Level::Fatal, msg)
+ }
+
+ pub fn cancel(&mut self, err: &mut DiagnosticBuilder) {
+ if err.level == Level::Error || err.level == Level::Fatal {
+ assert!(self.has_errors());
+ self.err_count.set(self.err_count.get() + 1);
+ }
+ err.cancel();
+ }
+
+ fn panic_if_treat_err_as_bug(&self) {
+ if self.treat_err_as_bug {
+ panic!("encountered error with `-Z treat_err_as_bug");
+ }
+ }
+
+ pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str)
+ -> FatalError {
+ self.emit(&sp.into(), msg, Fatal);
+ self.bump_err_count();
+ self.panic_if_treat_err_as_bug();
+ return FatalError;
+ }
+ pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str)
+ -> FatalError {
+ self.emit_with_code(&sp.into(), msg, code, Fatal);
+ self.bump_err_count();
+ self.panic_if_treat_err_as_bug();
+ return FatalError;
+ }
+ pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
+ self.emit(&sp.into(), msg, Error);
+ self.bump_err_count();
+ self.panic_if_treat_err_as_bug();
+ }
+ pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
+ self.emit_with_code(&sp.into(), msg, code, Error);
+ self.bump_err_count();
+ self.panic_if_treat_err_as_bug();
+ }
+ pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
+ self.emit(&sp.into(), msg, Warning);
+ }
+ pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
+ self.emit_with_code(&sp.into(), msg, code, Warning);
+ }
+ pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
+ self.emit(&sp.into(), msg, Bug);
+ panic!(ExplicitBug);
+ }
+ pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
+ let mut delayed = self.delayed_span_bug.borrow_mut();
+ *delayed = Some((sp.into(), msg.to_string()));
+ }
+ pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
+ self.emit(&sp.into(), msg, Bug);
+ self.bump_err_count();
+ }
+ pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
+ self.emit.borrow_mut().emit(&sp.into(), msg, None, Note);
+ }
+ pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
+ self.span_bug(sp, &format!("unimplemented {}", msg));
+ }
+ pub fn fatal(&self, msg: &str) -> FatalError {
+ if self.treat_err_as_bug {
+ self.bug(msg);
+ }
+ self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Fatal);
+ self.bump_err_count();
+ FatalError
+ }
+ pub fn err(&self, msg: &str) {
+ if self.treat_err_as_bug {
+ self.bug(msg);
+ }
+ self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Error);
+ self.bump_err_count();
+ }
+ pub fn warn(&self, msg: &str) {
+ self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Warning);
+ }
+ pub fn note_without_error(&self, msg: &str) {
+ self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Note);
+ }
+ pub fn bug(&self, msg: &str) -> ! {
+ self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Bug);
+ panic!(ExplicitBug);
+ }
+ pub fn unimpl(&self, msg: &str) -> ! {
+ self.bug(&format!("unimplemented {}", msg));
+ }
+
+ pub fn bump_err_count(&self) {
+ self.err_count.set(self.err_count.get() + 1);
+ }
+
+ pub fn err_count(&self) -> usize {
+ self.err_count.get()
+ }
+
+ pub fn has_errors(&self) -> bool {
+ self.err_count.get() > 0
+ }
+ pub fn abort_if_errors(&self) {
+ let s;
+ match self.err_count.get() {
+ 0 => {
+ let delayed_bug = self.delayed_span_bug.borrow();
+ match *delayed_bug {
+ Some((ref span, ref errmsg)) => {
+ self.span_bug(span.clone(), errmsg);
+ },
+ _ => {}
+ }
+
+ return;
+ }
+ 1 => s = "aborting due to previous error".to_string(),
+ _ => {
+ s = format!("aborting due to {} previous errors",
+ self.err_count.get());
+ }
+ }
+
+ panic!(self.fatal(&s));
+ }
+ pub fn emit(&self,
+ msp: &MultiSpan,
+ msg: &str,
+ lvl: Level) {
+ if lvl == Warning && !self.can_emit_warnings { return }
+ self.emit.borrow_mut().emit(&msp, msg, None, lvl);
+ if !self.continue_after_error.get() { self.abort_if_errors(); }
+ }
+ pub fn emit_with_code(&self,
+ msp: &MultiSpan,
+ msg: &str,
+ code: &str,
+ lvl: Level) {
+ if lvl == Warning && !self.can_emit_warnings { return }
+ self.emit.borrow_mut().emit(&msp, msg, Some(code), lvl);
+ if !self.continue_after_error.get() { self.abort_if_errors(); }
+ }
+}
+
+
+#[derive(Copy, PartialEq, Clone, Debug)]
+pub enum Level {
+ Bug,
+ Fatal,
+ // An error which while not immediately fatal, should stop the compiler
+ // progressing beyond the current phase.
+ PhaseFatal,
+ Error,
+ Warning,
+ Note,
+ Help,
+ Cancelled,
+}
+
+impl fmt::Display for Level {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.to_str().fmt(f)
+ }
+}
+
+impl Level {
+ pub fn color(self) -> term::color::Color {
+ match self {
+ Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED,
+ Warning => term::color::YELLOW,
+ Note => term::color::BRIGHT_GREEN,
+ Help => term::color::BRIGHT_CYAN,
+ Cancelled => unreachable!(),
+ }
+ }
+
+ pub fn to_str(self) -> &'static str {
+ match self {
+ Bug => "error: internal compiler error",
+ Fatal | PhaseFatal | Error => "error",
+ Warning => "warning",
+ Note => "note",
+ Help => "help",
+ Cancelled => panic!("Shouldn't call on cancelled error"),
+ }
+ }
+}
+
+pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T where
+ M: FnOnce() -> String,
+{
+ match opt {
+ Some(t) => t,
+ None => diag.bug(&msg()),
+ }
+}
+
+/// True if we should use the old-skool error format style. This is
+/// the default setting until the new errors are deemed stable enough
+/// for general use.
+///
+/// FIXME(#33240)
+#[cfg(not(test))]
+pub fn check_old_skool() -> bool {
+ use std::env;
+ env::var("RUST_NEW_ERROR_FORMAT").is_err()
+}
+
+/// For unit tests, use the new format.
+#[cfg(test)]
+pub fn check_old_skool() -> bool {
+ false
+}
--- /dev/null
+// Copyright 2014 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::HashMap;
+
+#[derive(Clone)]
+pub struct Registry {
+ descriptions: HashMap<&'static str, &'static str>
+}
+
+impl Registry {
+ pub fn new(descriptions: &[(&'static str, &'static str)]) -> Registry {
+ Registry { descriptions: descriptions.iter().cloned().collect() }
+ }
+
+ pub fn find_description(&self, code: &str) -> Option<&'static str> {
+ self.descriptions.get(code).cloned()
+ }
+}
--- /dev/null
+// Copyright 2012-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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Code for annotating snippets.
+
+use syntax_pos::{Span, FileMap, CharPos, LineInfo};
+use check_old_skool;
+use CodeMapper;
+use std::cmp;
+use std::rc::Rc;
+use std::mem;
+
+#[derive(Clone)]
+pub enum FormatMode {
+ NewErrorFormat,
+ OriginalErrorFormat,
+ EnvironmentSelected
+}
+
+#[derive(Clone)]
+pub struct SnippetData {
+ codemap: Rc<CodeMapper>,
+ files: Vec<FileInfo>,
+ format_mode: FormatMode,
+}
+
+#[derive(Clone)]
+pub struct FileInfo {
+ file: Rc<FileMap>,
+
+ /// The "primary file", if any, gets a `-->` marker instead of
+ /// `>>>`, and has a line-number/column printed and not just a
+ /// filename. It appears first in the listing. It is known to
+ /// contain at least one primary span, though primary spans (which
+ /// are designated with `^^^`) may also occur in other files.
+ primary_span: Option<Span>,
+
+ lines: Vec<Line>,
+
+ /// The type of error format to render. We keep it here so that
+ /// it's easy to configure for both tests and regular usage
+ format_mode: FormatMode,
+}
+
+#[derive(Clone, Debug)]
+struct Line {
+ line_index: usize,
+ annotations: Vec<Annotation>,
+}
+
+#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
+struct Annotation {
+ /// Start column, 0-based indexing -- counting *characters*, not
+ /// utf-8 bytes. Note that it is important that this field goes
+ /// first, so that when we sort, we sort orderings by start
+ /// column.
+ start_col: usize,
+
+ /// End column within the line (exclusive)
+ end_col: usize,
+
+ /// Is this annotation derived from primary span
+ is_primary: bool,
+
+ /// Is this a large span minimized down to a smaller span
+ is_minimized: bool,
+
+ /// Optional label to display adjacent to the annotation.
+ label: Option<String>,
+}
+
+#[derive(Debug)]
+pub struct RenderedLine {
+ pub text: Vec<StyledString>,
+ pub kind: RenderedLineKind,
+}
+
+#[derive(Debug)]
+pub struct StyledString {
+ pub text: String,
+ pub style: Style,
+}
+
+#[derive(Debug)]
+pub struct StyledBuffer {
+ text: Vec<Vec<char>>,
+ styles: Vec<Vec<Style>>
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum Style {
+ FileNameStyle,
+ LineAndColumn,
+ LineNumber,
+ Quotation,
+ UnderlinePrimary,
+ UnderlineSecondary,
+ LabelPrimary,
+ LabelSecondary,
+ OldSkoolNoteText,
+ OldSkoolNote,
+ NoStyle,
+}
+
+#[derive(Debug, Clone)]
+pub enum RenderedLineKind {
+ PrimaryFileName,
+ OtherFileName,
+ SourceText {
+ file: Rc<FileMap>,
+ line_index: usize,
+ },
+ Annotations,
+ Elision,
+}
+
+impl SnippetData {
+ pub fn new(codemap: Rc<CodeMapper>,
+ primary_span: Option<Span>,
+ format_mode: FormatMode) // (*)
+ -> Self {
+ // (*) The primary span indicates the file that must appear
+ // first, and which will have a line number etc in its
+ // name. Outside of tests, this is always `Some`, but for many
+ // tests it's not relevant to test this portion of the logic,
+ // and it's tedious to pick a primary span (read: tedious to
+ // port older tests that predate the existence of a primary
+ // span).
+
+ debug!("SnippetData::new(primary_span={:?})", primary_span);
+
+ let mut data = SnippetData {
+ codemap: codemap.clone(),
+ files: vec![],
+ format_mode: format_mode.clone()
+ };
+ if let Some(primary_span) = primary_span {
+ let lo = codemap.lookup_char_pos(primary_span.lo);
+ data.files.push(
+ FileInfo {
+ file: lo.file,
+ primary_span: Some(primary_span),
+ lines: vec![],
+ format_mode: format_mode.clone(),
+ });
+ }
+ data
+ }
+
+ pub fn push(&mut self, span: Span, is_primary: bool, label: Option<String>) {
+ debug!("SnippetData::push(span={:?}, is_primary={}, label={:?})",
+ span, is_primary, label);
+
+ let file_lines = match self.codemap.span_to_lines(span) {
+ Ok(file_lines) => file_lines,
+ Err(_) => {
+ // ignore unprintable spans completely.
+ return;
+ }
+ };
+
+ self.file(&file_lines.file)
+ .push_lines(&file_lines.lines, is_primary, label);
+ }
+
+ fn file(&mut self, file_map: &Rc<FileMap>) -> &mut FileInfo {
+ let index = self.files.iter().position(|f| f.file.name == file_map.name);
+ if let Some(index) = index {
+ return &mut self.files[index];
+ }
+
+ self.files.push(
+ FileInfo {
+ file: file_map.clone(),
+ lines: vec![],
+ primary_span: None,
+ format_mode: self.format_mode.clone()
+ });
+ self.files.last_mut().unwrap()
+ }
+
+ pub fn render_lines(&self) -> Vec<RenderedLine> {
+ debug!("SnippetData::render_lines()");
+
+ let mut rendered_lines: Vec<_> =
+ self.files.iter()
+ .flat_map(|f| f.render_file_lines(&self.codemap))
+ .collect();
+ prepend_prefixes(&mut rendered_lines, &self.format_mode);
+ trim_lines(&mut rendered_lines);
+ rendered_lines
+ }
+}
+
+pub trait StringSource {
+ fn make_string(self) -> String;
+}
+
+impl StringSource for String {
+ fn make_string(self) -> String {
+ self
+ }
+}
+
+impl StringSource for Vec<char> {
+ fn make_string(self) -> String {
+ self.into_iter().collect()
+ }
+}
+
+impl<S> From<(S, Style, RenderedLineKind)> for RenderedLine
+ where S: StringSource
+{
+ fn from((text, style, kind): (S, Style, RenderedLineKind)) -> Self {
+ RenderedLine {
+ text: vec![StyledString {
+ text: text.make_string(),
+ style: style,
+ }],
+ kind: kind,
+ }
+ }
+}
+
+impl<S1,S2> From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine
+ where S1: StringSource, S2: StringSource
+{
+ fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) -> Self {
+ let (text1, style1, text2, style2, kind) = tuple;
+ RenderedLine {
+ text: vec![
+ StyledString {
+ text: text1.make_string(),
+ style: style1,
+ },
+ StyledString {
+ text: text2.make_string(),
+ style: style2,
+ }
+ ],
+ kind: kind,
+ }
+ }
+}
+
+impl RenderedLine {
+ fn trim_last(&mut self) {
+ if let Some(last_text) = self.text.last_mut() {
+ let len = last_text.text.trim_right().len();
+ last_text.text.truncate(len);
+ }
+ }
+}
+
+impl RenderedLineKind {
+ fn prefix(&self) -> StyledString {
+ match *self {
+ RenderedLineKind::SourceText { file: _, line_index } =>
+ StyledString {
+ text: format!("{}", line_index + 1),
+ style: Style::LineNumber,
+ },
+ RenderedLineKind::Elision =>
+ StyledString {
+ text: String::from("..."),
+ style: Style::LineNumber,
+ },
+ RenderedLineKind::PrimaryFileName |
+ RenderedLineKind::OtherFileName |
+ RenderedLineKind::Annotations =>
+ StyledString {
+ text: String::from(""),
+ style: Style::LineNumber,
+ },
+ }
+ }
+}
+
+impl StyledBuffer {
+ fn new() -> StyledBuffer {
+ StyledBuffer { text: vec![], styles: vec![] }
+ }
+
+ fn render(&self, source_kind: RenderedLineKind) -> Vec<RenderedLine> {
+ let mut output: Vec<RenderedLine> = vec![];
+ let mut styled_vec: Vec<StyledString> = vec![];
+
+ for (row, row_style) in self.text.iter().zip(&self.styles) {
+ let mut current_style = Style::NoStyle;
+ let mut current_text = String::new();
+
+ for (&c, &s) in row.iter().zip(row_style) {
+ if s != current_style {
+ if !current_text.is_empty() {
+ styled_vec.push(StyledString { text: current_text, style: current_style });
+ }
+ current_style = s;
+ current_text = String::new();
+ }
+ current_text.push(c);
+ }
+ if !current_text.is_empty() {
+ styled_vec.push(StyledString { text: current_text, style: current_style });
+ }
+
+ if output.is_empty() {
+ //We know our first output line is source and the rest are highlights and labels
+ output.push(RenderedLine { text: styled_vec, kind: source_kind.clone() });
+ } else {
+ output.push(RenderedLine { text: styled_vec, kind: RenderedLineKind::Annotations });
+ }
+ styled_vec = vec![];
+ }
+
+ output
+ }
+
+ fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
+ while line >= self.text.len() {
+ self.text.push(vec![]);
+ self.styles.push(vec![]);
+ }
+
+ if col < self.text[line].len() {
+ self.text[line][col] = chr;
+ self.styles[line][col] = style;
+ } else {
+ let mut i = self.text[line].len();
+ while i < col {
+ let s = match self.text[0].get(i) {
+ Some(&'\t') => '\t',
+ _ => ' '
+ };
+ self.text[line].push(s);
+ self.styles[line].push(Style::NoStyle);
+ i += 1;
+ }
+ self.text[line].push(chr);
+ self.styles[line].push(style);
+ }
+ }
+
+ fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
+ let mut n = col;
+ for c in string.chars() {
+ self.putc(line, n, c, style);
+ n += 1;
+ }
+ }
+
+ fn set_style(&mut self, line: usize, col: usize, style: Style) {
+ if self.styles.len() > line && self.styles[line].len() > col {
+ self.styles[line][col] = style;
+ }
+ }
+
+ fn append(&mut self, line: usize, string: &str, style: Style) {
+ if line >= self.text.len() {
+ self.puts(line, 0, string, style);
+ } else {
+ let col = self.text[line].len();
+ self.puts(line, col, string, style);
+ }
+ }
+}
+
+impl FileInfo {
+ fn push_lines(&mut self,
+ lines: &[LineInfo],
+ is_primary: bool,
+ label: Option<String>) {
+ assert!(lines.len() > 0);
+
+ // If a span covers multiple lines, we reduce it to a single
+ // point at the start of the span. This means that instead
+ // of producing output like this:
+ //
+ // ```
+ // --> foo.rs:2:1
+ // 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>)
+ // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // 3 |> -> Set<LR0Item<'grammar>>
+ // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // (and so on)
+ // ```
+ //
+ // we produce:
+ //
+ // ```
+ // --> foo.rs:2:1
+ // 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>)
+ // ^
+ // ```
+ //
+ // Basically, although this loses information, multi-line spans just
+ // never look good.
+
+ let (line, start_col, mut end_col, is_minimized) = if lines.len() == 1 {
+ (lines[0].line_index, lines[0].start_col, lines[0].end_col, false)
+ } else {
+ (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1), true)
+ };
+
+ // Watch out for "empty spans". If we get a span like 6..6, we
+ // want to just display a `^` at 6, so convert that to
+ // 6..7. This is degenerate input, but it's best to degrade
+ // gracefully -- and the parser likes to suply a span like
+ // that for EOF, in particular.
+ if start_col == end_col {
+ end_col.0 += 1;
+ }
+
+ let index = self.ensure_source_line(line);
+ self.lines[index].push_annotation(start_col,
+ end_col,
+ is_primary,
+ is_minimized,
+ label);
+ }
+
+ /// Ensure that we have a `Line` struct corresponding to
+ /// `line_index` in the file. If we already have some other lines,
+ /// then this will add the intervening lines to ensure that we
+ /// have a complete snippet. (Note that when we finally display,
+ /// some of those lines may be elided.)
+ fn ensure_source_line(&mut self, line_index: usize) -> usize {
+ if self.lines.is_empty() {
+ self.lines.push(Line::new(line_index));
+ return 0;
+ }
+
+ // Find the range of lines we have thus far.
+ let first_line_index = self.lines.first().unwrap().line_index;
+ let last_line_index = self.lines.last().unwrap().line_index;
+ assert!(first_line_index <= last_line_index);
+
+ // If the new line is lower than all the lines we have thus
+ // far, then insert the new line and any intervening lines at
+ // the front. In a silly attempt at micro-optimization, we
+ // don't just call `insert` repeatedly, but instead make a new
+ // (empty) vector, pushing the new lines onto it, and then
+ // appending the old vector.
+ if line_index < first_line_index {
+ let lines = mem::replace(&mut self.lines, vec![]);
+ self.lines.extend(
+ (line_index .. first_line_index)
+ .map(|line| Line::new(line))
+ .chain(lines));
+ return 0;
+ }
+
+ // If the new line comes after the ones we have so far, insert
+ // lines for it.
+ if line_index > last_line_index {
+ self.lines.extend(
+ (last_line_index+1 .. line_index+1)
+ .map(|line| Line::new(line)));
+ return self.lines.len() - 1;
+ }
+
+ // Otherwise it should already exist.
+ return line_index - first_line_index;
+ }
+
+ fn render_file_lines(&self, codemap: &Rc<CodeMapper>) -> Vec<RenderedLine> {
+ let old_school = match self.format_mode {
+ FormatMode::OriginalErrorFormat => true,
+ FormatMode::NewErrorFormat => false,
+ FormatMode::EnvironmentSelected => check_old_skool()
+ };
+
+ // As a first step, we elide any instance of more than one
+ // continuous unannotated line.
+
+ let mut lines_iter = self.lines.iter();
+ let mut output = vec![];
+
+ // First insert the name of the file.
+ if !old_school {
+ match self.primary_span {
+ Some(span) => {
+ let lo = codemap.lookup_char_pos(span.lo);
+ output.push(RenderedLine {
+ text: vec![StyledString {
+ text: lo.file.name.clone(),
+ style: Style::FileNameStyle,
+ }, StyledString {
+ text: format!(":{}:{}", lo.line, lo.col.0 + 1),
+ style: Style::LineAndColumn,
+ }],
+ kind: RenderedLineKind::PrimaryFileName,
+ });
+ output.push(RenderedLine {
+ text: vec![StyledString {
+ text: "".to_string(),
+ style: Style::FileNameStyle,
+ }],
+ kind: RenderedLineKind::Annotations,
+ });
+ }
+ None => {
+ output.push(RenderedLine {
+ text: vec![StyledString {
+ text: self.file.name.clone(),
+ style: Style::FileNameStyle,
+ }],
+ kind: RenderedLineKind::OtherFileName,
+ });
+ output.push(RenderedLine {
+ text: vec![StyledString {
+ text: "".to_string(),
+ style: Style::FileNameStyle,
+ }],
+ kind: RenderedLineKind::Annotations,
+ });
+ }
+ }
+ }
+
+ let mut next_line = lines_iter.next();
+ while next_line.is_some() {
+ // Consume lines with annotations.
+ while let Some(line) = next_line {
+ if line.annotations.is_empty() { break; }
+
+ let mut rendered_lines = self.render_line(line);
+ assert!(!rendered_lines.is_empty());
+ if old_school {
+ match self.primary_span {
+ Some(span) => {
+ let lo = codemap.lookup_char_pos(span.lo);
+ let hi = codemap.lookup_char_pos(span.hi);
+ //Before each secondary line in old skool-mode, print the label
+ //as an old-style note
+ if !line.annotations[0].is_primary {
+ if let Some(ann) = line.annotations[0].label.clone() {
+ output.push(RenderedLine {
+ text: vec![StyledString {
+ text: lo.file.name.clone(),
+ style: Style::FileNameStyle,
+ }, StyledString {
+ text: format!(":{}:{}: {}:{} ", lo.line, lo.col.0 + 1,
+ hi.line, hi.col.0+1),
+ style: Style::LineAndColumn,
+ }, StyledString {
+ text: format!("note: "),
+ style: Style::OldSkoolNote,
+ }, StyledString {
+ text: format!("{}", ann),
+ style: Style::OldSkoolNoteText,
+ }],
+ kind: RenderedLineKind::Annotations,
+ });
+ }
+ }
+ rendered_lines[0].text.insert(0, StyledString {
+ text: format!(":{} ", lo.line),
+ style: Style::LineAndColumn,
+ });
+ rendered_lines[0].text.insert(0, StyledString {
+ text: lo.file.name.clone(),
+ style: Style::FileNameStyle,
+ });
+ let gap_amount =
+ rendered_lines[0].text[0].text.len() +
+ rendered_lines[0].text[1].text.len();
+ assert!(rendered_lines.len() >= 2,
+ "no annotations resulted from: {:?}",
+ line);
+ for i in 1..rendered_lines.len() {
+ rendered_lines[i].text.insert(0, StyledString {
+ text: vec![" "; gap_amount].join(""),
+ style: Style::NoStyle
+ });
+ }
+ }
+ _ =>()
+ }
+ }
+ output.append(&mut rendered_lines);
+ next_line = lines_iter.next();
+ }
+
+ // Emit lines without annotations, but only if they are
+ // followed by a line with an annotation.
+ let unannotated_line = next_line;
+ let mut unannotated_lines = 0;
+ while let Some(line) = next_line {
+ if !line.annotations.is_empty() { break; }
+ unannotated_lines += 1;
+ next_line = lines_iter.next();
+ }
+ if unannotated_lines > 1 {
+ output.push(RenderedLine::from((String::new(),
+ Style::NoStyle,
+ RenderedLineKind::Elision)));
+ } else if let Some(line) = unannotated_line {
+ output.append(&mut self.render_line(line));
+ }
+ }
+
+ output
+ }
+
+ fn render_line(&self, line: &Line) -> Vec<RenderedLine> {
+ let old_school = match self.format_mode {
+ FormatMode::OriginalErrorFormat => true,
+ FormatMode::NewErrorFormat => false,
+ FormatMode::EnvironmentSelected => check_old_skool()
+ };
+
+ let source_string = self.file.get_line(line.line_index)
+ .unwrap_or("");
+ let source_kind = RenderedLineKind::SourceText {
+ file: self.file.clone(),
+ line_index: line.line_index,
+ };
+
+ let mut styled_buffer = StyledBuffer::new();
+
+ // First create the source line we will highlight.
+ styled_buffer.append(0, &source_string, Style::Quotation);
+
+ if line.annotations.is_empty() {
+ return styled_buffer.render(source_kind);
+ }
+
+ // We want to display like this:
+ //
+ // vec.push(vec.pop().unwrap());
+ // --- ^^^ _ previous borrow ends here
+ // | |
+ // | error occurs here
+ // previous borrow of `vec` occurs here
+ //
+ // But there are some weird edge cases to be aware of:
+ //
+ // vec.push(vec.pop().unwrap());
+ // -------- - previous borrow ends here
+ // ||
+ // |this makes no sense
+ // previous borrow of `vec` occurs here
+ //
+ // For this reason, we group the lines into "highlight lines"
+ // and "annotations lines", where the highlight lines have the `~`.
+
+ //let mut highlight_line = Self::whitespace(&source_string);
+
+ // Sort the annotations by (start, end col)
+ let mut annotations = line.annotations.clone();
+ annotations.sort();
+
+ // Next, create the highlight line.
+ for annotation in &annotations {
+ if old_school {
+ for p in annotation.start_col .. annotation.end_col {
+ if p == annotation.start_col {
+ styled_buffer.putc(1, p, '^',
+ if annotation.is_primary {
+ Style::UnderlinePrimary
+ } else {
+ Style::OldSkoolNote
+ });
+ }
+ else {
+ styled_buffer.putc(1, p, '~',
+ if annotation.is_primary {
+ Style::UnderlinePrimary
+ } else {
+ Style::OldSkoolNote
+ });
+ }
+ }
+ }
+ else {
+ for p in annotation.start_col .. annotation.end_col {
+ if annotation.is_primary {
+ styled_buffer.putc(1, p, '^', Style::UnderlinePrimary);
+ if !annotation.is_minimized {
+ styled_buffer.set_style(0, p, Style::UnderlinePrimary);
+ }
+ } else {
+ styled_buffer.putc(1, p, '-', Style::UnderlineSecondary);
+ if !annotation.is_minimized {
+ styled_buffer.set_style(0, p, Style::UnderlineSecondary);
+ }
+ }
+ }
+ }
+ }
+
+ // Now we are going to write labels in. To start, we'll exclude
+ // the annotations with no labels.
+ let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) =
+ annotations.into_iter()
+ .partition(|a| a.label.is_some());
+
+ // If there are no annotations that need text, we're done.
+ if labeled_annotations.is_empty() {
+ return styled_buffer.render(source_kind);
+ }
+ if old_school {
+ return styled_buffer.render(source_kind);
+ }
+
+ // Now add the text labels. We try, when possible, to stick the rightmost
+ // annotation at the end of the highlight line:
+ //
+ // vec.push(vec.pop().unwrap());
+ // --- --- - previous borrow ends here
+ //
+ // But sometimes that's not possible because one of the other
+ // annotations overlaps it. For example, from the test
+ // `span_overlap_label`, we have the following annotations
+ // (written on distinct lines for clarity):
+ //
+ // fn foo(x: u32) {
+ // --------------
+ // -
+ //
+ // In this case, we can't stick the rightmost-most label on
+ // the highlight line, or we would get:
+ //
+ // fn foo(x: u32) {
+ // -------- x_span
+ // |
+ // fn_span
+ //
+ // which is totally weird. Instead we want:
+ //
+ // fn foo(x: u32) {
+ // --------------
+ // | |
+ // | x_span
+ // fn_span
+ //
+ // which is...less weird, at least. In fact, in general, if
+ // the rightmost span overlaps with any other span, we should
+ // use the "hang below" version, so we can at least make it
+ // clear where the span *starts*.
+ let mut labeled_annotations = &labeled_annotations[..];
+ match labeled_annotations.split_last().unwrap() {
+ (last, previous) => {
+ if previous.iter()
+ .chain(&unlabeled_annotations)
+ .all(|a| !overlaps(a, last))
+ {
+ // append the label afterwards; we keep it in a separate
+ // string
+ let highlight_label: String = format!(" {}", last.label.as_ref().unwrap());
+ if last.is_primary {
+ styled_buffer.append(1, &highlight_label, Style::LabelPrimary);
+ } else {
+ styled_buffer.append(1, &highlight_label, Style::LabelSecondary);
+ }
+ labeled_annotations = previous;
+ }
+ }
+ }
+
+ // If that's the last annotation, we're done
+ if labeled_annotations.is_empty() {
+ return styled_buffer.render(source_kind);
+ }
+
+ for (index, annotation) in labeled_annotations.iter().enumerate() {
+ // Leave:
+ // - 1 extra line
+ // - One line for each thing that comes after
+ let comes_after = labeled_annotations.len() - index - 1;
+ let blank_lines = 3 + comes_after;
+
+ // For each blank line, draw a `|` at our column. The
+ // text ought to be long enough for this.
+ for index in 2..blank_lines {
+ if annotation.is_primary {
+ styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlinePrimary);
+ } else {
+ styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlineSecondary);
+ }
+ }
+
+ if annotation.is_primary {
+ styled_buffer.puts(blank_lines, annotation.start_col,
+ annotation.label.as_ref().unwrap(), Style::LabelPrimary);
+ } else {
+ styled_buffer.puts(blank_lines, annotation.start_col,
+ annotation.label.as_ref().unwrap(), Style::LabelSecondary);
+ }
+ }
+
+ styled_buffer.render(source_kind)
+ }
+}
+
+fn prepend_prefixes(rendered_lines: &mut [RenderedLine], format_mode: &FormatMode) {
+ let old_school = match *format_mode {
+ FormatMode::OriginalErrorFormat => true,
+ FormatMode::NewErrorFormat => false,
+ FormatMode::EnvironmentSelected => check_old_skool()
+ };
+ if old_school {
+ return;
+ }
+
+ let prefixes: Vec<_> =
+ rendered_lines.iter()
+ .map(|rl| rl.kind.prefix())
+ .collect();
+
+ // find the max amount of spacing we need; add 1 to
+ // p.text.len() to leave space between the prefix and the
+ // source text
+ let padding_len =
+ prefixes.iter()
+ .map(|p| if p.text.len() == 0 { 0 } else { p.text.len() + 1 })
+ .max()
+ .unwrap_or(0);
+
+ // Ensure we insert at least one character of padding, so that the
+ // `-->` arrows can fit etc.
+ let padding_len = cmp::max(padding_len, 1);
+
+ for (mut prefix, line) in prefixes.into_iter().zip(rendered_lines) {
+ let extra_spaces = (prefix.text.len() .. padding_len).map(|_| ' ');
+ prefix.text.extend(extra_spaces);
+ match line.kind {
+ RenderedLineKind::Elision => {
+ line.text.insert(0, prefix);
+ }
+ RenderedLineKind::PrimaryFileName => {
+ // --> filename
+ // 22 |>
+ // ^
+ // padding_len
+ let dashes = (0..padding_len - 1).map(|_| ' ')
+ .chain(Some('-'))
+ .chain(Some('-'))
+ .chain(Some('>'))
+ .chain(Some(' '));
+ line.text.insert(0, StyledString {text: dashes.collect(),
+ style: Style::LineNumber})
+ }
+ RenderedLineKind::OtherFileName => {
+ // ::: filename
+ // 22 |>
+ // ^
+ // padding_len
+ let dashes = (0..padding_len - 1).map(|_| ' ')
+ .chain(Some(':'))
+ .chain(Some(':'))
+ .chain(Some(':'))
+ .chain(Some(' '));
+ line.text.insert(0, StyledString {text: dashes.collect(),
+ style: Style::LineNumber})
+ }
+ _ => {
+ line.text.insert(0, prefix);
+ line.text.insert(1, StyledString {text: String::from("|> "),
+ style: Style::LineNumber})
+ }
+ }
+ }
+}
+
+fn trim_lines(rendered_lines: &mut [RenderedLine]) {
+ for line in rendered_lines {
+ while !line.text.is_empty() {
+ line.trim_last();
+ if line.text.last().unwrap().text.is_empty() {
+ line.text.pop();
+ } else {
+ break;
+ }
+ }
+ }
+}
+
+impl Line {
+ fn new(line_index: usize) -> Line {
+ Line {
+ line_index: line_index,
+ annotations: vec![]
+ }
+ }
+
+ fn push_annotation(&mut self,
+ start: CharPos,
+ end: CharPos,
+ is_primary: bool,
+ is_minimized: bool,
+ label: Option<String>) {
+ self.annotations.push(Annotation {
+ start_col: start.0,
+ end_col: end.0,
+ is_primary: is_primary,
+ is_minimized: is_minimized,
+ label: label,
+ });
+ }
+}
+
+fn overlaps(a1: &Annotation,
+ a2: &Annotation)
+ -> bool
+{
+ (a2.start_col .. a2.end_col).contains(a1.start_col) ||
+ (a1.start_col .. a1.end_col).contains(a2.start_col)
+}
serialize = { path = "../libserialize" }
log = { path = "../liblog" }
syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
use std::io::Write;
use syntax::ast;
use syntax::attr::AttrMetaMethods;
-use syntax::codemap::Span;
use syntax::parse::token::InternedString;
+use syntax_pos::Span;
const IF_THIS_CHANGED: &'static str = "rustc_if_this_changed";
const THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need";
pub use self::SawStmtComponent::*;
use self::SawAbiComponent::*;
use syntax::ast::{self, Name, NodeId};
- use syntax::codemap::Span;
use syntax::parse::token;
+ use syntax_pos::Span;
use rustc::ty::TyCtxt;
use rustc::hir;
use rustc::hir::*;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
+extern crate syntax_pos;
mod assert_dep_graph;
mod calculate_svh;
use syntax::ast;
use syntax::attr::{self, AttrMetaMethods};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir::{self, PatKind};
use rustc::hir::intravisit::FnKind;
use syntax::{ast};
use syntax::attr::{self, AttrMetaMethods};
-use syntax::codemap::{self, Span};
+use syntax_pos::{self, Span};
use rustc::hir::{self, PatKind};
use rustc::hir::intravisit::FnKind;
if hints.iter().any(|attr| *attr == attr::ReprExtern) &&
self_type_def.dtor_kind().has_drop_flag() {
let drop_impl_span = ctx.tcx.map.def_id_span(drop_impl_did,
- codemap::DUMMY_SP);
+ syntax_pos::DUMMY_SP);
let self_defn_span = ctx.tcx.map.def_id_span(self_type_did,
- codemap::DUMMY_SP);
+ syntax_pos::DUMMY_SP);
ctx.span_lint_note(DROP_WITH_REPR_EXTERN,
drop_impl_span,
"implementing Drop adds hidden state to types, \
extern crate log;
extern crate rustc_back;
extern crate rustc_const_eval;
+extern crate syntax_pos;
pub use rustc::lint as lint;
pub use rustc::middle as middle;
use syntax::ast;
use syntax::abi::Abi;
use syntax::attr;
-use syntax::codemap::{self, Span};
+use syntax_pos::Span;
+use syntax::codemap;
use rustc::hir;
use syntax::ast;
use syntax::attr::{self, AttrMetaMethods};
-use syntax::codemap::Span;
use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType};
use syntax::ptr::P;
+use syntax_pos::Span;
use rustc_back::slice;
use rustc::hir;
rustc_back = { path = "../librustc_back" }
rustc_bitflags = { path = "../librustc_bitflags" }
rustc_const_math = { path = "../librustc_const_math" }
+rustc_errors = { path = "../librustc_errors" }
rustc_llvm = { path = "../librustc_llvm" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
use rustc::ty::subst;
use rustc::ty::{self, Ty, TyCtxt};
-use syntax::{ast, codemap};
+use syntax::ast;
use syntax::ast::NodeIdAssigner;
use syntax::ptr::P;
+use syntax_pos;
use std::cell::Cell;
use std::io::SeekFrom;
fn new_def_id(&self, def_id: DefId) -> DefId {
self.tr_def_id(def_id)
}
- fn new_span(&self, span: codemap::Span) -> codemap::Span {
+ fn new_span(&self, span: syntax_pos::Span) -> syntax_pos::Span {
self.tr_span(span)
}
}
/// Translates a `Span` from an extern crate to the corresponding `Span`
/// within the local crate's codemap.
- pub fn tr_span(&self, span: codemap::Span) -> codemap::Span {
+ pub fn tr_span(&self, span: syntax_pos::Span) -> syntax_pos::Span {
decoder::translate_span(self.cdata,
self.tcx.sess.codemap(),
&self.last_filemap_index,
}
}
-impl tr for codemap::Span {
- fn tr(&self, dcx: &DecodeContext) -> codemap::Span {
+impl tr for syntax_pos::Span {
+ fn tr(&self, dcx: &DecodeContext) -> syntax_pos::Span {
dcx.tr_span(*self)
}
}
#[cfg(test)]
trait FakeExtCtxt {
- fn call_site(&self) -> codemap::Span;
+ fn call_site(&self) -> syntax_pos::Span;
fn cfg(&self) -> ast::CrateConfig;
fn ident_of(&self, st: &str) -> ast::Ident;
fn name_of(&self, st: &str) -> ast::Name;
#[cfg(test)]
impl FakeExtCtxt for parse::ParseSess {
- fn call_site(&self) -> codemap::Span {
- codemap::Span {
- lo: codemap::BytePos(0),
- hi: codemap::BytePos(0),
- expn_id: codemap::NO_EXPANSION,
+ fn call_site(&self) -> syntax_pos::Span {
+ syntax_pos::Span {
+ lo: syntax_pos::BytePos(0),
+ hi: syntax_pos::BytePos(0),
+ expn_id: syntax_pos::NO_EXPANSION,
}
}
fn cfg(&self) -> ast::CrateConfig { Vec::new() }
use syntax::ast;
use syntax::abi::Abi;
-use syntax::codemap::{self, Span, mk_sp, Pos};
+use syntax::codemap;
use syntax::parse;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::parse::token::InternedString;
use syntax::visit;
+use syntax_pos::{self, Span, mk_sp, Pos};
use log;
struct LocalCrateReader<'a> {
info!("panic runtime not found -- loading {}", name);
let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
- codemap::DUMMY_SP,
+ syntax_pos::DUMMY_SP,
PathKind::Crate, false);
// Sanity check the loaded crate to ensure it is indeed a panic runtime
&self.sess.target.target.options.exe_allocation_crate
};
let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
- codemap::DUMMY_SP,
+ syntax_pos::DUMMY_SP,
PathKind::Crate, false);
// Sanity check the crate we loaded to ensure that it is indeed an
None => {
// We can't reuse an existing FileMap, so allocate a new one
// containing the information we need.
- let codemap::FileMap {
+ let syntax_pos::FileMap {
name,
abs_path,
start_pos,
return imported_filemaps;
- fn are_equal_modulo_startpos(fm1: &codemap::FileMap,
- fm2: &codemap::FileMap)
+ fn are_equal_modulo_startpos(fm1: &syntax_pos::FileMap,
+ fm2: &syntax_pos::FileMap)
-> bool {
if fm1.name != fm2.name {
return false;
use syntax::attr;
use syntax::codemap;
use syntax::parse::token::IdentInterner;
+use syntax_pos;
pub use middle::cstore::{NativeLibraryKind, LinkagePreference};
pub use middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
MetadataArchive(loader::ArchiveMetadata),
}
-/// Holds information about a codemap::FileMap imported from another crate.
+/// Holds information about a syntax_pos::FileMap imported from another crate.
/// See creader::import_codemap() for more information.
pub struct ImportedFileMap {
/// This FileMap's byte-offset within the codemap of its original crate
- pub original_start_pos: codemap::BytePos,
+ pub original_start_pos: syntax_pos::BytePos,
/// The end of this FileMap within the codemap of its original crate
- pub original_end_pos: codemap::BytePos,
+ pub original_end_pos: syntax_pos::BytePos,
/// The imported FileMap's representation within the local codemap
- pub translated_filemap: Rc<codemap::FileMap>
+ pub translated_filemap: Rc<syntax_pos::FileMap>
}
pub struct crate_metadata {
use syntax::parse::token::{self, IdentInterner};
use syntax::ast;
use syntax::abi::Abi;
-use syntax::codemap::{self, Span, BytePos, NO_EXPANSION};
+use syntax::codemap;
use syntax::print::pprust;
use syntax::ptr::P;
-
+use syntax_pos::{self, Span, BytePos, NO_EXPANSION};
pub type Cmd<'a> = &'a crate_metadata;
value: meta_item,
is_sugared_doc: is_sugared_doc,
},
- span: codemap::DUMMY_SP
+ span: syntax_pos::DUMMY_SP
}
}).collect()
},
pub fn translate_span(cdata: Cmd,
codemap: &codemap::CodeMap,
last_filemap_index_hint: &Cell<usize>,
- span: codemap::Span)
- -> codemap::Span {
+ span: syntax_pos::Span)
+ -> syntax_pos::Span {
let span = if span.lo > span.hi {
// Currently macro expansion sometimes produces invalid Span values
// where lo > hi. In order not to crash the compiler when trying to
// least some of the time).
// This workaround is only necessary as long as macro expansion is
// not fixed. FIXME(#23480)
- codemap::mk_sp(span.lo, span.lo)
+ syntax_pos::mk_sp(span.lo, span.lo)
} else {
span
};
let hi = (span.hi - filemap.original_start_pos) +
filemap.translated_filemap.start_pos;
- codemap::mk_sp(lo, hi)
+ syntax_pos::mk_sp(lo, hi)
}
pub fn each_inherent_implementation_for_type<F>(cdata: Cmd,
item_family(impl_doc) == Family::DefaultImpl
}
-pub fn get_imported_filemaps(metadata: &[u8]) -> Vec<codemap::FileMap> {
+pub fn get_imported_filemaps(metadata: &[u8]) -> Vec<syntax_pos::FileMap> {
let crate_doc = rbml::Doc::new(metadata);
let cm_doc = reader::get_doc(crate_doc, tag_codemap);
use std::u32;
use syntax::abi::Abi;
use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
-use syntax::codemap::BytePos;
use syntax::attr;
-use syntax::errors::Handler;
+use errors::Handler;
use syntax;
+use syntax_pos::BytePos;
use rbml::writer::Encoder;
use rustc::hir::{self, PatKind};
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
#[macro_use] #[no_link] extern crate rustc_bitflags;
-
+extern crate syntax_pos;
extern crate flate;
extern crate rbml;
extern crate serialize as rustc_serialize; // used by deriving
+extern crate rustc_errors as errors;
#[macro_use]
extern crate rustc;
use rustc_llvm as llvm;
use rustc_llvm::{False, ObjectFile, mk_section_iter};
use rustc_llvm::archive_ro::ArchiveRO;
-use syntax::codemap::Span;
-use syntax::errors::DiagnosticBuilder;
+use errors::DiagnosticBuilder;
+use syntax_pos::Span;
use rustc_back::target::Target;
use std::cmp;
use rustc::session::Session;
use std::collections::{HashSet, HashMap};
-use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ast;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::ext;
+use syntax_pos::Span;
pub struct MacroLoader<'a> {
sess: &'a Session,
use syntax::abi::Abi;
use syntax::ast;
-use syntax::errors::Handler;
+use errors::Handler;
use rbml::leb128;
use encoder;
use rustc::ty;
use rustc::mir::repr::*;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// Compile `expr`, yielding an rvalue.
use hair::*;
use rustc::middle::region::CodeExtent;
use rustc::mir::repr::*;
-use syntax::codemap::Span;
+use syntax_pos::Span;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
use rustc::mir::repr::*;
use hair::*;
use syntax::ast::{Name, NodeId};
-use syntax::codemap::Span;
+use syntax_pos::Span;
// helper functions, broken out by category:
mod simplify;
use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};
use rustc::mir::repr::*;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use std::cmp::Ordering;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
use rustc::mir::repr::*;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// Add a new temporary value of type `ty` storing the result of
use rustc::hir;
use syntax::abi::Abi;
use syntax::ast;
-use syntax::codemap::Span;
use syntax::parse::token::keywords;
+use syntax_pos::Span;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc::ty::subst::{Substs, Subst, VecPerParamSpace};
use rustc::ty::{Ty, TyCtxt};
use rustc::mir::repr::*;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::fnv::FnvHashMap;
use rustc::ty::{self, Ty};
use rustc::mir::repr::*;
use rustc::hir::{self, PatKind};
-use syntax::codemap::Span;
use syntax::ptr::P;
+use syntax_pos::Span;
/// When there are multiple patterns in a single arm, each one has its
/// own node-ids for the bindings. References to the variables always
use rustc::ty::{self, AdtDef, ClosureSubsts, Region, Ty};
use rustc::hir;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use self::cx::Cx;
pub mod cx;
extern crate rustc_bitflags;
#[macro_use]
extern crate syntax;
+extern crate syntax_pos;
extern crate rustc_const_math;
extern crate rustc_const_eval;
use rustc::hir;
use rustc::hir::intravisit::{self, FnKind, Visitor};
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use std::mem;
use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
use rustc::mir::traversal::ReversePostorder;
use rustc::ty::{self, TyCtxt};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use build::Location;
use rustc::mir::visit::{LvalueContext, Visitor};
use rustc::util::nodemap::DefIdMap;
use syntax::abi::Abi;
-use syntax::codemap::Span;
use syntax::feature_gate::UnstableFeatures;
+use syntax_pos::Span;
use std::collections::hash_map::Entry;
use std::fmt;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::visit::{self, Visitor};
use std::fmt;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
use rustc_data_structures::indexed_vec::Idx;
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
+rustc_errors = { path = "../librustc_errors" }
\ No newline at end of file
use rustc::lint;
use rustc::session::Session;
use syntax::ast::*;
-use syntax::codemap::Span;
-use syntax::errors;
use syntax::parse::token::{self, keywords};
use syntax::visit::{self, Visitor};
+use syntax_pos::Span;
+use errors;
struct AstValidator<'a> {
session: &'a Session,
use rustc::hir::{self, PatKind};
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir::intravisit::{self, FnKind, Visitor};
use std::collections::hash_map::Entry;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
+extern crate syntax_pos;
+extern crate rustc_errors as errors;
pub mod diagnostics;
use rustc::hir::map::Map;
use rustc::hir::intravisit::{self, Visitor};
use rustc::hir;
-use syntax::codemap::Span;
+use syntax_pos::Span;
#[derive(Clone, Copy, PartialEq)]
enum Context {
use rustc::hir;
use rustc::hir::intravisit;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut rvcx = RvalueContext { tcx: tcx };
use rustc::util::nodemap::NodeMap;
use syntax::{ast};
-use syntax::codemap::Span;
use syntax::feature_gate::{GateIssue, emit_feature_err};
+use syntax_pos::Span;
use rustc::hir::intravisit::{self, Visitor};
use rustc::hir;
rustc_bitflags = { path = "../librustc_bitflags" }
rustc_metadata = { path = "../librustc_metadata" }
syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
use syntax::ast;
use syntax::attr;
-use syntax::codemap::Span;
-use syntax::errors;
+use errors;
+use syntax_pos::Span;
use rustc::dep_graph::DepNode;
use rustc::hir::map::Map;
use rustc::hir::intravisit::Visitor;
extern crate rustc;
extern crate rustc_back;
extern crate rustc_metadata;
+extern crate syntax_pos;
+extern crate rustc_errors as errors;
pub use self::registry::Registry;
use std::mem;
use std::path::PathBuf;
use syntax::ast;
-use syntax::codemap::{Span, COMMAND_LINE_SP};
use syntax::ptr::P;
use syntax::attr::AttrMetaMethods;
+use syntax_pos::{Span, COMMAND_LINE_SP};
/// Pointer to a registrar function.
pub type PluginRegistrarFun =
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator};
use syntax::ext::base::{MacroExpanderFn, MacroRulesTT};
-use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ptr::P;
use syntax::ast;
use syntax::feature_gate::AttributeType;
+use syntax_pos::Span;
use std::collections::HashMap;
use std::borrow::ToOwned;
extern crate rustc;
#[macro_use] extern crate syntax;
+extern crate syntax_pos;
use rustc::dep_graph::DepNode;
use rustc::hir::{self, PatKind};
use rustc::ty::{self, TyCtxt};
use rustc::util::nodemap::NodeSet;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use std::cmp;
use std::mem::replace;
syntax = { path = "../libsyntax" }
rustc = { path = "../librustc" }
arena = { path = "../libarena" }
+rustc_errors = { path = "../librustc_errors" }
+syntax_pos = { path = "../libsyntax_pos" }
use syntax::ast::Name;
use syntax::attr;
use syntax::parse::token;
-use syntax::codemap::{Span, DUMMY_SP};
use syntax::ast::{Block, Crate, DeclKind};
use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind};
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
use syntax::visit::{self, Visitor};
+use syntax_pos::{Span, DUMMY_SP};
+
trait ToNameBinding<'a> {
fn to_name_binding(self) -> NameBinding<'a>;
}
use rustc::lint;
use syntax::ast::{self, ViewPathGlob, ViewPathList, ViewPathSimple};
use syntax::visit::{self, Visitor};
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
struct UnusedImportCheckVisitor<'a, 'b: 'a> {
extern crate log;
#[macro_use]
extern crate syntax;
+extern crate syntax_pos;
+extern crate rustc_errors as errors;
extern crate arena;
#[macro_use]
extern crate rustc;
use syntax::ext::mtwt;
use syntax::ast::{self, FloatTy};
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
-use syntax::codemap::{self, Span};
-use syntax::errors::DiagnosticBuilder;
use syntax::parse::token::{self, keywords};
use syntax::util::lev_distance::find_best_match_for_name;
use syntax::ast::{Local, Mutability, Pat, PatKind, Path};
use syntax::ast::{PathSegment, PathParameters, QSelf, TraitItemKind, TraitRef, Ty, TyKind};
+use syntax_pos::Span;
+use errors::DiagnosticBuilder;
+
use std::collections::{HashMap, HashSet};
use std::cell::{Cell, RefCell};
use std::fmt;
}
fn resolve_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
- span: syntax::codemap::Span,
+ span: syntax_pos::Span,
resolution_error: ResolutionError<'c>) {
resolve_struct_error(resolver, span, resolution_error).emit();
}
fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
- span: syntax::codemap::Span,
+ span: syntax_pos::Span,
resolution_error: ResolutionError<'c>)
-> DiagnosticBuilder<'a> {
if !resolver.emit_errors {
self.resolve_crate_relative_path(trait_path.span, segments, TypeNS)
} else {
self.resolve_module_relative_path(trait_path.span, segments, TypeNS)
- }.map(|binding| binding.span).unwrap_or(codemap::DUMMY_SP)
+ }.map(|binding| binding.span).unwrap_or(syntax_pos::DUMMY_SP)
};
- if definition_site != codemap::DUMMY_SP {
+ if definition_site != syntax_pos::DUMMY_SP {
err.span_label(definition_site,
&format!("type aliases cannot be used for traits"));
}
},
};
- if old_binding.span != codemap::DUMMY_SP {
+ if old_binding.span != syntax_pos::DUMMY_SP {
err.span_label(old_binding.span, &format!("previous {} of `{}` here", noun, name));
}
err.emit();
use rustc::hir::def::*;
use syntax::ast::{NodeId, Name};
-use syntax::codemap::{Span, DUMMY_SP};
use syntax::util::lev_distance::find_best_match_for_name;
+use syntax_pos::{Span, DUMMY_SP};
use std::cell::{Cell, RefCell};
rustc = { path = "../librustc" }
syntax = { path = "../libsyntax" }
serialize = { path = "../libserialize" }
+syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
use rustc::hir::def_id::DefId;
use syntax::ast::{CrateNum, NodeId};
-use syntax::codemap::Span;
+use syntax_pos::Span;
pub struct CrateData {
pub name: String,
use std::hash::*;
use syntax::ast::{self, NodeId, PatKind};
-use syntax::codemap::*;
use syntax::parse::token::{self, keywords};
use syntax::visit::{self, Visitor};
use syntax::print::pprust::{path_to_string, ty_to_string, bounds_to_string, generics_to_string};
use syntax::ptr::P;
+use syntax::codemap::Spanned;
+use syntax_pos::*;
use super::{escape, generated_code, SaveContext, PathCollector};
use super::data::*;
use rustc::hir::map::Map;
use rustc::ty::TyCtxt;
use syntax::ast::{CrateNum, NodeId};
-use syntax::codemap::{Span, CodeMap};
+use syntax::codemap::CodeMap;
+use syntax_pos::Span;
use data;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate serialize as rustc_serialize;
+extern crate syntax_pos;
mod csv_dumper;
mod json_dumper;
use std::path::{Path, PathBuf};
use syntax::ast::{self, NodeId, PatKind};
-use syntax::codemap::*;
use syntax::parse::token::{self, keywords};
use syntax::visit::{self, Visitor};
use syntax::print::pprust::{ty_to_string, arg_to_string};
+use syntax::codemap::MacroAttribute;
+use syntax_pos::*;
pub use self::csv_dumper::CsvDumper;
pub use self::json_dumper::JsonDumper;
use std::path::Path;
use syntax::ast;
-use syntax::codemap::*;
use syntax::parse::lexer::{self, Reader, StringReader};
use syntax::parse::token::{self, keywords, Token};
+use syntax_pos::*;
#[derive(Clone)]
pub struct SpanUtils<'a> {
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
rustc_incremental = { path = "../librustc_incremental" }
rustc_llvm = { path = "../librustc_llvm" }
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
use std::rc::Rc;
use rustc::hir::{self, PatKind};
use syntax::ast::{self, DUMMY_NODE_ID, NodeId};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir::fold::Folder;
use syntax::ptr::P;
use std::str;
use flate;
use syntax::ast;
-use syntax::codemap::Span;
use syntax::attr::AttrMetaMethods;
+use syntax_pos::Span;
// RLIB LLVM-BYTECODE OBJECT LAYOUT
// Version 1
use {CrateTranslation, ModuleTranslation};
use util::common::time;
use util::common::path2cstr;
-use syntax::codemap::MultiSpan;
-use syntax::errors::{self, Handler, Level, RenderSpan};
-use syntax::errors::emitter::CoreEmitter;
+use errors::{self, Handler, Level, RenderSpan};
+use errors::emitter::CoreEmitter;
+use syntax_pos::MultiSpan;
use std::collections::HashMap;
use std::ffi::{CStr, CString};
unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>,
msg: &'b str,
cookie: c_uint) {
- use syntax::codemap::ExpnId;
+ use syntax_pos::ExpnId;
match cgcx.lto_ctxt {
Some((sess, _)) => {
use std::collections::{HashMap, HashSet};
use std::str;
use std::{i8, i16, i32, i64};
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
use syntax::parse::token::InternedString;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use llvm::{Opcode, IntPredicate, RealPredicate};
use llvm::{ValueRef, BasicBlockRef};
use common::*;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use builder::Builder;
use type_::Type;
use std::ffi::CString;
use std::ptr;
-use syntax::codemap::Span;
+use syntax_pos::Span;
pub struct Builder<'a, 'tcx: 'a> {
pub llbuilder: BuilderRef,
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::hir;
-use syntax::codemap::DUMMY_SP;
-use syntax::errors;
+use syntax_pos::DUMMY_SP;
+use errors;
use syntax::ptr::P;
#[derive(Debug)]
use rustc::mir::visit::Visitor as MirVisitor;
use syntax::abi::Abi;
-use syntax::codemap::DUMMY_SP;
-use syntax::errors;
+use errors;
+use syntax_pos::DUMMY_SP;
use base::custom_coerce_unsize_info;
use context::SharedCrateContext;
use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized};
use std::cell::{Cell, RefCell};
use syntax::ast;
-use syntax::codemap::{DUMMY_SP, Span};
use syntax::parse::token::InternedString;
use syntax::parse::token;
+use syntax_pos::{DUMMY_SP, Span};
pub use context::{CrateContext, SharedCrateContext};
use libc::c_uint;
use syntax::ast::{self, LitKind};
use syntax::attr::{self, AttrMetaMethods};
-use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ptr::P;
+use syntax_pos::Span;
pub type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>;
use std::fmt;
use syntax::ast;
-use syntax::codemap::DUMMY_SP;
+use syntax_pos::DUMMY_SP;
/// A `Datum` encapsulates the result of evaluating an expression. It
/// describes where the value is stored, what Rust type the value has,
use libc::c_uint;
use std::ptr;
-use syntax::codemap::{Span, Pos};
+use syntax_pos::{Span, Pos};
use syntax::{ast, codemap};
use rustc_data_structures::bitvec::BitVector;
use std::rc::Rc;
use syntax;
use syntax::util::interner::Interner;
-use syntax::codemap::Span;
-use syntax::{ast, codemap};
+use syntax::ast;
use syntax::parse::token;
+use syntax_pos::{self, Span};
// From DWARF 5.
&[],
containing_scope,
NO_FILE_METADATA,
- codemap::DUMMY_SP)
+ syntax_pos::DUMMY_SP)
}
pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
&[sole_struct_member_description],
self.containing_scope,
self.file_metadata,
- codemap::DUMMY_SP);
+ syntax_pos::DUMMY_SP);
// Encode the information about the null variant in the union
// member's name.
let discriminant_base_type_metadata =
type_metadata(cx,
adt::ty_of_inttype(cx.tcx(), inttype),
- codemap::DUMMY_SP);
+ syntax_pos::DUMMY_SP);
let discriminant_name = get_enum_discriminant_name(cx, enum_def_id);
let name = CString::new(discriminant_name.as_bytes()).unwrap();
let node_def_id = cx.tcx().map.local_def_id(node_id);
let (var_scope, span) = get_namespace_and_span_for_item(cx, node_def_id);
- let (file_metadata, line_number) = if span != codemap::DUMMY_SP {
+ let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP {
let loc = span_start(cx, span);
(file_metadata(cx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint)
} else {
use std::ffi::CString;
use std::ptr;
-use syntax::codemap::{Span, Pos};
-use syntax::{ast, codemap};
+use syntax_pos::{self, Span, Pos};
+use syntax::ast;
use syntax::attr::IntType;
pub mod gdb;
let (containing_scope, span) = get_containing_scope_and_span(cx, instance);
// This can be the case for functions inlined from another crate
- if span == codemap::DUMMY_SP {
+ if span == syntax_pos::DUMMY_SP {
return FunctionDebugContext::FunctionWithoutDebugInfo;
}
signature.push(match sig.output {
ty::FnConverging(ret_ty) => match ret_ty.sty {
ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
- _ => type_metadata(cx, ret_ty, codemap::DUMMY_SP)
+ _ => type_metadata(cx, ret_ty, syntax_pos::DUMMY_SP)
},
ty::FnDiverging => diverging_type_metadata(cx)
});
// Arguments types
for &argument_type in inputs {
- signature.push(type_metadata(cx, argument_type, codemap::DUMMY_SP));
+ signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
}
if abi == Abi::RustCall && !sig.inputs.is_empty() {
if let ty::TyTuple(args) = sig.inputs[sig.inputs.len() - 1].sty {
for &argument_type in args {
- signature.push(type_metadata(cx, argument_type, codemap::DUMMY_SP));
+ signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
}
}
}
let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
generics.types.as_slice().iter().enumerate().map(|(i, param)| {
let actual_type = cx.tcx().normalize_associated_type(&actual_types[i]);
- let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP);
+ let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
let name = CString::new(param.name.as_str().as_bytes()).unwrap();
unsafe {
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
let impl_self_ty = monomorphize::apply_param_substs(cx.tcx(),
instance.substs,
&impl_self_ty);
- Some(type_metadata(cx, impl_self_ty, codemap::DUMMY_SP))
+ Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
} else {
// For trait method impls we still use the "parallel namespace"
// strategy
// Try to get some span information, if we have an inlined item.
let definition_span = match cx.external().borrow().get(&instance.def) {
Some(&Some(node_id)) => cx.tcx().map.span(node_id),
- _ => cx.tcx().map.def_id_span(instance.def, codemap::DUMMY_SP)
+ _ => cx.tcx().map.def_id_span(instance.def, syntax_pos::DUMMY_SP)
};
(containing_scope, definition_span)
use libc::c_uint;
use std::ffi::CString;
use std::ptr;
-use syntax::codemap::DUMMY_SP;
+use syntax_pos::DUMMY_SP;
pub fn mangled_name_of_item(ccx: &CrateContext, def_id: DefId, extra: &str) -> String {
fn fill_nested(ccx: &CrateContext, def_id: DefId, extra: &str, output: &mut String) {
use libc::c_uint;
use std::ptr;
-use syntax::codemap::{Span, Pos};
-use syntax::{ast, codemap};
+use syntax_pos::{self, Span, Pos};
+use syntax::ast;
pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
node_id: ast::NodeId,
if !bytes.is_empty() && &bytes[bytes.len()-1..] == b"}" {
cleanup_span = Span {
- lo: node_span.hi - codemap::BytePos(1),
+ lo: node_span.hi - syntax_pos::BytePos(1),
hi: node_span.hi,
expn_id: node_span.expn_id
};
use common::{CrateContext, FunctionContext};
use type_::Type;
-use syntax::codemap::Span;
-use syntax::{ast, codemap};
+use syntax_pos::{self, Span};
+use syntax::ast;
pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool
{
};
}
-/// Return codemap::Loc corresponding to the beginning of the span
-pub fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
+/// Return syntax_pos::Loc corresponding to the beginning of the span
+pub fn span_start(cx: &CrateContext, span: Span) -> syntax_pos::Loc {
cx.sess().codemap().lookup_char_pos(span.lo)
}
// Try to get some span information, if we have an inlined item.
let definition_span = match cx.external().borrow().get(&def_id) {
Some(&Some(node_id)) => cx.tcx().map.span(node_id),
- _ => cx.tcx().map.def_id_span(def_id, codemap::DUMMY_SP)
+ _ => cx.tcx().map.def_id_span(def_id, syntax_pos::DUMMY_SP)
};
(containing_scope, definition_span)
use rustc::hir;
-use syntax::{ast, codemap};
+use syntax::ast;
use syntax::parse::token::InternedString;
+use syntax_pos;
use std::fmt;
use std::mem;
}
fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- span: codemap::Span,
+ span: syntax_pos::Span,
source: Datum<'tcx, Rvalue>,
target: Datum<'tcx, Rvalue>)
-> Block<'blk, 'tcx> {
fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
fields: &[hir::Field],
base: Option<&hir::Expr>,
- expr_span: codemap::Span,
+ expr_span: syntax_pos::Span,
expr_id: ast::NodeId,
ty: Ty<'tcx>,
dest: Dest) -> Block<'blk, 'tcx> {
use value::Value;
use arena::TypedArena;
-use syntax::codemap::DUMMY_SP;
+use syntax_pos::DUMMY_SP;
pub fn trans_exchange_free_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
v: ValueRef,
use syntax::parse::token;
use rustc::session::Session;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
use std::cmp::Ordering;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
+extern crate syntax_pos;
+extern crate rustc_errors as errors;
pub use rustc::session;
pub use rustc::middle;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use syntax::ast::Name;
-use syntax::codemap::DUMMY_SP;
+use syntax_pos::DUMMY_SP;
// drop_glue pointer, size, align.
const VTABLE_OFFSET: usize = 3;
use type_::Type;
use value::Value;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
use std::ptr;
use machine;
use type_of;
-use syntax::codemap::DUMMY_SP;
+use syntax_pos::DUMMY_SP;
use syntax::parse::token::keywords;
use std::ops::Deref;
if let mir::AggregateKind::Closure(def_id, substs) = *kind {
use rustc::hir;
use syntax::ast::DUMMY_NODE_ID;
- use syntax::codemap::DUMMY_SP;
use syntax::ptr::P;
+ use syntax_pos::DUMMY_SP;
use closure;
closure::trans_closure_expr(closure::Dest::Ignore(bcx.ccx()),
use rustc::hir;
use syntax::attr;
-use syntax::errors;
+use errors;
use std::fmt;
use rustc_const_math::ConstInt;
use std::cell::RefCell;
use syntax::{abi, ast};
-use syntax::codemap::{Span, Pos};
-use syntax::errors::DiagnosticBuilder;
use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax::parse::token::{self, keywords};
+use syntax_pos::{Span, Pos};
+use errors::DiagnosticBuilder;
pub trait AstConv<'gcx, 'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::cmp;
use syntax::ast;
-use syntax::codemap::{Span, Spanned};
+use syntax::codemap::Spanned;
use syntax::ptr::P;
+use syntax_pos::Span;
use rustc::hir::{self, PatKind};
use rustc::hir::print as pprust;
SelectionContext, ObligationCause};
use rustc::ty::fold::TypeFoldable;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
//FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument.
pub fn normalize_associated_types_in<'a, 'gcx, 'tcx, T>(
use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
use rustc::hir;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use syntax::parse::token;
#[derive(Copy, Clone, Debug)]
use hir::def_id::DefId;
use rustc::infer;
use rustc::ty::{self, LvaluePreference, Ty};
-use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ptr::P;
+use syntax_pos::Span;
use rustc::hir;
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::ty::cast::{CastKind, CastTy};
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use util::common::ErrorReported;
/// Reifies a cast check to be checked once we have full type information for
use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace};
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use CrateCtxt;
use super::assoc;
use rustc::ty::Ty;
use rustc::infer::{InferOk, TypeOrigin};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir;
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
use util::nodemap::FnvHashSet;
use syntax::ast;
-use syntax::codemap::{self, Span};
+use syntax_pos::{self, Span};
/// check_drop_impl confirms that the Drop implementation identfied by
/// `drop_impl_did` is not any more specialized than the type it is
_ => {
// Destructors only work on nominal types. This was
// already checked by coherence, so we can panic here.
- let span = ccx.tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
+ let span = ccx.tcx.map.def_id_span(drop_impl_did, syntax_pos::DUMMY_SP);
span_bug!(span,
"should have been rejected by coherence check: {}",
dtor_self_type);
let named_type = tcx.lookup_item_type(self_type_did).ty;
let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs);
- let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
+ let drop_impl_span = tcx.map.def_id_span(drop_impl_did, syntax_pos::DUMMY_SP);
let fresh_impl_substs =
infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, &fresh_impl_substs);
let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap();
- let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
+ let drop_impl_span = tcx.map.def_id_span(drop_impl_did, syntax_pos::DUMMY_SP);
// We can assume the predicates attached to struct/enum definition
// hold.
use std::collections::{HashMap};
use syntax::abi::Abi;
use syntax::ast;
-use syntax::codemap::Span;
use syntax::parse::token;
+use syntax_pos::Span;
use rustc::hir;
use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
use rustc::ty::fold::TypeFoldable;
use rustc::infer::{self, InferOk, TypeOrigin};
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir;
use std::ops::Deref;
use rustc::infer;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir;
use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
use rustc::infer::{InferOk, TypeOrigin};
use syntax::ast;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
use rustc::hir;
use std::collections::HashSet;
use std::mem;
use rustc::traits::{Obligation, SelectionContext};
use util::nodemap::{FnvHashSet};
-
use syntax::ast;
-use syntax::codemap::Span;
-use syntax::errors::DiagnosticBuilder;
+use errors::DiagnosticBuilder;
+use syntax_pos::Span;
+
use rustc::hir::print as pprust;
use rustc::hir;
use rustc::hir::Expr_;
use syntax::ast;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
-use syntax::codemap::{self, Span, Spanned};
-use syntax::errors::DiagnosticBuilder;
+use syntax::codemap::{self, Spanned};
use syntax::parse::token::{self, InternedString, keywords};
use syntax::ptr::P;
use syntax::util::lev_distance::find_best_match_for_name;
+use syntax_pos::{self, Span};
+use errors::DiagnosticBuilder;
use rustc::hir::intravisit::{self, Visitor};
use rustc::hir::{self, PatKind};
for ty in &self.unsolved_variables() {
if let ty::TyInfer(_) = self.shallow_resolve(ty).sty {
debug!("default_type_parameters: defaulting `{:?}` to error", ty);
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.err);
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err);
}
}
return;
if self.type_var_diverges(resolved) {
debug!("default_type_parameters: defaulting `{:?}` to `()` because it diverges",
resolved);
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.mk_nil());
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
} else {
match self.type_is_unconstrained_numeric(resolved) {
UnconstrainedInt => {
debug!("default_type_parameters: defaulting `{:?}` to `i32`",
resolved);
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.i32)
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32)
},
UnconstrainedFloat => {
debug!("default_type_parameters: defaulting `{:?}` to `f32`",
resolved);
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.f64)
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64)
}
Neither => { }
}
for ty in &unsolved_variables {
let resolved = self.resolve_type_vars_if_possible(ty);
if self.type_var_diverges(resolved) {
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.mk_nil());
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
} else {
match self.type_is_unconstrained_numeric(resolved) {
UnconstrainedInt | UnconstrainedFloat => {
let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| {
for ty in &unbound_tyvars {
if self.type_var_diverges(ty) {
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.mk_nil());
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
} else {
match self.type_is_unconstrained_numeric(ty) {
UnconstrainedInt => {
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.i32)
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32)
},
UnconstrainedFloat => {
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.f64)
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64)
}
Neither => {
if let Some(default) = default_map.get(ty) {
self.find_conflicting_default(&unbound_tyvars, &default_map, conflict)
.unwrap_or(type_variable::Default {
ty: self.next_ty_var(),
- origin_span: codemap::DUMMY_SP,
+ origin_span: syntax_pos::DUMMY_SP,
def_id: self.tcx.map.local_def_id(0) // what do I put here?
});
// reporting for more then one conflict.
for ty in &unbound_tyvars {
if self.type_var_diverges(ty) {
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.mk_nil());
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
} else {
match self.type_is_unconstrained_numeric(ty) {
UnconstrainedInt => {
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.i32)
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32)
},
UnconstrainedFloat => {
- self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx.types.f64)
+ self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64)
},
Neither => {
if let Some(default) = default_map.get(ty) {
use std::mem;
use std::ops::Deref;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir::intravisit::{self, Visitor};
use rustc::hir::{self, PatKind};
use rustc::infer::UpvarRegion;
use std::collections::HashSet;
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor};
use std::collections::HashSet;
use syntax::ast;
-use syntax::codemap::{Span};
-use syntax::errors::DiagnosticBuilder;
use syntax::parse::token::keywords;
+use syntax_pos::Span;
+use errors::DiagnosticBuilder;
+
use rustc::hir::intravisit::{self, Visitor};
use rustc::hir;
use std::cell::Cell;
use syntax::ast;
-use syntax::codemap::{DUMMY_SP, Span};
+use syntax_pos::{DUMMY_SP, Span};
+
use rustc::hir::print::pat_to_string;
use rustc::hir::intravisit::{self, Visitor};
use rustc::hir::{self, PatKind};
use rustc::ty::TyCtxt;
use syntax::ast;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
use rustc::hir;
use rustc::hir::intravisit::Visitor;
use rustc::infer::{self, InferCtxt, TypeOrigin};
use std::cell::RefCell;
use std::rc::Rc;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use util::nodemap::{DefIdMap, FnvHashMap};
use rustc::dep_graph::DepNode;
use rustc::hir::map as hir_map;
use rustc::traits;
use rustc::ty::{self, TyCtxt};
use syntax::ast;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::dep_graph::DepNode;
use rustc::hir::intravisit;
use rustc::hir;
use std::rc::Rc;
use syntax::{abi, ast, attr};
-use syntax::codemap::Span;
use syntax::parse::token::keywords;
use syntax::ptr::P;
+use syntax_pos::Span;
+
use rustc::hir::{self, PatKind};
use rustc::hir::intravisit;
use rustc::hir::print as pprust;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
+extern crate syntax_pos;
extern crate arena;
extern crate fmt_macros;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate rustc_const_eval;
+extern crate rustc_errors as errors;
pub use rustc::dep_graph;
pub use rustc::hir;
use session::{config, CompileResult};
use util::common::time;
-use syntax::codemap::Span;
use syntax::ast;
use syntax::abi::Abi;
+use syntax_pos::Span;
use std::cell::RefCell;
use util::nodemap::NodeMap;
use rustc::ty;
use std::cell::Cell;
-use syntax::codemap::Span;
+use syntax_pos::Span;
#[derive(Clone)]
pub struct ElisionFailureInfo {
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_driver = { path = "../librustc_driver" }
+rustc_errors = { path = "../librustc_errors" }
rustc_lint = { path = "../librustc_lint" }
rustc_metadata = { path = "../librustc_metadata" }
rustc_resolve = { path = "../librustc_resolve" }
rustc_trans = { path = "../librustc_trans" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
log = { path = "../liblog" }
[build-dependencies]
pub use self::FunctionRetTy::*;
pub use self::Visibility::*;
-use syntax;
use syntax::abi::Abi;
use syntax::ast;
use syntax::attr;
use syntax::attr::{AttributeMethods, AttrMetaMethods};
-use syntax::codemap;
-use syntax::codemap::{DUMMY_SP, Pos, Spanned};
+use syntax::codemap::Spanned;
use syntax::parse::token::{self, InternedString, keywords};
use syntax::ptr::P;
+use syntax_pos::{self, DUMMY_SP, Pos};
use rustc_trans::back::link;
use rustc::middle::cstore;
}
}
fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
- fn span(&self) -> codemap::Span { unimplemented!() }
+ fn span(&self) -> syntax_pos::Span { unimplemented!() }
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
}
}
-impl Clean<Span> for syntax::codemap::Span {
+impl Clean<Span> for syntax_pos::Span {
fn clean(&self, cx: &DocContext) -> Span {
if *self == DUMMY_SP {
return Span::empty();
fn to_src(&self, cx: &DocContext) -> String;
}
-impl ToSource for syntax::codemap::Span {
+impl ToSource for syntax_pos::Span {
fn to_src(&self, cx: &DocContext) -> String {
debug!("converting span {:?} to snippet", self.clean(cx));
let sn = match cx.sess().codemap().span_to_snippet(*self) {
use rustc_resolve as resolve;
use rustc_metadata::cstore::CStore;
-use syntax::{ast, codemap, errors};
-use syntax::errors::emitter::ColorConfig;
+use syntax::{ast, codemap};
use syntax::feature_gate::UnstableFeatures;
use syntax::parse::token;
+use errors;
+use errors::emitter::ColorConfig;
use std::cell::{RefCell, Cell};
use std::collections::{HashMap, HashSet};
pub use self::StructType::*;
pub use self::TypeBound::*;
-use syntax;
-use syntax::codemap::Span;
use syntax::abi;
use syntax::ast;
use syntax::ast::{Name, NodeId};
use syntax::attr;
use syntax::ptr::P;
+use syntax_pos::{self, Span};
+
use rustc::hir;
pub struct Module {
vis: hir::Inherited,
stab: None,
depr: None,
- where_outer: syntax::codemap::DUMMY_SP,
- where_inner: syntax::codemap::DUMMY_SP,
+ where_outer: syntax_pos::DUMMY_SP,
+ where_inner: syntax_pos::DUMMY_SP,
attrs : hir::HirVec::new(),
extern_crates: Vec::new(),
imports : Vec::new(),
use std::io;
use std::io::prelude::*;
-use syntax::codemap::{CodeMap, Span};
+use syntax::codemap::CodeMap;
use syntax::parse::lexer::{self, Reader, TokenAndSpan};
use syntax::parse::token;
use syntax::parse;
+use syntax_pos::Span;
/// Highlights `src`, returning the HTML output.
pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>) -> String {
extern crate rustc_metadata;
extern crate serialize;
#[macro_use] extern crate syntax;
+extern crate syntax_pos;
extern crate test as testing;
extern crate rustc_unicode;
#[macro_use] extern crate log;
+extern crate rustc_errors as errors;
extern crate serialize as rustc_serialize; // used by deriving
use rustc_metadata::cstore::CStore;
use rustc_resolve::MakeGlobMap;
use syntax::codemap::CodeMap;
-use syntax::errors;
-use syntax::errors::emitter::ColorConfig;
+use errors;
+use errors::emitter::ColorConfig;
use syntax::parse::token;
use core;
let data = Arc::new(Mutex::new(Vec::new()));
let codemap = Rc::new(CodeMap::new());
let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
- None,
- codemap.clone());
+ None,
+ codemap.clone(),
+ errors::snippet::FormatMode::EnvironmentSelected);
let old = io::set_panic(box Sink(data.clone()));
let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
use syntax::ast;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
-use syntax::codemap::Span;
+use syntax_pos::Span;
use rustc::hir::map as hir_map;
use rustc::hir::def::Def;
serialize = { path = "../libserialize" }
log = { path = "../liblog" }
rustc_bitflags = { path = "../librustc_bitflags" }
+syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
pub use self::PathParameters::*;
use attr::{ThinAttributes, HasAttrs};
-use codemap::{mk_sp, respan, Span, Spanned, DUMMY_SP, ExpnId};
+use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId};
+use codemap::{respan, Spanned};
use abi::Abi;
use errors;
use ext::base;
use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaItemKind};
use ast::{Stmt, StmtKind, DeclKind};
use ast::{Expr, Item, Local, Decl};
-use codemap::{Span, Spanned, spanned, dummy_spanned};
-use codemap::BytePos;
+use codemap::{spanned, dummy_spanned, Spanned};
+use syntax_pos::{Span, BytePos};
use errors::Handler;
use feature_gate::{Features, GatedCfg};
use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
pub use self::ExpnFormat::*;
-use std::cell::{Cell, RefCell};
-use std::ops::{Add, Sub};
+use std::cell::RefCell;
use std::path::{Path,PathBuf};
use std::rc::Rc;
-use std::cmp;
use std::env;
-use std::{fmt, fs};
+use std::fs;
use std::io::{self, Read};
-
-use serialize::{Encodable, Decodable, Encoder, Decoder};
+pub use syntax_pos::*;
+use errors::CodeMapper;
use ast::Name;
-// _____________________________________________________________________________
-// Pos, BytePos, CharPos
-//
-
-pub trait Pos {
- fn from_usize(n: usize) -> Self;
- fn to_usize(&self) -> usize;
-}
-
-/// A byte offset. Keep this small (currently 32-bits), as AST contains
-/// a lot of them.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
-pub struct BytePos(pub u32);
-
-/// A character offset. Because of multibyte utf8 characters, a byte offset
-/// is not equivalent to a character offset. The CodeMap will convert BytePos
-/// values to CharPos values as necessary.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
-pub struct CharPos(pub usize);
-
-// FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
-// have been unsuccessful
-
-impl Pos for BytePos {
- fn from_usize(n: usize) -> BytePos { BytePos(n as u32) }
- fn to_usize(&self) -> usize { let BytePos(n) = *self; n as usize }
-}
-
-impl Add for BytePos {
- type Output = BytePos;
-
- fn add(self, rhs: BytePos) -> BytePos {
- BytePos((self.to_usize() + rhs.to_usize()) as u32)
- }
-}
-
-impl Sub for BytePos {
- type Output = BytePos;
-
- fn sub(self, rhs: BytePos) -> BytePos {
- BytePos((self.to_usize() - rhs.to_usize()) as u32)
- }
-}
-
-impl Encodable for BytePos {
- fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_u32(self.0)
- }
-}
-
-impl Decodable for BytePos {
- fn decode<D: Decoder>(d: &mut D) -> Result<BytePos, D::Error> {
- Ok(BytePos(d.read_u32()?))
- }
-}
-
-impl Pos for CharPos {
- fn from_usize(n: usize) -> CharPos { CharPos(n) }
- fn to_usize(&self) -> usize { let CharPos(n) = *self; n }
-}
-
-impl Add for CharPos {
- type Output = CharPos;
-
- fn add(self, rhs: CharPos) -> CharPos {
- CharPos(self.to_usize() + rhs.to_usize())
- }
-}
-
-impl Sub for CharPos {
- type Output = CharPos;
-
- fn sub(self, rhs: CharPos) -> CharPos {
- CharPos(self.to_usize() - rhs.to_usize())
- }
-}
-
-// _____________________________________________________________________________
-// Span, MultiSpan, Spanned
-//
-
-/// Spans represent a region of code, used for error reporting. Positions in spans
-/// are *absolute* positions from the beginning of the codemap, not positions
-/// relative to FileMaps. Methods on the CodeMap can be used to relate spans back
-/// to the original source.
-/// You must be careful if the span crosses more than one file - you will not be
-/// able to use many of the functions on spans in codemap and you cannot assume
-/// that the length of the span = hi - lo; there may be space in the BytePos
-/// range between files.
-#[derive(Clone, Copy, Hash, PartialEq, Eq)]
-pub struct Span {
- pub lo: BytePos,
- pub hi: BytePos,
- /// Information about where the macro came from, if this piece of
- /// code was created by a macro expansion.
- pub expn_id: ExpnId
-}
-
-/// A collection of spans. Spans have two orthogonal attributes:
-///
-/// - they can be *primary spans*. In this case they are the locus of
-/// the error, and would be rendered with `^^^`.
-/// - they can have a *label*. In this case, the label is written next
-/// to the mark in the snippet when we render.
-#[derive(Clone)]
-pub struct MultiSpan {
- primary_spans: Vec<Span>,
- span_labels: Vec<(Span, String)>,
-}
-
-#[derive(Clone, Debug)]
-pub struct SpanLabel {
- /// The span we are going to include in the final snippet.
- pub span: Span,
-
- /// Is this a primary span? This is the "locus" of the message,
- /// and is indicated with a `^^^^` underline, versus `----`.
- pub is_primary: bool,
-
- /// What label should we attach to this span (if any)?
- pub label: Option<String>,
-}
-
-pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION };
-
-// Generic span to be used for code originating from the command line
-pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0),
- hi: BytePos(0),
- expn_id: COMMAND_LINE_EXPN };
-
-impl Span {
- /// Returns a new span representing just the end-point of this span
- pub fn end_point(self) -> Span {
- let lo = cmp::max(self.hi.0 - 1, self.lo.0);
- Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id}
- }
-
- /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
- pub fn substitute_dummy(self, other: Span) -> Span {
- if self.source_equal(&DUMMY_SP) { other } else { self }
- }
-
- pub fn contains(self, other: Span) -> bool {
- self.lo <= other.lo && other.hi <= self.hi
- }
-
- /// Return true if the spans are equal with regards to the source text.
- ///
- /// Use this instead of `==` when either span could be generated code,
- /// and you only care that they point to the same bytes of source text.
- pub fn source_equal(&self, other: &Span) -> bool {
- self.lo == other.lo && self.hi == other.hi
- }
-
- /// Returns `Some(span)`, a union of `self` and `other`, on overlap.
- pub fn merge(self, other: Span) -> Option<Span> {
- if self.expn_id != other.expn_id {
- return None;
- }
-
- if (self.lo <= other.lo && self.hi > other.lo) ||
- (self.lo >= other.lo && self.lo < other.hi) {
- Some(Span {
- lo: cmp::min(self.lo, other.lo),
- hi: cmp::max(self.hi, other.hi),
- expn_id: self.expn_id,
- })
- } else {
- None
- }
- }
-
- /// Returns `Some(span)`, where the start is trimmed by the end of `other`
- pub fn trim_start(self, other: Span) -> Option<Span> {
- if self.hi > other.hi {
- Some(Span { lo: cmp::max(self.lo, other.hi), .. self })
- } else {
- None
- }
- }
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub struct Spanned<T> {
- pub node: T,
- pub span: Span,
-}
-
-impl Encodable for Span {
- fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_struct("Span", 2, |s| {
- s.emit_struct_field("lo", 0, |s| {
- self.lo.encode(s)
- })?;
-
- s.emit_struct_field("hi", 1, |s| {
- self.hi.encode(s)
- })
- })
- }
-}
-
-impl Decodable for Span {
- fn decode<D: Decoder>(d: &mut D) -> Result<Span, D::Error> {
- d.read_struct("Span", 2, |d| {
- let lo = d.read_struct_field("lo", 0, |d| {
- BytePos::decode(d)
- })?;
-
- let hi = d.read_struct_field("hi", 1, |d| {
- BytePos::decode(d)
- })?;
-
- Ok(mk_sp(lo, hi))
- })
- }
-}
-
-fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}",
- span.lo, span.hi, span.expn_id)
-}
-
-thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter) -> fmt::Result> =
- Cell::new(default_span_debug));
-
-impl fmt::Debug for Span {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- SPAN_DEBUG.with(|span_debug| span_debug.get()(*self, f))
- }
-}
-
-pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
- respan(mk_sp(lo, hi), t)
-}
-
-pub fn respan<T>(sp: Span, t: T) -> Spanned<T> {
- Spanned {node: t, span: sp}
-}
-
-pub fn dummy_spanned<T>(t: T) -> Spanned<T> {
- respan(DUMMY_SP, t)
-}
-
-/* assuming that we're not in macro expansion */
-pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
- Span {lo: lo, hi: hi, expn_id: NO_EXPANSION}
-}
-
/// Return the span itself if it doesn't come from a macro expansion,
/// otherwise return the call site span up to the `enclosing_sp` by
/// following the `expn_info` chain.
}
}
-impl MultiSpan {
- pub fn new() -> MultiSpan {
- MultiSpan {
- primary_spans: vec![],
- span_labels: vec![]
- }
- }
-
- pub fn from_span(primary_span: Span) -> MultiSpan {
- MultiSpan {
- primary_spans: vec![primary_span],
- span_labels: vec![]
- }
- }
-
- pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
- MultiSpan {
- primary_spans: vec,
- span_labels: vec![]
- }
- }
-
- pub fn push_span_label(&mut self, span: Span, label: String) {
- self.span_labels.push((span, label));
- }
-
- /// Selects the first primary span (if any)
- pub fn primary_span(&self) -> Option<Span> {
- self.primary_spans.first().cloned()
- }
-
- /// Returns all primary spans.
- pub fn primary_spans(&self) -> &[Span] {
- &self.primary_spans
- }
-
- /// Returns the strings to highlight. We always ensure that there
- /// is an entry for each of the primary spans -- for each primary
- /// span P, if there is at least one label with span P, we return
- /// those labels (marked as primary). But otherwise we return
- /// `SpanLabel` instances with empty labels.
- pub fn span_labels(&self) -> Vec<SpanLabel> {
- let is_primary = |span| self.primary_spans.contains(&span);
- let mut span_labels = vec![];
-
- for &(span, ref label) in &self.span_labels {
- span_labels.push(SpanLabel {
- span: span,
- is_primary: is_primary(span),
- label: Some(label.clone())
- });
- }
-
- for &span in &self.primary_spans {
- if !span_labels.iter().any(|sl| sl.span == span) {
- span_labels.push(SpanLabel {
- span: span,
- is_primary: true,
- label: None
- });
- }
- }
-
- span_labels
- }
+/// The source of expansion.
+#[derive(Clone, Hash, Debug, PartialEq, Eq)]
+pub enum ExpnFormat {
+ /// e.g. #[derive(...)] <item>
+ MacroAttribute(Name),
+ /// e.g. `format!()`
+ MacroBang(Name),
}
-impl From<Span> for MultiSpan {
- fn from(span: Span) -> MultiSpan {
- MultiSpan::from_span(span)
- }
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub struct Spanned<T> {
+ pub node: T,
+ pub span: Span,
}
-// _____________________________________________________________________________
-// Loc, LocWithOpt, FileMapAndLine, FileMapAndBytePos
-//
-
-/// A source code location used for error reporting
-#[derive(Debug)]
-pub struct Loc {
- /// Information about the original source
- pub file: Rc<FileMap>,
- /// The (1-based) line number
- pub line: usize,
- /// The (0-based) column offset
- pub col: CharPos
+pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
+ respan(mk_sp(lo, hi), t)
}
-/// A source code location used as the result of lookup_char_pos_adj
-// Actually, *none* of the clients use the filename *or* file field;
-// perhaps they should just be removed.
-#[derive(Debug)]
-pub struct LocWithOpt {
- pub filename: FileName,
- pub line: usize,
- pub col: CharPos,
- pub file: Option<Rc<FileMap>>,
+pub fn respan<T>(sp: Span, t: T) -> Spanned<T> {
+ Spanned {node: t, span: sp}
}
-// used to be structural records. Better names, anyone?
-#[derive(Debug)]
-pub struct FileMapAndLine { pub fm: Rc<FileMap>, pub line: usize }
-#[derive(Debug)]
-pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
-
-
-// _____________________________________________________________________________
-// ExpnFormat, NameAndSpan, ExpnInfo, ExpnId
-//
-
-/// The source of expansion.
-#[derive(Clone, Hash, Debug, PartialEq, Eq)]
-pub enum ExpnFormat {
- /// e.g. #[derive(...)] <item>
- MacroAttribute(Name),
- /// e.g. `format!()`
- MacroBang(Name),
+pub fn dummy_spanned<T>(t: T) -> Spanned<T> {
+ respan(DUMMY_SP, t)
}
#[derive(Clone, Hash, Debug)]
pub callee: NameAndSpan
}
-#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy)]
-pub struct ExpnId(u32);
-
-pub const NO_EXPANSION: ExpnId = ExpnId(!0);
-// For code appearing from the command line
-pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1);
-
-impl ExpnId {
- pub fn from_u32(id: u32) -> ExpnId {
- ExpnId(id)
- }
-
- pub fn into_u32(self) -> u32 {
- self.0
- }
-}
-
// _____________________________________________________________________________
// FileMap, MultiByteChar, FileName, FileLines
//
-pub type FileName = String;
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct LineInfo {
- /// Index of line, starting from 0.
- pub line_index: usize,
-
- /// Column in line where span begins, starting from 0.
- pub start_col: CharPos,
-
- /// Column in line where span ends, starting from 0, exclusive.
- pub end_col: CharPos,
-}
-
-pub struct FileLines {
- pub file: Rc<FileMap>,
- pub lines: Vec<LineInfo>
-}
-
-/// Identifies an offset of a multi-byte character in a FileMap
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)]
-pub struct MultiByteChar {
- /// The absolute offset of the character in the CodeMap
- pub pos: BytePos,
- /// The number of bytes, >=2
- pub bytes: usize,
-}
-
-/// A single source in the CodeMap.
-pub struct FileMap {
- /// The name of the file that the source came from, source that doesn't
- /// originate from files has names between angle brackets by convention,
- /// e.g. `<anon>`
- pub name: FileName,
- /// The absolute path of the file that the source came from.
- pub abs_path: Option<FileName>,
- /// The complete source code
- pub src: Option<Rc<String>>,
- /// The start position of this source in the CodeMap
- pub start_pos: BytePos,
- /// The end position of this source in the CodeMap
- pub end_pos: BytePos,
- /// Locations of lines beginnings in the source code
- pub lines: RefCell<Vec<BytePos>>,
- /// Locations of multi-byte characters in the source code
- pub multibyte_chars: RefCell<Vec<MultiByteChar>>,
-}
-
-impl Encodable for FileMap {
- fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_struct("FileMap", 6, |s| {
- s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
- s.emit_struct_field("abs_path", 1, |s| self.abs_path.encode(s))?;
- s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))?;
- s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))?;
- s.emit_struct_field("lines", 4, |s| {
- let lines = self.lines.borrow();
- // store the length
- s.emit_u32(lines.len() as u32)?;
-
- if !lines.is_empty() {
- // In order to preserve some space, we exploit the fact that
- // the lines list is sorted and individual lines are
- // probably not that long. Because of that we can store lines
- // as a difference list, using as little space as possible
- // for the differences.
- let max_line_length = if lines.len() == 1 {
- 0
- } else {
- lines.windows(2)
- .map(|w| w[1] - w[0])
- .map(|bp| bp.to_usize())
- .max()
- .unwrap()
- };
-
- let bytes_per_diff: u8 = match max_line_length {
- 0 ... 0xFF => 1,
- 0x100 ... 0xFFFF => 2,
- _ => 4
- };
-
- // Encode the number of bytes used per diff.
- bytes_per_diff.encode(s)?;
-
- // Encode the first element.
- lines[0].encode(s)?;
-
- let diff_iter = (&lines[..]).windows(2)
- .map(|w| (w[1] - w[0]));
-
- match bytes_per_diff {
- 1 => for diff in diff_iter { (diff.0 as u8).encode(s)? },
- 2 => for diff in diff_iter { (diff.0 as u16).encode(s)? },
- 4 => for diff in diff_iter { diff.0.encode(s)? },
- _ => unreachable!()
- }
- }
-
- Ok(())
- })?;
- s.emit_struct_field("multibyte_chars", 5, |s| {
- (*self.multibyte_chars.borrow()).encode(s)
- })
- })
- }
-}
-
-impl Decodable for FileMap {
- fn decode<D: Decoder>(d: &mut D) -> Result<FileMap, D::Error> {
-
- d.read_struct("FileMap", 6, |d| {
- let name: String = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
- let abs_path: Option<String> =
- d.read_struct_field("abs_path", 1, |d| Decodable::decode(d))?;
- let start_pos: BytePos = d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?;
- let end_pos: BytePos = d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))?;
- let lines: Vec<BytePos> = d.read_struct_field("lines", 4, |d| {
- let num_lines: u32 = Decodable::decode(d)?;
- let mut lines = Vec::with_capacity(num_lines as usize);
-
- if num_lines > 0 {
- // Read the number of bytes used per diff.
- let bytes_per_diff: u8 = Decodable::decode(d)?;
-
- // Read the first element.
- let mut line_start: BytePos = Decodable::decode(d)?;
- lines.push(line_start);
-
- for _ in 1..num_lines {
- let diff = match bytes_per_diff {
- 1 => d.read_u8()? as u32,
- 2 => d.read_u16()? as u32,
- 4 => d.read_u32()?,
- _ => unreachable!()
- };
-
- line_start = line_start + BytePos(diff);
-
- lines.push(line_start);
- }
- }
-
- Ok(lines)
- })?;
- let multibyte_chars: Vec<MultiByteChar> =
- d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?;
- Ok(FileMap {
- name: name,
- abs_path: abs_path,
- start_pos: start_pos,
- end_pos: end_pos,
- src: None,
- lines: RefCell::new(lines),
- multibyte_chars: RefCell::new(multibyte_chars)
- })
- })
- }
-}
-
-impl fmt::Debug for FileMap {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "FileMap({})", self.name)
- }
-}
-
-impl FileMap {
- /// EFFECT: register a start-of-line offset in the
- /// table of line-beginnings.
- /// UNCHECKED INVARIANT: these offsets must be added in the right
- /// order and must be in the right places; there is shared knowledge
- /// about what ends a line between this file and parse.rs
- /// WARNING: pos param here is the offset relative to start of CodeMap,
- /// and CodeMap will append a newline when adding a filemap without a newline at the end,
- /// so the safe way to call this is with value calculated as
- /// filemap.start_pos + newline_offset_relative_to_the_start_of_filemap.
- pub fn next_line(&self, pos: BytePos) {
- // the new charpos must be > the last one (or it's the first one).
- let mut lines = self.lines.borrow_mut();
- let line_len = lines.len();
- assert!(line_len == 0 || ((*lines)[line_len - 1] < pos));
- lines.push(pos);
- }
-
- /// get a line from the list of pre-computed line-beginnings.
- /// line-number here is 0-based.
- pub fn get_line(&self, line_number: usize) -> Option<&str> {
- match self.src {
- Some(ref src) => {
- let lines = self.lines.borrow();
- lines.get(line_number).map(|&line| {
- let begin: BytePos = line - self.start_pos;
- let begin = begin.to_usize();
- // We can't use `lines.get(line_number+1)` because we might
- // be parsing when we call this function and thus the current
- // line is the last one we have line info for.
- let slice = &src[begin..];
- match slice.find('\n') {
- Some(e) => &slice[..e],
- None => slice
- }
- })
- }
- None => None
- }
- }
-
- pub fn record_multibyte_char(&self, pos: BytePos, bytes: usize) {
- assert!(bytes >=2 && bytes <= 4);
- let mbc = MultiByteChar {
- pos: pos,
- bytes: bytes,
- };
- self.multibyte_chars.borrow_mut().push(mbc);
- }
-
- pub fn is_real_file(&self) -> bool {
- !(self.name.starts_with("<") &&
- self.name.ends_with(">"))
- }
-
- pub fn is_imported(&self) -> bool {
- self.src.is_none()
- }
-
- fn count_lines(&self) -> usize {
- self.lines.borrow().len()
- }
-}
-
/// An abstraction over the fs operations used by the Parser.
pub trait FileLoader {
/// Query the existence of a file.
}
}
-pub struct MacroBacktrace {
- /// span where macro was applied to generate this code
- pub call_site: Span,
-
- /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
- pub macro_decl_name: String,
-
- /// span where macro was defined (if known)
- pub def_site_span: Option<Span>,
-}
-
-// _____________________________________________________________________________
-// SpanLinesError, SpanSnippetError, DistinctSources, MalformedCodemapPositions
-//
-
-pub type FileLinesResult = Result<FileLines, SpanLinesError>;
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub enum SpanLinesError {
- IllFormedSpan(Span),
- DistinctSources(DistinctSources),
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub enum SpanSnippetError {
- IllFormedSpan(Span),
- DistinctSources(DistinctSources),
- MalformedForCodemap(MalformedCodemapPositions),
- SourceNotAvailable { filename: String }
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct DistinctSources {
- begin: (String, BytePos),
- end: (String, BytePos)
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct MalformedCodemapPositions {
- name: String,
- source_len: usize,
- begin_pos: BytePos,
- end_pos: BytePos
+impl CodeMapper for CodeMap {
+ fn lookup_char_pos(&self, pos: BytePos) -> Loc {
+ self.lookup_char_pos(pos)
+ }
+ fn span_to_lines(&self, sp: Span) -> FileLinesResult {
+ self.span_to_lines(sp)
+ }
+ fn span_to_string(&self, sp: Span) -> String {
+ self.span_to_string(sp)
+ }
+ fn span_to_filename(&self, sp: Span) -> FileName {
+ self.span_to_filename(sp)
+ }
+ fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
+ self.macro_backtrace(span)
+ }
}
-
// _____________________________________________________________________________
// Tests
//
#[cfg(test)]
mod tests {
use super::*;
+ use errors::{Level, CodeSuggestion};
+ use errors::emitter::EmitterWriter;
+ use errors::snippet::{SnippetData, RenderedLine, FormatMode};
+ use std::sync::{Arc, Mutex};
+ use std::io::{self, Write};
+ use std::str::from_utf8;
+ use std::rc::Rc;
#[test]
fn t1 () {
blork.rs:1:1: 1:12\n `first line.`\n");
}
+ /// Returns the span corresponding to the `n`th occurrence of
+ /// `substring` in `source_text`.
+ trait CodeMapExtension {
+ fn span_substr(&self,
+ file: &Rc<FileMap>,
+ source_text: &str,
+ substring: &str,
+ n: usize)
+ -> Span;
+ }
+
+ impl CodeMapExtension for CodeMap {
+ fn span_substr(&self,
+ file: &Rc<FileMap>,
+ source_text: &str,
+ substring: &str,
+ n: usize)
+ -> Span
+ {
+ println!("span_substr(file={:?}/{:?}, substring={:?}, n={})",
+ file.name, file.start_pos, substring, n);
+ let mut i = 0;
+ let mut hi = 0;
+ loop {
+ let offset = source_text[hi..].find(substring).unwrap_or_else(|| {
+ panic!("source_text `{}` does not have {} occurrences of `{}`, only {}",
+ source_text, n, substring, i);
+ });
+ let lo = hi + offset;
+ hi = lo + substring.len();
+ if i == n {
+ let span = Span {
+ lo: BytePos(lo as u32 + file.start_pos.0),
+ hi: BytePos(hi as u32 + file.start_pos.0),
+ expn_id: NO_EXPANSION,
+ };
+ assert_eq!(&self.span_to_snippet(span).unwrap()[..],
+ substring);
+ return span;
+ }
+ i += 1;
+ }
+ }
+ }
+
+ fn splice(start: Span, end: Span) -> Span {
+ Span {
+ lo: start.lo,
+ hi: end.hi,
+ expn_id: NO_EXPANSION,
+ }
+ }
+
+ fn make_string(lines: &[RenderedLine]) -> String {
+ lines.iter()
+ .flat_map(|rl| {
+ rl.text.iter()
+ .map(|s| &s.text[..])
+ .chain(Some("\n"))
+ })
+ .collect()
+ }
+
fn init_expansion_chain(cm: &CodeMap) -> Span {
// Creates an expansion chain containing two recursive calls
// root -> expA -> expA -> expB -> expB -> end
";
assert_eq!(sstr, res_str);
}
+
+ struct Sink(Arc<Mutex<Vec<u8>>>);
+ impl Write for Sink {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ Write::write(&mut *self.0.lock().unwrap(), data)
+ }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+ }
+
+ // Diagnostic doesn't align properly in span where line number increases by one digit
+ #[test]
+ fn test_hilight_suggestion_issue_11715() {
+ let data = Arc::new(Mutex::new(Vec::new()));
+ let cm = Rc::new(CodeMap::new());
+ let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())),
+ None,
+ cm.clone(),
+ FormatMode::NewErrorFormat);
+ let content = "abcdefg
+ koksi
+ line3
+ line4
+ cinq
+ line6
+ line7
+ line8
+ line9
+ line10
+ e-lä-vän
+ tolv
+ dreizehn
+ ";
+ let file = cm.new_filemap_and_lines("dummy.txt", None, content);
+ let start = file.lines.borrow()[10];
+ let end = file.lines.borrow()[11];
+ let sp = mk_sp(start, end);
+ let lvl = Level::Error;
+ println!("highlight_lines");
+ ew.highlight_lines(&sp.into(), lvl).unwrap();
+ println!("done");
+ let vec = data.lock().unwrap().clone();
+ let vec: &[u8] = &vec;
+ let str = from_utf8(vec).unwrap();
+ println!("r#\"\n{}\"#", str);
+ assert_eq!(str, &r#"
+ --> dummy.txt:11:1
+ |>
+11 |> e-lä-vän
+ |> ^
+"#[1..]);
+ }
+
+ #[test]
+ fn test_single_span_splice() {
+ // Test that a `MultiSpan` containing a single span splices a substition correctly
+ let cm = CodeMap::new();
+ let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
+ let selection = " \n ~~\n~~~\n~~~~~ \n \n";
+ cm.new_filemap_and_lines("blork.rs", None, inputtext);
+ let sp = span_from_selection(inputtext, selection);
+ let msp: MultiSpan = sp.into();
+
+ // check that we are extracting the text we thought we were extracting
+ assert_eq!(&cm.span_to_snippet(sp).unwrap(), "BB\nCCC\nDDDDD");
+
+ let substitute = "ZZZZZZ".to_owned();
+ let expected = "bbbbZZZZZZddddd";
+ let suggest = CodeSuggestion {
+ msp: msp,
+ substitutes: vec![substitute],
+ };
+ assert_eq!(suggest.splice_lines(&cm), expected);
+ }
+
+ #[test]
+ fn test_multi_span_splice() {
+ // Test that a `MultiSpan` containing multiple spans splices a substition correctly
+ let cm = CodeMap::new();
+ let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
+ let selection1 = " \n \n \n \n ~ \n"; // intentionally out of order
+ let selection2 = " \n ~~\n~~~\n~~~~~ \n \n";
+ cm.new_filemap_and_lines("blork.rs", None, inputtext);
+ let sp1 = span_from_selection(inputtext, selection1);
+ let sp2 = span_from_selection(inputtext, selection2);
+ let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]);
+
+ let expected = "bbbbZZZZZZddddd\neXYZe";
+ let suggest = CodeSuggestion {
+ msp: msp,
+ substitutes: vec!["ZZZZZZ".to_owned(),
+ "XYZ".to_owned()]
+ };
+
+ assert_eq!(suggest.splice_lines(&cm), expected);
+ }
+
+ #[test]
+ fn test_multispan_highlight() {
+ let data = Arc::new(Mutex::new(Vec::new()));
+ let cm = Rc::new(CodeMap::new());
+ let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())),
+ None,
+ cm.clone(),
+ FormatMode::NewErrorFormat);
+
+ let inp = "_____aaaaaa____bbbbbb__cccccdd_";
+ let sp1 = " ~~~~~~ ";
+ let sp2 = " ~~~~~~ ";
+ let sp3 = " ~~~~~ ";
+ let sp4 = " ~~~~ ";
+ let sp34 = " ~~~~~~~ ";
+
+ let expect_start = &r#"
+ --> dummy.txt:1:6
+ |>
+1 |> _____aaaaaa____bbbbbb__cccccdd_
+ |> ^^^^^^ ^^^^^^ ^^^^^^^
+"#[1..];
+
+ let span = |sp, expected| {
+ let sp = span_from_selection(inp, sp);
+ assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected);
+ sp
+ };
+ cm.new_filemap_and_lines("dummy.txt", None, inp);
+ let sp1 = span(sp1, "aaaaaa");
+ let sp2 = span(sp2, "bbbbbb");
+ let sp3 = span(sp3, "ccccc");
+ let sp4 = span(sp4, "ccdd");
+ let sp34 = span(sp34, "cccccdd");
+
+ let spans = vec![sp1, sp2, sp3, sp4];
+
+ let test = |expected, highlight: &mut FnMut()| {
+ data.lock().unwrap().clear();
+ highlight();
+ let vec = data.lock().unwrap().clone();
+ let actual = from_utf8(&vec[..]).unwrap();
+ println!("actual=\n{}", actual);
+ assert_eq!(actual, expected);
+ };
+
+ let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]);
+ test(expect_start, &mut || {
+ diag.highlight_lines(&msp, Level::Error).unwrap();
+ });
+ test(expect_start, &mut || {
+ let msp = MultiSpan::from_spans(spans.clone());
+ diag.highlight_lines(&msp, Level::Error).unwrap();
+ });
+ }
+
+ #[test]
+ fn test_huge_multispan_highlight() {
+ let data = Arc::new(Mutex::new(Vec::new()));
+ let cm = Rc::new(CodeMap::new());
+ let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())),
+ None,
+ cm.clone(),
+ FormatMode::NewErrorFormat);
+
+ let inp = "aaaaa\n\
+ aaaaa\n\
+ aaaaa\n\
+ bbbbb\n\
+ ccccc\n\
+ xxxxx\n\
+ yyyyy\n\
+ _____\n\
+ ddd__eee_\n\
+ elided\n\
+ __f_gg";
+ let file = cm.new_filemap_and_lines("dummy.txt", None, inp);
+
+ let span = |lo, hi, (off_lo, off_hi)| {
+ let lines = file.lines.borrow();
+ let (mut lo, mut hi): (BytePos, BytePos) = (lines[lo], lines[hi]);
+ lo.0 += off_lo;
+ hi.0 += off_hi;
+ mk_sp(lo, hi)
+ };
+ let sp0 = span(4, 6, (0, 5));
+ let sp1 = span(0, 6, (0, 5));
+ let sp2 = span(8, 8, (0, 3));
+ let sp3 = span(8, 8, (5, 8));
+ let sp4 = span(10, 10, (2, 3));
+ let sp5 = span(10, 10, (4, 6));
+
+ let expect0 = &r#"
+ --> dummy.txt:5:1
+ |>
+5 |> ccccc
+ |> ^
+...
+9 |> ddd__eee_
+ |> ^^^ ^^^
+10 |> elided
+11 |> __f_gg
+ |> ^ ^^
+"#[1..];
+
+ let expect = &r#"
+ --> dummy.txt:1:1
+ |>
+1 |> aaaaa
+ |> ^
+...
+9 |> ddd__eee_
+ |> ^^^ ^^^
+10 |> elided
+11 |> __f_gg
+ |> ^ ^^
+"#[1..];
+
+ macro_rules! test {
+ ($expected: expr, $highlight: expr) => ({
+ data.lock().unwrap().clear();
+ $highlight();
+ let vec = data.lock().unwrap().clone();
+ let actual = from_utf8(&vec[..]).unwrap();
+ println!("actual:");
+ println!("{}", actual);
+ println!("expected:");
+ println!("{}", $expected);
+ assert_eq!(&actual[..], &$expected[..]);
+ });
+ }
+
+ let msp0 = MultiSpan::from_spans(vec![sp0, sp2, sp3, sp4, sp5]);
+ let msp = MultiSpan::from_spans(vec![sp1, sp2, sp3, sp4, sp5]);
+
+ test!(expect0, || {
+ diag.highlight_lines(&msp0, Level::Error).unwrap();
+ });
+ test!(expect, || {
+ diag.highlight_lines(&msp, Level::Error).unwrap();
+ });
+ }
+
+ #[test]
+ fn tab() {
+ let file_text = "
+fn foo() {
+\tbar;
+}
+";
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+ let span_bar = cm.span_substr(&foo, file_text, "bar", 0);
+
+ let mut snippet = SnippetData::new(cm, Some(span_bar), FormatMode::NewErrorFormat);
+ snippet.push(span_bar, true, None);
+
+ let lines = snippet.render_lines();
+ let text = make_string(&lines);
+ assert_eq!(&text[..], &"
+ --> foo.rs:3:2
+ |>
+3 |> \tbar;
+ |> \t^^^
+"[1..]);
+ }
+
+ #[test]
+ fn one_line() {
+ let file_text = r#"
+fn foo() {
+ vec.push(vec.pop().unwrap());
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+ let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
+ let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
+ let span_semi = cm.span_substr(&foo, file_text, ";", 0);
+
+ let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat);
+ snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
+ snippet.push(span_vec1, false, Some(format!("error occurs here")));
+ snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
+
+ let lines = snippet.render_lines();
+ println!("{:#?}", lines);
+
+ let text: String = make_string(&lines);
+
+ println!("text=\n{}", text);
+ assert_eq!(&text[..], &r#"
+ ::: foo.rs
+ |>
+3 |> vec.push(vec.pop().unwrap());
+ |> --- --- - previous borrow ends here
+ |> | |
+ |> | error occurs here
+ |> previous borrow of `vec` occurs here
+"#[1..]);
+ }
+
+ #[test]
+ fn two_files() {
+ let file_text_foo = r#"
+fn foo() {
+ vec.push(vec.pop().unwrap());
+}
+"#;
+
+ let file_text_bar = r#"
+fn bar() {
+ // these blank links here
+ // serve to ensure that the line numbers
+ // from bar.rs
+ // require more digits
+
+
+
+
+
+
+
+
+
+
+ vec.push();
+
+ // this line will get elided
+
+ vec.pop().unwrap());
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo_map = cm.new_filemap_and_lines("foo.rs", None, file_text_foo);
+ let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0);
+ let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1);
+ let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0);
+
+ let bar_map = cm.new_filemap_and_lines("bar.rs", None, file_text_bar);
+ let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0);
+ let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1);
+ let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0);
+
+ let mut snippet = SnippetData::new(cm, Some(span_foo_vec1), FormatMode::NewErrorFormat);
+ snippet.push(span_foo_vec0, false, Some(format!("a")));
+ snippet.push(span_foo_vec1, true, Some(format!("b")));
+ snippet.push(span_foo_semi, false, Some(format!("c")));
+ snippet.push(span_bar_vec0, false, Some(format!("d")));
+ snippet.push(span_bar_vec1, false, Some(format!("e")));
+ snippet.push(span_bar_semi, false, Some(format!("f")));
+
+ let lines = snippet.render_lines();
+ println!("{:#?}", lines);
+
+ let text: String = make_string(&lines);
+
+ println!("text=\n{}", text);
+
+ // Note that the `|>` remain aligned across both files:
+ assert_eq!(&text[..], &r#"
+ --> foo.rs:3:14
+ |>
+3 |> vec.push(vec.pop().unwrap());
+ |> --- ^^^ - c
+ |> | |
+ |> | b
+ |> a
+ ::: bar.rs
+ |>
+17 |> vec.push();
+ |> --- - f
+ |> |
+ |> d
+...
+21 |> vec.pop().unwrap());
+ |> --- e
+"#[1..]);
+ }
+
+ #[test]
+ fn multi_line() {
+ let file_text = r#"
+fn foo() {
+ let name = find_id(&data, 22).unwrap();
+
+ // Add one more item we forgot to the vector. Silly us.
+ data.push(Data { name: format!("Hera"), id: 66 });
+
+ // Print everything out.
+ println!("Name: {:?}", name);
+ println!("Data: {:?}", data);
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+ let span_data0 = cm.span_substr(&foo, file_text, "data", 0);
+ let span_data1 = cm.span_substr(&foo, file_text, "data", 1);
+ let span_rbrace = cm.span_substr(&foo, file_text, "}", 3);
+
+ let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat);
+ snippet.push(span_data0, false, Some(format!("immutable borrow begins here")));
+ snippet.push(span_data1, false, Some(format!("mutable borrow occurs here")));
+ snippet.push(span_rbrace, false, Some(format!("immutable borrow ends here")));
+
+ let lines = snippet.render_lines();
+ println!("{:#?}", lines);
+
+ let text: String = make_string(&lines);
+
+ println!("text=\n{}", text);
+ assert_eq!(&text[..], &r#"
+ ::: foo.rs
+ |>
+3 |> let name = find_id(&data, 22).unwrap();
+ |> ---- immutable borrow begins here
+...
+6 |> data.push(Data { name: format!("Hera"), id: 66 });
+ |> ---- mutable borrow occurs here
+...
+11 |> }
+ |> - immutable borrow ends here
+"#[1..]);
+ }
+
+ #[test]
+ fn overlapping() {
+ let file_text = r#"
+fn foo() {
+ vec.push(vec.pop().unwrap());
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+ let span0 = cm.span_substr(&foo, file_text, "vec.push", 0);
+ let span1 = cm.span_substr(&foo, file_text, "vec", 0);
+ let span2 = cm.span_substr(&foo, file_text, "ec.push", 0);
+ let span3 = cm.span_substr(&foo, file_text, "unwrap", 0);
+
+ let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat);
+ snippet.push(span0, false, Some(format!("A")));
+ snippet.push(span1, false, Some(format!("B")));
+ snippet.push(span2, false, Some(format!("C")));
+ snippet.push(span3, false, Some(format!("D")));
+
+ let lines = snippet.render_lines();
+ println!("{:#?}", lines);
+ let text: String = make_string(&lines);
+
+ println!("text=r#\"\n{}\".trim_left()", text);
+ assert_eq!(&text[..], &r#"
+ ::: foo.rs
+ |>
+3 |> vec.push(vec.pop().unwrap());
+ |> -------- ------ D
+ |> ||
+ |> |C
+ |> A
+ |> B
+"#[1..]);
+ }
+
+ #[test]
+ fn one_line_out_of_order() {
+ let file_text = r#"
+fn foo() {
+ vec.push(vec.pop().unwrap());
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+ let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
+ let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
+ let span_semi = cm.span_substr(&foo, file_text, ";", 0);
+
+ // intentionally don't push the snippets left to right
+ let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat);
+ snippet.push(span_vec1, false, Some(format!("error occurs here")));
+ snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
+ snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
+
+ let lines = snippet.render_lines();
+ println!("{:#?}", lines);
+ let text: String = make_string(&lines);
+
+ println!("text=r#\"\n{}\".trim_left()", text);
+ assert_eq!(&text[..], &r#"
+ ::: foo.rs
+ |>
+3 |> vec.push(vec.pop().unwrap());
+ |> --- --- - previous borrow ends here
+ |> | |
+ |> | error occurs here
+ |> previous borrow of `vec` occurs here
+"#[1..]);
+ }
+
+ #[test]
+ fn elide_unnecessary_lines() {
+ let file_text = r#"
+fn foo() {
+ let mut vec = vec![0, 1, 2];
+ let mut vec2 = vec;
+ vec2.push(3);
+ vec2.push(4);
+ vec2.push(5);
+ vec2.push(6);
+ vec.push(7);
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+ let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3);
+ let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8);
+
+ let mut snippet = SnippetData::new(cm, None, FormatMode::NewErrorFormat);
+ snippet.push(span_vec0, false, Some(format!("`vec` moved here because it \
+ has type `collections::vec::Vec<i32>`")));
+ snippet.push(span_vec1, false, Some(format!("use of moved value: `vec`")));
+
+ let lines = snippet.render_lines();
+ println!("{:#?}", lines);
+ let text: String = make_string(&lines);
+ println!("text=r#\"\n{}\".trim_left()", text);
+ assert_eq!(&text[..], &r#"
+ ::: foo.rs
+ |>
+4 |> let mut vec2 = vec;
+ |> --- `vec` moved here because it has type `collections::vec::Vec<i32>`
+...
+9 |> vec.push(7);
+ |> --- use of moved value: `vec`
+"#[1..]);
+ }
+
+ #[test]
+ fn spans_without_labels() {
+ let file_text = r#"
+fn foo() {
+ let mut vec = vec![0, 1, 2];
+ let mut vec2 = vec;
+ vec2.push(3);
+ vec2.push(4);
+ vec2.push(5);
+ vec2.push(6);
+ vec.push(7);
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+
+ let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat);
+ for i in 0..4 {
+ let span_veci = cm.span_substr(&foo, file_text, "vec", i);
+ snippet.push(span_veci, false, None);
+ }
+
+ let lines = snippet.render_lines();
+ let text: String = make_string(&lines);
+ println!("text=&r#\"\n{}\n\"#[1..]", text);
+ assert_eq!(text, &r#"
+ ::: foo.rs
+ |>
+3 |> let mut vec = vec![0, 1, 2];
+ |> --- ---
+4 |> let mut vec2 = vec;
+ |> --- ---
+"#[1..]);
+ }
+
+ #[test]
+ fn span_long_selection() {
+ let file_text = r#"
+impl SomeTrait for () {
+ fn foo(x: u32) {
+ // impl 1
+ // impl 2
+ // impl 3
+ }
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+
+ let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat);
+ let fn_span = cm.span_substr(&foo, file_text, "fn", 0);
+ let rbrace_span = cm.span_substr(&foo, file_text, "}", 0);
+ snippet.push(splice(fn_span, rbrace_span), false, None);
+ let lines = snippet.render_lines();
+ let text: String = make_string(&lines);
+ println!("r#\"\n{}\"", text);
+ assert_eq!(text, &r#"
+ ::: foo.rs
+ |>
+3 |> fn foo(x: u32) {
+ |> -
+"#[1..]);
+ }
+
+ #[test]
+ fn span_overlap_label() {
+ // Test that we don't put `x_span` to the right of its highlight,
+ // since there is another highlight that overlaps it.
+
+ let file_text = r#"
+ fn foo(x: u32) {
+ }
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+
+ let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat);
+ let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0);
+ let x_span = cm.span_substr(&foo, file_text, "x", 0);
+ snippet.push(fn_span, false, Some(format!("fn_span")));
+ snippet.push(x_span, false, Some(format!("x_span")));
+ let lines = snippet.render_lines();
+ let text: String = make_string(&lines);
+ println!("r#\"\n{}\"", text);
+ assert_eq!(text, &r#"
+ ::: foo.rs
+ |>
+2 |> fn foo(x: u32) {
+ |> --------------
+ |> | |
+ |> | x_span
+ |> fn_span
+"#[1..]);
+ }
+
+ #[test]
+ fn span_overlap_label2() {
+ // Test that we don't put `x_span` to the right of its highlight,
+ // since there is another highlight that overlaps it. In this
+ // case, the overlap is only at the beginning, but it's still
+ // better to show the beginning more clearly.
+
+ let file_text = r#"
+ fn foo(x: u32) {
+ }
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+
+ let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat);
+ let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0);
+ let x_span = cm.span_substr(&foo, file_text, "x: u32)", 0);
+ snippet.push(fn_span, false, Some(format!("fn_span")));
+ snippet.push(x_span, false, Some(format!("x_span")));
+ let lines = snippet.render_lines();
+ let text: String = make_string(&lines);
+ println!("r#\"\n{}\"", text);
+ assert_eq!(text, &r#"
+ ::: foo.rs
+ |>
+2 |> fn foo(x: u32) {
+ |> --------------
+ |> | |
+ |> | x_span
+ |> fn_span
+"#[1..]);
+ }
+
+ #[test]
+ fn span_overlap_label3() {
+ // Test that we don't put `x_span` to the right of its highlight,
+ // since there is another highlight that overlaps it. In this
+ // case, the overlap is only at the beginning, but it's still
+ // better to show the beginning more clearly.
+
+ let file_text = r#"
+ fn foo() {
+ let closure = || {
+ inner
+ };
+ }
+}
+"#;
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+
+ let mut snippet = SnippetData::new(cm.clone(), None, FormatMode::NewErrorFormat);
+
+ let closure_span = {
+ let closure_start_span = cm.span_substr(&foo, file_text, "||", 0);
+ let closure_end_span = cm.span_substr(&foo, file_text, "}", 0);
+ splice(closure_start_span, closure_end_span)
+ };
+
+ let inner_span = cm.span_substr(&foo, file_text, "inner", 0);
+
+ snippet.push(closure_span, false, Some(format!("foo")));
+ snippet.push(inner_span, false, Some(format!("bar")));
+
+ let lines = snippet.render_lines();
+ let text: String = make_string(&lines);
+ println!("r#\"\n{}\"", text);
+ assert_eq!(text, &r#"
+ ::: foo.rs
+ |>
+3 |> let closure = || {
+ |> - foo
+4 |> inner
+ |> ----- bar
+"#[1..]);
+ }
+
+ #[test]
+ fn span_empty() {
+ // In one of the unit tests, we found that the parser sometimes
+ // gives empty spans, and in particular it supplied an EOF span
+ // like this one, which points at the very end. We want to
+ // fallback gracefully in this case.
+
+ let file_text = r#"
+fn main() {
+ struct Foo;
+
+ impl !Sync for Foo {}
+
+ unsafe impl Send for &'static Foo {
+ // error: cross-crate traits with a default impl, like `core::marker::Send`,
+ // can only be implemented for a struct/enum type, not
+ // `&'static Foo`
+}"#;
+
+
+ let cm = Rc::new(CodeMap::new());
+ let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
+
+ let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1);
+ rbrace_span.lo = rbrace_span.hi;
+
+ let mut snippet = SnippetData::new(cm.clone(),
+ Some(rbrace_span),
+ FormatMode::NewErrorFormat);
+ snippet.push(rbrace_span, false, None);
+ let lines = snippet.render_lines();
+ let text: String = make_string(&lines);
+ println!("r#\"\n{}\"", text);
+ assert_eq!(text, &r#"
+ --> foo.rs:11:2
+ |>
+11 |> }
+ |> -
+"#[1..]);
+ }
}
use attr::{AttrMetaMethods, HasAttrs};
use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
use fold::Folder;
-use {ast, fold, attr};
+use {fold, attr};
+use ast;
use codemap::{Spanned, respan};
use parse::{ParseSess, token};
use ptr::P;
use std::error::Error;
use rustc_serialize::json::as_json;
-use codemap::Span;
+use syntax_pos::Span;
use ext::base::ExtCtxt;
use diagnostics::plugin::{ErrorMap, ErrorInfo};
use ast;
use ast::{Ident, Name, TokenTree};
-use codemap::Span;
+use syntax_pos::Span;
use ext::base::{ExtCtxt, MacEager, MacResult};
use ext::build::AstBuilder;
use parse::token;
use diagnostics::metadata::output_metadata;
+pub use errors::*;
+
// Maximum width of any line in an extended error description (inclusive).
const MAX_DESCRIPTION_WIDTH: usize = 80;
+++ /dev/null
-// Copyright 2014 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::collections::HashMap;
-
-#[derive(Clone)]
-pub struct Registry {
- descriptions: HashMap<&'static str, &'static str>
-}
-
-impl Registry {
- pub fn new(descriptions: &[(&'static str, &'static str)]) -> Registry {
- Registry { descriptions: descriptions.iter().cloned().collect() }
- }
-
- pub fn find_description(&self, code: &str) -> Option<&'static str> {
- self.descriptions.get(code).cloned()
- }
-}
+++ /dev/null
-// Copyright 2012-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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use self::Destination::*;
-
-use codemap::{self, COMMAND_LINE_SP, DUMMY_SP, Span, MultiSpan};
-use diagnostics;
-
-use errors::check_old_skool;
-use errors::{Level, RenderSpan, CodeSuggestion, DiagnosticBuilder};
-use errors::RenderSpan::*;
-use errors::Level::*;
-use errors::snippet::{RenderedLineKind, SnippetData, Style};
-
-use std::{cmp, fmt};
-use std::io::prelude::*;
-use std::io;
-use std::rc::Rc;
-use term;
-
-/// Emitter trait for emitting errors. Do not implement this directly:
-/// implement `CoreEmitter` instead.
-pub trait Emitter {
- /// Emit a standalone diagnostic message.
- fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level);
-
- /// Emit a structured diagnostic.
- fn emit_struct(&mut self, db: &DiagnosticBuilder);
-}
-
-pub trait CoreEmitter {
- fn emit_message(&mut self,
- rsp: &RenderSpan,
- msg: &str,
- code: Option<&str>,
- lvl: Level,
- is_header: bool,
- show_snippet: bool);
-}
-
-impl<T: CoreEmitter> Emitter for T {
- fn emit(&mut self,
- msp: &MultiSpan,
- msg: &str,
- code: Option<&str>,
- lvl: Level) {
- self.emit_message(&FullSpan(msp.clone()),
- msg,
- code,
- lvl,
- true,
- true);
- }
-
- fn emit_struct(&mut self, db: &DiagnosticBuilder) {
- let old_school = check_old_skool();
- let db_span = FullSpan(db.span.clone());
- self.emit_message(&FullSpan(db.span.clone()),
- &db.message,
- db.code.as_ref().map(|s| &**s),
- db.level,
- true,
- true);
- for child in &db.children {
- let render_span = child.render_span
- .clone()
- .unwrap_or_else(
- || FullSpan(child.span.clone()));
-
- if !old_school {
- self.emit_message(&render_span,
- &child.message,
- None,
- child.level,
- false,
- true);
- } else {
- let (render_span, show_snippet) = match render_span.span().primary_span() {
- None => (db_span.clone(), false),
- _ => (render_span, true)
- };
- self.emit_message(&render_span,
- &child.message,
- None,
- child.level,
- false,
- show_snippet);
- }
- }
- }
-}
-
-/// maximum number of lines we will print for each error; arbitrary.
-pub const MAX_HIGHLIGHT_LINES: usize = 6;
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum ColorConfig {
- Auto,
- Always,
- Never,
-}
-
-impl ColorConfig {
- fn use_color(&self) -> bool {
- match *self {
- ColorConfig::Always => true,
- ColorConfig::Never => false,
- ColorConfig::Auto => stderr_isatty(),
- }
- }
-}
-
-/// A basic emitter for when we don't have access to a codemap or registry. Used
-/// for reporting very early errors, etc.
-pub struct BasicEmitter {
- dst: Destination,
-}
-
-impl CoreEmitter for BasicEmitter {
- fn emit_message(&mut self,
- _rsp: &RenderSpan,
- msg: &str,
- code: Option<&str>,
- lvl: Level,
- _is_header: bool,
- _show_snippet: bool) {
- // we ignore the span as we have no access to a codemap at this point
- if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) {
- panic!("failed to print diagnostics: {:?}", e);
- }
- }
-}
-
-impl BasicEmitter {
- pub fn stderr(color_config: ColorConfig) -> BasicEmitter {
- if color_config.use_color() {
- let dst = Destination::from_stderr();
- BasicEmitter { dst: dst }
- } else {
- BasicEmitter { dst: Raw(Box::new(io::stderr())) }
- }
- }
-}
-
-pub struct EmitterWriter {
- dst: Destination,
- registry: Option<diagnostics::registry::Registry>,
- cm: Rc<codemap::CodeMap>,
-
- /// Is this the first error emitted thus far? If not, we emit a
- /// `\n` before the top-level errors.
- first: bool,
-
- // For now, allow an old-school mode while we transition
- old_school: bool,
-}
-
-impl CoreEmitter for EmitterWriter {
- fn emit_message(&mut self,
- rsp: &RenderSpan,
- msg: &str,
- code: Option<&str>,
- lvl: Level,
- is_header: bool,
- show_snippet: bool) {
- match self.emit_message_(rsp, msg, code, lvl, is_header, show_snippet) {
- Ok(()) => { }
- Err(e) => panic!("failed to emit error: {}", e)
- }
- }
-}
-
-/// Do not use this for messages that end in `\n` – use `println_maybe_styled` instead. See
-/// `EmitterWriter::print_maybe_styled` for details.
-macro_rules! print_maybe_styled {
- ($dst: expr, $style: expr, $($arg: tt)*) => {
- $dst.print_maybe_styled(format_args!($($arg)*), $style, false)
- }
-}
-
-macro_rules! println_maybe_styled {
- ($dst: expr, $style: expr, $($arg: tt)*) => {
- $dst.print_maybe_styled(format_args!($($arg)*), $style, true)
- }
-}
-
-impl EmitterWriter {
- pub fn stderr(color_config: ColorConfig,
- registry: Option<diagnostics::registry::Registry>,
- code_map: Rc<codemap::CodeMap>)
- -> EmitterWriter {
- let old_school = check_old_skool();
- if color_config.use_color() {
- let dst = Destination::from_stderr();
- EmitterWriter { dst: dst,
- registry: registry,
- cm: code_map,
- first: true,
- old_school: old_school }
- } else {
- EmitterWriter { dst: Raw(Box::new(io::stderr())),
- registry: registry,
- cm: code_map,
- first: true,
- old_school: old_school }
- }
- }
-
- pub fn new(dst: Box<Write + Send>,
- registry: Option<diagnostics::registry::Registry>,
- code_map: Rc<codemap::CodeMap>)
- -> EmitterWriter {
- let old_school = check_old_skool();
- EmitterWriter { dst: Raw(dst),
- registry: registry,
- cm: code_map,
- first: true,
- old_school: old_school }
- }
-
- fn emit_message_(&mut self,
- rsp: &RenderSpan,
- msg: &str,
- code: Option<&str>,
- lvl: Level,
- is_header: bool,
- show_snippet: bool)
- -> io::Result<()> {
- if is_header {
- if self.first {
- self.first = false;
- } else {
- if !self.old_school {
- write!(self.dst, "\n")?;
- }
- }
- }
-
- match code {
- Some(code) if self.registry.as_ref()
- .and_then(|registry| registry.find_description(code))
- .is_some() => {
- let code_with_explain = String::from("--explain ") + code;
- if self.old_school {
- let loc = match rsp.span().primary_span() {
- Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
- Some(ps) => self.cm.span_to_string(ps),
- None => "".to_string()
- };
- print_diagnostic(&mut self.dst, &loc, lvl, msg, Some(code))?
- }
- else {
- print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))?
- }
- }
- _ => {
- if self.old_school {
- let loc = match rsp.span().primary_span() {
- Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
- Some(ps) => self.cm.span_to_string(ps),
- None => "".to_string()
- };
- print_diagnostic(&mut self.dst, &loc, lvl, msg, code)?
- }
- else {
- print_diagnostic(&mut self.dst, "", lvl, msg, code)?
- }
- }
- }
-
- if !show_snippet {
- return Ok(());
- }
-
- // Watch out for various nasty special spans; don't try to
- // print any filename or anything for those.
- match rsp.span().primary_span() {
- Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => {
- return Ok(());
- }
- _ => { }
- }
-
- // Otherwise, print out the snippet etc as needed.
- match *rsp {
- FullSpan(ref msp) => {
- self.highlight_lines(msp, lvl)?;
- if let Some(primary_span) = msp.primary_span() {
- self.print_macro_backtrace(primary_span)?;
- }
- }
- Suggestion(ref suggestion) => {
- self.highlight_suggestion(suggestion)?;
- if let Some(primary_span) = rsp.span().primary_span() {
- self.print_macro_backtrace(primary_span)?;
- }
- }
- }
- if self.old_school {
- match code {
- Some(code) if self.registry.as_ref()
- .and_then(|registry| registry.find_description(code))
- .is_some() => {
- let loc = match rsp.span().primary_span() {
- Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
- Some(ps) => self.cm.span_to_string(ps),
- None => "".to_string()
- };
- let msg = "run `rustc --explain ".to_string() + &code.to_string() +
- "` to see a detailed explanation";
- print_diagnostic(&mut self.dst, &loc, Level::Help, &msg,
- None)?
- }
- _ => ()
- }
- }
- Ok(())
- }
-
- fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()>
- {
- let primary_span = suggestion.msp.primary_span().unwrap();
- let lines = self.cm.span_to_lines(primary_span).unwrap();
- assert!(!lines.lines.is_empty());
-
- let complete = suggestion.splice_lines(&self.cm);
- let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES);
- let display_lines = &lines.lines[..line_count];
-
- let fm = &*lines.file;
- // Calculate the widest number to format evenly
- let max_digits = line_num_max_digits(display_lines.last().unwrap());
-
- // print the suggestion without any line numbers, but leave
- // space for them. This helps with lining up with previous
- // snippets from the actual error being reported.
- let mut lines = complete.lines();
- for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
- write!(&mut self.dst, "{0}:{1:2$} {3}\n",
- fm.name, "", max_digits, line)?;
- }
-
- // if we elided some lines, add an ellipsis
- if let Some(_) = lines.next() {
- write!(&mut self.dst, "{0:1$} {0:2$} ...\n",
- "", fm.name.len(), max_digits)?;
- }
-
- Ok(())
- }
-
- fn highlight_lines(&mut self,
- msp: &MultiSpan,
- lvl: Level)
- -> io::Result<()>
- {
- let mut snippet_data = SnippetData::new(self.cm.clone(),
- msp.primary_span());
- if self.old_school {
- let mut output_vec = vec![];
-
- for span_label in msp.span_labels() {
- let mut snippet_data = SnippetData::new(self.cm.clone(),
- Some(span_label.span));
-
- snippet_data.push(span_label.span,
- span_label.is_primary,
- span_label.label);
- if span_label.is_primary {
- output_vec.insert(0, snippet_data);
- }
- else {
- output_vec.push(snippet_data);
- }
- }
-
- for snippet_data in output_vec.iter() {
- let rendered_lines = snippet_data.render_lines();
- for rendered_line in &rendered_lines {
- for styled_string in &rendered_line.text {
- self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
- write!(&mut self.dst, "{}", styled_string.text)?;
- self.dst.reset_attrs()?;
- }
- write!(&mut self.dst, "\n")?;
- }
- }
- }
- else {
- for span_label in msp.span_labels() {
- snippet_data.push(span_label.span,
- span_label.is_primary,
- span_label.label);
- }
- let rendered_lines = snippet_data.render_lines();
- for rendered_line in &rendered_lines {
- for styled_string in &rendered_line.text {
- self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
- write!(&mut self.dst, "{}", styled_string.text)?;
- self.dst.reset_attrs()?;
- }
- write!(&mut self.dst, "\n")?;
- }
- }
- Ok(())
- }
-
- fn print_macro_backtrace(&mut self,
- sp: Span)
- -> io::Result<()> {
- for trace in self.cm.macro_backtrace(sp) {
- let mut diag_string =
- format!("in this expansion of {}", trace.macro_decl_name);
- if let Some(def_site_span) = trace.def_site_span {
- diag_string.push_str(
- &format!(" (defined in {})",
- self.cm.span_to_filename(def_site_span)));
- }
- let snippet = self.cm.span_to_string(trace.call_site);
- print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?;
- }
- Ok(())
- }
-}
-
-fn line_num_max_digits(line: &codemap::LineInfo) -> usize {
- let mut max_line_num = line.line_index + 1;
- let mut digits = 0;
- while max_line_num > 0 {
- max_line_num /= 10;
- digits += 1;
- }
- digits
-}
-
-fn print_diagnostic(dst: &mut Destination,
- topic: &str,
- lvl: Level,
- msg: &str,
- code: Option<&str>)
- -> io::Result<()> {
- if !topic.is_empty() {
- let old_school = check_old_skool();
- if !old_school {
- write!(dst, "{}: ", topic)?;
- }
- else {
- write!(dst, "{} ", topic)?;
- }
- dst.reset_attrs()?;
- }
- dst.start_attr(term::Attr::Bold)?;
- dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
- write!(dst, "{}", lvl.to_string())?;
- dst.reset_attrs()?;
- write!(dst, ": ")?;
- dst.start_attr(term::Attr::Bold)?;
- write!(dst, "{}", msg)?;
-
- if let Some(code) = code {
- let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
- print_maybe_styled!(dst, style, " [{}]", code.clone())?;
- }
-
- dst.reset_attrs()?;
- write!(dst, "\n")?;
- Ok(())
-}
-
-#[cfg(unix)]
-fn stderr_isatty() -> bool {
- use libc;
- unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
-}
-#[cfg(windows)]
-fn stderr_isatty() -> bool {
- type DWORD = u32;
- type BOOL = i32;
- type HANDLE = *mut u8;
- const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
- extern "system" {
- fn GetStdHandle(which: DWORD) -> HANDLE;
- fn GetConsoleMode(hConsoleHandle: HANDLE,
- lpMode: *mut DWORD) -> BOOL;
- }
- unsafe {
- let handle = GetStdHandle(STD_ERROR_HANDLE);
- let mut out = 0;
- GetConsoleMode(handle, &mut out) != 0
- }
-}
-
-enum Destination {
- Terminal(Box<term::StderrTerminal>),
- Raw(Box<Write + Send>),
-}
-
-impl Destination {
- fn from_stderr() -> Destination {
- match term::stderr() {
- Some(t) => Terminal(t),
- None => Raw(Box::new(io::stderr())),
- }
- }
-
- fn apply_style(&mut self,
- lvl: Level,
- _kind: &RenderedLineKind,
- style: Style)
- -> io::Result<()> {
- match style {
- Style::FileNameStyle |
- Style::LineAndColumn => {
- }
- Style::LineNumber => {
- self.start_attr(term::Attr::Bold)?;
- self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
- }
- Style::Quotation => {
- }
- Style::OldSkoolNote => {
- self.start_attr(term::Attr::Bold)?;
- self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))?;
- }
- Style::OldSkoolNoteText => {
- self.start_attr(term::Attr::Bold)?;
- }
- Style::UnderlinePrimary | Style::LabelPrimary => {
- self.start_attr(term::Attr::Bold)?;
- self.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
- }
- Style::UnderlineSecondary | Style::LabelSecondary => {
- self.start_attr(term::Attr::Bold)?;
- self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
- }
- Style::NoStyle => {
- }
- }
- Ok(())
- }
-
- fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> {
- match *self {
- Terminal(ref mut t) => { t.attr(attr)?; }
- Raw(_) => { }
- }
- Ok(())
- }
-
- fn reset_attrs(&mut self) -> io::Result<()> {
- match *self {
- Terminal(ref mut t) => { t.reset()?; }
- Raw(_) => { }
- }
- Ok(())
- }
-
- fn print_maybe_styled(&mut self,
- args: fmt::Arguments,
- color: term::Attr,
- print_newline_at_end: bool)
- -> io::Result<()> {
- match *self {
- Terminal(ref mut t) => {
- t.attr(color)?;
- // If `msg` ends in a newline, we need to reset the color before
- // the newline. We're making the assumption that we end up writing
- // to a `LineBufferedWriter`, which means that emitting the reset
- // after the newline ends up buffering the reset until we print
- // another line or exit. Buffering the reset is a problem if we're
- // sharing the terminal with any other programs (e.g. other rustc
- // instances via `make -jN`).
- //
- // Note that if `msg` contains any internal newlines, this will
- // result in the `LineBufferedWriter` flushing twice instead of
- // once, which still leaves the opportunity for interleaved output
- // to be miscolored. We assume this is rare enough that we don't
- // have to worry about it.
- t.write_fmt(args)?;
- t.reset()?;
- if print_newline_at_end {
- t.write_all(b"\n")
- } else {
- Ok(())
- }
- }
- Raw(ref mut w) => {
- w.write_fmt(args)?;
- if print_newline_at_end {
- w.write_all(b"\n")
- } else {
- Ok(())
- }
- }
- }
- }
-}
-
-impl Write for Destination {
- fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
- match *self {
- Terminal(ref mut t) => t.write(bytes),
- Raw(ref mut w) => w.write(bytes),
- }
- }
- fn flush(&mut self) -> io::Result<()> {
- match *self {
- Terminal(ref mut t) => t.flush(),
- Raw(ref mut w) => w.flush(),
- }
- }
-}
-
-
-#[cfg(test)]
-mod test {
- use errors::{Level, CodeSuggestion};
- use super::EmitterWriter;
- use codemap::{mk_sp, CodeMap, Span, MultiSpan, BytePos, NO_EXPANSION};
- use std::sync::{Arc, Mutex};
- use std::io::{self, Write};
- use std::str::from_utf8;
- use std::rc::Rc;
-
- struct Sink(Arc<Mutex<Vec<u8>>>);
- impl Write for Sink {
- fn write(&mut self, data: &[u8]) -> io::Result<usize> {
- Write::write(&mut *self.0.lock().unwrap(), data)
- }
- fn flush(&mut self) -> io::Result<()> { Ok(()) }
- }
-
- /// Given a string like " ^~~~~~~~~~~~ ", produces a span
- /// coverting that range. The idea is that the string has the same
- /// length as the input, and we uncover the byte positions. Note
- /// that this can span lines and so on.
- fn span_from_selection(input: &str, selection: &str) -> Span {
- assert_eq!(input.len(), selection.len());
- let left_index = selection.find('~').unwrap() as u32;
- let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index);
- Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION }
- }
-
- // Diagnostic doesn't align properly in span where line number increases by one digit
- #[test]
- fn test_hilight_suggestion_issue_11715() {
- let data = Arc::new(Mutex::new(Vec::new()));
- let cm = Rc::new(CodeMap::new());
- let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
- let content = "abcdefg
- koksi
- line3
- line4
- cinq
- line6
- line7
- line8
- line9
- line10
- e-lä-vän
- tolv
- dreizehn
- ";
- let file = cm.new_filemap_and_lines("dummy.txt", None, content);
- let start = file.lines.borrow()[10];
- let end = file.lines.borrow()[11];
- let sp = mk_sp(start, end);
- let lvl = Level::Error;
- println!("highlight_lines");
- ew.highlight_lines(&sp.into(), lvl).unwrap();
- println!("done");
- let vec = data.lock().unwrap().clone();
- let vec: &[u8] = &vec;
- let str = from_utf8(vec).unwrap();
- println!("r#\"\n{}\"#", str);
- assert_eq!(str, &r#"
- --> dummy.txt:11:1
- |>
-11 |> e-lä-vän
- |> ^
-"#[1..]);
- }
-
- #[test]
- fn test_single_span_splice() {
- // Test that a `MultiSpan` containing a single span splices a substition correctly
- let cm = CodeMap::new();
- let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
- let selection = " \n ~~\n~~~\n~~~~~ \n \n";
- cm.new_filemap_and_lines("blork.rs", None, inputtext);
- let sp = span_from_selection(inputtext, selection);
- let msp: MultiSpan = sp.into();
-
- // check that we are extracting the text we thought we were extracting
- assert_eq!(&cm.span_to_snippet(sp).unwrap(), "BB\nCCC\nDDDDD");
-
- let substitute = "ZZZZZZ".to_owned();
- let expected = "bbbbZZZZZZddddd";
- let suggest = CodeSuggestion {
- msp: msp,
- substitutes: vec![substitute],
- };
- assert_eq!(suggest.splice_lines(&cm), expected);
- }
-
- #[test]
- fn test_multi_span_splice() {
- // Test that a `MultiSpan` containing multiple spans splices a substition correctly
- let cm = CodeMap::new();
- let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
- let selection1 = " \n \n \n \n ~ \n"; // intentionally out of order
- let selection2 = " \n ~~\n~~~\n~~~~~ \n \n";
- cm.new_filemap_and_lines("blork.rs", None, inputtext);
- let sp1 = span_from_selection(inputtext, selection1);
- let sp2 = span_from_selection(inputtext, selection2);
- let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]);
-
- let expected = "bbbbZZZZZZddddd\neXYZe";
- let suggest = CodeSuggestion {
- msp: msp,
- substitutes: vec!["ZZZZZZ".to_owned(),
- "XYZ".to_owned()]
- };
-
- assert_eq!(suggest.splice_lines(&cm), expected);
- }
-
- #[test]
- fn test_multispan_highlight() {
- let data = Arc::new(Mutex::new(Vec::new()));
- let cm = Rc::new(CodeMap::new());
- let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
-
- let inp = "_____aaaaaa____bbbbbb__cccccdd_";
- let sp1 = " ~~~~~~ ";
- let sp2 = " ~~~~~~ ";
- let sp3 = " ~~~~~ ";
- let sp4 = " ~~~~ ";
- let sp34 = " ~~~~~~~ ";
-
- let expect_start = &r#"
- --> dummy.txt:1:6
- |>
-1 |> _____aaaaaa____bbbbbb__cccccdd_
- |> ^^^^^^ ^^^^^^ ^^^^^^^
-"#[1..];
-
- let span = |sp, expected| {
- let sp = span_from_selection(inp, sp);
- assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected);
- sp
- };
- cm.new_filemap_and_lines("dummy.txt", None, inp);
- let sp1 = span(sp1, "aaaaaa");
- let sp2 = span(sp2, "bbbbbb");
- let sp3 = span(sp3, "ccccc");
- let sp4 = span(sp4, "ccdd");
- let sp34 = span(sp34, "cccccdd");
-
- let spans = vec![sp1, sp2, sp3, sp4];
-
- let test = |expected, highlight: &mut FnMut()| {
- data.lock().unwrap().clear();
- highlight();
- let vec = data.lock().unwrap().clone();
- let actual = from_utf8(&vec[..]).unwrap();
- println!("actual=\n{}", actual);
- assert_eq!(actual, expected);
- };
-
- let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]);
- test(expect_start, &mut || {
- diag.highlight_lines(&msp, Level::Error).unwrap();
- });
- test(expect_start, &mut || {
- let msp = MultiSpan::from_spans(spans.clone());
- diag.highlight_lines(&msp, Level::Error).unwrap();
- });
- }
-
- #[test]
- fn test_huge_multispan_highlight() {
- let data = Arc::new(Mutex::new(Vec::new()));
- let cm = Rc::new(CodeMap::new());
- let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
-
- let inp = "aaaaa\n\
- aaaaa\n\
- aaaaa\n\
- bbbbb\n\
- ccccc\n\
- xxxxx\n\
- yyyyy\n\
- _____\n\
- ddd__eee_\n\
- elided\n\
- __f_gg";
- let file = cm.new_filemap_and_lines("dummy.txt", None, inp);
-
- let span = |lo, hi, (off_lo, off_hi)| {
- let lines = file.lines.borrow();
- let (mut lo, mut hi): (BytePos, BytePos) = (lines[lo], lines[hi]);
- lo.0 += off_lo;
- hi.0 += off_hi;
- mk_sp(lo, hi)
- };
- let sp0 = span(4, 6, (0, 5));
- let sp1 = span(0, 6, (0, 5));
- let sp2 = span(8, 8, (0, 3));
- let sp3 = span(8, 8, (5, 8));
- let sp4 = span(10, 10, (2, 3));
- let sp5 = span(10, 10, (4, 6));
-
- let expect0 = &r#"
- --> dummy.txt:5:1
- |>
-5 |> ccccc
- |> ^
-...
-9 |> ddd__eee_
- |> ^^^ ^^^
-10 |> elided
-11 |> __f_gg
- |> ^ ^^
-"#[1..];
-
- let expect = &r#"
- --> dummy.txt:1:1
- |>
-1 |> aaaaa
- |> ^
-...
-9 |> ddd__eee_
- |> ^^^ ^^^
-10 |> elided
-11 |> __f_gg
- |> ^ ^^
-"#[1..];
-
- macro_rules! test {
- ($expected: expr, $highlight: expr) => ({
- data.lock().unwrap().clear();
- $highlight();
- let vec = data.lock().unwrap().clone();
- let actual = from_utf8(&vec[..]).unwrap();
- println!("actual:");
- println!("{}", actual);
- println!("expected:");
- println!("{}", $expected);
- assert_eq!(&actual[..], &$expected[..]);
- });
- }
-
- let msp0 = MultiSpan::from_spans(vec![sp0, sp2, sp3, sp4, sp5]);
- let msp = MultiSpan::from_spans(vec![sp1, sp2, sp3, sp4, sp5]);
-
- test!(expect0, || {
- diag.highlight_lines(&msp0, Level::Error).unwrap();
- });
- test!(expect, || {
- diag.highlight_lines(&msp, Level::Error).unwrap();
- });
- }
-}
+++ /dev/null
-// Copyright 2012-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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A JSON emitter for errors.
-//!
-//! This works by converting errors to a simplified structural format (see the
-//! structs at the start of the file) and then serialising them. These should
-//! contain as much information about the error as possible.
-//!
-//! The format of the JSON output should be considered *unstable*. For now the
-//! structs at the end of this file (Diagnostic*) specify the error format.
-
-// FIXME spec the JSON output properly.
-
-
-use codemap::{self, MacroBacktrace, Span, SpanLabel, MultiSpan, CodeMap};
-use diagnostics::registry::Registry;
-use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion};
-use errors::emitter::Emitter;
-
-use std::rc::Rc;
-use std::io::{self, Write};
-use std::vec;
-
-use rustc_serialize::json::as_json;
-
-pub struct JsonEmitter {
- dst: Box<Write + Send>,
- registry: Option<Registry>,
- cm: Rc<CodeMap>,
-}
-
-impl JsonEmitter {
- pub fn basic() -> JsonEmitter {
- JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
- }
-
- pub fn stderr(registry: Option<Registry>,
- code_map: Rc<CodeMap>) -> JsonEmitter {
- JsonEmitter {
- dst: Box::new(io::stderr()),
- registry: registry,
- cm: code_map,
- }
- }
-}
-
-impl Emitter for JsonEmitter {
- fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, level: Level) {
- let data = Diagnostic::new(span, msg, code, level, self);
- if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
- panic!("failed to print diagnostics: {:?}", e);
- }
- }
-
- fn emit_struct(&mut self, db: &DiagnosticBuilder) {
- let data = Diagnostic::from_diagnostic_builder(db, self);
- if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
- panic!("failed to print diagnostics: {:?}", e);
- }
- }
-}
-
-// The following data types are provided just for serialisation.
-
-#[derive(RustcEncodable)]
-struct Diagnostic<'a> {
- /// The primary error message.
- message: &'a str,
- code: Option<DiagnosticCode>,
- /// "error: internal compiler error", "error", "warning", "note", "help".
- level: &'static str,
- spans: Vec<DiagnosticSpan>,
- /// Associated diagnostic messages.
- children: Vec<Diagnostic<'a>>,
- /// The message as rustc would render it. Currently this is only
- /// `Some` for "suggestions", but eventually it will include all
- /// snippets.
- rendered: Option<String>,
-}
-
-#[derive(RustcEncodable)]
-struct DiagnosticSpan {
- file_name: String,
- byte_start: u32,
- byte_end: u32,
- /// 1-based.
- line_start: usize,
- line_end: usize,
- /// 1-based, character offset.
- column_start: usize,
- column_end: usize,
- /// Is this a "primary" span -- meaning the point, or one of the points,
- /// where the error occurred?
- is_primary: bool,
- /// Source text from the start of line_start to the end of line_end.
- text: Vec<DiagnosticSpanLine>,
- /// Label that should be placed at this location (if any)
- label: Option<String>,
- /// If we are suggesting a replacement, this will contain text
- /// that should be sliced in atop this span. You may prefer to
- /// load the fully rendered version from the parent `Diagnostic`,
- /// however.
- suggested_replacement: Option<String>,
- /// Macro invocations that created the code at this span, if any.
- expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
-}
-
-#[derive(RustcEncodable)]
-struct DiagnosticSpanLine {
- text: String,
-
- /// 1-based, character offset in self.text.
- highlight_start: usize,
-
- highlight_end: usize,
-}
-
-#[derive(RustcEncodable)]
-struct DiagnosticSpanMacroExpansion {
- /// span where macro was applied to generate this code; note that
- /// this may itself derive from a macro (if
- /// `span.expansion.is_some()`)
- span: DiagnosticSpan,
-
- /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
- macro_decl_name: String,
-
- /// span where macro was defined (if known)
- def_site_span: Option<DiagnosticSpan>,
-}
-
-#[derive(RustcEncodable)]
-struct DiagnosticCode {
- /// The code itself.
- code: String,
- /// An explanation for the code.
- explanation: Option<&'static str>,
-}
-
-impl<'a> Diagnostic<'a> {
- fn new(msp: &MultiSpan,
- msg: &'a str,
- code: Option<&str>,
- level: Level,
- je: &JsonEmitter)
- -> Diagnostic<'a> {
- Diagnostic {
- message: msg,
- code: DiagnosticCode::map_opt_string(code.map(|c| c.to_owned()), je),
- level: level.to_str(),
- spans: DiagnosticSpan::from_multispan(msp, je),
- children: vec![],
- rendered: None,
- }
- }
-
- fn from_diagnostic_builder<'c>(db: &'c DiagnosticBuilder,
- je: &JsonEmitter)
- -> Diagnostic<'c> {
- Diagnostic {
- message: &db.message,
- code: DiagnosticCode::map_opt_string(db.code.clone(), je),
- level: db.level.to_str(),
- spans: DiagnosticSpan::from_multispan(&db.span, je),
- children: db.children.iter().map(|c| {
- Diagnostic::from_sub_diagnostic(c, je)
- }).collect(),
- rendered: None,
- }
- }
-
- fn from_sub_diagnostic<'c>(db: &'c SubDiagnostic, je: &JsonEmitter) -> Diagnostic<'c> {
- Diagnostic {
- message: &db.message,
- code: None,
- level: db.level.to_str(),
- spans: db.render_span.as_ref()
- .map(|sp| DiagnosticSpan::from_render_span(sp, je))
- .unwrap_or_else(|| DiagnosticSpan::from_multispan(&db.span, je)),
- children: vec![],
- rendered: db.render_span.as_ref()
- .and_then(|rsp| je.render(rsp)),
- }
- }
-}
-
-impl DiagnosticSpan {
- fn from_span_label(span: SpanLabel,
- suggestion: Option<&String>,
- je: &JsonEmitter)
- -> DiagnosticSpan {
- Self::from_span_etc(span.span,
- span.is_primary,
- span.label,
- suggestion,
- je)
- }
-
- fn from_span_etc(span: Span,
- is_primary: bool,
- label: Option<String>,
- suggestion: Option<&String>,
- je: &JsonEmitter)
- -> DiagnosticSpan {
- // obtain the full backtrace from the `macro_backtrace`
- // helper; in some ways, it'd be better to expand the
- // backtrace ourselves, but the `macro_backtrace` helper makes
- // some decision, such as dropping some frames, and I don't
- // want to duplicate that logic here.
- let backtrace = je.cm.macro_backtrace(span).into_iter();
- DiagnosticSpan::from_span_full(span,
- is_primary,
- label,
- suggestion,
- backtrace,
- je)
- }
-
- fn from_span_full(span: Span,
- is_primary: bool,
- label: Option<String>,
- suggestion: Option<&String>,
- mut backtrace: vec::IntoIter<MacroBacktrace>,
- je: &JsonEmitter)
- -> DiagnosticSpan {
- let start = je.cm.lookup_char_pos(span.lo);
- let end = je.cm.lookup_char_pos(span.hi);
- let backtrace_step = backtrace.next().map(|bt| {
- let call_site =
- Self::from_span_full(bt.call_site,
- false,
- None,
- None,
- backtrace,
- je);
- let def_site_span = bt.def_site_span.map(|sp| {
- Self::from_span_full(sp,
- false,
- None,
- None,
- vec![].into_iter(),
- je)
- });
- Box::new(DiagnosticSpanMacroExpansion {
- span: call_site,
- macro_decl_name: bt.macro_decl_name,
- def_site_span: def_site_span,
- })
- });
- DiagnosticSpan {
- file_name: start.file.name.clone(),
- byte_start: span.lo.0,
- byte_end: span.hi.0,
- line_start: start.line,
- line_end: end.line,
- column_start: start.col.0 + 1,
- column_end: end.col.0 + 1,
- is_primary: is_primary,
- text: DiagnosticSpanLine::from_span(span, je),
- suggested_replacement: suggestion.cloned(),
- expansion: backtrace_step,
- label: label,
- }
- }
-
- fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
- msp.span_labels()
- .into_iter()
- .map(|span_str| Self::from_span_label(span_str, None, je))
- .collect()
- }
-
- fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter)
- -> Vec<DiagnosticSpan> {
- assert_eq!(suggestion.msp.span_labels().len(), suggestion.substitutes.len());
- suggestion.msp.span_labels()
- .into_iter()
- .zip(&suggestion.substitutes)
- .map(|(span_label, suggestion)| {
- DiagnosticSpan::from_span_label(span_label,
- Some(suggestion),
- je)
- })
- .collect()
- }
-
- fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
- match *rsp {
- RenderSpan::FullSpan(ref msp) =>
- DiagnosticSpan::from_multispan(msp, je),
- RenderSpan::Suggestion(ref suggestion) =>
- DiagnosticSpan::from_suggestion(suggestion, je),
- }
- }
-}
-
-impl DiagnosticSpanLine {
- fn line_from_filemap(fm: &codemap::FileMap,
- index: usize,
- h_start: usize,
- h_end: usize)
- -> DiagnosticSpanLine {
- DiagnosticSpanLine {
- text: fm.get_line(index).unwrap().to_owned(),
- highlight_start: h_start,
- highlight_end: h_end,
- }
- }
-
- /// Create a list of DiagnosticSpanLines from span - each line with any part
- /// of `span` gets a DiagnosticSpanLine, with the highlight indicating the
- /// `span` within the line.
- fn from_span(span: Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
- je.cm.span_to_lines(span)
- .map(|lines| {
- let fm = &*lines.file;
- lines.lines
- .iter()
- .map(|line| {
- DiagnosticSpanLine::line_from_filemap(fm,
- line.line_index,
- line.start_col.0 + 1,
- line.end_col.0 + 1)
- })
- .collect()
- })
- .unwrap_or(vec![])
- }
-}
-
-impl DiagnosticCode {
- fn map_opt_string(s: Option<String>, je: &JsonEmitter) -> Option<DiagnosticCode> {
- s.map(|s| {
-
- let explanation = je.registry
- .as_ref()
- .and_then(|registry| registry.find_description(&s));
-
- DiagnosticCode {
- code: s,
- explanation: explanation,
- }
- })
- }
-}
-
-impl JsonEmitter {
- fn render(&self, render_span: &RenderSpan) -> Option<String> {
- match *render_span {
- RenderSpan::FullSpan(_) => {
- None
- }
- RenderSpan::Suggestion(ref suggestion) => {
- Some(suggestion.splice_lines(&self.cm))
- }
- }
- }
-}
-
+++ /dev/null
-// Copyright 2012-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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub use errors::emitter::ColorConfig;
-
-use self::Level::*;
-use self::RenderSpan::*;
-
-use codemap::{self, CodeMap, MultiSpan, NO_EXPANSION, Span};
-use diagnostics;
-use errors::emitter::{Emitter, EmitterWriter};
-
-use std::cell::{RefCell, Cell};
-use std::{error, fmt};
-use std::rc::Rc;
-use std::thread::panicking;
-use term;
-
-pub mod emitter;
-pub mod json;
-pub mod snippet;
-
-#[derive(Clone)]
-pub enum RenderSpan {
- /// A FullSpan renders with both with an initial line for the
- /// message, prefixed by file:linenum, followed by a summary of
- /// the source code covered by the span.
- FullSpan(MultiSpan),
-
- /// A suggestion renders with both with an initial line for the
- /// message, prefixed by file:linenum, followed by a summary
- /// of hypothetical source code, where each `String` is spliced
- /// into the lines in place of the code covered by each span.
- Suggestion(CodeSuggestion),
-}
-
-#[derive(Clone)]
-pub struct CodeSuggestion {
- msp: MultiSpan,
- substitutes: Vec<String>,
-}
-
-impl RenderSpan {
- fn span(&self) -> &MultiSpan {
- match *self {
- FullSpan(ref msp) |
- Suggestion(CodeSuggestion { ref msp, .. }) =>
- msp
- }
- }
-}
-
-impl CodeSuggestion {
- /// Returns the assembled code suggestion.
- pub fn splice_lines(&self, cm: &CodeMap) -> String {
- use codemap::{CharPos, Loc, Pos};
-
- fn push_trailing(buf: &mut String, line_opt: Option<&str>,
- lo: &Loc, hi_opt: Option<&Loc>) {
- let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi|hi.col.to_usize()));
- if let Some(line) = line_opt {
- if line.len() > lo {
- buf.push_str(match hi_opt {
- Some(hi) => &line[lo..hi],
- None => &line[lo..],
- });
- }
- if let None = hi_opt {
- buf.push('\n');
- }
- }
- }
-
- let mut primary_spans = self.msp.primary_spans().to_owned();
-
- assert_eq!(primary_spans.len(), self.substitutes.len());
- if primary_spans.is_empty() {
- return format!("");
- }
-
- // Assumption: all spans are in the same file, and all spans
- // are disjoint. Sort in ascending order.
- primary_spans.sort_by_key(|sp| sp.lo);
-
- // Find the bounding span.
- let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap();
- let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap();
- let bounding_span = Span { lo: lo, hi: hi, expn_id: NO_EXPANSION };
- let lines = cm.span_to_lines(bounding_span).unwrap();
- assert!(!lines.lines.is_empty());
-
- // To build up the result, we do this for each span:
- // - push the line segment trailing the previous span
- // (at the beginning a "phantom" span pointing at the start of the line)
- // - push lines between the previous and current span (if any)
- // - if the previous and current span are not on the same line
- // push the line segment leading up to the current span
- // - splice in the span substitution
- //
- // Finally push the trailing line segment of the last span
- let fm = &lines.file;
- let mut prev_hi = cm.lookup_char_pos(bounding_span.lo);
- prev_hi.col = CharPos::from_usize(0);
-
- let mut prev_line = fm.get_line(lines.lines[0].line_index);
- let mut buf = String::new();
-
- for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) {
- let cur_lo = cm.lookup_char_pos(sp.lo);
- if prev_hi.line == cur_lo.line {
- push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo));
- } else {
- push_trailing(&mut buf, prev_line, &prev_hi, None);
- // push lines between the previous and current span (if any)
- for idx in prev_hi.line..(cur_lo.line - 1) {
- if let Some(line) = fm.get_line(idx) {
- buf.push_str(line);
- buf.push('\n');
- }
- }
- if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
- buf.push_str(&cur_line[.. cur_lo.col.to_usize()]);
- }
- }
- buf.push_str(substitute);
- prev_hi = cm.lookup_char_pos(sp.hi);
- prev_line = fm.get_line(prev_hi.line - 1);
- }
- push_trailing(&mut buf, prev_line, &prev_hi, None);
- // remove trailing newline
- buf.pop();
- buf
- }
-}
-
-/// Used as a return value to signify a fatal error occurred. (It is also
-/// used as the argument to panic at the moment, but that will eventually
-/// not be true.)
-#[derive(Copy, Clone, Debug)]
-#[must_use]
-pub struct FatalError;
-
-impl fmt::Display for FatalError {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(f, "parser fatal error")
- }
-}
-
-impl error::Error for FatalError {
- fn description(&self) -> &str {
- "The parser has encountered a fatal error"
- }
-}
-
-/// Signifies that the compiler died with an explicit call to `.bug`
-/// or `.span_bug` rather than a failed assertion, etc.
-#[derive(Copy, Clone, Debug)]
-pub struct ExplicitBug;
-
-impl fmt::Display for ExplicitBug {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(f, "parser internal bug")
- }
-}
-
-impl error::Error for ExplicitBug {
- fn description(&self) -> &str {
- "The parser has encountered an internal bug"
- }
-}
-
-/// Used for emitting structured error messages and other diagnostic information.
-#[must_use]
-#[derive(Clone)]
-pub struct DiagnosticBuilder<'a> {
- handler: &'a Handler,
- level: Level,
- message: String,
- code: Option<String>,
- span: MultiSpan,
- children: Vec<SubDiagnostic>,
-}
-
-/// For example a note attached to an error.
-#[derive(Clone)]
-struct SubDiagnostic {
- level: Level,
- message: String,
- span: MultiSpan,
- render_span: Option<RenderSpan>,
-}
-
-impl<'a> DiagnosticBuilder<'a> {
- /// Emit the diagnostic.
- pub fn emit(&mut self) {
- if self.cancelled() {
- return;
- }
-
- self.handler.emit.borrow_mut().emit_struct(&self);
- self.cancel();
- self.handler.panic_if_treat_err_as_bug();
-
- // if self.is_fatal() {
- // panic!(FatalError);
- // }
- }
-
- /// Cancel the diagnostic (a structured diagnostic must either be emitted or
- /// cancelled or it will panic when dropped).
- /// BEWARE: if this DiagnosticBuilder is an error, then creating it will
- /// bump the error count on the Handler and cancelling it won't undo that.
- /// If you want to decrement the error count you should use `Handler::cancel`.
- pub fn cancel(&mut self) {
- self.level = Level::Cancelled;
- }
-
- pub fn cancelled(&self) -> bool {
- self.level == Level::Cancelled
- }
-
- pub fn is_fatal(&self) -> bool {
- self.level == Level::Fatal
- }
-
- /// Add a span/label to be included in the resulting snippet.
- /// This is pushed onto the `MultiSpan` that was created when the
- /// diagnostic was first built. If you don't call this function at
- /// all, and you just supplied a `Span` to create the diagnostic,
- /// then the snippet will just include that `Span`, which is
- /// called the primary span.
- pub fn span_label(&mut self, span: Span, label: &fmt::Display)
- -> &mut DiagnosticBuilder<'a> {
- self.span.push_span_label(span, format!("{}", label));
- self
- }
-
- pub fn note_expected_found(&mut self,
- label: &fmt::Display,
- expected: &fmt::Display,
- found: &fmt::Display)
- -> &mut DiagnosticBuilder<'a>
- {
- // For now, just attach these as notes
- self.note(&format!("expected {} `{}`", label, expected));
- self.note(&format!(" found {} `{}`", label, found));
- self
- }
-
- pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
- self.sub(Level::Note, msg, MultiSpan::new(), None);
- self
- }
- pub fn span_note<S: Into<MultiSpan>>(&mut self,
- sp: S,
- msg: &str)
- -> &mut DiagnosticBuilder<'a> {
- self.sub(Level::Note, msg, sp.into(), None);
- self
- }
- pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
- self.sub(Level::Warning, msg, MultiSpan::new(), None);
- self
- }
- pub fn span_warn<S: Into<MultiSpan>>(&mut self,
- sp: S,
- msg: &str)
- -> &mut DiagnosticBuilder<'a> {
- self.sub(Level::Warning, msg, sp.into(), None);
- self
- }
- pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> {
- self.sub(Level::Help, msg, MultiSpan::new(), None);
- self
- }
- pub fn span_help<S: Into<MultiSpan>>(&mut self,
- sp: S,
- msg: &str)
- -> &mut DiagnosticBuilder<'a> {
- self.sub(Level::Help, msg, sp.into(), None);
- self
- }
- /// Prints out a message with a suggested edit of the code.
- ///
- /// See `diagnostic::RenderSpan::Suggestion` for more information.
- pub fn span_suggestion<S: Into<MultiSpan>>(&mut self,
- sp: S,
- msg: &str,
- suggestion: String)
- -> &mut DiagnosticBuilder<'a> {
- self.sub(Level::Help, msg, MultiSpan::new(), Some(Suggestion(CodeSuggestion {
- msp: sp.into(),
- substitutes: vec![suggestion],
- })));
- self
- }
-
- pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
- self.span = sp.into();
- self
- }
-
- pub fn code(&mut self, s: String) -> &mut Self {
- self.code = Some(s);
- self
- }
-
- pub fn message(&self) -> &str {
- &self.message
- }
-
- pub fn level(&self) -> Level {
- self.level
- }
-
- /// Convenience function for internal use, clients should use one of the
- /// struct_* methods on Handler.
- fn new(handler: &'a Handler,
- level: Level,
- message: &str) -> DiagnosticBuilder<'a> {
- DiagnosticBuilder {
- handler: handler,
- level: level,
- message: message.to_owned(),
- code: None,
- span: MultiSpan::new(),
- children: vec![],
- }
- }
-
- /// Convenience function for internal use, clients should use one of the
- /// public methods above.
- fn sub(&mut self,
- level: Level,
- message: &str,
- span: MultiSpan,
- render_span: Option<RenderSpan>) {
- let sub = SubDiagnostic {
- level: level,
- message: message.to_owned(),
- span: span,
- render_span: render_span,
- };
- self.children.push(sub);
- }
-}
-
-impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.message.fmt(f)
- }
-}
-
-/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or
-/// we emit a bug.
-impl<'a> Drop for DiagnosticBuilder<'a> {
- fn drop(&mut self) {
- if !panicking() && !self.cancelled() {
- self.handler.emit.borrow_mut().emit(&MultiSpan::new(),
- "Error constructed but not emitted",
- None,
- Bug);
- panic!();
- }
- }
-}
-
-/// A handler deals with errors; certain errors
-/// (fatal, bug, unimpl) may cause immediate exit,
-/// others log errors for later reporting.
-pub struct Handler {
- err_count: Cell<usize>,
- emit: RefCell<Box<Emitter>>,
- pub can_emit_warnings: bool,
- treat_err_as_bug: bool,
- continue_after_error: Cell<bool>,
- delayed_span_bug: RefCell<Option<(MultiSpan, String)>>,
-}
-
-impl Handler {
- pub fn with_tty_emitter(color_config: ColorConfig,
- registry: Option<diagnostics::registry::Registry>,
- can_emit_warnings: bool,
- treat_err_as_bug: bool,
- cm: Rc<codemap::CodeMap>)
- -> Handler {
- let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm));
- Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter)
- }
-
- pub fn with_emitter(can_emit_warnings: bool,
- treat_err_as_bug: bool,
- e: Box<Emitter>) -> Handler {
- Handler {
- err_count: Cell::new(0),
- emit: RefCell::new(e),
- can_emit_warnings: can_emit_warnings,
- treat_err_as_bug: treat_err_as_bug,
- continue_after_error: Cell::new(true),
- delayed_span_bug: RefCell::new(None),
- }
- }
-
- pub fn set_continue_after_error(&self, continue_after_error: bool) {
- self.continue_after_error.set(continue_after_error);
- }
-
- pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
- DiagnosticBuilder::new(self, Level::Cancelled, "")
- }
-
- pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
- sp: S,
- msg: &str)
- -> DiagnosticBuilder<'a> {
- let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
- result.set_span(sp);
- if !self.can_emit_warnings {
- result.cancel();
- }
- result
- }
- pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
- sp: S,
- msg: &str,
- code: &str)
- -> DiagnosticBuilder<'a> {
- let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
- result.set_span(sp);
- result.code(code.to_owned());
- if !self.can_emit_warnings {
- result.cancel();
- }
- result
- }
- pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
- let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
- if !self.can_emit_warnings {
- result.cancel();
- }
- result
- }
- pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
- sp: S,
- msg: &str)
- -> DiagnosticBuilder<'a> {
- self.bump_err_count();
- let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
- result.set_span(sp);
- result
- }
- pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
- sp: S,
- msg: &str,
- code: &str)
- -> DiagnosticBuilder<'a> {
- self.bump_err_count();
- let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
- result.set_span(sp);
- result.code(code.to_owned());
- result
- }
- pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
- self.bump_err_count();
- DiagnosticBuilder::new(self, Level::Error, msg)
- }
- pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
- sp: S,
- msg: &str)
- -> DiagnosticBuilder<'a> {
- self.bump_err_count();
- let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
- result.set_span(sp);
- result
- }
- pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
- sp: S,
- msg: &str,
- code: &str)
- -> DiagnosticBuilder<'a> {
- self.bump_err_count();
- let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
- result.set_span(sp);
- result.code(code.to_owned());
- result
- }
- pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
- self.bump_err_count();
- DiagnosticBuilder::new(self, Level::Fatal, msg)
- }
-
- pub fn cancel(&mut self, err: &mut DiagnosticBuilder) {
- if err.level == Level::Error || err.level == Level::Fatal {
- assert!(self.has_errors());
- self.err_count.set(self.err_count.get() + 1);
- }
- err.cancel();
- }
-
- fn panic_if_treat_err_as_bug(&self) {
- if self.treat_err_as_bug {
- panic!("encountered error with `-Z treat_err_as_bug");
- }
- }
-
- pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str)
- -> FatalError {
- self.emit(&sp.into(), msg, Fatal);
- self.bump_err_count();
- self.panic_if_treat_err_as_bug();
- return FatalError;
- }
- pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str)
- -> FatalError {
- self.emit_with_code(&sp.into(), msg, code, Fatal);
- self.bump_err_count();
- self.panic_if_treat_err_as_bug();
- return FatalError;
- }
- pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
- self.emit(&sp.into(), msg, Error);
- self.bump_err_count();
- self.panic_if_treat_err_as_bug();
- }
- pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
- self.emit_with_code(&sp.into(), msg, code, Error);
- self.bump_err_count();
- self.panic_if_treat_err_as_bug();
- }
- pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
- self.emit(&sp.into(), msg, Warning);
- }
- pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
- self.emit_with_code(&sp.into(), msg, code, Warning);
- }
- pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
- self.emit(&sp.into(), msg, Bug);
- panic!(ExplicitBug);
- }
- pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
- let mut delayed = self.delayed_span_bug.borrow_mut();
- *delayed = Some((sp.into(), msg.to_string()));
- }
- pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
- self.emit(&sp.into(), msg, Bug);
- self.bump_err_count();
- }
- pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
- self.emit.borrow_mut().emit(&sp.into(), msg, None, Note);
- }
- pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
- self.span_bug(sp, &format!("unimplemented {}", msg));
- }
- pub fn fatal(&self, msg: &str) -> FatalError {
- if self.treat_err_as_bug {
- self.bug(msg);
- }
- self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Fatal);
- self.bump_err_count();
- FatalError
- }
- pub fn err(&self, msg: &str) {
- if self.treat_err_as_bug {
- self.bug(msg);
- }
- self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Error);
- self.bump_err_count();
- }
- pub fn warn(&self, msg: &str) {
- self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Warning);
- }
- pub fn note_without_error(&self, msg: &str) {
- self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Note);
- }
- pub fn bug(&self, msg: &str) -> ! {
- self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Bug);
- panic!(ExplicitBug);
- }
- pub fn unimpl(&self, msg: &str) -> ! {
- self.bug(&format!("unimplemented {}", msg));
- }
-
- pub fn bump_err_count(&self) {
- self.err_count.set(self.err_count.get() + 1);
- }
-
- pub fn err_count(&self) -> usize {
- self.err_count.get()
- }
-
- pub fn has_errors(&self) -> bool {
- self.err_count.get() > 0
- }
- pub fn abort_if_errors(&self) {
- let s;
- match self.err_count.get() {
- 0 => {
- let delayed_bug = self.delayed_span_bug.borrow();
- match *delayed_bug {
- Some((ref span, ref errmsg)) => {
- self.span_bug(span.clone(), errmsg);
- },
- _ => {}
- }
-
- return;
- }
- 1 => s = "aborting due to previous error".to_string(),
- _ => {
- s = format!("aborting due to {} previous errors",
- self.err_count.get());
- }
- }
-
- panic!(self.fatal(&s));
- }
- pub fn emit(&self,
- msp: &MultiSpan,
- msg: &str,
- lvl: Level) {
- if lvl == Warning && !self.can_emit_warnings { return }
- self.emit.borrow_mut().emit(&msp, msg, None, lvl);
- if !self.continue_after_error.get() { self.abort_if_errors(); }
- }
- pub fn emit_with_code(&self,
- msp: &MultiSpan,
- msg: &str,
- code: &str,
- lvl: Level) {
- if lvl == Warning && !self.can_emit_warnings { return }
- self.emit.borrow_mut().emit(&msp, msg, Some(code), lvl);
- if !self.continue_after_error.get() { self.abort_if_errors(); }
- }
-}
-
-
-#[derive(Copy, PartialEq, Clone, Debug)]
-pub enum Level {
- Bug,
- Fatal,
- // An error which while not immediately fatal, should stop the compiler
- // progressing beyond the current phase.
- PhaseFatal,
- Error,
- Warning,
- Note,
- Help,
- Cancelled,
-}
-
-impl fmt::Display for Level {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.to_str().fmt(f)
- }
-}
-
-impl Level {
- fn color(self) -> term::color::Color {
- match self {
- Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED,
- Warning => term::color::YELLOW,
- Note => term::color::BRIGHT_GREEN,
- Help => term::color::BRIGHT_CYAN,
- Cancelled => unreachable!(),
- }
- }
-
- fn to_str(self) -> &'static str {
- match self {
- Bug => "error: internal compiler error",
- Fatal | PhaseFatal | Error => "error",
- Warning => "warning",
- Note => "note",
- Help => "help",
- Cancelled => panic!("Shouldn't call on cancelled error"),
- }
- }
-}
-
-pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T where
- M: FnOnce() -> String,
-{
- match opt {
- Some(t) => t,
- None => diag.bug(&msg()),
- }
-}
-
-/// True if we should use the old-skool error format style. This is
-/// the default setting until the new errors are deemed stable enough
-/// for general use.
-///
-/// FIXME(#33240)
-#[cfg(not(test))]
-pub fn check_old_skool() -> bool {
- use std::env;
- env::var("RUST_NEW_ERROR_FORMAT").is_err()
-}
-
-/// For unit tests, use the new format.
-#[cfg(test)]
-pub fn check_old_skool() -> bool {
- false
-}
+++ /dev/null
-// Copyright 2012-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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Code for annotating snippets.
-
-use codemap::{CharPos, CodeMap, FileMap, LineInfo, Span};
-use errors::check_old_skool;
-use std::cmp;
-use std::rc::Rc;
-use std::mem;
-
-mod test;
-
-#[derive(Clone)]
-pub struct SnippetData {
- codemap: Rc<CodeMap>,
- files: Vec<FileInfo>,
-}
-
-#[derive(Clone)]
-pub struct FileInfo {
- file: Rc<FileMap>,
-
- /// The "primary file", if any, gets a `-->` marker instead of
- /// `>>>`, and has a line-number/column printed and not just a
- /// filename. It appears first in the listing. It is known to
- /// contain at least one primary span, though primary spans (which
- /// are designated with `^^^`) may also occur in other files.
- primary_span: Option<Span>,
-
- lines: Vec<Line>,
-}
-
-#[derive(Clone, Debug)]
-struct Line {
- line_index: usize,
- annotations: Vec<Annotation>,
-}
-
-#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
-struct Annotation {
- /// Start column, 0-based indexing -- counting *characters*, not
- /// utf-8 bytes. Note that it is important that this field goes
- /// first, so that when we sort, we sort orderings by start
- /// column.
- start_col: usize,
-
- /// End column within the line (exclusive)
- end_col: usize,
-
- /// Is this annotation derived from primary span
- is_primary: bool,
-
- /// Is this a large span minimized down to a smaller span
- is_minimized: bool,
-
- /// Optional label to display adjacent to the annotation.
- label: Option<String>,
-}
-
-#[derive(Debug)]
-pub struct RenderedLine {
- pub text: Vec<StyledString>,
- pub kind: RenderedLineKind,
-}
-
-#[derive(Debug)]
-pub struct StyledString {
- pub text: String,
- pub style: Style,
-}
-
-#[derive(Debug)]
-pub struct StyledBuffer {
- text: Vec<Vec<char>>,
- styles: Vec<Vec<Style>>
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum Style {
- FileNameStyle,
- LineAndColumn,
- LineNumber,
- Quotation,
- UnderlinePrimary,
- UnderlineSecondary,
- LabelPrimary,
- LabelSecondary,
- OldSkoolNoteText,
- OldSkoolNote,
- NoStyle,
-}
-
-#[derive(Debug, Clone)]
-pub enum RenderedLineKind {
- PrimaryFileName,
- OtherFileName,
- SourceText {
- file: Rc<FileMap>,
- line_index: usize,
- },
- Annotations,
- Elision,
-}
-
-impl SnippetData {
- pub fn new(codemap: Rc<CodeMap>,
- primary_span: Option<Span>) // (*)
- -> Self {
- // (*) The primary span indicates the file that must appear
- // first, and which will have a line number etc in its
- // name. Outside of tests, this is always `Some`, but for many
- // tests it's not relevant to test this portion of the logic,
- // and it's tedious to pick a primary span (read: tedious to
- // port older tests that predate the existence of a primary
- // span).
-
- debug!("SnippetData::new(primary_span={:?})", primary_span);
-
- let mut data = SnippetData {
- codemap: codemap.clone(),
- files: vec![]
- };
- if let Some(primary_span) = primary_span {
- let lo = codemap.lookup_char_pos(primary_span.lo);
- data.files.push(
- FileInfo {
- file: lo.file,
- primary_span: Some(primary_span),
- lines: vec![],
- });
- }
- data
- }
-
- pub fn push(&mut self, span: Span, is_primary: bool, label: Option<String>) {
- debug!("SnippetData::push(span={:?}, is_primary={}, label={:?})",
- span, is_primary, label);
-
- let file_lines = match self.codemap.span_to_lines(span) {
- Ok(file_lines) => file_lines,
- Err(_) => {
- // ignore unprintable spans completely.
- return;
- }
- };
-
- self.file(&file_lines.file)
- .push_lines(&file_lines.lines, is_primary, label);
- }
-
- fn file(&mut self, file_map: &Rc<FileMap>) -> &mut FileInfo {
- let index = self.files.iter().position(|f| f.file.name == file_map.name);
- if let Some(index) = index {
- return &mut self.files[index];
- }
-
- self.files.push(
- FileInfo {
- file: file_map.clone(),
- lines: vec![],
- primary_span: None,
- });
- self.files.last_mut().unwrap()
- }
-
- pub fn render_lines(&self) -> Vec<RenderedLine> {
- debug!("SnippetData::render_lines()");
-
- let mut rendered_lines: Vec<_> =
- self.files.iter()
- .flat_map(|f| f.render_file_lines(&self.codemap))
- .collect();
- prepend_prefixes(&mut rendered_lines);
- trim_lines(&mut rendered_lines);
- rendered_lines
- }
-}
-
-pub trait StringSource {
- fn make_string(self) -> String;
-}
-
-impl StringSource for String {
- fn make_string(self) -> String {
- self
- }
-}
-
-impl StringSource for Vec<char> {
- fn make_string(self) -> String {
- self.into_iter().collect()
- }
-}
-
-impl<S> From<(S, Style, RenderedLineKind)> for RenderedLine
- where S: StringSource
-{
- fn from((text, style, kind): (S, Style, RenderedLineKind)) -> Self {
- RenderedLine {
- text: vec![StyledString {
- text: text.make_string(),
- style: style,
- }],
- kind: kind,
- }
- }
-}
-
-impl<S1,S2> From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine
- where S1: StringSource, S2: StringSource
-{
- fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) -> Self {
- let (text1, style1, text2, style2, kind) = tuple;
- RenderedLine {
- text: vec![
- StyledString {
- text: text1.make_string(),
- style: style1,
- },
- StyledString {
- text: text2.make_string(),
- style: style2,
- }
- ],
- kind: kind,
- }
- }
-}
-
-impl RenderedLine {
- fn trim_last(&mut self) {
- if let Some(last_text) = self.text.last_mut() {
- let len = last_text.text.trim_right().len();
- last_text.text.truncate(len);
- }
- }
-}
-
-impl RenderedLineKind {
- fn prefix(&self) -> StyledString {
- match *self {
- RenderedLineKind::SourceText { file: _, line_index } =>
- StyledString {
- text: format!("{}", line_index + 1),
- style: Style::LineNumber,
- },
- RenderedLineKind::Elision =>
- StyledString {
- text: String::from("..."),
- style: Style::LineNumber,
- },
- RenderedLineKind::PrimaryFileName |
- RenderedLineKind::OtherFileName |
- RenderedLineKind::Annotations =>
- StyledString {
- text: String::from(""),
- style: Style::LineNumber,
- },
- }
- }
-}
-
-impl StyledBuffer {
- fn new() -> StyledBuffer {
- StyledBuffer { text: vec![], styles: vec![] }
- }
-
- fn render(&self, source_kind: RenderedLineKind) -> Vec<RenderedLine> {
- let mut output: Vec<RenderedLine> = vec![];
- let mut styled_vec: Vec<StyledString> = vec![];
-
- for (row, row_style) in self.text.iter().zip(&self.styles) {
- let mut current_style = Style::NoStyle;
- let mut current_text = String::new();
-
- for (&c, &s) in row.iter().zip(row_style) {
- if s != current_style {
- if !current_text.is_empty() {
- styled_vec.push(StyledString { text: current_text, style: current_style });
- }
- current_style = s;
- current_text = String::new();
- }
- current_text.push(c);
- }
- if !current_text.is_empty() {
- styled_vec.push(StyledString { text: current_text, style: current_style });
- }
-
- if output.is_empty() {
- //We know our first output line is source and the rest are highlights and labels
- output.push(RenderedLine { text: styled_vec, kind: source_kind.clone() });
- } else {
- output.push(RenderedLine { text: styled_vec, kind: RenderedLineKind::Annotations });
- }
- styled_vec = vec![];
- }
-
- output
- }
-
- fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
- while line >= self.text.len() {
- self.text.push(vec![]);
- self.styles.push(vec![]);
- }
-
- if col < self.text[line].len() {
- self.text[line][col] = chr;
- self.styles[line][col] = style;
- } else {
- let mut i = self.text[line].len();
- while i < col {
- let s = match self.text[0].get(i) {
- Some(&'\t') => '\t',
- _ => ' '
- };
- self.text[line].push(s);
- self.styles[line].push(Style::NoStyle);
- i += 1;
- }
- self.text[line].push(chr);
- self.styles[line].push(style);
- }
- }
-
- fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
- let mut n = col;
- for c in string.chars() {
- self.putc(line, n, c, style);
- n += 1;
- }
- }
-
- fn set_style(&mut self, line: usize, col: usize, style: Style) {
- if self.styles.len() > line && self.styles[line].len() > col {
- self.styles[line][col] = style;
- }
- }
-
- fn append(&mut self, line: usize, string: &str, style: Style) {
- if line >= self.text.len() {
- self.puts(line, 0, string, style);
- } else {
- let col = self.text[line].len();
- self.puts(line, col, string, style);
- }
- }
-}
-
-impl FileInfo {
- fn push_lines(&mut self,
- lines: &[LineInfo],
- is_primary: bool,
- label: Option<String>) {
- assert!(lines.len() > 0);
-
- // If a span covers multiple lines, we reduce it to a single
- // point at the start of the span. This means that instead
- // of producing output like this:
- //
- // ```
- // --> foo.rs:2:1
- // 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>)
- // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- // 3 |> -> Set<LR0Item<'grammar>>
- // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- // (and so on)
- // ```
- //
- // we produce:
- //
- // ```
- // --> foo.rs:2:1
- // 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>)
- // ^
- // ```
- //
- // Basically, although this loses information, multi-line spans just
- // never look good.
-
- let (line, start_col, mut end_col, is_minimized) = if lines.len() == 1 {
- (lines[0].line_index, lines[0].start_col, lines[0].end_col, false)
- } else {
- (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1), true)
- };
-
- // Watch out for "empty spans". If we get a span like 6..6, we
- // want to just display a `^` at 6, so convert that to
- // 6..7. This is degenerate input, but it's best to degrade
- // gracefully -- and the parser likes to suply a span like
- // that for EOF, in particular.
- if start_col == end_col {
- end_col.0 += 1;
- }
-
- let index = self.ensure_source_line(line);
- self.lines[index].push_annotation(start_col,
- end_col,
- is_primary,
- is_minimized,
- label);
- }
-
- /// Ensure that we have a `Line` struct corresponding to
- /// `line_index` in the file. If we already have some other lines,
- /// then this will add the intervening lines to ensure that we
- /// have a complete snippet. (Note that when we finally display,
- /// some of those lines may be elided.)
- fn ensure_source_line(&mut self, line_index: usize) -> usize {
- if self.lines.is_empty() {
- self.lines.push(Line::new(line_index));
- return 0;
- }
-
- // Find the range of lines we have thus far.
- let first_line_index = self.lines.first().unwrap().line_index;
- let last_line_index = self.lines.last().unwrap().line_index;
- assert!(first_line_index <= last_line_index);
-
- // If the new line is lower than all the lines we have thus
- // far, then insert the new line and any intervening lines at
- // the front. In a silly attempt at micro-optimization, we
- // don't just call `insert` repeatedly, but instead make a new
- // (empty) vector, pushing the new lines onto it, and then
- // appending the old vector.
- if line_index < first_line_index {
- let lines = mem::replace(&mut self.lines, vec![]);
- self.lines.extend(
- (line_index .. first_line_index)
- .map(|line| Line::new(line))
- .chain(lines));
- return 0;
- }
-
- // If the new line comes after the ones we have so far, insert
- // lines for it.
- if line_index > last_line_index {
- self.lines.extend(
- (last_line_index+1 .. line_index+1)
- .map(|line| Line::new(line)));
- return self.lines.len() - 1;
- }
-
- // Otherwise it should already exist.
- return line_index - first_line_index;
- }
-
- fn render_file_lines(&self, codemap: &Rc<CodeMap>) -> Vec<RenderedLine> {
- let old_school = check_old_skool();
-
- // As a first step, we elide any instance of more than one
- // continuous unannotated line.
-
- let mut lines_iter = self.lines.iter();
- let mut output = vec![];
-
- // First insert the name of the file.
- if !old_school {
- match self.primary_span {
- Some(span) => {
- let lo = codemap.lookup_char_pos(span.lo);
- output.push(RenderedLine {
- text: vec![StyledString {
- text: lo.file.name.clone(),
- style: Style::FileNameStyle,
- }, StyledString {
- text: format!(":{}:{}", lo.line, lo.col.0 + 1),
- style: Style::LineAndColumn,
- }],
- kind: RenderedLineKind::PrimaryFileName,
- });
- output.push(RenderedLine {
- text: vec![StyledString {
- text: "".to_string(),
- style: Style::FileNameStyle,
- }],
- kind: RenderedLineKind::Annotations,
- });
- }
- None => {
- output.push(RenderedLine {
- text: vec![StyledString {
- text: self.file.name.clone(),
- style: Style::FileNameStyle,
- }],
- kind: RenderedLineKind::OtherFileName,
- });
- output.push(RenderedLine {
- text: vec![StyledString {
- text: "".to_string(),
- style: Style::FileNameStyle,
- }],
- kind: RenderedLineKind::Annotations,
- });
- }
- }
- }
-
- let mut next_line = lines_iter.next();
- while next_line.is_some() {
- // Consume lines with annotations.
- while let Some(line) = next_line {
- if line.annotations.is_empty() { break; }
-
- let mut rendered_lines = self.render_line(line);
- assert!(!rendered_lines.is_empty());
- if old_school {
- match self.primary_span {
- Some(span) => {
- let lo = codemap.lookup_char_pos(span.lo);
- let hi = codemap.lookup_char_pos(span.hi);
- //Before each secondary line in old skool-mode, print the label
- //as an old-style note
- if !line.annotations[0].is_primary {
- if let Some(ann) = line.annotations[0].label.clone() {
- output.push(RenderedLine {
- text: vec![StyledString {
- text: lo.file.name.clone(),
- style: Style::FileNameStyle,
- }, StyledString {
- text: format!(":{}:{}: {}:{} ", lo.line, lo.col.0 + 1,
- hi.line, hi.col.0+1),
- style: Style::LineAndColumn,
- }, StyledString {
- text: format!("note: "),
- style: Style::OldSkoolNote,
- }, StyledString {
- text: format!("{}", ann),
- style: Style::OldSkoolNoteText,
- }],
- kind: RenderedLineKind::Annotations,
- });
- }
- }
- rendered_lines[0].text.insert(0, StyledString {
- text: format!(":{} ", lo.line),
- style: Style::LineAndColumn,
- });
- rendered_lines[0].text.insert(0, StyledString {
- text: lo.file.name.clone(),
- style: Style::FileNameStyle,
- });
- let gap_amount =
- rendered_lines[0].text[0].text.len() +
- rendered_lines[0].text[1].text.len();
- assert!(rendered_lines.len() >= 2,
- "no annotations resulted from: {:?}",
- line);
- for i in 1..rendered_lines.len() {
- rendered_lines[i].text.insert(0, StyledString {
- text: vec![" "; gap_amount].join(""),
- style: Style::NoStyle
- });
- }
- }
- _ =>()
- }
- }
- output.append(&mut rendered_lines);
- next_line = lines_iter.next();
- }
-
- // Emit lines without annotations, but only if they are
- // followed by a line with an annotation.
- let unannotated_line = next_line;
- let mut unannotated_lines = 0;
- while let Some(line) = next_line {
- if !line.annotations.is_empty() { break; }
- unannotated_lines += 1;
- next_line = lines_iter.next();
- }
- if unannotated_lines > 1 {
- output.push(RenderedLine::from((String::new(),
- Style::NoStyle,
- RenderedLineKind::Elision)));
- } else if let Some(line) = unannotated_line {
- output.append(&mut self.render_line(line));
- }
- }
-
- output
- }
-
- fn render_line(&self, line: &Line) -> Vec<RenderedLine> {
- let old_school = check_old_skool();
- let source_string = self.file.get_line(line.line_index)
- .unwrap_or("");
- let source_kind = RenderedLineKind::SourceText {
- file: self.file.clone(),
- line_index: line.line_index,
- };
-
- let mut styled_buffer = StyledBuffer::new();
-
- // First create the source line we will highlight.
- styled_buffer.append(0, &source_string, Style::Quotation);
-
- if line.annotations.is_empty() {
- return styled_buffer.render(source_kind);
- }
-
- // We want to display like this:
- //
- // vec.push(vec.pop().unwrap());
- // --- ^^^ _ previous borrow ends here
- // | |
- // | error occurs here
- // previous borrow of `vec` occurs here
- //
- // But there are some weird edge cases to be aware of:
- //
- // vec.push(vec.pop().unwrap());
- // -------- - previous borrow ends here
- // ||
- // |this makes no sense
- // previous borrow of `vec` occurs here
- //
- // For this reason, we group the lines into "highlight lines"
- // and "annotations lines", where the highlight lines have the `~`.
-
- //let mut highlight_line = Self::whitespace(&source_string);
-
- // Sort the annotations by (start, end col)
- let mut annotations = line.annotations.clone();
- annotations.sort();
-
- // Next, create the highlight line.
- for annotation in &annotations {
- if old_school {
- for p in annotation.start_col .. annotation.end_col {
- if p == annotation.start_col {
- styled_buffer.putc(1, p, '^',
- if annotation.is_primary {
- Style::UnderlinePrimary
- } else {
- Style::OldSkoolNote
- });
- }
- else {
- styled_buffer.putc(1, p, '~',
- if annotation.is_primary {
- Style::UnderlinePrimary
- } else {
- Style::OldSkoolNote
- });
- }
- }
- }
- else {
- for p in annotation.start_col .. annotation.end_col {
- if annotation.is_primary {
- styled_buffer.putc(1, p, '^', Style::UnderlinePrimary);
- if !annotation.is_minimized {
- styled_buffer.set_style(0, p, Style::UnderlinePrimary);
- }
- } else {
- styled_buffer.putc(1, p, '-', Style::UnderlineSecondary);
- if !annotation.is_minimized {
- styled_buffer.set_style(0, p, Style::UnderlineSecondary);
- }
- }
- }
- }
- }
-
- // Now we are going to write labels in. To start, we'll exclude
- // the annotations with no labels.
- let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) =
- annotations.into_iter()
- .partition(|a| a.label.is_some());
-
- // If there are no annotations that need text, we're done.
- if labeled_annotations.is_empty() {
- return styled_buffer.render(source_kind);
- }
- if old_school {
- return styled_buffer.render(source_kind);
- }
-
- // Now add the text labels. We try, when possible, to stick the rightmost
- // annotation at the end of the highlight line:
- //
- // vec.push(vec.pop().unwrap());
- // --- --- - previous borrow ends here
- //
- // But sometimes that's not possible because one of the other
- // annotations overlaps it. For example, from the test
- // `span_overlap_label`, we have the following annotations
- // (written on distinct lines for clarity):
- //
- // fn foo(x: u32) {
- // --------------
- // -
- //
- // In this case, we can't stick the rightmost-most label on
- // the highlight line, or we would get:
- //
- // fn foo(x: u32) {
- // -------- x_span
- // |
- // fn_span
- //
- // which is totally weird. Instead we want:
- //
- // fn foo(x: u32) {
- // --------------
- // | |
- // | x_span
- // fn_span
- //
- // which is...less weird, at least. In fact, in general, if
- // the rightmost span overlaps with any other span, we should
- // use the "hang below" version, so we can at least make it
- // clear where the span *starts*.
- let mut labeled_annotations = &labeled_annotations[..];
- match labeled_annotations.split_last().unwrap() {
- (last, previous) => {
- if previous.iter()
- .chain(&unlabeled_annotations)
- .all(|a| !overlaps(a, last))
- {
- // append the label afterwards; we keep it in a separate
- // string
- let highlight_label: String = format!(" {}", last.label.as_ref().unwrap());
- if last.is_primary {
- styled_buffer.append(1, &highlight_label, Style::LabelPrimary);
- } else {
- styled_buffer.append(1, &highlight_label, Style::LabelSecondary);
- }
- labeled_annotations = previous;
- }
- }
- }
-
- // If that's the last annotation, we're done
- if labeled_annotations.is_empty() {
- return styled_buffer.render(source_kind);
- }
-
- for (index, annotation) in labeled_annotations.iter().enumerate() {
- // Leave:
- // - 1 extra line
- // - One line for each thing that comes after
- let comes_after = labeled_annotations.len() - index - 1;
- let blank_lines = 3 + comes_after;
-
- // For each blank line, draw a `|` at our column. The
- // text ought to be long enough for this.
- for index in 2..blank_lines {
- if annotation.is_primary {
- styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlinePrimary);
- } else {
- styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlineSecondary);
- }
- }
-
- if annotation.is_primary {
- styled_buffer.puts(blank_lines, annotation.start_col,
- annotation.label.as_ref().unwrap(), Style::LabelPrimary);
- } else {
- styled_buffer.puts(blank_lines, annotation.start_col,
- annotation.label.as_ref().unwrap(), Style::LabelSecondary);
- }
- }
-
- styled_buffer.render(source_kind)
- }
-}
-
-fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) {
- let old_school = check_old_skool();
- if old_school {
- return;
- }
-
- let prefixes: Vec<_> =
- rendered_lines.iter()
- .map(|rl| rl.kind.prefix())
- .collect();
-
- // find the max amount of spacing we need; add 1 to
- // p.text.len() to leave space between the prefix and the
- // source text
- let padding_len =
- prefixes.iter()
- .map(|p| if p.text.len() == 0 { 0 } else { p.text.len() + 1 })
- .max()
- .unwrap_or(0);
-
- // Ensure we insert at least one character of padding, so that the
- // `-->` arrows can fit etc.
- let padding_len = cmp::max(padding_len, 1);
-
- for (mut prefix, line) in prefixes.into_iter().zip(rendered_lines) {
- let extra_spaces = (prefix.text.len() .. padding_len).map(|_| ' ');
- prefix.text.extend(extra_spaces);
- match line.kind {
- RenderedLineKind::Elision => {
- line.text.insert(0, prefix);
- }
- RenderedLineKind::PrimaryFileName => {
- // --> filename
- // 22 |>
- // ^
- // padding_len
- let dashes = (0..padding_len - 1).map(|_| ' ')
- .chain(Some('-'))
- .chain(Some('-'))
- .chain(Some('>'))
- .chain(Some(' '));
- line.text.insert(0, StyledString {text: dashes.collect(),
- style: Style::LineNumber})
- }
- RenderedLineKind::OtherFileName => {
- // ::: filename
- // 22 |>
- // ^
- // padding_len
- let dashes = (0..padding_len - 1).map(|_| ' ')
- .chain(Some(':'))
- .chain(Some(':'))
- .chain(Some(':'))
- .chain(Some(' '));
- line.text.insert(0, StyledString {text: dashes.collect(),
- style: Style::LineNumber})
- }
- _ => {
- line.text.insert(0, prefix);
- line.text.insert(1, StyledString {text: String::from("|> "),
- style: Style::LineNumber})
- }
- }
- }
-}
-
-fn trim_lines(rendered_lines: &mut [RenderedLine]) {
- for line in rendered_lines {
- while !line.text.is_empty() {
- line.trim_last();
- if line.text.last().unwrap().text.is_empty() {
- line.text.pop();
- } else {
- break;
- }
- }
- }
-}
-
-impl Line {
- fn new(line_index: usize) -> Line {
- Line {
- line_index: line_index,
- annotations: vec![]
- }
- }
-
- fn push_annotation(&mut self,
- start: CharPos,
- end: CharPos,
- is_primary: bool,
- is_minimized: bool,
- label: Option<String>) {
- self.annotations.push(Annotation {
- start_col: start.0,
- end_col: end.0,
- is_primary: is_primary,
- is_minimized: is_minimized,
- label: label,
- });
- }
-}
-
-fn overlaps(a1: &Annotation,
- a2: &Annotation)
- -> bool
-{
- (a2.start_col .. a2.end_col).contains(a1.start_col) ||
- (a1.start_col .. a1.end_col).contains(a2.start_col)
-}
+++ /dev/null
-// Copyright 2016 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Code for testing annotated snippets.
-
-#![cfg(test)]
-
-use codemap::{BytePos, CodeMap, FileMap, NO_EXPANSION, Span};
-use std::rc::Rc;
-use super::{RenderedLine, SnippetData};
-
-/// Returns the span corresponding to the `n`th occurrence of
-/// `substring` in `source_text`.
-trait CodeMapExtension {
- fn span_substr(&self,
- file: &Rc<FileMap>,
- source_text: &str,
- substring: &str,
- n: usize)
- -> Span;
-}
-
-impl CodeMapExtension for CodeMap {
- fn span_substr(&self,
- file: &Rc<FileMap>,
- source_text: &str,
- substring: &str,
- n: usize)
- -> Span
- {
- println!("span_substr(file={:?}/{:?}, substring={:?}, n={})",
- file.name, file.start_pos, substring, n);
- let mut i = 0;
- let mut hi = 0;
- loop {
- let offset = source_text[hi..].find(substring).unwrap_or_else(|| {
- panic!("source_text `{}` does not have {} occurrences of `{}`, only {}",
- source_text, n, substring, i);
- });
- let lo = hi + offset;
- hi = lo + substring.len();
- if i == n {
- let span = Span {
- lo: BytePos(lo as u32 + file.start_pos.0),
- hi: BytePos(hi as u32 + file.start_pos.0),
- expn_id: NO_EXPANSION,
- };
- assert_eq!(&self.span_to_snippet(span).unwrap()[..],
- substring);
- return span;
- }
- i += 1;
- }
- }
-}
-
-fn splice(start: Span, end: Span) -> Span {
- Span {
- lo: start.lo,
- hi: end.hi,
- expn_id: NO_EXPANSION,
- }
-}
-
-fn make_string(lines: &[RenderedLine]) -> String {
- lines.iter()
- .flat_map(|rl| {
- rl.text.iter()
- .map(|s| &s.text[..])
- .chain(Some("\n"))
- })
- .collect()
-}
-
-#[test]
-fn tab() {
- let file_text = "
-fn foo() {
-\tbar;
-}
-";
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
- let span_bar = cm.span_substr(&foo, file_text, "bar", 0);
-
- let mut snippet = SnippetData::new(cm, Some(span_bar));
- snippet.push(span_bar, true, None);
-
- let lines = snippet.render_lines();
- let text = make_string(&lines);
- assert_eq!(&text[..], &"
- --> foo.rs:3:2
- |>
-3 |> \tbar;
- |> \t^^^
-"[1..]);
-}
-
-#[test]
-fn one_line() {
- let file_text = r#"
-fn foo() {
- vec.push(vec.pop().unwrap());
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
- let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
- let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
- let span_semi = cm.span_substr(&foo, file_text, ";", 0);
-
- let mut snippet = SnippetData::new(cm, None);
- snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
- snippet.push(span_vec1, false, Some(format!("error occurs here")));
- snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
-
- let lines = snippet.render_lines();
- println!("{:#?}", lines);
-
- let text: String = make_string(&lines);
-
- println!("text=\n{}", text);
- assert_eq!(&text[..], &r#"
- ::: foo.rs
- |>
-3 |> vec.push(vec.pop().unwrap());
- |> --- --- - previous borrow ends here
- |> | |
- |> | error occurs here
- |> previous borrow of `vec` occurs here
-"#[1..]);
-}
-
-#[test]
-fn two_files() {
- let file_text_foo = r#"
-fn foo() {
- vec.push(vec.pop().unwrap());
-}
-"#;
-
- let file_text_bar = r#"
-fn bar() {
- // these blank links here
- // serve to ensure that the line numbers
- // from bar.rs
- // require more digits
-
-
-
-
-
-
-
-
-
-
- vec.push();
-
- // this line will get elided
-
- vec.pop().unwrap());
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo_map = cm.new_filemap_and_lines("foo.rs", None, file_text_foo);
- let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0);
- let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1);
- let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0);
-
- let bar_map = cm.new_filemap_and_lines("bar.rs", None, file_text_bar);
- let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0);
- let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1);
- let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0);
-
- let mut snippet = SnippetData::new(cm, Some(span_foo_vec1));
- snippet.push(span_foo_vec0, false, Some(format!("a")));
- snippet.push(span_foo_vec1, true, Some(format!("b")));
- snippet.push(span_foo_semi, false, Some(format!("c")));
- snippet.push(span_bar_vec0, false, Some(format!("d")));
- snippet.push(span_bar_vec1, false, Some(format!("e")));
- snippet.push(span_bar_semi, false, Some(format!("f")));
-
- let lines = snippet.render_lines();
- println!("{:#?}", lines);
-
- let text: String = make_string(&lines);
-
- println!("text=\n{}", text);
-
- // Note that the `|>` remain aligned across both files:
- assert_eq!(&text[..], &r#"
- --> foo.rs:3:14
- |>
-3 |> vec.push(vec.pop().unwrap());
- |> --- ^^^ - c
- |> | |
- |> | b
- |> a
- ::: bar.rs
- |>
-17 |> vec.push();
- |> --- - f
- |> |
- |> d
-...
-21 |> vec.pop().unwrap());
- |> --- e
-"#[1..]);
-}
-
-#[test]
-fn multi_line() {
- let file_text = r#"
-fn foo() {
- let name = find_id(&data, 22).unwrap();
-
- // Add one more item we forgot to the vector. Silly us.
- data.push(Data { name: format!("Hera"), id: 66 });
-
- // Print everything out.
- println!("Name: {:?}", name);
- println!("Data: {:?}", data);
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
- let span_data0 = cm.span_substr(&foo, file_text, "data", 0);
- let span_data1 = cm.span_substr(&foo, file_text, "data", 1);
- let span_rbrace = cm.span_substr(&foo, file_text, "}", 3);
-
- let mut snippet = SnippetData::new(cm, None);
- snippet.push(span_data0, false, Some(format!("immutable borrow begins here")));
- snippet.push(span_data1, false, Some(format!("mutable borrow occurs here")));
- snippet.push(span_rbrace, false, Some(format!("immutable borrow ends here")));
-
- let lines = snippet.render_lines();
- println!("{:#?}", lines);
-
- let text: String = make_string(&lines);
-
- println!("text=\n{}", text);
- assert_eq!(&text[..], &r#"
- ::: foo.rs
- |>
-3 |> let name = find_id(&data, 22).unwrap();
- |> ---- immutable borrow begins here
-...
-6 |> data.push(Data { name: format!("Hera"), id: 66 });
- |> ---- mutable borrow occurs here
-...
-11 |> }
- |> - immutable borrow ends here
-"#[1..]);
-}
-
-#[test]
-fn overlapping() {
- let file_text = r#"
-fn foo() {
- vec.push(vec.pop().unwrap());
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
- let span0 = cm.span_substr(&foo, file_text, "vec.push", 0);
- let span1 = cm.span_substr(&foo, file_text, "vec", 0);
- let span2 = cm.span_substr(&foo, file_text, "ec.push", 0);
- let span3 = cm.span_substr(&foo, file_text, "unwrap", 0);
-
- let mut snippet = SnippetData::new(cm, None);
- snippet.push(span0, false, Some(format!("A")));
- snippet.push(span1, false, Some(format!("B")));
- snippet.push(span2, false, Some(format!("C")));
- snippet.push(span3, false, Some(format!("D")));
-
- let lines = snippet.render_lines();
- println!("{:#?}", lines);
- let text: String = make_string(&lines);
-
- println!("text=r#\"\n{}\".trim_left()", text);
- assert_eq!(&text[..], &r#"
- ::: foo.rs
- |>
-3 |> vec.push(vec.pop().unwrap());
- |> -------- ------ D
- |> ||
- |> |C
- |> A
- |> B
-"#[1..]);
-}
-
-#[test]
-fn one_line_out_of_order() {
- let file_text = r#"
-fn foo() {
- vec.push(vec.pop().unwrap());
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
- let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
- let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
- let span_semi = cm.span_substr(&foo, file_text, ";", 0);
-
- // intentionally don't push the snippets left to right
- let mut snippet = SnippetData::new(cm, None);
- snippet.push(span_vec1, false, Some(format!("error occurs here")));
- snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
- snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
-
- let lines = snippet.render_lines();
- println!("{:#?}", lines);
- let text: String = make_string(&lines);
-
- println!("text=r#\"\n{}\".trim_left()", text);
- assert_eq!(&text[..], &r#"
- ::: foo.rs
- |>
-3 |> vec.push(vec.pop().unwrap());
- |> --- --- - previous borrow ends here
- |> | |
- |> | error occurs here
- |> previous borrow of `vec` occurs here
-"#[1..]);
-}
-
-#[test]
-fn elide_unnecessary_lines() {
- let file_text = r#"
-fn foo() {
- let mut vec = vec![0, 1, 2];
- let mut vec2 = vec;
- vec2.push(3);
- vec2.push(4);
- vec2.push(5);
- vec2.push(6);
- vec.push(7);
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
- let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3);
- let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8);
-
- let mut snippet = SnippetData::new(cm, None);
- snippet.push(span_vec0, false, Some(format!("`vec` moved here because it \
- has type `collections::vec::Vec<i32>`")));
- snippet.push(span_vec1, false, Some(format!("use of moved value: `vec`")));
-
- let lines = snippet.render_lines();
- println!("{:#?}", lines);
- let text: String = make_string(&lines);
- println!("text=r#\"\n{}\".trim_left()", text);
- assert_eq!(&text[..], &r#"
- ::: foo.rs
- |>
-4 |> let mut vec2 = vec;
- |> --- `vec` moved here because it has type `collections::vec::Vec<i32>`
-...
-9 |> vec.push(7);
- |> --- use of moved value: `vec`
-"#[1..]);
-}
-
-#[test]
-fn spans_without_labels() {
- let file_text = r#"
-fn foo() {
- let mut vec = vec![0, 1, 2];
- let mut vec2 = vec;
- vec2.push(3);
- vec2.push(4);
- vec2.push(5);
- vec2.push(6);
- vec.push(7);
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
- let mut snippet = SnippetData::new(cm.clone(), None);
- for i in 0..4 {
- let span_veci = cm.span_substr(&foo, file_text, "vec", i);
- snippet.push(span_veci, false, None);
- }
-
- let lines = snippet.render_lines();
- let text: String = make_string(&lines);
- println!("text=&r#\"\n{}\n\"#[1..]", text);
- assert_eq!(text, &r#"
- ::: foo.rs
- |>
-3 |> let mut vec = vec![0, 1, 2];
- |> --- ---
-4 |> let mut vec2 = vec;
- |> --- ---
-"#[1..]);
-}
-
-#[test]
-fn span_long_selection() {
- let file_text = r#"
-impl SomeTrait for () {
- fn foo(x: u32) {
- // impl 1
- // impl 2
- // impl 3
- }
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
- let mut snippet = SnippetData::new(cm.clone(), None);
- let fn_span = cm.span_substr(&foo, file_text, "fn", 0);
- let rbrace_span = cm.span_substr(&foo, file_text, "}", 0);
- snippet.push(splice(fn_span, rbrace_span), false, None);
- let lines = snippet.render_lines();
- let text: String = make_string(&lines);
- println!("r#\"\n{}\"", text);
- assert_eq!(text, &r#"
- ::: foo.rs
- |>
-3 |> fn foo(x: u32) {
- |> -
-"#[1..]);
-}
-
-#[test]
-fn span_overlap_label() {
- // Test that we don't put `x_span` to the right of its highlight,
- // since there is another highlight that overlaps it.
-
- let file_text = r#"
- fn foo(x: u32) {
- }
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
- let mut snippet = SnippetData::new(cm.clone(), None);
- let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0);
- let x_span = cm.span_substr(&foo, file_text, "x", 0);
- snippet.push(fn_span, false, Some(format!("fn_span")));
- snippet.push(x_span, false, Some(format!("x_span")));
- let lines = snippet.render_lines();
- let text: String = make_string(&lines);
- println!("r#\"\n{}\"", text);
- assert_eq!(text, &r#"
- ::: foo.rs
- |>
-2 |> fn foo(x: u32) {
- |> --------------
- |> | |
- |> | x_span
- |> fn_span
-"#[1..]);
-}
-
-#[test]
-fn span_overlap_label2() {
- // Test that we don't put `x_span` to the right of its highlight,
- // since there is another highlight that overlaps it. In this
- // case, the overlap is only at the beginning, but it's still
- // better to show the beginning more clearly.
-
- let file_text = r#"
- fn foo(x: u32) {
- }
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
- let mut snippet = SnippetData::new(cm.clone(), None);
- let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0);
- let x_span = cm.span_substr(&foo, file_text, "x: u32)", 0);
- snippet.push(fn_span, false, Some(format!("fn_span")));
- snippet.push(x_span, false, Some(format!("x_span")));
- let lines = snippet.render_lines();
- let text: String = make_string(&lines);
- println!("r#\"\n{}\"", text);
- assert_eq!(text, &r#"
- ::: foo.rs
- |>
-2 |> fn foo(x: u32) {
- |> --------------
- |> | |
- |> | x_span
- |> fn_span
-"#[1..]);
-}
-
-#[test]
-fn span_overlap_label3() {
- // Test that we don't put `x_span` to the right of its highlight,
- // since there is another highlight that overlaps it. In this
- // case, the overlap is only at the beginning, but it's still
- // better to show the beginning more clearly.
-
- let file_text = r#"
- fn foo() {
- let closure = || {
- inner
- };
- }
-}
-"#;
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
- let mut snippet = SnippetData::new(cm.clone(), None);
-
- let closure_span = {
- let closure_start_span = cm.span_substr(&foo, file_text, "||", 0);
- let closure_end_span = cm.span_substr(&foo, file_text, "}", 0);
- splice(closure_start_span, closure_end_span)
- };
-
- let inner_span = cm.span_substr(&foo, file_text, "inner", 0);
-
- snippet.push(closure_span, false, Some(format!("foo")));
- snippet.push(inner_span, false, Some(format!("bar")));
-
- let lines = snippet.render_lines();
- let text: String = make_string(&lines);
- println!("r#\"\n{}\"", text);
- assert_eq!(text, &r#"
- ::: foo.rs
- |>
-3 |> let closure = || {
- |> - foo
-4 |> inner
- |> ----- bar
-"#[1..]);
-}
-
-#[test]
-fn span_empty() {
- // In one of the unit tests, we found that the parser sometimes
- // gives empty spans, and in particular it supplied an EOF span
- // like this one, which points at the very end. We want to
- // fallback gracefully in this case.
-
- let file_text = r#"
-fn main() {
- struct Foo;
-
- impl !Sync for Foo {}
-
- unsafe impl Send for &'static Foo {
- // error: cross-crate traits with a default impl, like `core::marker::Send`,
- // can only be implemented for a struct/enum type, not
- // `&'static Foo`
-}"#;
-
-
- let cm = Rc::new(CodeMap::new());
- let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
-
- let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1);
- rbrace_span.lo = rbrace_span.hi;
-
- let mut snippet = SnippetData::new(cm.clone(), Some(rbrace_span));
- snippet.push(rbrace_span, false, None);
- let lines = snippet.render_lines();
- let text: String = make_string(&lines);
- println!("r#\"\n{}\"", text);
- assert_eq!(text, &r#"
- --> foo.rs:11:2
- |>
-11 |> }
- |> -
-"#[1..]);
-}
use ast;
use ast::{Name, PatKind};
use attr::HasAttrs;
-use codemap;
-use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
+use codemap::{self, CodeMap, ExpnInfo};
+use syntax_pos::{Span, ExpnId, NO_EXPANSION};
use errors::DiagnosticBuilder;
use ext;
use ext::expand;
use abi::Abi;
use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind};
use attr;
-use codemap::{Span, respan, Spanned, DUMMY_SP, Pos};
+use syntax_pos::{Span, DUMMY_SP, Pos};
+use codemap::{respan, Spanned};
use ext::base::ExtCtxt;
use parse::token::{self, keywords, InternedString};
use ptr::P;
use ext::build::AstBuilder;
use attr;
use attr::{AttrMetaMethods, WithAttrs, ThinAttributesExt};
-use codemap;
-use codemap::{Span, Spanned, ExpnInfo, ExpnId, NameAndSpan, MacroBang, MacroAttribute};
+use codemap::{Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
+use syntax_pos::{self, Span, ExpnId};
use config::StripUnconfigured;
use ext::base::*;
use feature_gate::{self, Features};
result = expand_item(item, self);
self.pop_mod_path();
} else {
- let filename = if inner != codemap::DUMMY_SP {
+ let filename = if inner != syntax_pos::DUMMY_SP {
Some(self.cx.parse_sess.codemap().span_to_filename(inner))
} else { None };
let orig_filename = replace(&mut self.cx.filename, filename);
use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
use ast;
use ast::Name;
- use codemap;
+ use syntax_pos;
use ext::base::{ExtCtxt, DummyMacroLoader};
use ext::mtwt;
use fold::Folder;
}
impl<'v> Visitor<'v> for IdentFinder {
- fn visit_ident(&mut self, _: codemap::Span, id: ast::Ident){
+ fn visit_ident(&mut self, _: syntax_pos::Span, id: ast::Ident){
self.ident_accumulator.push(id);
}
}
// except according to those terms.
use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, TokenTree, Ty};
-use codemap::Span;
+use syntax_pos::Span;
use ext::base::ExtCtxt;
use ext::base;
use ext::build::AstBuilder;
use ast::TokenTree;
pub use parse::new_parser_from_tts;
- pub use codemap::{BytePos, Span, dummy_spanned, DUMMY_SP};
+ pub use syntax_pos::{BytePos, Span, DUMMY_SP};
+ pub use codemap::{dummy_spanned};
pub trait ToTokens {
fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
// except according to those terms.
use ast;
-use codemap::{Pos, Span};
-use codemap;
+use syntax_pos::{self, Pos, Span};
use ext::base::*;
use ext::base;
use ext::build::AstBuilder;
// resolve a file-system path to an absolute file-system path (if it
// isn't already)
-fn res_rel_file(cx: &mut ExtCtxt, sp: codemap::Span, arg: &Path) -> PathBuf {
+fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf {
// NB: relative paths are resolved relative to the compilation unit
if !arg.is_absolute() {
let mut cu = PathBuf::from(&cx.codemap().span_to_filename(sp));
use ast;
use ast::{TokenTree, Name, Ident};
-use codemap::{BytePos, mk_sp, Span, Spanned};
-use codemap;
+use syntax_pos::{self, BytePos, mk_sp, Span};
+use codemap::Spanned;
use errors::FatalError;
use parse::lexer::*; //resolve bug?
use parse::ParseSess;
/// token tree it was derived from.
pub enum NamedMatch {
- MatchedSeq(Vec<Rc<NamedMatch>>, codemap::Span),
+ MatchedSeq(Vec<Rc<NamedMatch>>, syntax_pos::Span),
MatchedNonterminal(Nonterminal)
}
-> ParseResult<HashMap<Name, Rc<NamedMatch>>> {
fn n_rec(p_s: &ParseSess, m: &TokenTree, res: &[Rc<NamedMatch>],
ret_val: &mut HashMap<Name, Rc<NamedMatch>>, idx: &mut usize)
- -> Result<(), (codemap::Span, String)> {
+ -> Result<(), (syntax_pos::Span, String)> {
match *m {
TokenTree::Sequence(_, ref seq) => {
for next_m in &seq.tts {
pub enum ParseResult<T> {
Success(T),
/// Arm failed to match
- Failure(codemap::Span, String),
+ Failure(syntax_pos::Span, String),
/// Fatal error (malformed macro?). Abort compilation.
- Error(codemap::Span, String)
+ Error(syntax_pos::Span, String)
}
pub type NamedParseResult = ParseResult<HashMap<Name, Rc<NamedMatch>>>;
// except according to those terms.
use ast::{self, TokenTree};
-use codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
use ext::base::{NormalTT, TTMacroExpander};
use ext::tt::macro_parser::{Success, Error, Failure};
use ast;
use ast::{TokenTree, Ident, Name};
-use codemap::{Span, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
use errors::{Handler, DiagnosticBuilder};
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
use parse::token::{DocComment, MatchNt, SubstNt};
use ast;
use attr;
use attr::AttrMetaMethods;
-use codemap::{CodeMap, Span};
+use codemap::CodeMap;
+use syntax_pos::Span;
use errors::Handler;
-use visit;
-use visit::{FnKind, Visitor};
+use visit::{self, FnKind, Visitor};
use parse::ParseSess;
use parse::token::InternedString;
use ast::*;
use ast;
use attr::{ThinAttributes, ThinAttributesExt};
-use codemap::{respan, Span, Spanned};
+use syntax_pos::Span;
+use codemap::{Spanned, respan};
use parse::token::{self, keywords};
use ptr::P;
use util::small_vector::SmallVector;
--- /dev/null
+// Copyright 2012-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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A JSON emitter for errors.
+//!
+//! This works by converting errors to a simplified structural format (see the
+//! structs at the start of the file) and then serialising them. These should
+//! contain as much information about the error as possible.
+//!
+//! The format of the JSON output should be considered *unstable*. For now the
+//! structs at the end of this file (Diagnostic*) specify the error format.
+
+// FIXME spec the JSON output properly.
+
+use codemap::CodeMap;
+use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan};
+use errors::registry::Registry;
+use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
+use errors::emitter::Emitter;
+
+use std::rc::Rc;
+use std::io::{self, Write};
+use std::vec;
+
+use rustc_serialize::json::as_json;
+
+pub struct JsonEmitter {
+ dst: Box<Write + Send>,
+ registry: Option<Registry>,
+ cm: Rc<CodeMapper + 'static>,
+}
+
+impl JsonEmitter {
+ pub fn basic() -> JsonEmitter {
+ JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
+ }
+
+ pub fn stderr(registry: Option<Registry>,
+ code_map: Rc<CodeMap>) -> JsonEmitter {
+ JsonEmitter {
+ dst: Box::new(io::stderr()),
+ registry: registry,
+ cm: code_map,
+ }
+ }
+}
+
+impl Emitter for JsonEmitter {
+ fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, level: Level) {
+ let data = Diagnostic::new(span, msg, code, level, self);
+ if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
+ panic!("failed to print diagnostics: {:?}", e);
+ }
+ }
+
+ fn emit_struct(&mut self, db: &DiagnosticBuilder) {
+ let data = Diagnostic::from_diagnostic_builder(db, self);
+ if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
+ panic!("failed to print diagnostics: {:?}", e);
+ }
+ }
+}
+
+// The following data types are provided just for serialisation.
+
+#[derive(RustcEncodable)]
+struct Diagnostic<'a> {
+ /// The primary error message.
+ message: &'a str,
+ code: Option<DiagnosticCode>,
+ /// "error: internal compiler error", "error", "warning", "note", "help".
+ level: &'static str,
+ spans: Vec<DiagnosticSpan>,
+ /// Associated diagnostic messages.
+ children: Vec<Diagnostic<'a>>,
+ /// The message as rustc would render it. Currently this is only
+ /// `Some` for "suggestions", but eventually it will include all
+ /// snippets.
+ rendered: Option<String>,
+}
+
+#[derive(RustcEncodable)]
+struct DiagnosticSpan {
+ file_name: String,
+ byte_start: u32,
+ byte_end: u32,
+ /// 1-based.
+ line_start: usize,
+ line_end: usize,
+ /// 1-based, character offset.
+ column_start: usize,
+ column_end: usize,
+ /// Is this a "primary" span -- meaning the point, or one of the points,
+ /// where the error occurred?
+ is_primary: bool,
+ /// Source text from the start of line_start to the end of line_end.
+ text: Vec<DiagnosticSpanLine>,
+ /// Label that should be placed at this location (if any)
+ label: Option<String>,
+ /// If we are suggesting a replacement, this will contain text
+ /// that should be sliced in atop this span. You may prefer to
+ /// load the fully rendered version from the parent `Diagnostic`,
+ /// however.
+ suggested_replacement: Option<String>,
+ /// Macro invocations that created the code at this span, if any.
+ expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
+}
+
+#[derive(RustcEncodable)]
+struct DiagnosticSpanLine {
+ text: String,
+
+ /// 1-based, character offset in self.text.
+ highlight_start: usize,
+
+ highlight_end: usize,
+}
+
+#[derive(RustcEncodable)]
+struct DiagnosticSpanMacroExpansion {
+ /// span where macro was applied to generate this code; note that
+ /// this may itself derive from a macro (if
+ /// `span.expansion.is_some()`)
+ span: DiagnosticSpan,
+
+ /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
+ macro_decl_name: String,
+
+ /// span where macro was defined (if known)
+ def_site_span: Option<DiagnosticSpan>,
+}
+
+#[derive(RustcEncodable)]
+struct DiagnosticCode {
+ /// The code itself.
+ code: String,
+ /// An explanation for the code.
+ explanation: Option<&'static str>,
+}
+
+impl<'a> Diagnostic<'a> {
+ fn new(msp: &MultiSpan,
+ msg: &'a str,
+ code: Option<&str>,
+ level: Level,
+ je: &JsonEmitter)
+ -> Diagnostic<'a> {
+ Diagnostic {
+ message: msg,
+ code: DiagnosticCode::map_opt_string(code.map(|c| c.to_owned()), je),
+ level: level.to_str(),
+ spans: DiagnosticSpan::from_multispan(msp, je),
+ children: vec![],
+ rendered: None,
+ }
+ }
+
+ fn from_diagnostic_builder<'c>(db: &'c DiagnosticBuilder,
+ je: &JsonEmitter)
+ -> Diagnostic<'c> {
+ Diagnostic {
+ message: &db.message,
+ code: DiagnosticCode::map_opt_string(db.code.clone(), je),
+ level: db.level.to_str(),
+ spans: DiagnosticSpan::from_multispan(&db.span, je),
+ children: db.children.iter().map(|c| {
+ Diagnostic::from_sub_diagnostic(c, je)
+ }).collect(),
+ rendered: None,
+ }
+ }
+
+ fn from_sub_diagnostic<'c>(db: &'c SubDiagnostic, je: &JsonEmitter) -> Diagnostic<'c> {
+ Diagnostic {
+ message: &db.message,
+ code: None,
+ level: db.level.to_str(),
+ spans: db.render_span.as_ref()
+ .map(|sp| DiagnosticSpan::from_render_span(sp, je))
+ .unwrap_or_else(|| DiagnosticSpan::from_multispan(&db.span, je)),
+ children: vec![],
+ rendered: db.render_span.as_ref()
+ .and_then(|rsp| je.render(rsp)),
+ }
+ }
+}
+
+impl DiagnosticSpan {
+ fn from_span_label(span: SpanLabel,
+ suggestion: Option<&String>,
+ je: &JsonEmitter)
+ -> DiagnosticSpan {
+ Self::from_span_etc(span.span,
+ span.is_primary,
+ span.label,
+ suggestion,
+ je)
+ }
+
+ fn from_span_etc(span: Span,
+ is_primary: bool,
+ label: Option<String>,
+ suggestion: Option<&String>,
+ je: &JsonEmitter)
+ -> DiagnosticSpan {
+ // obtain the full backtrace from the `macro_backtrace`
+ // helper; in some ways, it'd be better to expand the
+ // backtrace ourselves, but the `macro_backtrace` helper makes
+ // some decision, such as dropping some frames, and I don't
+ // want to duplicate that logic here.
+ let backtrace = je.cm.macro_backtrace(span).into_iter();
+ DiagnosticSpan::from_span_full(span,
+ is_primary,
+ label,
+ suggestion,
+ backtrace,
+ je)
+ }
+
+ fn from_span_full(span: Span,
+ is_primary: bool,
+ label: Option<String>,
+ suggestion: Option<&String>,
+ mut backtrace: vec::IntoIter<MacroBacktrace>,
+ je: &JsonEmitter)
+ -> DiagnosticSpan {
+ let start = je.cm.lookup_char_pos(span.lo);
+ let end = je.cm.lookup_char_pos(span.hi);
+ let backtrace_step = backtrace.next().map(|bt| {
+ let call_site =
+ Self::from_span_full(bt.call_site,
+ false,
+ None,
+ None,
+ backtrace,
+ je);
+ let def_site_span = bt.def_site_span.map(|sp| {
+ Self::from_span_full(sp,
+ false,
+ None,
+ None,
+ vec![].into_iter(),
+ je)
+ });
+ Box::new(DiagnosticSpanMacroExpansion {
+ span: call_site,
+ macro_decl_name: bt.macro_decl_name,
+ def_site_span: def_site_span,
+ })
+ });
+ DiagnosticSpan {
+ file_name: start.file.name.clone(),
+ byte_start: span.lo.0,
+ byte_end: span.hi.0,
+ line_start: start.line,
+ line_end: end.line,
+ column_start: start.col.0 + 1,
+ column_end: end.col.0 + 1,
+ is_primary: is_primary,
+ text: DiagnosticSpanLine::from_span(span, je),
+ suggested_replacement: suggestion.cloned(),
+ expansion: backtrace_step,
+ label: label,
+ }
+ }
+
+ fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
+ msp.span_labels()
+ .into_iter()
+ .map(|span_str| Self::from_span_label(span_str, None, je))
+ .collect()
+ }
+
+ fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter)
+ -> Vec<DiagnosticSpan> {
+ assert_eq!(suggestion.msp.span_labels().len(), suggestion.substitutes.len());
+ suggestion.msp.span_labels()
+ .into_iter()
+ .zip(&suggestion.substitutes)
+ .map(|(span_label, suggestion)| {
+ DiagnosticSpan::from_span_label(span_label,
+ Some(suggestion),
+ je)
+ })
+ .collect()
+ }
+
+ fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
+ match *rsp {
+ RenderSpan::FullSpan(ref msp) =>
+ DiagnosticSpan::from_multispan(msp, je),
+ RenderSpan::Suggestion(ref suggestion) =>
+ DiagnosticSpan::from_suggestion(suggestion, je),
+ }
+ }
+}
+
+impl DiagnosticSpanLine {
+ fn line_from_filemap(fm: &syntax_pos::FileMap,
+ index: usize,
+ h_start: usize,
+ h_end: usize)
+ -> DiagnosticSpanLine {
+ DiagnosticSpanLine {
+ text: fm.get_line(index).unwrap().to_owned(),
+ highlight_start: h_start,
+ highlight_end: h_end,
+ }
+ }
+
+ /// Create a list of DiagnosticSpanLines from span - each line with any part
+ /// of `span` gets a DiagnosticSpanLine, with the highlight indicating the
+ /// `span` within the line.
+ fn from_span(span: Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
+ je.cm.span_to_lines(span)
+ .map(|lines| {
+ let fm = &*lines.file;
+ lines.lines
+ .iter()
+ .map(|line| {
+ DiagnosticSpanLine::line_from_filemap(fm,
+ line.line_index,
+ line.start_col.0 + 1,
+ line.end_col.0 + 1)
+ })
+ .collect()
+ })
+ .unwrap_or(vec![])
+ }
+}
+
+impl DiagnosticCode {
+ fn map_opt_string(s: Option<String>, je: &JsonEmitter) -> Option<DiagnosticCode> {
+ s.map(|s| {
+
+ let explanation = je.registry
+ .as_ref()
+ .and_then(|registry| registry.find_description(&s));
+
+ DiagnosticCode {
+ code: s,
+ explanation: explanation,
+ }
+ })
+ }
+}
+
+impl JsonEmitter {
+ fn render(&self, render_span: &RenderSpan) -> Option<String> {
+ use std::borrow::Borrow;
+
+ match *render_span {
+ RenderSpan::FullSpan(_) => {
+ None
+ }
+ RenderSpan::Suggestion(ref suggestion) => {
+ Some(suggestion.splice_lines(self.cm.borrow()))
+ }
+ }
+ }
+}
+
#![feature(str_escape)]
#![feature(unicode)]
#![feature(question_mark)]
-#![feature(range_contains)]
extern crate serialize;
extern crate term;
#[macro_use] extern crate log;
#[macro_use] #[no_link] extern crate rustc_bitflags;
extern crate rustc_unicode;
+pub extern crate rustc_errors as errors;
+extern crate syntax_pos;
extern crate serialize as rustc_serialize; // used by deriving
+
// A variant of 'try!' that panics on an Err. This is used as a crutch on the
// way towards a non-panic!-prone parser. It should be used for fatal parsing
// errors; eventually we plan to convert all code using panictry to just use
macro_rules! panictry {
($e:expr) => ({
use std::result::Result::{Ok, Err};
- use $crate::errors::FatalError;
+ use errors::FatalError;
match $e {
Ok(e) => e,
Err(mut e) => {
pub mod diagnostics {
pub mod macros;
pub mod plugin;
- pub mod registry;
pub mod metadata;
}
-pub mod errors;
+pub mod json;
pub mod syntax {
pub use ext;
use attr;
use ast;
-use codemap::{spanned, Spanned, mk_sp, Span};
+use syntax_pos::{mk_sp, Span};
+use codemap::{spanned, Spanned};
use parse::common::SeqSep;
use parse::PResult;
use parse::token;
pub use self::CommentStyle::*;
use ast;
-use codemap::{BytePos, CharPos, CodeMap, Pos};
+use codemap::CodeMap;
+use syntax_pos::{BytePos, CharPos, Pos};
use errors;
use parse::lexer::is_block_doc_comment;
use parse::lexer::{StringReader, TokenAndSpan};
// except according to those terms.
use ast;
-use codemap::{BytePos, CharPos, CodeMap, Pos, Span};
-use codemap;
+use syntax_pos::{self, BytePos, CharPos, Pos, Span};
+use codemap::CodeMap;
use errors::{FatalError, Handler, DiagnosticBuilder};
use ext::tt::transcribe::tt_next_token;
use parse::token::{self, keywords, str_to_ident};
pub col: CharPos,
/// The last character to be read
pub curr: Option<char>,
- pub filemap: Rc<codemap::FileMap>,
+ pub filemap: Rc<syntax_pos::FileMap>,
// cached:
pub peek_tok: token::Token,
pub peek_span: Span,
impl<'a> StringReader<'a> {
/// For comments.rs, which hackily pokes into pos and curr
pub fn new_raw<'b>(span_diagnostic: &'b Handler,
- filemap: Rc<codemap::FileMap>)
+ filemap: Rc<syntax_pos::FileMap>)
-> StringReader<'b> {
if filemap.src.is_none() {
span_diagnostic.bug(&format!("Cannot lex filemap \
filemap: filemap,
// dummy values; not read
peek_tok: token::Eof,
- peek_span: codemap::DUMMY_SP,
+ peek_span: syntax_pos::DUMMY_SP,
source_text: source_text,
fatal_errs: Vec::new(),
};
}
pub fn new<'b>(span_diagnostic: &'b Handler,
- filemap: Rc<codemap::FileMap>)
+ filemap: Rc<syntax_pos::FileMap>)
-> StringReader<'b> {
let mut sr = StringReader::new_raw(span_diagnostic, filemap);
if let Err(_) = sr.advance_token() {
/// Report a fatal error spanning [`from_pos`, `to_pos`).
fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError {
- self.fatal_span(codemap::mk_sp(from_pos, to_pos), m)
+ self.fatal_span(syntax_pos::mk_sp(from_pos, to_pos), m)
}
/// Report a lexical error spanning [`from_pos`, `to_pos`).
fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) {
- self.err_span(codemap::mk_sp(from_pos, to_pos), m)
+ self.err_span(syntax_pos::mk_sp(from_pos, to_pos), m)
}
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
for c in c.escape_default() {
m.push(c)
}
- self.span_diagnostic.struct_span_fatal(codemap::mk_sp(from_pos, to_pos), &m[..])
+ self.span_diagnostic.struct_span_fatal(syntax_pos::mk_sp(from_pos, to_pos), &m[..])
}
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
for c in c.escape_default() {
m.push(c)
}
- self.span_diagnostic.struct_span_err(codemap::mk_sp(from_pos, to_pos), &m[..])
+ self.span_diagnostic.struct_span_err(syntax_pos::mk_sp(from_pos, to_pos), &m[..])
}
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending the
None => {
if self.is_eof() {
self.peek_tok = token::Eof;
- self.peek_span = codemap::mk_sp(self.filemap.end_pos, self.filemap.end_pos);
+ self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos);
} else {
let start_bytepos = self.last_pos;
self.peek_tok = self.next_token_inner()?;
- self.peek_span = codemap::mk_sp(start_bytepos, self.last_pos);
+ self.peek_span = syntax_pos::mk_sp(start_bytepos, self.last_pos);
};
}
}
match self.curr {
Some(c) => {
if c.is_whitespace() {
- self.span_diagnostic.span_err(codemap::mk_sp(self.last_pos, self.last_pos),
+ self.span_diagnostic.span_err(syntax_pos::mk_sp(self.last_pos, self.last_pos),
"called consume_any_line_comment, but there \
was whitespace");
}
Some(TokenAndSpan {
tok: tok,
- sp: codemap::mk_sp(start_bpos, self.last_pos),
+ sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
})
})
} else {
Some(TokenAndSpan {
tok: token::Comment,
- sp: codemap::mk_sp(start_bpos, self.last_pos),
+ sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
})
};
}
}
return Some(TokenAndSpan {
tok: token::Shebang(self.name_from(start)),
- sp: codemap::mk_sp(start, self.last_pos),
+ sp: syntax_pos::mk_sp(start, self.last_pos),
});
}
}
}
let c = Some(TokenAndSpan {
tok: token::Whitespace,
- sp: codemap::mk_sp(start_bpos, self.last_pos),
+ sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
});
debug!("scanning whitespace: {:?}", c);
c
Some(TokenAndSpan {
tok: tok,
- sp: codemap::mk_sp(start_bpos, self.last_pos),
+ sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
})
})
}
let valid = if self.curr_is('{') {
self.scan_unicode_escape(delim) && !ascii_only
} else {
- let span = codemap::mk_sp(start, self.last_pos);
+ let span = syntax_pos::mk_sp(start, self.last_pos);
self.span_diagnostic
.struct_span_err(span, "incorrect unicode escape sequence")
.span_help(span,
},
c);
if e == '\r' {
- err.span_help(codemap::mk_sp(escaped_pos, last_pos),
+ err.span_help(syntax_pos::mk_sp(escaped_pos, last_pos),
"this is an isolated carriage return; consider \
checking your editor and version control \
settings");
}
if (e == '{' || e == '}') && !ascii_only {
- err.span_help(codemap::mk_sp(escaped_pos, last_pos),
+ err.span_help(syntax_pos::mk_sp(escaped_pos, last_pos),
"if used in a formatting string, curly braces \
are escaped with `{{` and `}}`");
}
mod tests {
use super::*;
- use codemap::{BytePos, CodeMap, Span, NO_EXPANSION};
+ use syntax_pos::{BytePos, Span, NO_EXPANSION};
+ use codemap::CodeMap;
use errors;
use parse::token;
use parse::token::str_to_ident;
fn mk_sh(cm: Rc<CodeMap>) -> errors::Handler {
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
- let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), None, cm);
+ let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()),
+ None,
+ cm,
+ errors::snippet::FormatMode::EnvironmentSelected);
errors::Handler::with_emitter(true, false, Box::new(emitter))
}
let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string());
let comment = lexer.next_token();
assert_eq!(comment.tok, token::Comment);
- assert_eq!(comment.sp, ::codemap::mk_sp(BytePos(0), BytePos(7)));
+ assert_eq!(comment.sp, ::syntax_pos::mk_sp(BytePos(0), BytePos(7)));
assert_eq!(lexer.next_token().tok, token::Whitespace);
assert_eq!(lexer.next_token().tok,
token::DocComment(token::intern("/// test")));
// Characters and their corresponding confusables were collected from
// http://www.unicode.org/Public/security/revision-06/confusables.txt
-use codemap::mk_sp as make_span;
+use syntax_pos::mk_sp as make_span;
use errors::DiagnosticBuilder;
use super::StringReader;
//! The main parser interface
use ast;
-use codemap::{self, Span, CodeMap, FileMap};
+use codemap::CodeMap;
+use syntax_pos::{self, Span, FileMap};
use errors::{Handler, ColorConfig, DiagnosticBuilder};
use parse::parser::Parser;
use parse::token::InternedString;
let end_pos = filemap.end_pos;
let mut parser = tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg);
- if parser.token == token::Eof && parser.span == codemap::DUMMY_SP {
- parser.span = codemap::mk_sp(end_pos, end_pos);
+ if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP {
+ parser.span = syntax_pos::mk_sp(end_pos, end_pos);
}
parser
mod tests {
use super::*;
use std::rc::Rc;
- use codemap::{Span, BytePos, Pos, Spanned, NO_EXPANSION};
+ use syntax_pos::{Span, BytePos, Pos, NO_EXPANSION};
+ use codemap::Spanned;
use ast::{self, TokenTree, PatKind};
use abi::Abi;
use attr::{first_attr_value_str_by_name, AttrMetaMethods};
use util::parser_testing::{string_to_tts, string_to_parser};
use util::parser_testing::{string_to_expr, string_to_item, string_to_stmt};
- // produce a codemap::span
+ // produce a syntax_pos::span
fn sp(a: u32, b: u32) -> Span {
Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION}
}
//!
//! Obsolete syntax that becomes too hard to parse can be removed.
-use codemap::Span;
+use syntax_pos::Span;
use parse::parser;
/// The specific types of unsupported syntax
use attr::{ThinAttributes, ThinAttributesExt, AttributesExt};
use ast::{BinOpKind, UnOp};
use ast;
-use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap};
+use codemap::{self, CodeMap, Spanned, spanned};
+use syntax_pos::{self, Span, BytePos, mk_sp};
use errors::{self, DiagnosticBuilder};
use ext::tt::macro_parser;
use parse;
{
let tok0 = rdr.real_token();
let span = tok0.sp;
- let filename = if span != codemap::DUMMY_SP {
+ let filename = if span != syntax_pos::DUMMY_SP {
Some(sess.codemap().span_to_filename(span))
} else { None };
let placeholder = TokenAndSpan {
}
/// Parse the fields of a struct-like pattern
- fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<codemap::Spanned<ast::FieldPat>> , bool)> {
+ fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<codemap::Spanned<ast::FieldPat>>, bool)> {
let mut fields = Vec::new();
let mut etc = false;
let mut first = true;
};
fields.push(codemap::Spanned { span: mk_sp(lo, hi),
- node: ast::FieldPat { ident: fieldname,
- pat: subpat,
- is_shorthand: is_shorthand }});
+ node: ast::FieldPat { ident: fieldname,
+ pat: subpat,
+ is_shorthand: is_shorthand }});
}
return Ok((fields, etc));
}
SeqSep::none(), |p| p.parse_token_tree())?;
let mac = Mac_ { path: path, tts: tts, ctxt: EMPTY_CTXT };
pat = PatKind::Mac(codemap::Spanned {node: mac,
- span: mk_sp(lo, self.last_span.hi)});
+ span: mk_sp(lo, self.last_span.hi)});
} else {
// Parse ident @ pat
// This can give false positives and parse nullary enums,
|p| p.parse_token_tree())?;
let m_ = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT };
let m: ast::Mac = codemap::Spanned { node: m_,
- span: mk_sp(lo,
- self.last_span.hi) };
+ span: mk_sp(lo,
+ self.last_span.hi) };
if delim != token::Brace {
self.expect(&token::Semi)?
}
return Err(self.fatal(&format!("expected item, found `{}`", token_str)));
}
- let hi = if self.span == codemap::DUMMY_SP {
+ let hi = if self.span == syntax_pos::DUMMY_SP {
inner_lo
} else {
self.last_span.hi
// single-variant-enum... :
let m = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT };
let m: ast::Mac = codemap::Spanned { node: m,
- span: mk_sp(mac_lo,
- self.last_span.hi) };
+ span: mk_sp(mac_lo,
+ self.last_span.hi) };
if delim != token::Brace {
if !self.eat(&token::Semi) {
use util::parser::AssocOp;
use attr;
use attr::{AttrMetaMethods, AttributeMethods};
-use codemap::{self, CodeMap, BytePos};
+use codemap::{self, CodeMap};
+use syntax_pos::{self, BytePos};
use errors;
use parse::token::{self, keywords, BinOpToken, Token, InternedString};
use parse::lexer::comments;
self.end() // close the head-box
}
- pub fn bclose_(&mut self, span: codemap::Span,
+ pub fn bclose_(&mut self, span: syntax_pos::Span,
indented: usize) -> io::Result<()> {
self.bclose_maybe_open(span, indented, true)
}
- pub fn bclose_maybe_open(&mut self, span: codemap::Span,
+ pub fn bclose_maybe_open(&mut self, span: syntax_pos::Span,
indented: usize, close_box: bool) -> io::Result<()> {
try!(self.maybe_print_comment(span.hi));
try!(self.break_offset_if_not_bol(1, -(indented as isize)));
}
Ok(())
}
- pub fn bclose(&mut self, span: codemap::Span) -> io::Result<()> {
+ pub fn bclose(&mut self, span: syntax_pos::Span) -> io::Result<()> {
self.bclose_(span, INDENT_UNIT)
}
mut op: F,
mut get_span: G) -> io::Result<()> where
F: FnMut(&mut State, &T) -> io::Result<()>,
- G: FnMut(&T) -> codemap::Span,
+ G: FnMut(&T) -> syntax_pos::Span,
{
try!(self.rbox(0, b));
let len = elts.len();
pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef,
generics: &ast::Generics, ident: ast::Ident,
- span: codemap::Span,
+ span: syntax_pos::Span,
visibility: &ast::Visibility) -> io::Result<()> {
try!(self.head(&visibility_qualified(visibility, "enum")));
try!(self.print_ident(ident));
pub fn print_variants(&mut self,
variants: &[ast::Variant],
- span: codemap::Span) -> io::Result<()> {
+ span: syntax_pos::Span) -> io::Result<()> {
try!(self.bopen());
for v in variants {
try!(self.space_if_not_bol());
struct_def: &ast::VariantData,
generics: &ast::Generics,
ident: ast::Ident,
- span: codemap::Span,
+ span: syntax_pos::Span,
print_finalizer: bool) -> io::Result<()> {
try!(self.print_ident(ident));
try!(self.print_generics(generics));
self.end()
}
- pub fn maybe_print_trailing_comment(&mut self, span: codemap::Span,
+ pub fn maybe_print_trailing_comment(&mut self, span: syntax_pos::Span,
next_pos: Option<BytePos>)
-> io::Result<()> {
let cm = match self.cm {
use ast;
use codemap;
use parse::token;
+ use syntax_pos;
#[test]
fn test_fun_to_string() {
let decl = ast::FnDecl {
inputs: Vec::new(),
- output: ast::FunctionRetTy::Default(codemap::DUMMY_SP),
+ output: ast::FunctionRetTy::Default(syntax_pos::DUMMY_SP),
variadic: false
};
let generics = ast::Generics::default();
fn test_variant_to_string() {
let ident = token::str_to_ident("principal_skinner");
- let var = codemap::respan(codemap::DUMMY_SP, ast::Variant_ {
+ let var = codemap::respan(syntax_pos::DUMMY_SP, ast::Variant_ {
name: ident,
attrs: Vec::new(),
// making this up as I go.... ?
use ast;
use attr;
-use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute};
-use codemap;
+use syntax_pos::{DUMMY_SP, Span};
+use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute};
use parse::token::{intern, InternedString, keywords};
use parse::{token, ParseSess};
use ptr::P;
#![allow(dead_code)]
#![allow(unused_imports)]
+
use self::HasTestSignature::*;
use std::iter;
use std::vec;
use attr::AttrMetaMethods;
use attr;
-use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute};
-use codemap;
+use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos};
+use std::rc::Rc;
+
+use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute};
use errors;
+use errors::snippet::{RenderedLine, SnippetData};
use config;
use entry::{self, EntryPointType};
use ext::base::{ExtCtxt, DummyMacroLoader};
use visit::*;
use ast::*;
-use codemap::Span;
+use syntax_pos::Span;
pub struct NodeCounter {
pub count: usize,
use abi::Abi;
use ast::*;
use attr::ThinAttributesExt;
-use codemap::{Span, Spanned};
+use syntax_pos::Span;
+use codemap::Spanned;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum FnKind<'a> {
fmt_macros = { path = "../libfmt_macros" }
log = { path = "../liblog" }
syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
+rustc_errors = { path = "../librustc_errors" }
\ No newline at end of file
use syntax::ast;
use syntax::codemap;
-use syntax::codemap::Span;
use syntax::ext::base;
use syntax::ext::base::*;
use syntax::feature_gate;
use syntax::parse::{self, token};
use syntax::ptr::P;
use syntax::ast::AsmDialect;
+use syntax_pos::Span;
enum State {
Asm,
/// current compilation environment.
use syntax::ast;
-use syntax::codemap::Span;
use syntax::ext::base::*;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;
use syntax::attr;
use syntax::parse::token;
+use syntax_pos::Span;
pub fn expand_cfg<'cx>(cx: &mut ExtCtxt,
sp: Span,
// except according to those terms.
use syntax::ast;
-use syntax::codemap;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
+use syntax_pos;
use std::string::String;
pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
- sp: codemap::Span,
+ sp: syntax_pos::Span,
tts: &[ast::TokenTree])
-> Box<base::MacResult+'static> {
let es = match base::get_exprs_from_tts(cx, sp, tts) {
// except according to those terms.
use syntax::ast::{self, TokenTree};
-use syntax::codemap::Span;
use syntax::ext::base::*;
use syntax::ext::base;
use syntax::feature_gate;
use syntax::parse::token;
use syntax::parse::token::str_to_ident;
use syntax::ptr::P;
+use syntax_pos::Span;
pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree])
-> Box<base::MacResult+'cx> {
use deriving::generic::ty::*;
use syntax::ast::MetaItem;
-use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax_pos::Span;
pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt,
span: Span,
use syntax::ast::{Expr, ItemKind, Generics, MetaItem, VariantData};
use syntax::attr;
-use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
+use syntax_pos::Span;
#[derive(PartialEq)]
enum Mode { Deep, Shallow }
use deriving::generic::ty::*;
use syntax::ast::{MetaItem, Expr};
-use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
+use syntax_pos::Span;
pub fn expand_deriving_eq(cx: &mut ExtCtxt,
span: Span,
use deriving::generic::ty::*;
use syntax::ast::{MetaItem, Expr, self};
-use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
+use syntax_pos::Span;
pub fn expand_deriving_ord(cx: &mut ExtCtxt,
span: Span,
use deriving::generic::ty::*;
use syntax::ast::{MetaItem, Expr, BinOpKind};
-use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
+use syntax_pos::Span;
pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
span: Span,
use deriving::generic::ty::*;
use syntax::ast::{MetaItem, Expr, BinOpKind, self};
-use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
+use syntax_pos::Span;
pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
span: Span,
use syntax::ast;
use syntax::ast::{MetaItem, Expr};
-use syntax::codemap::{Span, respan, DUMMY_SP};
+use syntax::codemap::respan;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::ptr::P;
+use syntax_pos::{Span, DUMMY_SP};
pub fn expand_deriving_debug(cx: &mut ExtCtxt,
span: Span,
use syntax::ast;
use syntax::ast::{MetaItem, Expr, Mutability};
-use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::InternedString;
use syntax::parse::token;
use syntax::ptr::P;
+use syntax_pos::Span;
pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt,
span: Span,
use deriving::generic::ty::*;
use syntax::ast::{MetaItem, Expr};
-use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
+use syntax_pos::Span;
pub fn expand_deriving_default(cx: &mut ExtCtxt,
span: Span,
use deriving::generic::ty::*;
use syntax::ast::{MetaItem, Expr, ExprKind, Mutability};
-use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt,Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::ptr::P;
+use syntax_pos::Span;
pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt,
span: Span,
use syntax::attr::AttrMetaMethods;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
-use syntax::codemap::{self, respan, DUMMY_SP};
-use syntax::codemap::Span;
-use syntax::errors::Handler;
+use syntax::codemap::{self, respan};
use syntax::util::move_map::MoveMap;
use syntax::parse::token::{keywords, InternedString};
use syntax::ptr::P;
+use syntax_pos::{Span, DUMMY_SP};
+use errors::Handler;
use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty};
use syntax::ast::{Expr, Generics, Ident, SelfKind};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
-use syntax::codemap::{Span,respan};
+use syntax::codemap::respan;
use syntax::ptr::P;
+use syntax_pos::Span;
/// The types of pointers
#[derive(Clone, Eq, PartialEq)]
use deriving::generic::ty::*;
use syntax::ast::{MetaItem, Expr, Mutability};
-use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
+use syntax_pos::Span;
pub fn expand_deriving_hash(cx: &mut ExtCtxt,
span: Span,
use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
-use syntax::codemap::{self, Span};
+use syntax::codemap;
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::ptr::P;
+use syntax_pos::Span;
macro_rules! pathvec {
($($x:ident)::+) => (
*/
use syntax::ast;
-use syntax::codemap::Span;
use syntax::ext::base::*;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
+use syntax_pos::Span;
use std::env;
use fmt_macros as parse;
use syntax::ast;
-use syntax::codemap::{Span, respan, DUMMY_SP};
+use syntax::codemap::respan;
use syntax::ext::base::*;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::token::{self, keywords};
use syntax::ptr::P;
+use syntax_pos::{Span, DUMMY_SP};
use std::collections::HashMap;
#[macro_use] extern crate log;
#[macro_use]
extern crate syntax;
+extern crate syntax_pos;
+extern crate rustc_errors as errors;
use syntax::ext::base::{MacroExpanderFn, NormalTT};
use syntax::ext::base::{SyntaxEnv, SyntaxExtension};
// except according to those terms.
use syntax::ast;
-use syntax::codemap;
use syntax::ext::base;
use syntax::feature_gate;
use syntax::print;
+use syntax_pos;
pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt,
- sp: codemap::Span,
+ sp: syntax_pos::Span,
tts: &[ast::TokenTree])
-> Box<base::MacResult+'cx> {
if !cx.ecfg.enable_log_syntax() {
// except according to those terms.
use syntax::ast::TokenTree;
-use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt;
use syntax::ext::base;
use syntax::feature_gate;
use syntax::parse::token::keywords;
-
+use syntax_pos::Span;
pub fn expand_trace_macros(cx: &mut ExtCtxt,
sp: Span,
--- /dev/null
+[package]
+authors = ["The Rust Project Developers"]
+name = "syntax_pos"
+version = "0.0.0"
+
+[lib]
+name = "syntax_pos"
+path = "lib.rs"
+crate-type = ["dylib"]
+
+[dependencies]
+serialize = { path = "../libserialize" }
--- /dev/null
+// Copyright 2012-2013 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The source positions and related helper functions
+//!
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![crate_name = "syntax_pos"]
+#![unstable(feature = "rustc_private", issue = "27812")]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+ html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
+
+#![feature(custom_attribute)]
+#![allow(unused_attributes)]
+#![feature(rustc_private)]
+#![feature(staged_api)]
+#![feature(question_mark)]
+
+use std::cell::{Cell, RefCell};
+use std::ops::{Add, Sub};
+use std::rc::Rc;
+use std::cmp;
+
+use std::fmt;
+
+use serialize::{Encodable, Decodable, Encoder, Decoder};
+
+extern crate serialize;
+extern crate serialize as rustc_serialize; // used by deriving
+
+pub type FileName = String;
+
+/// Spans represent a region of code, used for error reporting. Positions in spans
+/// are *absolute* positions from the beginning of the codemap, not positions
+/// relative to FileMaps. Methods on the CodeMap can be used to relate spans back
+/// to the original source.
+/// You must be careful if the span crosses more than one file - you will not be
+/// able to use many of the functions on spans in codemap and you cannot assume
+/// that the length of the span = hi - lo; there may be space in the BytePos
+/// range between files.
+#[derive(Clone, Copy, Hash, PartialEq, Eq)]
+pub struct Span {
+ pub lo: BytePos,
+ pub hi: BytePos,
+ /// Information about where the macro came from, if this piece of
+ /// code was created by a macro expansion.
+ pub expn_id: ExpnId
+}
+
+/// A collection of spans. Spans have two orthogonal attributes:
+///
+/// - they can be *primary spans*. In this case they are the locus of
+/// the error, and would be rendered with `^^^`.
+/// - they can have a *label*. In this case, the label is written next
+/// to the mark in the snippet when we render.
+#[derive(Clone)]
+pub struct MultiSpan {
+ primary_spans: Vec<Span>,
+ span_labels: Vec<(Span, String)>,
+}
+
+impl Span {
+ /// Returns a new span representing just the end-point of this span
+ pub fn end_point(self) -> Span {
+ let lo = cmp::max(self.hi.0 - 1, self.lo.0);
+ Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id}
+ }
+
+ /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
+ pub fn substitute_dummy(self, other: Span) -> Span {
+ if self.source_equal(&DUMMY_SP) { other } else { self }
+ }
+
+ pub fn contains(self, other: Span) -> bool {
+ self.lo <= other.lo && other.hi <= self.hi
+ }
+
+ /// Return true if the spans are equal with regards to the source text.
+ ///
+ /// Use this instead of `==` when either span could be generated code,
+ /// and you only care that they point to the same bytes of source text.
+ pub fn source_equal(&self, other: &Span) -> bool {
+ self.lo == other.lo && self.hi == other.hi
+ }
+
+ /// Returns `Some(span)`, a union of `self` and `other`, on overlap.
+ pub fn merge(self, other: Span) -> Option<Span> {
+ if self.expn_id != other.expn_id {
+ return None;
+ }
+
+ if (self.lo <= other.lo && self.hi > other.lo) ||
+ (self.lo >= other.lo && self.lo < other.hi) {
+ Some(Span {
+ lo: cmp::min(self.lo, other.lo),
+ hi: cmp::max(self.hi, other.hi),
+ expn_id: self.expn_id,
+ })
+ } else {
+ None
+ }
+ }
+
+ /// Returns `Some(span)`, where the start is trimmed by the end of `other`
+ pub fn trim_start(self, other: Span) -> Option<Span> {
+ if self.hi > other.hi {
+ Some(Span { lo: cmp::max(self.lo, other.hi), .. self })
+ } else {
+ None
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct SpanLabel {
+ /// The span we are going to include in the final snippet.
+ pub span: Span,
+
+ /// Is this a primary span? This is the "locus" of the message,
+ /// and is indicated with a `^^^^` underline, versus `----`.
+ pub is_primary: bool,
+
+ /// What label should we attach to this span (if any)?
+ pub label: Option<String>,
+}
+
+impl Encodable for Span {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ s.emit_struct("Span", 2, |s| {
+ s.emit_struct_field("lo", 0, |s| {
+ self.lo.encode(s)
+ })?;
+
+ s.emit_struct_field("hi", 1, |s| {
+ self.hi.encode(s)
+ })
+ })
+ }
+}
+
+impl Decodable for Span {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Span, D::Error> {
+ d.read_struct("Span", 2, |d| {
+ let lo = d.read_struct_field("lo", 0, |d| {
+ BytePos::decode(d)
+ })?;
+
+ let hi = d.read_struct_field("hi", 1, |d| {
+ BytePos::decode(d)
+ })?;
+
+ Ok(mk_sp(lo, hi))
+ })
+ }
+}
+
+fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}",
+ span.lo, span.hi, span.expn_id)
+}
+
+impl fmt::Debug for Span {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ SPAN_DEBUG.with(|span_debug| span_debug.get()(*self, f))
+ }
+}
+
+pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION };
+
+// Generic span to be used for code originating from the command line
+pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0),
+ hi: BytePos(0),
+ expn_id: COMMAND_LINE_EXPN };
+
+impl MultiSpan {
+ pub fn new() -> MultiSpan {
+ MultiSpan {
+ primary_spans: vec![],
+ span_labels: vec![]
+ }
+ }
+
+ pub fn from_span(primary_span: Span) -> MultiSpan {
+ MultiSpan {
+ primary_spans: vec![primary_span],
+ span_labels: vec![]
+ }
+ }
+
+ pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
+ MultiSpan {
+ primary_spans: vec,
+ span_labels: vec![]
+ }
+ }
+
+ pub fn push_span_label(&mut self, span: Span, label: String) {
+ self.span_labels.push((span, label));
+ }
+
+ /// Selects the first primary span (if any)
+ pub fn primary_span(&self) -> Option<Span> {
+ self.primary_spans.first().cloned()
+ }
+
+ /// Returns all primary spans.
+ pub fn primary_spans(&self) -> &[Span] {
+ &self.primary_spans
+ }
+
+ /// Returns the strings to highlight. We always ensure that there
+ /// is an entry for each of the primary spans -- for each primary
+ /// span P, if there is at least one label with span P, we return
+ /// those labels (marked as primary). But otherwise we return
+ /// `SpanLabel` instances with empty labels.
+ pub fn span_labels(&self) -> Vec<SpanLabel> {
+ let is_primary = |span| self.primary_spans.contains(&span);
+ let mut span_labels = vec![];
+
+ for &(span, ref label) in &self.span_labels {
+ span_labels.push(SpanLabel {
+ span: span,
+ is_primary: is_primary(span),
+ label: Some(label.clone())
+ });
+ }
+
+ for &span in &self.primary_spans {
+ if !span_labels.iter().any(|sl| sl.span == span) {
+ span_labels.push(SpanLabel {
+ span: span,
+ is_primary: true,
+ label: None
+ });
+ }
+ }
+
+ span_labels
+ }
+}
+
+impl From<Span> for MultiSpan {
+ fn from(span: Span) -> MultiSpan {
+ MultiSpan::from_span(span)
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy)]
+pub struct ExpnId(pub u32);
+
+pub const NO_EXPANSION: ExpnId = ExpnId(!0);
+// For code appearing from the command line
+pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1);
+
+impl ExpnId {
+ pub fn from_u32(id: u32) -> ExpnId {
+ ExpnId(id)
+ }
+
+ pub fn into_u32(self) -> u32 {
+ self.0
+ }
+}
+
+/// Identifies an offset of a multi-byte character in a FileMap
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)]
+pub struct MultiByteChar {
+ /// The absolute offset of the character in the CodeMap
+ pub pos: BytePos,
+ /// The number of bytes, >=2
+ pub bytes: usize,
+}
+
+/// A single source in the CodeMap.
+pub struct FileMap {
+ /// The name of the file that the source came from, source that doesn't
+ /// originate from files has names between angle brackets by convention,
+ /// e.g. `<anon>`
+ pub name: FileName,
+ /// The absolute path of the file that the source came from.
+ pub abs_path: Option<FileName>,
+ /// The complete source code
+ pub src: Option<Rc<String>>,
+ /// The start position of this source in the CodeMap
+ pub start_pos: BytePos,
+ /// The end position of this source in the CodeMap
+ pub end_pos: BytePos,
+ /// Locations of lines beginnings in the source code
+ pub lines: RefCell<Vec<BytePos>>,
+ /// Locations of multi-byte characters in the source code
+ pub multibyte_chars: RefCell<Vec<MultiByteChar>>,
+}
+
+impl Encodable for FileMap {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ s.emit_struct("FileMap", 6, |s| {
+ s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
+ s.emit_struct_field("abs_path", 1, |s| self.abs_path.encode(s))?;
+ s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))?;
+ s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))?;
+ s.emit_struct_field("lines", 4, |s| {
+ let lines = self.lines.borrow();
+ // store the length
+ s.emit_u32(lines.len() as u32)?;
+
+ if !lines.is_empty() {
+ // In order to preserve some space, we exploit the fact that
+ // the lines list is sorted and individual lines are
+ // probably not that long. Because of that we can store lines
+ // as a difference list, using as little space as possible
+ // for the differences.
+ let max_line_length = if lines.len() == 1 {
+ 0
+ } else {
+ lines.windows(2)
+ .map(|w| w[1] - w[0])
+ .map(|bp| bp.to_usize())
+ .max()
+ .unwrap()
+ };
+
+ let bytes_per_diff: u8 = match max_line_length {
+ 0 ... 0xFF => 1,
+ 0x100 ... 0xFFFF => 2,
+ _ => 4
+ };
+
+ // Encode the number of bytes used per diff.
+ bytes_per_diff.encode(s)?;
+
+ // Encode the first element.
+ lines[0].encode(s)?;
+
+ let diff_iter = (&lines[..]).windows(2)
+ .map(|w| (w[1] - w[0]));
+
+ match bytes_per_diff {
+ 1 => for diff in diff_iter { (diff.0 as u8).encode(s)? },
+ 2 => for diff in diff_iter { (diff.0 as u16).encode(s)? },
+ 4 => for diff in diff_iter { diff.0.encode(s)? },
+ _ => unreachable!()
+ }
+ }
+
+ Ok(())
+ })?;
+ s.emit_struct_field("multibyte_chars", 5, |s| {
+ (*self.multibyte_chars.borrow()).encode(s)
+ })
+ })
+ }
+}
+
+impl Decodable for FileMap {
+ fn decode<D: Decoder>(d: &mut D) -> Result<FileMap, D::Error> {
+
+ d.read_struct("FileMap", 6, |d| {
+ let name: String = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
+ let abs_path: Option<String> =
+ d.read_struct_field("abs_path", 1, |d| Decodable::decode(d))?;
+ let start_pos: BytePos = d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?;
+ let end_pos: BytePos = d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))?;
+ let lines: Vec<BytePos> = d.read_struct_field("lines", 4, |d| {
+ let num_lines: u32 = Decodable::decode(d)?;
+ let mut lines = Vec::with_capacity(num_lines as usize);
+
+ if num_lines > 0 {
+ // Read the number of bytes used per diff.
+ let bytes_per_diff: u8 = Decodable::decode(d)?;
+
+ // Read the first element.
+ let mut line_start: BytePos = Decodable::decode(d)?;
+ lines.push(line_start);
+
+ for _ in 1..num_lines {
+ let diff = match bytes_per_diff {
+ 1 => d.read_u8()? as u32,
+ 2 => d.read_u16()? as u32,
+ 4 => d.read_u32()?,
+ _ => unreachable!()
+ };
+
+ line_start = line_start + BytePos(diff);
+
+ lines.push(line_start);
+ }
+ }
+
+ Ok(lines)
+ })?;
+ let multibyte_chars: Vec<MultiByteChar> =
+ d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?;
+ Ok(FileMap {
+ name: name,
+ abs_path: abs_path,
+ start_pos: start_pos,
+ end_pos: end_pos,
+ src: None,
+ lines: RefCell::new(lines),
+ multibyte_chars: RefCell::new(multibyte_chars)
+ })
+ })
+ }
+}
+
+impl fmt::Debug for FileMap {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "FileMap({})", self.name)
+ }
+}
+
+impl FileMap {
+ /// EFFECT: register a start-of-line offset in the
+ /// table of line-beginnings.
+ /// UNCHECKED INVARIANT: these offsets must be added in the right
+ /// order and must be in the right places; there is shared knowledge
+ /// about what ends a line between this file and parse.rs
+ /// WARNING: pos param here is the offset relative to start of CodeMap,
+ /// and CodeMap will append a newline when adding a filemap without a newline at the end,
+ /// so the safe way to call this is with value calculated as
+ /// filemap.start_pos + newline_offset_relative_to_the_start_of_filemap.
+ pub fn next_line(&self, pos: BytePos) {
+ // the new charpos must be > the last one (or it's the first one).
+ let mut lines = self.lines.borrow_mut();
+ let line_len = lines.len();
+ assert!(line_len == 0 || ((*lines)[line_len - 1] < pos));
+ lines.push(pos);
+ }
+
+ /// get a line from the list of pre-computed line-beginnings.
+ /// line-number here is 0-based.
+ pub fn get_line(&self, line_number: usize) -> Option<&str> {
+ match self.src {
+ Some(ref src) => {
+ let lines = self.lines.borrow();
+ lines.get(line_number).map(|&line| {
+ let begin: BytePos = line - self.start_pos;
+ let begin = begin.to_usize();
+ // We can't use `lines.get(line_number+1)` because we might
+ // be parsing when we call this function and thus the current
+ // line is the last one we have line info for.
+ let slice = &src[begin..];
+ match slice.find('\n') {
+ Some(e) => &slice[..e],
+ None => slice
+ }
+ })
+ }
+ None => None
+ }
+ }
+
+ pub fn record_multibyte_char(&self, pos: BytePos, bytes: usize) {
+ assert!(bytes >=2 && bytes <= 4);
+ let mbc = MultiByteChar {
+ pos: pos,
+ bytes: bytes,
+ };
+ self.multibyte_chars.borrow_mut().push(mbc);
+ }
+
+ pub fn is_real_file(&self) -> bool {
+ !(self.name.starts_with("<") &&
+ self.name.ends_with(">"))
+ }
+
+ pub fn is_imported(&self) -> bool {
+ self.src.is_none()
+ }
+
+ pub fn count_lines(&self) -> usize {
+ self.lines.borrow().len()
+ }
+}
+
+// _____________________________________________________________________________
+// Pos, BytePos, CharPos
+//
+
+pub trait Pos {
+ fn from_usize(n: usize) -> Self;
+ fn to_usize(&self) -> usize;
+}
+
+/// A byte offset. Keep this small (currently 32-bits), as AST contains
+/// a lot of them.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
+pub struct BytePos(pub u32);
+
+/// A character offset. Because of multibyte utf8 characters, a byte offset
+/// is not equivalent to a character offset. The CodeMap will convert BytePos
+/// values to CharPos values as necessary.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
+pub struct CharPos(pub usize);
+
+// FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
+// have been unsuccessful
+
+impl Pos for BytePos {
+ fn from_usize(n: usize) -> BytePos { BytePos(n as u32) }
+ fn to_usize(&self) -> usize { let BytePos(n) = *self; n as usize }
+}
+
+impl Add for BytePos {
+ type Output = BytePos;
+
+ fn add(self, rhs: BytePos) -> BytePos {
+ BytePos((self.to_usize() + rhs.to_usize()) as u32)
+ }
+}
+
+impl Sub for BytePos {
+ type Output = BytePos;
+
+ fn sub(self, rhs: BytePos) -> BytePos {
+ BytePos((self.to_usize() - rhs.to_usize()) as u32)
+ }
+}
+
+impl Encodable for BytePos {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ s.emit_u32(self.0)
+ }
+}
+
+impl Decodable for BytePos {
+ fn decode<D: Decoder>(d: &mut D) -> Result<BytePos, D::Error> {
+ Ok(BytePos(d.read_u32()?))
+ }
+}
+
+impl Pos for CharPos {
+ fn from_usize(n: usize) -> CharPos { CharPos(n) }
+ fn to_usize(&self) -> usize { let CharPos(n) = *self; n }
+}
+
+impl Add for CharPos {
+ type Output = CharPos;
+
+ fn add(self, rhs: CharPos) -> CharPos {
+ CharPos(self.to_usize() + rhs.to_usize())
+ }
+}
+
+impl Sub for CharPos {
+ type Output = CharPos;
+
+ fn sub(self, rhs: CharPos) -> CharPos {
+ CharPos(self.to_usize() - rhs.to_usize())
+ }
+}
+
+// _____________________________________________________________________________
+// Loc, LocWithOpt, FileMapAndLine, FileMapAndBytePos
+//
+
+/// A source code location used for error reporting
+#[derive(Debug)]
+pub struct Loc {
+ /// Information about the original source
+ pub file: Rc<FileMap>,
+ /// The (1-based) line number
+ pub line: usize,
+ /// The (0-based) column offset
+ pub col: CharPos
+}
+
+/// A source code location used as the result of lookup_char_pos_adj
+// Actually, *none* of the clients use the filename *or* file field;
+// perhaps they should just be removed.
+#[derive(Debug)]
+pub struct LocWithOpt {
+ pub filename: FileName,
+ pub line: usize,
+ pub col: CharPos,
+ pub file: Option<Rc<FileMap>>,
+}
+
+// used to be structural records. Better names, anyone?
+#[derive(Debug)]
+pub struct FileMapAndLine { pub fm: Rc<FileMap>, pub line: usize }
+#[derive(Debug)]
+pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct LineInfo {
+ /// Index of line, starting from 0.
+ pub line_index: usize,
+
+ /// Column in line where span begins, starting from 0.
+ pub start_col: CharPos,
+
+ /// Column in line where span ends, starting from 0, exclusive.
+ pub end_col: CharPos,
+}
+
+pub struct FileLines {
+ pub file: Rc<FileMap>,
+ pub lines: Vec<LineInfo>
+}
+
+thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter) -> fmt::Result> =
+ Cell::new(default_span_debug));
+
+/* assuming that we're not in macro expansion */
+pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
+ Span {lo: lo, hi: hi, expn_id: NO_EXPANSION}
+}
+
+pub struct MacroBacktrace {
+ /// span where macro was applied to generate this code
+ pub call_site: Span,
+
+ /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
+ pub macro_decl_name: String,
+
+ /// span where macro was defined (if known)
+ pub def_site_span: Option<Span>,
+}
+
+// _____________________________________________________________________________
+// SpanLinesError, SpanSnippetError, DistinctSources, MalformedCodemapPositions
+//
+
+pub type FileLinesResult = Result<FileLines, SpanLinesError>;
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum SpanLinesError {
+ IllFormedSpan(Span),
+ DistinctSources(DistinctSources),
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum SpanSnippetError {
+ IllFormedSpan(Span),
+ DistinctSources(DistinctSources),
+ MalformedForCodemap(MalformedCodemapPositions),
+ SourceNotAvailable { filename: String }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct DistinctSources {
+ pub begin: (String, BytePos),
+ pub end: (String, BytePos)
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct MalformedCodemapPositions {
+ pub name: String,
+ pub source_len: usize,
+ pub begin_pos: BytePos,
+ pub end_pos: BytePos
+}
+
#![feature(plugin_registrar, quote, rustc_private)]
extern crate syntax;
+extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
use syntax::ast::{self, TokenTree, Item, MetaItem, ImplItem, TraitItem, ItemKind};
-use syntax::codemap::Span;
use syntax::ext::base::*;
use syntax::parse::{self, token};
use syntax::ptr::P;
+use syntax_pos::Span;
use rustc_plugin::Registry;
#[macro_export]
extern crate syntax;
use syntax::ast;
-use syntax::codemap::Span;
use syntax::parse;
+use syntax_pos::Span;
struct ParseSess;
#![feature(quote, rustc_private)]
extern crate syntax;
+extern crate syntax_pos;
use syntax::ast;
-use syntax::codemap::{self, DUMMY_SP};
use syntax::parse;
use syntax::print::pprust;
+use syntax_pos::DUMMY_SP;
fn main() {
let ps = syntax::parse::ParseSess::new();
// except according to those terms.
// error-pattern: requires at least a format string argument
-// error-pattern: bad-format-args.rs:19:5: 19:15 note: in this expansion
+// error-pattern: in this expansion
// error-pattern: expected token: `,`
-// error-pattern: bad-format-args.rs:20:5: 20:19 note: in this expansion
-// error-pattern: bad-format-args.rs:21:5: 21:22 note: in this expansion
+// error-pattern: in this expansion
+// error-pattern: in this expansion
fn main() {
format!();
#![feature(quote, rustc_private)]
extern crate syntax;
+extern crate syntax_pos;
use syntax::ast;
-use syntax::codemap::{self, DUMMY_SP};
+use syntax::codemap;
use syntax::parse;
use syntax::print::pprust;
+use syntax_pos::DUMMY_SP;
fn main() {
let ps = syntax::parse::ParseSess::new();
extern crate rustc_llvm as llvm;
extern crate rustc_metadata;
extern crate rustc_resolve;
+extern crate rustc_errors;
+extern crate rustc_errors as errors;
#[macro_use] extern crate syntax;
use std::ffi::{CStr, CString};
use rustc_metadata::cstore::CStore;
use libc::c_void;
-use syntax::diagnostics::registry::Registry;
+use rustc_errors::registry::Registry;
use syntax::parse::token;
fn main() {
extern crate rustc_driver;
extern crate rustc_lint;
extern crate rustc_metadata;
+extern crate rustc_errors;
extern crate syntax;
use rustc::dep_graph::DepGraph;
use rustc::session::config::{basic_options, build_configuration, Input, OutputType};
use rustc_driver::driver::{compile_input, CompileController, anon_src};
use rustc_metadata::cstore::CStore;
-use syntax::diagnostics::registry::Registry;
+use rustc_errors::registry::Registry;
use syntax::parse::token;
use std::path::PathBuf;
extern crate syntax;
extern crate syntax_ext;
+extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
use syntax::ast;
-use syntax::codemap::Span;
use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::ptr::P;
use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure};
use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
+use syntax_pos::Span;
use rustc_plugin::Registry;
#[plugin_registrar]
extern crate syntax;
extern crate syntax_ext;
+extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
use syntax::ast;
use syntax::attr::AttrMetaMethods;
-use syntax::codemap::Span;
use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure};
use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching};
use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
+use syntax_pos::Span;
use rustc_plugin::Registry;
#[plugin_registrar]
extern crate syntax;
extern crate rustc;
extern crate rustc_plugin;
+extern crate syntax_pos;
use syntax::ast;
-use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager};
use syntax::util::small_vector::SmallVector;
use rustc_plugin::Registry;
reg.register_macro("multiple_items", expand)
}
-fn expand(cx: &mut ExtCtxt, _: codemap::Span, _: &[ast::TokenTree]) -> Box<MacResult+'static> {
+fn expand(cx: &mut ExtCtxt, _: syntax_pos::Span, _: &[ast::TokenTree]) -> Box<MacResult+'static> {
MacEager::items(SmallVector::many(vec![
quote_item!(cx, struct Struct1;).unwrap(),
quote_item!(cx, struct Struct2;).unwrap()
extern crate syntax;
extern crate rustc;
extern crate rustc_plugin;
+extern crate syntax_pos;
use syntax::ast::{self, TokenTree, Item, MetaItem, ImplItem, TraitItem, ItemKind};
-use syntax::codemap::Span;
use syntax::ext::base::*;
use syntax::parse::{self, token};
use syntax::ptr::P;
+use syntax_pos::Span;
use rustc_plugin::Registry;
#[macro_export]
#![feature(box_syntax, rustc_private)]
extern crate syntax;
+extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
use std::borrow::ToOwned;
use syntax::ast;
-use syntax::codemap::Span;
use syntax::ext::build::AstBuilder;
use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT};
use syntax::parse::token;
use syntax::print::pprust;
use syntax::ptr::P;
+use syntax_pos::Span;
use rustc_plugin::Registry;
struct Expander {
#![feature(plugin_registrar, quote, rustc_private)]
extern crate syntax;
+extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
-use syntax::codemap::Span;
use syntax::parse::token::{self, str_to_ident, NtExpr, NtPat};
use syntax::ast::{TokenTree, Pat};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use syntax::ext::tt::macro_parser::{Success, Failure, Error};
use syntax::ptr::P;
+use syntax_pos::Span;
use rustc_plugin::Registry;
fn expand_mbe_matches(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
#![feature(slice_patterns)]
extern crate syntax;
+extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
-use syntax::codemap::Span;
use syntax::ast::TokenTree;
use syntax::parse::token;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder; // trait for expr_usize
+use syntax_pos::Span;
use rustc_plugin::Registry;
// WARNING WARNING WARNING WARNING WARNING
extern crate syntax_extension_with_dll_deps_1 as other;
extern crate syntax;
+extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
use syntax::ast::{TokenTree, Item, MetaItem};
-use syntax::codemap::Span;
use syntax::ext::base::*;
+use syntax_pos::Span;
use rustc_plugin::Registry;
#[plugin_registrar]
extern crate rustc;
extern crate rustc_driver;
extern crate syntax;
+extern crate rustc_errors as errors;
use rustc::session::Session;
use rustc::session::config::{self, Input};
use rustc_driver::{driver, CompilerCalls, Compilation};
-use syntax::{diagnostics, errors};
use std::path::PathBuf;
fn early_callback(&mut self,
_: &getopts::Matches,
_: &config::Options,
- _: &diagnostics::registry::Registry,
+ _: &errors::registry::Registry,
_: config::ErrorOutputType)
-> Compilation {
self.count *= 2;
_: &config::Options,
_: &Option<PathBuf>,
_: &Option<PathBuf>,
- _: &diagnostics::registry::Registry)
+ _: &errors::registry::Registry)
-> Option<(Input, Option<PathBuf>)> {
panic!("This shouldn't happen");
}
#![feature(quote, rustc_private)]
extern crate syntax;
+extern crate syntax_pos;
-use syntax::codemap::DUMMY_SP;
use syntax::print::pprust::*;
use syntax::parse::token::intern;
+use syntax_pos::DUMMY_SP;
fn main() {
let ps = syntax::parse::ParseSess::new();
use runtest::{ProcRes};
// These structs are a subset of the ones found in
-// `syntax::errors::json`.
+// `syntax::json`.
#[derive(RustcEncodable, RustcDecodable)]
struct Diagnostic {