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