Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ extern (C++) class VarDeclaration : Declaration
bool dllExport; /// __declspec(dllexport)
mixin VarDeclarationExtra;
bool systemInferred; /// @system was inferred from initializer
bool wasUsed;
}

import dmd.common.bitfields : generateBitFields;
Expand Down
11 changes: 11 additions & 0 deletions compiler/src/dmd/dscope.d
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ enum Contract : ubyte
ensure = 3, // out contract
}

/// Active linting rules for the current scope
extern (C++) enum LintFlags : uint
{
none = 0,
constSpecial = 1 << 0, // Enforce `const` on special methods (opEquals, etc.)
unusedParams = 1 << 1,
all = ~0
}

/// Bitfield for settable/copyable flags, see `copyFlagsFrom`, `resetAllFlags`
private extern (D) struct FlagBitFields
{
Expand Down Expand Up @@ -186,6 +195,8 @@ extern (C++) struct Scope
mixin(generateBitFields!(NonFlagBitFields, ushort, "bitFields2"));
Previews previews;

LintFlags lintFlags;

// user defined attributes
UserAttributeDeclaration userAttribDecl;

Expand Down
27 changes: 26 additions & 1 deletion compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -9015,8 +9015,33 @@ private extern(C++) class NewScopeVisitor : Visitor
// then it's evaluated on demand in function semantic
sc = prd.createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, prd); // @suppress(dscanner.style.long_line)
}
}
else if (prd.ident == Id.lint)
{
sc = prd.createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining);

if (!prd.args || prd.args.length == 0)
{
sc.lintFlags |= LintFlags.all;
}
else
{
foreach (arg; *prd.args)
{
auto id = arg.isIdentifierExp();
if (!id) continue;

if (id.ident == Id.constSpecial)
sc.lintFlags |= LintFlags.constSpecial;
else if (id.ident == Id.unusedParams)
sc.lintFlags |= LintFlags.unusedParams;
else if (id.ident == Id.none)
sc.lintFlags = LintFlags.none;
else if (id.ident == Id.all)
sc.lintFlags |= LintFlags.all;
}
}
}
}
/**************************************
* Use the ForwardingScopeDsymbol as the parent symbol for members.
*/
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dmd/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
return &errorSupplemental;
case Classification.deprecation:
return &deprecationSupplemental;
case Classification.gagged, Classification.tip, Classification.warning:
case Classification.gagged, Classification.tip, Classification.warning, Classification.lint:
assert(0);
}
}();
Expand Down
82 changes: 80 additions & 2 deletions compiler/src/dmd/errors.d
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ import dmd.sarif;
nothrow:

/// Constants used to discriminate kinds of error messages.
extern (C++)
enum ErrorKind
{
warning,
deprecation,
error,
tip,
message,
lint,
}

/********************************
Expand Down Expand Up @@ -119,6 +121,7 @@ enum Classification : Color
warning = Color.brightYellow, /// for warnings
deprecation = Color.brightCyan, /// for deprecations
tip = Color.brightGreen, /// for tip messages
lint = Color.brightMagenta, /// for lint messages
}


Expand Down Expand Up @@ -221,6 +224,32 @@ extern(C++) void errorBackend(const(char)* filename, uint linnum, uint charnum,
va_end(ap);
}

/**
* Print a lint message with the prefix and highlighting.
* Does NOT increase error or warning counts.
* Params:
* loc = location of message
* ruleName = name of the lint rule to display in brackets
* format = printf-style format specification
* ... = printf-style variadic arguments
*/
static if (__VERSION__ < 2092)
extern (C++) void lint(Loc loc, const(char)* ruleName, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
vreportDiagnostic(loc, format, ap, ErrorKind.lint, ruleName);
va_end(ap);
}
else
pragma(printf) extern (C++) void lint(Loc loc, const(char)* ruleName, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
vreportDiagnostic(loc, format, ap, ErrorKind.lint, ruleName);
va_end(ap);
}

/**
* Print additional details about an error message.
* Doesn't increase the error count or print an additional error prefix.
Expand Down Expand Up @@ -577,6 +606,35 @@ private extern(C++) void vreportDiagnostic(const SourceLoc loc, const(char)* for
return;
}
return;

case ErrorKind.lint:
global.errors++;
if (!global.gag)
{
info.headerColor = Classification.lint;
if (global.params.v.messageStyle == MessageStyle.sarif)
{
addSarifDiagnostic(loc, format, ap, kind);
return;
}
printDiagnostic(format, ap, info);

if (global.params.v.errorLimit && global.errors >= global.params.v.errorLimit)
{
fprintf(stderr, "error limit (%d) reached, use `-verrors=0` to show all\n", global.params.v.errorLimit);
fatal();
}
}
else
{
if (global.params.v.showGaggedErrors)
{
info.headerColor = Classification.gagged;
printDiagnostic(format, ap, info);
}
global.gaggedErrors++;
}
return;
}
}

Expand Down Expand Up @@ -636,6 +694,16 @@ private extern(C++) void vsupplementalDiagnostic(const SourceLoc loc, const(char
}
return;

case ErrorKind.lint:
case ErrorKind.tip:
case ErrorKind.message:
if (!global.gag)
{
info.headerColor = Classification.lint;
printDiagnostic(format, ap, info);
}
return;

default:
assert(false, "internal error: unhandled kind in error report");
}
Expand Down Expand Up @@ -663,6 +731,7 @@ private void printDiagnostic(const(char)* format, va_list ap, ref DiagnosticCont
case ErrorKind.warning: header = "Warning: "; break;
case ErrorKind.tip: header = " Tip: "; break;
case ErrorKind.message: assert(0);
case ErrorKind.lint: header = "Lint: "; break;
}
}

Expand Down Expand Up @@ -694,8 +763,17 @@ private void printDiagnostic(const(char)* format, va_list ap, ref DiagnosticCont
tmp.reset();
if (info.p1)
{
tmp.writestring(info.p1);
tmp.writestring(" ");
if (info.kind == ErrorKind.lint)
{
tmp.writeByte('[');
tmp.writestring(info.p1);
tmp.writestring("] ");
}
else
{
tmp.writestring(info.p1);
tmp.writestring(" ");
}
}
if (info.p2)
{
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dmd/errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum class ErrorKind
error = 2,
tip = 3,
message = 4,
lint = 5,
};

#if defined(__GNUC__)
Expand All @@ -41,6 +42,7 @@ D_ATTRIBUTE_FORMAT(2, 3) void errorSupplemental(Loc loc, const char *format, ...
D_ATTRIBUTE_FORMAT(1, 2) void message(const char *format, ...);
D_ATTRIBUTE_FORMAT(2, 3) void message(Loc loc, const char *format, ...);
D_ATTRIBUTE_FORMAT(1, 2) void tip(const char *format, ...);
D_ATTRIBUTE_FORMAT(2, 3) void lint(Loc loc, const char *format, ...);

#if defined(__GNUC__) || defined(__clang__)
#define D_ATTRIBUTE_NORETURN __attribute__((noreturn))
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -7193,6 +7193,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}

auto vd = e.var.isVarDeclaration();
if (vd) vd.wasUsed = true;
auto fd = e.var.isFuncDeclaration();

if (fd)
Expand Down
30 changes: 29 additions & 1 deletion compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -6639,6 +6639,8 @@ class VarDeclaration : public Declaration
bool inAlignSection(bool v);
bool systemInferred() const;
bool systemInferred(bool v);
bool wasUsed() const;
bool wasUsed(bool v);
private:
uint32_t bitFields;
public:
Expand Down Expand Up @@ -6973,6 +6975,14 @@ struct ModuleDeclaration final
}
};

enum class LintFlags : uint32_t
{
none = 0u,
constSpecial = 1u,
unusedParams = 2u,
all = 4294967295u,
};

struct Scope final
{
Scope* enclosing;
Expand Down Expand Up @@ -7047,6 +7057,7 @@ struct Scope final
bool explicitVisibility() const;
bool explicitVisibility(bool v);
Previews previews;
LintFlags lintFlags;
UserAttributeDeclaration* userAttribDecl;
void* lastdc;
void* anchorCounts;
Expand Down Expand Up @@ -7092,7 +7103,7 @@ struct Scope final
argStruct()
{
}
Scope(Scope* enclosing, Module* _module = nullptr, ScopeDsymbol* scopesym = nullptr, FuncDeclaration* func = nullptr, VarDeclaration* varDecl = nullptr, Dsymbol* parent = nullptr, LabelStatement* slabel = nullptr, SwitchStatement* switchStatement = nullptr, Statement* tryBody = nullptr, TryFinallyStatement* tryFinally = nullptr, ScopeGuardStatement* scopeGuard = nullptr, Statement* sbreak = nullptr, Statement* scontinue = nullptr, ForeachStatement* fes = nullptr, Scope* callsc = nullptr, Dsymbol* inunion = nullptr, VarDeclaration* lastVar = nullptr, ErrorSink* eSink = nullptr, Module* minst = nullptr, TemplateInstance* tinst = nullptr, CtorFlow ctorflow = CtorFlow(), AlignDeclaration* aligndecl = nullptr, CPPNamespaceDeclaration* namespace_ = nullptr, LINK linkage = (LINK)1u, CPPMANGLE cppmangle = (CPPMANGLE)0u, PragmaDeclaration* inlining = nullptr, Visibility visibility = Visibility((Visibility::Kind)5u, nullptr), STC stc = (STC)0LLU, DeprecatedDeclaration* depdecl = nullptr, uint16_t bitFields = 0u, uint16_t bitFields2 = 0u, Previews previews = Previews(), UserAttributeDeclaration* userAttribDecl = nullptr, void* lastdc = nullptr, void* anchorCounts = nullptr, Identifier* prevAnchor = nullptr, AliasDeclaration* aliasAsg = nullptr, StructDeclaration* argStruct = nullptr) :
Scope(Scope* enclosing, Module* _module = nullptr, ScopeDsymbol* scopesym = nullptr, FuncDeclaration* func = nullptr, VarDeclaration* varDecl = nullptr, Dsymbol* parent = nullptr, LabelStatement* slabel = nullptr, SwitchStatement* switchStatement = nullptr, Statement* tryBody = nullptr, TryFinallyStatement* tryFinally = nullptr, ScopeGuardStatement* scopeGuard = nullptr, Statement* sbreak = nullptr, Statement* scontinue = nullptr, ForeachStatement* fes = nullptr, Scope* callsc = nullptr, Dsymbol* inunion = nullptr, VarDeclaration* lastVar = nullptr, ErrorSink* eSink = nullptr, Module* minst = nullptr, TemplateInstance* tinst = nullptr, CtorFlow ctorflow = CtorFlow(), AlignDeclaration* aligndecl = nullptr, CPPNamespaceDeclaration* namespace_ = nullptr, LINK linkage = (LINK)1u, CPPMANGLE cppmangle = (CPPMANGLE)0u, PragmaDeclaration* inlining = nullptr, Visibility visibility = Visibility((Visibility::Kind)5u, nullptr), STC stc = (STC)0LLU, DeprecatedDeclaration* depdecl = nullptr, uint16_t bitFields = 0u, uint16_t bitFields2 = 0u, Previews previews = Previews(), LintFlags lintFlags = (LintFlags)0u, UserAttributeDeclaration* userAttribDecl = nullptr, void* lastdc = nullptr, void* anchorCounts = nullptr, Identifier* prevAnchor = nullptr, AliasDeclaration* aliasAsg = nullptr, StructDeclaration* argStruct = nullptr) :
enclosing(enclosing),
_module(_module),
scopesym(scopesym),
Expand Down Expand Up @@ -7125,6 +7136,7 @@ struct Scope final
bitFields(bitFields),
bitFields2(bitFields2),
previews(previews),
lintFlags(lintFlags),
userAttribDecl(userAttribDecl),
lastdc(lastdc),
anchorCounts(anchorCounts),
Expand Down Expand Up @@ -7979,6 +7991,15 @@ extern bool c_isxdigit(const int32_t c);

extern bool c_isalnum(const int32_t c);

enum class ErrorKind
{
warning = 0,
deprecation = 1,
error = 2,
tip = 3,
message = 4,
lint = 5,
};
extern bool isAlphaASCII(const char32_t c);

extern void error(Loc loc, const char* format, ...);
Expand All @@ -7987,6 +8008,8 @@ extern void error(const char* filename, uint32_t linnum, uint32_t charnum, const

extern void errorBackend(const char* filename, uint32_t linnum, uint32_t charnum, const char* format, ...);

extern void lint(Loc loc, const char* ruleName, const char* format, ...);

extern void errorSupplemental(Loc loc, const char* format, ...);

extern void warning(Loc loc, const char* format, ...);
Expand Down Expand Up @@ -8715,6 +8738,11 @@ struct Id final
static Identifier* Pinline;
static Identifier* lib;
static Identifier* linkerDirective;
static Identifier* lint;
static Identifier* constSpecial;
static Identifier* unusedParams;
static Identifier* none;
static Identifier* all;
static Identifier* mangle;
static Identifier* msg;
static Identifier* startaddress;
Expand Down
5 changes: 5 additions & 0 deletions compiler/src/dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@ immutable Msgtable[] msgtable =
{ "Pinline", "inline" },
{ "lib" },
{ "linkerDirective" },
{ "lint" },
{ "constSpecial" },
{ "unusedParams" },
{ "none" },
{ "all" },
{ "mangle" },
{ "msg" },
{ "startaddress" },
Expand Down
7 changes: 7 additions & 0 deletions compiler/src/dmd/pragmasem.d
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc)
.error(pd.loc, "%s `%s` takes no argument", pd.kind, pd.toPrettyChars);
return declarations();
}
else if (pd.ident == Id.lint)
{
return declarations();
}
else if (!global.params.ignoreUnsupportedPragmas)
{
error(pd.loc, "unrecognized `pragma(%s)`", pd.ident.toChars());
Expand Down Expand Up @@ -329,6 +333,9 @@ bool pragmaStmtSemantic(PragmaStatement ps, Scope* sc)
if (!pragmaMangleSemantic(ps.loc, sc, ps.args, decls.length ? &decls : null))
return false;
}
else if (ps.ident == Id.lint)
{
}
else if (!global.params.ignoreUnsupportedPragmas)
{
error(ps.loc, "unrecognized `pragma(%s)`", ps.ident.toChars());
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/sarif.d
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ string errorKindToString(ErrorKind kind) nothrow
case ErrorKind.deprecation: return "note"; // Minor problem, opportunity for improvement
case ErrorKind.tip: return "note"; // Minor improvement suggestion
case ErrorKind.message: return "none"; // Not applicable for "fail" kind, so use "none"
case ErrorKind.lint: return "note";
}
}

Expand Down
Loading
Loading