Skip to content

Commit 457fab8

Browse files
ntrelWebFreak001
authored andcommitted
[style.alias_syntax] Add AutoFix replacement
1 parent 9dc3d0d commit 457fab8

1 file changed

Lines changed: 75 additions & 3 deletions

File tree

src/dscanner/analysis/alias_syntax_check.d

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

3788
private:
@@ -40,16 +91,37 @@ private:
4091

4192
unittest
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

Comments
 (0)