1
1
use rustc:: hir;
2
- use rustc:: lint:: { EarlyContext , LateContext } ;
2
+ use rustc:: lint:: { EarlyContext , LateContext , LintContext } ;
3
+ use rustc_errors;
3
4
use std:: borrow:: Cow ;
5
+ use std:: fmt:: Display ;
4
6
use std;
5
- use syntax:: ast;
7
+ use syntax:: codemap:: { CharPos , Span } ;
8
+ use syntax:: print:: pprust:: binop_to_string;
6
9
use syntax:: util:: parser:: AssocOp ;
10
+ use syntax:: ast;
7
11
use utils:: { higher, snippet, snippet_opt} ;
8
- use syntax:: print:: pprust:: binop_to_string;
9
12
10
13
/// A helper type to build suggestion correctly handling parenthesis.
11
14
pub enum Sugg < ' a > {
@@ -20,7 +23,7 @@ pub enum Sugg<'a> {
20
23
/// Literal constant `1`, for convenience.
21
24
pub const ONE : Sugg < ' static > = Sugg :: NonParen ( Cow :: Borrowed ( "1" ) ) ;
22
25
23
- impl < ' a > std :: fmt :: Display for Sugg < ' a > {
26
+ impl < ' a > Display for Sugg < ' a > {
24
27
fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> Result < ( ) , std:: fmt:: Error > {
25
28
match * self {
26
29
Sugg :: NonParen ( ref s) | Sugg :: MaybeParen ( ref s) | Sugg :: BinOp ( _, ref s) => {
@@ -126,7 +129,7 @@ impl<'a> Sugg<'a> {
126
129
}
127
130
128
131
/// Convenience method to create the `<lhs> as <rhs>` suggestion.
129
- pub fn as_ty < R : std :: fmt :: Display > ( self , rhs : R ) -> Sugg < ' static > {
132
+ pub fn as_ty < R : Display > ( self , rhs : R ) -> Sugg < ' static > {
130
133
make_assoc ( AssocOp :: As , & self , & Sugg :: NonParen ( rhs. to_string ( ) . into ( ) ) )
131
134
}
132
135
@@ -198,7 +201,7 @@ impl<T> ParenHelper<T> {
198
201
}
199
202
}
200
203
201
- impl < T : std :: fmt :: Display > std :: fmt :: Display for ParenHelper < T > {
204
+ impl < T : Display > Display for ParenHelper < T > {
202
205
fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> Result < ( ) , std:: fmt:: Error > {
203
206
if self . paren {
204
207
write ! ( f, "({})" , self . wrapped)
@@ -354,3 +357,83 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp {
354
357
And | Eq | Ge | Gt | Le | Lt | Ne | Or => panic ! ( "This operator does not exist" ) ,
355
358
} )
356
359
}
360
+
361
+ /// Return the indentation before `span` if there are nothing but `[ \t]` before it on its line.
362
+ fn indentation < T : LintContext > ( cx : & T , span : Span ) -> Option < String > {
363
+ let lo = cx. sess ( ) . codemap ( ) . lookup_char_pos ( span. lo ) ;
364
+ if let Some ( line) = lo. file . get_line ( lo. line - 1 /* line numbers in `Loc` are 1-based */ ) {
365
+ if let Some ( ( pos, _) ) = line. char_indices ( ) . find ( |& ( _, c) | c != ' ' && c != '\t' ) {
366
+ // we can mix char and byte positions here because we only consider `[ \t]`
367
+ if lo. col == CharPos ( pos) {
368
+ Some ( line[ ..pos] . into ( ) )
369
+ } else {
370
+ None
371
+ }
372
+ } else {
373
+ None
374
+ }
375
+ } else {
376
+ None
377
+ }
378
+ }
379
+
380
+ pub trait DiagnosticBuilderExt < T : LintContext > {
381
+ /// Suggests to add an attribute to an item.
382
+ ///
383
+ /// Correctly handles indentation of the attribute and item.
384
+ ///
385
+ /// # Example
386
+ ///
387
+ /// ```rust
388
+ /// db.suggest_item_with_attr(cx, item, "#[derive(Default)]");
389
+ /// ```
390
+ fn suggest_item_with_attr < D : Display +?Sized > ( & mut self , cx : & T , item : Span , msg : & str , attr : & D ) ;
391
+
392
+ /// Suggest to add an item before another.
393
+ ///
394
+ /// The item should not be indented (expect for inner indentation).
395
+ ///
396
+ /// # Example
397
+ ///
398
+ /// ```rust
399
+ /// db.suggest_prepend_item(cx, item,
400
+ /// "fn foo() {
401
+ /// bar();
402
+ /// }");
403
+ /// ```
404
+ fn suggest_prepend_item ( & mut self , cx : & T , item : Span , msg : & str , new_item : & str ) ;
405
+ }
406
+
407
+ impl < ' a , ' b , T : LintContext > DiagnosticBuilderExt < T > for rustc_errors:: DiagnosticBuilder < ' b > {
408
+ fn suggest_item_with_attr < D : Display +?Sized > ( & mut self , cx : & T , item : Span , msg : & str , attr : & D ) {
409
+ if let Some ( indent) = indentation ( cx, item) {
410
+ let span = Span {
411
+ hi : item. lo ,
412
+ ..item
413
+ } ;
414
+
415
+ self . span_suggestion ( span, msg, format ! ( "{}\n {}" , attr, indent) ) ;
416
+ }
417
+ }
418
+
419
+ fn suggest_prepend_item ( & mut self , cx : & T , item : Span , msg : & str , new_item : & str ) {
420
+ if let Some ( indent) = indentation ( cx, item) {
421
+ let span = Span {
422
+ hi : item. lo ,
423
+ ..item
424
+ } ;
425
+
426
+ let mut first = true ;
427
+ let new_item = new_item. lines ( ) . map ( |l| {
428
+ if first {
429
+ first = false ;
430
+ format ! ( "{}\n " , l)
431
+ } else {
432
+ format ! ( "{}{}\n " , indent, l)
433
+ }
434
+ } ) . collect :: < String > ( ) ;
435
+
436
+ self . span_suggestion ( span, msg, format ! ( "{}\n {}" , new_item, indent) ) ;
437
+ }
438
+ }
439
+ }
0 commit comments