forked from qt-creator/qt-creator
		
	CPlusPlus: Make Usage::Type QFlags-based
We want to extend the enum with more non-exclusive values. Change-Id: I4d8ebe1f7327139c7817b9f621b4b74a883c5e09 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
		@@ -119,7 +119,7 @@ void FindUsages::reportResult(unsigned tokenIndex, const QList<LookupItem> &cand
 | 
			
		||||
    const int len = tk.utf16chars();
 | 
			
		||||
 | 
			
		||||
    const Usage u(Utils::FilePath::fromString(_doc->fileName()), lineText,
 | 
			
		||||
                  getContainingFunction(line, col), getType(line, col, tokenIndex),
 | 
			
		||||
                  getContainingFunction(line, col), getTags(line, col, tokenIndex),
 | 
			
		||||
                  line, col - 1, len);
 | 
			
		||||
    _usages.append(u);
 | 
			
		||||
    _references.append(tokenIndex);
 | 
			
		||||
@@ -143,86 +143,86 @@ QString FindUsages::getContainingFunction(int line, int column)
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class FindUsages::GetUsageType
 | 
			
		||||
class FindUsages::GetUsageTags
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    GetUsageType(FindUsages *findUsages, const QList<AST *> &astPath, int tokenIndex)
 | 
			
		||||
    GetUsageTags(FindUsages *findUsages, const QList<AST *> &astPath, int tokenIndex)
 | 
			
		||||
        : m_findUsages(findUsages), m_astPath(astPath), m_tokenIndex(tokenIndex)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Usage::Type getUsageType() const
 | 
			
		||||
    Usage::Tags getTags() const
 | 
			
		||||
    {
 | 
			
		||||
        if (m_astPath.size() < 2 || !m_astPath.last()->asSimpleName())
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
            return {};
 | 
			
		||||
 | 
			
		||||
        for (auto it = m_astPath.rbegin() + 1; it != m_astPath.rend(); ++it) {
 | 
			
		||||
            if ((*it)->asExpressionStatement())
 | 
			
		||||
                return Usage::Type::Read;
 | 
			
		||||
                return Usage::Tag::Read;
 | 
			
		||||
            if ((*it)->asSwitchStatement())
 | 
			
		||||
                return Usage::Type::Read;
 | 
			
		||||
                return Usage::Tag::Read;
 | 
			
		||||
            if ((*it)->asCaseStatement())
 | 
			
		||||
                return Usage::Type::Read;
 | 
			
		||||
                return Usage::Tag::Read;
 | 
			
		||||
            if ((*it)->asIfStatement())
 | 
			
		||||
                return Usage::Type::Read;
 | 
			
		||||
                return Usage::Tag::Read;
 | 
			
		||||
            if ((*it)->asLambdaCapture())
 | 
			
		||||
                return Usage::Type::Other;
 | 
			
		||||
                return {};
 | 
			
		||||
            if ((*it)->asTypenameTypeParameter())
 | 
			
		||||
                return Usage::Type::Declaration;
 | 
			
		||||
                return Usage::Tag::Declaration;
 | 
			
		||||
            if ((*it)->asNewExpression())
 | 
			
		||||
                return Usage::Type::Other;
 | 
			
		||||
                return {};
 | 
			
		||||
            if (ClassSpecifierAST *classSpec = (*it)->asClassSpecifier()) {
 | 
			
		||||
                if (classSpec->name == *(it - 1))
 | 
			
		||||
                    return Usage::Type::Declaration;
 | 
			
		||||
                    return Usage::Tag::Declaration;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if (const auto memInitAst = (*it)->asMemInitializer()) {
 | 
			
		||||
                if (memInitAst->name == *(it - 1))
 | 
			
		||||
                    return Usage::Type::Write;
 | 
			
		||||
                return Usage::Type::Read;
 | 
			
		||||
                    return Usage::Tag::Write;
 | 
			
		||||
                return Usage::Tag::Read;
 | 
			
		||||
            }
 | 
			
		||||
            if ((*it)->asCall())
 | 
			
		||||
                return checkPotentialWrite(getUsageTypeForCall(it), it + 1);
 | 
			
		||||
                return checkPotentialWrite(getTagsForCall(it), it + 1);
 | 
			
		||||
            if ((*it)->asDeleteExpression())
 | 
			
		||||
                return Usage::Type::Write;
 | 
			
		||||
                return Usage::Tag::Write;
 | 
			
		||||
            if (const auto binExpr = (*it)->asBinaryExpression()) {
 | 
			
		||||
                if (binExpr->left_expression == *(it - 1) && isAssignment(binExpr->binary_op_token))
 | 
			
		||||
                    return checkPotentialWrite(Usage::Type::Write, it + 1);
 | 
			
		||||
                    return checkPotentialWrite(Usage::Tag::Write, it + 1);
 | 
			
		||||
                const std::optional<LookupItem> item = getTypeOfExpr(binExpr->left_expression,
 | 
			
		||||
                                                                     it + 1);
 | 
			
		||||
                if (!item)
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                return checkPotentialWrite(getUsageTypeFromLhsAndRhs(
 | 
			
		||||
                    return {};
 | 
			
		||||
                return checkPotentialWrite(getTagsFromLhsAndRhs(
 | 
			
		||||
                                               item->type(), binExpr->right_expression, it),
 | 
			
		||||
                                           it + 1);
 | 
			
		||||
            }
 | 
			
		||||
            if (const auto unaryOp = (*it)->asUnaryExpression()) {
 | 
			
		||||
                switch (m_findUsages->tokenKind(unaryOp->unary_op_token)) {
 | 
			
		||||
                case T_PLUS_PLUS: case T_MINUS_MINUS:
 | 
			
		||||
                    return checkPotentialWrite(Usage::Type::Write, it + 1);
 | 
			
		||||
                    return checkPotentialWrite(Usage::Tag::Write, it + 1);
 | 
			
		||||
                case T_AMPER: case T_STAR:
 | 
			
		||||
                    continue;
 | 
			
		||||
                default:
 | 
			
		||||
                    return Usage::Type::Read;
 | 
			
		||||
                    return Usage::Tag::Read;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (const auto sizeofExpr = (*it)->asSizeofExpression()) {
 | 
			
		||||
                if (containsToken(sizeofExpr->expression))
 | 
			
		||||
                    return Usage::Type::Read;
 | 
			
		||||
                return Usage::Type::Other;
 | 
			
		||||
                    return Usage::Tag::Read;
 | 
			
		||||
                return {};
 | 
			
		||||
            }
 | 
			
		||||
            if (const auto arrayExpr = (*it)->asArrayAccess()) {
 | 
			
		||||
                if (containsToken(arrayExpr->expression))
 | 
			
		||||
                    return Usage::Type::Read;
 | 
			
		||||
                    return Usage::Tag::Read;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if (const auto postIncrDecrOp = (*it)->asPostIncrDecr())
 | 
			
		||||
                return checkPotentialWrite(Usage::Type::Write, it + 1);
 | 
			
		||||
                return checkPotentialWrite(Usage::Tag::Write, it + 1);
 | 
			
		||||
            if (const auto declaratorId = (*it)->asDeclaratorId()) {
 | 
			
		||||
                // We don't want to classify constructors and destructors as declarations
 | 
			
		||||
                // when listing class usages.
 | 
			
		||||
                if (m_findUsages->_declSymbol->asClass())
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                    return {};
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if (const auto declarator = (*it)->asDeclarator()) {
 | 
			
		||||
@@ -231,36 +231,36 @@ public:
 | 
			
		||||
                            && (!declarator->postfix_declarator_list
 | 
			
		||||
                            || !declarator->postfix_declarator_list->value
 | 
			
		||||
                            || !declarator->postfix_declarator_list->value->asFunctionDeclarator())) {
 | 
			
		||||
                        return Usage::Type::Initialization;
 | 
			
		||||
                        return {Usage::Tag::Declaration, Usage::Tag::Write};
 | 
			
		||||
                    }
 | 
			
		||||
                    return Usage::Type::Declaration;
 | 
			
		||||
                    return Usage::Tag::Declaration;
 | 
			
		||||
                }
 | 
			
		||||
                if (const auto decl = (*(it + 1))->asSimpleDeclaration()) {
 | 
			
		||||
                    if (decl->symbols && decl->symbols->value) {
 | 
			
		||||
                        return checkPotentialWrite(
 | 
			
		||||
                                    getUsageTypeFromLhsAndRhs(decl->symbols->value->type(),
 | 
			
		||||
                                    getTagsFromLhsAndRhs(decl->symbols->value->type(),
 | 
			
		||||
                                                              declarator->initializer, it + 1),
 | 
			
		||||
                                    it + 1);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return Usage::Type::Other;
 | 
			
		||||
                return {};
 | 
			
		||||
            }
 | 
			
		||||
            if (const auto retStmt = (*it)->asReturnStatement()) {
 | 
			
		||||
                for (auto funcIt = it + 1; funcIt != m_astPath.rend(); ++funcIt) {
 | 
			
		||||
                    if (FunctionDefinitionAST * const funcAst = (*funcIt)->asFunctionDefinition()) {
 | 
			
		||||
                        if (funcAst->symbol) {
 | 
			
		||||
                            return checkPotentialWrite(
 | 
			
		||||
                                        getUsageTypeFromLhsAndRhs(funcAst->symbol->type(),
 | 
			
		||||
                                        getTagsFromLhsAndRhs(funcAst->symbol->type(),
 | 
			
		||||
                                                                  retStmt->expression, funcIt),
 | 
			
		||||
                                        funcIt + 1);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return Usage::Type::Other;
 | 
			
		||||
                return {};
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Usage::Type::Other;
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -286,27 +286,27 @@ private:
 | 
			
		||||
    // 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 Usage::Type getUsageTypeFromDataType(FullySpecifiedType type)
 | 
			
		||||
    static Usage::Tags getTagsFromDataType(FullySpecifiedType type)
 | 
			
		||||
    {
 | 
			
		||||
        if (type.isAuto())
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
            return {};
 | 
			
		||||
        if (const auto refType = type->asReferenceType())
 | 
			
		||||
            return refType->elementType().isConst() ? Usage::Type::Read : Usage::Type::WritableRef;
 | 
			
		||||
            return refType->elementType().isConst() ? Usage::Tag::Read : Usage::Tag::WritableRef;
 | 
			
		||||
        while (type->asPointerType()) {
 | 
			
		||||
            type = type->asPointerType()->elementType();
 | 
			
		||||
            if (!type.isConst())
 | 
			
		||||
                return Usage::Type::WritableRef;
 | 
			
		||||
                return Usage::Tag::WritableRef;
 | 
			
		||||
        }
 | 
			
		||||
        return Usage::Type::Read;
 | 
			
		||||
        return Usage::Tag::Read;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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.
 | 
			
		||||
    Usage::Type checkPotentialWrite(Usage::Type usageType, Iterator startIt) const
 | 
			
		||||
    Usage::Tags checkPotentialWrite(Usage::Tags tags, Iterator startIt) const
 | 
			
		||||
    {
 | 
			
		||||
        if (usageType != Usage::Type::Write && usageType != Usage::Type::WritableRef)
 | 
			
		||||
            return usageType;
 | 
			
		||||
        if (tags != Usage::Tag::Write && tags != Usage::Tag::WritableRef)
 | 
			
		||||
            return tags;
 | 
			
		||||
        for (auto it = startIt; it != m_astPath.rend(); ++it) {
 | 
			
		||||
            if ((*it)->firstToken() > m_tokenIndex)
 | 
			
		||||
                break;
 | 
			
		||||
@@ -324,10 +324,10 @@ private:
 | 
			
		||||
                                     capList->value->identifier->name)) {
 | 
			
		||||
                     continue;
 | 
			
		||||
                 }
 | 
			
		||||
                 return capList->value->amper_token ? usageType : Usage::Type::Read;
 | 
			
		||||
                 return capList->value->amper_token ? tags : Usage::Tag::Read;
 | 
			
		||||
             }
 | 
			
		||||
        }
 | 
			
		||||
        return usageType;
 | 
			
		||||
        return tags;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const QList<LookupItem> getTypesOfExpr(ExpressionAST *expr, Iterator scopeSearchPos) const
 | 
			
		||||
@@ -356,21 +356,21 @@ private:
 | 
			
		||||
        return std::optional<LookupItem>(items.first());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Usage::Type getUsageTypeFromLhsAndRhs(const FullySpecifiedType &lhsType, ExpressionAST *rhs,
 | 
			
		||||
    Usage::Tags getTagsFromLhsAndRhs(const FullySpecifiedType &lhsType, ExpressionAST *rhs,
 | 
			
		||||
                                          Iterator scopeSearchPos) const
 | 
			
		||||
    {
 | 
			
		||||
        const Usage::Type usageType = getUsageTypeFromDataType(lhsType);
 | 
			
		||||
        if (usageType != Usage::Type::Other)
 | 
			
		||||
            return usageType;
 | 
			
		||||
        const Usage::Tags tags = getTagsFromDataType(lhsType);
 | 
			
		||||
        if (tags.toInt())
 | 
			
		||||
            return tags;
 | 
			
		||||
 | 
			
		||||
        // If the lhs has type auto, we use the RHS type.
 | 
			
		||||
        const std::optional<LookupItem> item = getTypeOfExpr(rhs, scopeSearchPos);
 | 
			
		||||
        if (!item)
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
        return getUsageTypeFromDataType(item->type());
 | 
			
		||||
            return {};
 | 
			
		||||
        return getTagsFromDataType(item->type());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Usage::Type getUsageTypeForCall(Iterator callIt) const
 | 
			
		||||
    Usage::Tags getTagsForCall(Iterator callIt) const
 | 
			
		||||
    {
 | 
			
		||||
        CallAST * const call = (*callIt)->asCall();
 | 
			
		||||
 | 
			
		||||
@@ -383,11 +383,11 @@ private:
 | 
			
		||||
                if (!memberAccess || !memberAccess->member_name || !memberAccess->member_name->name)
 | 
			
		||||
                    continue;
 | 
			
		||||
                if (memberAccess->member_name == *(it - 1))
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                    return {};
 | 
			
		||||
                const std::optional<LookupItem> item = getTypeOfExpr(memberAccess->base_expression,
 | 
			
		||||
                                                                     it);
 | 
			
		||||
                if (!item)
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                    return {};
 | 
			
		||||
                FullySpecifiedType baseExprType = item->type();
 | 
			
		||||
                if (const auto refType = baseExprType->asReferenceType())
 | 
			
		||||
                    baseExprType = refType->elementType();
 | 
			
		||||
@@ -406,21 +406,21 @@ private:
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if (!klass)
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                    return {};
 | 
			
		||||
                items = context.lookup(memberAccess->member_name->name, klass);
 | 
			
		||||
                if (items.isEmpty())
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                    return {};
 | 
			
		||||
                for (const LookupItem &item : std::as_const(items)) {
 | 
			
		||||
                    if (item.type()->asFunctionType()) {
 | 
			
		||||
                        if (item.type().isConst())
 | 
			
		||||
                            return Usage::Type::Read;
 | 
			
		||||
                            return Usage::Tag::Read;
 | 
			
		||||
                        if (item.type().isStatic())
 | 
			
		||||
                            return Usage::Type::Other;
 | 
			
		||||
                        return Usage::Type::WritableRef;
 | 
			
		||||
                            return {};
 | 
			
		||||
                        return Usage::Tag::WritableRef;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
            return {};
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check whether our symbol is passed as an argument to the function.
 | 
			
		||||
@@ -433,27 +433,27 @@ private:
 | 
			
		||||
            match = argList->value == *(callIt - 1);
 | 
			
		||||
        }
 | 
			
		||||
        if (!match)
 | 
			
		||||
            return Usage::Type::Other;
 | 
			
		||||
            return {};
 | 
			
		||||
 | 
			
		||||
        // If we find more than one overload with a matching number of arguments,
 | 
			
		||||
        // and they have conflicting usage types, then we give up and report Type::Other.
 | 
			
		||||
        // We could do better by trying to match the types manually and finding out
 | 
			
		||||
        // which overload is the right one, but that would be an inordinate amount
 | 
			
		||||
        // of effort and we'd still have no guarantee that the result is correct.
 | 
			
		||||
        Usage::Type currentType = Usage::Type::Other;
 | 
			
		||||
        Usage::Tags currentTags;
 | 
			
		||||
        for (const LookupItem &item : getTypesOfExpr(call->base_expression, callIt + 1)) {
 | 
			
		||||
            Function * const func = item.type()->asFunctionType();
 | 
			
		||||
            if (!func || func->argumentCount() <= argPos)
 | 
			
		||||
                continue;
 | 
			
		||||
            const Usage::Type newType = getUsageTypeFromLhsAndRhs(
 | 
			
		||||
            const Usage::Tags newTags = getTagsFromLhsAndRhs(
 | 
			
		||||
                        func->argumentAt(argPos)->type(), (*(callIt - 1))->asExpression(), callIt);
 | 
			
		||||
            if (newType != Usage::Type::Other && newType != currentType) {
 | 
			
		||||
                if (currentType != Usage::Type::Other)
 | 
			
		||||
                    return Usage::Type::Other;
 | 
			
		||||
                currentType = newType;
 | 
			
		||||
            if (newTags.toInt() && newTags != currentTags) {
 | 
			
		||||
                if (currentTags.toInt())
 | 
			
		||||
                    return {};
 | 
			
		||||
                currentTags = newTags;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return currentType;
 | 
			
		||||
        return currentTags;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    FindUsages * const m_findUsages;
 | 
			
		||||
@@ -461,11 +461,11 @@ private:
 | 
			
		||||
    const int m_tokenIndex;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Usage::Type FindUsages::getType(int line, int column, int tokenIndex)
 | 
			
		||||
Usage::Tags FindUsages::getTags(int line, int column, int tokenIndex)
 | 
			
		||||
{
 | 
			
		||||
    if (!_categorize)
 | 
			
		||||
        return Usage::Type::Other;
 | 
			
		||||
    return GetUsageType(this, ASTPath(_doc)(line, column), tokenIndex).getUsageType();
 | 
			
		||||
        return {};
 | 
			
		||||
    return GetUsageTags(this, ASTPath(_doc)(line, column), tokenIndex).getTags();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString FindUsages::matchingLine(const Token &tk) const
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user