Use a visitor to look for non-FFI-safe types

Fixes #16250.
This commit is contained in:
Keegan McAllister 2014-09-03 19:03:25 -07:00
parent 7f676b8699
commit f422de1e85
2 changed files with 74 additions and 40 deletions

View File

@ -45,6 +45,7 @@
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::{ast, ast_util, visit};
use syntax::visit::Visitor;
declare_lint!(WHILE_TRUE, Warn,
"suggest using `loop { }` instead of `while true { }`")
@ -339,6 +340,51 @@ fn is_comparison(binop: ast::BinOp) -> bool {
declare_lint!(CTYPES, Warn,
"proper use of libc types in foreign modules")
struct CTypesVisitor<'a> {
cx: &'a Context<'a>
}
impl<'a> CTypesVisitor<'a> {
fn check_def(&mut self, sp: Span, ty_id: ast::NodeId, path_id: ast::NodeId) {
match self.cx.tcx.def_map.borrow().get_copy(&path_id) {
def::DefPrimTy(ast::TyInt(ast::TyI)) => {
self.cx.span_lint(CTYPES, sp,
"found rust type `int` in foreign module, while \
libc::c_int or libc::c_long should be used");
}
def::DefPrimTy(ast::TyUint(ast::TyU)) => {
self.cx.span_lint(CTYPES, sp,
"found rust type `uint` in foreign module, while \
libc::c_uint or libc::c_ulong should be used");
}
def::DefTy(..) => {
let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().find(&ty_id) {
Some(&ty::atttce_resolved(t)) => t,
_ => fail!("ast_ty_to_ty_cache was incomplete after typeck!")
};
if !ty::is_ffi_safe(self.cx.tcx, tty) {
self.cx.span_lint(CTYPES, sp,
"found type without foreign-function-safe
representation annotation in foreign module, consider \
adding a #[repr(...)] attribute to the type");
}
}
_ => ()
}
}
}
impl<'a> Visitor<()> for CTypesVisitor<'a> {
fn visit_ty(&mut self, ty: &ast::Ty, _: ()) {
match ty.node {
ast::TyPath(_, _, id) => self.check_def(ty.span, ty.id, id),
_ => (),
}
visit::walk_ty(self, ty, ());
}
}
pub struct CTypes;
impl LintPass for CTypes {
@ -348,38 +394,8 @@ fn get_lints(&self) -> LintArray {
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
fn check_ty(cx: &Context, ty: &ast::Ty) {
match ty.node {
ast::TyPath(_, _, id) => {
match cx.tcx.def_map.borrow().get_copy(&id) {
def::DefPrimTy(ast::TyInt(ast::TyI)) => {
cx.span_lint(CTYPES, ty.span,
"found rust type `int` in foreign module, while \
libc::c_int or libc::c_long should be used");
}
def::DefPrimTy(ast::TyUint(ast::TyU)) => {
cx.span_lint(CTYPES, ty.span,
"found rust type `uint` in foreign module, while \
libc::c_uint or libc::c_ulong should be used");
}
def::DefTy(..) => {
let tty = match cx.tcx.ast_ty_to_ty_cache.borrow().find(&ty.id) {
Some(&ty::atttce_resolved(t)) => t,
_ => fail!("ast_ty_to_ty_cache was incomplete after typeck!")
};
if !ty::is_ffi_safe(cx.tcx, tty) {
cx.span_lint(CTYPES, ty.span,
"found type without foreign-function-safe
representation annotation in foreign module, consider \
adding a #[repr(...)] attribute to the type");
}
}
_ => ()
}
}
ast::TyPtr(ref mt) => { check_ty(cx, &*mt.ty) }
_ => {}
}
let mut vis = CTypesVisitor { cx: cx };
vis.visit_ty(ty, ());
}
fn check_foreign_fn(cx: &Context, decl: &ast::FnDecl) {
@ -390,15 +406,15 @@ fn check_foreign_fn(cx: &Context, decl: &ast::FnDecl) {
}
match it.node {
ast::ItemForeignMod(ref nmod) if nmod.abi != abi::RustIntrinsic => {
for ni in nmod.items.iter() {
match ni.node {
ast::ForeignItemFn(decl, _) => check_foreign_fn(cx, &*decl),
ast::ForeignItemStatic(t, _) => check_ty(cx, &*t)
ast::ItemForeignMod(ref nmod) if nmod.abi != abi::RustIntrinsic => {
for ni in nmod.items.iter() {
match ni.node {
ast::ForeignItemFn(decl, _) => check_foreign_fn(cx, &*decl),
ast::ForeignItemStatic(t, _) => check_ty(cx, &*t)
}
}
}
}
_ => {/* nothing to do */ }
_ => (),
}
}
}
@ -493,7 +509,7 @@ struct RawPtrDerivingVisitor<'a> {
cx: &'a Context<'a>
}
impl<'a> visit::Visitor<()> for RawPtrDerivingVisitor<'a> {
impl<'a> Visitor<()> for RawPtrDerivingVisitor<'a> {
fn visit_ty(&mut self, ty: &ast::Ty, _: ()) {
static MSG: &'static str = "use of `#[deriving]` with a raw pointer";
match ty.node {

View File

@ -0,0 +1,18 @@
// 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.
#![deny(warnings)]
extern {
pub fn foo(x: (int)); //~ ERROR found rust type `int` in foreign module
}
fn main() {
}