@@ -25,13 +25,64 @@ final class AliasSyntaxCheck : BaseAnalyzer
2525
2626 override void visit (const AliasDeclaration ad)
2727 {
28+ // new alias syntax uses `ad.initializers` instead
2829 if (ad.declaratorIdentifierList is null )
2930 return ;
3031 assert (ad.declaratorIdentifierList.identifiers.length > 0 ,
3132 " Identifier list length is zero, libdparse has a bug" );
33+
34+ static string tokenStr (const Token [] tokens)
35+ {
36+ string r;
37+ foreach (i, t; tokens)
38+ {
39+ if (i)
40+ {
41+ // keep whitespace to separate multiple tokens like original
42+ foreach (tt; tokens[i - 1 ].trailingTrivia)
43+ r ~= tt.text;
44+ }
45+ foreach (lt; t.leadingTrivia)
46+ r ~= lt.text;
47+
48+ string st = t.text ? t.text : t.type.str;
49+ assert (st.length);
50+ r ~= st;
51+ }
52+ return r;
53+ }
54+ // `alias storage target ident, ident2;`
55+ string target;
56+ foreach (i, sc; ad.storageClasses)
57+ {
58+ target ~= tokenStr(sc.tokens);
59+ target ~= ' ' ;
60+ }
61+ target ~= tokenStr(ad.type.tokens);
62+ // or single function type:
63+ // `alias storage type ident(params) attributes;`
64+ if (ad.parameters)
65+ {
66+ target ~= tokenStr(ad.parameters.tokens);
67+ foreach (fa; ad.memberFunctionAttributes)
68+ {
69+ target ~= ' ' ;
70+ target ~= tokenStr(fa.tokens);
71+ }
72+ }
73+ // need `ident = target, ident2 = target`
74+ string rep;
75+ foreach (i, t; ad.declaratorIdentifierList.identifiers)
76+ {
77+ if (i)
78+ rep ~= " , " ;
79+ rep ~= t.text ~ " = " ~ target;
80+ }
3281 addErrorMessage(ad, KEY ,
3382 " Prefer the new \" 'alias' identifier '=' type ';'\" syntax"
34- ~ " to the old \" 'alias' type identifier ';'\" syntax." );
83+ ~ " to the old \" 'alias' type identifier ';'\" syntax." ,
84+ [AutoFix.replacement(ad.tokens[1 .. $ - 1 ], rep,
85+ " Rewrite alias to use assignment syntax" )]);
3586 }
3687
3788private :
@@ -40,16 +91,37 @@ private:
4091
4192unittest
4293{
43- import dscanner.analysis.helpers : assertAnalyzerWarnings;
94+ import dscanner.analysis.helpers : assertAnalyzerWarnings, assertAutoFix ;
4495 import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
4596 import std.stdio : stderr;
4697
4798 StaticAnalysisConfig sac = disabledConfig();
4899 sac.alias_syntax_check = Check.enabled;
49100 assertAnalyzerWarnings(q{
50101 alias int abcde; /+
51- ^^^^^^^^^^^^^^^^ [warn]: Prefer the new "'alias' identifier '=' type ';'" syntax to the old "'alias' type identifier ';'" syntax.+/
102+ ^^^^^^^^^^^^^^^^ [warn]: Prefer the new "'alias' identifier '=' type ';'" syntax to the old "'alias' type identifier ';'" syntax.+/
52103 alias abcde = int ;
104+ alias xyz[] a, b; /+
105+ ^^^^^^^^^^^^^^^^^ [warn]: Prefer the new "'alias' identifier '=' type ';'" syntax to the old "'alias' type identifier ';'" syntax.+/
106+ alias a = xyz, b = xyz;
107+ alias void Func(); /+
108+ ^^^^^^^^^^^^^^^^^^ [warn]: Prefer the new "'alias' identifier '=' type ';'" syntax to the old "'alias' type identifier ';'" syntax.+/
109+ alias Func = void ();
110+ alias tem (T) = T! int ;
111+ }c, sac);
112+
113+ assertAutoFix(q{
114+ alias T * PT ; // fix
115+ alias int [f(1 , 2 ) + 3 ] sa; // fix
116+ alias void Func(int i) pure @att(4 * 5. g); // fix
117+ alias extern (C) void function () FP ; // fix
118+ alias xyz a, b; // fix
119+ }c, q{
120+ alias PT = T * ; // fix
121+ alias sa = int [f(1 , 2 ) + 3 ]; // fix
122+ alias Func = void (int i) pure @att(4 * 5. g); // fix
123+ alias FP = extern (C ) void function (); // fix
124+ alias a = xyz, b = xyz; // fix
53125 }c, sac);
54126
55127 stderr.writeln(" Unittest for AliasSyntaxCheck passed." );
0 commit comments