@@ -160,6 +160,90 @@ impl Backend {
160160 return Some ( location) ;
161161 }
162162
163+ // 8. Try standalone constant lookup (define() constants).
164+ if let Some ( location) = self . resolve_constant_definition ( & func_candidates) {
165+ return Some ( location) ;
166+ }
167+
168+ None
169+ }
170+
171+ // ─── Constant Definition Resolution ─────────────────────────────────────
172+
173+ /// Resolve a standalone constant to its `define('NAME', …)` call site.
174+ ///
175+ /// Checks `global_defines` (user-defined constants discovered from parsed
176+ /// files) for a matching constant name, reads the source file, and returns
177+ /// a `Location` pointing at the `define(` call. Built-in constants from
178+ /// `stub_constant_index` are not navigable (they have no real file).
179+ fn resolve_constant_definition ( & self , candidates : & [ String ] ) -> Option < Location > {
180+ // Look up the constant in global_defines.
181+ let file_uri = {
182+ let dmap = self . global_defines . lock ( ) . ok ( ) ?;
183+ let mut result = None ;
184+ for candidate in candidates {
185+ if let Some ( uri) = dmap. get ( candidate. as_str ( ) ) {
186+ result = Some ( ( candidate. clone ( ) , uri. clone ( ) ) ) ;
187+ break ;
188+ }
189+ }
190+ result
191+ } ;
192+
193+ let ( const_name, file_uri) = file_uri?;
194+
195+ // Read the file content (try open files first, then disk).
196+ let file_content = self
197+ . open_files
198+ . lock ( )
199+ . ok ( )
200+ . and_then ( |files| files. get ( & file_uri) . cloned ( ) )
201+ . or_else ( || {
202+ let path = Url :: parse ( & file_uri) . ok ( ) ?. to_file_path ( ) . ok ( ) ?;
203+ std:: fs:: read_to_string ( path) . ok ( )
204+ } ) ?;
205+
206+ let position = Self :: find_define_position ( & file_content, & const_name) ?;
207+ let parsed_uri = Url :: parse ( & file_uri) . ok ( ) ?;
208+
209+ Some ( Location {
210+ uri : parsed_uri,
211+ range : Range {
212+ start : position,
213+ end : position,
214+ } ,
215+ } )
216+ }
217+
218+ /// Find the position of a `define('NAME'` or `define("NAME"` call in
219+ /// file content.
220+ ///
221+ /// Searches each line for a `define(` keyword followed (possibly with
222+ /// whitespace) by a string literal containing the constant name.
223+ /// Returns the position of the `define` keyword on the matching line.
224+ fn find_define_position ( content : & str , constant_name : & str ) -> Option < Position > {
225+ // Patterns: `'NAME'` and `"NAME"` — we search for these after
226+ // the `define(` token, allowing optional whitespace.
227+ let single_q = format ! ( "'{}'" , constant_name) ;
228+ let double_q = format ! ( "\" {}\" " , constant_name) ;
229+
230+ for ( line_idx, line) in content. lines ( ) . enumerate ( ) {
231+ // Find `define(` anywhere on the line.
232+ let Some ( def_pos) = line. find ( "define(" ) else {
233+ continue ;
234+ } ;
235+
236+ // Extract the text after `define(` and trim leading whitespace
237+ // to allow `define( 'NAME'` with spaces.
238+ let after_paren = line[ def_pos + 7 ..] . trim_start ( ) ;
239+ if after_paren. starts_with ( & single_q) || after_paren. starts_with ( & double_q) {
240+ return Some ( Position {
241+ line : line_idx as u32 ,
242+ character : def_pos as u32 ,
243+ } ) ;
244+ }
245+ }
246+
163247 None
164248 }
165249
0 commit comments