1 // Copyright (c) 2018, dlang-community 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.redundant_storage_class; 7 8 import std.stdio; 9 import std..string; 10 import dparse.ast; 11 import dparse.lexer; 12 import dscanner.analysis.base; 13 import dscanner.analysis.helpers; 14 import dsymbol.scope_ : Scope; 15 16 /** 17 * Checks for redundant storage classes such immutable and __gshared, static and __gshared 18 */ 19 class RedundantStorageClassCheck : BaseAnalyzer 20 { 21 alias visit = BaseAnalyzer.visit; 22 enum string REDUNDANT_VARIABLE_ATTRIBUTES = "Variable declaration for `%s` has redundant attributes (%-(`%s`%|, %))."; 23 24 this(string fileName, bool skipTests = false) 25 { 26 super(fileName, null, skipTests); 27 } 28 29 override void visit(const Declaration node) 30 { 31 checkAttributes(node); 32 node.accept(this); 33 } 34 35 void checkAttributes(const Declaration node) 36 { 37 if (node.variableDeclaration !is null && node.attributes !is null) 38 checkVariableDeclaration(node.variableDeclaration, node.attributes); 39 } 40 41 void checkVariableDeclaration(const VariableDeclaration vd, const Attribute[] attributes) 42 { 43 import std.algorithm.comparison : among; 44 import std.algorithm.searching: all; 45 46 string[] globalAttributes; 47 foreach (attrib; attributes) 48 { 49 if (attrib.attribute.type.among(tok!"shared", tok!"static", tok!"__gshared", tok!"immutable")) 50 globalAttributes ~= attrib.attribute.type.str; 51 } 52 if (globalAttributes.length > 1) 53 { 54 if (globalAttributes.length == 2 && ( 55 globalAttributes.all!(a => a.among("shared", "static")) || 56 globalAttributes.all!(a => a.among("static", "immutable")) 57 )) 58 return; 59 auto t = vd.declarators[0].name; 60 string message = REDUNDANT_VARIABLE_ATTRIBUTES.format(t.text, globalAttributes); 61 addErrorMessage(t.line, t.column, "dscanner.unnecessary.duplicate_attribute", message); 62 } 63 } 64 } 65 66 unittest 67 { 68 import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 69 70 StaticAnalysisConfig sac = disabledConfig(); 71 sac.redundant_storage_classes = Check.enabled; 72 73 // https://github.com/dlang-community/D-Scanner/issues/438 74 assertAnalyzerWarnings(q{ 75 immutable int a; 76 77 immutable shared int a; // [warn]: %s 78 shared immutable int a; // [warn]: %s 79 80 immutable __gshared int a; // [warn]: %s 81 __gshared immutable int a; // [warn]: %s 82 83 __gshared static int a; // [warn]: %s 84 85 shared static int a; 86 static shared int a; 87 static immutable int a; 88 immutable static int a; 89 90 enum int a; 91 extern(C++) immutable int a; 92 immutable int function(immutable int, shared int) a; 93 }c.format( 94 RedundantStorageClassCheck.REDUNDANT_VARIABLE_ATTRIBUTES.format("a", ["immutable", "shared"]), 95 RedundantStorageClassCheck.REDUNDANT_VARIABLE_ATTRIBUTES.format("a", ["shared", "immutable"]), 96 RedundantStorageClassCheck.REDUNDANT_VARIABLE_ATTRIBUTES.format("a", ["immutable", "__gshared"]), 97 RedundantStorageClassCheck.REDUNDANT_VARIABLE_ATTRIBUTES.format("a", ["__gshared", "immutable"]), 98 RedundantStorageClassCheck.REDUNDANT_VARIABLE_ATTRIBUTES.format("a", ["__gshared", "static"]), 99 ), sac); 100 101 stderr.writeln("Unittest for RedundantStorageClassCheck passed."); 102 }