forked from qt-creator/qt-creator
		
	CppHighlighter: highlight all functions/methods.
- Highlight all function/methods (not just virtual methods). - Highlight as a function even if number of arguments does not match. In that case, add a diagnostic message to indicate there are too many/too few arguments. - Fix highlighting of parameters in function declarations. These used to be handled indiferently, and they could be mistaken for type or field references. - Properly highlight template method calls. Change-Id: I6e61c9ee47763db95c62314f9cc1c4d398df38b3 Reviewed-by: Leandro Melo <leandro.melo@nokia.com>
This commit is contained in:
		
				
					committed by
					
						
						Leandro Melo
					
				
			
			
				
	
			
			
			
						parent
						
							16bca8b06c
						
					
				
				
					commit
					809611f346
				
			@@ -179,7 +179,8 @@ public:
 | 
			
		||||
    enum ExtraDiagnosticKind
 | 
			
		||||
    {
 | 
			
		||||
        AllExtraDiagnostics = -1,
 | 
			
		||||
        ExportedQmlTypesDiagnostic
 | 
			
		||||
        ExportedQmlTypesDiagnostic,
 | 
			
		||||
        CppSemanticsDiagnostic
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ class CollectSymbols: protected SymbolVisitor
 | 
			
		||||
    Snapshot _snapshot;
 | 
			
		||||
    QSet<QByteArray> _types;
 | 
			
		||||
    QSet<QByteArray> _members;
 | 
			
		||||
    QSet<QByteArray> _virtualMethods;
 | 
			
		||||
    QSet<QByteArray> _functions;
 | 
			
		||||
    QSet<QByteArray> _statics;
 | 
			
		||||
    bool _mainDocument;
 | 
			
		||||
 | 
			
		||||
@@ -90,9 +90,9 @@ public:
 | 
			
		||||
        return _members;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const QSet<QByteArray> &virtualMethods() const
 | 
			
		||||
    const QSet<QByteArray> &functions() const
 | 
			
		||||
    {
 | 
			
		||||
        return _virtualMethods;
 | 
			
		||||
        return _functions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const QSet<QByteArray> &statics() const
 | 
			
		||||
@@ -149,15 +149,14 @@ protected:
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void addVirtualMethod(const Name *name)
 | 
			
		||||
    void addFunction(const Name *name)
 | 
			
		||||
    {
 | 
			
		||||
        if (! name) {
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        } else if (name->isNameId()) {
 | 
			
		||||
            const Identifier *id = name->identifier();
 | 
			
		||||
            _virtualMethods.insert(QByteArray::fromRawData(id->chars(), id->size()));
 | 
			
		||||
 | 
			
		||||
            _functions.insert(QByteArray::fromRawData(id->chars(), id->size()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -181,9 +180,7 @@ protected:
 | 
			
		||||
 | 
			
		||||
    virtual bool visit(Function *symbol)
 | 
			
		||||
    {
 | 
			
		||||
        if (symbol->isVirtual())
 | 
			
		||||
            addVirtualMethod(symbol->name());
 | 
			
		||||
 | 
			
		||||
        addFunction(symbol->name());
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -203,10 +200,8 @@ protected:
 | 
			
		||||
        if (symbol->enclosingEnum() != 0)
 | 
			
		||||
            addStatic(symbol->name());
 | 
			
		||||
 | 
			
		||||
        if (Function *funTy = symbol->type()->asFunctionType()) {
 | 
			
		||||
            if (funTy->isVirtual())
 | 
			
		||||
                addVirtualMethod(symbol->name());
 | 
			
		||||
        }
 | 
			
		||||
        if (symbol->type()->isFunctionType())
 | 
			
		||||
            addFunction(symbol->name());
 | 
			
		||||
 | 
			
		||||
        if (symbol->isTypedef())
 | 
			
		||||
            addType(symbol->name());
 | 
			
		||||
@@ -305,7 +300,7 @@ CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context, cons
 | 
			
		||||
    _fileName = doc->fileName();
 | 
			
		||||
    _potentialTypes = collectTypes.types();
 | 
			
		||||
    _potentialMembers = collectTypes.members();
 | 
			
		||||
    _potentialVirtualMethods = collectTypes.virtualMethods();
 | 
			
		||||
    _potentialFunctions = collectTypes.functions();
 | 
			
		||||
    _potentialStatics = collectTypes.statics();
 | 
			
		||||
 | 
			
		||||
    typeOfExpression.init(_doc, _context.snapshot(), _context.bindings());
 | 
			
		||||
@@ -317,7 +312,7 @@ CheckSymbols::~CheckSymbols()
 | 
			
		||||
void CheckSymbols::run()
 | 
			
		||||
{
 | 
			
		||||
    qSort(_macroUses.begin(), _macroUses.end(), sortByLinePredicate);
 | 
			
		||||
    _diagnosticMessages.clear();
 | 
			
		||||
    _doc->clearDiagnosticMessages();
 | 
			
		||||
 | 
			
		||||
    if (! isCanceled()) {
 | 
			
		||||
        if (_doc->translationUnit()) {
 | 
			
		||||
@@ -333,7 +328,7 @@ void CheckSymbols::run()
 | 
			
		||||
bool CheckSymbols::warning(unsigned line, unsigned column, const QString &text, unsigned length)
 | 
			
		||||
{
 | 
			
		||||
    Document::DiagnosticMessage m(Document::DiagnosticMessage::Warning, _fileName, line, column, text, length);
 | 
			
		||||
    _diagnosticMessages.append(m);
 | 
			
		||||
    _doc->addDiagnosticMessage(m);
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -482,8 +477,8 @@ bool CheckSymbols::visit(SimpleDeclarationAST *ast)
 | 
			
		||||
                if (Function *funTy = decl->type()->asFunctionType()) {
 | 
			
		||||
                    if (funTy->isVirtual()) {
 | 
			
		||||
                        addUse(declId, SemanticInfo::VirtualMethodUse);
 | 
			
		||||
                    } else if (maybeVirtualMethod(decl->name())) {
 | 
			
		||||
                        addVirtualMethod(_context.lookup(decl->name(), decl->enclosingScope()), declId, funTy->argumentCount());
 | 
			
		||||
                    } else {
 | 
			
		||||
                        addFunction(_context.lookup(decl->name(), decl->enclosingScope()), declId, funTy->argumentCount());
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -542,7 +537,7 @@ bool CheckSymbols::visit(CallAST *ast)
 | 
			
		||||
 | 
			
		||||
        if (MemberAccessAST *access = ast->base_expression->asMemberAccess()) {
 | 
			
		||||
            if (access->member_name && access->member_name->name) {
 | 
			
		||||
                if (maybeVirtualMethod(access->member_name->name)) {
 | 
			
		||||
                if (maybeFunction(access->member_name->name)) {
 | 
			
		||||
                    const QByteArray expression = textOf(access);
 | 
			
		||||
 | 
			
		||||
                    const QList<LookupItem> candidates =
 | 
			
		||||
@@ -553,12 +548,12 @@ bool CheckSymbols::visit(CallAST *ast)
 | 
			
		||||
                    if (QualifiedNameAST *q = memberName->asQualifiedName())
 | 
			
		||||
                        memberName = q->unqualified_name;
 | 
			
		||||
 | 
			
		||||
                    addVirtualMethod(candidates, memberName, argumentCount);
 | 
			
		||||
                    addFunction(candidates, memberName, argumentCount);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else if (IdExpressionAST *idExpr = ast->base_expression->asIdExpression()) {
 | 
			
		||||
            if (const Name *name = idExpr->name->name) {
 | 
			
		||||
                if (maybeVirtualMethod(name)) {
 | 
			
		||||
                if (maybeFunction(name)) {
 | 
			
		||||
                    NameAST *exprName = idExpr->name;
 | 
			
		||||
                    if (QualifiedNameAST *q = exprName->asQualifiedName())
 | 
			
		||||
                        exprName = q->unqualified_name;
 | 
			
		||||
@@ -566,7 +561,7 @@ bool CheckSymbols::visit(CallAST *ast)
 | 
			
		||||
                    const QList<LookupItem> candidates =
 | 
			
		||||
                        typeOfExpression(textOf(idExpr), enclosingScope(),
 | 
			
		||||
                                         TypeOfExpression::Preprocess);
 | 
			
		||||
                    addVirtualMethod(candidates, exprName, argumentCount);
 | 
			
		||||
                    addFunction(candidates, exprName, argumentCount);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -658,6 +653,8 @@ void CheckSymbols::checkName(NameAST *ast, Scope *scope)
 | 
			
		||||
            Class *klass = scope->asClass();
 | 
			
		||||
            if (hasVirtualDestructor(_context.lookupType(klass)))
 | 
			
		||||
                addUse(ast, SemanticInfo::VirtualMethodUse);
 | 
			
		||||
            else
 | 
			
		||||
                addUse(ast, SemanticInfo::FunctionUse);
 | 
			
		||||
        } else if (maybeType(ast->name) || maybeStatic(ast->name)) {
 | 
			
		||||
            const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
 | 
			
		||||
            addTypeOrStatic(candidates, ast);
 | 
			
		||||
@@ -686,6 +683,14 @@ bool CheckSymbols::visit(DestructorNameAST *ast)
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CheckSymbols::visit(ParameterDeclarationAST *ast)
 | 
			
		||||
{
 | 
			
		||||
    accept(ast->type_specifier_list);
 | 
			
		||||
    // Skip parameter name, it does not need to be colored
 | 
			
		||||
    accept(ast->expression);
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CheckSymbols::visit(QualifiedNameAST *ast)
 | 
			
		||||
{
 | 
			
		||||
    if (ast->name) {
 | 
			
		||||
@@ -729,6 +734,8 @@ bool CheckSymbols::visit(QualifiedNameAST *ast)
 | 
			
		||||
            if (ast->unqualified_name->asDestructorName() != 0) {
 | 
			
		||||
                if (hasVirtualDestructor(binding))
 | 
			
		||||
                    addUse(ast->unqualified_name, SemanticInfo::VirtualMethodUse);
 | 
			
		||||
                else
 | 
			
		||||
                    addUse(ast->unqualified_name, SemanticInfo::FunctionUse);
 | 
			
		||||
            } else {
 | 
			
		||||
                addTypeOrStatic(binding->find(ast->unqualified_name->name), ast->unqualified_name);
 | 
			
		||||
            }
 | 
			
		||||
@@ -807,8 +814,8 @@ bool CheckSymbols::visit(FunctionDefinitionAST *ast)
 | 
			
		||||
 | 
			
		||||
            if (fun->isVirtual()) {
 | 
			
		||||
                addUse(declId, SemanticInfo::VirtualMethodUse);
 | 
			
		||||
            } else if (maybeVirtualMethod(fun->name())) {
 | 
			
		||||
                addVirtualMethod(_context.lookup(fun->name(), fun->enclosingScope()), declId, fun->argumentCount());
 | 
			
		||||
            } else {
 | 
			
		||||
                addFunction(_context.lookup(fun->name(), fun->enclosingScope()), declId, fun->argumentCount());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -1022,7 +1029,7 @@ void CheckSymbols::addStatic(const QList<LookupItem> &candidates, NameAST *ast)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CheckSymbols::addVirtualMethod(const QList<LookupItem> &candidates, NameAST *ast, unsigned argumentCount)
 | 
			
		||||
void CheckSymbols::addFunction(const QList<LookupItem> &candidates, NameAST *ast, unsigned argumentCount)
 | 
			
		||||
{
 | 
			
		||||
    unsigned startToken = ast->firstToken();
 | 
			
		||||
    if (DestructorNameAST *dtor = ast->asDestructorName())
 | 
			
		||||
@@ -1033,30 +1040,57 @@ void CheckSymbols::addVirtualMethod(const QList<LookupItem> &candidates, NameAST
 | 
			
		||||
    if (tok.generated())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    enum { Match_None, Match_TooManyArgs, Match_TooFewArgs, Match_Ok } matchType = Match_None;
 | 
			
		||||
    SemanticInfo::UseKind kind = SemanticInfo::FunctionUse;
 | 
			
		||||
    foreach (const LookupItem &r, candidates) {
 | 
			
		||||
        Symbol *c = r.declaration();
 | 
			
		||||
        if (! c)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        Function *funTy = r.type()->asFunctionType();
 | 
			
		||||
        if (! funTy)
 | 
			
		||||
            continue;
 | 
			
		||||
        if (! funTy->isVirtual())
 | 
			
		||||
            continue;
 | 
			
		||||
        else if (argumentCount < funTy->minimumArgumentCount())
 | 
			
		||||
            continue;
 | 
			
		||||
        else if (argumentCount > funTy->argumentCount()) {
 | 
			
		||||
            if (! funTy->isVariadic())
 | 
			
		||||
                continue;
 | 
			
		||||
        Function *funTy = c->type()->asFunctionType();
 | 
			
		||||
        if (! funTy) {
 | 
			
		||||
            //Try to find a template function
 | 
			
		||||
            if (Template * t = r.type()->asTemplateType())
 | 
			
		||||
                if ((c = t->declaration()))
 | 
			
		||||
                    funTy = c->type()->asFunctionType();
 | 
			
		||||
        }
 | 
			
		||||
        if (! funTy)
 | 
			
		||||
            continue; // TODO: add diagnostic messages and color call-operators calls too?
 | 
			
		||||
 | 
			
		||||
        if (argumentCount < funTy->minimumArgumentCount()) {
 | 
			
		||||
            if (matchType != Match_Ok) {
 | 
			
		||||
                kind = funTy->isVirtual() ? SemanticInfo::VirtualMethodUse : SemanticInfo::FunctionUse;
 | 
			
		||||
                matchType = Match_TooFewArgs;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (argumentCount > funTy->argumentCount() && ! funTy->isVariadic()) {
 | 
			
		||||
            if (matchType != Match_Ok) {
 | 
			
		||||
                matchType = Match_TooManyArgs;
 | 
			
		||||
                kind = funTy->isVirtual() ? SemanticInfo::VirtualMethodUse : SemanticInfo::FunctionUse;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (!funTy->isVirtual()) {
 | 
			
		||||
            matchType = Match_Ok;
 | 
			
		||||
            kind = SemanticInfo::FunctionUse;
 | 
			
		||||
            //continue, to check if there is a matching candidate which is virtual
 | 
			
		||||
        } else {
 | 
			
		||||
            matchType = Match_Ok;
 | 
			
		||||
            kind = SemanticInfo::VirtualMethodUse;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (matchType != Match_None) {
 | 
			
		||||
        unsigned line, column;
 | 
			
		||||
        getTokenStartPosition(startToken, &line, &column);
 | 
			
		||||
        const unsigned length = tok.length();
 | 
			
		||||
 | 
			
		||||
        const Use use(line, column, length, SemanticInfo::VirtualMethodUse);
 | 
			
		||||
        // Add a diagnostic message if argument count does not match
 | 
			
		||||
        if (matchType == Match_TooFewArgs)
 | 
			
		||||
            warning(line, column, "Too few arguments", length);
 | 
			
		||||
        else if (matchType == Match_TooManyArgs)
 | 
			
		||||
            warning(line, column, "Too many arguments", length);
 | 
			
		||||
 | 
			
		||||
        const Use use(line, column, length, kind);
 | 
			
		||||
        addUse(use);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1112,12 +1146,12 @@ bool CheckSymbols::maybeStatic(const Name *name) const
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CheckSymbols::maybeVirtualMethod(const Name *name) const
 | 
			
		||||
bool CheckSymbols::maybeFunction(const Name *name) const
 | 
			
		||||
{
 | 
			
		||||
    if (name) {
 | 
			
		||||
        if (const Identifier *ident = name->identifier()) {
 | 
			
		||||
            const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
 | 
			
		||||
            if (_potentialVirtualMethods.contains(id))
 | 
			
		||||
            if (_potentialFunctions.contains(id))
 | 
			
		||||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -107,7 +107,7 @@ protected:
 | 
			
		||||
    bool maybeType(const Name *name) const;
 | 
			
		||||
    bool maybeMember(const Name *name) const;
 | 
			
		||||
    bool maybeStatic(const Name *name) const;
 | 
			
		||||
    bool maybeVirtualMethod(const Name *name) const;
 | 
			
		||||
    bool maybeFunction(const Name *name) const;
 | 
			
		||||
 | 
			
		||||
    void checkName(NameAST *ast, Scope *scope = 0);
 | 
			
		||||
    void checkNamespace(NameAST *name);
 | 
			
		||||
@@ -121,7 +121,7 @@ protected:
 | 
			
		||||
    void addTypeOrStatic(const QList<LookupItem> &candidates, NameAST *ast);
 | 
			
		||||
    void addStatic(const QList<LookupItem> &candidates, NameAST *ast);
 | 
			
		||||
    void addClassMember(const QList<LookupItem> &candidates, NameAST *ast);
 | 
			
		||||
    void addVirtualMethod(const QList<LookupItem> &candidates, NameAST *ast, unsigned argumentCount);
 | 
			
		||||
    void addFunction(const QList<LookupItem> &candidates, NameAST *ast, unsigned argumentCount);
 | 
			
		||||
 | 
			
		||||
    bool isTemplateClass(Symbol *s) const;
 | 
			
		||||
 | 
			
		||||
@@ -142,6 +142,7 @@ protected:
 | 
			
		||||
 | 
			
		||||
    virtual bool visit(SimpleNameAST *ast);
 | 
			
		||||
    virtual bool visit(DestructorNameAST *ast);
 | 
			
		||||
    virtual bool visit(ParameterDeclarationAST *ast);
 | 
			
		||||
    virtual bool visit(QualifiedNameAST *ast);
 | 
			
		||||
    virtual bool visit(TemplateIdAST *ast);
 | 
			
		||||
 | 
			
		||||
@@ -166,10 +167,9 @@ private:
 | 
			
		||||
    LookupContext _context;
 | 
			
		||||
    TypeOfExpression typeOfExpression;
 | 
			
		||||
    QString _fileName;
 | 
			
		||||
    QList<Document::DiagnosticMessage> _diagnosticMessages;
 | 
			
		||||
    QSet<QByteArray> _potentialTypes;
 | 
			
		||||
    QSet<QByteArray> _potentialMembers;
 | 
			
		||||
    QSet<QByteArray> _potentialVirtualMethods;
 | 
			
		||||
    QSet<QByteArray> _potentialFunctions;
 | 
			
		||||
    QSet<QByteArray> _potentialStatics;
 | 
			
		||||
    QList<AST *> _astStack;
 | 
			
		||||
    QVector<Use> _usages;
 | 
			
		||||
 
 | 
			
		||||
@@ -1154,13 +1154,19 @@ void CppModelManager::updateEditor(Document::Ptr doc)
 | 
			
		||||
 | 
			
		||||
                    QTextCursor c(ed->document()->findBlockByNumber(m.line() - 1));
 | 
			
		||||
                    const QString text = c.block().text();
 | 
			
		||||
                    for (int i = 0; i < text.size(); ++i) {
 | 
			
		||||
                        if (! text.at(i).isSpace()) {
 | 
			
		||||
                            c.setPosition(c.position() + i);
 | 
			
		||||
                            break;
 | 
			
		||||
                    if (m.length() > 0 && m.column() + m.length() < (unsigned)text.size()) {
 | 
			
		||||
                        int column = m.column() > 0 ? m.column() - 1 : 0;
 | 
			
		||||
                        c.setPosition(c.position() + column);
 | 
			
		||||
                        c.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, m.length());
 | 
			
		||||
                    } else {
 | 
			
		||||
                        for (int i = 0; i < text.size(); ++i) {
 | 
			
		||||
                            if (! text.at(i).isSpace()) {
 | 
			
		||||
                                c.setPosition(c.position() + i);
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
 | 
			
		||||
                    }
 | 
			
		||||
                    c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
 | 
			
		||||
                    sel.cursor = c;
 | 
			
		||||
                    sel.format.setToolTip(m.text());
 | 
			
		||||
                    e.selections.append(sel);
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,8 @@ public:
 | 
			
		||||
        StaticUse,
 | 
			
		||||
        VirtualMethodUse,
 | 
			
		||||
        LabelUse,
 | 
			
		||||
        MacroUse
 | 
			
		||||
        MacroUse,
 | 
			
		||||
        FunctionUse
 | 
			
		||||
    };
 | 
			
		||||
    typedef TextEditor::SemanticHighlighter::Result Use;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user