1- use rowan:: TextSize ;
1+ use rowan:: { TextRange , TextSize } ;
22use squawk_linter:: Edit ;
33use squawk_syntax:: {
44 SyntaxKind ,
@@ -9,6 +9,7 @@ use crate::{
99 column_name:: ColumnName ,
1010 offsets:: token_from_offset,
1111 quote:: { quote_column_alias, unquote_ident} ,
12+ symbols:: Name ,
1213} ;
1314
1415#[ derive( Debug , Clone ) ]
@@ -34,6 +35,7 @@ pub fn code_actions(file: ast::SourceFile, offset: TextSize) -> Option<Vec<CodeA
3435 quote_identifier ( & mut actions, & file, offset) ;
3536 unquote_identifier ( & mut actions, & file, offset) ;
3637 add_explicit_alias ( & mut actions, & file, offset) ;
38+ remove_redundant_alias ( & mut actions, & file, offset) ;
3739 Some ( actions)
3840}
3941
@@ -395,6 +397,45 @@ fn add_explicit_alias(
395397 Some ( ( ) )
396398}
397399
400+ fn remove_redundant_alias (
401+ actions : & mut Vec < CodeAction > ,
402+ file : & ast:: SourceFile ,
403+ offset : TextSize ,
404+ ) -> Option < ( ) > {
405+ let token = token_from_offset ( file, offset) ?;
406+ let target = token. parent_ancestors ( ) . find_map ( ast:: Target :: cast) ?;
407+
408+ let as_name = target. as_name ( ) ?;
409+ let alias_name = as_name. name ( ) ?;
410+
411+ let ( inferred_column, _) = ColumnName :: inferred_from_target ( target. clone ( ) ) ?;
412+ let inferred_column_alias = inferred_column. to_string ( ) ?;
413+
414+ let alias = alias_name. syntax ( ) . text ( ) . to_string ( ) ;
415+
416+ if Name :: new ( alias) != Name :: new ( inferred_column_alias) {
417+ return None ;
418+ }
419+
420+ // TODO:
421+ // This lets use remove any whitespace so we don't end up with:
422+ // select x as x, b from t;
423+ // becoming
424+ // select x , b from t;
425+ // but we probably want a better way to express this.
426+ // Maybe a "Remove preceding whitespace" style option for edits.
427+ let expr_end = target. expr ( ) ?. syntax ( ) . text_range ( ) . end ( ) ;
428+ let alias_end = as_name. syntax ( ) . text_range ( ) . end ( ) ;
429+
430+ actions. push ( CodeAction {
431+ title : "Remove redundant alias" . to_owned ( ) ,
432+ edits : vec ! [ Edit :: delete( TextRange :: new( expr_end, alias_end) ) ] ,
433+ kind : ActionKind :: QuickFix ,
434+ } ) ;
435+
436+ Some ( ( ) )
437+ }
438+
398439#[ cfg( test) ]
399440mod test {
400441 use super :: * ;
@@ -1045,4 +1086,65 @@ mod test {
10451086 @r#"select 'foo' as "?column?" from t;"#
10461087 ) ;
10471088 }
1089+
1090+ #[ test]
1091+ fn remove_redundant_alias_simple ( ) {
1092+ assert_snapshot ! ( apply_code_action(
1093+ remove_redundant_alias,
1094+ "select col_name as col_na$0me from t;" ) ,
1095+ @"select col_name from t;"
1096+ ) ;
1097+ }
1098+
1099+ #[ test]
1100+ fn remove_redundant_alias_quoted ( ) {
1101+ assert_snapshot ! ( apply_code_action(
1102+ remove_redundant_alias,
1103+ r#"select "x"$0 as x from t;"# ) ,
1104+ @r#"select "x" from t;"#
1105+ ) ;
1106+ }
1107+
1108+ #[ test]
1109+ fn remove_redundant_alias_case_insensitive ( ) {
1110+ assert_snapshot ! ( apply_code_action(
1111+ remove_redundant_alias,
1112+ "select col_name$0 as COL_NAME from t;" ) ,
1113+ @"select col_name from t;"
1114+ ) ;
1115+ }
1116+
1117+ #[ test]
1118+ fn remove_redundant_alias_function ( ) {
1119+ assert_snapshot ! ( apply_code_action(
1120+ remove_redundant_alias,
1121+ "select count(*)$0 as count from t;" ) ,
1122+ @"select count(*) from t;"
1123+ ) ;
1124+ }
1125+
1126+ #[ test]
1127+ fn remove_redundant_alias_field_expr ( ) {
1128+ assert_snapshot ! ( apply_code_action(
1129+ remove_redundant_alias,
1130+ "select t.col$0umn as column from t;" ) ,
1131+ @"select t.column from t;"
1132+ ) ;
1133+ }
1134+
1135+ #[ test]
1136+ fn remove_redundant_alias_not_applicable_different_name ( ) {
1137+ assert ! ( code_action_not_applicable(
1138+ remove_redundant_alias,
1139+ "select col_name$0 as foo from t;"
1140+ ) ) ;
1141+ }
1142+
1143+ #[ test]
1144+ fn remove_redundant_alias_not_applicable_no_alias ( ) {
1145+ assert ! ( code_action_not_applicable(
1146+ remove_redundant_alias,
1147+ "select col_name$0 from t;"
1148+ ) ) ;
1149+ }
10481150}
0 commit comments