@@ -763,11 +763,21 @@ pub fn getBuildFile(self: *DocumentStore, uri: Uri) ?*BuildFile {
763763/// invalidates any pointers into `DocumentStore.build_files`
764764/// **Thread safe** takes an exclusive lock
765765/// This function does not protect against data races from modifying the BuildFile
766- fn getOrLoadBuildFile (self : * DocumentStore , uri : Uri ) error { Canceled , OutOfMemory }! * BuildFile {
766+ fn getOrLoadBuildFile (
767+ self : * DocumentStore ,
768+ uri : Uri ,
769+ source_handle : ? * const Handle ,
770+ ) error { Canceled , OutOfMemory }! ? * BuildFile {
767771 comptime std .debug .assert (supports_build_system );
768772
773+ // A filename alone is not sufficient because ordinary modules may be named `build.zig`.
774+ if (source_handle ) | handle | std .debug .assert (handle .uri .eql (uri ));
775+
769776 if (self .getBuildFile (uri )) | build_file | return build_file ;
770777
778+ const handle = source_handle orelse (try self .getOrLoadHandle (uri ) orelse return null );
779+ if (! isBuildScript (& handle .tree )) return null ;
780+
771781 const new_build_file : * BuildFile = blk : {
772782 try self .mutex .lock (self .io );
773783 defer self .mutex .unlock (self .io );
@@ -1244,6 +1254,43 @@ pub fn isBuildFile(uri: Uri) bool {
12441254 return std .mem .endsWith (u8 , uri .raw , "/build.zig" );
12451255}
12461256
1257+ /// Returns whether the parsed source exposes the entry point required by `zig build`.
1258+ pub fn isBuildScript (tree : * const Ast ) bool {
1259+ std .debug .assert (tree .mode == .zig );
1260+
1261+ for (tree .rootDecls ()) | decl | {
1262+ var buffer : [1 ]Ast.Node.Index = undefined ;
1263+ const fn_proto = tree .fullFnProto (& buffer , decl ) orelse continue ;
1264+ const visibility_token = fn_proto .visib_token orelse continue ;
1265+ const name_token = fn_proto .name_token orelse continue ;
1266+
1267+ std .debug .assert (tree .tokenTag (visibility_token ) == .keyword_pub );
1268+ std .debug .assert (tree .tokenTag (name_token ) == .identifier );
1269+ if (std .mem .eql (u8 , tree .tokenSlice (name_token ), "build" )) return true ;
1270+ }
1271+ return false ;
1272+ }
1273+
1274+ test isBuildScript {
1275+ var build_script = try Ast .parse (std .testing .allocator ,
1276+ \\const std = @import("std");
1277+ \\pub fn build(b: *std.Build) void {
1278+ \\ _ = b;
1279+ \\}
1280+ , .zig );
1281+ defer build_script .deinit (std .testing .allocator );
1282+ try std .testing .expect (isBuildScript (& build_script ));
1283+
1284+ var module = try Ast .parse (std .testing .allocator ,
1285+ \\const ParseOptions = @import("../error_handling.zig").ParseOptions;
1286+ \\pub fn parse(options: ParseOptions) void {
1287+ \\ _ = options;
1288+ \\}
1289+ , .zig );
1290+ defer module .deinit (std .testing .allocator );
1291+ try std .testing .expect (! isBuildScript (& module ));
1292+ }
1293+
12471294pub fn isBuiltinFile (uri : Uri ) bool {
12481295 return std .mem .endsWith (u8 , uri .raw , "/builtin.zig" );
12491296}
@@ -1460,7 +1507,7 @@ fn collectPotentialBuildFiles(self: *DocumentStore, uri: Uri) error{ Canceled, O
14601507 const build_file_uri : Uri = try .fromPath (self .allocator , build_path );
14611508 defer build_file_uri .deinit (self .allocator );
14621509
1463- const build_file = try self .getOrLoadBuildFile (build_file_uri ) ;
1510+ const build_file = try self .getOrLoadBuildFile (build_file_uri , null ) orelse continue ;
14641511 potential_build_files .appendAssumeCapacity (build_file );
14651512 }
14661513 // The potential build files that come first should have higher priority.
@@ -1541,18 +1588,6 @@ fn createAndStoreDocument(
15411588 .uri = > {},
15421589 };
15431590
1544- if (supports_build_system and options .lsp_synced and isBuildFile (uri ) and ! isInStd (uri )) {
1545- switch (options .load_build_file_behaviour ) {
1546- .load_but_dont_update = > {
1547- _ = try store .getOrLoadBuildFile (uri );
1548- },
1549- .only_update = > {
1550- store .invalidateBuildFile (uri );
1551- },
1552- .never = > {},
1553- }
1554- }
1555-
15561591 const handle_future : * Handle.Future = handle_future : {
15571592 try store .mutex .lock (store .io );
15581593 defer store .mutex .unlock (store .io );
@@ -1628,6 +1663,22 @@ fn createAndStoreDocument(
16281663 };
16291664 old_handle .deinit (store .allocator );
16301665
1666+ if (supports_build_system and options .lsp_synced and isBuildFile (uri ) and ! isInStd (uri ) and isBuildScript (& handle_future .handle .tree )) {
1667+ switch (options .load_build_file_behaviour ) {
1668+ .load_but_dont_update = > {
1669+ _ = try store .getOrLoadBuildFile (uri , & handle_future .handle );
1670+ },
1671+ .only_update = > {
1672+ if (store .getBuildFile (uri )) | build_file | {
1673+ store .invalidateBuildFile (build_file .uri );
1674+ } else {
1675+ _ = try store .getOrLoadBuildFile (uri , & handle_future .handle );
1676+ }
1677+ },
1678+ .never = > {},
1679+ }
1680+ }
1681+
16311682 handle_future .err = null ;
16321683 return & handle_future .handle ;
16331684}
0 commit comments