diff --git a/src/dscanner/analysis/alias_syntax_check.d b/src/dscanner/analysis/alias_syntax_check.d index 5c30ec4..7629a49 100644 --- a/src/dscanner/analysis/alias_syntax_check.d +++ b/src/dscanner/analysis/alias_syntax_check.d @@ -5,50 +5,80 @@ module dscanner.analysis.alias_syntax_check; -import dparse.ast; -import dparse.lexer; import dscanner.analysis.base; +import dmd.tokens; +import dmd.lexer : Lexer; +import dmd.location : Loc; /** * Checks for uses of the old alias syntax. */ -final class AliasSyntaxCheck : BaseAnalyzer +extern(C++) class AliasSyntaxCheck(AST) : BaseAnalyzerDmd { - alias visit = BaseAnalyzer.visit; - mixin AnalyzerInfo!"alias_syntax_check"; + alias visit = BaseAnalyzerDmd.visit; - this(BaseAnalyzerArguments args) + extern(D) this(string fileName) { - super(args); + super(fileName); } - override void visit(const AliasDeclaration ad) + override void visit(AST.AliasDeclaration ad) { - if (ad.declaratorIdentifierList is null) - return; - assert(ad.declaratorIdentifierList.identifiers.length > 0, - "Identifier list length is zero, libdparse has a bug"); - addErrorMessage(ad, KEY, - "Prefer the new \"'alias' identifier '=' type ';'\" syntax" - ~ " to the old \"'alias' type identifier ';'\" syntax."); + import dscanner.utils: readFile; + import dmd.errorsink : ErrorSinkNull; + import dmd.globals : global; + + __gshared ErrorSinkNull errorSinkNull; + if (!errorSinkNull) + errorSinkNull = new ErrorSinkNull; + + auto bytes = readFile(fileName); + bool foundEq = false; + Loc idLoc; + + bytes ~= '\0'; + bytes = bytes[ad.loc.fileOffset .. $]; + + scope lexer = new Lexer(null, cast(char*) bytes, 0, bytes.length, 0, 0, errorSinkNull, &global.compileEnv); + TOK nextTok; + lexer.nextToken(); + + do + { + if (lexer.token.value == TOK.assign) + foundEq = true; + + if (lexer.token.value == TOK.identifier) + idLoc = lexer.token.loc; + + nextTok = lexer.nextToken; + } + while(nextTok != TOK.semicolon && nextTok != TOK.endOfFile); + + if (!foundEq) + // Re-lexing is done based on offsets, so the alias appears to be at line 1. + // Fix this by computing the initial location. + addErrorMessage(cast(ulong) (ad.loc.linnum + idLoc.linnum - 1), cast(ulong) idLoc.charnum, KEY, + "Prefer the new \"'alias' identifier '=' type ';'\" syntax" + ~ " to the old \"'alias' type identifier ';'\" syntax."); } + private: enum KEY = "dscanner.style.alias_syntax"; } unittest { - import dscanner.analysis.helpers : assertAnalyzerWarnings; + import dscanner.analysis.helpers : assertAnalyzerWarnings = assertAnalyzerWarningsDMD; import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; import std.stdio : stderr; StaticAnalysisConfig sac = disabledConfig(); sac.alias_syntax_check = Check.enabled; assertAnalyzerWarnings(q{ - alias int abcde; /+ - ^^^^^^^^^^^^^^^^ [warn]: Prefer the new "'alias' identifier '=' type ';'" syntax to the old "'alias' type identifier ';'" syntax.+/ + alias int abcde; // [warn]: Prefer the new "'alias' identifier '=' type ';'" syntax to the old "'alias' type identifier ';'" syntax. alias abcde = int; }c, sac); diff --git a/src/dscanner/analysis/run.d b/src/dscanner/analysis/run.d index f617576..4459fc5 100644 --- a/src/dscanner/analysis/run.d +++ b/src/dscanner/analysis/run.d @@ -929,10 +929,6 @@ private BaseAnalyzer[] getAnalyzersForModuleAndConfig(string fileName, checks ~= new UselessAssertCheck(args.setSkipTests( analysisConfig.useless_assert_check == Check.skipTests && !ut)); - if (moduleName.shouldRun!AliasSyntaxCheck(analysisConfig)) - checks ~= new AliasSyntaxCheck(args.setSkipTests( - analysisConfig.alias_syntax_check == Check.skipTests && !ut)); - if (moduleName.shouldRun!StaticIfElse(analysisConfig)) checks ~= new StaticIfElse(args.setSkipTests( analysisConfig.static_if_else_check == Check.skipTests && !ut)); @@ -1321,6 +1317,9 @@ MessageSet analyzeDmd(string fileName, ASTBase.Module m, const char[] moduleName if (moduleName.shouldRunDmd!(LengthSubtractionCheck!ASTBase)(config)) visitors ~= new LengthSubtractionCheck!ASTBase(fileName); + + if (moduleName.shouldRunDmd!(AliasSyntaxCheck!ASTBase)(config)) + visitors ~= new AliasSyntaxCheck!ASTBase(fileName); if (moduleName.shouldRunDmd!(ExplicitlyAnnotatedUnittestCheck!ASTBase)(config)) visitors ~= new ExplicitlyAnnotatedUnittestCheck!ASTBase(fileName);