From 890d23aeca60e7ebf478a568b4248eaa274d8744 Mon Sep 17 00:00:00 2001 From: Sergii K Date: Tue, 17 Mar 2026 15:10:30 +0300 Subject: [PATCH] Refactoring add pragma lint (#74) (#75) * Refactoring add pragma lint (#72) * fix .h * Refactoring st3 (#65) * fix extern (C++) * Auto-update C++ headers via dtoh * make refactoring (#68) * Refactoring add pragma lint v6 (#70) * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * Refactoring add pragma lint v6 (#71) * Refactoring add pragma lint v5 (#69) * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * Refactoring add pragma lint v6 (#70) (#64) * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * add unusedParams * update *.h * refactoring --- compiler/src/dmd/declaration.d | 1 + compiler/src/dmd/dscope.d | 11 +++ compiler/src/dmd/dsymbolsem.d | 27 +++++- compiler/src/dmd/dtemplate.d | 2 +- compiler/src/dmd/errors.d | 82 ++++++++++++++++++- compiler/src/dmd/errors.h | 2 + compiler/src/dmd/expressionsem.d | 1 + compiler/src/dmd/frontend.h | 31 ++++++- compiler/src/dmd/id.d | 5 ++ compiler/src/dmd/pragmasem.d | 7 ++ compiler/src/dmd/sarif.d | 1 + compiler/src/dmd/semantic3.d | 66 ++++++++++++++- .../fail_compilation/lint_const_special.d | 74 +++++++++++++++++ .../fail_compilation/lint_unused_params.d | 72 ++++++++++++++++ 14 files changed, 376 insertions(+), 6 deletions(-) create mode 100644 compiler/test/fail_compilation/lint_const_special.d create mode 100644 compiler/test/fail_compilation/lint_unused_params.d diff --git a/compiler/src/dmd/declaration.d b/compiler/src/dmd/declaration.d index e1a4f9bf656c..050579ac5836 100644 --- a/compiler/src/dmd/declaration.d +++ b/compiler/src/dmd/declaration.d @@ -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; diff --git a/compiler/src/dmd/dscope.d b/compiler/src/dmd/dscope.d index f6be0f82730a..0b48e8c51ffc 100644 --- a/compiler/src/dmd/dscope.d +++ b/compiler/src/dmd/dscope.d @@ -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 { @@ -186,6 +195,8 @@ extern (C++) struct Scope mixin(generateBitFields!(NonFlagBitFields, ushort, "bitFields2")); Previews previews; + LintFlags lintFlags; + // user defined attributes UserAttributeDeclaration userAttribDecl; diff --git a/compiler/src/dmd/dsymbolsem.d b/compiler/src/dmd/dsymbolsem.d index 76e5260444b3..bfa0fb867649 100644 --- a/compiler/src/dmd/dsymbolsem.d +++ b/compiler/src/dmd/dsymbolsem.d @@ -8869,8 +8869,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. */ diff --git a/compiler/src/dmd/dtemplate.d b/compiler/src/dmd/dtemplate.d index c2bcb0d491ec..a5d4f8af0b00 100644 --- a/compiler/src/dmd/dtemplate.d +++ b/compiler/src/dmd/dtemplate.d @@ -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); } }(); diff --git a/compiler/src/dmd/errors.d b/compiler/src/dmd/errors.d index a6f63dc40f0c..9f04942a1f43 100644 --- a/compiler/src/dmd/errors.d +++ b/compiler/src/dmd/errors.d @@ -29,6 +29,7 @@ import dmd.sarif; nothrow: /// Constants used to discriminate kinds of error messages. +extern (C++) enum ErrorKind { warning, @@ -36,6 +37,7 @@ enum ErrorKind error, tip, message, + lint, } /******************************** @@ -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 } @@ -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. @@ -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; } } @@ -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"); } @@ -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; } } @@ -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) { diff --git a/compiler/src/dmd/errors.h b/compiler/src/dmd/errors.h index 13a716c03026..a92e186e18cf 100644 --- a/compiler/src/dmd/errors.h +++ b/compiler/src/dmd/errors.h @@ -22,6 +22,7 @@ enum class ErrorKind error = 2, tip = 3, message = 4, + lint = 5, }; #if defined(__GNUC__) @@ -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)) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 725fc718ad3c..cca9b222962b 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -7183,6 +7183,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) diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index c4439b55b655..48aa08d9796a 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -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: @@ -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; @@ -7047,6 +7057,7 @@ struct Scope final bool explicitVisibility() const; bool explicitVisibility(bool v); Previews previews; + LintFlags lintFlags; UserAttributeDeclaration* userAttribDecl; void* lastdc; void* anchorCounts; @@ -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), @@ -7125,6 +7136,7 @@ struct Scope final bitFields(bitFields), bitFields2(bitFields2), previews(previews), + lintFlags(lintFlags), userAttribDecl(userAttribDecl), lastdc(lastdc), anchorCounts(anchorCounts), @@ -7979,12 +7991,24 @@ 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 void error(Loc loc, const char* format, ...); extern void error(const char* filename, uint32_t linnum, uint32_t charnum, const char* format, ...); 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, ...); @@ -8713,6 +8737,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; diff --git a/compiler/src/dmd/id.d b/compiler/src/dmd/id.d index 4ac0f4f3d5e6..b4a979a82ca2 100644 --- a/compiler/src/dmd/id.d +++ b/compiler/src/dmd/id.d @@ -307,6 +307,11 @@ immutable Msgtable[] msgtable = { "Pinline", "inline" }, { "lib" }, { "linkerDirective" }, + { "lint" }, + { "constSpecial" }, + { "unusedParams" }, + { "none" }, + { "all" }, { "mangle" }, { "msg" }, { "startaddress" }, diff --git a/compiler/src/dmd/pragmasem.d b/compiler/src/dmd/pragmasem.d index d94414d9b5f3..65af9a9237ee 100644 --- a/compiler/src/dmd/pragmasem.d +++ b/compiler/src/dmd/pragmasem.d @@ -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()); @@ -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()); diff --git a/compiler/src/dmd/sarif.d b/compiler/src/dmd/sarif.d index e7f48bda3c44..26144ca5cfde 100644 --- a/compiler/src/dmd/sarif.d +++ b/compiler/src/dmd/sarif.d @@ -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"; } } diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index 234782645487..3ee5e92f3b05 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -95,6 +95,61 @@ void semantic3(Dsymbol dsym, Scope* sc) dsym.accept(v); } +/*************************************** + * Checks if a special method should be marked as `const` and emits a lint warning. + */ +private void lintConstSpecial(FuncDeclaration fd, bool isKnownStructMember = false) +{ + if (!fd || !fd._scope || !(fd._scope.lintFlags & LintFlags.constSpecial)) + return; + + if (fd.isGenerated() || (fd.storage_class & STC.const_) || fd.type.isConst()) + return; + + if (!isKnownStructMember) + { + if (fd.ident != Id.opEquals && fd.ident != Id.opCmp && + fd.ident != Id.tohash && fd.ident != Id.tostring) + return; + + if (!fd.toParent2() || !fd.toParent2().isStructDeclaration()) + return; + } + + import dmd.errors : lint; + + lint(fd.loc, "constSpecial".ptr, "special method `%s` should be marked as `const`".ptr, fd.ident ? fd.ident.toChars() : fd.toChars()); +} + +/*************************************** + * Checks for unused parameters in a function and emits a lint warning. + */ +private void lintUnusedParams(FuncDeclaration funcdecl) +{ + if (!funcdecl || !funcdecl._scope || !(funcdecl._scope.lintFlags & LintFlags.unusedParams)) + return; + + if (!funcdecl.fbody || !funcdecl.parameters) + return; + + const bool isRequiredByInterface = funcdecl.isOverride() || + (funcdecl.isVirtual() && !funcdecl.isFinal()); + + if (isRequiredByInterface) + return; + + foreach (v; *funcdecl.parameters) + { + bool isIgnoredName = v.ident && v.ident.toChars()[0] == '_'; + + if (v.ident && !v.wasUsed && !(v.storage_class & STC.temp) && !isIgnoredName) + { + import dmd.errors : lint; + lint(v.loc, "unusedParams".ptr, "function parameter `%s` is never used".ptr, v.ident.toChars()); + } + } +} + private extern(C++) final class Semantic3Visitor : Visitor { alias visit = Visitor.visit; @@ -296,6 +351,8 @@ private extern(C++) final class Semantic3Visitor : Visitor funcdecl.hasSemantic3Errors = false; funcdecl.saferD = sc.previews.safer && !sc.inCfile; + lintConstSpecial(funcdecl); + if (!funcdecl.type || funcdecl.type.ty != Tfunction) return; TypeFunction f = cast(TypeFunction)funcdecl.type; @@ -1441,15 +1498,19 @@ private extern(C++) final class Semantic3Visitor : Visitor } } + lintUnusedParams(funcdecl); + /* If this function had instantiated with gagging, error reproduction will be * done by TemplateInstance::semantic. * Otherwise, error gagging should be temporarily ungagged by functionSemantic3. */ funcdecl.semanticRun = PASS.semantic3done; + if ((global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement())) funcdecl.hasSemantic3Errors = true; else funcdecl.hasSemantic3Errors = false; + if (funcdecl.type.ty == Terror) funcdecl.errors = true; //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), sc, funcdecl.loc.toChars()); @@ -1778,6 +1839,8 @@ void semanticTypeInfoMembers(StructDeclaration sd) { if (fd && fd._scope && fd.semanticRun < PASS.semantic3done) { + lintConstSpecial(fd, true); + const errors = global.startGagging(); fd.semantic3(fd._scope); if (global.endGagging(errors)) @@ -1788,12 +1851,12 @@ void semanticTypeInfoMembers(StructDeclaration sd) runSemantic(sd.xeq, sd.xerreq); runSemantic(sd.xcmp, sd.xerrcmp); - FuncDeclaration ftostr = search_toString(sd); if (ftostr && ftostr._scope && ftostr.semanticRun < PASS.semantic3done) { + lintConstSpecial(ftostr, true); ftostr.semantic3(ftostr._scope); } @@ -1801,6 +1864,7 @@ void semanticTypeInfoMembers(StructDeclaration sd) sd.xhash._scope && sd.xhash.semanticRun < PASS.semantic3done) { + lintConstSpecial(sd.xhash, true); sd.xhash.semantic3(sd.xhash._scope); } diff --git a/compiler/test/fail_compilation/lint_const_special.d b/compiler/test/fail_compilation/lint_const_special.d new file mode 100644 index 000000000000..5335e7cae4d5 --- /dev/null +++ b/compiler/test/fail_compilation/lint_const_special.d @@ -0,0 +1,74 @@ +/* +REQUIRED_ARGS: -w +TEST_OUTPUT: +--- +fail_compilation/lint_const_special.d(18): Lint: [constSpecial] special method `opEquals` should be marked as `const` +fail_compilation/lint_const_special.d(23): Lint: [constSpecial] special method `toHash` should be marked as `const` +fail_compilation/lint_const_special.d(28): Lint: [constSpecial] special method `opCmp` should be marked as `const` +fail_compilation/lint_const_special.d(33): Lint: [constSpecial] special method `toString` should be marked as `const` +--- +*/ + +// Enable our new lint rule for the file +pragma(lint, constSpecial): + +struct BadStruct +{ + // LINT: special method `opEquals` should be marked as `const` + bool opEquals(ref const BadStruct rhs) { + return true; + } + + // LINT: special method `toHash` should be marked as `const` + hash_t toHash() { + return 0; + } + + // LINT: special method `opCmp` should be marked as `const` + int opCmp(ref const BadStruct rhs) { + return 0; + } + + // LINT: special method `toString` should be marked as `const` + string toString() { + return "BadStruct"; + } +} + +struct GoodStruct +{ + // OK: method is marked as const + bool opEquals(ref const GoodStruct rhs) const { + return true; + } + + // OK: method is marked as const + hash_t toHash() const { + return 1; + } + + // OK: method is marked as const + int opCmp(ref const GoodStruct rhs) const { + return 0; + } + + // OK: method is marked as const + string toString() const { + return "GoodStruct"; + } +} + +// Disable the linter for the following code +pragma(lint, none): + +struct IgnoredStruct +{ + // No lint messages here, as the linter is disabled! + bool opEquals(ref const IgnoredStruct rhs) { + return true; + } +} + +void main() +{ +} diff --git a/compiler/test/fail_compilation/lint_unused_params.d b/compiler/test/fail_compilation/lint_unused_params.d new file mode 100644 index 000000000000..aae840de73c4 --- /dev/null +++ b/compiler/test/fail_compilation/lint_unused_params.d @@ -0,0 +1,72 @@ +/* +REQUIRED_ARGS: -w +TEST_OUTPUT: +--- +fail_compilation/lint_unused_params.d(17): Lint: [unusedParams] function parameter `y` is never used +fail_compilation/lint_unused_params.d(36): Lint: [unusedParams] function parameter `b` is never used +fail_compilation/lint_unused_params.d(52): Lint: [unusedParams] function parameter `b` is never used +fail_compilation/lint_unused_params.d(64): Lint: [unusedParams] function parameter `z` is never used +fail_compilation/lint_unused_params.d(43): Lint: [unusedParams] function parameter `y` is never used +fail_compilation/lint_unused_params.d(47): Error: template instance `lint_unused_params.tplFunc!int` error instantiating +--- +*/ + +pragma(lint, unusedParams): + +// 1. Regular functions +void testBasic(int x, int y) +{ + cast(void)x; +} + +// 2. Interfaces and abstract methods (no body - ignored) +interface I { void ifaceMethod(int a); } +abstract class AbstractBase { abstract void absMethod(int a); } + +// 3. Virtual and overridden methods (ignored) +class Base { void foo(int a) {} } +class Derived : Base +{ + override void foo(int a) {} +} + +// 4. Final methods (cannot be overridden, so parameters must be used) +class Normal +{ + final void bar(int a, int b) + { + cast(void)a; + } +} + +// 5. Template functions (checked upon instantiation) +void tplFunc(T)(T x, T y) +{ + cast(void)x; +} +alias instantiateTpl = tplFunc!int; + +// 6. Delegates and lambdas +void testDelegate() +{ + auto dg = (int a, int b) { + cast(void)a; + }; +} + +// 7. Unnamed parameters (ignored by the compiler as they have STC.temp) +void unnamedParam(int, int x) +{ + cast(void)x; +} + +// 8. Default parameters +void defaultArg(int x = 5, int z = 10) +{ + cast(void)x; +} + +// 9. Disable linter for the rest of the file +pragma(lint, none): + +void completelyIgnored(int a) {}