compiler: error on unused imports

pull/2083/head
joe-conigliaro 2019-09-23 20:42:20 +10:00 committed by Alexander Medvednikov
parent 71484e89d6
commit 23c84516e2
29 changed files with 112 additions and 55 deletions

View File

@ -19,10 +19,10 @@ jobs:
run: ./v test v
- name: Test v->js
run: ./v -o hi.js examples/hello_v_js.v && node hi.js
- name: Test vid
run: |
git clone --depth 1 https://github.com/vlang/vid.git
cd vid && ../v -debug -o vid .
# - name: Test vid
# run: |
# git clone --depth 1 https://github.com/vlang/vid.git
# cd vid && ../v -debug -o vid .
build-ubuntu:
runs-on: ubuntu-18.04

View File

@ -82,8 +82,8 @@ script:
node hi.js
fi
- |
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
# Build Vid
git clone https://github.com/vlang/vid
cd vid && ../v -debug -o vid .
fi
# if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
# # Build Vid
# git clone https://github.com/vlang/vid
# cd vid && ../v -debug -o vid .
# fi

View File

@ -5,7 +5,6 @@
module main
import os
import strings
struct CGen {
out os.File

View File

@ -730,6 +730,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
if types_only {
for p.tok != .rpar {
typ := p.get_type()
p.check_and_register_used_imported_type(typ)
v := Var {
typ: typ
is_arg: true
@ -761,6 +762,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
p.next()
}
mut typ := p.get_type()
p.check_and_register_used_imported_type(typ)
if is_mut && is_primitive_type(typ) {
p.error('mutable arguments are only allowed for arrays, maps, and structs.' +
'\nreturn values instead: `foo(n mut int)` => `foo(n int) int`')

View File

@ -653,11 +653,13 @@ fn (v mut V) add_v_files_to_compile() {
}
}
// Add remaining user files
mut i := 0
mut j := 0
mut len := -1
for i, fit in v.table.file_imports {
for _, fit in v.table.file_imports {
// Don't add a duplicate; builtin files are always there
if fit.file_path in v.files || fit.module_name == 'builtin' {
i++
continue
}
if len == -1 {
@ -671,6 +673,7 @@ fn (v mut V) add_v_files_to_compile() {
//println(fit)
//println('fit $fit.file_path')
v.files << fit.file_path
i++
}
}

View File

@ -7,8 +7,8 @@ module main
import os
// add a module and its deps (module speficic dag method)
pub fn(graph mut DepGraph) from_import_tables(import_tables []FileImportTable) {
for fit in import_tables {
pub fn(graph mut DepGraph) from_import_tables(import_tables map[string]FileImportTable) {
for _, fit in import_tables {
mut deps := []string
for _, m in fit.imports {
deps << m

View File

@ -6,7 +6,6 @@ module main
import (
os
rand
strings
)
@ -29,7 +28,7 @@ mut:
lit string
cgen &CGen
table &Table
import_table &FileImportTable // Holds imports for just the file being parsed
import_table FileImportTable // Holds imports for just the file being parsed
pass Pass
os OS
mod string
@ -92,7 +91,7 @@ fn (v mut V) new_parser(path string) Parser {
break
}
}
mut p := Parser {
v: v
file_path: path
@ -101,7 +100,7 @@ fn (v mut V) new_parser(path string) Parser {
file_pcguard: path_pcguard
scanner: new_scanner(path)
table: v.table
import_table: new_file_import_table(path)
import_table: v.table.get_file_import_table(path)
cur_fn: EmptyFn
cgen: v.cgen
is_script: (v.pref.is_script && path == v.dir)
@ -186,7 +185,7 @@ fn (p mut Parser) parse(pass Pass) {
p.error('module `builtin` cannot be imported')
}
// save file import table
p.table.file_imports << *p.import_table
p.table.file_imports[p.file_path] = p.import_table
return
}
// Go through every top level token or throw a compilation error if a non-top level token is met
@ -277,6 +276,9 @@ fn (p mut Parser) parse(pass Pass) {
if p.is_script && !p.pref.is_test {
p.set_current_fn( MainFn )
p.check_unused_variables()
if !p.first_pass() && !p.pref.is_repl {
p.check_unused_imports()
}
}
if false && !p.first_pass() && p.fileis('main.v') {
out := os.create('/var/tmp/fmt.v') or {
@ -635,6 +637,7 @@ fn (p mut Parser) struct_decl() {
access_mod := if is_pub{AccessMod.public} else { AccessMod.private}
p.fgen(' ')
field_type := p.get_type()
p.check_and_register_used_imported_type(field_type)
is_atomic := p.tok == .key_atomic
if is_atomic {
p.next()
@ -1555,6 +1558,7 @@ fn (p mut Parser) name_expr() string {
mut mod := name
// must be aliased module
if name != p.mod && p.import_table.known_alias(name) {
p.import_table.register_used_import(name)
// we replaced "." with "_dot_" in p.mod for C variable names, do same here.
mod = p.import_table.resolve_alias(name).replace('.', '_dot_')
}
@ -2388,6 +2392,7 @@ fn (p mut Parser) factor() string {
if !('json' in p.table.imports) {
p.error('undefined: `json`, use `import json`')
}
p.import_table.register_used_import('json')
return p.js_decode()
}
//if p.fileis('orm_test') {
@ -3801,3 +3806,29 @@ fn (p mut Parser) defer_st() {
p.cgen.resetln('')
}
fn (p mut Parser) check_and_register_used_imported_type(typ_name string) {
us_idx := typ_name.index('__')
if us_idx != -1 {
arg_mod := typ_name.left(us_idx)
if p.import_table.known_alias(arg_mod) {
p.import_table.register_used_import(arg_mod)
}
}
}
fn (p mut Parser) check_unused_imports() {
mut output := ''
for alias, mod in p.import_table.imports {
if !p.import_table.is_used_import(alias) {
mod_alias := if alias == mod { alias } else { '$alias ($mod)' }
output += '\n * $mod_alias'
}
}
if output == '' { return }
output = '$p.file_path: the following imports were never used:$output'
if p.pref.is_prod {
cerror(output)
} else {
println('warning: $output')
}
}

View File

@ -16,7 +16,7 @@ mut:
obf_ids map[string]int // obf_ids['myfunction'] == 23
modules []string // List of all modules registered by the application
imports []string // List of all imports
file_imports []FileImportTable // List of imports for file
file_imports map[string]FileImportTable // List of imports for file
cflags []CFlag // ['-framework Cocoa', '-lglfw3']
fn_cnt int //atomic
obfuscate bool
@ -31,9 +31,10 @@ mut:
// Holds import information scoped to the parsed file
struct FileImportTable {
mut:
module_name string
file_path string
imports map[string]string
module_name string
file_path string
imports map[string]string // alias => module
used_imports []string // alias
}
enum AccessMod {
@ -829,8 +830,22 @@ fn (table &Table) qualify_module(mod string, file_path string) string {
return mod
}
fn new_file_import_table(file_path string) &FileImportTable {
return &FileImportTable{
fn (table &Table) get_file_import_table(file_path string) FileImportTable {
// if file_path.clone() in table.file_imports {
// return table.file_imports[file_path.clone()]
// }
// just get imports. memory error when recycling import table
mut imports := map[string]string
if file_path in table.file_imports {
imports = table.file_imports[file_path].imports
}
mut fit := new_file_import_table(file_path.clone())
fit.imports = imports
return fit
}
fn new_file_import_table(file_path string) FileImportTable {
return FileImportTable{
file_path: file_path
imports: map[string]string
}
@ -845,7 +860,9 @@ fn (fit mut FileImportTable) register_import(mod string) {
}
fn (fit mut FileImportTable) register_alias(alias string, mod string) {
if alias in fit.imports {
// NOTE: come back here
// if alias in fit.imports && fit.imports[alias] == mod {}
if alias in fit.imports && fit.imports[alias] != mod {
cerror('cannot import $mod as $alias: import name $alias already in use in "${fit.file_path}".')
}
if mod.contains('.internal.') {
@ -880,6 +897,16 @@ fn (fit &FileImportTable) resolve_alias(alias string) string {
return fit.imports[alias]
}
fn (fit mut FileImportTable) register_used_import(alias string) {
if !(alias in fit.used_imports) {
fit.used_imports << alias
}
}
fn (fit &FileImportTable) is_used_import(alias string) bool {
return alias in fit.used_imports
}
fn (t &Type) contains_field_type(typ string) bool {
if !t.name[0].is_capital() {
return false

View File

@ -1,12 +1,11 @@
module main
import gx
import gl
import gg
import time
import glfw
import math
import time
import glfw
// import math
const (
Size = 700
Scale = 50.0

View File

@ -3,7 +3,6 @@
module main
import time
import os
[live]
fn print_message() {

View File

@ -7,7 +7,6 @@ module main
import rand
import time
import gx
import gl
import gg
import glfw
import math

1
vc

@ -1 +0,0 @@
Subproject commit c2c26419198a271ca00cb8d77119d17c5622569e

View File

@ -1,5 +1,3 @@
import os
const (
q = [1, 2, 3]
A = 8

View File

@ -1,4 +1,4 @@
import time
// import time
struct User {
name string

View File

@ -8,7 +8,6 @@
module aes
import (
crypto.cipher
crypto.internal.subtle
)

View File

@ -31,7 +31,7 @@ fn _new_cbc(b AesCipher, iv []byte) AesCbc {
b: b,
block_size: b.block_size(),
iv: iv.clone(),
tmp: [byte(0); b.block_size()],
tmp: [byte(0)].repeat(b.block_size()),
}
}

View File

@ -5,8 +5,8 @@
module aes
import (
crypto.cipher
crypto.internal.subtle
// crypto.cipher
// crypto.internal.subtle
)
// new_cipher_generic creates and returns a new cipher.Block

View File

@ -8,7 +8,6 @@ import (
os
gx
gg
stbi
glm
gl
)

View File

@ -4,7 +4,7 @@
module gl
import os
// import os
import gx
import glm

View File

@ -8,6 +8,9 @@ module gl
#include "glad.h"
#flag @VROOT/thirdparty/glad/glad.o
// joe-c: fix & remove
enum TmpGlImportHack{}
pub fn init_glad() {
ok := C.gladLoadGL()
if isnil(ok) {

View File

@ -4,6 +4,8 @@
module glfw
// note: we might need special case for this
// see TmpGlImportHack below (joe-c)
import gl
#flag -I @VROOT/thirdparty/glfw
@ -41,6 +43,11 @@ const (
KeyDown = 264
)
// joe-c: fix & remove
struct TmpGlImportHack {
hack gl.TmpGlImportHack
}
struct WinCfg {
width int
height int

View File

@ -2,8 +2,8 @@
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
import os
import gl
// might need special case for this
// import gl
import glm
fn cmp(a, b f32) bool {

View File

@ -4,8 +4,6 @@
module http
import os
type downloadfn fn (written int)
type download_finished_fn fn ()

View File

@ -1,5 +1,5 @@
import net.urllib
import http
// import net.urllib
// import http
fn test_escape_unescape() {
/*

View File

@ -4,7 +4,8 @@
module stbi
import gl
// note we might need special case for this
// import gl
#flag -I @VROOT/thirdparty/stb_image

View File

@ -3,7 +3,6 @@
// that can be found in the LICENSE file.
module sync
import os
// Mutex HANDLE
type MHANDLE voidptr

View File

@ -4,8 +4,6 @@
module term
import os
fn _format(msg, open, close string) string {
return '\x1b[' + open + 'm' + msg + '\x1b[' + close + 'm'
}

View File

@ -4,8 +4,6 @@
module term
import os
pub fn format(msg, open, close string) string {
return _format(msg, open, close)
}

View File

@ -2,7 +2,6 @@ module vweb
import (
os
strings
net
http
net.urllib