@@ -85,17 +85,20 @@ impl SyntaxRange {
85
85
#[ derive( Encodable , Decodable , Debug , Clone ) ]
86
86
crate struct CallLocation {
87
87
crate call_expr : SyntaxRange ,
88
+ crate call_ident : SyntaxRange ,
88
89
crate enclosing_item : SyntaxRange ,
89
90
}
90
91
91
92
impl CallLocation {
92
93
fn new (
93
94
expr_span : rustc_span:: Span ,
95
+ ident_span : rustc_span:: Span ,
94
96
enclosing_item_span : rustc_span:: Span ,
95
97
source_file : & SourceFile ,
96
98
) -> Self {
97
99
CallLocation {
98
100
call_expr : SyntaxRange :: new ( expr_span, source_file) ,
101
+ call_ident : SyntaxRange :: new ( ident_span, source_file) ,
99
102
enclosing_item : SyntaxRange :: new ( enclosing_item_span, source_file) ,
100
103
}
101
104
}
@@ -146,24 +149,39 @@ where
146
149
}
147
150
148
151
// Get type of function if expression is a function call
149
- let ( ty, span ) = match ex. kind {
152
+ let ( ty, call_span , ident_span ) = match ex. kind {
150
153
hir:: ExprKind :: Call ( f, _) => {
151
154
let types = tcx. typeck ( ex. hir_id . owner ) ;
152
155
153
156
if let Some ( ty) = types. node_type_opt ( f. hir_id ) {
154
- ( ty, ex. span )
157
+ ( ty, ex. span , f . span )
155
158
} else {
156
159
trace ! ( "node_type_opt({}) = None" , f. hir_id) ;
157
160
return ;
158
161
}
159
162
}
160
- hir:: ExprKind :: MethodCall ( _, _ , span ) => {
163
+ hir:: ExprKind :: MethodCall ( _, args , call_span ) => {
161
164
let types = tcx. typeck ( ex. hir_id . owner ) ;
162
165
let Some ( def_id) = types. type_dependent_def_id ( ex. hir_id ) else {
163
166
trace ! ( "type_dependent_def_id({}) = None" , ex. hir_id) ;
164
167
return ;
165
168
} ;
166
- ( tcx. type_of ( def_id) , span)
169
+
170
+ // The MethodCall node doesn't directly contain a span for the
171
+ // method identifier, so we have to compute it by trimming the full
172
+ // span based on the arguments.
173
+ let ident_span = match args. get ( 1 ) {
174
+ // If there is an argument, e.g. "f(x)", then
175
+ // get the span "f(" and delete the lparen.
176
+ Some ( arg) => {
177
+ let with_paren = call_span. until ( arg. span ) ;
178
+ with_paren. with_hi ( with_paren. hi ( ) - BytePos ( 1 ) )
179
+ }
180
+ // Otherwise, just delete both parens directly.
181
+ None => call_span. with_hi ( call_span. hi ( ) - BytePos ( 2 ) ) ,
182
+ } ;
183
+
184
+ ( tcx. type_of ( def_id) , call_span, ident_span)
167
185
}
168
186
_ => {
169
187
return ;
@@ -172,8 +190,8 @@ where
172
190
173
191
// If this span comes from a macro expansion, then the source code may not actually show
174
192
// a use of the given item, so it would be a poor example. Hence, we skip all uses in macros.
175
- if span . from_expansion ( ) {
176
- trace ! ( "Rejecting expr from macro: {:?}" , span ) ;
193
+ if call_span . from_expansion ( ) {
194
+ trace ! ( "Rejecting expr from macro: {:?}" , call_span ) ;
177
195
return ;
178
196
}
179
197
@@ -183,26 +201,29 @@ where
183
201
. hir ( )
184
202
. span_with_body ( tcx. hir ( ) . local_def_id_to_hir_id ( tcx. hir ( ) . get_parent_item ( ex. hir_id ) ) ) ;
185
203
if enclosing_item_span. from_expansion ( ) {
186
- trace ! ( "Rejecting expr ({:?}) from macro item: {:?}" , span , enclosing_item_span) ;
204
+ trace ! ( "Rejecting expr ({:?}) from macro item: {:?}" , call_span , enclosing_item_span) ;
187
205
return ;
188
206
}
189
207
190
208
assert ! (
191
- enclosing_item_span. contains( span) ,
192
- "Attempted to scrape call at [{:?}] whose enclosing item [{:?}] doesn't contain the span of the call." ,
193
- span,
194
- enclosing_item_span
209
+ enclosing_item_span. contains( call_span) ,
210
+ "Attempted to scrape call at [{call_span:?}] whose enclosing item [{enclosing_item_span:?}] doesn't contain the span of the call." ,
211
+ ) ;
212
+
213
+ assert ! (
214
+ call_span. contains( ident_span) ,
215
+ "Attempted to scrape call at [{call_span:?}] whose identifier [{ident_span:?}] was not contained in the span of the call."
195
216
) ;
196
217
197
218
// Save call site if the function resolves to a concrete definition
198
219
if let ty:: FnDef ( def_id, _) = ty. kind ( ) {
199
220
if self . target_crates . iter ( ) . all ( |krate| * krate != def_id. krate ) {
200
- trace ! ( "Rejecting expr from crate not being documented: {:?}" , span ) ;
221
+ trace ! ( "Rejecting expr from crate not being documented: {call_span :?}" ) ;
201
222
return ;
202
223
}
203
224
204
225
let source_map = tcx. sess . source_map ( ) ;
205
- let file = source_map. lookup_char_pos ( span . lo ( ) ) . file ;
226
+ let file = source_map. lookup_char_pos ( call_span . lo ( ) ) . file ;
206
227
let file_path = match file. name . clone ( ) {
207
228
FileName :: Real ( real_filename) => real_filename. into_local_path ( ) ,
208
229
_ => None ,
@@ -212,20 +233,20 @@ where
212
233
let abs_path = fs:: canonicalize ( file_path. clone ( ) ) . unwrap ( ) ;
213
234
let cx = & self . cx ;
214
235
let mk_call_data = || {
215
- let clean_span = crate :: clean:: types:: Span :: new ( span ) ;
236
+ let clean_span = crate :: clean:: types:: Span :: new ( call_span ) ;
216
237
let url = cx. href_from_span ( clean_span, false ) . unwrap ( ) ;
217
238
let display_name = file_path. display ( ) . to_string ( ) ;
218
- let edition = span . edition ( ) ;
239
+ let edition = call_span . edition ( ) ;
219
240
CallData { locations : Vec :: new ( ) , url, display_name, edition }
220
241
} ;
221
242
222
243
let fn_key = tcx. def_path_hash ( * def_id) ;
223
244
let fn_entries = self . calls . entry ( fn_key) . or_default ( ) ;
224
245
225
- trace ! ( "Including expr: {:?}" , span ) ;
246
+ trace ! ( "Including expr: {:?}" , call_span ) ;
226
247
let enclosing_item_span =
227
248
source_map. span_extend_to_prev_char ( enclosing_item_span, '\n' , false ) ;
228
- let location = CallLocation :: new ( span , enclosing_item_span, & file) ;
249
+ let location = CallLocation :: new ( call_span , ident_span , enclosing_item_span, & file) ;
229
250
fn_entries. entry ( abs_path) . or_insert_with ( mk_call_data) . locations . push ( location) ;
230
251
}
231
252
}
0 commit comments