cppcheck/lib/checkother.h

408 lines
19 KiB
C
Raw Normal View History

/*
* Cppcheck - A tool for static C/C++ code analysis
2019-02-09 07:24:06 +01:00
* Copyright (C) 2007-2019 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
#ifndef checkotherH
#define checkotherH
//---------------------------------------------------------------------------
2009-03-20 18:16:21 +01:00
#include "check.h"
2017-05-27 04:33:47 +02:00
#include "config.h"
#include "valueflow.h"
#include <cstddef>
#include <string>
#include <vector>
2017-05-27 04:33:47 +02:00
class ErrorLogger;
class Settings;
class Token;
class Tokenizer;
class Variable;
2009-03-20 18:16:21 +01:00
/// @addtogroup Checks
/// @{
/** @brief Various small checks */
class CPPCHECKLIB CheckOther : public Check {
public:
/** @brief This constructor is used when registering the CheckClass */
2014-11-20 14:20:09 +01:00
CheckOther() : Check(myName()) {
}
2009-03-20 18:16:21 +01:00
2010-03-17 22:16:18 +01:00
/** @brief This constructor is used when running checks. */
2009-03-20 18:16:21 +01:00
CheckOther(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
2014-11-20 14:20:09 +01:00
: Check(myName(), tokenizer, settings, errorLogger) {
}
2009-03-20 18:16:21 +01:00
/** @brief Run checks against the normal token list */
void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) OVERRIDE {
CheckOther checkOther(tokenizer, settings, errorLogger);
// Checks
checkOther.warningOldStylePointerCast();
checkOther.invalidPointerCast();
checkOther.checkCharVariable();
checkOther.checkRedundantAssignment();
checkOther.checkRedundantAssignmentInSwitch();
checkOther.checkSuspiciousCaseInSwitch();
checkOther.checkDuplicateBranch();
checkOther.checkDuplicateExpression();
checkOther.checkUnreachableCode();
checkOther.checkSuspiciousSemicolon();
checkOther.checkVariableScope();
checkOther.checkSignOfUnsignedVariable(); // don't ignore casts (#3574)
checkOther.checkIncompleteArrayFill();
checkOther.checkVarFuncNullUB();
checkOther.checkNanInArithmeticExpression();
checkOther.checkCommaSeparatedReturn();
checkOther.checkRedundantPointerOp();
checkOther.checkZeroDivision();
checkOther.checkNegativeBitwiseShift();
checkOther.checkInterlockedDecrement();
checkOther.checkUnusedLabel();
checkOther.checkEvaluationOrder();
checkOther.checkFuncArgNamesDifferent();
2018-10-16 20:17:27 +02:00
checkOther.checkShadowVariables();
checkOther.checkConstArgument();
}
/** @brief Run checks against the simplified token list */
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) OVERRIDE {
2009-03-20 18:16:21 +01:00
CheckOther checkOther(tokenizer, settings, errorLogger);
// Checks
checkOther.clarifyCalculation();
checkOther.clarifyStatement();
checkOther.checkPassByReference();
checkOther.checkIncompleteStatement();
checkOther.checkCastIntToCharAndBack();
2009-03-20 18:16:21 +01:00
checkOther.checkMisusedScopedObject();
checkOther.checkPipeParameterSize();
checkOther.checkInvalidFree();
checkOther.checkRedundantCopy();
checkOther.checkSuspiciousEqualityComparison();
checkOther.checkComparisonFunctionIsAlwaysTrueOrFalse();
checkOther.checkAccessOfMovedVariable();
2009-03-20 18:16:21 +01:00
}
/** @brief Clarify calculation for ".. a * b ? .." */
void clarifyCalculation();
/** @brief Suspicious statement like '*A++;' */
void clarifyStatement();
/** @brief Are there C-style pointer casts in a c++ file? */
void warningOldStylePointerCast();
/** @brief Check for pointer casts to a type with an incompatible binary data representation */
void invalidPointerCast();
/** @brief %Check scope of variables */
void checkVariableScope();
static bool checkInnerScope(const Token *tok, const Variable* var, bool& used);
/** @brief %Check for comma separated statements in return */
void checkCommaSeparatedReturn();
/** @brief %Check for function parameters that should be passed by reference */
void checkPassByReference();
/** @brief Using char variable as array index / as operand in bit operation */
void checkCharVariable();
/** @brief Incomplete statement. A statement that only contains a constant or variable */
void checkIncompleteStatement();
/** @brief %Check zero division*/
void checkZeroDivision();
/** @brief Check for NaN (not-a-number) in an arithmetic expression */
void checkNanInArithmeticExpression();
/** @brief copying to memory or assigning to a variable twice */
void checkRedundantAssignment();
/** @brief %Check for assigning to the same variable twice in a switch statement*/
void checkRedundantAssignmentInSwitch();
/** @brief %Check for code like 'case A||B:'*/
void checkSuspiciousCaseInSwitch();
/** @brief %Check for code like 'case A||B:'*/
void checkSuspiciousEqualityComparison();
/** @brief %Check for objects that are destroyed immediately */
void checkMisusedScopedObject();
/** @brief %Check for suspicious code where if and else branch are the same (e.g "if (a) b = true; else b = true;") */
void checkDuplicateBranch();
/** @brief %Check for suspicious code with the same expression on both sides of operator (e.g "if (a && a)") */
void checkDuplicateExpression();
/** @brief %Check for code that gets never executed, such as duplicate break statements */
void checkUnreachableCode();
/** @brief %Check for testing sign of unsigned variable */
void checkSignOfUnsignedVariable();
/** @brief %Check for suspicious use of semicolon */
void checkSuspiciousSemicolon();
/** @brief %Check for free() operations on invalid memory locations */
void checkInvalidFree();
void invalidFreeError(const Token *tok, bool inconclusive);
/** @brief %Check for code creating redundant copies */
void checkRedundantCopy();
/** @brief %Check for bitwise shift with negative right operand */
void checkNegativeBitwiseShift();
/** @brief %Check for buffers that are filled incompletely with memset and similar functions */
void checkIncompleteArrayFill();
2013-02-27 21:05:18 +01:00
/** @brief %Check that variadic function calls don't use NULL. If NULL is \#defined as 0 and the function expects a pointer, the behaviour is undefined. */
void checkVarFuncNullUB();
/** @brief %Check that calling the POSIX pipe() system call is called with an integer array of size two. */
void checkPipeParameterSize();
/** @brief %Check to avoid casting a return value to unsigned char and then back to integer type. */
void checkCastIntToCharAndBack();
/** @brief %Check for using of comparison functions evaluating always to true or false. */
void checkComparisonFunctionIsAlwaysTrueOrFalse();
/** @brief %Check for redundant pointer operations */
void checkRedundantPointerOp();
/** @brief %Check for race condition with non-interlocked access after InterlockedDecrement() */
void checkInterlockedDecrement();
/** @brief %Check for unused labels */
void checkUnusedLabel();
/** @brief %Check for expression that depends on order of evaluation of side effects */
void checkEvaluationOrder();
/** @brief %Check for access of moved or forwarded variable */
void checkAccessOfMovedVariable();
/** @brief %Check if function declaration and definition argument names different */
void checkFuncArgNamesDifferent();
2018-10-16 20:17:27 +02:00
/** @brief %Check for shadow variables. Less noisy than gcc/clang -Wshadow. */
void checkShadowVariables();
void checkConstArgument();
private:
// Error messages..
lib: fix a bunch of warnings about differing function arguments in definition and declaration. [lib/token.h:72] -> [lib/token.cpp:36]: (style, inconclusive) Function 'Token' argument 1 names different: declaration 'tokensBack' definition 't'. [lib/token.h:445] -> [lib/token.cpp:497]: (style, inconclusive) Function 'multiCompare' argument 1 names different: declaration 'needle' definition 'tok'. [lib/checkio.h:73] -> [lib/checkio.cpp:1385]: (style, inconclusive) Function 'ArgumentInfo' argument 3 names different: declaration 'isCPP' definition '_isCPP'. [lib/checkother.h:216] -> [lib/checkother.cpp:2136]: (style, inconclusive) Function 'checkComparisonFunctionIsAlwaysTrueOrFalseError' argument 2 names different: declaration 'strFunctionName' definition 'functionName'. [lib/errorlogger.h:214] -> [lib/errorlogger.cpp:51]: (style, inconclusive) Function 'ErrorMessage' argument 2 names different: declaration 'file0' definition 'file0_'. [lib/errorlogger.h:215] -> [lib/errorlogger.cpp:65]: (style, inconclusive) Function 'ErrorMessage' argument 2 names different: declaration 'file0' definition 'file0_'. [lib/library.h:327] -> [lib/library.cpp:1043]: (style, inconclusive) Function 'ignorefunction' argument 1 names different: declaration 'function' definition 'functionName'. [lib/mathlib.h:112] -> [lib/mathlib.cpp:1275]: (style, inconclusive) Function 'isNullValue' argument 1 names different: declaration 'tok' definition 'str'. [lib/preprocessor.h:91] -> [lib/preprocessor.cpp:122]: (style, inconclusive) Function 'setDirectives' argument 1 names different: declaration 'tokens' definition 'tokens1'. [lib/symboldatabase.h:860] -> [lib/symboldatabase.cpp:1801]: (style, inconclusive) Function 'argsMatch' argument 1 names different: declaration 'info' definition 'scope'. [lib/symboldatabase.h:1171] -> [lib/symboldatabase.cpp:2048]: (style, inconclusive) Function 'addClassFunction' argument 1 names different: declaration 'info' definition 'scope'. [lib/symboldatabase.h:1174] -> [lib/symboldatabase.cpp:2208]: (style, inconclusive) Function 'addNewFunction' argument 1 names different: declaration 'info' definition 'scope'. [lib/symboldatabase.h:1090] -> [lib/symboldatabase.cpp:3648]: (style, inconclusive) Function 'findVariableType' argument 2 names different: declaration 'type' definition 'typeTok'. [lib/symboldatabase.h:1101] -> [lib/symboldatabase.cpp:4308]: (style, inconclusive) Function 'findType' argument 1 names different: declaration 'tok' definition 'startTok'. [lib/symboldatabase.h:1176] -> [lib/symboldatabase.cpp:4349]: (style, inconclusive) Function 'findTypeInNested' argument 1 names different: declaration 'tok' definition 'startTok'. [lib/symboldatabase.h:1193] -> [lib/symboldatabase.cpp:4501]: (style, inconclusive) Function 'setValueType' argument 2 names different: declaration 'enumerators' definition 'enumerator'. [lib/path.h:159] -> [lib/path.cpp:247]: (style, inconclusive) Function 'isCPP' argument 1 names different: declaration 'extensionInLowerCase' definition 'path'. [lib/path.h:145] -> [lib/path.cpp:266]: (style, inconclusive) Function 'acceptFile' argument 1 names different: declaration 'filename' definition 'path'.
2017-04-03 00:06:46 +02:00
void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result);
void checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName);
void checkPipeParameterSizeError(const Token *tok, const std::string &strVarName, const std::string &strDim);
void clarifyCalculationError(const Token *tok, const std::string &op);
void clarifyStatementError(const Token* tok);
2009-03-21 17:58:13 +01:00
void cstyleCastError(const Token *tok);
void invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive);
void passedByValueError(const Token *tok, const std::string &parname, bool inconclusive);
2009-03-21 17:58:13 +01:00
void constStatementError(const Token *tok, const std::string &type);
void signedCharArrayIndexError(const Token *tok);
void unknownSignCharArrayIndexError(const Token *tok);
2009-03-21 17:58:13 +01:00
void charBitOpError(const Token *tok);
void variableScopeError(const Token *tok, const std::string &varname);
void zerodivError(const Token *tok, const ValueFlow::Value *value);
void nanInArithmeticExpressionError(const Token *tok);
void redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive);
void redundantAssignmentInSwitchError(const Token *tok1, const Token *tok2, const std::string &var);
void redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var);
void redundantCopyInSwitchError(const Token *tok1, const Token* tok2, const std::string &var);
void redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname);
void suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString);
void suspiciousEqualityComparisonError(const Token* tok);
void selfAssignmentError(const Token *tok, const std::string &varname);
void misusedScopeObjectError(const Token *tok, const std::string &varname);
void duplicateBranchError(const Token *tok1, const Token *tok2, ErrorPath errors);
void duplicateAssignExpressionError(const Token *tok1, const Token *tok2, bool inconclusive);
void oppositeExpressionError(const Token *opTok, ErrorPath errors);
void duplicateExpressionError(const Token *tok1, const Token *tok2, const Token *opTok, ErrorPath errors);
void duplicateValueTernaryError(const Token *tok);
void duplicateExpressionTernaryError(const Token *tok, ErrorPath errors);
void duplicateBreakError(const Token *tok, bool inconclusive);
void unreachableCodeError(const Token* tok, bool inconclusive);
Use valueflow in unsigned less than zero checker (#1630) The unsigned less than zero checker looked for patterns like "<= 0". Switching to use valueflow improves the checker in a few aspects. First, it removes false positives where instead of 0, the code is using 0L, 0U, etc. Instead of having to hard code the different variants of 0, valueflow handles this automatically. This fixes FPs on the form uint32_t value = 0xFUL; void f() { if (value < 0u) { value = 0u; } } where 0u was previously not recognized by the checker. This fixes #8836. Morover, it makes it possible to handle templates properly. In commit fa076598ade8a751ad85d5375bc976439e32c117, all warnings inside templates were made inconclusive, since the checker had no idea if "0" came from a template parameter or not. This makes it possible to not warn for the following case which was reported as a FP in #3233 template<int n> void foo(unsigned int x) { if (x <= n); } foo<0>(); but give a warning for the following case template<int n> void foo(unsigned int x) { if (x <= 0); } Previously, both these cases gave inconclusive warnings. Finally, it makes it possible to give warnings for the following code: void f(unsigned x) { int y = 0; if (x <= y) {} } Also, previously, the checker for unsigned variables larger than 0, the checker used the string of the astoperand. This meant that for code like the following: void f(unsigned x, unsigned y) { if (x -y >= 0) {} } cppcheck would output [unsigned-expression-positive.c] (style) Unsigned variable '-' can't be negative so it is unnecessary to test it. using expressionString() instead gives a better error message [unsigned-expression-positive.c] (style) Unsigned expression 'x-z' can't be negative so it is unnecessary to test it.
2019-01-31 09:30:29 +01:00
void unsignedLessThanZeroError(const Token *tok, const ValueFlow::Value *v, const std::string &varname);
void pointerLessThanZeroError(const Token *tok, const ValueFlow::Value *v);
void unsignedPositiveError(const Token *tok, const ValueFlow::Value *v, const std::string &varname);
void pointerPositiveError(const Token *tok, const ValueFlow::Value *v);
void SuspiciousSemicolonError(const Token *tok);
void negativeBitwiseShiftError(const Token *tok, int op);
void redundantCopyError(const Token *tok, const std::string &varname);
void incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean);
void varFuncNullUBError(const Token *tok);
void commaSeparatedReturnError(const Token *tok);
void redundantPointerOpError(const Token* tok, const std::string& varname, bool inconclusive);
void raceAfterInterlockedDecrementError(const Token* tok);
void unusedLabelError(const Token* tok, bool inSwitch);
void unknownEvaluationOrder(const Token* tok);
static bool isMovedParameterAllowedForInconclusiveFunction(const Token * tok);
2017-10-10 15:49:15 +02:00
void accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive);
void funcArgNamesDifferent(const std::string & functionName, size_t index, const Token* declaration, const Token* definition);
void funcArgOrderDifferent(const std::string & functionName, const Token * declaration, const Token * definition, const std::vector<const Token*> & declarations, const std::vector<const Token*> & definitions);
void shadowError(const Token *var, const Token *shadowed, bool shadowVar);
void constArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value);
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE {
CheckOther c(nullptr, settings, errorLogger);
ErrorPath errorPath;
// error
c.zerodivError(nullptr, nullptr);
c.misusedScopeObjectError(nullptr, "varname");
c.invalidPointerCastError(nullptr, "float", "double", false);
c.negativeBitwiseShiftError(nullptr, 1);
c.negativeBitwiseShiftError(nullptr, 2);
c.checkPipeParameterSizeError(nullptr, "varname", "dimension");
c.raceAfterInterlockedDecrementError(nullptr);
c.invalidFreeError(nullptr, false);
//performance
c.redundantCopyError(nullptr, "varname");
c.redundantCopyError(nullptr, nullptr, "var");
c.redundantAssignmentError(nullptr, nullptr, "var", false);
// style/warning
c.checkComparisonFunctionIsAlwaysTrueOrFalseError(nullptr, "isless","varName",false);
c.checkCastIntToCharAndBackError(nullptr, "func_name");
c.cstyleCastError(nullptr);
c.passedByValueError(nullptr, "parametername", false);
c.constStatementError(nullptr, "type");
c.signedCharArrayIndexError(nullptr);
c.unknownSignCharArrayIndexError(nullptr);
c.charBitOpError(nullptr);
c.variableScopeError(nullptr, "varname");
c.redundantAssignmentInSwitchError(nullptr, nullptr, "var");
c.redundantCopyInSwitchError(nullptr, nullptr, "var");
c.suspiciousCaseInSwitchError(nullptr, "||");
c.suspiciousEqualityComparisonError(nullptr);
c.selfAssignmentError(nullptr, "varname");
c.clarifyCalculationError(nullptr, "+");
c.clarifyStatementError(nullptr);
c.duplicateBranchError(nullptr, nullptr, errorPath);
c.duplicateAssignExpressionError(nullptr, nullptr, true);
c.oppositeExpressionError(nullptr, errorPath);
c.duplicateExpressionError(nullptr, nullptr, nullptr, errorPath);
c.duplicateValueTernaryError(nullptr);
c.duplicateExpressionTernaryError(nullptr, errorPath);
c.duplicateBreakError(nullptr, false);
c.unreachableCodeError(nullptr, false);
Use valueflow in unsigned less than zero checker (#1630) The unsigned less than zero checker looked for patterns like "<= 0". Switching to use valueflow improves the checker in a few aspects. First, it removes false positives where instead of 0, the code is using 0L, 0U, etc. Instead of having to hard code the different variants of 0, valueflow handles this automatically. This fixes FPs on the form uint32_t value = 0xFUL; void f() { if (value < 0u) { value = 0u; } } where 0u was previously not recognized by the checker. This fixes #8836. Morover, it makes it possible to handle templates properly. In commit fa076598ade8a751ad85d5375bc976439e32c117, all warnings inside templates were made inconclusive, since the checker had no idea if "0" came from a template parameter or not. This makes it possible to not warn for the following case which was reported as a FP in #3233 template<int n> void foo(unsigned int x) { if (x <= n); } foo<0>(); but give a warning for the following case template<int n> void foo(unsigned int x) { if (x <= 0); } Previously, both these cases gave inconclusive warnings. Finally, it makes it possible to give warnings for the following code: void f(unsigned x) { int y = 0; if (x <= y) {} } Also, previously, the checker for unsigned variables larger than 0, the checker used the string of the astoperand. This meant that for code like the following: void f(unsigned x, unsigned y) { if (x -y >= 0) {} } cppcheck would output [unsigned-expression-positive.c] (style) Unsigned variable '-' can't be negative so it is unnecessary to test it. using expressionString() instead gives a better error message [unsigned-expression-positive.c] (style) Unsigned expression 'x-z' can't be negative so it is unnecessary to test it.
2019-01-31 09:30:29 +01:00
c.unsignedLessThanZeroError(nullptr, nullptr, "varname");
c.unsignedPositiveError(nullptr, nullptr, "varname");
c.pointerLessThanZeroError(nullptr, nullptr);
c.pointerPositiveError(nullptr, nullptr);
c.SuspiciousSemicolonError(nullptr);
c.incompleteArrayFillError(nullptr, "buffer", "memset", false);
c.varFuncNullUBError(nullptr);
c.nanInArithmeticExpressionError(nullptr);
c.commaSeparatedReturnError(nullptr);
c.redundantPointerOpError(nullptr, "varname", false);
c.unusedLabelError(nullptr, true);
c.unusedLabelError(nullptr, false);
c.unknownEvaluationOrder(nullptr);
2017-10-10 15:49:15 +02:00
c.accessMovedError(nullptr, "v", nullptr, false);
c.funcArgNamesDifferent("function", 1, nullptr, nullptr);
c.redundantBitwiseOperationInSwitchError(nullptr, "varname");
c.shadowError(nullptr, nullptr, false);
c.shadowError(nullptr, nullptr, true);
c.constArgumentError(nullptr, nullptr, nullptr);
2018-04-04 21:51:31 +02:00
const std::vector<const Token *> nullvec;
c.funcArgOrderDifferent("function", nullptr, nullptr, nullvec, nullvec);
}
2014-11-20 14:20:09 +01:00
static std::string myName() {
2009-06-12 15:20:08 +02:00
return "Other";
}
std::string classInfo() const OVERRIDE {
return "Other checks\n"
// error
"- division with zero\n"
"- scoped object destroyed immediately after construction\n"
"- assignment in an assert statement\n"
"- free() or delete of an invalid memory location\n"
"- bitwise operation with negative right operand\n"
"- provide wrong dimensioned array to pipe() system command (--std=posix)\n"
"- cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n"
"- race condition with non-interlocked access after InterlockedDecrement() call\n"
"- expression 'x = x++;' depends on order of evaluation of side effects\n"
// warning
"- either division by zero or useless condition\n"
"- access of moved or forwarded variable.\n"
// performance
"- redundant data copying for const variable\n"
"- subsequent assignment or copying to a variable or buffer\n"
"- passing parameter by value\n"
// portability
"- Passing NULL pointer to function with variable number of arguments leads to UB.\n"
2009-10-29 21:34:43 +01:00
// style
"- C-style pointer cast in C++ code\n"
"- casting between incompatible pointer types\n"
"- [Incomplete statement](IncompleteStatement)\n"
"- [check how signed char variables are used](CharVar)\n"
"- variable scope can be limited\n"
"- unusual pointer arithmetic. For example: \"abc\" + 'd'\n"
"- redundant assignment, increment, or bitwise operation in a switch statement\n"
"- redundant strcpy in a switch statement\n"
"- Suspicious case labels in switch()\n"
"- assignment of a variable to itself\n"
"- Comparison of values leading always to true or false\n"
"- Clarify calculation with parentheses\n"
2018-10-11 13:59:21 +02:00
"- suspicious comparison of '\\0' with a char\\* variable\n"
"- duplicate break statement\n"
"- unreachable code\n"
"- testing if unsigned variable is negative/positive\n"
"- Suspicious use of ; at the end of 'if/for/while' statement.\n"
"- Array filled incompletely using memset/memcpy/memmove.\n"
"- NaN (not a number) value used in arithmetic expression.\n"
"- comma in return statement (the comma can easily be misread as a semicolon).\n"
"- prefer erfc, expm1 or log1p to avoid loss of precision.\n"
"- identical code in both branches of if/else or ternary operator.\n"
2018-10-11 13:59:21 +02:00
"- redundant pointer operation on pointer like &\\*some_ptr.\n"
"- find unused 'goto' labels.\n"
"- function declaration and definition argument names different.\n"
2018-10-16 20:17:27 +02:00
"- function declaration and definition argument order different.\n"
"- shadow variable.\n";
}
};
/// @}
//---------------------------------------------------------------------------
#endif // checkotherH