mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
compiler: error on unused imports
This commit is contained in:
parent
71484e89d6
commit
23c84516e2
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@ -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
|
||||||
|
10
.travis.yml
10
.travis.yml
@ -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
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
module main
|
module main
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import strings
|
|
||||||
|
|
||||||
struct CGen {
|
struct CGen {
|
||||||
out os.File
|
out os.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`')
|
||||||
|
@ -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++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
module main
|
module main
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import os
|
|
||||||
|
|
||||||
[live]
|
[live]
|
||||||
fn print_message() {
|
fn print_message() {
|
||||||
|
@ -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
vc
@ -1 +0,0 @@
|
|||||||
Subproject commit c2c26419198a271ca00cb8d77119d17c5622569e
|
|
@ -1,5 +1,3 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
q = [1, 2, 3]
|
q = [1, 2, 3]
|
||||||
A = 8
|
A = 8
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import time
|
// import time
|
||||||
|
|
||||||
struct User {
|
struct User {
|
||||||
name string
|
name string
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
module aes
|
module aes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
crypto.cipher
|
|
||||||
crypto.internal.subtle
|
crypto.internal.subtle
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
os
|
os
|
||||||
gx
|
gx
|
||||||
gg
|
gg
|
||||||
stbi
|
|
||||||
glm
|
glm
|
||||||
gl
|
gl
|
||||||
)
|
)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
module gl
|
module gl
|
||||||
|
|
||||||
import os
|
// import os
|
||||||
import gx
|
import gx
|
||||||
import glm
|
import glm
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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 ()
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import net.urllib
|
// import net.urllib
|
||||||
import http
|
// import http
|
||||||
|
|
||||||
fn test_escape_unescape() {
|
fn test_escape_unescape() {
|
||||||
/*
|
/*
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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'
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ module vweb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
os
|
os
|
||||||
strings
|
|
||||||
net
|
net
|
||||||
http
|
http
|
||||||
net.urllib
|
net.urllib
|
||||||
|
Loading…
Reference in New Issue
Block a user