forked from qt-creator/qt-creator
		
	CPlusPlus: Categorize "Find Usages" results
That is, find out whether a certain access was a read, a write, a declaration or something else, and report the result to upper layers. Follow-up patches can make this information visible to users. Task-number: QTCREATORBUG-12734 Task-number: QTCREATORBUG-19373 Change-Id: Iee79e39dd1eb5a986a7e27846991e0e01b2c3a2f Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
		@@ -28,16 +28,21 @@
 | 
			
		||||
#include "Overview.h"
 | 
			
		||||
 | 
			
		||||
#include <cplusplus/AST.h>
 | 
			
		||||
#include <cplusplus/TranslationUnit.h>
 | 
			
		||||
#include <cplusplus/ASTPath.h>
 | 
			
		||||
#include <cplusplus/Control.h>
 | 
			
		||||
#include <cplusplus/Names.h>
 | 
			
		||||
#include <cplusplus/Symbols.h>
 | 
			
		||||
#include <cplusplus/CoreTypes.h>
 | 
			
		||||
#include <cplusplus/Literals.h>
 | 
			
		||||
#include <cplusplus/Names.h>
 | 
			
		||||
#include <cplusplus/Scope.h>
 | 
			
		||||
#include <cplusplus/Symbols.h>
 | 
			
		||||
#include <cplusplus/TranslationUnit.h>
 | 
			
		||||
#include <cplusplus/TypeOfExpression.h>
 | 
			
		||||
 | 
			
		||||
#include <utils/optional.h>
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
using namespace CPlusPlus;
 | 
			
		||||
 | 
			
		||||
FindUsages::FindUsages(const QByteArray &originalSource, Document::Ptr doc, const Snapshot &snapshot)
 | 
			
		||||
@@ -132,17 +137,251 @@ void FindUsages::reportResult(unsigned tokenIndex, const QList<LookupItem> &cand
 | 
			
		||||
        lineText = fetchLine(line);
 | 
			
		||||
    else
 | 
			
		||||
        lineText = matchingLine(tk);
 | 
			
		||||
 | 
			
		||||
    if (col)
 | 
			
		||||
        --col;  // adjust the column position.
 | 
			
		||||
 | 
			
		||||
    const int len = tk.utf16chars();
 | 
			
		||||
 | 
			
		||||
    const Usage u(Utils::FilePath::fromString(_doc->fileName()), lineText, line, col, len);
 | 
			
		||||
    const Usage u(Utils::FilePath::fromString(_doc->fileName()), lineText,
 | 
			
		||||
                  getType(line, col, tokenIndex), line, col - 1, len);
 | 
			
		||||
    _usages.append(u);
 | 
			
		||||
    _references.append(tokenIndex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Usage::Type FindUsages::getType(int line, int column, int tokenIndex)
 | 
			
		||||
{
 | 
			
		||||
    const auto containsToken = [tokenIndex](const AST *ast) {
 | 
			
		||||
        return ast->firstToken() <= tokenIndex && ast->lastToken() > tokenIndex;
 | 
			
		||||
    };
 | 
			
		||||
    const auto isAssignment = [this](int token) {
 | 
			
		||||
        switch (tokenKind(token)) {
 | 
			
		||||
        case T_AMPER_EQUAL: case T_CARET_EQUAL: case T_SLASH_EQUAL: case T_EQUAL:
 | 
			
		||||
        case T_MINUS_EQUAL: case T_PERCENT_EQUAL: case T_PIPE_EQUAL: case T_PLUS_EQUAL:
 | 
			
		||||
        case T_STAR_EQUAL: case T_TILDE_EQUAL:
 | 
			
		||||
            return true;
 | 
			
		||||
        default:
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // This is called for the type of the LHS of an (initialization) assignment.
 | 
			
		||||
    // We consider the RHS to be writable through the LHS if the LHS is a pointer
 | 
			
		||||
    // that is non-const at any element level, or if it is a a non-const reference.
 | 
			
		||||
    static const auto getUsageTypeFromDataType = [](FullySpecifiedType type) {
 | 
			
		||||
        if (type.isAuto())
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
        if (const auto refType = type->asReferenceType())
 | 
			
		||||
            return refType->elementType().isConst() ? Usage::Type::Read : Usage::Type::WritableRef;
 | 
			
		||||
        while (type->isPointerType()) {
 | 
			
		||||
            type = type->asPointerType()->elementType();
 | 
			
		||||
            if (!type.isConst())
 | 
			
		||||
                return Usage::Type::WritableRef;
 | 
			
		||||
        }
 | 
			
		||||
        return Usage::Type::Read;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const QList<AST *> astPath = ASTPath(_doc)(line, column);
 | 
			
		||||
 | 
			
		||||
    // If we found a potential write access inside a lambda, we have to check whether the variable
 | 
			
		||||
    // was captured by value. If so, it's not really a write access.
 | 
			
		||||
    // FIXME: The parser does not record whether the capture was by reference.
 | 
			
		||||
    const auto checkPotentialWrite = [&](Usage::Type usageType, auto startIt) {
 | 
			
		||||
        if (usageType != Usage::Type::Write && usageType != Usage::Type::WritableRef)
 | 
			
		||||
            return usageType;
 | 
			
		||||
        for (auto it = startIt; it != astPath.rend(); ++it) {
 | 
			
		||||
            if ((*it)->firstToken() > tokenIndex)
 | 
			
		||||
                break;
 | 
			
		||||
            const auto lambdaExpr = (*it)->asLambdaExpression();
 | 
			
		||||
            if (!lambdaExpr)
 | 
			
		||||
                continue;
 | 
			
		||||
             LambdaCaptureAST * const captureAst = lambdaExpr->lambda_introducer->lambda_capture;
 | 
			
		||||
             if (!captureAst)
 | 
			
		||||
                 continue;
 | 
			
		||||
             for (CaptureListAST *capList = captureAst->capture_list; capList;
 | 
			
		||||
                  capList = capList->next) {
 | 
			
		||||
                 if (!capList->value || !capList->value->identifier)
 | 
			
		||||
                     continue;
 | 
			
		||||
                 if (!Matcher::match(_declSymbol->name(), capList->value->identifier->name))
 | 
			
		||||
                     continue;
 | 
			
		||||
                 return capList->value->amper_token ? usageType : Usage::Type::Read;
 | 
			
		||||
             }
 | 
			
		||||
        }
 | 
			
		||||
        return usageType;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const auto getTypeOfExpr = [&](ExpressionAST *expr, auto scopeSearchPos)
 | 
			
		||||
            -> Utils::optional<LookupItem> {
 | 
			
		||||
        if (!expr)
 | 
			
		||||
            return {};
 | 
			
		||||
        Scope *scope = nullptr;
 | 
			
		||||
        for (auto it = scopeSearchPos; !scope && it != astPath.rend(); ++it) {
 | 
			
		||||
            if (const auto stmt = (*it)->asCompoundStatement())
 | 
			
		||||
                scope = stmt->symbol;
 | 
			
		||||
            else if (const auto klass = (*it)->asClassSpecifier())
 | 
			
		||||
                scope = klass->symbol;
 | 
			
		||||
            else if (const auto ns = (*it)->asNamespace())
 | 
			
		||||
                scope = ns->symbol;
 | 
			
		||||
        }
 | 
			
		||||
        if (!scope)
 | 
			
		||||
            scope = _doc->globalNamespace();
 | 
			
		||||
        const QList<LookupItem> items = typeofExpression(expr, _doc, scope);
 | 
			
		||||
        if (items.isEmpty())
 | 
			
		||||
            return {};
 | 
			
		||||
        return Utils::optional<LookupItem>(items.first());
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const auto getUsageTypeFromLhsAndRhs
 | 
			
		||||
            = [&](const FullySpecifiedType &lhsType, ExpressionAST *rhs, auto scopeSearchPos) {
 | 
			
		||||
        const Usage::Type usageType = getUsageTypeFromDataType(lhsType);
 | 
			
		||||
        if (usageType != Usage::Type::Other)
 | 
			
		||||
            return usageType;
 | 
			
		||||
 | 
			
		||||
        // If the lhs has type auto, we use the RHS type.
 | 
			
		||||
        const Utils::optional<LookupItem> item = getTypeOfExpr(rhs, scopeSearchPos);
 | 
			
		||||
        if (!item)
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
        return getUsageTypeFromDataType(item->type());
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const auto getUsageTypeForCall = [&](auto callIt) {
 | 
			
		||||
        CallAST * const call = (*callIt)->asCall();
 | 
			
		||||
 | 
			
		||||
        // Check whether this is a member function call on the symbol we are looking for
 | 
			
		||||
        // (possibly indirectly via a data member).
 | 
			
		||||
        // If it is and the function is not const, then this is a potential write.
 | 
			
		||||
        if (call->base_expression == *(callIt - 1)) {
 | 
			
		||||
            for (auto it = callIt; it != astPath.rbegin(); --it) {
 | 
			
		||||
                const auto memberAccess = (*it)->asMemberAccess();
 | 
			
		||||
                if (!memberAccess)
 | 
			
		||||
                    continue;
 | 
			
		||||
                if (memberAccess->member_name == *(it - 1))
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                const Utils::optional<LookupItem> item
 | 
			
		||||
                        = getTypeOfExpr(memberAccess->base_expression, it);
 | 
			
		||||
                if (!item)
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                FullySpecifiedType baseExprType = item->type();
 | 
			
		||||
                if (const auto refType = baseExprType->asReferenceType())
 | 
			
		||||
                    baseExprType = refType->elementType();
 | 
			
		||||
                while (const auto ptrType = baseExprType->asPointerType())
 | 
			
		||||
                    baseExprType = ptrType->elementType();
 | 
			
		||||
                Class *klass = baseExprType->asClassType();
 | 
			
		||||
                const LookupContext context(_doc, _snapshot);
 | 
			
		||||
                QList<LookupItem> items;
 | 
			
		||||
                if (!klass) {
 | 
			
		||||
                    if (const auto namedType = baseExprType->asNamedType()) {
 | 
			
		||||
                        items = context.lookup(namedType->name(), item->scope());
 | 
			
		||||
                        if (items.isEmpty())
 | 
			
		||||
                            return Usage::Type::Other;
 | 
			
		||||
                        klass = items.first().type()->asClassType();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if (!klass)
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                items = context.lookup(memberAccess->member_name->name, klass);
 | 
			
		||||
                if (items.isEmpty())
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                for (const LookupItem &item : qAsConst(items)) {
 | 
			
		||||
                    if (item.type()->isFunctionType())
 | 
			
		||||
                        return item.type().isConst() ? Usage::Type::Read : Usage::Type::WritableRef;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check whether our symbol is passed as an argument to the function.
 | 
			
		||||
        // If it is and the corresponding parameter is a non-const pointer or reference,
 | 
			
		||||
        // then this is a potential write.
 | 
			
		||||
        bool match = false;
 | 
			
		||||
        int argPos = -1;
 | 
			
		||||
        for (ExpressionListAST *argList = call->expression_list; argList && !match;
 | 
			
		||||
             argList = argList->next, ++argPos) {
 | 
			
		||||
            match = argList->value == *(callIt - 1);
 | 
			
		||||
        }
 | 
			
		||||
        if (!match)
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
        const Utils::optional<LookupItem> item = getTypeOfExpr(call->base_expression, callIt + 1);
 | 
			
		||||
        if (!item)
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
        Function * const func = item->type()->asFunctionType();
 | 
			
		||||
        if (!func || func->argumentCount() <= argPos)
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
        return getUsageTypeFromLhsAndRhs(func->argumentAt(argPos)->type(),
 | 
			
		||||
                                         (*(callIt - 1))->asExpression(), callIt);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (astPath.size() < 2 || !astPath.last()->asSimpleName())
 | 
			
		||||
        return Usage::Type::Other;
 | 
			
		||||
 | 
			
		||||
    for (auto it = astPath.rbegin() + 1; it != astPath.rend(); ++it) {
 | 
			
		||||
        if ((*it)->asExpressionStatement())
 | 
			
		||||
            return Usage::Type::Read;
 | 
			
		||||
        if ((*it)->asLambdaCapture() || (*it)->asNamedTypeSpecifier()
 | 
			
		||||
                || (*it)->asElaboratedTypeSpecifier()) {
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
        }
 | 
			
		||||
        if ((*it)->asTypenameTypeParameter())
 | 
			
		||||
            return Usage::Type::Declaration;
 | 
			
		||||
        if (ClassSpecifierAST *classSpec = (*it)->asClassSpecifier()) {
 | 
			
		||||
            if (classSpec->name == *(it - 1))
 | 
			
		||||
                return Usage::Type::Declaration;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if ((*it)->asCall())
 | 
			
		||||
            return checkPotentialWrite(getUsageTypeForCall(it), it + 1);
 | 
			
		||||
        if (const auto binExpr = (*it)->asBinaryExpression()) {
 | 
			
		||||
            if (binExpr->left_expression == *(it - 1) && isAssignment(binExpr->binary_op_token))
 | 
			
		||||
                return checkPotentialWrite(Usage::Type::Write, it + 1);
 | 
			
		||||
            const Utils::optional<LookupItem> item = getTypeOfExpr(binExpr->left_expression, it + 1);
 | 
			
		||||
            if (!item)
 | 
			
		||||
                return Usage::Type::Other;
 | 
			
		||||
            return checkPotentialWrite(getUsageTypeFromLhsAndRhs(
 | 
			
		||||
                                           item->type(), binExpr->right_expression, it), it + 1);
 | 
			
		||||
        }
 | 
			
		||||
        if (const auto unaryOp = (*it)->asUnaryExpression()) {
 | 
			
		||||
            switch (tokenKind(unaryOp->unary_op_token)) {
 | 
			
		||||
            case T_PLUS_PLUS: case T_MINUS_MINUS:
 | 
			
		||||
                return checkPotentialWrite(Usage::Type::Write, it + 1);
 | 
			
		||||
            case T_AMPER: case T_STAR:
 | 
			
		||||
                continue;
 | 
			
		||||
            default:
 | 
			
		||||
                return Usage::Type::Read;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (const auto declaratorId = (*it)->asDeclaratorId()) {
 | 
			
		||||
            // We don't want to classify constructors and destructors as declarations
 | 
			
		||||
            // when listing class usages.
 | 
			
		||||
            if (_declSymbol->asClass())
 | 
			
		||||
                return Usage::Type::Other;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (const auto declarator = (*it)->asDeclarator()) {
 | 
			
		||||
            if (containsToken(declarator->core_declarator))
 | 
			
		||||
                return Usage::Type::Declaration;
 | 
			
		||||
            if (const auto decl = (*(it + 1))->asSimpleDeclaration()) {
 | 
			
		||||
                if (decl->symbols && decl->symbols->value) {
 | 
			
		||||
                    return checkPotentialWrite(
 | 
			
		||||
                                getUsageTypeFromLhsAndRhs(decl->symbols->value->type(),
 | 
			
		||||
                                                          declarator->initializer, it + 1), it + 1);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
        }
 | 
			
		||||
        if (const auto retStmt = (*it)->asReturnStatement()) {
 | 
			
		||||
            for (auto funcIt = it + 1; funcIt != astPath.rend(); ++funcIt) {
 | 
			
		||||
                if (FunctionDefinitionAST * const funcAst = (*funcIt)->asFunctionDefinition()) {
 | 
			
		||||
                    if (funcAst->symbol) {
 | 
			
		||||
                        return checkPotentialWrite(
 | 
			
		||||
                                    getUsageTypeFromLhsAndRhs(funcAst->symbol->type(),
 | 
			
		||||
                                                              retStmt->expression, funcIt),
 | 
			
		||||
                                    funcIt + 1);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return Usage::Type::Other;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString FindUsages::matchingLine(const Token &tk) const
 | 
			
		||||
{
 | 
			
		||||
    const char *beg = _source.constData();
 | 
			
		||||
 
 | 
			
		||||
@@ -39,13 +39,15 @@ namespace CPlusPlus {
 | 
			
		||||
class CPLUSPLUS_EXPORT Usage
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Usage() = default;
 | 
			
		||||
    Usage(const Utils::FilePath &path, const QString &lineText, int line, int col, int len)
 | 
			
		||||
        : path(path), lineText(lineText), line(line), col(col), len(len) {}
 | 
			
		||||
    enum class Type { Declaration, Read, Write, WritableRef, Other };
 | 
			
		||||
 | 
			
		||||
    Usage() = default;
 | 
			
		||||
    Usage(const Utils::FilePath &path, const QString &lineText, Type t, int line, int col, int len)
 | 
			
		||||
        : path(path), lineText(lineText), type(t), line(line), col(col), len(len) {}
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    Utils::FilePath path;
 | 
			
		||||
    QString lineText;
 | 
			
		||||
    Type type = Type::Other;
 | 
			
		||||
    int line = 0;
 | 
			
		||||
    int col = 0;
 | 
			
		||||
    int len = 0;
 | 
			
		||||
@@ -71,6 +73,7 @@ protected:
 | 
			
		||||
 | 
			
		||||
    void reportResult(unsigned tokenIndex, const Name *name, Scope *scope = nullptr);
 | 
			
		||||
    void reportResult(unsigned tokenIndex, const QList<LookupItem> &candidates);
 | 
			
		||||
    Usage::Type getType(int line, int column, int tokenIndex);
 | 
			
		||||
 | 
			
		||||
    bool checkCandidates(const QList<LookupItem> &candidates) const;
 | 
			
		||||
    void checkExpression(unsigned startToken, unsigned endToken, Scope *scope = nullptr);
 | 
			
		||||
 
 | 
			
		||||
@@ -650,8 +650,9 @@ restart_search:
 | 
			
		||||
                if (macro.name() == useMacro.name()) {
 | 
			
		||||
                    unsigned column;
 | 
			
		||||
                    const QString &lineSource = matchingLine(use.bytesBegin(), source, &column);
 | 
			
		||||
                    usages.append(CPlusPlus::Usage(fileName, lineSource, use.beginLine(), column,
 | 
			
		||||
                                        useMacro.nameToQString().size()));
 | 
			
		||||
                    usages.append(CPlusPlus::Usage(fileName, lineSource,
 | 
			
		||||
                                                   CPlusPlus::Usage::Type::Other, use.beginLine(),
 | 
			
		||||
                                                   column, useMacro.nameToQString().size()));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -133,6 +133,7 @@ private Q_SLOTS:
 | 
			
		||||
    void variableTemplateInExpression();
 | 
			
		||||
 | 
			
		||||
    void variadicMacros();
 | 
			
		||||
    void writableRefs();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::dump(const QList<Usage> &usages) const
 | 
			
		||||
@@ -181,6 +182,8 @@ void tst_FindUsages::inlineMethod()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(arg);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(findUsages.references().size(), 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -214,6 +217,9 @@ void tst_FindUsages::lambdaCaptureByValue()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(d);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 3);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::lambdaCaptureByReference()
 | 
			
		||||
@@ -246,6 +252,10 @@ void tst_FindUsages::lambdaCaptureByReference()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(d);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 3);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
    QEXPECT_FAIL(nullptr, "parser does not record capture type", Continue);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Write);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::shadowedNames_1()
 | 
			
		||||
@@ -276,6 +286,8 @@ void tst_FindUsages::shadowedNames_1()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(d);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::shadowedNames_2()
 | 
			
		||||
@@ -309,6 +321,9 @@ void tst_FindUsages::shadowedNames_2()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(d);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 3);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::staticVariables()
 | 
			
		||||
@@ -355,6 +370,11 @@ void tst_FindUsages::staticVariables()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(d);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 5);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Write);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(3).type, Usage::Type::Write);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(4).type, Usage::Type::Write);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::functionNameFoundInArguments()
 | 
			
		||||
@@ -387,12 +407,15 @@ void foo2(int b=bar()){}    // 3rd result
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(find.usages().size(), 3);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages()[0].line, 1);
 | 
			
		||||
    QCOMPARE(find.usages()[0].col, 5);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(find.usages()[1].type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(find.usages()[1].line, 4);
 | 
			
		||||
    QCOMPARE(find.usages()[1].col, 16);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(find.usages()[2].type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(find.usages()[2].line, 5);
 | 
			
		||||
    QCOMPARE(find.usages()[2].col, 16);
 | 
			
		||||
}
 | 
			
		||||
@@ -451,18 +474,22 @@ struct Struct{
 | 
			
		||||
    find(memberFunctionFoo);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages()[0].line, 3);
 | 
			
		||||
    QCOMPARE(find.usages()[0].col, 15);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(find.usages()[1].type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(find.usages()[1].line, 5);
 | 
			
		||||
    QCOMPARE(find.usages()[1].col, 24);
 | 
			
		||||
 | 
			
		||||
    find(variableFoo);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages()[0].line, 5);
 | 
			
		||||
    QCOMPARE(find.usages()[0].col, 12);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(find.usages()[1].type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages()[1].line, 6);
 | 
			
		||||
    QCOMPARE(find.usages()[1].col, 22);
 | 
			
		||||
}
 | 
			
		||||
@@ -519,6 +546,13 @@ int main() {
 | 
			
		||||
    FindUsages find(src, doc, snapshot);
 | 
			
		||||
    find(sv);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 7);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(3).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(4).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(5).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(6).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::templateConstructorVsCallOperator()
 | 
			
		||||
@@ -571,6 +605,13 @@ int main()
 | 
			
		||||
    FindUsages find(src, doc, snapshot);
 | 
			
		||||
    find(sv);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 7);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(3).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(4).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(5).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(6).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
@@ -667,6 +708,8 @@ void tst_FindUsages::qproperty_1()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(setX_method);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.references().size(), 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -711,6 +754,8 @@ void tst_FindUsages::instantiateTemplateWithNestedClass()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(barDeclaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::operatorAsteriskOfNestedClassOfTemplateClass_QTCREATORBUG9006()
 | 
			
		||||
@@ -756,6 +801,8 @@ void tst_FindUsages::operatorAsteriskOfNestedClassOfTemplateClass_QTCREATORBUG90
 | 
			
		||||
    findUsages(fooDeclaration);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::anonymousClass_QTCREATORBUG8963()
 | 
			
		||||
@@ -799,6 +846,8 @@ void tst_FindUsages::anonymousClass_QTCREATORBUG8963()
 | 
			
		||||
    findUsages(isNotIntDeclaration);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::anonymousClass_QTCREATORBUG11859()
 | 
			
		||||
@@ -839,9 +888,13 @@ void tst_FindUsages::anonymousClass_QTCREATORBUG11859()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(fooAsStruct);
 | 
			
		||||
    QCOMPARE(findUsages.references().size(), 1);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 1);
 | 
			
		||||
    QCOMPARE(findUsages.usages().first().type, Usage::Type::Declaration);
 | 
			
		||||
 | 
			
		||||
    findUsages(fooAsMemberOfAnonymousStruct);
 | 
			
		||||
    QCOMPARE(findUsages.references().size(), 2);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::using_insideGlobalNamespace()
 | 
			
		||||
@@ -882,6 +935,9 @@ void tst_FindUsages::using_insideGlobalNamespace()
 | 
			
		||||
    findUsages(structSymbol);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 3);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::using_insideNamespace()
 | 
			
		||||
@@ -925,6 +981,9 @@ void tst_FindUsages::using_insideNamespace()
 | 
			
		||||
    findUsages(structSymbol);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 3);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::using_insideFunction()
 | 
			
		||||
@@ -965,6 +1024,9 @@ void tst_FindUsages::using_insideFunction()
 | 
			
		||||
    findUsages(structSymbol);
 | 
			
		||||
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 3);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::operatorArrowOfNestedClassOfTemplateClass_QTCREATORBUG9005()
 | 
			
		||||
@@ -1009,6 +1071,8 @@ void tst_FindUsages::operatorArrowOfNestedClassOfTemplateClass_QTCREATORBUG9005(
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(fooDeclaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::templateClassParameters()
 | 
			
		||||
@@ -1044,6 +1108,11 @@ void tst_FindUsages::templateClassParameters()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(templArgument);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 5);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(3).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(4).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::templateClass_className()
 | 
			
		||||
@@ -1085,6 +1154,13 @@ void tst_FindUsages::templateClass_className()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(classTS);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 7);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(3).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(4).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(5).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(6).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::templateFunctionParameters()
 | 
			
		||||
@@ -1118,6 +1194,10 @@ void tst_FindUsages::templateFunctionParameters()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(templArgument);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 4);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(3).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::templatedFunction_QTCREATORBUG9749()
 | 
			
		||||
@@ -1148,6 +1228,8 @@ void tst_FindUsages::templatedFunction_QTCREATORBUG9749()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(func);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::usingInDifferentNamespace_QTCREATORBUG7978()
 | 
			
		||||
@@ -1187,6 +1269,9 @@ void tst_FindUsages::usingInDifferentNamespace_QTCREATORBUG7978()
 | 
			
		||||
    FindUsages findUsages(src, doc, snapshot);
 | 
			
		||||
    findUsages(templateClass);
 | 
			
		||||
    QCOMPARE(findUsages.usages().size(), 3);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::unicodeIdentifier()
 | 
			
		||||
@@ -1214,6 +1299,8 @@ void tst_FindUsages::unicodeIdentifier()
 | 
			
		||||
    findUsages(declaration);
 | 
			
		||||
    const QList<Usage> usages = findUsages.usages();
 | 
			
		||||
    QCOMPARE(usages.size(), 2);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Write);
 | 
			
		||||
    QCOMPARE(usages.at(0).len, 7);
 | 
			
		||||
    QCOMPARE(usages.at(1).len, 7);
 | 
			
		||||
}
 | 
			
		||||
@@ -1243,8 +1330,10 @@ void tst_FindUsages::inAlignas()
 | 
			
		||||
    FindUsages find(src, doc, snapshot);
 | 
			
		||||
    find(c);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages()[0].line, 1);
 | 
			
		||||
    QCOMPARE(find.usages()[0].col, 7);
 | 
			
		||||
    QCOMPARE(find.usages()[1].type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(find.usages()[1].line, 2);
 | 
			
		||||
    QCOMPARE(find.usages()[1].col, 15);
 | 
			
		||||
}
 | 
			
		||||
@@ -1284,8 +1373,10 @@ void tst_FindUsages::memberAccessAsTemplate()
 | 
			
		||||
        FindUsages find(src, doc, snapshot);
 | 
			
		||||
        find(c);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
        QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages()[0].line, 1);
 | 
			
		||||
        QCOMPARE(find.usages()[0].col, 7);
 | 
			
		||||
        QCOMPARE(find.usages()[1].type, Usage::Type::Other);
 | 
			
		||||
        QCOMPARE(find.usages()[1].line, 11);
 | 
			
		||||
        QCOMPARE(find.usages()[1].col, 24);
 | 
			
		||||
    }
 | 
			
		||||
@@ -1303,8 +1394,10 @@ void tst_FindUsages::memberAccessAsTemplate()
 | 
			
		||||
        FindUsages find(src, doc, snapshot);
 | 
			
		||||
        find(f);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
        QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages()[0].line, 4);
 | 
			
		||||
        QCOMPARE(find.usages()[0].col, 7);
 | 
			
		||||
        QCOMPARE(find.usages()[1].type, Usage::Type::Other);
 | 
			
		||||
        QCOMPARE(find.usages()[1].line, 11);
 | 
			
		||||
        QCOMPARE(find.usages()[1].col, 11);
 | 
			
		||||
    }
 | 
			
		||||
@@ -1344,6 +1437,10 @@ void tst_FindUsages::variadicFunctionTemplate()
 | 
			
		||||
        FindUsages find(src, doc, snapshot);
 | 
			
		||||
        find(v);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 4);
 | 
			
		||||
        QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
        QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
 | 
			
		||||
        QCOMPARE(find.usages().at(3).type, Usage::Type::Read);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1391,8 +1488,13 @@ void tst_FindUsages::typeTemplateParameterWithDefault()
 | 
			
		||||
        FindUsages find(src, doc, snapshot);
 | 
			
		||||
        find(xv);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
        QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
        find(sv);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 3);
 | 
			
		||||
        QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
        QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1430,6 +1532,8 @@ void tst_FindUsages::resolveOrder_for_templateFunction_vs_function()
 | 
			
		||||
        FindUsages find(src, doc, snapshot);
 | 
			
		||||
        find(xv);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
        QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1470,6 +1574,9 @@ void tst_FindUsages::templateArrowOperator_with_defaultType()
 | 
			
		||||
        FindUsages find(src, doc, snapshot);
 | 
			
		||||
        find(sv);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 3);
 | 
			
		||||
        QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
        QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1489,7 +1596,7 @@ void tst_FindUsages::templateSpecialization_with_IntArgument()
 | 
			
		||||
                           "    S<2> s2;\n"
 | 
			
		||||
                           "    s0.s.value;\n"
 | 
			
		||||
                           "    s1.s.value;\n"
 | 
			
		||||
                           "    s2.s.value;\n"
 | 
			
		||||
                           "    s2.s.value = s2.s.value;\n"
 | 
			
		||||
                           "}\n";
 | 
			
		||||
 | 
			
		||||
    Document::Ptr doc = Document::create("templateSpecialization_with_IntArgument");
 | 
			
		||||
@@ -1549,18 +1656,25 @@ void tst_FindUsages::templateSpecialization_with_IntArgument()
 | 
			
		||||
        find(sv[1]);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
 | 
			
		||||
        QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages()[0].line, 2);
 | 
			
		||||
        QCOMPARE(find.usages()[0].col, 15);
 | 
			
		||||
        QCOMPARE(find.usages()[1].type, Usage::Type::Read);
 | 
			
		||||
        QCOMPARE(find.usages()[1].line, 13);
 | 
			
		||||
        QCOMPARE(find.usages()[1].col, 9);
 | 
			
		||||
 | 
			
		||||
        find(sv[2]);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 3);
 | 
			
		||||
 | 
			
		||||
        QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages()[0].line, 3);
 | 
			
		||||
        QCOMPARE(find.usages()[0].col, 15);
 | 
			
		||||
        QCOMPARE(find.usages()[1].type, Usage::Type::Write);
 | 
			
		||||
        QCOMPARE(find.usages()[1].line, 14);
 | 
			
		||||
        QCOMPARE(find.usages()[1].col, 9);
 | 
			
		||||
        QCOMPARE(find.usages()[2].type, Usage::Type::Read);
 | 
			
		||||
        QCOMPARE(find.usages()[2].line, 14);
 | 
			
		||||
        QCOMPARE(find.usages()[2].col, 22);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1621,16 +1735,20 @@ void tst_FindUsages::templateSpecialization_with_BoolArgument()
 | 
			
		||||
        find(sv[0]);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
 | 
			
		||||
        QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages()[0].line, 1);
 | 
			
		||||
        QCOMPARE(find.usages()[0].col, 15);
 | 
			
		||||
        QCOMPARE(find.usages()[1].type, Usage::Type::Read);
 | 
			
		||||
        QCOMPARE(find.usages()[1].line, 9);
 | 
			
		||||
        QCOMPARE(find.usages()[1].col, 9);
 | 
			
		||||
 | 
			
		||||
        find(sv[1]);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
 | 
			
		||||
        QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages()[0].line, 2);
 | 
			
		||||
        QCOMPARE(find.usages()[0].col, 15);
 | 
			
		||||
        QCOMPARE(find.usages()[1].type, Usage::Type::Read);
 | 
			
		||||
        QCOMPARE(find.usages()[1].line, 10);
 | 
			
		||||
        QCOMPARE(find.usages()[1].col, 9);
 | 
			
		||||
    }
 | 
			
		||||
@@ -1693,16 +1811,20 @@ void tst_FindUsages::templatePartialSpecialization()
 | 
			
		||||
        find(sv[0]);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
 | 
			
		||||
        QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages()[0].line, 1);
 | 
			
		||||
        QCOMPARE(find.usages()[0].col, 15);
 | 
			
		||||
        QCOMPARE(find.usages()[1].type, Usage::Type::Read);
 | 
			
		||||
        QCOMPARE(find.usages()[1].line, 9);
 | 
			
		||||
        QCOMPARE(find.usages()[1].col, 10);
 | 
			
		||||
 | 
			
		||||
        find(sv[1]);
 | 
			
		||||
        QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
 | 
			
		||||
        QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
 | 
			
		||||
        QCOMPARE(find.usages()[0].line, 2);
 | 
			
		||||
        QCOMPARE(find.usages()[0].col, 15);
 | 
			
		||||
        QCOMPARE(find.usages()[1].type, Usage::Type::Read);
 | 
			
		||||
        QCOMPARE(find.usages()[1].line, 10);
 | 
			
		||||
        QCOMPARE(find.usages()[1].col, 10);
 | 
			
		||||
    }
 | 
			
		||||
@@ -1758,12 +1880,18 @@ int main()
 | 
			
		||||
 | 
			
		||||
    find(sv[0]);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
 | 
			
		||||
    find(sv[1]);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
 | 
			
		||||
    find(sv[2]);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::template_SFINAE_1()
 | 
			
		||||
@@ -1802,6 +1930,8 @@ int main(){
 | 
			
		||||
    FindUsages find(src, doc, snapshot);
 | 
			
		||||
    find(sv);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::variableTemplateInExpression()
 | 
			
		||||
@@ -1845,6 +1975,8 @@ int main(){
 | 
			
		||||
    FindUsages find(src, doc, snapshot);
 | 
			
		||||
    find(sv);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::variadicMacros()
 | 
			
		||||
@@ -1883,6 +2015,184 @@ int main(){}
 | 
			
		||||
    FindUsages find(src, doc, snapshot);
 | 
			
		||||
    find(sv);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 2);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tst_FindUsages::writableRefs()
 | 
			
		||||
{
 | 
			
		||||
    const QByteArray src = R"(
 | 
			
		||||
struct S {
 | 
			
		||||
    static int value;
 | 
			
		||||
    static void *p;
 | 
			
		||||
    static const void *p2;
 | 
			
		||||
    struct Nested {
 | 
			
		||||
        int constFunc() const;
 | 
			
		||||
        void nonConstFunc();
 | 
			
		||||
    } n;
 | 
			
		||||
    Nested constFunc() const;
 | 
			
		||||
    void nonConstFunc();
 | 
			
		||||
};
 | 
			
		||||
void func1(int &);
 | 
			
		||||
void func2(const int &);
 | 
			
		||||
void func3(int *);
 | 
			
		||||
void func4(const int *);
 | 
			
		||||
void func5(int);
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    S s;
 | 
			
		||||
    auto *p = &s.value;
 | 
			
		||||
    int **pp;
 | 
			
		||||
    p = &s.value;
 | 
			
		||||
    *pp = &s.value;
 | 
			
		||||
    //p = &s::value; FIXME: This one is not found at all...
 | 
			
		||||
    s.p = &s.value;
 | 
			
		||||
    // s::p = &s::value; FIXME: Same here.
 | 
			
		||||
    (&s)->p = &((new S)->value);
 | 
			
		||||
    const int *p2 = &s.value;
 | 
			
		||||
    s.p2 = &s.value;
 | 
			
		||||
    int * const p3 = &s.value;
 | 
			
		||||
    int &r = s.value;
 | 
			
		||||
    const int &cr = s.value;
 | 
			
		||||
    func1(s.value);
 | 
			
		||||
    func2(s.value);
 | 
			
		||||
    func3(&s.value);
 | 
			
		||||
    func4(&s.value);
 | 
			
		||||
    func5(s.value);
 | 
			
		||||
    *p = 5;
 | 
			
		||||
    func1(*p);
 | 
			
		||||
    func2(*p);
 | 
			
		||||
    func3(p);
 | 
			
		||||
    func4(p);
 | 
			
		||||
    func5(p);
 | 
			
		||||
    int &r2 = *p;
 | 
			
		||||
    const int &cr2 = *p;
 | 
			
		||||
    s = S();
 | 
			
		||||
    auto * const ps = &s;
 | 
			
		||||
    const auto *ps2 = &s;
 | 
			
		||||
    auto &pr = s;
 | 
			
		||||
    const auto pr2 = &s;
 | 
			
		||||
    s.constFunc().nonConstFunc();
 | 
			
		||||
    s.nonConstFunc();
 | 
			
		||||
    (&s)->nonConstFunc();
 | 
			
		||||
    s.n.constFunc();
 | 
			
		||||
    s.n.nonConstFunc();
 | 
			
		||||
}
 | 
			
		||||
)";
 | 
			
		||||
 | 
			
		||||
    const Document::Ptr doc = Document::create("writableRefs");
 | 
			
		||||
    doc->setUtf8Source(src);
 | 
			
		||||
    doc->check();
 | 
			
		||||
 | 
			
		||||
    QVERIFY(doc->diagnosticMessages().isEmpty());
 | 
			
		||||
    QCOMPARE(doc->globalSymbolCount(), 7);
 | 
			
		||||
 | 
			
		||||
    Snapshot snapshot;
 | 
			
		||||
    snapshot.insert(doc);
 | 
			
		||||
 | 
			
		||||
    Class * const structS = doc->globalSymbolAt(0)->asClass();
 | 
			
		||||
    QVERIFY(structS);
 | 
			
		||||
    QCOMPARE(structS->name()->identifier()->chars(), "S");
 | 
			
		||||
    QCOMPARE(structS->memberCount(), 7);
 | 
			
		||||
 | 
			
		||||
    Declaration * const sv = structS->memberAt(0)->asDeclaration();
 | 
			
		||||
    QVERIFY(sv);
 | 
			
		||||
    QCOMPARE(sv->name()->identifier()->chars(), "value");
 | 
			
		||||
 | 
			
		||||
    // Access to struct member
 | 
			
		||||
    FindUsages find(src, doc, snapshot);
 | 
			
		||||
    find(sv);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 16);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(2).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(3).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(4).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(5).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(6).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(7).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(8).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(9).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(10).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(11).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(12).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(13).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(14).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(15).type, Usage::Type::Read);
 | 
			
		||||
 | 
			
		||||
    Function * const main = doc->globalSymbolAt(6)->asFunction();
 | 
			
		||||
    QVERIFY(main);
 | 
			
		||||
    QCOMPARE(main->memberCount(), 1);
 | 
			
		||||
    Block * const block = main->memberAt(0)->asBlock();
 | 
			
		||||
    QVERIFY(block);
 | 
			
		||||
    QCOMPARE(block->memberCount(), 13);
 | 
			
		||||
 | 
			
		||||
    // Access to pointer
 | 
			
		||||
    Declaration * const p = block->memberAt(1)->asDeclaration();
 | 
			
		||||
    QVERIFY(p);
 | 
			
		||||
    QCOMPARE(p->name()->identifier()->chars(), "p");
 | 
			
		||||
    find(p);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 10);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::Write);
 | 
			
		||||
    QCOMPARE(find.usages().at(2).type, Usage::Type::Write);
 | 
			
		||||
    QCOMPARE(find.usages().at(3).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(4).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(5).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(6).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(7).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(8).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(9).type, Usage::Type::Read);
 | 
			
		||||
 | 
			
		||||
    // Access to struct variable via its members
 | 
			
		||||
    Declaration * const varS = block->memberAt(0)->asDeclaration();
 | 
			
		||||
    QVERIFY(varS);
 | 
			
		||||
    QCOMPARE(varS->name()->identifier()->chars(), "s");
 | 
			
		||||
    find(varS);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 28);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(2).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(3).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(4).type, Usage::Type::Write);
 | 
			
		||||
    QCOMPARE(find.usages().at(5).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(6).type, Usage::Type::Write);
 | 
			
		||||
    QCOMPARE(find.usages().at(7).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(8).type, Usage::Type::Write);
 | 
			
		||||
    QCOMPARE(find.usages().at(9).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(10).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(11).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(12).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(13).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(14).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(15).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(16).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(17).type, Usage::Type::Read);
 | 
			
		||||
 | 
			
		||||
    // Direct access to struct variable
 | 
			
		||||
    QCOMPARE(find.usages().at(18).type, Usage::Type::Write);
 | 
			
		||||
    QCOMPARE(find.usages().at(19).type, Usage::Type::WritableRef);
 | 
			
		||||
    QEXPECT_FAIL(nullptr, "parser does not record const qualifier for auto types", Continue);
 | 
			
		||||
    QCOMPARE(find.usages().at(20).type, Usage::Type::Read);
 | 
			
		||||
    QEXPECT_FAIL(nullptr, "parser does not record reference qualifier for auto types", Continue);
 | 
			
		||||
    QCOMPARE(find.usages().at(21).type, Usage::Type::WritableRef);
 | 
			
		||||
    QEXPECT_FAIL(nullptr, "parser does not record const qualifier for auto types", Continue);
 | 
			
		||||
    QCOMPARE(find.usages().at(22).type, Usage::Type::Read);
 | 
			
		||||
 | 
			
		||||
    // Member function calls.
 | 
			
		||||
    QCOMPARE(find.usages().at(23).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(24).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(25).type, Usage::Type::WritableRef);
 | 
			
		||||
    QCOMPARE(find.usages().at(26).type, Usage::Type::Read);
 | 
			
		||||
    QCOMPARE(find.usages().at(27).type, Usage::Type::WritableRef);
 | 
			
		||||
 | 
			
		||||
    // Usages of struct type
 | 
			
		||||
    find(structS);
 | 
			
		||||
    QCOMPARE(find.usages().size(), 4);
 | 
			
		||||
    QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
 | 
			
		||||
    QCOMPARE(find.usages().at(1).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(find.usages().at(2).type, Usage::Type::Other);
 | 
			
		||||
    QCOMPARE(find.usages().at(3).type, Usage::Type::Other);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QTEST_APPLESS_MAIN(tst_FindUsages)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user