parser,ast,checker: add support for `[deprecated: "use another module"] module obsolete`
parent
3bd528b218
commit
e1a2ab345d
|
@ -4,6 +4,7 @@
|
|||
[has_globals]
|
||||
module ast
|
||||
|
||||
import time
|
||||
import v.cflag
|
||||
import v.token
|
||||
import v.util
|
||||
|
@ -36,8 +37,10 @@ pub mut:
|
|||
cur_fn &FnDecl = 0 // previously stored in Checker.cur_fn and Gen.cur_fn
|
||||
cur_concrete_types []Type // current concrete types, e.g. <int, string>
|
||||
gostmts int // how many `go` statements there were in the parsed files.
|
||||
enum_decls map[string]EnumDecl
|
||||
// When table.gostmts > 0, __VTHREADS__ is defined, which can be checked with `$if threads {`
|
||||
enum_decls map[string]EnumDecl
|
||||
mdeprecated_msg map[string]string // module deprecation message
|
||||
mdeprecated_after map[string]time.Time // module deprecation date
|
||||
}
|
||||
|
||||
// used by vls to avoid leaks
|
||||
|
@ -301,6 +304,15 @@ pub fn (t &Table) known_fn(name string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
pub fn (mut t Table) mark_module_as_deprecated(mname string, message string) {
|
||||
t.mdeprecated_msg[mname] = message
|
||||
t.mdeprecated_after[mname] = time.now()
|
||||
}
|
||||
|
||||
pub fn (mut t Table) mark_module_as_deprecated_after(mname string, after_date string) {
|
||||
t.mdeprecated_after[mname] = time.parse_iso8601(after_date) or { time.now() }
|
||||
}
|
||||
|
||||
pub fn (mut t Table) register_fn(new_fn Fn) {
|
||||
t.fns[new_fn.name] = new_fn
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
module checker
|
||||
|
||||
import os
|
||||
import time
|
||||
import v.ast
|
||||
import v.vmod
|
||||
import v.token
|
||||
|
@ -2240,6 +2241,11 @@ fn (mut c Checker) import_stmt(node ast.Import) {
|
|||
}
|
||||
c.error('module `$node.mod` has no constant or function `$sym.name`', sym.pos)
|
||||
}
|
||||
if after_time := c.table.mdeprecated_after[node.mod] {
|
||||
now := time.now()
|
||||
deprecation_message := c.table.mdeprecated_msg[node.mod]
|
||||
c.deprecate('module', node.mod, deprecation_message, now, after_time, node.pos)
|
||||
}
|
||||
}
|
||||
|
||||
// stmts should be used for processing normal statement lists (fn bodies, for loop bodies etc).
|
||||
|
|
|
@ -1439,7 +1439,6 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
|||
}
|
||||
|
||||
fn (mut c Checker) deprecate_fnmethod(kind string, name string, the_fn ast.Fn, node ast.CallExpr) {
|
||||
start_message := '$kind `$name`'
|
||||
mut deprecation_message := ''
|
||||
now := time.now()
|
||||
mut after_time := now
|
||||
|
@ -1454,19 +1453,24 @@ fn (mut c Checker) deprecate_fnmethod(kind string, name string, the_fn ast.Fn, n
|
|||
}
|
||||
}
|
||||
}
|
||||
c.deprecate(kind, name, deprecation_message, now, after_time, node.pos)
|
||||
}
|
||||
|
||||
fn (mut c Checker) deprecate(kind string, name string, deprecation_message string, now time.Time, after_time time.Time, pos token.Pos) {
|
||||
start_message := '$kind `$name`'
|
||||
error_time := after_time.add_days(180)
|
||||
if error_time < now {
|
||||
c.error(semicolonize('$start_message has been deprecated since $after_time.ymmdd()',
|
||||
deprecation_message), node.pos)
|
||||
deprecation_message), pos)
|
||||
} else if after_time < now {
|
||||
c.warn(semicolonize('$start_message has been deprecated since $after_time.ymmdd(), it will be an error after $error_time.ymmdd()',
|
||||
deprecation_message), node.pos)
|
||||
deprecation_message), pos)
|
||||
} else if after_time == now {
|
||||
c.warn(semicolonize('$start_message has been deprecated', deprecation_message),
|
||||
node.pos)
|
||||
pos)
|
||||
} else {
|
||||
c.note(semicolonize('$start_message will be deprecated after $after_time.ymmdd(), and will become an error after $error_time.ymmdd()',
|
||||
deprecation_message), node.pos)
|
||||
deprecation_message), pos)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
vlib/v/checker/tests/modules/deprecated_module/main.v:2:1: notice: module `deprecated_module.www.ttt` will be deprecated after 2999-01-01, and will become an error after 2999-06-30; use xxx.yyy
|
||||
1 | import deprecated_module.bbb.ccc
|
||||
2 | import deprecated_module.www.ttt
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
3 | import deprecated_module.xxx.yyy
|
||||
4 |
|
||||
vlib/v/checker/tests/modules/deprecated_module/main.v:12:11: error: undefined ident: `deprecated_module.www.ttt.non_existing`
|
||||
10 | dump(ttt.f())
|
||||
11 | dump(yyy.f())
|
||||
12 | dump(ttt.non_existing)
|
||||
| ~~~~~~~~~~~~
|
||||
13 | }
|
|
@ -0,0 +1,5 @@
|
|||
module ccc
|
||||
|
||||
pub fn f() int {
|
||||
return 142
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import deprecated_module.bbb.ccc
|
||||
import deprecated_module.www.ttt
|
||||
import deprecated_module.xxx.yyy
|
||||
|
||||
// NB: www.ttt has been deprecated.
|
||||
// => compiling this should produce an error,
|
||||
// showing the deprecation message
|
||||
fn main() {
|
||||
dump(ccc.f())
|
||||
dump(ttt.f())
|
||||
dump(yyy.f())
|
||||
dump(ttt.non_existing)
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
[deprecated: 'use xxx.yyy']
|
||||
[deprecated_after: '2999-01-01']
|
||||
module ttt
|
||||
|
||||
pub fn f() int {
|
||||
return 1142
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module yyy
|
||||
|
||||
pub fn f() int {
|
||||
return 42
|
||||
}
|
|
@ -478,7 +478,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
|
|||
f.interface_decl(node)
|
||||
}
|
||||
ast.Module {
|
||||
f.mod(node)
|
||||
f.module_stmt(node)
|
||||
}
|
||||
ast.Return {
|
||||
f.return_stmt(node)
|
||||
|
@ -1135,7 +1135,7 @@ pub fn (mut f Fmt) interface_method(method ast.FnDecl) {
|
|||
f.mark_types_import_as_used(method.return_type)
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) mod(mod ast.Module) {
|
||||
pub fn (mut f Fmt) module_stmt(mod ast.Module) {
|
||||
f.set_current_module_name(mod.name)
|
||||
if mod.is_skipped {
|
||||
return
|
||||
|
|
|
@ -2967,16 +2967,19 @@ fn (mut p Parser) parse_number_literal() ast.Expr {
|
|||
fn (mut p Parser) module_decl() ast.Module {
|
||||
mut module_attrs := []ast.Attr{}
|
||||
mut attrs_pos := p.tok.pos()
|
||||
if p.tok.kind == .lsbr {
|
||||
for p.tok.kind == .lsbr {
|
||||
p.attributes()
|
||||
module_attrs = p.attrs
|
||||
}
|
||||
module_attrs << p.attrs
|
||||
mut name := 'main'
|
||||
is_skipped := p.tok.kind != .key_module
|
||||
mut module_pos := token.Pos{}
|
||||
mut name_pos := token.Pos{}
|
||||
mut mod_node := ast.Module{}
|
||||
if !is_skipped {
|
||||
is_skipped := p.tok.kind != .key_module
|
||||
if is_skipped {
|
||||
// the attributes were for something else != module, like a struct/fn/type etc.
|
||||
module_attrs = []
|
||||
} else {
|
||||
p.attrs = []
|
||||
module_pos = p.tok.pos()
|
||||
p.next()
|
||||
|
@ -3020,6 +3023,14 @@ fn (mut p Parser) module_decl() ast.Module {
|
|||
if !is_skipped {
|
||||
for ma in module_attrs {
|
||||
match ma.name {
|
||||
'deprecated' {
|
||||
// [deprecated: 'use a replacement']
|
||||
p.table.mark_module_as_deprecated(p.mod, ma.arg)
|
||||
}
|
||||
'deprecated_after' {
|
||||
// [deprecated_after: '2027-12-30']
|
||||
p.table.mark_module_as_deprecated_after(p.mod, ma.arg)
|
||||
}
|
||||
'manualfree' {
|
||||
p.is_manualfree = true
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue