builtin: x.vstring() instead of string(x) (#6102)

pull/6104/head
Delyan Angelov 2020-08-10 19:05:26 +03:00 committed by GitHub
parent eba413853f
commit 36eae1c175
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 143 additions and 72 deletions

View File

@ -120,6 +120,23 @@ pub fn tos_lit(s charptr) string {
} }
} }
// byteptr.vstring() - converts a C style string to a V string. NB: the string data is reused, NOT copied.
[unsafe]
pub fn (bp byteptr) vstring() string {
return string{
str: bp
len: unsafe {C.strlen(bp)}
}
}
// byteptr.vstring_with_len() - converts a C style string to a V string. NB: the string data is reused, NOT copied.
[unsafe]
pub fn (bp byteptr) vstring_with_len(len int) string {
return string{
str: bp
len: len
}
}
// string.clone_static returns an independent copy of a given array // string.clone_static returns an independent copy of a given array
// It should be used only in -autofree generated code. // It should be used only in -autofree generated code.
@ -1429,9 +1446,10 @@ pub fn (s string) repeat(count int) string {
} }
} }
unsafe { unsafe {
ret[s.len * count] = 0 new_len := s.len * count
ret[new_len] = 0
return ret.vstring_with_len(new_len)
} }
return string(ret)
} }
pub fn (s string) fields() []string { pub fn (s string) fields() []string {
@ -1463,7 +1481,7 @@ pub fn (s string) filter(func fn(b byte) bool) string {
} }
unsafe { unsafe {
buf[new_len] = 0 buf[new_len] = 0
return string(buf, new_len) return buf.vstring_with_len(new_len)
} }
} }
@ -1524,6 +1542,6 @@ pub fn (s string) strip_margin_custom(del byte) string {
} }
unsafe { unsafe {
ret[count] = 0 ret[count] = 0
return ret.vstring_with_len(count)
} }
return string(ret)
} }

View File

@ -502,10 +502,10 @@ fn test_bytes_to_string() {
buf[3] = `l` buf[3] = `l`
buf[4] = `o` buf[4] = `o`
} }
assert string(buf) == 'hello' assert unsafe { buf.vstring() } == 'hello'
assert string(buf, 2) == 'he' assert unsafe { buf.vstring_with_len(2) } == 'he'
bytes := [`h`, `e`, `l`, `l`, `o`] bytes := [`h`, `e`, `l`, `l`, `o`]
assert string(bytes, 5) == 'hello' assert bytes.bytestr() == 'hello'
} }
fn test_count() { fn test_count() {

View File

@ -70,7 +70,7 @@ fn (mut cb Clipboard) get_text() string {
#} #}
#utf8_clip = [ns_clip UTF8String]; #utf8_clip = [ns_clip UTF8String];
return string(utf8_clip) return unsafe { utf8_clip.vstring() }
} }
pub fn new_primary() &Clipboard { pub fn new_primary() &Clipboard {

View File

@ -309,7 +309,7 @@ fn (mut cb Clipboard) start_listener(){
C.XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property) C.XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property)
if cb.is_supported_target(prop.actual_type) { if cb.is_supported_target(prop.actual_type) {
cb.got_text = true cb.got_text = true
cb.text = string(prop.data) //TODO: return byteptr to support other mimetypes cb.text = byteptr(prop.data).vstring() //TODO: return byteptr to support other mimetypes
} }
cb.mutex.unlock() cb.mutex.unlock()
} }

View File

@ -44,7 +44,7 @@ pub fn resource_path() string {
if conv_result == 0 { if conv_result == 0 {
panic('CFURLGetFileSystemRepresentation failed') panic('CFURLGetFileSystemRepresentation failed')
} }
result := string(buffer) result := unsafe { buffer.vstring() }
C.CFRelease(resource_dir_url) C.CFRelease(resource_dir_url)
return result return result
} }

View File

@ -116,7 +116,7 @@ pub fn (conn Connection) escape_string(s string) string {
quote := byte(39) // single quote quote := byte(39) // single quote
C.mysql_real_escape_string_quote(conn.conn, to, s.str, len, quote) C.mysql_real_escape_string_quote(conn.conn, to, s.str, len, quote)
return string(to) return unsafe { to.vstring() }
} }
// set_option is used to set extra connect options and affect behavior for a connection. // set_option is used to set extra connect options and affect behavior for a connection.
@ -175,12 +175,12 @@ pub fn (conn Connection) info() string {
// get_host_info returns a string describing the connection. // get_host_info returns a string describing the connection.
pub fn (conn Connection) get_host_info() string { pub fn (conn Connection) get_host_info() string {
return string(C.mysql_get_host_info(conn.conn)) return unsafe { C.mysql_get_host_info(conn.conn).vstring() }
} }
// get_server_info returns the server version number as a string. // get_server_info returns the server version number as a string.
pub fn (conn Connection) get_server_info() string { pub fn (conn Connection) get_server_info() string {
return string(C.mysql_get_server_info(conn.conn)) return unsafe { C.mysql_get_server_info(conn.conn).vstring() }
} }
// get_server_version returns the server version number as an integer. // get_server_version returns the server version number as an integer.
@ -192,7 +192,7 @@ pub fn (conn Connection) get_server_version() u64 {
// get_client_info returns client version information as a string. // get_client_info returns client version information as a string.
pub fn get_client_info() string { pub fn get_client_info() string {
return string(C.mysql_get_client_info()) return unsafe { C.mysql_get_client_info().vstring() }
} }
// get_client_version returns client version information as an integer. // get_client_version returns client version information as an integer.

View File

@ -34,7 +34,7 @@ pub fn (r Result) rows() []Row {
if rr[i] == 0 { if rr[i] == 0 {
row.vals << '' row.vals << ''
} else { } else {
row.vals << string(&byte(rr[i])) row.vals << mystring( byteptr(rr[i]) )
} }
} }
rows << row rows << row
@ -64,12 +64,12 @@ pub fn (r Result) fields() []Field {
orig_fields := C.mysql_fetch_fields(r.result) orig_fields := C.mysql_fetch_fields(r.result)
for i in 0..nr_cols { for i in 0..nr_cols {
fields << Field{ fields << Field{
name: string(orig_fields[i].name) name: mystring(orig_fields[i].name)
org_name: string(orig_fields[i].org_name) org_name: mystring(orig_fields[i].org_name)
table: string(orig_fields[i].table) table: mystring(orig_fields[i].table)
org_table: string(orig_fields[i].org_table) org_table: mystring(orig_fields[i].org_table)
db: string(orig_fields[i].db) db: mystring(orig_fields[i].db)
catalog: string(orig_fields[i].catalog) catalog: mystring(orig_fields[i].catalog)
def: resolve_nil_str(orig_fields[i].def) def: resolve_nil_str(orig_fields[i].def)
length: orig_fields.length length: orig_fields.length
max_length: orig_fields.max_length max_length: orig_fields.max_length

View File

@ -2,7 +2,7 @@ module mysql
// get_error_msg returns error message from MySQL instance. // get_error_msg returns error message from MySQL instance.
fn get_error_msg(conn &C.MYSQL) string { fn get_error_msg(conn &C.MYSQL) string {
return string(C.mysql_error(conn)) return unsafe { C.mysql_error(conn).vstring() }
} }
// get_errno returns error number from MySQL instance. // get_errno returns error number from MySQL instance.
@ -13,5 +13,12 @@ fn get_errno(conn &C.MYSQL) int {
// resolve_nil_str returns empty string if passed value is a nil pointer. // resolve_nil_str returns empty string if passed value is a nil pointer.
fn resolve_nil_str(ptr byteptr) string { fn resolve_nil_str(ptr byteptr) string {
if isnil(ptr) { return '' } if isnil(ptr) { return '' }
return string(ptr) return unsafe { ptr.vstring() }
}
[inline]
fn mystring(b byteptr) string {
unsafe {
return b.vstring()
}
} }

View File

@ -156,7 +156,7 @@ pub fn (ftp FTP) pwd() string {
return '' return ''
} }
_, data := ftp.read() _, data := ftp.read()
spl := data.split('"') spl := data.split('"') // "
if spl.len >= 2 { if spl.len >= 2 {
return spl[1] return spl[1]
} }
@ -236,7 +236,7 @@ pub fn (ftp FTP) dir() ?[]string {
} }
dtp.close() dtp.close()
mut dir := []string{} mut dir := []string{}
sdir := string(byteptr(list_dir.data)) sdir := list_dir.bytestr()
for lfile in sdir.split('\n') { for lfile in sdir.split('\n') {
if lfile.len > 1 { if lfile.len > 1 {
spl := lfile.split(' ') spl := lfile.split(' ')

View File

@ -275,7 +275,7 @@ fn sanitize(valid fn(byte) bool, v string) string {
break break
} }
if ok { if ok {
return v return v.clone()
} }
// TODO: Use `filter` instead of this nonesense // TODO: Use `filter` instead of this nonesense
buf := v.bytes() buf := v.bytes()
@ -285,7 +285,7 @@ fn sanitize(valid fn(byte) bool, v string) string {
bytes.delete(i) bytes.delete(i)
} }
} }
return string(bytes) return bytes.bytestr()
} }
fn sanitize_cookie_name(name string) string { fn sanitize_cookie_name(name string) string {

View File

@ -272,7 +272,7 @@ fn escape(s string, mode EncodingMode) string {
t[i] = `+` t[i] = `+`
} }
} }
return string(t,t.len) return t.bytestr()
} }
upperhex := '0123456789ABCDEF' upperhex := '0123456789ABCDEF'
mut j := 0 mut j := 0
@ -293,7 +293,7 @@ fn escape(s string, mode EncodingMode) string {
j++ j++
} }
} }
return string(t,t.len) return t.bytestr()
} }
// A URL represents a parsed URL (technically, a URI reference). // A URL represents a parsed URL (technically, a URI reference).
@ -367,7 +367,7 @@ fn (u &Userinfo) empty() bool {
// string returns the encoded userinfo information in the standard form // string returns the encoded userinfo information in the standard form
// of 'username[:password]'. // of 'username[:password]'.
fn (u &Userinfo) string() string { fn (u &Userinfo) str() string {
if u.empty() { if u.empty() {
return '' return ''
} }
@ -771,7 +771,7 @@ pub fn (u URL) str() string {
buf.write('//') buf.write('//')
} }
if !u.user.empty() { if !u.user.empty() {
buf.write(u.user.string()) buf.write(u.user.str())
buf.write('@') buf.write('@')
} }
if u.host != '' { if u.host != '' {

View File

@ -32,12 +32,8 @@ fn create_key_challenge_response(seckey string) string {
guid := '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' guid := '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
sha1buf := seckey + guid sha1buf := seckey + guid
hash := sha1.sum(sha1buf.bytes()) hash := sha1.sum(sha1buf.bytes())
hashstr := string(byteptr(hash.data)) hashstr := hash.bytestr()
b64 := base64.encode(hashstr) b64 := base64.encode(hashstr)
unsafe {
sha1buf.free()
hash.free()
}
return b64 return b64
} }

View File

@ -294,7 +294,7 @@ pub fn (mut ws Client) write(payload byteptr, payload_len int, code OPCode) int
} }
bytes_written = ws.write_to_server(fbdata, frame_len) bytes_written = ws.write_to_server(fbdata, frame_len)
if bytes_written == -1 { if bytes_written == -1 {
err := string(byteptr(C.strerror(C.errno))) err := unsafe { byteptr(C.strerror(C.errno)).vstring() }
ws.log.error('write: there was an error writing data: $err') ws.log.error('write: there was an error writing data: $err')
ws.send_error_event('Error writing data') ws.send_error_event('Error writing data')
goto free_data goto free_data
@ -344,7 +344,7 @@ pub fn (mut ws Client) read() int {
return -1 return -1
} }
-1 { -1 {
err := string(byteptr(C.strerror(C.errno))) err := unsafe { byteptr(C.strerror(C.errno)).vstring() }
ws.log.error('read: error reading frame. $err') ws.log.error('read: error reading frame. $err')
ws.send_error_event('error reading frame') ws.send_error_event('error reading frame')
goto free_data goto free_data
@ -564,7 +564,7 @@ pub fn (mut ws Client) read() int {
code = (int(unsafe {data[header_len]}) << 8) + int(unsafe {data[header_len + 1]}) code = (int(unsafe {data[header_len]}) << 8) + int(unsafe {data[header_len + 1]})
header_len += 2 header_len += 2
payload_len -= 2 payload_len -= 2
reason = unsafe {string(&data[header_len])} reason = unsafe { byteptr(&data[header_len]).vstring() }
ws.log.info('Closing with reason: $reason & code: $code') ws.log.info('Closing with reason: $reason & code: $code')
if reason.len > 1 && !utf8.validate(reason.str, reason.len) { if reason.len > 1 && !utf8.validate(reason.str, reason.len) {
ws.log.error('malformed utf8 payload') ws.log.error('malformed utf8 payload')
@ -654,4 +654,4 @@ fn (mut ws Client) send_control_frame(code OPCode, frame_typ string, payload []b
return bytes_written return bytes_written
} }
} }
} }

View File

@ -39,7 +39,7 @@ pub fn read_file(path string) ?string {
mut str := malloc(fsize + 1) mut str := malloc(fsize + 1)
C.fread(str, fsize, 1, fp) C.fread(str, fsize, 1, fp)
str[fsize] = 0 str[fsize] = 0
return string(str,fsize) return str.vstring_with_len(fsize)
} }
} }
@ -673,7 +673,7 @@ pub fn get_raw_line() string {
} }
offset++ offset++
} }
return string(buf, offset) return buf.vstring_with_len(offset)
} }
} $else { } $else {
max := size_t(0) max := size_t(0)
@ -858,7 +858,7 @@ pub fn executable() string {
eprintln('os.executable() failed at reading /proc/self/exe to get exe path') eprintln('os.executable() failed at reading /proc/self/exe to get exe path')
return executable_fallback() return executable_fallback()
} }
return string(result) return unsafe { result.vstring() }
} }
$if windows { $if windows {
max := 512 max := 512
@ -896,7 +896,7 @@ pub fn executable() string {
eprintln('os.executable() failed at calling proc_pidpath with pid: $pid . proc_pidpath returned $ret ') eprintln('os.executable() failed at calling proc_pidpath with pid: $pid . proc_pidpath returned $ret ')
return executable_fallback() return executable_fallback()
} }
return string(result) return unsafe { result.vstring() }
} }
$if freebsd { $if freebsd {
mut result := vcalloc(max_path_len) mut result := vcalloc(max_path_len)
@ -905,7 +905,7 @@ pub fn executable() string {
unsafe { unsafe {
C.sysctl(mib.data, 4, result, &size, 0, 0) C.sysctl(mib.data, 4, result, &size, 0, 0)
} }
return string(result) return unsafe { result.vstring() }
} }
// "Sadly there is no way to get the full path of the executed file in OpenBSD." // "Sadly there is no way to get the full path of the executed file in OpenBSD."
$if openbsd {} $if openbsd {}
@ -918,7 +918,7 @@ pub fn executable() string {
eprintln('os.executable() failed at reading /proc/curproc/exe to get exe path') eprintln('os.executable() failed at reading /proc/curproc/exe to get exe path')
return executable_fallback() return executable_fallback()
} }
return string(result,count) return result.vstring_with_len(count)
} }
$if dragonfly { $if dragonfly {
mut result := vcalloc(max_path_len) mut result := vcalloc(max_path_len)
@ -927,7 +927,7 @@ pub fn executable() string {
eprintln('os.executable() failed at reading /proc/curproc/file to get exe path') eprintln('os.executable() failed at reading /proc/curproc/file to get exe path')
return executable_fallback() return executable_fallback()
} }
return string(result,count) return unsafe { result.vstring_with_len(count) }
} }
return executable_fallback() return executable_fallback()
} }
@ -1056,7 +1056,7 @@ pub fn getwd() string {
if C.getcwd(charptr(buf), 512) == 0 { if C.getcwd(charptr(buf), 512) == 0 {
return '' return ''
} }
return string(buf) return unsafe { buf.vstring() }
} }
} }
@ -1079,7 +1079,7 @@ pub fn real_path(fpath string) string {
return fpath return fpath
} }
} }
return string(fullpath) return unsafe { fullpath.vstring() }
} }
// is_abs_path returns true if `path` is absolute. // is_abs_path returns true if `path` is absolute.

View File

@ -51,8 +51,10 @@ fn init_os_args(argc int, argv &&byte) []string {
// mut args := []string(make(0, argc, sizeof(string))) // mut args := []string(make(0, argc, sizeof(string)))
// mut args := []string{len:argc} // mut args := []string{len:argc}
for i in 0 .. argc { for i in 0 .. argc {
// args [i] = string(argv[i]) // args [i] = argv[i].vstring()
args << unsafe {string(argv[i])} unsafe {
args << byteptr(argv[i]).vstring()
}
} }
return args return args
} }

View File

@ -45,7 +45,7 @@ pub fn connect(config Config) ?DB {
println("status=$status") println("status=$status")
if status != C.CONNECTION_OK { if status != C.CONNECTION_OK {
error_msg := C.PQerrorMessage(conn) error_msg := C.PQerrorMessage(conn)
return error ('Connection to a PG database failed: ' + string(error_msg)) return error ('Connection to a PG database failed: ' + unsafe { error_msg.vstring() } )
} }
return DB {conn: conn} return DB {conn: conn}
} }
@ -58,7 +58,8 @@ fn res_to_rows(res voidptr) []Row {
mut row := Row{} mut row := Row{}
for j in 0..nr_cols { for j in 0..nr_cols {
val := C.PQgetvalue(res, i, j) val := C.PQgetvalue(res, i, j)
row.vals << string(val) sval := unsafe { val.vstring() }
row.vals << sval
} }
rows << row rows << row
} }
@ -100,7 +101,7 @@ pub fn (db DB) q_strings(query string) []Row {
pub fn (db DB) exec(query string) []Row { pub fn (db DB) exec(query string) []Row {
res := C.PQexec(db.conn, query.str) res := C.PQexec(db.conn, query.str)
e := string(C.PQerrorMessage(db.conn)) e := unsafe { C.PQerrorMessage(db.conn).vstring() }
if e != '' { if e != '' {
println('pg exec error:') println('pg exec error:')
println(e) println(e)
@ -118,7 +119,7 @@ fn rows_first_or_empty(rows []Row) ?Row {
pub fn (db DB) exec_one(query string) ?Row { pub fn (db DB) exec_one(query string) ?Row {
res := C.PQexec(db.conn, query.str) res := C.PQexec(db.conn, query.str)
e := string(C.PQerrorMessage(db.conn)) e := unsafe { C.PQerrorMessage(db.conn).vstring() }
if e != '' { if e != '' {
return error('pg exec error: "$e"') return error('pg exec error: "$e"')
} }
@ -156,7 +157,7 @@ pub fn (db DB) exec_param(query string, param string) []Row {
} }
fn (db DB) handle_error_or_result(res voidptr, elabel string) []Row { fn (db DB) handle_error_or_result(res voidptr, elabel string) []Row {
e := string(C.PQerrorMessage(db.conn)) e := unsafe { C.PQerrorMessage(db.conn).vstring() }
if e != '' { if e != '' {
println('pg $elabel error:') println('pg $elabel error:')
println(e) println(e)

View File

@ -141,7 +141,7 @@ pub fn string(len int) string {
buf[i] = chars[intn(chars.len)] buf[i] = chars[intn(chars.len)]
} }
} }
return string(buf, len) return unsafe { buf.vstring_with_len(len) }
} }
// rand.uuid_v4 generate a completely random UUID (v4) // rand.uuid_v4 generate a completely random UUID (v4)
@ -181,7 +181,7 @@ pub fn uuid_v4() string {
buf[14] = `4` buf[14] = `4`
buf[buflen] = 0 buf[buflen] = 0
} }
return string(buf, buflen) return unsafe { buf.vstring_with_len(buflen) }
} }
const( const(
@ -232,5 +232,5 @@ pub fn ulid_at_millisecond(unix_time_milli u64) string {
unsafe{ unsafe{
buf[26] = 0 buf[26] = 0
} }
return string(buf, buflen) return unsafe { buf.vstring_with_len(buflen) }
} }

View File

@ -38,7 +38,7 @@ pub fn (mut b Builder) writeln(s string) {
} }
pub fn (b Builder) str() string { pub fn (b Builder) str() string {
return string(b.buf, b.len) return unsafe { byteptr(b.buf.data).vstring_with_len(b.len) }
} }
pub fn (mut b Builder) cut(n int) { pub fn (mut b Builder) cut(n int) {

View File

@ -116,7 +116,7 @@ pub fn (mut b Builder) str() string {
'If you want to reuse a builder, call b.free() first.') 'If you want to reuse a builder, call b.free() first.')
} }
b.buf << `\0` b.buf << `\0`
s := string(b.buf,b.len) s := tos(b.buf.data, b.len)
bis := b.initial_size bis := b.initial_size
//free(b.buf.data) //free(b.buf.data)
b.buf = []byte{cap: bis} b.buf = []byte{cap: bis}

View File

@ -10,7 +10,7 @@ pub fn repeat(c byte, n int) string {
C.memset( bytes, c, n ) C.memset( bytes, c, n )
bytes[n] = `0` bytes[n] = `0`
} }
return string( bytes, n ) return unsafe { bytes.vstring_with_len(n) }
} }
// strings.repeat_string - gives you `n` repetitions of the substring `s` // strings.repeat_string - gives you `n` repetitions of the substring `s`
@ -34,5 +34,5 @@ pub fn repeat_string(s string, n int) string {
unsafe { unsafe {
bytes[blen] = `0` bytes[blen] = `0`
} }
return string( bytes, blen ) return unsafe { bytes.vstring_with_len(blen) }
} }

View File

@ -4,9 +4,8 @@ pub fn repeat(c byte, n int) string {
if n <= 0 { if n <= 0 {
return '' return ''
} }
mut arr := [c].repeat(n + 1) arr := [c].repeat(n)
arr[n] = `\0` return arr.bytestr()
return string(arr,n)
} }
pub fn repeat_string(s string, n int) string { pub fn repeat_string(s string, n int) string {

View File

@ -769,6 +769,14 @@ pub:
has_low bool has_low bool
} }
// NB: &string(x) gets parsed as ast.PrefixExpr{ right: ast.CastExpr{...} }
// TODO: that is very likely a parsing bug. It should get parsed as just
// ast.CastExpr{...}, where .typname is '&string' instead.
// The current situation leads to special cases in vfmt and cgen
// (see prefix_expr_cast_expr in fmt.v, and .is_amp in cgen.v)
// .in_prexpr is also needed because of that, because the checker needs to
// show warnings about the deprecated C->V conversions `string(x)` and
// `string(x,y)`, while skipping the real pointer casts like `&string(x)`.
pub struct CastExpr { pub struct CastExpr {
pub: pub:
expr Expr // `buf` in `string(buf, n)` expr Expr // `buf` in `string(buf, n)`
@ -779,6 +787,7 @@ pub mut:
typname string typname string
expr_type table.Type // `byteptr` expr_type table.Type // `byteptr`
has_arg bool has_arg bool
in_prexpr bool // is the parent node an ast.PrefixExpr
} }
pub struct AssertStmt { pub struct AssertStmt {

View File

@ -2265,6 +2265,16 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
node.expr_type = c.expr(node.expr) node.expr_type = c.expr(node.expr)
from_type_sym := c.table.get_type_symbol(node.expr_type) from_type_sym := c.table.get_type_symbol(node.expr_type)
to_type_sym := c.table.get_type_symbol(node.typ) to_type_sym := c.table.get_type_symbol(node.typ)
expr_is_ptr := node.expr_type.is_ptr() || node.expr_type.idx() in table.pointer_type_idxs
if expr_is_ptr && to_type_sym.kind == .string && !node.in_prexpr {
if node.has_arg {
c.warn('to convert a C string buffer pointer to a V string, please use x.vstring_with_len(len) instead of string(x,len)',
node.pos)
} else {
c.warn('to convert a C string buffer pointer to a V string, please use x.vstring() instead of string(x)',
node.pos)
}
}
if node.expr_type == table.byte_type && to_type_sym.kind == .string { if node.expr_type == table.byte_type && to_type_sym.kind == .string {
c.error('can not cast type `byte` to string, use `${node.expr.str()}.str()` instead.', c.error('can not cast type `byte` to string, use `${node.expr.str()}.str()` instead.',
node.pos) node.pos)

View File

@ -0,0 +1,14 @@
vlib/v/checker/tests/warnings_for_string_c2v_calls.v:8:14: error: to convert a C string buffer pointer to a V string, please use x.vstring() instead of string(x)
6 | p[2] = `z`
7 | }
8 | x := string(p)
| ^
9 | y := string(p, 10)
10 | eprintln('x: $x | y: $y')
vlib/v/checker/tests/warnings_for_string_c2v_calls.v:9:14: error: to convert a C string buffer pointer to a V string, please use x.vstring_with_len(len) instead of string(x,len)
7 | }
8 | x := string(p)
9 | y := string(p, 10)
| ^
10 | eprintln('x: $x | y: $y')
11 | eprintln('x.len: $x.len | y.len: $y.len')

View File

@ -0,0 +1,12 @@
fn main() {
mut p := vcalloc(20)
unsafe {
p[0] = `A`
p[1] = `B`
p[2] = `z`
}
x := string(p)
y := string(p, 10)
eprintln('x: $x | y: $y')
eprintln('x.len: $x.len | y.len: $y.len')
}

View File

@ -5,7 +5,7 @@ fn abc() string {
fullpath[1] = `b` fullpath[1] = `b`
fullpath[2] = `c` fullpath[2] = `c`
fullpath[3] = 0 fullpath[3] = 0
return string(fullpath) return fullpath.vstring()
} }
return '' return ''
} }
@ -17,7 +17,7 @@ fn def() string {
fullpath[1] = `b` fullpath[1] = `b`
fullpath[2] = `c` fullpath[2] = `c`
fullpath[3] = 0 fullpath[3] = 0
return string(fullpath, 3) return fullpath.vstring_with_len(3)
} }
return '' return ''
} }

View File

@ -309,8 +309,11 @@ fn (mut p Parser) prefix_expr() ast.PrefixExpr {
// p.warn('unsafe') // p.warn('unsafe')
// } // }
p.next() p.next()
right := if op == .minus { p.expr(token.Precedence.call) } else { p.expr(token.Precedence.prefix) } mut right := if op == .minus { p.expr(token.Precedence.call) } else { p.expr(token.Precedence.prefix) }
p.is_amp = false p.is_amp = false
if mut right is ast.CastExpr {
right.in_prexpr = true
}
return ast.PrefixExpr{ return ast.PrefixExpr{
op: op op: op
right: right right: right

View File

@ -323,7 +323,7 @@ fn filter_num_sep(txt byteptr, start, end int) string {
} }
} }
b[i1] = 0 // C string compatibility b[i1] = 0 // C string compatibility
return string(b) return b.vstring_with_len(i1)
} }
} }

View File

@ -10,7 +10,7 @@ fn test_cstring() {
fn test_cstring_with_zeros() { fn test_cstring_with_zeros() {
rawbytes := c'\x00username\x00password' rawbytes := c'\x00username\x00password'
s := string(rawbytes, 18) s := unsafe { rawbytes.vstring_with_len(18) }
h := s.bytes().hex() h := s.bytes().hex()
assert h == '00757365726e616d650070617373776f7264' assert h == '00757365726e616d650070617373776f7264'
} }

View File

@ -583,7 +583,7 @@ fn readall(conn net.Socket) string {
for { for {
n := C.recv(conn.sockfd, buf, 1024, 0) n := C.recv(conn.sockfd, buf, 1024, 0)
m := conn.crecv(buf, 1024) m := conn.crecv(buf, 1024)
message += string( byteptr(buf), m ) message += unsafe { byteptr(buf).vstring_with_len(m) }
if message.len > max_http_post_size { break } if message.len > max_http_post_size { break }
if n == m { break } if n == m { break }
} }