1 // Distributed under the Boost Software License, Version 1.0. 2 // (See accompanying file LICENSE_1_0.txt or copy at 3 // http://www.boost.org/LICENSE_1_0.txt) 4 5 module analysis.label_var_same_name_check; 6 7 import std.d.ast; 8 import std.d.lexer; 9 10 import analysis.base; 11 import analysis.helpers; 12 13 /** 14 * Checks for labels and variables that have the same name. 15 */ 16 class LabelVarNameCheck : BaseAnalyzer 17 { 18 this(string fileName) 19 { 20 super(fileName); 21 } 22 23 override void visit(const Module mod) 24 { 25 pushScope(); 26 mod.accept(this); 27 popScope(); 28 } 29 30 override void visit(const BlockStatement block) 31 { 32 pushScope(); 33 block.accept(this); 34 popScope(); 35 } 36 37 override void visit(const StructBody structBody) 38 { 39 pushScope(); 40 structBody.accept(this); 41 popScope(); 42 } 43 44 override void visit(const VariableDeclaration var) 45 { 46 foreach (dec; var.declarators) 47 duplicateCheck(dec.name, false); 48 } 49 50 override void visit(const LabeledStatement labeledStatement) 51 { 52 duplicateCheck(labeledStatement.identifier, true); 53 if (labeledStatement.declarationOrStatement !is null) 54 labeledStatement.declarationOrStatement.accept(this); 55 } 56 57 alias visit = BaseAnalyzer.visit; 58 59 private: 60 61 Thing[string][] stack; 62 63 void duplicateCheck(const Token name, bool fromLabel) 64 { 65 import std.conv : to; 66 const(Thing)* thing = name.text in currentScope; 67 if (thing is null) 68 currentScope[name.text] = Thing(name.text, name.line, name.column, false); 69 else 70 { 71 immutable thisKind = fromLabel ? "Label" : "Variable"; 72 immutable otherKind = thing.isVar ? "variable" : "label"; 73 addErrorMessage(name.line, name.column, "dscanner.suspicious.label_var_same_name", 74 thisKind ~ " \"" ~ name.text ~ "\" has the same name as a " 75 ~ otherKind ~ " defined on line " ~ to!string(thing.line) ~ "."); 76 } 77 } 78 79 static struct Thing 80 { 81 string name; 82 size_t line; 83 size_t column; 84 bool isVar; 85 } 86 87 ref currentScope() @property 88 { 89 return stack[$-1]; 90 } 91 92 void pushScope() 93 { 94 stack.length++; 95 } 96 97 void popScope() 98 { 99 stack.length--; 100 } 101 } 102 103 unittest 104 { 105 import analysis.config : StaticAnalysisConfig; 106 import std.stdio : stderr; 107 108 StaticAnalysisConfig sac; 109 sac.label_var_same_name_check = true; 110 assertAnalyzerWarnings(q{ 111 unittest 112 { 113 blah: 114 int blah; // [warn]: Variable "blah" has the same name as a label defined on line 4. 115 } 116 int blah; 117 }}, sac); 118 stderr.writeln("Unittest for LabelVarNameCheck passed."); 119 }