forked from qt-creator/qt-creator
Highlight user defined types.
This commit is contained in:
@@ -36,16 +36,211 @@
|
|||||||
#include <TranslationUnit.h>
|
#include <TranslationUnit.h>
|
||||||
#include <Scope.h>
|
#include <Scope.h>
|
||||||
#include <AST.h>
|
#include <AST.h>
|
||||||
|
#include <SymbolVisitor.h>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
using namespace CPlusPlus;
|
using namespace CPlusPlus;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class CollectTypes: protected SymbolVisitor
|
||||||
|
{
|
||||||
|
Document::Ptr _doc;
|
||||||
|
Snapshot _snapshot;
|
||||||
|
QSet<QByteArray> _types;
|
||||||
|
QList<ScopedSymbol *> _scopes;
|
||||||
|
QList<NameAST *> _names;
|
||||||
|
bool _mainDocument;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CollectTypes(Document::Ptr doc, const Snapshot &snapshot)
|
||||||
|
: _doc(doc), _snapshot(snapshot), _mainDocument(false)
|
||||||
|
{
|
||||||
|
QSet<Namespace *> processed;
|
||||||
|
process(doc, &processed);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QSet<QByteArray> &types() const
|
||||||
|
{
|
||||||
|
return _types;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QList<ScopedSymbol *> &scopes() const
|
||||||
|
{
|
||||||
|
return _scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Scope *findScope(unsigned tokenOffset, const QList<ScopedSymbol *> &scopes)
|
||||||
|
{
|
||||||
|
for (int i = scopes.size() - 1; i != -1; --i) {
|
||||||
|
ScopedSymbol *symbol = scopes.at(i);
|
||||||
|
const unsigned start = symbol->startOffset();
|
||||||
|
const unsigned end = symbol->endOffset();
|
||||||
|
|
||||||
|
if (tokenOffset >= start && tokenOffset < end)
|
||||||
|
return symbol->members();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void process(Document::Ptr doc, QSet<Namespace *> *processed)
|
||||||
|
{
|
||||||
|
if (! doc)
|
||||||
|
return;
|
||||||
|
else if (! processed->contains(doc->globalNamespace())) {
|
||||||
|
processed->insert(doc->globalNamespace());
|
||||||
|
|
||||||
|
foreach (const Document::Include &i, doc->includes())
|
||||||
|
process(_snapshot.document(i.fileName()), processed);
|
||||||
|
|
||||||
|
_mainDocument = (doc == _doc); // ### improve
|
||||||
|
accept(doc->globalNamespace());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addType(const Identifier *id)
|
||||||
|
{
|
||||||
|
if (id)
|
||||||
|
_types.insert(QByteArray::fromRawData(id->chars(), id->size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addType(const Name *name)
|
||||||
|
{
|
||||||
|
if (! name) {
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
|
||||||
|
for (unsigned i = 0; i < q->nameCount(); ++i)
|
||||||
|
addType(q->nameAt(i));
|
||||||
|
|
||||||
|
} else if (name->isNameId() || name->isTemplateNameId()) {
|
||||||
|
addType(name->identifier());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addScope(ScopedSymbol *symbol)
|
||||||
|
{
|
||||||
|
if (_mainDocument)
|
||||||
|
_scopes.append(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// nothing to do
|
||||||
|
virtual bool visit(UsingNamespaceDirective *) { return true; }
|
||||||
|
virtual bool visit(UsingDeclaration *) { return true; }
|
||||||
|
virtual bool visit(Argument *) { return true; }
|
||||||
|
virtual bool visit(BaseClass *) { return true; }
|
||||||
|
|
||||||
|
virtual bool visit(Function *symbol)
|
||||||
|
{
|
||||||
|
addScope(symbol);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(Block *symbol)
|
||||||
|
{
|
||||||
|
addScope(symbol);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(NamespaceAlias *symbol)
|
||||||
|
{
|
||||||
|
addType(symbol->name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(Declaration *symbol)
|
||||||
|
{
|
||||||
|
if (symbol->isTypedef())
|
||||||
|
addType(symbol->name());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(TypenameArgument *symbol)
|
||||||
|
{
|
||||||
|
addType(symbol->name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(Enum *symbol)
|
||||||
|
{
|
||||||
|
addScope(symbol);
|
||||||
|
addType(symbol->name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(Namespace *symbol)
|
||||||
|
{
|
||||||
|
addScope(symbol);
|
||||||
|
addType(symbol->name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(Class *symbol)
|
||||||
|
{
|
||||||
|
addScope(symbol);
|
||||||
|
addType(symbol->name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(ForwardClassDeclaration *symbol)
|
||||||
|
{
|
||||||
|
addType(symbol->name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Objective-C
|
||||||
|
virtual bool visit(ObjCBaseClass *) { return true; }
|
||||||
|
virtual bool visit(ObjCBaseProtocol *) { return true; }
|
||||||
|
virtual bool visit(ObjCPropertyDeclaration *) { return true; }
|
||||||
|
|
||||||
|
virtual bool visit(ObjCMethod *symbol)
|
||||||
|
{
|
||||||
|
addScope(symbol);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(ObjCClass *symbol)
|
||||||
|
{
|
||||||
|
addScope(symbol);
|
||||||
|
addType(symbol->name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(ObjCForwardClassDeclaration *symbol)
|
||||||
|
{
|
||||||
|
addType(symbol->name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(ObjCProtocol *symbol)
|
||||||
|
{
|
||||||
|
addScope(symbol);
|
||||||
|
addType(symbol->name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(ObjCForwardProtocolDeclaration *symbol)
|
||||||
|
{
|
||||||
|
addType(symbol->name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of anonymous namespace
|
||||||
|
|
||||||
CheckUndefinedSymbols::CheckUndefinedSymbols(TranslationUnit *unit, const LookupContext &context)
|
CheckUndefinedSymbols::CheckUndefinedSymbols(TranslationUnit *unit, const LookupContext &context)
|
||||||
: ASTVisitor(unit), _context(context)
|
: ASTVisitor(unit), _context(context)
|
||||||
{
|
{
|
||||||
_fileName = context.thisDocument()->fileName();
|
_fileName = context.thisDocument()->fileName();
|
||||||
|
CollectTypes collectTypes(context.thisDocument(), context.snapshot());
|
||||||
|
_potentialTypes = collectTypes.types();
|
||||||
|
_scopes = collectTypes.scopes();
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckUndefinedSymbols::~CheckUndefinedSymbols()
|
CheckUndefinedSymbols::~CheckUndefinedSymbols()
|
||||||
@@ -84,17 +279,19 @@ bool CheckUndefinedSymbols::visit(UsingDirectiveAST *ast)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckUndefinedSymbols::visit(SimpleDeclarationAST *ast)
|
bool CheckUndefinedSymbols::visit(SimpleDeclarationAST *)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckUndefinedSymbols::visit(NamedTypeSpecifierAST *ast)
|
bool CheckUndefinedSymbols::visit(NamedTypeSpecifierAST *ast)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
if (ast->name) {
|
if (ast->name) {
|
||||||
unsigned line, column;
|
unsigned line, column;
|
||||||
getTokenStartPosition(ast->firstToken(), &line, &column);
|
getTokenStartPosition(ast->name->firstToken(), &line, &column);
|
||||||
|
|
||||||
|
// ### use the potential types.
|
||||||
Scope *enclosingScope = _context.thisDocument()->scopeAt(line, column);
|
Scope *enclosingScope = _context.thisDocument()->scopeAt(line, column);
|
||||||
const QList<Symbol *> candidates = _context.lookup(ast->name->name, enclosingScope);
|
const QList<Symbol *> candidates = _context.lookup(ast->name->name, enclosingScope);
|
||||||
|
|
||||||
@@ -108,8 +305,9 @@ bool CheckUndefinedSymbols::visit(NamedTypeSpecifierAST *ast)
|
|||||||
if (! ty)
|
if (! ty)
|
||||||
warning(ast->name, QCoreApplication::translate("CheckUndefinedSymbols", "Expected a type-name"));
|
warning(ast->name, QCoreApplication::translate("CheckUndefinedSymbols", "Expected a type-name"));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckUndefinedSymbols::checkNamespace(NameAST *name)
|
void CheckUndefinedSymbols::checkNamespace(NameAST *name)
|
||||||
@@ -131,3 +329,133 @@ void CheckUndefinedSymbols::checkNamespace(NameAST *name)
|
|||||||
const unsigned length = tokenAt(name->lastToken() - 1).end() - tokenAt(name->firstToken()).begin();
|
const unsigned length = tokenAt(name->lastToken() - 1).end() - tokenAt(name->firstToken()).begin();
|
||||||
warning(line, column, QCoreApplication::translate("CheckUndefinedSymbols", "Expected a namespace-name"), length);
|
warning(line, column, QCoreApplication::translate("CheckUndefinedSymbols", "Expected a namespace-name"), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckUndefinedSymbols::visit(SimpleNameAST *ast)
|
||||||
|
{
|
||||||
|
if (ast->name) {
|
||||||
|
const QByteArray id = QByteArray::fromRawData(ast->name->identifier()->chars(), // ### move
|
||||||
|
ast->name->identifier()->size());
|
||||||
|
if (_potentialTypes.contains(id)) {
|
||||||
|
const unsigned tokenOffset = tokenAt(ast->firstToken()).offset;
|
||||||
|
Scope *scope = CollectTypes::findScope(tokenOffset, _scopes); // ### move
|
||||||
|
if (! scope)
|
||||||
|
scope = _context.thisDocument()->globalSymbols();
|
||||||
|
|
||||||
|
const QList<Symbol *> candidates = _context.lookup(ast->name, scope);
|
||||||
|
addTypeUsage(candidates, ast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckUndefinedSymbols::visit(TemplateIdAST *ast)
|
||||||
|
{
|
||||||
|
if (ast->name) {
|
||||||
|
const QByteArray id = QByteArray::fromRawData(ast->name->identifier()->chars(), // ### move
|
||||||
|
ast->name->identifier()->size());
|
||||||
|
if (_potentialTypes.contains(id)) {
|
||||||
|
Scope *scope = CollectTypes::findScope(tokenAt(ast->firstToken()).offset, _scopes); // ### move
|
||||||
|
if (! scope)
|
||||||
|
scope = _context.thisDocument()->globalSymbols();
|
||||||
|
|
||||||
|
ClassOrNamespace *b = _context.lookupType(ast->name, scope);
|
||||||
|
addTypeUsage(b, ast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckUndefinedSymbols::visit(DestructorNameAST *ast)
|
||||||
|
{
|
||||||
|
if (ast->name) {
|
||||||
|
const QByteArray id = QByteArray::fromRawData(ast->name->identifier()->chars(), // ### move
|
||||||
|
ast->name->identifier()->size());
|
||||||
|
if (_potentialTypes.contains(id)) {
|
||||||
|
Scope *scope = CollectTypes::findScope(tokenAt(ast->firstToken()).offset, _scopes); // ### move
|
||||||
|
if (! scope)
|
||||||
|
scope = _context.thisDocument()->globalSymbols();
|
||||||
|
|
||||||
|
ClassOrNamespace *b = _context.lookupType(ast->name, scope);
|
||||||
|
addTypeUsage(b, ast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckUndefinedSymbols::visit(QualifiedNameAST *ast)
|
||||||
|
{
|
||||||
|
if (ast->name) {
|
||||||
|
Scope *scope = CollectTypes::findScope(tokenAt(ast->firstToken()).offset, _scopes); // ### move
|
||||||
|
if (! scope)
|
||||||
|
scope = _context.thisDocument()->globalSymbols();
|
||||||
|
|
||||||
|
ClassOrNamespace *b = 0;
|
||||||
|
if (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list) {
|
||||||
|
NestedNameSpecifierAST *nested_name_specifier = it->value;
|
||||||
|
NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name; // ### remove shadowing
|
||||||
|
|
||||||
|
const Name *name = class_or_namespace_name->name;
|
||||||
|
b = _context.lookupType(name, scope);
|
||||||
|
addTypeUsage(b, class_or_namespace_name);
|
||||||
|
|
||||||
|
for (it = it->next; b && it; it = it->next) {
|
||||||
|
NestedNameSpecifierAST *nested_name_specifier = it->value;
|
||||||
|
|
||||||
|
if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) {
|
||||||
|
b = b->findType(class_or_namespace_name->name);
|
||||||
|
addTypeUsage(b, class_or_namespace_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b && ast->unqualified_name)
|
||||||
|
addTypeUsage(b->find(ast->unqualified_name->name), ast->unqualified_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckUndefinedSymbols::addTypeUsage(ClassOrNamespace *b, NameAST *ast)
|
||||||
|
{
|
||||||
|
if (! b)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const Token &tok = tokenAt(ast->firstToken());
|
||||||
|
if (tok.generated())
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned line, column;
|
||||||
|
getTokenStartPosition(ast->firstToken(), &line, &column);
|
||||||
|
const unsigned length = tok.length();
|
||||||
|
Use use(line, column, length);
|
||||||
|
_typeUsages.append(use);
|
||||||
|
//qDebug() << "added use" << oo(ast->name) << line << column << length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckUndefinedSymbols::addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast)
|
||||||
|
{
|
||||||
|
const Token &tok = tokenAt(ast->firstToken());
|
||||||
|
if (tok.generated())
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned line, column;
|
||||||
|
getTokenStartPosition(ast->firstToken(), &line, &column);
|
||||||
|
const unsigned length = tok.length();
|
||||||
|
|
||||||
|
foreach (Symbol *c, candidates) {
|
||||||
|
if (c->isTypedef() || c->isClass() || c->isEnum() || c->isForwardClassDeclaration() || c->isTypenameArgument()) {
|
||||||
|
Use use(line, column, length);
|
||||||
|
_typeUsages.append(use);
|
||||||
|
//qDebug() << "added use" << oo(ast->name) << line << column << length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<CheckUndefinedSymbols::Use> CheckUndefinedSymbols::typeUsages() const
|
||||||
|
{
|
||||||
|
return _typeUsages;
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "CppDocument.h"
|
#include "CppDocument.h"
|
||||||
#include "LookupContext.h"
|
#include "LookupContext.h"
|
||||||
#include <ASTVisitor.h>
|
#include <ASTVisitor.h>
|
||||||
|
#include <QtCore/QSet>
|
||||||
|
|
||||||
namespace CPlusPlus {
|
namespace CPlusPlus {
|
||||||
|
|
||||||
@@ -44,6 +45,17 @@ public:
|
|||||||
|
|
||||||
QList<Document::DiagnosticMessage> operator()(AST *ast);
|
QList<Document::DiagnosticMessage> operator()(AST *ast);
|
||||||
|
|
||||||
|
struct Use { // ### remove me
|
||||||
|
unsigned line;
|
||||||
|
unsigned column;
|
||||||
|
unsigned length;
|
||||||
|
|
||||||
|
Use(unsigned line = 0, unsigned column = 0, unsigned length = 0)
|
||||||
|
: line(line), column(column), length(length) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<Use> typeUsages() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using ASTVisitor::visit;
|
using ASTVisitor::visit;
|
||||||
|
|
||||||
@@ -51,15 +63,25 @@ protected:
|
|||||||
bool warning(AST *ast, const QString &text);
|
bool warning(AST *ast, const QString &text);
|
||||||
|
|
||||||
void checkNamespace(NameAST *name);
|
void checkNamespace(NameAST *name);
|
||||||
|
void addTypeUsage(ClassOrNamespace *b, NameAST *ast);
|
||||||
|
void addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast);
|
||||||
|
|
||||||
virtual bool visit(UsingDirectiveAST *);
|
virtual bool visit(UsingDirectiveAST *);
|
||||||
virtual bool visit(SimpleDeclarationAST *);
|
virtual bool visit(SimpleDeclarationAST *);
|
||||||
virtual bool visit(NamedTypeSpecifierAST *);
|
virtual bool visit(NamedTypeSpecifierAST *);
|
||||||
|
|
||||||
|
virtual bool visit(SimpleNameAST *ast);
|
||||||
|
virtual bool visit(DestructorNameAST *ast);
|
||||||
|
virtual bool visit(QualifiedNameAST *ast);
|
||||||
|
virtual bool visit(TemplateIdAST *ast);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LookupContext _context;
|
LookupContext _context;
|
||||||
QString _fileName;
|
QString _fileName;
|
||||||
QList<Document::DiagnosticMessage> _diagnosticMessages;
|
QList<Document::DiagnosticMessage> _diagnosticMessages;
|
||||||
|
QSet<QByteArray> _potentialTypes;
|
||||||
|
QList<ScopedSymbol *> _scopes;
|
||||||
|
QList<Use> _typeUsages;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace CPlusPlus
|
} // end of namespace CPlusPlus
|
||||||
|
|||||||
@@ -128,12 +128,14 @@ void FindUsages::reportResult(unsigned tokenIndex, const QList<Symbol *> &candid
|
|||||||
|
|
||||||
void FindUsages::reportResult(unsigned tokenIndex)
|
void FindUsages::reportResult(unsigned tokenIndex)
|
||||||
{
|
{
|
||||||
if (_processed.contains(tokenIndex))
|
const Token &tk = tokenAt(tokenIndex);
|
||||||
|
if (tk.generated())
|
||||||
|
return;
|
||||||
|
else if (_processed.contains(tokenIndex))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_processed.insert(tokenIndex);
|
_processed.insert(tokenIndex);
|
||||||
|
|
||||||
const Token &tk = tokenAt(tokenIndex);
|
|
||||||
const QString lineText = matchingLine(tk);
|
const QString lineText = matchingLine(tk);
|
||||||
|
|
||||||
unsigned line, col;
|
unsigned line, col;
|
||||||
|
|||||||
@@ -779,14 +779,11 @@ void Preprocessor::preprocess(const QString &fileName, const QByteArray &source,
|
|||||||
if (! env->isBuiltinMacro(spell)) {
|
if (! env->isBuiltinMacro(spell)) {
|
||||||
Macro *m = env->resolve(spell);
|
Macro *m = env->resolve(spell);
|
||||||
if (m && ! m->isFunctionLike()) {
|
if (m && ! m->isFunctionLike()) {
|
||||||
QByteArray expandedDefinition;
|
// expand object-like macros.
|
||||||
expandObjectLikeMacro(identifierToken, spell, m, &expandedDefinition);
|
processObjectLikeMacro(identifierToken, spell, m);
|
||||||
if (expandedDefinition.trimmed().isEmpty()) {
|
|
||||||
out(QByteArray(spell.length(), ' '));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
out(spell);
|
out(spell);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -265,6 +265,10 @@ protected:
|
|||||||
|
|
||||||
bool findMemberForToken(unsigned tokenIdx, NameAST *ast)
|
bool findMemberForToken(unsigned tokenIdx, NameAST *ast)
|
||||||
{
|
{
|
||||||
|
const Token &tok = tokenAt(tokenIdx);
|
||||||
|
if (tok.generated())
|
||||||
|
return false;
|
||||||
|
|
||||||
unsigned line, column;
|
unsigned line, column;
|
||||||
getTokenStartPosition(tokenIdx, &line, &column);
|
getTokenStartPosition(tokenIdx, &line, &column);
|
||||||
|
|
||||||
@@ -303,6 +307,10 @@ protected:
|
|||||||
for (TemplateArgumentListAST *arg = ast->template_argument_list; arg; arg = arg->next)
|
for (TemplateArgumentListAST *arg = ast->template_argument_list; arg; arg = arg->next)
|
||||||
accept(arg->value);
|
accept(arg->value);
|
||||||
|
|
||||||
|
const Token &tok = tokenAt(ast->identifier_token);
|
||||||
|
if (tok.generated())
|
||||||
|
return false;
|
||||||
|
|
||||||
unsigned line, column;
|
unsigned line, column;
|
||||||
getTokenStartPosition(ast->firstToken(), &line, &column);
|
getTokenStartPosition(ast->firstToken(), &line, &column);
|
||||||
|
|
||||||
@@ -1781,6 +1789,7 @@ void CPPEditor::setFontSettings(const TextEditor::FontSettings &fs)
|
|||||||
m_occurrencesUnusedFormat.clearForeground();
|
m_occurrencesUnusedFormat.clearForeground();
|
||||||
m_occurrencesUnusedFormat.setToolTip(tr("Unused variable"));
|
m_occurrencesUnusedFormat.setToolTip(tr("Unused variable"));
|
||||||
m_occurrenceRenameFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES_RENAME));
|
m_occurrenceRenameFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES_RENAME));
|
||||||
|
m_typeFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_TYPE));
|
||||||
|
|
||||||
// only set the background, we do not want to modify foreground properties set by the syntax highlighter or the link
|
// only set the background, we do not want to modify foreground properties set by the syntax highlighter or the link
|
||||||
m_occurrencesFormat.clearForeground();
|
m_occurrencesFormat.clearForeground();
|
||||||
@@ -1889,6 +1898,21 @@ void CPPEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
setExtraSelections(UndefinedSymbolSelection, undefinedSymbolSelections);
|
setExtraSelections(UndefinedSymbolSelection, undefinedSymbolSelections);
|
||||||
|
|
||||||
|
QList<QTextEdit::ExtraSelection> typeSelections;
|
||||||
|
foreach (const SemanticInfo::Use &use, semanticInfo.typeUsages) {
|
||||||
|
QTextCursor cursor(document());
|
||||||
|
cursor.setPosition(document()->findBlockByNumber(use.line - 1).position() + use.column - 1);
|
||||||
|
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, use.length);
|
||||||
|
|
||||||
|
QTextEdit::ExtraSelection sel;
|
||||||
|
sel.cursor = cursor;
|
||||||
|
sel.format = m_typeFormat;
|
||||||
|
typeSelections.append(sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
setExtraSelections(TypeSelection, typeSelections);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setExtraSelections(UnusedSymbolSelection, unusedSelections);
|
setExtraSelections(UnusedSymbolSelection, unusedSelections);
|
||||||
@@ -1987,12 +2011,14 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
|
|||||||
Snapshot snapshot;
|
Snapshot snapshot;
|
||||||
Document::Ptr doc;
|
Document::Ptr doc;
|
||||||
QList<Document::DiagnosticMessage> diagnosticMessages;
|
QList<Document::DiagnosticMessage> diagnosticMessages;
|
||||||
|
QList<SemanticInfo::Use> typeUsages;
|
||||||
|
|
||||||
if (! source.force && revision == source.revision) {
|
if (! source.force && revision == source.revision) {
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
snapshot = m_lastSemanticInfo.snapshot; // ### TODO: use the new snapshot.
|
snapshot = m_lastSemanticInfo.snapshot; // ### TODO: use the new snapshot.
|
||||||
doc = m_lastSemanticInfo.doc;
|
doc = m_lastSemanticInfo.doc;
|
||||||
diagnosticMessages = m_lastSemanticInfo.diagnosticMessages;
|
diagnosticMessages = m_lastSemanticInfo.diagnosticMessages;
|
||||||
|
typeUsages = m_lastSemanticInfo.typeUsages;
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2003,17 +2029,14 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
|
|||||||
doc = snapshot.documentFromSource(preprocessedCode, source.fileName);
|
doc = snapshot.documentFromSource(preprocessedCode, source.fileName);
|
||||||
doc->check();
|
doc->check();
|
||||||
|
|
||||||
Document::Ptr documentInSnapshot = snapshot.document(source.fileName);
|
|
||||||
if (! documentInSnapshot) {
|
|
||||||
// use the newly parsed document.
|
|
||||||
documentInSnapshot = doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
LookupContext context(doc, snapshot);
|
LookupContext context(doc, snapshot);
|
||||||
|
|
||||||
if (TranslationUnit *unit = doc->translationUnit()) {
|
if (TranslationUnit *unit = doc->translationUnit()) {
|
||||||
CheckUndefinedSymbols checkUndefinedSymbols(unit, context);
|
CheckUndefinedSymbols checkUndefinedSymbols(unit, context);
|
||||||
diagnosticMessages = checkUndefinedSymbols(unit->ast());
|
diagnosticMessages = checkUndefinedSymbols(unit->ast());
|
||||||
|
typeUsages.clear();
|
||||||
|
foreach (const CheckUndefinedSymbols::Use &use, checkUndefinedSymbols.typeUsages()) // ### remove me
|
||||||
|
typeUsages.append(SemanticInfo::Use(use.line, use.column, use.length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2035,6 +2058,7 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
|
|||||||
semanticInfo.hasD = useTable.hasD;
|
semanticInfo.hasD = useTable.hasD;
|
||||||
semanticInfo.forced = source.force;
|
semanticInfo.forced = source.force;
|
||||||
semanticInfo.diagnosticMessages = diagnosticMessages;
|
semanticInfo.diagnosticMessages = diagnosticMessages;
|
||||||
|
semanticInfo.typeUsages = typeUsages;
|
||||||
|
|
||||||
return semanticInfo;
|
return semanticInfo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ public:
|
|||||||
bool forced: 1;
|
bool forced: 1;
|
||||||
CPlusPlus::Snapshot snapshot;
|
CPlusPlus::Snapshot snapshot;
|
||||||
CPlusPlus::Document::Ptr doc;
|
CPlusPlus::Document::Ptr doc;
|
||||||
LocalUseMap localUses;
|
LocalUseMap localUses; // ### rename
|
||||||
|
QList<Use> typeUsages;
|
||||||
QList<CPlusPlus::Document::DiagnosticMessage> diagnosticMessages;
|
QList<CPlusPlus::Document::DiagnosticMessage> diagnosticMessages;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -299,6 +300,7 @@ private:
|
|||||||
QTextCharFormat m_occurrencesFormat;
|
QTextCharFormat m_occurrencesFormat;
|
||||||
QTextCharFormat m_occurrencesUnusedFormat;
|
QTextCharFormat m_occurrencesUnusedFormat;
|
||||||
QTextCharFormat m_occurrenceRenameFormat;
|
QTextCharFormat m_occurrenceRenameFormat;
|
||||||
|
QTextCharFormat m_typeFormat;
|
||||||
|
|
||||||
QList<QTextEdit::ExtraSelection> m_renameSelections;
|
QList<QTextEdit::ExtraSelection> m_renameSelections;
|
||||||
int m_currentRenameSelection;
|
int m_currentRenameSelection;
|
||||||
|
|||||||
@@ -360,11 +360,14 @@ void CppHighlighter::highlightWord(QStringRef word, int position, int length)
|
|||||||
{
|
{
|
||||||
// try to highlight Qt 'identifiers' like QObject and Q_PROPERTY
|
// try to highlight Qt 'identifiers' like QObject and Q_PROPERTY
|
||||||
// but don't highlight words like 'Query'
|
// but don't highlight words like 'Query'
|
||||||
if (word.length() > 1
|
|
||||||
&& word.at(0) == QLatin1Char('Q')
|
if (word.length() > 1 && word.at(0) == QLatin1Char('Q')) {
|
||||||
&& (word.at(1).isUpper()
|
for (int i = 1; i < word.length(); ++i) {
|
||||||
|| word.at(1) == QLatin1Char('_')
|
const QChar &ch = word.at(i);
|
||||||
|| word.at(1) == QLatin1Char('t'))) {
|
if (! (ch.isUpper() || ch == QLatin1Char('_')))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setFormat(position, length, m_formats[CppTypeFormat]);
|
setFormat(position, length, m_formats[CppTypeFormat]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -340,6 +340,7 @@ public:
|
|||||||
FakeVimSelection,
|
FakeVimSelection,
|
||||||
OtherSelection,
|
OtherSelection,
|
||||||
SnippetPlaceholderSelection,
|
SnippetPlaceholderSelection,
|
||||||
|
TypeSelection,
|
||||||
NExtraSelectionKinds
|
NExtraSelectionKinds
|
||||||
};
|
};
|
||||||
void setExtraSelections(ExtraSelectionKind kind, const QList<QTextEdit::ExtraSelection> &selections);
|
void setExtraSelections(ExtraSelectionKind kind, const QList<QTextEdit::ExtraSelection> &selections);
|
||||||
|
|||||||
@@ -153,12 +153,10 @@ bool CheckStatement::visit(ExpressionOrDeclarationStatementAST *ast)
|
|||||||
{
|
{
|
||||||
// translationUnit()->warning(ast->firstToken(),
|
// translationUnit()->warning(ast->firstToken(),
|
||||||
// "ambiguous expression or declaration statement");
|
// "ambiguous expression or declaration statement");
|
||||||
if (ast->declaration) {
|
|
||||||
semantic()->check(ast->declaration, _scope);
|
semantic()->check(ast->declaration, _scope);
|
||||||
_exprType = FullySpecifiedType();
|
|
||||||
} else {
|
|
||||||
_exprType = semantic()->check(ast->expression, _scope);
|
_exprType = semantic()->check(ast->expression, _scope);
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user