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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user