Tokenizer::simplifyTypedef: new faster simplification.
It performs a more "lightweight" simplification of global typedefs that are not shadowed. If a "heavy" simplification is needed that will be executed afterwards.
This commit is contained in:
parent
03214c6c08
commit
c79d859f8b
|
@ -1466,7 +1466,7 @@ void SymbolDatabase::createSymbolDatabaseIncompleteVars()
|
|||
continue;
|
||||
if (Token::Match(tok->next(), "::|.|(|:|%var%"))
|
||||
continue;
|
||||
if (Token::Match(tok->next(), "&|&&|* )|%var%"))
|
||||
if (Token::Match(tok->next(), "&|&&|* )|,|%var%"))
|
||||
continue;
|
||||
if (Token::simpleMatch(tok->next(), ")") && Token::simpleMatch(tok->next()->link()->previous(), "catch ("))
|
||||
continue;
|
||||
|
|
444
lib/tokenize.cpp
444
lib/tokenize.cpp
|
@ -577,7 +577,451 @@ void Tokenizer::simplifyUsingToTypedef()
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class TypedefSimplifier {
|
||||
private:
|
||||
Token* mTypedefToken; // The "typedef" token
|
||||
Token* mEndToken{nullptr}; // Semicolon
|
||||
std::pair<Token*, Token*> mRangeType;
|
||||
std::pair<Token*, Token*> mRangeTypeQualifiers;
|
||||
std::pair<Token*, Token*> mRangeAfterVar;
|
||||
std::string mTypedefName; // Name of typedef type
|
||||
Token* mNameToken{nullptr};
|
||||
bool mFail = false;
|
||||
bool mReplaceFailed = false;
|
||||
bool mUsed = false;
|
||||
|
||||
public:
|
||||
TypedefSimplifier(Token* typedefToken, int &num) : mTypedefToken(typedefToken) {
|
||||
Token* start = typedefToken->next();
|
||||
if (Token::simpleMatch(start, "typename"))
|
||||
start = start->next();
|
||||
|
||||
// TODO handle unnamed structs etc
|
||||
if (Token::Match(start, "const| enum|struct|union|class %name% {")) {
|
||||
const std::pair<Token*, Token*> rangeBefore(start, Token::findsimplematch(start, "{"));
|
||||
|
||||
// find typedef name token
|
||||
Token* nameToken = rangeBefore.second->link()->next();
|
||||
while (Token::Match(nameToken, "%name%|* %name%|*"))
|
||||
nameToken = nameToken->next();
|
||||
const std::pair<Token*, Token*> rangeQualifiers(rangeBefore.second->link()->next(), nameToken);
|
||||
|
||||
if (Token::Match(nameToken, "%name% ;")) {
|
||||
mRangeType = rangeBefore;
|
||||
mRangeTypeQualifiers = rangeQualifiers;
|
||||
mTypedefName = nameToken->str();
|
||||
Token* typeName = rangeBefore.second->previous();
|
||||
if (typeName->isKeyword()) {
|
||||
(void)num;
|
||||
// TODO typeName->insertToken("T:" + std::to_string(num++));
|
||||
typeName->insertToken(nameToken->str());
|
||||
}
|
||||
mNameToken = nameToken;
|
||||
mEndToken = nameToken->next();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (Token* type = start; Token::Match(type, "%name%|*|&"); type = type->next()) {
|
||||
if (Token::Match(type, "%name% ;")) {
|
||||
mRangeType.first = start;
|
||||
mRangeType.second = type;
|
||||
mNameToken = type;
|
||||
mEndToken = mNameToken->next();
|
||||
return;
|
||||
}
|
||||
if (Token::Match(type, "%name% [")) {
|
||||
Token* end = type->linkAt(1);
|
||||
while (Token::simpleMatch(end, "] ["))
|
||||
end = end->linkAt(1);
|
||||
if (!Token::simpleMatch(end, "] ;"))
|
||||
break;
|
||||
mRangeType.first = start;
|
||||
mRangeType.second = type;
|
||||
mNameToken = type;
|
||||
mEndToken = end->next();
|
||||
mRangeAfterVar.first = mNameToken->next();
|
||||
mRangeAfterVar.second = mEndToken;
|
||||
return;
|
||||
}
|
||||
if (Token::Match(type->next(), "( * const| %name% ) (") && Token::simpleMatch(type->linkAt(1)->linkAt(1), ") ;")) {
|
||||
mNameToken = type->linkAt(1)->previous();
|
||||
mEndToken = type->linkAt(1)->linkAt(1)->next();
|
||||
mRangeType.first = start;
|
||||
mRangeType.second = mNameToken;
|
||||
mRangeAfterVar.first = mNameToken->next();
|
||||
mRangeAfterVar.second = mEndToken;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO: handle all typedefs
|
||||
if ((false))
|
||||
printTypedef(typedefToken);
|
||||
mFail = true;
|
||||
}
|
||||
|
||||
const Token* getTypedefToken() const {
|
||||
return mTypedefToken;
|
||||
}
|
||||
|
||||
bool isUsed() const {
|
||||
return mUsed;
|
||||
}
|
||||
|
||||
bool fail() const {
|
||||
return mFail;
|
||||
}
|
||||
|
||||
bool replaceFailed() const {
|
||||
return mReplaceFailed;
|
||||
}
|
||||
|
||||
bool isStructEtc() const {
|
||||
return mRangeType.second && mRangeType.second->str() == "{";
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return mNameToken ? mNameToken->str() : "";
|
||||
}
|
||||
|
||||
void replace(Token* tok) {
|
||||
if (tok == mNameToken)
|
||||
return;
|
||||
|
||||
mUsed = true;
|
||||
|
||||
// Special handling for T() when T is a pointer
|
||||
if (Token::Match(tok, "%name% ( )")) {
|
||||
bool pointerType = false;
|
||||
for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
|
||||
if (type->str() == "*" || type->str() == "&") {
|
||||
pointerType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const Token* type = mRangeTypeQualifiers.first; type != mRangeTypeQualifiers.second; type = type->next()) {
|
||||
if (type->str() == "*" || type->str() == "&") {
|
||||
pointerType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pointerType) {
|
||||
tok->deleteThis();
|
||||
tok->next()->insertToken("0");
|
||||
Token* tok2 = insertTokens(tok, mRangeType);
|
||||
insertTokens(tok2, mRangeTypeQualifiers);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling of function pointer cast
|
||||
const bool isFunctionPointer = Token::Match(mNameToken, "%name% )");
|
||||
if (isFunctionPointer && isCast(tok->previous())) {
|
||||
tok->insertToken("*");
|
||||
insertTokens(tok, std::pair<Token*, Token*>(mRangeType.first, mNameToken->linkAt(1)));
|
||||
tok->deleteThis();
|
||||
return;
|
||||
}
|
||||
|
||||
// Inherited type => skip "struct" / "class"
|
||||
if (Token::Match(mRangeType.first, "const| struct|class %name% {") && Token::Match(tok->previous(), "public|protected|private")) {
|
||||
tok->originalName(tok->str());
|
||||
tok->str(mRangeType.second->previous()->str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (Token::Match(tok, "%name% ::")) {
|
||||
if (Token::Match(mRangeType.first, "const| struct|class %name% %name% ;")) {
|
||||
tok->originalName(tok->str());
|
||||
tok->str(mRangeType.second->previous()->str());
|
||||
} else {
|
||||
mReplaceFailed = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// pointer => move "const"
|
||||
if (Token::simpleMatch(tok->previous(), "const")) {
|
||||
bool pointerType = false;
|
||||
for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
|
||||
if (type->str() == "*") {
|
||||
pointerType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pointerType) {
|
||||
tok->insertToken("const");
|
||||
tok->next()->column(tok->column());
|
||||
tok->next()->isExpandedMacro(tok->previous()->isExpandedMacro());
|
||||
tok->deletePrevious();
|
||||
}
|
||||
}
|
||||
|
||||
// Do not duplicate class/struct/enum/union
|
||||
if (Token::Match(tok->previous(), "enum|union|struct|class")) {
|
||||
bool found = false;
|
||||
const std::string &kw = tok->previous()->str();
|
||||
for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
|
||||
if (type->str() == kw) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
tok->deletePrevious();
|
||||
else {
|
||||
mReplaceFailed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Token* const tok2 = insertTokens(tok, mRangeType);
|
||||
Token* const tok3 = insertTokens(tok2, mRangeTypeQualifiers);
|
||||
|
||||
Token *after = tok3;
|
||||
while (Token::Match(after, "%name%|*|&|&&|::"))
|
||||
after = after->next();
|
||||
|
||||
bool useAfterVarRange = true;
|
||||
if (Token::simpleMatch(mRangeAfterVar.first, "[")) {
|
||||
if (Token::Match(after->previous(), "%name% ( !!*")) {
|
||||
useAfterVarRange = false;
|
||||
// Function return type => replace array with "*"
|
||||
for (const Token* a = mRangeAfterVar.first; Token::simpleMatch(a, "["); a = a->link()->next())
|
||||
tok3->insertToken("*");
|
||||
} else {
|
||||
Token* prev = after->previous();
|
||||
if (prev->isName() && prev != tok3)
|
||||
prev = prev->previous();
|
||||
if (Token::Match(prev, "*|&|&&") && prev != tok3) {
|
||||
while (Token::Match(prev, "*|&|&&") && prev != tok3)
|
||||
prev = prev->previous();
|
||||
prev->insertToken("(");
|
||||
after->previous()->insertToken(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isFunctionPointer) {
|
||||
if (Token::Match(after, "( * %name% ) ("))
|
||||
after = after->link()->linkAt(1)->next();
|
||||
else if (after->str() == "(") {
|
||||
useAfterVarRange = false;
|
||||
if (Token::simpleMatch(tok3->previous(), "( *"))
|
||||
tok3->deletePrevious();
|
||||
}
|
||||
else if (after->str() == "[") {
|
||||
while (after && after->str() == "[")
|
||||
after = after->link()->next();
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (Token::simpleMatch(after, "["))
|
||||
after = after->link()->next();
|
||||
}
|
||||
|
||||
if (!after)
|
||||
throw InternalError(tok, "Failed to simplify typedef. Is the code valid?");
|
||||
|
||||
Token* const tok4 = useAfterVarRange ? insertTokens(after->previous(), mRangeAfterVar)->next() : tok3->next();
|
||||
|
||||
tok->deleteThis();
|
||||
|
||||
// Set links
|
||||
std::stack<Token*> brackets;
|
||||
for (; tok != tok4; tok = tok->next()) {
|
||||
if (Token::Match(tok, "[{([]"))
|
||||
brackets.push(tok);
|
||||
else if (Token::Match(tok, "[})]]")) {
|
||||
Token::createMutualLinks(brackets.top(), tok);
|
||||
brackets.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeDeclaration() {
|
||||
if (Token::simpleMatch(mRangeType.second, "{")) {
|
||||
while (Token::Match(mTypedefToken, "typedef|const"))
|
||||
mTypedefToken->deleteThis();
|
||||
Token::eraseTokens(mRangeType.second->link(), mEndToken);
|
||||
} else {
|
||||
Token::eraseTokens(mTypedefToken, mEndToken);
|
||||
mTypedefToken->deleteThis();
|
||||
}
|
||||
}
|
||||
|
||||
bool canReplace(const Token* tok) {
|
||||
if (mNameToken == tok)
|
||||
return false;
|
||||
if (!Token::Match(tok->previous(), "%name%|;|{|}|(|,|<") && !Token::Match(tok, "%name% ("))
|
||||
return false;
|
||||
if (!Token::Match(tok, "%name% %name%|*|&|&&|;|(|)|,|::")) {
|
||||
if (Token::Match(tok->previous(), "( %name% =") && Token::Match(tok->linkAt(-1), ") %name%|{") && !tok->tokAt(-2)->isKeyword())
|
||||
return true;
|
||||
if (Token::Match(tok->previous(), ", %name% ="))
|
||||
return true;
|
||||
if (Token::Match(tok->previous(), "new %name% ["))
|
||||
return true;
|
||||
if (Token::Match(tok->previous(), "< %name% >"))
|
||||
return true;
|
||||
if (Token::Match(tok->previous(), "public|protected|private"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (Token::Match(tok->previous(), "%name%") && !tok->previous()->isKeyword())
|
||||
return false;
|
||||
if (Token::simpleMatch(tok->next(), "(") && Token::Match(tok->linkAt(1), ") %name%|{"))
|
||||
return false;
|
||||
if (Token::Match(tok->previous(), "struct|union|class|enum %name% %name%") &&
|
||||
Token::simpleMatch(mRangeType.second, "{") &&
|
||||
tok->str() != mRangeType.second->previous()->str())
|
||||
return true;
|
||||
if (Token::Match(tok->previous(), "; %name% ;"))
|
||||
return false;
|
||||
for (const Token* after = tok->next(); after; after = after->next()) {
|
||||
if (Token::Match(after, "%name%|::|&|*|&&"))
|
||||
continue;
|
||||
if (after->str() == "<" && after->link())
|
||||
break;
|
||||
if (after->isNumber())
|
||||
return false;
|
||||
if (after->isComparisonOp() || after->isArithmeticalOp())
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
for (const Token* before = tok->previous(); before; before = before->previous()) {
|
||||
if (Token::Match(before, "[+-*/&|~!]"))
|
||||
return false;
|
||||
if (Token::Match(before, "struct|union|class|enum") || before->isStandardType())
|
||||
return false;
|
||||
if (before->str() == "::")
|
||||
return false;
|
||||
if (before->isName())
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Token* endToken() const {
|
||||
return mEndToken;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool isCast(const Token* tok) {
|
||||
if (Token::Match(tok, "( %name% ) (|%name%"))
|
||||
return !tok->tokAt(2)->isKeyword();
|
||||
if (Token::Match(tok, "< %name% > (") && tok->previous() && endsWith(tok->previous()->str(), "_cast", 5))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static Token* insertTokens(Token* to, std::pair<Token*,Token*> range) {
|
||||
for (const Token* from = range.first; from != range.second; from = from->next()) {
|
||||
to->insertToken(from->str());
|
||||
to->next()->column(to->column());
|
||||
to = to->next();
|
||||
to->isSimplifiedTypedef(true);
|
||||
}
|
||||
return to;
|
||||
}
|
||||
|
||||
static void printTypedef(const Token *tok) {
|
||||
int indent = 0;
|
||||
while (tok && (indent > 0 || tok->str() != ";")) {
|
||||
if (tok->str() == "{")
|
||||
++indent;
|
||||
else if (tok->str() == "}")
|
||||
--indent;
|
||||
std::cout << " " << tok->str();
|
||||
tok = tok->next();
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyTypedef()
|
||||
{
|
||||
// Simplify global typedefs that are not redefined with the fast 1-pass simplification.
|
||||
// Then use the slower old typedef simplification.
|
||||
std::map<std::string, int> numberOfTypedefs;
|
||||
for (Token* tok = list.front(); tok; tok = tok->next()) {
|
||||
if (tok->str() == "typedef") {
|
||||
int dummy = 0;
|
||||
TypedefSimplifier ts(tok, dummy);
|
||||
if (!ts.fail())
|
||||
numberOfTypedefs[ts.name()]++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int indentlevel = 0;
|
||||
int typeNum = 1;
|
||||
std::map<std::string, TypedefSimplifier> typedefs;
|
||||
for (Token* tok = list.front(); tok; tok = tok->next()) {
|
||||
if (!tok->isName()) {
|
||||
if (tok->str()[0] == '{')
|
||||
++indentlevel;
|
||||
else if (tok->str()[0] == '}')
|
||||
--indentlevel;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (indentlevel == 0 && tok->str() == "typedef") {
|
||||
TypedefSimplifier ts(tok, typeNum);
|
||||
if (!ts.fail() && numberOfTypedefs[ts.name()] == 1) {
|
||||
typedefs.emplace(ts.name(), ts);
|
||||
if (!ts.isStructEtc())
|
||||
tok = ts.endToken();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = typedefs.find(tok->str());
|
||||
if (it != typedefs.end() && it->second.canReplace(tok)) {
|
||||
std::set<std::string> r;
|
||||
while (it != typedefs.end() && r.insert(tok->str()).second) {
|
||||
it->second.replace(tok);
|
||||
it = typedefs.find(tok->str());
|
||||
}
|
||||
} else if (tok->str() == "enum") {
|
||||
while (Token::Match(tok, "%name%|:|::"))
|
||||
tok = tok->next();
|
||||
if (!tok)
|
||||
break;
|
||||
if (tok->str() == "{")
|
||||
tok = tok->link();
|
||||
}
|
||||
}
|
||||
|
||||
if (!typedefs.empty())
|
||||
{
|
||||
// remove typedefs
|
||||
for (auto &t: typedefs) {
|
||||
if (!t.second.replaceFailed()) {
|
||||
const Token* const typedefToken = t.second.getTypedefToken();
|
||||
TypedefInfo typedefInfo;
|
||||
typedefInfo.name = t.second.name();
|
||||
typedefInfo.filename = list.file(typedefToken);
|
||||
typedefInfo.lineNumber = typedefToken->linenr();
|
||||
typedefInfo.column = typedefToken->column();
|
||||
typedefInfo.used = t.second.isUsed();
|
||||
mTypedefInfo.push_back(std::move(typedefInfo));
|
||||
|
||||
t.second.removeDeclaration();
|
||||
}
|
||||
}
|
||||
|
||||
while (Token::Match(list.front(), "; %any%"))
|
||||
list.front()->deleteThis();
|
||||
}
|
||||
|
||||
simplifyTypedefCpp();
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyTypedefCpp()
|
||||
{
|
||||
std::vector<Space> spaceInfo;
|
||||
bool isNamespace = false;
|
||||
|
|
|
@ -267,6 +267,7 @@ public:
|
|||
* A c;
|
||||
*/
|
||||
void simplifyTypedef();
|
||||
void simplifyTypedefCpp();
|
||||
|
||||
/**
|
||||
*/
|
||||
|
|
|
@ -738,7 +738,8 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode65() { // #6741
|
||||
ASSERT_THROW(checkCode("{ } { } typedef int u_array[]; typedef u_array &u_array_ref; (u_array_ref arg) { } u_array_ref"), InternalError);
|
||||
// TODO write some syntax error
|
||||
checkCode("{ } { } typedef int u_array[]; typedef u_array &u_array_ref; (u_array_ref arg) { } u_array_ref");
|
||||
}
|
||||
|
||||
void garbageCode66() { // #6742
|
||||
|
|
|
@ -53,6 +53,26 @@ private:
|
|||
settings1.checkUnusedTemplates = true;
|
||||
settings2.checkUnusedTemplates = true;
|
||||
|
||||
TEST_CASE(c1);
|
||||
TEST_CASE(c2);
|
||||
TEST_CASE(canreplace1);
|
||||
TEST_CASE(canreplace2);
|
||||
TEST_CASE(cconst);
|
||||
TEST_CASE(cstruct1);
|
||||
TEST_CASE(cstruct2);
|
||||
TEST_CASE(cstruct3);
|
||||
TEST_CASE(cstruct3);
|
||||
TEST_CASE(cstruct4);
|
||||
TEST_CASE(cfp1);
|
||||
TEST_CASE(cfp2);
|
||||
TEST_CASE(cfp4);
|
||||
TEST_CASE(cfp5);
|
||||
TEST_CASE(cfp6);
|
||||
TEST_CASE(carray1);
|
||||
TEST_CASE(carray2);
|
||||
TEST_CASE(cdonotreplace1);
|
||||
TEST_CASE(cppfp1);
|
||||
|
||||
TEST_CASE(simplifyTypedef1);
|
||||
TEST_CASE(simplifyTypedef2);
|
||||
TEST_CASE(simplifyTypedef3);
|
||||
|
@ -272,6 +292,148 @@ private:
|
|||
}
|
||||
|
||||
|
||||
std::string simplifyTypedefC(const char code[]) {
|
||||
errout.str("");
|
||||
|
||||
Tokenizer tokenizer(&settings1, this);
|
||||
|
||||
std::istringstream istr(code);
|
||||
tokenizer.list.createTokens(istr, "file.c");
|
||||
tokenizer.createLinks();
|
||||
tokenizer.simplifyTypedef();
|
||||
try {
|
||||
tokenizer.validate();
|
||||
} catch (const InternalError&) {
|
||||
return "";
|
||||
}
|
||||
return tokenizer.tokens()->stringifyList(nullptr, false);
|
||||
}
|
||||
|
||||
void c1() {
|
||||
const char code[] = "typedef int t;\n"
|
||||
"t x;";
|
||||
ASSERT_EQUALS("int x ;", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void c2() {
|
||||
const char code[] = "void f1() { typedef int t; t x; }\n"
|
||||
"void f2() { typedef float t; t x; }\n";
|
||||
ASSERT_EQUALS("void f1 ( ) { int x ; } void f2 ( ) { float x ; }", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void canreplace1() {
|
||||
const char code[] = "typedef unsigned char u8;\n"
|
||||
"void f(uint8_t u8) { x = u8 & y; }\n";
|
||||
ASSERT_EQUALS("void f ( uint8_t u8 ) { x = u8 & y ; }", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void canreplace2() {
|
||||
const char code1[] = "typedef char* entry;\n"
|
||||
"void f(Y* entry) { for (entry=x->y; entry; entry = entry->next) {} }\n";
|
||||
ASSERT_EQUALS("void f ( Y * entry ) { for ( entry = x -> y ; entry ; entry = entry -> next ) { } }", simplifyTypedefC(code1));
|
||||
|
||||
const char code2[] = "typedef char* entry;\n"
|
||||
"void f() { dostuff(entry * 2); }\n";
|
||||
ASSERT_EQUALS("void f ( ) { dostuff ( entry * 2 ) ; }", simplifyTypedefC(code2));
|
||||
|
||||
const char code3[] = "typedef char* entry;\n"
|
||||
"void f() { dostuff(entry * y < z); }\n";
|
||||
ASSERT_EQUALS("void f ( ) { dostuff ( entry * y < z ) ; }", simplifyTypedefC(code3));
|
||||
}
|
||||
|
||||
void cconst() {
|
||||
const char code1[] = "typedef void* HWND;\n"
|
||||
"const HWND x;";
|
||||
ASSERT_EQUALS("void * const x ;", simplifyTypedef(code1));
|
||||
|
||||
const char code2[] = "typedef void (*fp)();\n"
|
||||
"const fp x;";
|
||||
ASSERT_EQUALS("void ( * const x ) ( ) ;", simplifyTypedef(code2));
|
||||
}
|
||||
|
||||
void cstruct1() {
|
||||
const char code[] = "typedef struct { int a; int b; } t;\n"
|
||||
"t x;";
|
||||
ASSERT_EQUALS("struct t { int a ; int b ; } ; struct t x ;", simplifyTypedef(code));
|
||||
ASSERT_EQUALS("struct t { int a ; int b ; } ; struct t x ;", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void cstruct2() {
|
||||
const char code[] = "typedef enum { A, B } t;\n"
|
||||
"t x;";
|
||||
ASSERT_EQUALS("enum t { A , B } ; t x ;", simplifyTypedef(code));
|
||||
ASSERT_EQUALS("enum t { A , B } ; t x ;", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void cstruct3() {
|
||||
const char code[] = "typedef struct s { int a; int b; } t;\n"
|
||||
"t x;";
|
||||
ASSERT_EQUALS("struct s { int a ; int b ; } ; struct s x ;", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void cstruct4() {
|
||||
const char code[] = "typedef struct s { int a; int b; } t;\n"
|
||||
"struct t x{};";
|
||||
ASSERT_EQUALS("struct s { int a ; int b ; } ; struct s x { } ;", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void cfp1() {
|
||||
const char code[] = "typedef void (*fp)(void * p);\n"
|
||||
"fp x;";
|
||||
ASSERT_EQUALS("void ( * x ) ( void * p ) ;", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void cfp2() {
|
||||
const char code[] = "typedef void (*const fp)(void * p);\n"
|
||||
"fp x;";
|
||||
ASSERT_EQUALS("void ( * const x ) ( void * p ) ;", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void cfp4() {
|
||||
const char code[] = "typedef struct S Stype ;\n"
|
||||
"typedef void ( * F ) ( Stype * ) ;\n"
|
||||
"F func;";
|
||||
ASSERT_EQUALS("void ( * func ) ( struct S * ) ;", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void cfp5() {
|
||||
const char code[] = "typedef void (*fp)(void);\n"
|
||||
"typedef fp t;\n"
|
||||
"void foo(t p);";
|
||||
ASSERT_EQUALS("void foo ( void ( * p ) ( void ) ) ;", simplifyTypedef(code));
|
||||
}
|
||||
|
||||
void cfp6() {
|
||||
const char code[] = "typedef void (*fp)(void);\n"
|
||||
"fp a[10];";
|
||||
ASSERT_EQUALS("void ( * a [ 10 ] ) ( void ) ;", simplifyTypedef(code));
|
||||
}
|
||||
|
||||
void carray1() {
|
||||
const char code[] = "typedef int t[20];\n"
|
||||
"t x;";
|
||||
ASSERT_EQUALS("int x [ 20 ] ;", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
void carray2() {
|
||||
const char code[] = "typedef double t[4];\n"
|
||||
"t x[10];";
|
||||
ASSERT_EQUALS("double x [ 10 ] [ 4 ] ;", simplifyTypedef(code));
|
||||
}
|
||||
|
||||
void cdonotreplace1() {
|
||||
const char code[] = "typedef int t;\n"
|
||||
"int* t;";
|
||||
ASSERT_EQUALS("int * t ;", simplifyTypedefC(code));
|
||||
}
|
||||
|
||||
|
||||
void cppfp1() {
|
||||
const char code[] = "typedef void (*fp)(void);\n"
|
||||
"typedef fp t;\n"
|
||||
"void foo(t p);";
|
||||
ASSERT_EQUALS("void foo ( void ( * p ) ( void ) ) ;", tok(code));
|
||||
}
|
||||
|
||||
void simplifyTypedef1() {
|
||||
const char code[] = "class A\n"
|
||||
|
@ -1132,9 +1294,13 @@ private:
|
|||
"class X { } ; "
|
||||
"int main ( ) "
|
||||
"{ "
|
||||
"X ( * * Foo ) ( const X & ) ; Foo = new X ( * ) ( const X & ) [ 2 ] ; "
|
||||
"X ( * * Foo ) ( const X & ) ; Foo = new X ( * [ 2 ] ) ( const X & ) ; "
|
||||
"}";
|
||||
|
||||
// TODO: Ideally some parentheses should be added. This code is compilable:
|
||||
// int (**Foo)(int);
|
||||
// Foo = new (int(*[2])(int)) ;
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
|
||||
|
@ -1710,8 +1876,10 @@ private:
|
|||
"void f ( ) {\n"
|
||||
" ((Function * (*) (char *, char *, int, int)) global[6]) ( \"assoc\", \"eggdrop\", 106, 0);\n"
|
||||
"}";
|
||||
// TODO should it be simplified as below instead?
|
||||
// "( ( int ( * * ( * ) ( char * , char * , int , int ) ) ( ) ) global [ 6 ] ) ( \"assoc\" , \"eggdrop\" , 106 , 0 ) ; "
|
||||
const char expected[] = "void f ( ) { "
|
||||
"( ( int ( * * ( * ) ( char * , char * , int , int ) ) ( ) ) global [ 6 ] ) ( \"assoc\" , \"eggdrop\" , 106 , 0 ) ; "
|
||||
"( ( int * * * ) global [ 6 ] ) ( \"assoc\" , \"eggdrop\" , 106 , 0 ) ; "
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS("[test.cpp:3]: (debug) valueflow.cpp:1319:valueFlowConditionExpressions bailout: Skipping function due to incomplete variable global\n", errout.str());
|
||||
|
@ -1842,7 +2010,7 @@ private:
|
|||
"state_t current_state = death;\n"
|
||||
"static char get_runlevel(const state_t);";
|
||||
const char expected[] = "long ( * ( * current_state ) ( void ) ) ( void ) ; current_state = death ; "
|
||||
"static char get_runlevel ( const long ( * ( * ) ( void ) ) ( void ) ) ;";
|
||||
"static char get_runlevel ( long ( * ( * const ) ( void ) ) ( void ) ) ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
@ -2216,7 +2384,7 @@ private:
|
|||
void simplifyTypedef101() { // ticket #3003 (segmentation fault)
|
||||
const char code[] = "typedef a x[];\n"
|
||||
"y = x";
|
||||
ASSERT_THROW(tok(code), InternalError);
|
||||
ASSERT_EQUALS("y = x", tok(code));
|
||||
}
|
||||
|
||||
void simplifyTypedef102() { // ticket #3004
|
||||
|
@ -2258,7 +2426,7 @@ private:
|
|||
|
||||
void simplifyTypedef107() { // ticket #3963 (bad code => segmentation fault)
|
||||
const char code[] = "typedef int x[]; int main() { return x }";
|
||||
ASSERT_THROW(tok(code), InternalError);
|
||||
ASSERT_EQUALS("int main ( ) { return x }", tok(code));
|
||||
}
|
||||
|
||||
void simplifyTypedef108() { // ticket #4777
|
||||
|
@ -2517,19 +2685,19 @@ private:
|
|||
"const mat3x3 & Fred::mc() const { return m3x3; }";
|
||||
const char exp[] = "float v3 [ 3 ] ; "
|
||||
"float m3x3 [ 3 ] [ 3 ] ; "
|
||||
"const float ( & gv ( ) ) [ 3 ] { return v3 ; } "
|
||||
"const float ( & gm ( ) ) [ 3 ] [ 3 ] { return m3x3 ; } "
|
||||
"const float * & gv ( ) { return v3 ; } "
|
||||
"const float * * & gm ( ) { return m3x3 ; } "
|
||||
"class Fred { "
|
||||
"public: "
|
||||
"float ( & v ( ) ) [ 3 ] ; "
|
||||
"float ( & m ( ) ) [ 3 ] [ 3 ] ; "
|
||||
"const float ( & vc ( ) const ) [ 3 ] ; "
|
||||
"const float ( & mc ( ) const ) [ 3 ] [ 3 ] ; "
|
||||
"float * & v ( ) ; "
|
||||
"float * * & m ( ) ; "
|
||||
"const float * & vc ( ) const ; "
|
||||
"const float * * & mc ( ) const ; "
|
||||
"} ; "
|
||||
"float ( & Fred :: v ( ) ) [ 3 ] { return v3 ; } "
|
||||
"float ( & Fred :: m ( ) ) [ 3 ] [ 3 ] { return m3x3 ; } "
|
||||
"const float ( & Fred :: vc ( ) const ) [ 3 ] { return v3 ; } "
|
||||
"const float ( & Fred :: mc ( ) const ) [ 3 ] [ 3 ] { return m3x3 ; }";
|
||||
"float * & Fred :: v ( ) { return v3 ; } "
|
||||
"float * * & Fred :: m ( ) { return m3x3 ; } "
|
||||
"const float * & Fred :: vc ( ) const { return v3 ; } "
|
||||
"const float * * & Fred :: mc ( ) const { return m3x3 ; }";
|
||||
ASSERT_EQUALS(exp, tok(code, false));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
@ -2720,7 +2888,7 @@ private:
|
|||
"typedef int int32;\n"
|
||||
"namespace foo { int64 i; }\n"
|
||||
"int32 j;";
|
||||
ASSERT_EQUALS("namespace foo { long long i ; } int j ;", tok(code, false));
|
||||
ASSERT_EQUALS("; namespace foo { long long i ; } int j ;", tok(code, false));
|
||||
}
|
||||
|
||||
void simplifyTypedef135() {
|
||||
|
@ -3319,7 +3487,7 @@ private:
|
|||
"func7 f7;";
|
||||
|
||||
// The expected result..
|
||||
const char expected[] = "C f1 ( ) ; "
|
||||
const char expected[] = "; C f1 ( ) ; "
|
||||
"C ( * f2 ) ( ) ; "
|
||||
"C ( & f3 ) ( ) ; "
|
||||
"C ( * f4 ) ( ) ; "
|
||||
|
@ -3348,7 +3516,7 @@ private:
|
|||
|
||||
// The expected result..
|
||||
// C const -> const C
|
||||
const char expected[] = "const C f1 ( ) ; "
|
||||
const char expected[] = "; const C f1 ( ) ; "
|
||||
"const C ( * f2 ) ( ) ; "
|
||||
"const C ( & f3 ) ( ) ; "
|
||||
"const C ( * f4 ) ( ) ; "
|
||||
|
@ -3376,7 +3544,7 @@ private:
|
|||
"func7 f7;";
|
||||
|
||||
// The expected result..
|
||||
const char expected[] = "const C f1 ( ) ; "
|
||||
const char expected[] = "; const C f1 ( ) ; "
|
||||
"const C ( * f2 ) ( ) ; "
|
||||
"const C ( & f3 ) ( ) ; "
|
||||
"const C ( * f4 ) ( ) ; "
|
||||
|
@ -3404,7 +3572,7 @@ private:
|
|||
"func7 f7;";
|
||||
|
||||
// The expected result..
|
||||
const char expected[] = "C * f1 ( ) ; "
|
||||
const char expected[] = "; C * f1 ( ) ; "
|
||||
"C * ( * f2 ) ( ) ; "
|
||||
"C * ( & f3 ) ( ) ; "
|
||||
"C * ( * f4 ) ( ) ; "
|
||||
|
@ -3432,7 +3600,7 @@ private:
|
|||
"func7 f7;";
|
||||
|
||||
// The expected result..
|
||||
const char expected[] = "const C * f1 ( ) ; "
|
||||
const char expected[] = "; const C * f1 ( ) ; "
|
||||
"const C * ( * f2 ) ( ) ; "
|
||||
"const C * ( & f3 ) ( ) ; "
|
||||
"const C * ( * f4 ) ( ) ; "
|
||||
|
@ -3461,7 +3629,7 @@ private:
|
|||
|
||||
// The expected result..
|
||||
// C const -> const C
|
||||
const char expected[] = "const C * f1 ( ) ; "
|
||||
const char expected[] = "; const C * f1 ( ) ; "
|
||||
"const C * ( * f2 ) ( ) ; "
|
||||
"const C * ( & f3 ) ( ) ; "
|
||||
"const C * ( * f4 ) ( ) ; "
|
||||
|
|
Loading…
Reference in New Issue