auto merge of #7706 : sanxiyn/rust/qualification-lint, r=pcwalton

Fix #2551.

Lint is off by default because I didn't bother to fix all of std and extra.
This commit is contained in:
bors 2013-07-12 05:46:42 -07:00
commit ad708139fe
4 changed files with 63 additions and 26 deletions

View File

@ -71,6 +71,7 @@ use syntax::{ast, visit, ast_util};
pub enum lint {
ctypes,
unused_imports,
unnecessary_qualification,
while_true,
path_statement,
implicit_copies,
@ -148,6 +149,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
default: warn
}),
("unnecessary_qualification",
LintSpec {
lint: unnecessary_qualification,
desc: "detects unnecessarily qualified names",
default: allow
}),
("while_true",
LintSpec {
lint: while_true,
@ -557,11 +565,7 @@ fn item_stopping_visitor<E: Copy>(outer: visit::vt<E>) -> visit::vt<E> {
_ => (outer.visit_fn)(fk, fd, b, s, id, (e, v))
}
},
.. **(ty_stopping_visitor(outer))})
}
fn ty_stopping_visitor<E>(v: visit::vt<E>) -> visit::vt<E> {
visit::mk_vt(@visit::Visitor {visit_ty: |_t, (_e, _v)| { },.. **v})
.. **outer})
}
fn lint_while_true() -> visit::vt<@mut Context> {

View File

@ -17,7 +17,7 @@ use metadata::csearch::get_type_name_if_impl;
use metadata::cstore::find_extern_mod_stmt_cnum;
use metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
use middle::lang_items::LanguageItems;
use middle::lint::unused_imports;
use middle::lint::{unnecessary_qualification, unused_imports};
use middle::pat_util::pat_bindings;
use syntax::ast::*;
@ -3561,7 +3561,7 @@ impl Resolver {
// Resolve derived traits.
for traits.iter().advance |trt| {
self.resolve_trait_reference(trt, visitor, TraitDerivation);
self.resolve_trait_reference(item.id, trt, visitor, TraitDerivation);
}
for (*methods).iter().advance |method| {
@ -3802,27 +3802,29 @@ impl Resolver {
visitor: ResolveVisitor) {
for type_parameters.iter().advance |type_parameter| {
for type_parameter.bounds.iter().advance |bound| {
self.resolve_type_parameter_bound(bound, visitor);
self.resolve_type_parameter_bound(type_parameter.id, bound, visitor);
}
}
}
pub fn resolve_type_parameter_bound(@mut self,
id: node_id,
type_parameter_bound: &TyParamBound,
visitor: ResolveVisitor) {
match *type_parameter_bound {
TraitTyParamBound(ref tref) => {
self.resolve_trait_reference(tref, visitor, TraitBoundingTypeParameter)
self.resolve_trait_reference(id, tref, visitor, TraitBoundingTypeParameter)
}
RegionTyParamBound => {}
}
}
pub fn resolve_trait_reference(@mut self,
id: node_id,
trait_reference: &trait_ref,
visitor: ResolveVisitor,
reference_type: TraitReferenceType) {
match self.resolve_path(&trait_reference.path, TypeNS, true, visitor) {
match self.resolve_path(id, &trait_reference.path, TypeNS, true, visitor) {
None => {
let path_str = self.idents_to_str(trait_reference.path.idents);
@ -3930,7 +3932,8 @@ impl Resolver {
let original_trait_refs;
match opt_trait_reference {
&Some(ref trait_reference) => {
self.resolve_trait_reference(trait_reference, visitor, TraitImplementation);
self.resolve_trait_reference(id, trait_reference, visitor,
TraitImplementation);
// Record the current set of trait references.
let mut new_trait_refs = ~[];
@ -4142,7 +4145,7 @@ impl Resolver {
match result_def {
None => {
match self.resolve_path(path, TypeNS, true, visitor) {
match self.resolve_path(ty.id, path, TypeNS, true, visitor) {
Some(def) => {
debug!("(resolving type) resolved `%s` to \
type %?",
@ -4179,7 +4182,7 @@ impl Resolver {
do bounds.map |bound_vec| {
for bound_vec.iter().advance |bound| {
self.resolve_type_parameter_bound(bound, visitor);
self.resolve_type_parameter_bound(ty.id, bound, visitor);
}
};
}
@ -4187,7 +4190,7 @@ impl Resolver {
ty_closure(c) => {
do c.bounds.map |bounds| {
for bounds.iter().advance |bound| {
self.resolve_type_parameter_bound(bound, visitor);
self.resolve_type_parameter_bound(ty.id, bound, visitor);
}
};
visit_ty(ty, ((), visitor));
@ -4340,7 +4343,7 @@ impl Resolver {
pat_ident(binding_mode, ref path, _) => {
// This must be an enum variant, struct, or constant.
match self.resolve_path(path, ValueNS, false, visitor) {
match self.resolve_path(pat_id, path, ValueNS, false, visitor) {
Some(def @ def_variant(*)) |
Some(def @ def_struct(*)) => {
self.record_def(pattern.id, def);
@ -4373,7 +4376,7 @@ impl Resolver {
pat_enum(ref path, _) => {
// This must be an enum variant, struct or const.
match self.resolve_path(path, ValueNS, false, visitor) {
match self.resolve_path(pat_id, path, ValueNS, false, visitor) {
Some(def @ def_fn(*)) |
Some(def @ def_variant(*)) |
Some(def @ def_struct(*)) |
@ -4410,7 +4413,7 @@ impl Resolver {
}
pat_struct(ref path, _, _) => {
match self.resolve_path(path, TypeNS, false, visitor) {
match self.resolve_path(pat_id, path, TypeNS, false, visitor) {
Some(def_ty(class_id))
if self.structs.contains(&class_id) => {
let class_def = def_struct(class_id);
@ -4484,6 +4487,7 @@ impl Resolver {
/// If `check_ribs` is true, checks the local definitions first; i.e.
/// doesn't skip straight to the containing module.
pub fn resolve_path(@mut self,
id: node_id,
path: &Path,
namespace: Namespace,
check_ribs: bool,
@ -4500,16 +4504,24 @@ impl Resolver {
namespace);
}
let unqualified_def = self.resolve_identifier(
*path.idents.last(), namespace, check_ribs, path.span);
if path.idents.len() > 1 {
return self.resolve_module_relative_path(path,
self.xray_context,
namespace);
let def = self.resolve_module_relative_path(
path, self.xray_context, namespace);
match (def, unqualified_def) {
(Some(d), Some(ud)) if d == ud => {
self.session.add_lint(unnecessary_qualification,
id, path.span,
~"unnecessary qualification");
}
_ => ()
}
return def;
}
return self.resolve_identifier(*path.idents.last(),
namespace,
check_ribs,
path.span);
return unqualified_def;
}
pub fn resolve_identifier(@mut self,
@ -4920,7 +4932,7 @@ impl Resolver {
// This is a local path in the value namespace. Walk through
// scopes looking for it.
match self.resolve_path(path, ValueNS, true, visitor) {
match self.resolve_path(expr.id, path, ValueNS, true, visitor) {
Some(def) => {
// Write the result into the def map.
debug!("(resolving expr) resolved `%s`",
@ -4987,7 +4999,7 @@ impl Resolver {
expr_struct(ref path, _, _) => {
// Resolve the path to the structure it goes to.
match self.resolve_path(path, TypeNS, false, visitor) {
match self.resolve_path(expr.id, path, TypeNS, false, visitor) {
Some(def_ty(class_id)) | Some(def_struct(class_id))
if self.structs.contains(&class_id) => {
let class_def = def_struct(class_id);

View File

@ -462,6 +462,7 @@ pub fn id_visitor<T: Copy>(vfn: @fn(node_id, T)) -> visit::vt<T> {
},
visit_ty: |ty, (t, vt)| {
vfn(ty.id, copy t);
match ty.node {
ty_path(_, _, id) => vfn(id, copy t),
_ => { /* fall through */ }

View File

@ -0,0 +1,20 @@
// Copyright 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.
#[deny(unnecessary_qualification)];
mod foo {
pub fn bar() {}
}
fn main() {
use foo::bar;
foo::bar(); //~ ERROR: unnecessary qualification
}