diff --git a/CheckOther.cpp b/CheckOther.cpp index 92adbc9e2..f65e3b620 100644 --- a/CheckOther.cpp +++ b/CheckOther.cpp @@ -517,5 +517,92 @@ void CheckUnsignedDivision() declvar = findtoken(declvar->next, pattern_declvar); } } +//--------------------------------------------------------------------------- + + + +//--------------------------------------------------------------------------- +// Check scope of variables.. +//--------------------------------------------------------------------------- + +static void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] ); + +void CheckVariableScope() +{ + // Walk through all tokens.. + bool func = false; + int indentlevel = 0; + for ( TOKEN *tok = tokens; tok; tok = tok->next ) + { + if ( tok->str[0] == '{' ) + { + indentlevel++; + } + if ( tok->str[0] == '}' ) + { + indentlevel--; + if ( indentlevel == 0 ) + func = false; + } + if ( indentlevel == 0 && match(tok, ") {") ) + { + func = true; + } + if ( indentlevel > 0 && func && strchr("{};", tok->str[0]) ) + { + // Variable declaration? + if (match(tok->next, "var var ;")) + CheckVariableScope_LookupVar( tok->next, getstr(tok, 2) ); + + // Variable declaration? + else if (match(tok->next, "var var =")) + CheckVariableScope_LookupVar( tok->next, getstr(tok, 2) ); + } + } + +} +//--------------------------------------------------------------------------- + +static void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] ) +{ + const TOKEN *tok = tok1; + + // Skip the variable declaration.. + tok = tok->next; + while ( tok->str[0] != ';' ) + tok = tok->next; + + // Check if the variable is used in this indentlevel.. + bool used = false; + int indentlevel = 0; + while ( indentlevel >= 0 && tok ) + { + if ( tok->str[0] == '{' ) + { + indentlevel++; + } + + else if ( tok->str[0] == '}' ) + { + indentlevel--; + } + + else if ( strcmp(tok->str, varname) == 0 ) + { + if ( indentlevel == 0 ) + return; + used = true; + } + + tok = tok->next; + } + + // Warning if "used" is true + std::ostringstream errmsg; + errmsg << FileLine(tok1) << " The scope of the variable '" << varname << "' can be limited"; + ReportErr( errmsg.str() ); +} +//--------------------------------------------------------------------------- + diff --git a/CheckOther.h b/CheckOther.h index 5beb5a4cb..c9bded78d 100644 --- a/CheckOther.h +++ b/CheckOther.h @@ -37,6 +37,9 @@ void CheckCaseWithoutBreak(); // Check for unsigned division that might create bad results void CheckUnsignedDivision(); +// Check scope of variables +void CheckVariableScope(); + //--------------------------------------------------------------------------- #endif diff --git a/CommonCheck.cpp b/CommonCheck.cpp index 03535a58e..d4feb9c47 100644 --- a/CommonCheck.cpp +++ b/CommonCheck.cpp @@ -11,7 +11,7 @@ bool OnlyReportUniqueErrors; std::ostringstream errout; //--------------------------------------------------------------------------- -std::string FileLine(TOKEN *tok) +std::string FileLine(const TOKEN *tok) { std::ostringstream ostr; ostr << "[" << Files[tok->FileIndex] << ":" << tok->linenr << "]"; diff --git a/CommonCheck.h b/CommonCheck.h index dde08765e..89af51034 100644 --- a/CommonCheck.h +++ b/CommonCheck.h @@ -8,7 +8,7 @@ struct TOKEN; -std::string FileLine(TOKEN *tok); +std::string FileLine(const TOKEN *tok); extern bool OnlyReportUniqueErrors; diff --git a/tests.cpp b/tests.cpp index 1e1a2a946..ce88c0e86 100644 --- a/tests.cpp +++ b/tests.cpp @@ -714,5 +714,26 @@ static void unused_variable() "}\n"; + // Scope of variable.. + const char test2[] = "void f()\n" + "{\n" + " int i;\n" + " if (abc)\n" + " {\n" + " i = 1;\n" + " }\n" + "}\n"; + check( CheckVariableScope, __LINE__, test2, "[test.cpp:3] The scope of the variable 'i' can be limited\n" ); +/* + const char test3[] = "void f()\n" + "{\n" + " int i = 0;\n" + " while (abc)\n" + " {\n" + " i = i + 1;\n" + " }\n" + "}\n"; + check( CheckVariableScope, __LINE__, test3, "" ); +*/ } diff --git a/tokenize.cpp b/tokenize.cpp index f9414dcdf..994263eb9 100644 --- a/tokenize.cpp +++ b/tokenize.cpp @@ -1018,12 +1018,12 @@ TOKEN *findtoken(TOKEN *tok1, const char *tokenstr[]) } //--------------------------------------------------------------------------- -bool match(TOKEN *tok, const std::string pattern) +bool match(const TOKEN *tok, const char pattern[]) { if (!tok) return false; - const char *p = pattern.c_str(); + const char *p = pattern; while (*p) { char str[50]; diff --git a/tokenize.h b/tokenize.h index ad48deb43..14f3a4944 100644 --- a/tokenize.h +++ b/tokenize.h @@ -36,7 +36,7 @@ void DeallocateTokens(); // Helper functions for handling the tokens list.. TOKEN *findtoken(TOKEN *tok1, const char *tokenstr[]); -bool match(TOKEN *tok, const std::string pattern); +bool match(const TOKEN *tok, const char pattern[]); TOKEN *gettok(TOKEN *tok, int index); const char *getstr(TOKEN *tok, int index);