void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings)
{
    const SymbolDatabase* symbolDatabase = tokenizer.getSymbolDatabase();

    // Function declarations..
    for (std::size_t i = 0; i < symbolDatabase->functionScopes.size(); i++) {
        const Scope* scope = symbolDatabase->functionScopes[i];
        const Function* func = scope->function;
        if (!func || !func->token || scope->classStart->fileIndex() != 0)
            continue;

        // Don't warn about functions that are marked by __attribute__((constructor)) or __attribute__((destructor))
        if (func->isAttributeConstructor() || func->isAttributeDestructor() || func->type != Function::eFunction)
            continue;

        // Don't care about templates
        if (func->retDef->str() == "template")
            continue;

        FunctionUsage &usage = _functions[func->name()];

        if (!usage.lineNumber)
            usage.lineNumber = func->token->linenr();

        // No filename set yet..
        if (usage.filename.empty()) {
            usage.filename = tokenizer.getSourceFilePath();
        }
        // Multiple files => filename = "+"
        else if (usage.filename != tokenizer.getSourceFilePath()) {
            //func.filename = "+";
            usage.usedOtherFile |= usage.usedSameFile;
        }
    }

    // Function usage..
    for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {

        // parsing of library code to find called functions
        if (settings->library.isexecutableblock(FileName, tok->str())) {
            const Token * markupVarToken = tok->tokAt(settings->library.blockstartoffset(FileName));
            int scope = 0;
            bool start = true;
            // find all function calls in library code (starts with '(', not if or while etc)
            while (scope || start) {
                if (markupVarToken->str() == settings->library.blockstart(FileName)) {
                    scope++;
                    if (start) {
                        start = false;
                    }
                } else if (markupVarToken->str() == settings->library.blockend(FileName))
                    scope--;
                else if (!settings->library.iskeyword(FileName, markupVarToken->str())) {
                    if (_functions.find(markupVarToken->str()) != _functions.end())
                        _functions[markupVarToken->str()].usedOtherFile = true;
                    else if (markupVarToken->next()->str() == "(") {
                        FunctionUsage &func = _functions[markupVarToken->str()];
                        func.filename = tokenizer.getSourceFilePath();
                        if (func.filename.empty() || func.filename == "+")
                            func.usedOtherFile = true;
                        else
                            func.usedSameFile = true;
                    }
                }
                markupVarToken = markupVarToken->next();
            }
        }

        if (!settings->library.markupFile(FileName) // only check source files
            && settings->library.isexporter(tok->str()) && tok->next() != 0) {
            const Token * qPropToken = tok;
            qPropToken = qPropToken->next();
            while (qPropToken && qPropToken->str() != ")") {
                if (settings->library.isexportedprefix(tok->str(), qPropToken->str())) {
                    const Token* qNextPropToken = qPropToken->next();
                    const std::string& value = qNextPropToken->str();
                    if (_functions.find(value) != _functions.end()) {
                        _functions[value].usedOtherFile = true;
                    }
                }
                if (settings->library.isexportedsuffix(tok->str(), qPropToken->str())) {
                    const Token* qNextPropToken = qPropToken->previous();
                    const std::string& value = qNextPropToken->str();
                    if (value != ")" && _functions.find(value) != _functions.end()) {
                        _functions[value].usedOtherFile = true;
                    }
                }
                qPropToken = qPropToken->next();
            }
        }

        if (settings->library.markupFile(FileName)
            && settings->library.isimporter(FileName, tok->str()) && tok->next()) {
            const Token * qPropToken = tok;
            qPropToken = qPropToken->next();
            if (qPropToken->next()) {
                qPropToken = qPropToken->next();
                while (qPropToken && qPropToken->str() != ")") {
                    const std::string& value = qPropToken->str();
                    if (!value.empty()) {
                        _functions[value].usedOtherFile = true;
                        break;
                    }
                    qPropToken = qPropToken->next();
                }
            }
        }

        if (settings->library.isreflection(tok->str())) {
            const int index = settings->library.reflectionArgument(tok->str());
            if (index >= 0) {
                const Token * funcToken = tok->next();
                int p = 0;
                std::string value;
                while (funcToken) {
                    if (funcToken->str()==",") {
                        if (++p==index)
                            break;
                        value = "";
                    } else
                        value += funcToken->str();
                    funcToken = funcToken->next();
                }
                if (p==index) {
                    value = value.substr(1, value.length() - 2);
                    _functions[value].usedOtherFile = true;
                }
            }
        }

        const Token *funcname = nullptr;

        if (tok->scope()->isExecutable() && Token::Match(tok->next(), "%var% (")) {
            funcname = tok->next();
        }

        else if (tok->scope()->isExecutable() && Token::Match(tok->next(), "%var% <") && Token::simpleMatch(tok->linkAt(2), "> (")) {
            funcname = tok->next();
        }

        else if (Token::Match(tok, "[;{}.,()[=+-/|!?:] &| %var% [(),;:}]")) {
            funcname = tok->next();
            if (tok->str() == "&")
                funcname = funcname->next();
        }

        else if (Token::Match(tok, "[;{}.,()[=+-/|!?:] &| %var% :: %var%")) {
            funcname = tok->next();
            if (funcname->str() == "&")
                funcname = funcname->next();
            while (Token::Match(funcname,"%var% :: %var%"))
                funcname = funcname->tokAt(2);
            if (!Token::Match(funcname, "%var% [(),;:}]"))
                continue;
        }

        else
            continue;

        // funcname ( => Assert that the end parentheses isn't followed by {
        if (Token::Match(funcname, "%var% (|<")) {
            const Token *ftok = funcname->next();
            if (ftok->str() == "<")
                ftok = ftok->link();
            if (Token::Match(ftok->linkAt(1), ") const|throw|{"))
                funcname = nullptr;
        }

        if (funcname) {
            FunctionUsage &func = _functions[ funcname->str()];

            if (func.filename.empty() || func.filename == "+")
                func.usedOtherFile = true;
            else
                func.usedSameFile = true;
        }
    }
}
void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer)
{
    // Function declarations..
    for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
        if (tok->fileIndex() != 0)
            continue;

        // token contains a ':' => skip to next ; or {
        if (tok->str().find(":") != std::string::npos) {
            while (tok && tok->str().find_first_of(";{"))
                tok = tok->next();
            if (tok)
                continue;
            break;
        }

        // If this is a template function, skip it
        if (tok->previous() && tok->previous()->str() == ">")
            continue;

        const Token *funcname = 0;

        if (Token::Match(tok, "%type% %var% ("))
            funcname = tok->next();
        else if (Token::Match(tok, "%type% *|& %var% ("))
            funcname = tok->tokAt(2);
        else if (Token::Match(tok, "%type% :: %var% (") && !Token::Match(tok, tok->strAt(2).c_str()))
            funcname = tok->tokAt(2);

        // Don't assume throw as a function name: void foo() throw () {}
        if (Token::Match(tok->previous(), ")|const") || funcname == 0)
            continue;

        tok = funcname->linkAt(1);

        // Check that ") {" is found..
        if (! Token::simpleMatch(tok, ") {") &&
            ! Token::simpleMatch(tok, ") const {") &&
            ! Token::simpleMatch(tok, ") const throw ( ) {") &&
            ! Token::simpleMatch(tok, ") throw ( ) {"))
            funcname = 0;

        if (funcname) {
            FunctionUsage &func = _functions[ funcname->str()];

            if (!func.lineNumber)
                func.lineNumber = funcname->linenr();

            // No filename set yet..
            if (func.filename.empty()) {
                func.filename = tokenizer.getSourceFilePath();
            }
            // Multiple files => filename = "+"
            else if (func.filename != tokenizer.getSourceFilePath()) {
                //func.filename = "+";
                func.usedOtherFile |= func.usedSameFile;
            }
        }
    }

    // Function usage..
    for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
        const Token *funcname = 0;

        if (Token::Match(tok->next(), "%var% (")) {
            funcname = tok->next();
        }

        else if (Token::Match(tok, "[;{}.,()[=+-/&|!?:] %var% [(),;:}]"))
            funcname = tok->next();

        else if (Token::Match(tok, "[=(,] &| %var% :: %var%")) {
            funcname = tok->next();
            if (funcname->str() == "&")
                funcname = funcname->next();
            while (Token::Match(funcname,"%var% :: %var%"))
                funcname = funcname->tokAt(2);
            if (!Token::Match(funcname, "%var% [,);]"))
                continue;
        }

        else
            continue;

        // funcname ( => Assert that the end parenthesis isn't followed by {
        if (Token::Match(funcname, "%var% (")) {
            if (Token::Match(funcname->linkAt(1), ") const|{"))
                funcname = NULL;
        }

        if (funcname) {
            FunctionUsage &func = _functions[ funcname->str()];

            if (func.filename.empty() || func.filename == "+")
                func.usedOtherFile = true;
            else
                func.usedSameFile = true;
        }
    }
}
Exemple #3
0
void MakeClassFunctionFunctionsTable::parseTokens(const Tokenizer &tokenizer)
{
	symbolDatabase=tokenizer.getSymbolDatabase();

	// Function declarations..
    for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { 

		if (scope->type != Scope::eClass)
			continue;
		functionFunctionTable[scope._Ptr->_Myval.className];

		for (const Token *tok = scope->classDef->next(); tok && tok != scope->classEnd; tok = tok->next()) {
			const Token *funcname = 0;

			if (Token::Match(tok, "%type% %var% ("))
				funcname = tok->next();
			else if (Token::Match(tok, "%type% *|& %var% ("))
				funcname = tok->tokAt(2);

			// Don't assume throw as a function name: void foo() throw () {}
			if (Token::Match(tok->previous(), ")|const") || funcname == 0)
				continue;

			tok = funcname->linkAt(1);

			if (funcname) {
				FunctionDeclaration &func = _functions[ funcname->str()];

				if (!func.lineNumber)
					func.lineNumber = funcname->linenr();

				// No filename set yet..
				if (func.filename.empty()) {
					func.filename = tokenizer.getSourceFilePath();
				}

				if(func.scopeName.empty())
				{
					func.scopeName = tok->scope()->className;
					func.scopeType = tok->scope()->type;
				}
			}
		}
    }

	// Function usage..
    for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
        // only check functions
        if (scope->type != Scope::eFunction)
            continue;
	
		if(_functions[scope->className].scopeName.empty() || _functions[scope->className].scopeType!=Scope::eClass)
			continue;

	    for (const Token *tok = scope->classDef->next(); tok && tok != scope->classEnd; tok = tok->next()) {
			const Token *funcname = 0;

			if (Token::Match(tok->next(), "%var% (")) {
				funcname = tok->next();
			}

			else if (Token::Match(tok, "[;{}.,()[=+-/&|!?:] %var% [(),;:}]"))
				funcname = tok->next();

			else if (Token::Match(tok, "[=(,] &| %var% :: %var%")) {
				funcname = tok->next();
				if (funcname->str() == "&")
					funcname = funcname->next();
				while (Token::Match(funcname,"%var% :: %var%"))
					funcname = funcname->tokAt(2);
				if (!Token::Match(funcname, "%var% [,);]"))
					continue;
			}

			else
				continue;

			// funcname ( => Assert that the end parenthesis isn't followed by {
			if (Token::Match(funcname, "%var% (")) {
				if (Token::Match(funcname->linkAt(1), ") const|{"))
					funcname = NULL;
			}

			if (funcname) {
				if(_functions[funcname->str()].scopeName.empty() || _functions[funcname->str()].scopeType!=Scope::eClass)
					continue;

				//사용기록 저장
				std::pair<bool,			// read or write
							std::pair<	std::string,	//file path
										unsigned int	//code line
										>> a;
				a.first=false;
				a.second.first=tokenizer.getSourceFilePath();
				a.second.second=funcname->linenr();

				std::list<std::pair<bool,std::pair<	std::string,unsigned int>>>::iterator it;
				for(it=functionFunctionTable[_functions[funcname->str()].scopeName][funcname->str()][scope->className].begin();
					it!=functionFunctionTable[_functions[funcname->str()].scopeName][funcname->str()][scope->className].end();
					++it)
				{
					if(it->second.first.find(a.first) && it->second.second==a.second.second)
						break;
				}
				if(it==functionFunctionTable[_functions[funcname->str()].scopeName][funcname->str()][scope->className].end())
					functionFunctionTable[_functions[funcname->str()].scopeName][funcname->str()][scope->className].push_back(a);
			}
		}
	}
}
void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings)
{
    // Function declarations..
    for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
        if (tok->fileIndex() != 0)
            continue;

        // token contains a ':' => skip to next ; or {
        if (tok->str().find(":") != std::string::npos) {
            while (tok && tok->str().find_first_of(";{"))
                tok = tok->next();
            if (tok)
                continue;
            break;
        }

        // If this is a template function, skip it
        if (tok->previous() && tok->previous()->str() == ">")
            continue;

        const Token *funcname = 0;

        if (Token::Match(tok, "%type% %var% ("))
            funcname = tok->next();
        else if (Token::Match(tok, "%type% *|& %var% ("))
            funcname = tok->tokAt(2);
        else if (Token::Match(tok, "%type% :: %var% (") && !Token::Match(tok, tok->strAt(2).c_str()))
            funcname = tok->tokAt(2);

        // Don't assume throw as a function name: void foo() throw () {}
        if (Token::Match(tok->previous(), ")|const") || funcname == 0)
            continue;

        // Don't warn about functions that are marked by __attribute__((constructor))
        if (tok->isAttributeConstructor() || funcname->isAttributeConstructor())
            continue;

        tok = funcname->linkAt(1);

        // Check that ") {" is found..
        if (! Token::Match(tok, ") const| {") &&
            ! Token::Match(tok, ") const| throw ( ) {"))
            funcname = 0;

        if (funcname) {
            FunctionUsage &func = _functions[ funcname->str()];

            if (!func.lineNumber)
                func.lineNumber = funcname->linenr();

            // No filename set yet..
            if (func.filename.empty()) {
                func.filename = tokenizer.getSourceFilePath();
            }
            // Multiple files => filename = "+"
            else if (func.filename != tokenizer.getSourceFilePath()) {
                //func.filename = "+";
                func.usedOtherFile |= func.usedSameFile;
            }
        }
    }

    // Function usage..
    const Token *scopeEnd = NULL;
    for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {

        // parsing of library code to find called functions
        if (settings->library.isexecutableblock(FileName, tok->str())) {
            const Token * markupVarToken = tok->tokAt(settings->library.blockstartoffset(FileName));
            int scope = 1;
            // find all function calls in library code (starts with '(', not if or while etc)
            while (scope) {
                if (markupVarToken->str() == settings->library.blockstart(FileName)) {
                    scope++;
                } else if (markupVarToken->str() == settings->library.blockend(FileName))
                    scope--;
                else if (!settings->library.iskeyword(FileName, markupVarToken->str())) {
                    if (_functions.find(markupVarToken->str()) != _functions.end())
                        _functions[markupVarToken->str()].usedOtherFile = true;
                    else if (markupVarToken->next()->str() == "(") {
                        FunctionUsage &func = _functions[markupVarToken->str()];
                        func.filename = tokenizer.getSourceFilePath();
                        if (func.filename.empty() || func.filename == "+")
                            func.usedOtherFile = true;
                        else
                            func.usedSameFile = true;
                    }
                }
                markupVarToken = markupVarToken->next();
            }
        }

        if (!settings->library.markupFile(FileName) // only check source files
            && settings->library.isexporter(tok->str()) && tok->next() != 0) {
            const Token * qPropToken = tok;
            qPropToken = qPropToken->next();
            while (qPropToken && qPropToken->str() != ")") {
                if (settings->library.isexportedprefix(tok->str(), qPropToken->str())) {
                    const Token* qNextPropToken = qPropToken->next();
                    const std::string value = qNextPropToken->str();
                    if (_functions.find(value) != _functions.end()) {
                        _functions[value].usedOtherFile = true;
                    }
                }
                if (settings->library.isexportedsuffix(tok->str(), qPropToken->str())) {
                    const Token* qNextPropToken = qPropToken->previous();
                    const std::string value = qNextPropToken->str();
                    if (value != ")" && _functions.find(value) != _functions.end()) {
                        _functions[value].usedOtherFile = true;
                    }
                }
                qPropToken = qPropToken->next();
            }
        }

        if (settings->library.markupFile(FileName)
            && settings->library.isimporter(FileName, tok->str()) && tok->next()) {
            const Token * qPropToken = tok;
            qPropToken = qPropToken->next();
            if (qPropToken->next()) {
                qPropToken = qPropToken->next();
                while (qPropToken && qPropToken->str() != ")") {
                    const std::string value = qPropToken->str();
                    if (!value.empty()) {
                        _functions[value].usedOtherFile = true;
                        break;
                    }
                    qPropToken = qPropToken->next();
                }
            }
        }

        if (settings->library.isreflection(FileName, tok->str())) {
            const int index = settings->library.reflectionArgument(FileName, tok->str());
            if (index >= 0) {
                const Token * funcToken = tok->tokAt(index);
                if (funcToken) {
                    std::string value = funcToken->str();
                    value = value.substr(1, value.length() - 2);
                    _functions[value].usedOtherFile = true;
                }
            }
        }

        if (scopeEnd == NULL) {
            if (!Token::Match(tok, ")|= const| {"))
                continue;
            scopeEnd = tok;
            while (scopeEnd->str() != "{")
                scopeEnd = scopeEnd->next();
            scopeEnd = scopeEnd->link();
        } else if (tok == scopeEnd) {
            scopeEnd = NULL;
            continue;
        }


        const Token *funcname = 0;

        if (Token::Match(tok->next(), "%var% (")) {
            funcname = tok->next();
        }

        else if (Token::Match(tok->next(), "%var% <") && Token::simpleMatch(tok->linkAt(2), "> (")) {
            funcname = tok->next();
        }

        else if (Token::Match(tok, "[;{}.,()[=+-/&|!?:] %var% [(),;:}]"))
            funcname = tok->next();

        else if (Token::Match(tok, "[=(,] &| %var% :: %var%")) {
            funcname = tok->next();
            if (funcname->str() == "&")
                funcname = funcname->next();
            while (Token::Match(funcname,"%var% :: %var%"))
                funcname = funcname->tokAt(2);
            if (!Token::Match(funcname, "%var% [,);]"))
                continue;
        }

        else
            continue;

        // funcname ( => Assert that the end parentheses isn't followed by {
        if (Token::Match(funcname, "%var% (|<")) {
            const Token *ftok = funcname->next();
            if (ftok->str() == "<")
                ftok = ftok->link();
            if (Token::Match(ftok->linkAt(1), ") const|throw|{"))
                funcname = NULL;
        }

        if (funcname) {
            FunctionUsage &func = _functions[ funcname->str()];

            if (func.filename.empty() || func.filename == "+")
                func.usedOtherFile = true;
            else
                func.usedSameFile = true;
        }
    }
}
Exemple #5
0
void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &tokenizer)
{
    (void)tokenlist;
    (void)tokenizer;

#ifdef HAVE_RULES
    // Are there rules to execute?
    bool isrule = false;
    for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
        if (it->tokenlist == tokenlist)
            isrule = true;
    }

    // There is no rule to execute
    if (isrule == false)
        return;

    // Write all tokens in a string that can be parsed by pcre
    std::ostringstream ostr;
    for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next())
        ostr << " " << tok->str();
    const std::string str(ostr.str());

    for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
        const Settings::Rule &rule = *it;
        if (rule.pattern.empty() || rule.id.empty() || rule.severity.empty() || rule.tokenlist != tokenlist)
            continue;

        const char *error = 0;
        int erroffset = 0;
        pcre *re = pcre_compile(rule.pattern.c_str(),0,&error,&erroffset,NULL);
        if (!re) {
            if (error) {
                ErrorLogger::ErrorMessage errmsg(std::list<ErrorLogger::ErrorMessage::FileLocation>(),
                                                 Severity::error,
                                                 error,
                                                 "pcre_compile",
                                                 false);

                reportErr(errmsg);
            }
            continue;
        }

        int pos = 0;
        int ovector[30];
        while (pos < (int)str.size() && 0 <= pcre_exec(re, NULL, str.c_str(), (int)str.size(), pos, 0, ovector, 30)) {
            unsigned int pos1 = (unsigned int)ovector[0];
            unsigned int pos2 = (unsigned int)ovector[1];

            // jump to the end of the match for the next pcre_exec
            pos = (int)pos2;

            // determine location..
            ErrorLogger::ErrorMessage::FileLocation loc;
            loc.setfile(tokenizer.getSourceFilePath());
            loc.line = 0;

            std::size_t len = 0;
            for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
                len = len + 1U + tok->str().size();
                if (len > pos1) {
                    loc.setfile(tokenizer.list.getFiles().at(tok->fileIndex()));
                    loc.line = tok->linenr();
                    break;
                }
            }

            const std::list<ErrorLogger::ErrorMessage::FileLocation> callStack(1, loc);

            // Create error message
            std::string summary;
            if (rule.summary.empty())
                summary = "found '" + str.substr(pos1, pos2 - pos1) + "'";
            else
                summary = rule.summary;
            const ErrorLogger::ErrorMessage errmsg(callStack, Severity::fromString(rule.severity), summary, rule.id, false);

            // Report error
            reportErr(errmsg);
        }

        pcre_free(re);
    }
#endif
}