|
21 | 21 | #include "astutils.h" |
22 | 22 |
|
23 | 23 | #include "config.h" |
| 24 | +#include "errortypes.h" |
24 | 25 | #include "library.h" |
25 | 26 | #include "mathlib.h" |
26 | 27 | #include "settings.h" |
@@ -732,6 +733,75 @@ static void followVariableExpressionError(const Token *tok1, const Token *tok2, |
732 | 733 | errors->push_back(item); |
733 | 734 | } |
734 | 735 |
|
| 736 | +const Token* followReferences(const Token* tok, ErrorPath* errors, int depth = 20) |
| 737 | +{ |
| 738 | + if (!tok) |
| 739 | + return nullptr; |
| 740 | + if (depth < 0) |
| 741 | + return tok; |
| 742 | + const Variable *var = tok->variable(); |
| 743 | + if (var && var->declarationId() == tok->varId()) { |
| 744 | + if (var->nameToken() == tok) { |
| 745 | + return tok; |
| 746 | + } else if (var->isReference() || var->isRValueReference()) { |
| 747 | + if (!var->declEndToken()) |
| 748 | + return tok; |
| 749 | + if (var->isArgument()) { |
| 750 | + if (errors) |
| 751 | + errors->emplace_back(var->declEndToken(), "Passed to reference."); |
| 752 | + return tok; |
| 753 | + } else if (Token::simpleMatch(var->declEndToken(), "=")) { |
| 754 | + if (errors) |
| 755 | + errors->emplace_back(var->declEndToken(), "Assigned to reference."); |
| 756 | + const Token *vartok = var->declEndToken()->astOperand2(); |
| 757 | + if (vartok == tok) |
| 758 | + return tok; |
| 759 | + if (vartok) |
| 760 | + return followReferences(vartok, errors, depth - 1); |
| 761 | + } else { |
| 762 | + return tok; |
| 763 | + } |
| 764 | + } |
| 765 | + } else if (Token::Match(tok->previous(), "%name% (")) { |
| 766 | + const Function *f = tok->previous()->function(); |
| 767 | + if (f) { |
| 768 | + if (!Function::returnsReference(f)) |
| 769 | + return tok; |
| 770 | + std::set<const Token*> result; |
| 771 | + ErrorPath errorPath; |
| 772 | + for (const Token* returnTok : Function::findReturns(f)) { |
| 773 | + if (returnTok == tok) |
| 774 | + continue; |
| 775 | + const Token* argvarTok = followReferences(returnTok, errors, depth - 1); |
| 776 | + const Variable* argvar = argvarTok->variable(); |
| 777 | + if (!argvar) |
| 778 | + return tok; |
| 779 | + if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) { |
| 780 | + int n = getArgumentPos(argvar, f); |
| 781 | + if (n < 0) |
| 782 | + return tok; |
| 783 | + std::vector<const Token*> args = getArguments(tok->previous()); |
| 784 | + if (n >= args.size()) |
| 785 | + return tok; |
| 786 | + const Token* argTok = args[n]; |
| 787 | + ErrorPath er; |
| 788 | + er.emplace_back(returnTok, "Return reference."); |
| 789 | + er.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'."); |
| 790 | + const Token* tok2 = followReferences(argTok, &er, depth - 1); |
| 791 | + errorPath = er; |
| 792 | + result.insert(tok2); |
| 793 | + } |
| 794 | + } |
| 795 | + if (result.size() == 1) { |
| 796 | + if (errors) |
| 797 | + errors->insert(errors->end(), errorPath.begin(), errorPath.end()); |
| 798 | + return *result.begin(); |
| 799 | + } |
| 800 | + } |
| 801 | + } |
| 802 | + return tok; |
| 803 | +} |
| 804 | + |
735 | 805 | static bool isSameLifetime(const Token * const tok1, const Token * const tok2) |
736 | 806 | { |
737 | 807 | ValueFlow::Value v1 = getLifetimeObjValue(tok1); |
@@ -851,6 +921,13 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2 |
851 | 921 | return isSameExpression(cpp, macro, varTok1, varTok2, library, true, followVar, errors); |
852 | 922 | } |
853 | 923 | } |
| 924 | + // Follow references |
| 925 | + if (tok1->str() != tok2->str()) { |
| 926 | + const Token* refTok1 = followReferences(tok1, errors); |
| 927 | + const Token* refTok2 = followReferences(tok2, errors); |
| 928 | + if (refTok1 != tok1 || refTok2 != tok2) |
| 929 | + return isSameExpression(cpp, macro, refTok1, refTok2, library, pure, followVar, errors); |
| 930 | + } |
854 | 931 | if (tok1->varId() != tok2->varId() || tok1->str() != tok2->str() || tok1->originalName() != tok2->originalName()) { |
855 | 932 | if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) || |
856 | 933 | (Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) { |
|
0 commit comments