From b91d0a45139202175bcf1e9e40ece15faead936b Mon Sep 17 00:00:00 2001 From: xdBronch <51252236+xdBronch@users.noreply.github.com> Date: Thu, 16 Apr 2026 09:59:39 -0400 Subject: [PATCH 1/4] nuke cImport from orbit --- README.md | 2 +- build.zig | 4 +- build.zig.zon | 2 +- src/DiagnosticsCollection.zig | 2 - src/DocumentStore.zig | 260 ------------------------ src/Server.zig | 7 - src/analysis.zig | 20 -- src/build_runner/build_runner.zig | 2 - src/features/completions.zig | 26 --- src/features/goto.zig | 47 +---- src/features/hover.zig | 30 +-- src/features/inlay_hints.zig | 4 - src/tools/langref.html.in | 165 +-------------- src/translate_c.zig | 301 ---------------------------- src/zls.zig | 1 - tests/language_features/cimport.zig | 135 ------------- tests/lsp_features/hover.zig | 11 +- tests/tests.zig | 3 - 18 files changed, 11 insertions(+), 1011 deletions(-) delete mode 100644 src/translate_c.zig delete mode 100644 tests/language_features/cimport.zig diff --git a/README.md b/README.md index 54db2f3ce..a13d1d151 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ When upgrading Zig, make sure to update ZLS too keep them in sync. ## Features -ZLS supports most language features, including simple type function support, using namespace, payload capture type resolution, custom packages, cImport and others. Support for comptime and semantic analysis is Work-in-Progress. +ZLS supports most language features, including simple type function support, payload capture type resolution, custom packages, and others. Support for comptime and semantic analysis is Work-in-Progress. The following LSP features are supported: diff --git a/build.zig b/build.zig index cfec30536..6ba06a5a9 100644 --- a/build.zig +++ b/build.zig @@ -6,10 +6,10 @@ const zls_version = std.SemanticVersion.parse(@import("build.zig.zon").version) const minimum_build_zig_version = @import("build.zig.zon").minimum_zig_version; /// Specify the minimum Zig version that is usable with ZLS: -/// Release 0.16.0 +/// delete @cImport from the language /// /// A breaking change to the Zig Build System should be handled by updating ZLS's build runner (see src\build_runner) -const minimum_runtime_zig_version = "0.16.0"; +const minimum_runtime_zig_version = "0.17.0-dev.39+d092c752f"; const release_targets = [_]std.Target.Query{ .{ .cpu_arch = .aarch64, .os_tag = .linux }, diff --git a/build.zig.zon b/build.zig.zon index 67ea58df4..e4cefd63b 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -10,7 +10,7 @@ // nix flake update --commit-lock-file // ``` // If you do not use Nix, a ZLS maintainer can take care of this. - .minimum_zig_version = "0.16.0", + .minimum_zig_version = "0.17.0-dev.39+d092c752f", // Must be kept in sync with the `deps.nix` for the Nix flake. // If you do not use Nix, a ZLS maintainer can take care of this. .dependencies = .{ diff --git a/src/DiagnosticsCollection.zig b/src/DiagnosticsCollection.zig index 2dbbe165c..a6184b0c5 100644 --- a/src/DiagnosticsCollection.zig +++ b/src/DiagnosticsCollection.zig @@ -33,8 +33,6 @@ pub const Tag = enum(u32) { /// - ast-check /// - warn_style parse, - /// errors from `@cImport` - cimport, /// - Build On Save /// - Build Runner _, diff --git a/src/DocumentStore.zig b/src/DocumentStore.zig index e40a9881a..2c870cf99 100644 --- a/src/DocumentStore.zig +++ b/src/DocumentStore.zig @@ -11,7 +11,6 @@ const Ast = std.zig.Ast; const BuildAssociatedConfig = @import("BuildAssociatedConfig.zig"); pub const BuildConfig = @import("build_runner/shared.zig").BuildConfig; const tracy = @import("tracy"); -const translate_c = @import("translate_c.zig"); const DocumentScope = @import("DocumentScope.zig"); const DiagnosticsCollection = @import("DiagnosticsCollection.zig"); const TrigramStore = @import("TrigramStore.zig"); @@ -26,7 +25,6 @@ mutex: std.Io.Mutex = .init, wait_group: if (supports_build_system) std.Io.Group else void = if (supports_build_system) .init else {}, handles: Uri.ArrayHashMap(*Handle.Future) = .empty, build_files: if (supports_build_system) Uri.ArrayHashMap(*BuildFile) else void = if (supports_build_system) .empty else {}, -cimports: if (supports_build_system) std.array_hash_map.Auto(CImportHash, translate_c.Result) else void = if (supports_build_system) .empty else {}, diagnostics_collection: *DiagnosticsCollection, builds_in_progress: std.atomic.Value(i32) = .init(0), transport: ?*lsp.Transport = null, @@ -165,8 +163,6 @@ pub const Handle = struct { tree: Ast, /// List of every file that has been `@Import`ed. Does not include imported modules. file_imports: []const Uri, - /// Contains one entry for every `@cImport` in the document - cimports: std.MultiArrayList(CImportHandle), /// `true` if the document has been directly opened by the client i.e. with `textDocument/didOpen` /// `false` indicates the document only exists because it is a dependency of another document /// or has been closed with `textDocument/didClose`. @@ -421,20 +417,11 @@ pub const Handle = struct { var new_file_imports: std.ArrayList(Uri) = .empty; errdefer new_file_imports.deinit(allocator); - var new_cimports: std.MultiArrayList(CImportHandle) = .empty; - errdefer { - for (new_cimports.items(.source)) |source| { - allocator.free(source); - } - new_cimports.deinit(allocator); - } - try collectImports( allocator, handle.uri, &new_tree, &new_file_imports, - &new_cimports, ); const file_imports = try new_file_imports.toOwnedSlice(allocator); @@ -446,12 +433,10 @@ pub const Handle = struct { old_handle.tree = handle.tree; old_handle.impl.has_tree_and_source = true; } - old_handle.cimports = handle.cimports; handle.tree = new_tree; old_handle.file_imports = handle.file_imports; handle.file_imports = file_imports; - handle.cimports = new_cimports; handle.impl.has_tree_and_source = true; old_handle.document_scope = handle.document_scope; @@ -484,7 +469,6 @@ pub const Handle = struct { uri: Uri, tree: *const Ast, file_imports: *std.ArrayList(Uri), - cimports: *std.MultiArrayList(CImportHandle), ) error{OutOfMemory}!void { const tracy_zone = tracy.trace(@src()); defer tracy_zone.end(); @@ -522,25 +506,6 @@ pub const Handle = struct { file_imports.appendAssumeCapacity(import_uri); continue; } - - if (std.mem.eql(u8, name, "@cImport")) { - try cimports.ensureUnusedCapacity(allocator, 1); - - const c_source = translate_c.convertCInclude(allocator, tree, node) catch |err| switch (err) { - error.Unsupported => continue, - error.OutOfMemory => return error.OutOfMemory, - }; - - var hasher: CImportHasher = .init(&@splat(0)); - hasher.update(c_source); - - cimports.appendAssumeCapacity(.{ - .node = node, - .hash = hasher.finalResult(), - .source = c_source, - }); - continue; - } } } @@ -549,7 +514,6 @@ pub const Handle = struct { .uri = undefined, .tree = undefined, .file_imports = &.{}, - .cimports = .empty, .lsp_synced = undefined, .impl = .{ .store = undefined, @@ -572,9 +536,6 @@ pub const Handle = struct { for (self.file_imports) |uri| uri.deinit(allocator); allocator.free(self.file_imports); - for (self.cimports.items(.source)) |source| allocator.free(source); - self.cimports.deinit(allocator); - self.impl.associated_build_file.deinit(allocator); self.impl.associated_compilation_units.deinit(allocator); @@ -712,11 +673,6 @@ pub fn deinit(self: *DocumentStore) void { self.allocator.destroy(build_file); } self.build_files.deinit(self.allocator); - - for (self.cimports.values()) |*result| { - result.deinit(self.allocator); - } - self.cimports.deinit(self.allocator); } self.* = undefined; @@ -1635,7 +1591,6 @@ fn createAndStoreDocument( .uri = gop.key_ptr.*, .tree = undefined, .file_imports = &.{}, - .cimports = .empty, .lsp_synced = options.lsp_synced, .impl = .{ .store = store, @@ -1672,18 +1627,6 @@ fn createAndStoreDocument( return &handle_future.handle; } -pub const CImportHasher = std.crypto.auth.siphash.SipHash128(1, 3); -pub const CImportHash = [CImportHasher.mac_length]u8; - -pub const CImportHandle = struct { - /// the `@cImport` node - node: Ast.Node.Index, - /// hash of c source file - hash: CImportHash, - /// c source file - source: []const u8, -}; - /// returns `true` if all include paths could be collected /// may return `false` because include paths from a build.zig may not have been resolved already /// **Thread safe** takes a shared lock @@ -1751,209 +1694,6 @@ pub fn collectIncludeDirs( return collected_all; } -/// returns `true` if all c macro definitions could be collected -/// may return `false` because macros from a build.zig may not have been resolved already -/// **Thread safe** takes a shared lock -pub fn collectCMacros( - store: *DocumentStore, - allocator: std.mem.Allocator, - handle: *Handle, - c_macros: *std.ArrayList([]const u8), -) error{ Canceled, OutOfMemory }!bool { - comptime std.debug.assert(supports_build_system); - - const collected_all = switch (try handle.getAssociatedBuildFile(store)) { - .none => true, - .unresolved => false, - .resolved => |resolved| collected_all: { - const build_config = resolved.build_file.tryLockConfig(store.io) orelse break :collected_all false; - defer resolved.build_file.unlockConfig(store.io); - - const module = build_config.modules.map.get(resolved.root_source_file) orelse break :collected_all true; - - try c_macros.ensureUnusedCapacity(allocator, module.c_macros.len); - for (module.c_macros) |c_macro| { - c_macros.appendAssumeCapacity(try allocator.dupe(u8, c_macro)); - } - break :collected_all true; - }, - }; - - return collected_all; -} - -/// returns the document behind `@cImport()` where `node` is the `cImport` node -/// if a cImport can't be translated e.g. requires computing a -/// comptime value `resolveCImport` will return null -/// returned memory is owned by DocumentStore -/// **Thread safe** takes an exclusive lock -pub fn resolveCImport(self: *DocumentStore, handle: *Handle, node: Ast.Node.Index) error{ Canceled, OutOfMemory }!?Uri { - comptime std.debug.assert(supports_build_system); - - const tracy_zone = tracy.trace(@src()); - defer tracy_zone.end(); - - if (self.config.zig_exe_path == null) return null; - if (self.config.zig_lib_dir == null) return null; - if (self.config.global_cache_dir == null) return null; - - const index = std.mem.findScalar(Ast.Node.Index, handle.cimports.items(.node), node) orelse return null; - const hash: CImportHash = handle.cimports.items(.hash)[index]; - const source = handle.cimports.items(.source)[index]; - - { - try self.mutex.lock(self.io); - defer self.mutex.unlock(self.io); - if (self.cimports.get(hash)) |result| { - switch (result) { - .success => |uri| return uri, - .failure => return null, - } - } - } - - var include_dirs: std.ArrayList([]const u8) = .empty; - defer { - for (include_dirs.items) |path| { - self.allocator.free(path); - } - include_dirs.deinit(self.allocator); - } - - const collected_all_include_dirs = self.collectIncludeDirs(self.allocator, handle, &include_dirs) catch |err| switch (err) { - error.Canceled => return error.Canceled, - else => { - log.err("failed to resolve include paths: {}", .{err}); - return null; - }, - }; - - var c_macros: std.ArrayList([]const u8) = .empty; - defer { - for (c_macros.items) |c_macro| { - self.allocator.free(c_macro); - } - c_macros.deinit(self.allocator); - } - - const collected_all_c_macros = self.collectCMacros(self.allocator, handle, &c_macros) catch |err| switch (err) { - error.Canceled => return error.Canceled, - else => { - log.err("failed to resolve include paths: {}", .{err}); - return null; - }, - }; - - const maybe_result = translate_c.translate( - self.io, - self.allocator, - self.config, - include_dirs.items, - c_macros.items, - source, - ) catch |err| switch (err) { - error.Canceled, error.OutOfMemory => |e| return e, - else => |e| { - log.err("failed to translate cimport: {}", .{e}); - return null; - }, - }; - var result = maybe_result orelse return null; - - if (result == .failure and (!collected_all_include_dirs or !collected_all_c_macros)) { - result.deinit(self.allocator); - return null; - } - - { - try self.mutex.lock(self.io); - defer self.mutex.unlock(self.io); - const gop = self.cimports.getOrPutValue(self.allocator, hash, result) catch |err| { - result.deinit(self.allocator); - return err; - }; - if (gop.found_existing) { - result.deinit(self.allocator); - result = gop.value_ptr.*; - } - } - - self.publishCimportDiagnostics(handle) catch |err| switch (err) { - error.Canceled => return error.Canceled, - else => { - log.err("failed to publish cImport diagnostics: {}", .{err}); - }, - }; - - switch (result) { - .success => |uri| { - log.debug("Translated cImport into {s}", .{uri.raw}); - return uri; - }, - .failure => return null, - } -} - -fn publishCimportDiagnostics(self: *DocumentStore, handle: *Handle) (std.mem.Allocator.Error || std.Io.File.Writer.Error)!void { - var wip: std.zig.ErrorBundle.Wip = undefined; - try wip.init(self.allocator); - defer wip.deinit(); - - const src_path = try wip.addString(""); - - for (handle.cimports.items(.hash), handle.cimports.items(.node)) |hash, node| { - const result = blk: { - try self.mutex.lock(self.io); - defer self.mutex.unlock(self.io); - break :blk self.cimports.get(hash) orelse continue; - }; - const error_bundle: std.zig.ErrorBundle = switch (result) { - .success => continue, - .failure => |bundle| bundle, - }; - - if (error_bundle.errorMessageCount() == 0) continue; - - const loc = offsets.nodeToLoc(&handle.tree, node); - const source_loc = std.zig.findLineColumn(handle.tree.source, loc.start); - - // assert that the `@intCast` below is safe - comptime std.debug.assert(std.zig.max_src_size <= std.math.maxInt(u32)); - - const src_loc = try wip.addSourceLocation(.{ - .src_path = src_path, - .line = @intCast(source_loc.line), - .column = @intCast(source_loc.column), - .span_start = @intCast(loc.start), - .span_main = @intCast(loc.start), - .span_end = @intCast(loc.end), - .source_line = try wip.addString(source_loc.source_line), - }); - - for (error_bundle.getMessages()) |err_msg_index| { - const err_msg = error_bundle.getErrorMessage(err_msg_index); - const msg = error_bundle.nullTerminatedString(err_msg.msg); - - try wip.addRootErrorMessage(.{ - .msg = try wip.addString(msg), - .src_loc = src_loc, - }); - } - } - - { - var error_bundle = try wip.toOwnedBundle(""); - errdefer error_bundle.deinit(self.allocator); - - try self.diagnostics_collection.pushSingleDocumentDiagnostics( - .cimport, - handle.uri, - .{ .error_bundle = error_bundle }, - ); - } - try self.diagnostics_collection.publishDiagnostics(); -} - pub const UriFromImportStringResult = union(enum) { none, one: Uri, diff --git a/src/Server.zig b/src/Server.zig index b7d48eb2b..94e87e9de 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -1028,13 +1028,6 @@ pub fn resolveConfiguration(server: *Server) error{ Canceled, OutOfMemory }!void server.document_store.invalidateBuildFile(build_file_uri); } } - - if (new_zig_exe_path or new_zig_lib_path) { - for (server.document_store.cimports.values()) |*cimport| { - cimport.deinit(server.document_store.allocator); - } - server.document_store.cimports.clearAndFree(server.document_store.allocator); - } } if (server.status == .initialized and diff --git a/src/analysis.zig b/src/analysis.zig index 1c3d9535d..a9c52128b 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -1751,9 +1751,6 @@ fn resolveCallsiteReferences(analyser: *Analyser, decl_handle: DeclWithHandle) E }; const tree = &decl_handle.handle.tree; - const is_cimport = std.mem.eql(u8, std.Io.Dir.path.basename(decl_handle.handle.uri.raw), "cimport.zig"); - - if (is_cimport or !analyser.collect_callsite_references) return null; // protection against recursive callsite resolution const gop_resolved = try analyser.resolved_callsites.getOrPut(analyser.gpa, pay); @@ -2405,17 +2402,6 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error if (try analyser.resolveImportString(analyser.root_handle orelse return null, import_string)) |ty| return ty; return null; }, - .c_import => { - if (!DocumentStore.supports_build_system) return null; - const cimport_uri = (try analyser.store.resolveCImport(handle, node)) orelse return null; - - const new_handle = try analyser.store.getOrLoadHandle(cimport_uri) orelse return null; - - return .{ - .data = .{ .container = .root(new_handle) }, - .is_type_val = true, - }; - }, .FieldType => { if (params.len < 2) return null; @@ -5213,7 +5199,6 @@ pub fn getFieldAccessType( pub const PositionContext = union(enum) { builtin: offsets.Loc, import_string_literal: offsets.Loc, - cinclude_string_literal: offsets.Loc, embedfile_string_literal: offsets.Loc, string_literal: offsets.Loc, field_access: offsets.Loc, @@ -5242,7 +5227,6 @@ pub const PositionContext = union(enum) { return switch (self) { .builtin, .import_string_literal, - .cinclude_string_literal, .embedfile_string_literal, .string_literal, .field_access, @@ -5266,13 +5250,11 @@ pub const PositionContext = union(enum) { /// Asserts that `self` is one of the following: /// - `.import_string_literal` - /// - `.cinclude_string_literal` /// - `.embedfile_string_literal` /// - `.string_literal` pub fn stringLiteralContentLoc(self: PositionContext, source: []const u8) offsets.Loc { var location = switch (self) { .import_string_literal, - .cinclude_string_literal, .embedfile_string_literal, .string_literal, => |l| l, @@ -5500,8 +5482,6 @@ pub fn getPositionContext( const builtin_name = tree.source[loc.start..loc.end]; if (std.mem.eql(u8, builtin_name, "@import")) { new_state = .{ .import_string_literal = tok.loc }; - } else if (std.mem.eql(u8, builtin_name, "@cInclude")) { - new_state = .{ .cinclude_string_literal = tok.loc }; } else if (std.mem.eql(u8, builtin_name, "@embedFile")) { new_state = .{ .embedfile_string_literal = tok.loc }; } diff --git a/src/build_runner/build_runner.zig b/src/build_runner/build_runner.zig index d5e28a04f..93e606e06 100644 --- a/src/build_runner/build_runner.zig +++ b/src/build_runner/build_runner.zig @@ -282,8 +282,6 @@ pub fn main(init: process.Init.Minimal) !void { builder.verbose_llvm_ir = arg["--verbose-llvm-ir=".len..]; } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) { builder.verbose_llvm_bc = arg["--verbose-llvm-bc=".len..]; - } else if (mem.eql(u8, arg, "--verbose-cimport")) { - builder.verbose_cimport = true; } else if (mem.eql(u8, arg, "--verbose-cc")) { builder.verbose_cc = true; } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { diff --git a/src/features/completions.zig b/src/features/completions.zig index 09b6a5779..501031dea 100644 --- a/src/features/completions.zig +++ b/src/features/completions.zig @@ -217,19 +217,6 @@ fn typeToCompletion(builder: *Builder, ty: Analyser.Type) Analyser.Error!void { fn declToCompletion(builder: *Builder, decl_handle: Analyser.DeclWithHandle) Analyser.Error!void { const name = decl_handle.handle.tree.tokenSlice(decl_handle.nameToken()); - const is_cimport = std.mem.eql(u8, std.Io.Dir.path.basename(decl_handle.handle.uri.raw), "cimport.zig"); - if (is_cimport) { - if (std.mem.startsWith(u8, name, "_")) return; - const exclusions: std.StaticStringMap(void) = .initComptime(.{ - .{ "linux", {} }, - .{ "unix", {} }, - .{ "WIN32", {} }, - .{ "WINNT", {} }, - .{ "WIN64", {} }, - }); - if (exclusions.has(name)) return; - } - var doc_comments_buffer: [2][]const u8 = undefined; var doc_comments: std.ArrayList([]const u8) = .initBuffer(&doc_comments_buffer); if (try decl_handle.docComments(builder.arena)) |docs| { @@ -875,7 +862,6 @@ fn collectErrorSetNames( /// Asserts that `pos_context` is one of the following: /// - `.import_string_literal` -/// - `.cinclude_string_literal` /// - `.embedfile_string_literal` /// - `.string_literal` fn completeFileSystemStringLiteral(builder: *Builder, pos_context: Analyser.PositionContext) Analyser.Error!void { @@ -986,15 +972,6 @@ fn completeFileSystemStringLiteral(builder: *Builder, pos_context: Analyser.Posi var search_paths: std.ArrayList([]const u8) = .empty; if (std.Io.Dir.path.isAbsolute(completing) and pos_context != .import_string_literal) { try search_paths.append(builder.arena, completing); - } else if (pos_context == .cinclude_string_literal) { - if (!DocumentStore.supports_build_system) return; - _ = store.collectIncludeDirs(builder.arena, builder.orig_handle, &search_paths) catch |err| switch (err) { - error.Canceled => return error.Canceled, - else => { - log.err("failed to resolve include paths: {}", .{err}); - return; - }, - }; } else blk: { const document_path = builder.orig_handle.uri.toFsPath(builder.arena) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, @@ -1018,7 +995,6 @@ fn completeFileSystemStringLiteral(builder: *Builder, pos_context: Analyser.Posi const entry = opt_entry orelse break; const expected_extension = switch (pos_context) { .import_string_literal => ".zig", - .cinclude_string_literal => ".h", .embedfile_string_literal => null, .string_literal => null, else => unreachable, @@ -1046,7 +1022,6 @@ fn completeFileSystemStringLiteral(builder: *Builder, pos_context: Analyser.Posi try builder.completions.append(builder.arena, .{ .label = label, .kind = if (entry.kind == .file) .File else .Folder, - .detail = if (pos_context == .cinclude_string_literal) path else null, .textEdit = createTextEdit(builder, .{ .newText = insert_text, .insert = insert_range, .replace = replace_range }), .sortText = try generateSortText(builder.arena, score, label), }); @@ -1094,7 +1069,6 @@ pub fn completionAtIndex( .error_access => |loc| try completeError(&builder, loc), .label_access, .label_decl => try completeLabel(&builder), .import_string_literal, - .cinclude_string_literal, .embedfile_string_literal, .string_literal, => try completeFileSystemStringLiteral(&builder, pos_context), diff --git a/src/features/goto.zig b/src/features/goto.zig index 953aa594f..4627415e2 100644 --- a/src/features/goto.zig +++ b/src/features/goto.zig @@ -165,30 +165,7 @@ fn gotoDefinitionBuiltin( const tree = &handle.tree; const name_loc = offsets.tokenIndexToLoc(tree.source, loc.start); const name = offsets.locToSlice(tree.source, name_loc); - if (std.mem.eql(u8, name, "@cImport")) { - if (!DocumentStore.supports_build_system) return null; - - const index = for (handle.cimports.items(.node), 0..) |cimport_node, index| { - const main_token = tree.nodeMainToken(cimport_node); - if (loc.start == tree.tokenStart(main_token)) break index; - } else return null; - const hash = handle.cimports.items(.hash)[index]; - - const result = analyser.store.cimports.get(hash) orelse return null; - const target_range: types.Range = .{ - .start = .{ .line = 0, .character = 0 }, - .end = .{ .line = 0, .character = 0 }, - }; - switch (result) { - .failure => return null, - .success => |uri| return .{ - .originSelectionRange = offsets.locToRange(tree.source, name_loc, offset_encoding), - .targetUri = uri.raw, - .targetRange = target_range, - .targetSelectionRange = target_range, - }, - } - } else if (std.mem.eql(u8, name, "@This")) { + if (std.mem.eql(u8, name, "@This")) { const ty = try analyser.innermostContainer(handle, name_loc.start); const definition = ty.typeDefinitionToken() orelse return null; const token_loc = offsets.tokenToLoc(tree, definition.token); @@ -243,8 +220,6 @@ fn gotoDefinitionString( const tracy_zone = tracy.trace(@src()); defer tracy_zone.end(); - const io = document_store.io; - const loc = pos_context.stringLiteralContentLoc(handle.tree.source); if (loc.start == loc.end) return null; const import_str = offsets.locToSlice(handle.tree.source, loc); @@ -253,25 +228,6 @@ fn gotoDefinitionString( .import_string_literal, .embedfile_string_literal, => try document_store.uriFromImportStr(arena, handle, import_str), - .cinclude_string_literal => blk: { - if (!DocumentStore.supports_build_system) return null; - - if (std.Io.Dir.path.isAbsolute(import_str)) { - break :blk .{ .one = try .fromPath(arena, import_str) }; - } - - var include_dirs: std.ArrayList([]const u8) = .empty; - _ = try document_store.collectIncludeDirs(arena, handle, &include_dirs); - for (include_dirs.items) |dir| { - const path = try std.Io.Dir.path.join(arena, &.{ dir, import_str }); - std.Io.Dir.accessAbsolute(io, path, .{}) catch |err| switch (err) { - error.Canceled => return error.Canceled, - else => {}, - }; - break :blk .{ .one = try .fromPath(arena, path) }; - } - return null; - }, else => unreachable, }; @@ -339,7 +295,6 @@ pub fn gotoHandler( } }, .import_string_literal, - .cinclude_string_literal, .embedfile_string_literal, => { const links = try gotoDefinitionString(&server.document_store, arena, pos_context, handle, server.offset_encoding) orelse return null; diff --git a/src/features/hover.zig b/src/features/hover.zig index 19f512641..7e27beaf1 100644 --- a/src/features/hover.zig +++ b/src/features/hover.zig @@ -213,7 +213,6 @@ fn hoverDefinitionBuiltin( analyser: *Analyser, arena: std.mem.Allocator, handle: *DocumentStore.Handle, - pos_index: usize, name_loc: offsets.Loc, markup_kind: types.MarkupKind, offset_encoding: offsets.Encoding, @@ -226,33 +225,6 @@ fn hoverDefinitionBuiltin( var contents: std.ArrayList(u8) = .empty; - if (std.mem.eql(u8, name, "@cImport")) blk: { - const index = for (handle.cimports.items(.node), 0..) |cimport_node, index| { - const main_token = handle.tree.nodeMainToken(cimport_node); - const cimport_loc = offsets.tokenToLoc(&handle.tree, main_token); - if (cimport_loc.start <= pos_index and pos_index <= cimport_loc.end) break index; - } else break :blk; - - const source = handle.cimports.items(.source)[index]; - - switch (markup_kind) { - .plaintext, .unknown_value => { - try contents.print(arena, - \\{s} - \\ - , .{source}); - }, - .markdown => { - try contents.print(arena, - \\```c - \\{s} - \\``` - \\ - , .{source}); - }, - } - } - const builtin = data.builtins.get(name) orelse return null; const signature = try Analyser.renderBuiltinFunctionSignature( arena, @@ -523,7 +495,7 @@ pub fn hover( const pos_context = try Analyser.getPositionContext(arena, &handle.tree, source_index, true); const response = switch (pos_context) { - .builtin => |loc| try hoverDefinitionBuiltin(analyser, arena, handle, source_index, loc, markup_kind, offset_encoding), + .builtin => |loc| try hoverDefinitionBuiltin(analyser, arena, handle, loc, markup_kind, offset_encoding), .var_access, .test_doctest_name => try hoverDefinitionGlobal(analyser, arena, handle, source_index, markup_kind, offset_encoding), .field_access => |loc| try hoverDefinitionFieldAccess(analyser, arena, handle, source_index, loc, markup_kind, offset_encoding), .label_access, .label_decl => |loc| try hoverDefinitionLabel(analyser, arena, handle, source_index, loc, markup_kind, offset_encoding), diff --git a/src/features/inlay_hints.zig b/src/features/inlay_hints.zig index 9ffef22bd..02bc4c2fd 100644 --- a/src/features/inlay_hints.zig +++ b/src/features/inlay_hints.zig @@ -38,9 +38,6 @@ const excluded_builtins_set: std.EnumArray(std.zig.BuiltinFn.Tag, bool) = .init( .bit_reverse = true, .offset_of = false, .call = false, - .c_define = true, - .c_import = true, - .c_include = true, .clz = true, .cmpxchg_strong = false, .cmpxchg_weak = false, @@ -48,7 +45,6 @@ const excluded_builtins_set: std.EnumArray(std.zig.BuiltinFn.Tag, bool) = .init( .compile_log = true, // variadic .const_cast = true, .ctz = true, - .c_undef = true, .c_va_arg = false, .c_va_copy = false, .c_va_end = false, diff --git a/src/tools/langref.html.in b/src/tools/langref.html.in index 6f11bc006..2020d248c 100644 --- a/src/tools/langref.html.in +++ b/src/tools/langref.html.in @@ -1032,9 +1032,8 @@ {#header_close#} {#header_open|Local Variables#} -
- Local variables occur inside {#link|Functions#}, {#link|comptime#} blocks, and {#link|@cImport#} blocks. -
+Local variables occur inside {#link|Functions#}, {#link|comptime#} + blocks, and labeled {#link|Blocks#}.
When a local variable is {#syntax#}const{#endsyntax#}, it means that after initialization, the variable's value will not change. If the initialization value of a {#syntax#}const{#endsyntax#} variable is @@ -4573,62 +4572,6 @@ comptime { {#header_close#} - {#header_open|@cDefine#} -
{#syntax#}@cDefine(comptime name: []const u8, value) void{#endsyntax#}
- - This function can only occur inside {#syntax#}@cImport{#endsyntax#}. -
-
- This appends #define $name $value to the {#syntax#}@cImport{#endsyntax#}
- temporary buffer.
-
- To define without a value, like this: -
-#define _GNU_SOURCE
- - Use the void value, like this: -
-{#syntax#}@cDefine("_GNU_SOURCE", {}){#endsyntax#}
- {#see_also|Import from C Header File|@cInclude|@cImport|@cUndef|void#}
- {#header_close#}
- {#header_open|@cImport#}
- {#syntax#}@cImport(expression) type{#endsyntax#}
- - This function parses C code and imports the functions, types, variables, - and compatible macro definitions into a new empty struct type, and then - returns that type. -
-- {#syntax#}expression{#endsyntax#} is interpreted at compile time. The builtin functions - {#syntax#}@cInclude{#endsyntax#}, {#syntax#}@cDefine{#endsyntax#}, and {#syntax#}@cUndef{#endsyntax#} work - within this expression, appending to a temporary buffer which is then parsed as C code. -
-- Usually you should only have one {#syntax#}@cImport{#endsyntax#} in your entire application, because it saves the compiler - from invoking clang multiple times, and prevents inline functions from being duplicated. -
-- Reasons for having multiple {#syntax#}@cImport{#endsyntax#} expressions would be: -
-#define CONNECTION_COUNT{#syntax#}@cInclude(comptime path: []const u8) void{#endsyntax#}
- - This function can only occur inside {#syntax#}@cImport{#endsyntax#}. -
-
- This appends #include <$path>\n to the {#syntax#}c_import{#endsyntax#}
- temporary buffer.
-
{#syntax#}@clz(operand: anytype) anytype{#endsyntax#}
{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.
@@ -4758,18 +4701,6 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val {#see_also|@clz|@popCount#} {#header_close#} - {#header_open|@cUndef#} -{#syntax#}@cUndef(comptime name: []const u8) void{#endsyntax#}
- - This function can only occur inside {#syntax#}@cImport{#endsyntax#}. -
-
- This appends #undef $name to the {#syntax#}@cImport{#endsyntax#}
- temporary buffer.
-
{#syntax#}@cVaArg(operand: *std.builtin.VaList, comptime T: type) T{#endsyntax#}
@@ -6784,35 +6715,6 @@ const builtin = @import("builtin");
{#see_also|Primitive Types#} {#header_close#} - {#header_open|Import from C Header File#} -
- The {#syntax#}@cImport{#endsyntax#} builtin function can be used
- to directly import symbols from .h files:
-
- The {#syntax#}@cImport{#endsyntax#} function takes an expression as a parameter.
- This expression is evaluated at compile-time and is used to control
- preprocessor directives and include multiple .h files:
-
@@ -6872,42 +6774,8 @@ $ zig translate-c -cflags -fshort-enums -- varycflags.h|grep -B1 do_something pub const enum_FOO = u8; pub extern fn do_something(foo: enum_FOO) c_int;{#end_shell_samp#} {#header_close#} - {#header_open|@cImport vs translate-c#} -
{#syntax#}@cImport{#endsyntax#} and zig translate-c use the same underlying - C translation functionality, so on a technical level they are equivalent. In practice, - {#syntax#}@cImport{#endsyntax#} is useful as a way to quickly and easily access numeric constants, typedefs, - and record types without needing any extra setup. If you need to pass {#link|cflags|Using -target and -cflags#} - to clang, or if you would like to edit the translated code, it is recommended to use - zig translate-c and save the results to a file. Common reasons for editing - the generated code include: changing {#syntax#}anytype{#endsyntax#} parameters in function-like macros to more - specific types; changing {#syntax#}[*c]T{#endsyntax#} pointers to {#syntax#}[*]T{#endsyntax#} or - {#syntax#}*T{#endsyntax#} pointers for improved type safety; and - {#link|enabling or disabling runtime safety|@setRuntimeSafety#} within specific functions. -
- {#header_close#} - {#see_also|Targets|C Type Primitives|Pointers|C Pointers|Import from C Header File|@cInclude|@cImport|@setRuntimeSafety#} {#header_close#} - {#header_open|C Translation Caching#} -- The C translation feature (whether used via zig translate-c or - {#syntax#}@cImport{#endsyntax#}) integrates with the Zig caching system. Subsequent runs with - the same source file, target, and cflags will use the cache instead of repeatedly translating - the same code. -
-- To see where the cached files are stored when compiling code that uses {#syntax#}@cImport{#endsyntax#}, - use the --verbose-cimport flag: -
- {#code|verbose_cimport_flag.zig#} -
- cimport.h contains the file to translate (constructed from calls to
- {#syntax#}@cInclude{#endsyntax#}, {#syntax#}@cDefine{#endsyntax#}, and {#syntax#}@cUndef{#endsyntax#}),
- cimport.h.d is the list of file dependencies, and
- cimport.zig contains the translated output.
-
Some C constructs cannot be translated to Zig - for example, goto, @@ -6933,35 +6801,6 @@ pub extern fn do_something(foo: enum_FOO) c_int;{#end_shell_samp#}
{#see_also|opaque|extern|@compileError#} {#header_close#} - {#header_open|C Macros#} -- C Translation makes a best-effort attempt to translate function-like macros into equivalent - Zig functions. Since C macros operate at the level of lexical tokens, not all C macros - can be translated to Zig. Macros that cannot be translated will be demoted to - {#syntax#}@compileError{#endsyntax#}. Note that C code which uses macros will be - translated without any additional issues (since Zig operates on the pre-processed source - with macros expanded). It is merely the macros themselves which may not be translatable to - Zig. -
-Consider the following example:
- {#syntax_block|c|macro.c#} -#define MAKELOCAL(NAME, INIT) int NAME = INIT -int foo(void) { - MAKELOCAL(a, 1); - MAKELOCAL(b, 2); - return a + b; -} - {#end_syntax_block#} - {#shell_samp#}$ zig translate-c macro.c > macro.zig{#end_shell_samp#} - {#code|macro.zig#} - -Note that {#syntax#}foo{#endsyntax#} was translated correctly despite using a non-translatable - macro. {#syntax#}MAKELOCAL{#endsyntax#} was demoted to {#syntax#}@compileError{#endsyntax#} since - it cannot be expressed as a Zig function; this simply means that you cannot directly use - {#syntax#}MAKELOCAL{#endsyntax#} from Zig. -
- {#see_also|@compileError#} - {#header_close#} {#header_open|C Pointers#}
diff --git a/src/translate_c.zig b/src/translate_c.zig
deleted file mode 100644
index a4f8fd783..000000000
--- a/src/translate_c.zig
+++ /dev/null
@@ -1,301 +0,0 @@
-//! Implementation of the `translate-c` i.e `@cImport`.
-
-const std = @import("std");
-const zig_builtin = @import("builtin");
-const DocumentStore = @import("DocumentStore.zig");
-const ast = @import("ast.zig");
-const tracy = @import("tracy");
-const Ast = std.zig.Ast;
-const Uri = @import("Uri.zig");
-const log = std.log.scoped(.translate_c);
-
-const OutMessage = std.zig.Client.Message;
-const InMessage = std.zig.Server.Message;
-
-/// converts a `@cInclude` node into an equivalent c header file
-/// which can then be handed over to `zig translate-c`
-/// Caller owns returned memory.
-///
-/// **Example**
-/// ```zig
-/// const glfw = @cImport({
-/// @cDefine("GLFW_INCLUDE_VULKAN", {});
-/// @cInclude("GLFW/glfw3.h");
-/// });
-/// ```
-/// gets converted into:
-/// ```c
-/// #define GLFW_INCLUDE_VULKAN
-/// #include "GLFW/glfw3.h"
-/// ```
-pub fn convertCInclude(allocator: std.mem.Allocator, tree: *const Ast, node: Ast.Node.Index) error{ OutOfMemory, Unsupported }![]const u8 {
- const tracy_zone = tracy.trace(@src());
- defer tracy_zone.end();
-
- std.debug.assert(ast.isBuiltinCall(tree, node));
- std.debug.assert(std.mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(node)), "@cImport"));
-
- var output: std.ArrayList(u8) = .empty;
- errdefer output.deinit(allocator);
-
- var buffer: [2]Ast.Node.Index = undefined;
- for (tree.builtinCallParams(&buffer, node).?) |child| {
- try convertCIncludeInternal(allocator, tree, child, &output);
- }
-
- return output.toOwnedSlice(allocator);
-}
-
-fn convertCIncludeInternal(
- allocator: std.mem.Allocator,
- tree: *const Ast,
- node: Ast.Node.Index,
- output: *std.ArrayList(u8),
-) error{ OutOfMemory, Unsupported }!void {
- var buffer: [2]Ast.Node.Index = undefined;
- if (tree.blockStatements(&buffer, node)) |statements| {
- for (statements) |statement| {
- try convertCIncludeInternal(allocator, tree, statement, output);
- }
- } else if (tree.builtinCallParams(&buffer, node)) |params| {
- if (params.len < 1) return;
-
- const call_name = tree.tokenSlice(tree.nodeMainToken(node));
-
- if (tree.nodeTag(params[0]) != .string_literal) return error.Unsupported;
- const first = extractString(tree.tokenSlice(tree.nodeMainToken(params[0])));
-
- if (std.mem.eql(u8, call_name, "@cInclude")) {
- try output.print(allocator, "#include <{s}>\n", .{first});
- } else if (std.mem.eql(u8, call_name, "@cDefine")) {
- if (params.len < 2) return;
-
- var buffer2: [2]Ast.Node.Index = undefined;
- const is_void = if (tree.blockStatements(&buffer2, params[1])) |block| block.len == 0 else false;
-
- if (is_void) {
- try output.print(allocator, "#define {s}\n", .{first});
- } else {
- if (tree.nodeTag(params[1]) != .string_literal) return error.Unsupported;
- const second = extractString(tree.tokenSlice(tree.nodeMainToken(params[1])));
- try output.print(allocator, "#define {s} {s}\n", .{ first, second });
- }
- } else if (std.mem.eql(u8, call_name, "@cUndef")) {
- try output.print(allocator, "#undef {s}\n", .{first});
- } else {
- return error.Unsupported;
- }
- }
-}
-
-pub const Result = union(enum) {
- // uri to the generated zig file
- success: Uri,
- // zig translate-c failed with the given error messages
- failure: std.zig.ErrorBundle,
-
- pub fn deinit(self: *Result, allocator: std.mem.Allocator) void {
- switch (self.*) {
- .success => |uri| uri.deinit(allocator),
- .failure => |*bundle| bundle.deinit(allocator),
- }
- }
-};
-
-/// takes a c header file and returns the result from calling `zig translate-c`
-/// returns a Uri to the generated zig file on success or the content of stderr on failure
-/// null indicates a failure which is automatically logged
-/// Caller owns returned memory.
-pub fn translate(
- io: std.Io,
- allocator: std.mem.Allocator,
- config: DocumentStore.Config,
- include_dirs: []const []const u8,
- c_macros: []const []const u8,
- source: []const u8,
-) !?Result {
- const tracy_zone = tracy.trace(@src());
- defer tracy_zone.end();
-
- const zig_exe_path = config.zig_exe_path.?;
- const zig_lib_dir = config.zig_lib_dir.?;
- const global_cache_dir = config.global_cache_dir.?;
-
- var random_bytes: [16]u8 = undefined;
- io.random(&random_bytes);
- var sub_path: [std.base64.url_safe.Encoder.calcSize(16)]u8 = undefined;
- _ = std.base64.url_safe.Encoder.encode(&sub_path, &random_bytes);
-
- var sub_dir = try global_cache_dir.handle.createDirPathOpen(io, &sub_path, .{});
- defer sub_dir.close(io);
-
- sub_dir.writeFile(io, .{
- .sub_path = "cimport.h",
- .data = source,
- }) catch |err| switch (err) {
- error.Canceled => return error.Canceled,
- else => {
- log.warn("failed to write to '{s}/{s}/cimport.h': {}", .{ global_cache_dir.path orelse ".", sub_path, err });
- return null;
- },
- };
-
- defer global_cache_dir.handle.deleteTree(io, &sub_path) catch |err| {
- log.warn("failed to delete '{s}/{s}': {}", .{ global_cache_dir.path orelse ".", sub_path, err });
- };
-
- const file_path = try std.Io.Dir.path.join(allocator, &.{ global_cache_dir.path orelse ".", &sub_path, "cimport.h" });
- defer allocator.free(file_path);
-
- const base_args = &[_][]const u8{
- zig_exe_path,
- "translate-c",
- "--zig-lib-dir",
- zig_lib_dir.path orelse ".",
- "--cache-dir",
- global_cache_dir.path orelse ".",
- "--global-cache-dir",
- global_cache_dir.path orelse ".",
- "-lc",
- "--listen=-",
- };
-
- const argc = base_args.len + 2 * include_dirs.len + c_macros.len + 1;
- var argv: std.ArrayList([]const u8) = try .initCapacity(allocator, argc);
- defer argv.deinit(allocator);
-
- argv.appendSliceAssumeCapacity(base_args);
-
- for (include_dirs) |include_dir| {
- argv.appendAssumeCapacity("-I");
- argv.appendAssumeCapacity(include_dir);
- }
-
- argv.appendSliceAssumeCapacity(c_macros);
-
- argv.appendAssumeCapacity(file_path);
-
- var process = std.process.spawn(io, .{
- .argv = argv.items,
- .stdin = .pipe,
- .stdout = .pipe,
- .stderr = .pipe,
- }) catch |err| switch (err) {
- error.Canceled => return error.Canceled,
- else => {
- log.err("failed to spawn zig translate-c process, error: {}", .{err});
- return null;
- },
- };
- defer process.kill(io);
-
- {
- var stdin_writer = process.stdin.?.writer(io, &.{});
- const writer = &stdin_writer.interface;
-
- writer.writeStruct(OutMessage.Header{
- .tag = .update,
- .bytes_len = 0,
- }, .little) catch return @as(std.Io.File.Writer.Error!?Result, stdin_writer.err.?);
-
- writer.writeStruct(OutMessage.Header{
- .tag = .exit,
- .bytes_len = 0,
- }, .little) catch return @as(std.Io.File.Writer.Error!?Result, stdin_writer.err.?);
- }
-
- var multi_reader_buffer: std.Io.File.MultiReader.Buffer(2) = undefined;
- var multi_reader: std.Io.File.MultiReader = undefined;
- defer multi_reader.deinit();
- multi_reader.init(
- allocator,
- io,
- multi_reader_buffer.toStreams(),
- &.{ process.stdout.?, process.stderr.? },
- );
-
- const stdout = multi_reader.reader(0);
- const stderr = multi_reader.reader(1);
-
- outer: while (true) {
- const timeout: std.Io.Timeout = .{ .duration = .{ .clock = .awake, .raw = .fromSeconds(90) } };
-
- while (stdout.buffered().len < @sizeOf(InMessage.Header)) {
- multi_reader.fill(64, timeout) catch |err| switch (err) {
- error.EndOfStream => break :outer,
- else => |e| return e,
- };
- }
- const header = stdout.takeStruct(InMessage.Header, .little) catch unreachable;
- while (stdout.buffered().len < header.bytes_len) {
- multi_reader.fill(64, timeout) catch |err| switch (err) {
- error.EndOfStream => break :outer,
- else => |e| return e,
- };
- }
- try multi_reader.checkAnyError();
-
- const body = stdout.take(header.bytes_len) catch unreachable;
- var reader: std.Io.Reader = .fixed(body);
-
- // log.debug("received header: {}", .{header});
-
- switch (header.tag) {
- .zig_version => {
- // log.debug("zig-version: {s}", .{body});
- },
- .emit_digest => {
- _ = reader.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch return error.InvalidMessage;
- const bin_result_path = reader.takeArray(16) catch return error.InvalidMessage;
- if (reader.bufferedLen() != 0) return error.InvalidMessage; // ensure that we read the entire body
-
- const hex_result_path = std.Build.Cache.binToHex(bin_result_path.*);
- const result_path = try global_cache_dir.join(allocator, &.{ "o", &hex_result_path, "cimport.zig" });
- defer allocator.free(result_path);
-
- return .{ .success = try .fromPath(allocator, std.mem.sliceTo(result_path, '\n')) };
- },
- .error_bundle => {
- const error_bundle_header = reader.takeStruct(InMessage.ErrorBundle, .little) catch return error.InvalidMessage;
-
- const extra = reader.readSliceEndianAlloc(allocator, u32, error_bundle_header.extra_len, .little) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- error.EndOfStream => return error.InvalidMessage,
- error.ReadFailed => unreachable,
- };
- errdefer allocator.free(extra);
-
- const string_bytes = reader.readAlloc(allocator, error_bundle_header.string_bytes_len) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- error.EndOfStream => return error.InvalidMessage,
- error.ReadFailed => unreachable,
- };
- errdefer allocator.free(string_bytes);
-
- if (reader.bufferedLen() != 0) return error.InvalidMessage; // ensure that we read the entire body
-
- const error_bundle: std.zig.ErrorBundle = .{ .string_bytes = string_bytes, .extra = extra };
-
- return .{ .failure = error_bundle };
- },
- else => {},
- }
- }
-
- const term = try process.wait(io);
- switch (term) {
- .exited => |code| std.log.err("zig translate-c failed with code {d} and stderr:\n{s}", .{ code, stderr.buffered() }),
- .signal => |sig| std.log.err("zig translate-c failed with signal {t} and stderr:\n{s}", .{ sig, stderr.buffered() }),
- .stopped => |sig| std.log.err("zig translate-c stopped with signal {d} and stderr:\n{s}", .{ sig, stderr.buffered() }),
- .unknown => |code| std.log.err("zig translate-c failed for unknown reason with code {d} and stderr:\n{s}", .{ code, stderr.buffered() }),
- }
- return null;
-}
-
-fn extractString(str: []const u8) []const u8 {
- if (std.mem.startsWith(u8, str, "\"") and std.mem.endsWith(u8, str, "\"")) {
- return str[1 .. str.len - 1];
- } else {
- return str;
- }
-}
diff --git a/src/zls.zig b/src/zls.zig
index 7f244c28d..485a1e714 100644
--- a/src/zls.zig
+++ b/src/zls.zig
@@ -17,7 +17,6 @@ pub const print_ast = @import("print_ast.zig");
pub const Server = @import("Server.zig");
pub const snippets = @import("snippets.zig");
pub const testing = @import("testing.zig");
-pub const translate_c = @import("translate_c.zig");
pub const TrigramStore = @import("TrigramStore.zig");
pub const Uri = @import("Uri.zig");
diff --git a/tests/language_features/cimport.zig b/tests/language_features/cimport.zig
deleted file mode 100644
index bd9f0aaec..000000000
--- a/tests/language_features/cimport.zig
+++ /dev/null
@@ -1,135 +0,0 @@
-const std = @import("std");
-const zls = @import("zls");
-
-const Ast = std.zig.Ast;
-
-const Context = @import("../context.zig").Context;
-
-const offsets = zls.offsets;
-const translate_c = zls.translate_c;
-
-const io = std.testing.io;
-const allocator: std.mem.Allocator = std.testing.allocator;
-
-test "zig compile server - translate c" {
- var result1 = try testTranslate(
- \\void foo(int);
- \\void bar(float*);
- );
- defer result1.deinit(allocator);
- try std.testing.expect(result1 == .success);
-
- var result2 = try testTranslate(
- \\#include