165 lines
3.5 KiB
D
165 lines
3.5 KiB
D
// Copyright The dlang community - 2018
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
module dscanner.analysis.trust_too_much;
|
|
|
|
import std.stdio;
|
|
import dparse.ast;
|
|
import dparse.lexer;
|
|
import dscanner.analysis.base;
|
|
import dsymbol.scope_;
|
|
|
|
/**
|
|
* Checks that `@trusted` is only applied to a a single function
|
|
*/
|
|
final class TrustTooMuchCheck : BaseAnalyzer
|
|
{
|
|
private:
|
|
|
|
static immutable MESSAGE = "Trusting a whole scope is a bad idea, " ~
|
|
"`@trusted` should only be attached to the functions individually";
|
|
static immutable string KEY = "dscanner.trust_too_much";
|
|
|
|
bool checkAtAttribute = true;
|
|
|
|
public:
|
|
|
|
alias visit = BaseAnalyzer.visit;
|
|
|
|
mixin AnalyzerInfo!"trust_too_much";
|
|
|
|
///
|
|
this(BaseAnalyzerArguments args)
|
|
{
|
|
super(args);
|
|
}
|
|
|
|
override void visit(const AtAttribute d)
|
|
{
|
|
if (checkAtAttribute && d.identifier.text == "trusted")
|
|
addErrorMessage(d, KEY, MESSAGE);
|
|
d.accept(this);
|
|
}
|
|
|
|
// always applied to function body, so OK
|
|
override void visit(const MemberFunctionAttribute d)
|
|
{
|
|
const oldCheckAtAttribute = checkAtAttribute;
|
|
checkAtAttribute = false;
|
|
d.accept(this);
|
|
checkAtAttribute = oldCheckAtAttribute;
|
|
}
|
|
|
|
// handles `@trusted{}` and old style, leading, atAttribute for single funcs
|
|
override void visit(const Declaration d)
|
|
{
|
|
const oldCheckAtAttribute = checkAtAttribute;
|
|
|
|
checkAtAttribute = d.functionDeclaration is null && d.unittest_ is null &&
|
|
d.constructor is null && d.destructor is null &&
|
|
d.staticConstructor is null && d.staticDestructor is null &&
|
|
d.sharedStaticConstructor is null && d.sharedStaticDestructor is null;
|
|
d.accept(this);
|
|
checkAtAttribute = oldCheckAtAttribute;
|
|
}
|
|
|
|
// issue #588
|
|
override void visit(const AliasDeclaration d)
|
|
{
|
|
const oldCheckAtAttribute = checkAtAttribute;
|
|
checkAtAttribute = false;
|
|
d.accept(this);
|
|
checkAtAttribute = oldCheckAtAttribute;
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
|
|
import dscanner.analysis.helpers : assertAnalyzerWarnings;
|
|
import std.format : format;
|
|
|
|
StaticAnalysisConfig sac = disabledConfig();
|
|
sac.trust_too_much = Check.enabled;
|
|
const msg = TrustTooMuchCheck.MESSAGE;
|
|
|
|
//--- fail cases ---//
|
|
|
|
assertAnalyzerWarnings(q{
|
|
@trusted: /+
|
|
^^^^^^^^ [warn]: %s +/
|
|
void test();
|
|
}c.format(msg), sac);
|
|
|
|
assertAnalyzerWarnings(q{
|
|
@trusted @nogc: /+
|
|
^^^^^^^^ [warn]: %s +/
|
|
void test();
|
|
}c.format(msg), sac);
|
|
|
|
assertAnalyzerWarnings(q{
|
|
@trusted { /+
|
|
^^^^^^^^ [warn]: %s +/
|
|
void test();
|
|
void test();
|
|
}
|
|
}c.format(msg), sac);
|
|
|
|
assertAnalyzerWarnings(q{
|
|
@safe {
|
|
@trusted @nogc { /+
|
|
^^^^^^^^ [warn]: %s +/
|
|
void test();
|
|
void test();
|
|
}}
|
|
}c.format(msg), sac);
|
|
|
|
assertAnalyzerWarnings(q{
|
|
@nogc @trusted { /+
|
|
^^^^^^^^ [warn]: %s +/
|
|
void test();
|
|
void test();
|
|
}
|
|
}c.format(msg), sac);
|
|
|
|
assertAnalyzerWarnings(q{
|
|
@trusted template foo(){ /+
|
|
^^^^^^^^ [warn]: %s +/
|
|
}
|
|
}c.format(msg), sac);
|
|
|
|
assertAnalyzerWarnings(q{
|
|
struct foo{
|
|
@trusted: /+
|
|
^^^^^^^^ [warn]: %s +/
|
|
}
|
|
}c.format(msg), sac);
|
|
//--- pass cases ---//
|
|
|
|
assertAnalyzerWarnings(q{
|
|
void test() @trusted {}
|
|
}c, sac);
|
|
|
|
assertAnalyzerWarnings(q{
|
|
@trusted void test();
|
|
}c, sac);
|
|
|
|
assertAnalyzerWarnings(q{
|
|
@nogc template foo(){
|
|
}
|
|
}c , sac);
|
|
|
|
assertAnalyzerWarnings(q{
|
|
alias nothrow @trusted uint F4();
|
|
}c , sac);
|
|
|
|
assertAnalyzerWarnings(q{
|
|
@trusted ~this();
|
|
@trusted this();
|
|
}c , sac);
|
|
|
|
stderr.writeln("Unittest for TrustTooMuchCheck passed.");
|
|
}
|