diff --git a/addons/cppcheckdata.py b/addons/cppcheckdata.py index 0cc2845fc..4817c52bb 100755 --- a/addons/cppcheckdata.py +++ b/addons/cppcheckdata.py @@ -141,6 +141,7 @@ class Token: isExpandedMacro Is this token a expanded macro token isSplittedVarDeclComma Is this a comma changed to semicolon in a splitted variable declaration ('int a,b;' => 'int a; int b;') isSplittedVarDeclEq Is this a '=' changed to semicolon in a splitted variable declaration ('int a=5;' => 'int a; a=5;') + isImplicitInt Is this token an implicit "int"? varId varId for token, each variable has a unique non-zero id variable Variable information for this token. See the Variable class. function If this token points at a function call, this attribute has the Function @@ -192,6 +193,7 @@ class Token: isExpandedMacro = False isSplittedVarDeclComma = False isSplittedVarDeclEq = False + isImplicitInt = False varId = None variableId = None variable = None @@ -257,6 +259,8 @@ class Token: self.isSplittedVarDeclComma = True if element.get('isSplittedVarDeclEq'): self.isSplittedVarDeclEq = True + if element.get('isImplicitInt'): + self.isImplicitInt = True self.linkId = element.get('link') self.link = None if element.get('varId'): @@ -288,9 +292,10 @@ class Token: "isNumber", "isInt", "isFloat", "isString", "strlen", "isChar", "isOp", "isArithmeticalOp", "isComparisonOp", "isLogicalOp", "isExpandedMacro", "isSplittedVarDeclComma", - "isSplittedVarDeclEq","linkId", "varId", "variableId", - "functionId", "valuesId", "valueType", "typeScopeId", - "astParentId", "astOperand1Id", "file", "linenr", "column"] + "isSplittedVarDeclEq", "isImplicitInt", "linkId", "varId", + "variableId", "functionId", "valuesId", "valueType", + "typeScopeId", "astParentId", "astOperand1Id", "file", + "linenr", "column"] return "{}({})".format( "Token", ", ".join(("{}={}".format(a, repr(getattr(self, a))) for a in attrs)) diff --git a/addons/misra.py b/addons/misra.py index a65b4704e..4f2db7729 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -1486,6 +1486,11 @@ class MisraChecker: if usedParameter.isString and parameterDefinition.nameToken: reportErrorIfVariableIsNotConst(parameterDefinition.nameToken, usedParameter) + def misra_8_1(self, cfg): + for token in cfg.tokenlist: + if token.isImplicitInt: + self.reportError(token, 8, 1) + def misra_8_2(self, data, rawTokens): def getFollowingRawTokens(rawTokens, token, count): following =[] @@ -3271,6 +3276,7 @@ class MisraChecker: if cfgNumber == 0: self.executeCheck(703, self.misra_7_3, data.rawTokens) self.executeCheck(704, self.misra_7_4, cfg) + self.executeCheck(801, self.misra_8_1, cfg) if cfgNumber == 0: self.executeCheck(802, self.misra_8_2, cfg, data.rawTokens) self.executeCheck(811, self.misra_8_11, cfg) diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 23ab33415..3fa935d76 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -326,6 +326,8 @@ void misra_7_4(void) misra_7_4_call(1, "text_call"); // 7.4 11.8 } +const misra_8_1_a; // 8.1 + static int misra_8_2_a (int n, ...); extern int misra_8_2_b (int n); extern int misra_8_2_c (int); // 8.2 diff --git a/lib/token.h b/lib/token.h index bbdad70f9..ecaddc47f 100644 --- a/lib/token.h +++ b/lib/token.h @@ -633,6 +633,13 @@ public: setFlag(fIsSplitVarDeclEq, b); } + bool isImplicitInt() const { + return getFlag(fIsImplicitInt); + } + void isImplicitInt(bool b) { + setFlag(fIsImplicitInt, b); + } + bool isBitfield() const { return mImpl->mBits > 0; } @@ -1196,7 +1203,7 @@ private: Token *mPrevious; Token *mLink; - enum { + enum : uint32_t { fIsUnsigned = (1 << 0), fIsSigned = (1 << 1), fIsPointerCompare = (1 << 2), @@ -1227,7 +1234,8 @@ private: fConstexpr = (1 << 27), fExternC = (1 << 28), fIsSplitVarDeclComma = (1 << 29), // set to true when variable declarations are split up ('int a,b;' => 'int a; int b;') - fIsSplitVarDeclEq = (1 << 30) // set to true when variable declaration with initialization is split up ('int a=5;' => 'int a; a=5;') + fIsSplitVarDeclEq = (1 << 30), // set to true when variable declaration with initialization is split up ('int a=5;' => 'int a; a=5;') + fIsImplicitInt = (1U << 31) // Is "int" token implicitly added? }; Token::Type mTokType; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 31655699e..f779732b4 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5457,6 +5457,8 @@ void Tokenizer::dump(std::ostream &out) const out << " isSplittedVarDeclComma=\"true\""; if (tok->isSplittedVarDeclEq()) out << " isSplittedVarDeclEq=\"true\""; + if (tok->isImplicitInt()) + out << " isImplicitInt=\"true\""; if (tok->link()) out << " link=\"" << tok->link() << '\"'; if (tok->varId() > 0) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index e0163061b..cef633b9d 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -1860,6 +1860,16 @@ void TokenList::simplifyPlatformTypes() void TokenList::simplifyStdType() { for (Token *tok = front(); tok; tok = tok->next()) { + + if (Token::Match(tok, "const|extern *|&|%name%") && (!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) { + if (Token::Match(tok->next(), "%name% !!;")) + continue; + + tok->insertToken("int"); + tok->next()->isImplicitInt(true); + continue; + } + if (Token::Match(tok, "char|short|int|long|unsigned|signed|double|float") || (mSettings->standards.c >= Standards::C99 && Token::Match(tok, "complex|_Complex"))) { bool isFloat= false; bool isSigned = false; @@ -1897,6 +1907,7 @@ void TokenList::simplifyStdType() tok->str("int"); tok->isSigned(isSigned); tok->isUnsigned(isUnsigned); + tok->isImplicitInt(true); } } else { typeSpec->isLong(typeSpec->isLong() || (isFloat && countLong == 1) || countLong > 1); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 047143dbd..af0e8b416 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -228,15 +228,17 @@ private: TEST_CASE(volatile_variables); // unsigned i; => unsigned int i; - TEST_CASE(unsigned1); - TEST_CASE(unsigned2); - TEST_CASE(unsigned3); // template arguments + TEST_CASE(implicitIntConst); + TEST_CASE(implicitIntExtern); + TEST_CASE(implicitIntSigned1); + TEST_CASE(implicitIntUnsigned1); + TEST_CASE(implicitIntUnsigned2); + TEST_CASE(implicitIntUnsigned3); // template arguments TEST_CASE(simplifyStdType); // #4947, #4950, #4951 TEST_CASE(createLinks); TEST_CASE(createLinks2); - TEST_CASE(signed1); TEST_CASE(simplifyString); TEST_CASE(simplifyConst); @@ -2535,10 +2537,22 @@ private: } } + void implicitIntConst() { + ASSERT_EQUALS("const int x ;", tokenizeAndStringify("const x;")); + ASSERT_EQUALS("const int * x ;", tokenizeAndStringify("const *x;")); + ASSERT_EQUALS("const int * f ( ) ;", tokenizeAndStringify("const *f();")); + } + + void implicitIntExtern() { + ASSERT_EQUALS("extern int x ;", tokenizeAndStringify("extern x;")); + ASSERT_EQUALS("extern int * x ;", tokenizeAndStringify("extern *x;")); + ASSERT_EQUALS("const int * f ( ) ;", tokenizeAndStringify("const *f();")); + } + /** * tokenize "signed i" => "signed int i" */ - void signed1() { + void implicitIntSigned1() { { const char code1[] = "void foo ( signed int , float ) ;"; ASSERT_EQUALS(code1, tokenizeAndStringify(code1)); @@ -2572,7 +2586,7 @@ private: * tokenize "unsigned i" => "unsigned int i" * tokenize "unsigned" => "unsigned int" */ - void unsigned1() { + void implicitIntUnsigned1() { // No changes.. { const char code[] = "void foo ( unsigned int , float ) ;"; @@ -2607,14 +2621,14 @@ private: } } - void unsigned2() { + void implicitIntUnsigned2() { const char code[] = "i = (unsigned)j;"; const char expected[] = "i = ( unsigned int ) j ;"; ASSERT_EQUALS(expected, tokenizeAndStringify(code)); } // simplify "unsigned" when using templates.. - void unsigned3() { + void implicitIntUnsigned3() { { const char code[] = "; foo();"; const char expected[] = "; foo < unsigned int > ( ) ;";