1 // Copyright The dlang community - 2018 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 module dscanner.analysis.trust_too_much; 7 8 import std.stdio; 9 import dparse.ast; 10 import dparse.lexer; 11 import dscanner.analysis.base; 12 import dsymbol.scope_; 13 14 /** 15 * Checks that `@trusted` is only applied to a a single function 16 */ 17 class TrustTooMuchCheck : BaseAnalyzer 18 { 19 private: 20 21 static immutable MESSAGE = "Trusting a whole scope is a bad idea, " ~ 22 "`@trusted` should only be attached to the functions individually"; 23 static immutable string KEY = "dscanner.trust_too_much"; 24 25 bool checkAtAttribute = true; 26 27 public: 28 29 alias visit = BaseAnalyzer.visit; 30 31 /// 32 this(string fileName, bool skipTests = false) 33 { 34 super(fileName, sc, skipTests); 35 } 36 37 override void visit(const AtAttribute d) 38 { 39 if (checkAtAttribute && d.identifier.text == "trusted") 40 { 41 const Token t = d.identifier; 42 addErrorMessage(t.line, t.column, KEY, MESSAGE); 43 } 44 d.accept(this); 45 } 46 47 // always applied to function body, so OK 48 override void visit(const MemberFunctionAttribute d) 49 { 50 const oldCheckAtAttribute = checkAtAttribute; 51 checkAtAttribute = false; 52 d.accept(this); 53 checkAtAttribute = oldCheckAtAttribute; 54 } 55 56 // handles `@trusted{}` and old style, leading, atAttribute for single funcs 57 override void visit(const Declaration d) 58 { 59 const oldCheckAtAttribute = checkAtAttribute; 60 checkAtAttribute = d.functionDeclaration is null; 61 d.accept(this); 62 checkAtAttribute = oldCheckAtAttribute; 63 } 64 65 // issue #588 66 override void visit(const AliasDeclaration d) 67 { 68 const oldCheckAtAttribute = checkAtAttribute; 69 checkAtAttribute = false; 70 d.accept(this); 71 checkAtAttribute = oldCheckAtAttribute; 72 } 73 } 74 75 unittest 76 { 77 import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 78 import dscanner.analysis.helpers : assertAnalyzerWarnings; 79 import std.format : format; 80 81 StaticAnalysisConfig sac = disabledConfig(); 82 sac.trust_too_much = Check.enabled; 83 const msg = TrustTooMuchCheck.MESSAGE; 84 85 //--- fail cases ---// 86 87 assertAnalyzerWarnings(q{ 88 @trusted: // [warn]: %s 89 void test(); 90 }c.format(msg), sac); 91 92 assertAnalyzerWarnings(q{ 93 @trusted @nogc: // [warn]: %s 94 void test(); 95 }c.format(msg), sac); 96 97 assertAnalyzerWarnings(q{ 98 @trusted { // [warn]: %s 99 void test(); 100 void test(); 101 } 102 }c.format(msg), sac); 103 104 assertAnalyzerWarnings(q{ 105 @safe { 106 @trusted @nogc { // [warn]: %s 107 void test(); 108 void test(); 109 }} 110 }c.format(msg), sac); 111 112 assertAnalyzerWarnings(q{ 113 @nogc @trusted { // [warn]: %s 114 void test(); 115 void test(); 116 } 117 }c.format(msg), sac); 118 119 assertAnalyzerWarnings(q{ 120 @trusted template foo(){ // [warn]: %s 121 } 122 }c.format(msg), sac); 123 124 assertAnalyzerWarnings(q{ 125 struct foo{ 126 @trusted: // [warn]: %s 127 } 128 }c.format(msg), sac); 129 //--- pass cases ---// 130 131 assertAnalyzerWarnings(q{ 132 void test() @trusted {} 133 }c, sac); 134 135 assertAnalyzerWarnings(q{ 136 @trusted void test(); 137 }c, sac); 138 139 assertAnalyzerWarnings(q{ 140 @nogc template foo(){ 141 } 142 }c , sac); 143 144 assertAnalyzerWarnings(q{ 145 alias nothrow @trusted uint F4(); 146 }c , sac); 147 148 stderr.writeln("Unittest for TrustTooMuchCheck passed."); 149 }