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 run: ./v test v
- name: Test v->js - name: Test v->js
run: ./v -o hi.js examples/hello_v_js.v && node hi.js run: ./v -o hi.js examples/hello_v_js.v && node hi.js
- name: Test vid # - name: Test vid
run: | # run: |
git clone --depth 1 https://github.com/vlang/vid.git # git clone --depth 1 https://github.com/vlang/vid.git
cd vid && ../v -debug -o vid . # cd vid && ../v -debug -o vid .
build-ubuntu: build-ubuntu:
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04

View File

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

View File

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

View File

@ -730,6 +730,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
if types_only { if types_only {
for p.tok != .rpar { for p.tok != .rpar {
typ := p.get_type() typ := p.get_type()
p.check_and_register_used_imported_type(typ)
v := Var { v := Var {
typ: typ typ: typ
is_arg: true is_arg: true
@ -761,6 +762,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
p.next() p.next()
} }
mut typ := p.get_type() mut typ := p.get_type()
p.check_and_register_used_imported_type(typ)
if is_mut && is_primitive_type(typ) { if is_mut && is_primitive_type(typ) {
p.error('mutable arguments are only allowed for arrays, maps, and structs.' + p.error('mutable arguments are only allowed for arrays, maps, and structs.' +
'\nreturn values instead: `foo(n mut int)` => `foo(n int) int`') '\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 // Add remaining user files
mut i := 0
mut j := 0 mut j := 0
mut len := -1 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 // Don't add a duplicate; builtin files are always there
if fit.file_path in v.files || fit.module_name == 'builtin' { if fit.file_path in v.files || fit.module_name == 'builtin' {
i++
continue continue
} }
if len == -1 { if len == -1 {
@ -671,6 +673,7 @@ fn (v mut V) add_v_files_to_compile() {
//println(fit) //println(fit)
//println('fit $fit.file_path') //println('fit $fit.file_path')
v.files << fit.file_path v.files << fit.file_path
i++
} }
} }

View File

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

View File

@ -6,7 +6,6 @@ module main
import ( import (
os os
rand
strings strings
) )
@ -29,7 +28,7 @@ mut:
lit string lit string
cgen &CGen cgen &CGen
table &Table 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 pass Pass
os OS os OS
mod string mod string
@ -92,7 +91,7 @@ fn (v mut V) new_parser(path string) Parser {
break break
} }
} }
mut p := Parser { mut p := Parser {
v: v v: v
file_path: path file_path: path
@ -101,7 +100,7 @@ fn (v mut V) new_parser(path string) Parser {
file_pcguard: path_pcguard file_pcguard: path_pcguard
scanner: new_scanner(path) scanner: new_scanner(path)
table: v.table table: v.table
import_table: new_file_import_table(path) import_table: v.table.get_file_import_table(path)
cur_fn: EmptyFn cur_fn: EmptyFn
cgen: v.cgen cgen: v.cgen
is_script: (v.pref.is_script && path == v.dir) 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') p.error('module `builtin` cannot be imported')
} }
// save file import table // save file import table
p.table.file_imports << *p.import_table p.table.file_imports[p.file_path] = p.import_table
return return
} }
// Go through every top level token or throw a compilation error if a non-top level token is met // 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 { if p.is_script && !p.pref.is_test {
p.set_current_fn( MainFn ) p.set_current_fn( MainFn )
p.check_unused_variables() 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') { if false && !p.first_pass() && p.fileis('main.v') {
out := os.create('/var/tmp/fmt.v') or { 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} access_mod := if is_pub{AccessMod.public} else { AccessMod.private}
p.fgen(' ') p.fgen(' ')
field_type := p.get_type() field_type := p.get_type()
p.check_and_register_used_imported_type(field_type)
is_atomic := p.tok == .key_atomic is_atomic := p.tok == .key_atomic
if is_atomic { if is_atomic {
p.next() p.next()
@ -1555,6 +1558,7 @@ fn (p mut Parser) name_expr() string {
mut mod := name mut mod := name
// must be aliased module // must be aliased module
if name != p.mod && p.import_table.known_alias(name) { 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. // we replaced "." with "_dot_" in p.mod for C variable names, do same here.
mod = p.import_table.resolve_alias(name).replace('.', '_dot_') 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) { if !('json' in p.table.imports) {
p.error('undefined: `json`, use `import json`') p.error('undefined: `json`, use `import json`')
} }
p.import_table.register_used_import('json')
return p.js_decode() return p.js_decode()
} }
//if p.fileis('orm_test') { //if p.fileis('orm_test') {
@ -3801,3 +3806,29 @@ fn (p mut Parser) defer_st() {
p.cgen.resetln('') 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 obf_ids map[string]int // obf_ids['myfunction'] == 23
modules []string // List of all modules registered by the application modules []string // List of all modules registered by the application
imports []string // List of all imports 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'] cflags []CFlag // ['-framework Cocoa', '-lglfw3']
fn_cnt int //atomic fn_cnt int //atomic
obfuscate bool obfuscate bool
@ -31,9 +31,10 @@ mut:
// Holds import information scoped to the parsed file // Holds import information scoped to the parsed file
struct FileImportTable { struct FileImportTable {
mut: mut:
module_name string module_name string
file_path string file_path string
imports map[string]string imports map[string]string // alias => module
used_imports []string // alias
} }
enum AccessMod { enum AccessMod {
@ -829,8 +830,22 @@ fn (table &Table) qualify_module(mod string, file_path string) string {
return mod return mod
} }
fn new_file_import_table(file_path string) &FileImportTable { fn (table &Table) get_file_import_table(file_path string) FileImportTable {
return &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 file_path: file_path
imports: map[string]string 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) { 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}".') cerror('cannot import $mod as $alias: import name $alias already in use in "${fit.file_path}".')
} }
if mod.contains('.internal.') { if mod.contains('.internal.') {
@ -880,6 +897,16 @@ fn (fit &FileImportTable) resolve_alias(alias string) string {
return fit.imports[alias] 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 { fn (t &Type) contains_field_type(typ string) bool {
if !t.name[0].is_capital() { if !t.name[0].is_capital() {
return false return false

View File

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

View File

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

View File

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

1
vc

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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