update dmd and include the API needed for semantic analysis (#66)

* update dmd and include the API needed for semantic analysis

* update libparse + initial implementation for properly documented public functions

* test

* refactor

* update workflows

* delete unused code
This commit is contained in:
lucica28 2023-05-19 10:25:25 +03:00 committed by Vladiwostok
parent b90a8620ce
commit cb432bc651
11 changed files with 581 additions and 717 deletions

View file

@ -107,6 +107,10 @@ jobs:
sudo apt-get install gdc-12 -y
gdc-12 --version
# - name: Setup upterm session
# if: ${{ matrix.build.type == 'make' && matrix.host == 'macos-latest'}}
# uses: lhotari/action-upterm@v1
# Compile D-Scanner and execute all tests without dub
- name: Build and test without dub
if: ${{ matrix.build.type == 'make' }}
@ -119,7 +123,8 @@ jobs:
./build.bat
./build.bat test
else
make "-j$(nproc)" all test
NUM_PROC=$(nproc || getconf _NPROCESSORS_ONLN || 1)
make "-j$((NUM_PROC / 2))" all test
fi
# Compile D-Scanner and execute all tests using a specific dependency version

View file

@ -18,8 +18,8 @@ if %githashsize% == 0 (
move /y bin\githash_.txt bin\githash.txt
)
set DFLAGS=-O -release -version=StdLoggerDisableWarning -version=CallbackAPI -version=DMDLIB -version=MARS -Jbin -Jdmd %MFLAGS%
set TESTFLAGS=-g -w -version=StdLoggerDisableWarning -version=CallbackAPI -version=DMDLIB -version=MARS -Jbin -Jdmd
set DFLAGS=-O -release -version=StdLoggerDisableWarning -version=CallbackAPI -version=DMDLIB -version=MARS -Jbin -Jdmd -Jdmd\compiler\src\dmd\res %MFLAGS%
set TESTFLAGS=-g -w -version=StdLoggerDisableWarning -version=CallbackAPI -version=DMDLIB -version=MARS -Jbin -Jdmd -Jdmd\compiler\src\dmd\res
set CORE=
set LIBDPARSE=
set STD=
@ -29,6 +29,8 @@ set DSYMBOL=
set CONTAINERS=
set LIBDDOC=
SET DMD_FRONTEND_SRC=objc_glue.obj clone.obj transitivevisitor.obj iasm.obj iasmdmd.obj canthrow.obj tokens.obj optimize.obj func.obj semantic2.obj dvarstats.obj ph2.obj code.obj cdef.obj xmm.obj out.obj elfobj.obj glocal.obj dvec.obj code_x86.obj iasm2.obj string2.obj file2.obj obj.obj go.obj inliner.obj cc.obj bcomplex.obj mscoffobj.obj ptrntab.obj dlist.obj pdata.obj fp.obj cod3.obj os.obj cgelem.obj dcode.obj disasm86.obj exh.obj blockopt.obj aarray.obj cg.obj newman.obj dwarfdbginf.obj codebuilder.obj var.obj cod2.obj machobj.obj cgobj.obj cod4.obj dtype.obj cv4.obj backend.obj el.obj cgcod.obj cv8.obj dwarf.obj evalu8.obj ty.obj mem.obj cgxmm.obj gdag.obj gother.obj goh.obj cgcv.obj debugprint.obj cgsched.obj dwarfeh.obj cgreg.obj backconfig.obj gloop.obj divcoeff.obj cod5.obj dwarf2.obj cg87.obj nteh.obj dcgcv.obj util2.obj compress.obj type.obj elpicpie.obj gsroa.obj cgcs.obj ee.obj symbol.obj barray.obj melf.obj oper.obj cgcse.obj rtlsym.obj mscoff.obj drtlsym.obj symtab.obj dt.obj mach.obj cod1.obj global.obj filespec.obj gflow.obj elem.obj cgen.obj md5.obj chkformat.obj argtypes_sysv_x64.obj sideeffect.obj denum.obj apply.obj e2ir.obj typinf.obj statement.obj arraytypes.obj blockexit.obj init.obj scanomf.obj utils.obj parsetimevisitor.obj errorsink.obj scanmscoff.obj initsem.obj arrayop.obj nogc.obj dsymbol.obj hdrgen.obj dmangle.obj astenums.obj libmscoff.obj compiler.obj foreachvar.obj scanmach.obj dcast.obj tocsym.obj tocvdebug.obj semantic3.obj builtin.obj sapply.obj printast.obj dtemplate.obj importc.obj file_manager.obj dclass.obj argtypes_x86.obj glue.obj statement_rewrite_walker.obj target.obj aggregate.obj stringtable.obj ctfloat.obj response.obj strtold.obj port.obj aav.obj env.obj optional.obj filename.obj man.obj rootobject.obj complex.obj hash.obj region.obj utf.obj speller.obj rmem.obj array.obj longdouble.obj bitarray.obj eh.obj strictvisitor.obj permissivevisitor.obj lambdacomp.obj ctfeexpr.obj cparse.obj imphint.obj delegatize.obj access.obj identifier.obj todt.obj dmsc.obj entity.obj impcnvtab.obj dimport.obj lexer.obj dinifile.obj libomf.obj vsoptions.obj dstruct.obj aliasthis.obj ctorflow.obj errors.obj astcodegen.obj mtype.obj dtoh.obj argtypes_aarch64.obj cpreprocess.obj dmdparams.obj lib.obj id.obj parse.obj doc.obj scanelf.obj iasmgcc.obj cppmanglewin.obj stmtstate.obj ob.obj expression.obj declaration.obj location.obj dinterpret.obj inline.obj bitfields.obj string.obj int128.obj file.obj outbuffer.obj nspace.obj gluelayer.obj json.obj toir.obj intrange.obj cond.obj constfold.obj dversion.obj staticassert.obj dmodule.obj traits.obj opover.obj link.obj toctype.obj staticcond.obj statementsem.obj globals.obj libmach.obj toobj.obj s2ir.obj inlinecost.obj objc.obj visitor.obj asttypename.obj mustuse.obj dsymbolsem.obj frontend.obj safe.obj dscope.obj attrib.obj ast_node.obj escape.obj cli.obj templateparamsem.obj libelf.obj console.obj cppmangle.obj astbase.obj dmacro.obj typesem.obj expressionsem.obj
set DMD_ROOT_SRC=
for %%x in (dmd\compiler\src\dmd\common\*.d) do set DMD_ROOT_SRC=!DMD_ROOT_SRC! %%x
for %%x in (dmd\compiler\src\dmd\root\*.d) do set DMD_ROOT_SRC=!DMD_ROOT_SRC! %%x
@ -67,9 +69,21 @@ for %%x in (DCD\dsymbol\src\dsymbol\conversion\*.d) do set DSYMBOL=!DSYMBOL! %%x
for %%x in (containers\src\containers\*.d) do set CONTAINERS=!CONTAINERS! %%x
for %%x in (containers\src\containers\internal\*.d) do set CONTAINERS=!CONTAINERS! %%x
for %%x in (dmd\compiler\src\dmd\common\*.d) do %DC% %DFLAGS% -c %%x -od. -I"dmd\compiler\src"
for %%x in (dmd\compiler\src\dmd\root\*.d) do %DC% %DFLAGS% -c %%x -od. -I"dmd\compiler\src"
for %%x in (dmd\compiler\src\dmd\backend\*.d) do %DC% %DFLAGS% -c %%x -od. -I"dmd\compiler\src"
for %%x in (dmd\compiler\src\dmd\*.d) do %DC% %DFLAGS% -c %%x -od. -I"dmd\compiler\src"
%DC% %DFLAGS% -c dmd\compiler\src\dmd\backend\iasm.d -od. -ofiasm2.obj -I"dmd\compiler\src"
%DC% %DFLAGS% -c dmd\compiler\src\dmd\common\string.d -od. -ofstring2.obj -I"dmd\compiler\src"
%DC% %DFLAGS% -c dmd\compiler\src\dmd\common\file.d -od. -offile2.obj -I"dmd\compiler\src"
if "%1" == "test" goto test_cmd
@echo on
dir
echo %DMD_FRONTEND_SRC%
%DC% %MFLAGS%^
%CORE%^
%STD%^
@ -79,9 +93,7 @@ if "%1" == "test" goto test_cmd
%INIFILED%^
%DSYMBOL%^
%CONTAINERS%^
%DMD_ROOT_SRC%^
%DMD_LEXER_SRC%^
%DMD_PARSER_SRC%^
%DMD_FRONTEND_SRC%^
%DFLAGS%^
-I"libdparse\src"^
-I"DCD\dsymbol\src"^
@ -102,14 +114,13 @@ set TESTNAME="bin\dscanner-unittest"
%INIFILED%^
%DSYMBOL%^
%CONTAINERS%^
%DMD_ROOT_SRC%^
%DMD_LEXER_SRC%^
%DMD_PARSER_SRC%^
%DMD_FRONTEND_SRC%^
-I"libdparse\src"^
-I"DCD\dsymbol\src"^
-I"containers\src"^
-I"libddoc\src"^
-I"dmd\compiler\src"^
-I"dmd\compiler\src\dmd\res"^
-lib %TESTFLAGS%^
-of%TESTNAME%.lib
if exist %TESTNAME%.lib %DC% %MFLAGS%^
@ -124,6 +135,7 @@ if exist %TESTNAME%.lib %DC% %MFLAGS%^
-I"libddoc\src"^
-I"libddoc\common\source"^
-I"dmd\compiler\src"^
-I"dmd\compiler\src\dmd\res"^
-unittest^
%TESTFLAGS%^
-of%TESTNAME%.exe

2
dmd

@ -1 +1 @@
Subproject commit 020685c85b4fde7d50511716dc98dfc5dc97ef2b
Subproject commit a4220358ecfcffe7ea38ab4a1996ffc5a5331f22

View file

@ -16,9 +16,10 @@
"inifiled": "~>1.3.1",
"emsi_containers": "~>0.9.0",
"libddoc": "~>0.8.0",
"dmd:root": "~master",
"dmd:lexer": "~master",
"dmd:parser": "~master"
"dmd": {
"repository": "git+https://github.com/dlang/dmd.git",
"version": "a4220358ecfcffe7ea38ab4a1996ffc5a5331f22"
}
},
"targetPath" : "bin",
"stringImportPaths" : [

View file

@ -1,5 +1,7 @@
.PHONY: all test clean
.DEFAULT_GOAL := all
DC ?= dmd
GIT ?= git
DMD := $(DC)
@ -7,11 +9,19 @@ GDC := gdc
LDC := ldc2
DMD_ROOT_SRC := \
$(shell find dmd/compiler/src/dmd/common -name "*.d")\
$(shell find dmd/compiler/src/dmd/root -name "*.d")
$(shell find dmd/compiler/src/dmd/root -name "*.d")\
DMD_FRONTEND_SRC := \
$(shell find dmd/compiler/src/dmd/common -name "*.d")\
$(shell find dmd/compiler/src/dmd/root -name "*.d")\
$(shell find dmd/compiler/src/dmd/backend -name "*.d")\
$(shell find dmd/compiler/src/dmd -maxdepth 1 -name "*.d" ! -name "mars.d" )
DMD_LEXER_SRC := \
dmd/compiler/src/dmd/console.d \
dmd/compiler/src/dmd/entity.d \
dmd/compiler/src/dmd/errors.d \
dmd/compiler/src/dmd/errorsink.d \
dmd/compiler/src/dmd/file_manager.d \
dmd/compiler/src/dmd/globals.d \
dmd/compiler/src/dmd/id.d \
@ -19,6 +29,7 @@ DMD_LEXER_SRC := \
dmd/compiler/src/dmd/lexer.d \
dmd/compiler/src/dmd/tokens.d \
dmd/compiler/src/dmd/utils.d \
dmd/compiler/src/dmd/location.d \
$(DMD_ROOT_SRC)
DMD_PARSER_SRC := \
@ -39,7 +50,8 @@ LIB_SRC := \
$(shell find libdparse/src/dparse/ -name "*.d")\
$(shell find libddoc/src -name "*.d") \
$(shell find libddoc/common/source -name "*.d") \
$(DMD_PARSER_SRC)
$(DMD_FRONTEND_SRC)
PROJECT_SRC := $(shell find src/ -name "*.d")
SRC := $(LIB_SRC) $(PROJECT_SRC)
@ -78,17 +90,17 @@ LDC_DEBUG_VERSIONS = -d-version=dparse_verbose
GDC_VERSIONS = -fversion=StdLoggerDisableWarning -fversion=CallbackAPI -fversion=DMDLIB -fversion=MARS
GDC_DEBUG_VERSIONS = -fversion=dparse_verbose
DC_FLAGS += -Jbin -Jdmd
DC_FLAGS += -Jbin -Jdmd -Jdmd/compiler/src/dmd/res
override DMD_FLAGS += $(DFLAGS) -w -release -O -od${OBJ_DIR}
override LDC_FLAGS += $(DFLAGS) -O5 -release -oq
override GDC_FLAGS += $(DFLAGS) -O3 -frelease -fall-instantiations
override GDC_TEST_FLAGS += -fall-instantiations
DC_TEST_FLAGS += -g -Jbin -Jdmd
DC_TEST_FLAGS += -g -Jbin -Jdmd -Jdmd/compiler/src/dmd/res
override DMD_TEST_FLAGS += -w
DC_DEBUG_FLAGS := -g -Jbin -Jdmd
DC_DEBUG_FLAGS := -g -Jbin -Jdmd -Jdmd/compiler/src/dmd/res
ifeq ($(DC), $(filter $(DC), dmd ldmd2 gdmd))
VERSIONS := $(DMD_VERSIONS)
@ -113,7 +125,13 @@ SHELL:=/usr/bin/env bash
GITHASH = bin/githash.txt
FIRST_RUN_FLAG := $(OBJ_DIR)/$(DC)/first_run.flag
$(OBJ_DIR)/$(DC)/%.o: %.d
if [ ! -f $(FIRST_RUN_FLAG) ]; then \
${DC} -run dmd/config.d bin VERSION /etc; \
touch $(FIRST_RUN_FLAG); \
fi
${DC} ${DC_FLAGS} ${VERSIONS} ${INCLUDE_PATHS} -c $< ${WRITE_TO_TARGET_NAME}
$(UT_OBJ_DIR)/$(DC)/%.o: %.d

View file

@ -10,6 +10,8 @@ import std.meta : AliasSeq;
import std.string;
import std.sumtype;
import dmd.transitivevisitor;
import dmd.visitor;
import dmd.func;
import core.stdc.string;
import std.conv : to;
@ -909,9 +911,9 @@ unittest
* Visitor that implements the AST traversal logic.
* Supports collecting error messages
*/
extern(C++) class BaseAnalyzerDmd(AST) : ParseTimeTransitiveVisitor!AST
extern(C++) class BaseAnalyzerDmd : SemanticTimeTransitiveVisitor
{
alias visit = ParseTimeTransitiveVisitor!AST.visit;
alias visit = SemanticTimeTransitiveVisitor.visit;
extern(D) this(string fileName, bool skipTests = false)
{
@ -934,7 +936,7 @@ extern(C++) class BaseAnalyzerDmd(AST) : ParseTimeTransitiveVisitor!AST
return _messages[].array;
}
override void visit(AST.UnitTestDeclaration ud)
override void visit(UnitTestDeclaration ud)
{
if (!skipTests)
super.visit(ud);

View file

@ -22,6 +22,8 @@ import std.experimental.allocator.mallocator;
import dmd.parse : Parser;
import dmd.astbase : ASTBase;
import dmd.astcodegen;
import dmd.frontend;
S between(S)(S value, S before, S after) if (isSomeString!S)
{
@ -471,3 +473,121 @@ void assertAnalyzerWarningsDMD(string code, const StaticAnalysisConfig config, b
throw new AssertError(message, file, line);
}
}
void assertAnalyzerWarningsDMD(string code, const StaticAnalysisConfig config, bool semantic = false,
string file = __FILE__, size_t line = __LINE__)
{
import dmd.globals : global;
import dscanner.utils : getModuleName;
import std.file : remove, exists;
import std.stdio : File;
import std.path : dirName;
import dmd.arraytypes : Strings;
import std.stdio : File;
import std.file : exists, remove;
auto deleteme = "test.txt";
File f = File(deleteme, "w");
scope(exit)
{
assert(exists(deleteme));
remove(deleteme);
}
f.write(code);
f.close();
auto dmdParentDir = dirName(dirName(dirName(dirName(__FILE_FULL_PATH__))));
global.params.useUnitTests = true;
global.path = new Strings();
global.path.push((dmdParentDir ~ "/dmd").ptr);
global.path.push((dmdParentDir ~ "/dmd/druntime/src").ptr);
initDMD();
auto input = cast(char[]) code;
input ~= '\0';
auto t = dmd.frontend.parseModule(cast(const(char)[]) file, cast(const (char)[]) input);
if (semantic)
t.module_.fullSemantic();
MessageSet rawWarnings = analyzeDmd("test.txt", t.module_, getModuleName(t.module_.md), config);
string[] codeLines = code.splitLines();
// Get the warnings ordered by line
string[size_t] warnings;
foreach (rawWarning; rawWarnings[])
{
// Skip the warning if it is on line zero
immutable size_t rawLine = rawWarning.line;
if (rawLine == 0)
{
stderr.writefln("!!! Skipping warning because it is on line zero:\n%s",
rawWarning.message);
continue;
}
size_t warnLine = line - 1 + rawLine;
warnings[warnLine] = format("[warn]: %s", rawWarning.message);
}
// Get all the messages from the comments in the code
string[size_t] messages;
foreach (i, codeLine; codeLines)
{
// Skip if no [warn] comment
if (codeLine.indexOf("// [warn]:") == -1)
continue;
// Skip if there is no comment or code
immutable string codePart = codeLine.before("// ");
immutable string commentPart = codeLine.after("// ");
if (!codePart.length || !commentPart.length)
continue;
// Get the line of this code line
size_t lineNo = i + line;
// Get the message
messages[lineNo] = commentPart;
}
// Throw an assert error if any messages are not listed in the warnings
foreach (lineNo, message; messages)
{
// No warning
if (lineNo !in warnings)
{
immutable string errors = "Expected warning:\n%s\nFrom source code at (%s:?):\n%s".format(messages[lineNo],
lineNo, codeLines[lineNo - line]);
throw new AssertError(errors, file, lineNo);
}
// Different warning
else if (warnings[lineNo] != messages[lineNo])
{
immutable string errors = "Expected warning:\n%s\nBut was:\n%s\nFrom source code at (%s:?):\n%s".format(
messages[lineNo], warnings[lineNo], lineNo, codeLines[lineNo - line]);
throw new AssertError(errors, file, lineNo);
}
}
// Throw an assert error if there were any warnings that were not expected
string[] unexpectedWarnings;
foreach (lineNo, warning; warnings)
{
// Unexpected warning
if (lineNo !in messages)
{
unexpectedWarnings ~= "%s\nFrom source code at (%s:?):\n%s".format(warning,
lineNo, codeLines[lineNo - line]);
}
}
if (unexpectedWarnings.length)
{
immutable string message = "Unexpected warnings:\n" ~ unexpectedWarnings.join("\n");
throw new AssertError(message, file, line);
}
}

File diff suppressed because it is too large Load diff

View file

@ -97,6 +97,9 @@ import dscanner.reports : DScannerJsonReporter, SonarQubeGenericIssueDataReporte
import dmd.astbase : ASTBase;
import dmd.parse : Parser;
import dmd.frontend;
import dmd.astcodegen;
bool first = true;
version (unittest)
@ -393,25 +396,27 @@ bool analyze(string[] fileNames, const StaticAnalysisConfig config, string error
import dmd.globals : global;
import dmd.identifier : Identifier;
import std.string : toStringz;
Id.initialize();
global._init();
global.params.useUnitTests = true;
ASTBase.Type._init();
import dmd.arraytypes : Strings;
bool hasErrors;
foreach (fileName; fileNames)
{
auto code = readFile(fileName);
auto id = Identifier.idPool(fileName);
auto ast_m = new ASTBase.Module(fileName.toStringz, id, false, false);
auto dmdParentDir = dirName(dirName(dirName(dirName(__FILE_FULL_PATH__))));
global.params.useUnitTests = true;
global.path = new Strings();
global.path.push((dmdParentDir ~ "/dmd").ptr);
global.path.push((dmdParentDir ~ "/dmd/druntime/src").ptr);
initDMD();
auto code = readFile(fileName);
auto input = cast(char[]) code;
input ~= '\0';
scope astbaseParser = new Parser!ASTBase(ast_m, input, false);
astbaseParser.nextToken();
ast_m.members = astbaseParser.parseModule();
auto t = dmd.frontend.parseModule(cast(const(char)[]) fileName, cast(const (char)[]) input);
// t.module_.fullSemantic();
// Skip files that could not be read and continue with the rest
if (code.length == 0)
@ -426,7 +431,7 @@ bool analyze(string[] fileNames, const StaticAnalysisConfig config, string error
if (errorCount > 0 || (staticAnalyze && warningCount > 0))
hasErrors = true;
MessageSet results = analyze(fileName, m, config, moduleCache, tokens, staticAnalyze);
MessageSet resultsDmd = analyzeDmd(fileName, ast_m, getModuleName(astbaseParser.md), config);
MessageSet resultsDmd = analyzeDmd(fileName, t.module_, getModuleName(t.module_.md), config);
foreach (result; resultsDmd[])
{
results.insert(result);
@ -739,7 +744,7 @@ bool shouldRun(check : BaseAnalyzer)(string moduleName, const ref StaticAnalysis
*
* If no includes are specified, all modules are included.
*/
bool shouldRunDmd(check : BaseAnalyzerDmd!ASTBase)(const char[] moduleName, const ref StaticAnalysisConfig config)
bool shouldRunDmd(check : BaseAnalyzerDmd)(const char[] moduleName, const ref StaticAnalysisConfig config)
{
enum string a = check.name;
@ -921,10 +926,6 @@ private BaseAnalyzer[] getAnalyzersForModuleAndConfig(string fileName,
checks ~= new AutoFunctionChecker(args.setSkipTests(
analysisConfig.auto_function_check == Check.skipTests && !ut));
if (moduleName.shouldRun!ProperlyDocumentedPublicFunctions(analysisConfig))
checks ~= new ProperlyDocumentedPublicFunctions(args.setSkipTests(
analysisConfig.properly_documented_public_functions == Check.skipTests && !ut));
if (moduleName.shouldRun!VcallCtorChecker(analysisConfig))
checks ~= new VcallCtorChecker(args.setSkipTests(
analysisConfig.vcall_in_ctor == Check.skipTests && !ut));
@ -1265,77 +1266,83 @@ version (unittest)
}
}
MessageSet analyzeDmd(string fileName, ASTBase.Module m, const char[] moduleName, const StaticAnalysisConfig config)
MessageSet analyzeDmd(string fileName, ASTCodegen.Module m, const char[] moduleName, const StaticAnalysisConfig config)
{
MessageSet set = new MessageSet;
BaseAnalyzerDmd!ASTBase[] visitors;
BaseAnalyzerDmd[] visitors;
if (moduleName.shouldRunDmd!(ObjectConstCheck!ASTBase)(config))
visitors ~= new ObjectConstCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(ObjectConstCheck!ASTCodegen)(config))
visitors ~= new ObjectConstCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(EnumArrayVisitor!ASTBase)(config))
visitors ~= new EnumArrayVisitor!ASTBase(fileName);
if (moduleName.shouldRunDmd!(EnumArrayVisitor!ASTCodegen)(config))
visitors ~= new EnumArrayVisitor!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(DeleteCheck!ASTBase)(config))
visitors ~= new DeleteCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(DeleteCheck!ASTCodegen)(config))
visitors ~= new DeleteCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(FinalAttributeChecker!ASTBase)(config))
visitors ~= new FinalAttributeChecker!ASTBase(fileName);
if (moduleName.shouldRunDmd!(FinalAttributeChecker!ASTCodegen)(config))
visitors ~= new FinalAttributeChecker!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(ImportSortednessCheck!ASTBase)(config))
visitors ~= new ImportSortednessCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(ImportSortednessCheck!ASTCodegen)(config))
visitors ~= new ImportSortednessCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(IncorrectInfiniteRangeCheck!ASTBase)(config))
visitors ~= new IncorrectInfiniteRangeCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(IncorrectInfiniteRangeCheck!ASTCodegen)(config))
visitors ~= new IncorrectInfiniteRangeCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(RedundantAttributesCheck!ASTBase)(config))
visitors ~= new RedundantAttributesCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(RedundantAttributesCheck!ASTCodegen)(config))
visitors ~= new RedundantAttributesCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(LengthSubtractionCheck!ASTBase)(config))
visitors ~= new LengthSubtractionCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(LengthSubtractionCheck!ASTCodegen)(config))
visitors ~= new LengthSubtractionCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(AliasSyntaxCheck!ASTBase)(config))
visitors ~= new AliasSyntaxCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(AliasSyntaxCheck!ASTCodegen)(config))
visitors ~= new AliasSyntaxCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(ExplicitlyAnnotatedUnittestCheck!ASTBase)(config))
visitors ~= new ExplicitlyAnnotatedUnittestCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(ExplicitlyAnnotatedUnittestCheck!ASTCodegen)(config))
visitors ~= new ExplicitlyAnnotatedUnittestCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(ConstructorCheck!ASTBase)(config))
visitors ~= new ConstructorCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(ConstructorCheck!ASTCodegen)(config))
visitors ~= new ConstructorCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(AssertWithoutMessageCheck!ASTBase)(config))
visitors ~= new AssertWithoutMessageCheck!ASTBase(
if (moduleName.shouldRunDmd!(AssertWithoutMessageCheck!ASTCodegen)(config))
visitors ~= new AssertWithoutMessageCheck!ASTCodegen(
fileName,
config.assert_without_msg == Check.skipTests && !ut
);
if (moduleName.shouldRunDmd!(LocalImportCheck!ASTBase)(config))
visitors ~= new LocalImportCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(LocalImportCheck!ASTCodegen)(config))
visitors ~= new LocalImportCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(OpEqualsWithoutToHashCheck!ASTBase)(config))
visitors ~= new OpEqualsWithoutToHashCheck!ASTBase(
if (moduleName.shouldRunDmd!(OpEqualsWithoutToHashCheck!ASTCodegen)(config))
visitors ~= new OpEqualsWithoutToHashCheck!ASTCodegen(
fileName,
config.opequals_tohash_check == Check.skipTests && !ut
);
if (moduleName.shouldRunDmd!(AutoRefAssignmentCheck!ASTBase)(config))
visitors ~= new AutoRefAssignmentCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(AutoRefAssignmentCheck!ASTCodegen)(config))
visitors ~= new AutoRefAssignmentCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(LogicPrecedenceCheck!ASTBase)(config))
visitors ~= new LogicPrecedenceCheck!ASTBase(
if (moduleName.shouldRunDmd!(LogicPrecedenceCheck!ASTCodegen)(config))
visitors ~= new LogicPrecedenceCheck!ASTCodegen(
fileName,
config.logical_precedence_check == Check.skipTests && !ut
);
if (moduleName.shouldRunDmd!(BuiltinPropertyNameCheck!ASTBase)(config))
visitors ~= new BuiltinPropertyNameCheck!ASTBase(fileName);
if (moduleName.shouldRunDmd!(BuiltinPropertyNameCheck!ASTCodegen)(config))
visitors ~= new BuiltinPropertyNameCheck!ASTCodegen(fileName);
if (moduleName.shouldRunDmd!(BackwardsRangeCheck!ASTBase)(config))
visitors ~= new BackwardsRangeCheck!ASTBase(
if (moduleName.shouldRunDmd!(BackwardsRangeCheck!ASTCodegen)(config))
visitors ~= new BackwardsRangeCheck!ASTCodegen(
fileName,
config.backwards_range_check == Check.skipTests && !ut
);
if (moduleName.shouldRunDmd!(ProperlyDocumentedPublicFunctions!ASTCodegen)(config))
visitors ~= new ProperlyDocumentedPublicFunctions!ASTCodegen(
fileName,
config.properly_documented_public_functions == Check.skipTests && !ut
);
foreach (visitor; visitors)
{
m.accept(visitor);

View file

@ -50,6 +50,8 @@ extern(C++) class ImportVisitor(AST) : ParseTimeTransitiveVisitor!AST
private void visitFile(bool usingStdin, string fileName, RedBlackTree!string importedModules)
{
import dmd.errorsink : ErrorSinkNull;
Id.initialize();
global._init();
global.params.useUnitTests = true;
@ -60,7 +62,11 @@ private void visitFile(bool usingStdin, string fileName, RedBlackTree!string imp
ubyte[] bytes = usingStdin ? readStdin() : readFile(fileName);
auto input = cast(char[]) bytes;
scope p = new Parser!ASTBase(m, input, false);
__gshared ErrorSinkNull errorSinkNull;
if (!errorSinkNull)
errorSinkNull = new ErrorSinkNull;
scope p = new Parser!ASTBase(m, input, false, new ErrorSinkNull, null, false);
p.nextToken();
m.members = p.parseModule();

View file

@ -10,6 +10,7 @@ import std.path: isValidPath;
import dmd.astbase : ASTBase;
import dmd.parse : Parser;
import dmd.astcodegen;
private void processBOM(ref ubyte[] sourceCode, string fname)
{
@ -316,14 +317,14 @@ auto ref safeAccess(M)(M m)
/**
* Return the module name from a ModuleDeclaration instance with the following format: `foo.bar.module`
*/
const(char[]) getModuleName(ASTBase.ModuleDeclaration *mdptr)
const(char[]) getModuleName(ASTCodegen.ModuleDeclaration *mdptr)
{
import std.array : array, join;
if (mdptr !is null)
{
import std.algorithm : map;
ASTBase.ModuleDeclaration md = *mdptr;
ASTCodegen.ModuleDeclaration md = *mdptr;
if (md.packages.length != 0)
return join(md.packages.map!(e => e.toString()).array ~ md.id.toString().dup, ".");