Initial work on smart highlight of local symbols. For-statements and symbols genarated from a macro expansion are not yet highlighted.

This commit is contained in:
Roberto Raggi
2009-06-25 11:02:02 +02:00
parent 44d8b28a9f
commit 27f92695cf
5 changed files with 301 additions and 29 deletions

View File

@@ -71,6 +71,7 @@
#include <QtCore/QDebug>
#include <QtCore/QTime>
#include <QtCore/QTimer>
#include <QtCore/QStack>
#include <QtGui/QAction>
#include <QtGui/QHeaderView>
#include <QtGui/QLayout>
@@ -109,6 +110,217 @@ public:
}
};
class FindLocals: protected ASTVisitor
{
Scope *_functionScope;
class FindScope: protected SymbolVisitor
{
TranslationUnit *_unit;
Scope *_scope;
unsigned _line;
unsigned _column;
public:
Scope *operator()(unsigned line, unsigned column,
Symbol *root, TranslationUnit *unit)
{
_unit = unit;
_scope = 0;
_line = line;
_column = column;
accept(root);
return _scope;
}
private:
using SymbolVisitor::visit;
virtual bool preVisit(Symbol *)
{ return ! _scope; }
virtual bool visit(Block *block)
{ return processScope(block->members()); }
virtual bool visit(Function *function)
{ return processScope(function->members()); }
bool processScope(Scope *scope)
{
if (_scope || ! scope)
return false;
for (unsigned i = 0; i < scope->symbolCount(); ++i) {
accept(scope->symbolAt(i));
if (_scope)
return false;
}
unsigned startOffset = scope->owner()->startOffset();
unsigned endOffset = scope->owner()->endOffset();
unsigned startLine, startColumn;
unsigned endLine, endColumn;
_unit->getPosition(startOffset, &startLine, &startColumn);
_unit->getPosition(endOffset, &endLine, &endColumn);
if (_line > startLine || (_line == startLine && _column >= startColumn)) {
if (_line < endLine || (_line == endLine && _column < endColumn)) {
_scope = scope;
}
}
return false;
}
};
public:
FindLocals(Control *control)
: ASTVisitor(control)
{ }
struct Use {
SimpleNameAST *name;
unsigned line;
unsigned column;
unsigned length;
Use(){}
Use(SimpleNameAST *name, unsigned line, unsigned column, unsigned length)
: name(name), line(line), column(column), length(length) {}
};
typedef QHash<Symbol *, QList<Use> > UseMap;
typedef QHashIterator<Symbol *, QList<Use> > UseIterator;
UseMap uses; // ### private
UseMap operator()(FunctionDefinitionAST *ast)
{
uses.clear();
if (ast && ast->symbol) {
_functionScope = ast->symbol->members();
accept(ast);
}
return uses;
}
protected:
using ASTVisitor::visit;
bool findMember(Scope *scope, SimpleNameAST *ast, unsigned line, unsigned column)
{
Identifier *id = identifier(ast->identifier_token);
if (scope) {
for (Symbol *member = scope->lookat(id); member; member = member->next()) {
if (member->identifier() != id)
continue;
else if (member->line() < line || (member->line() == line && (member->isGenerated() || member->column() >= column))) {
//qDebug() << "*** found member:" << member->line() << member->column() << member->name()->identifier()->chars();
uses[member].append(Use(ast, line, column, id->size()));
return true;
}
}
}
return false;
}
virtual bool visit(SimpleNameAST *ast)
{
unsigned line, column;
getTokenStartPosition(ast->firstToken(), &line, &column);
FindScope findScope;
Scope *scope = findScope(line, column,
_functionScope->owner(),
translationUnit());
while (scope) {
if (scope->isFunctionScope()) {
Function *fun = scope->owner()->asFunction();
if (findMember(fun->members(), ast, line, column))
return false;
else if (findMember(fun->arguments(), ast, line, column))
return false;
} else if (scope->isBlockScope()) {
if (findMember(scope, ast, line, column))
return false;
} else {
break;
}
scope = scope->enclosingScope();
}
#if 0
qDebug() << "symbol:" << id->chars() << "at pos:" << line << column
<< "is not defined";
#endif
return false;
}
virtual bool visit(QualifiedNameAST *)
{
// ### visit the template arguments.
return false;
}
virtual bool visit(PostfixExpressionAST *ast)
{
accept(ast->base_expression);
for (PostfixAST *it = ast->postfix_expressions; it; it = it->next) {
if (it->asMemberAccess() != 0)
continue; // skip members
accept(it);
}
return false;
}
virtual bool visit(NewExpressionAST *ast)
{
accept(ast->new_placement);
accept(ast->new_initializer);
return false;
}
virtual bool visit(ElaboratedTypeSpecifierAST *)
{
// ### template args
return false;
}
virtual bool visit(ClassSpecifierAST *)
{
// ### template args
return false;
}
virtual bool visit(EnumSpecifierAST *)
{
// ### template args
return false;
}
virtual bool visit(UsingDirectiveAST *)
{
return false;
}
virtual bool visit(UsingAST *ast)
{
accept(ast->name);
return false;
}
};
class FunctionDefinitionUnderCursor: protected ASTVisitor
{
QTextCursor _textCursor;
@@ -620,6 +832,7 @@ void CPPEditor::simplifyDeclarations()
const QString fileName = file()->fileName();
const QByteArray preprocessedCode = snapshot.preprocessedCode(plainText, fileName);
Document::Ptr doc = snapshot.documentFromSource(preprocessedCode, fileName);
doc->check();
SimplifyDeclarations simplify(this, doc);
simplify(textCursor());
@@ -692,6 +905,7 @@ void CPPEditor::updateMethodBoxIndexNow()
const Snapshot snapshot = m_modelManager->snapshot();
const QByteArray preprocessedCode = snapshot.preprocessedCode(toPlainText(), file()->fileName());
Document::Ptr doc = snapshot.documentFromSource(preprocessedCode, file()->fileName());
doc->check();
Control *control = doc->control();
TranslationUnit *translationUnit = doc->translationUnit();
AST *ast = translationUnit->ast();
@@ -699,33 +913,56 @@ void CPPEditor::updateMethodBoxIndexNow()
FunctionDefinitionUnderCursor functionDefinitionUnderCursor(control);
FunctionDefinitionAST *currentFunctionDefinition = functionDefinitionUnderCursor(ast, textCursor());
QTextCharFormat format;
format.setUnderlineColor(Qt::darkGray);
format.setUnderlineStyle(QTextCharFormat::DashUnderline);
ProcessDeclarators processDeclarators(control);
const QList<DeclaratorIdAST *> declarators = processDeclarators(currentFunctionDefinition);
foreach (DeclaratorIdAST *declarator, declarators) {
bool generated = false;
for (unsigned tk = declarator->firstToken(), end = declarator->lastToken(); tk != end; ++tk) {
if (translationUnit->tokenAt(tk).generated) {
generated = true;
FindLocals findLocals(control);
const FindLocals::UseMap useMap = findLocals(currentFunctionDefinition);
FindLocals::UseIterator it(useMap);
while (it.hasNext()) {
it.next();
const QList<FindLocals::Use> &uses = it.value();
bool good = false;
foreach (const FindLocals::Use &use, uses) {
unsigned l = line;
unsigned c = column + 1; // convertCursorPosition() returns a 0-based column number.
if (l == use.line && c >= use.column && c <= (use.column + use.length)) {
good = true;
break;
}
}
if (generated)
if (! good)
continue;
unsigned startLine, startColumn;
unsigned endLine, endColumn;
translationUnit->getTokenStartPosition(declarator->firstToken(), &startLine, &startColumn);
translationUnit->getTokenEndPosition(declarator->lastToken() - 1, &endLine, &endColumn);
QTextEdit::ExtraSelection sel;
sel.cursor = textCursor();
sel.cursor.setPosition(document()->findBlockByNumber(startLine - 1).position() + startColumn - 1);
sel.cursor.setPosition(document()->findBlockByLineNumber(endLine - 1).position() + endColumn - 1,
QTextCursor::KeepAnchor);
sel.format = format;
selections.append(sel);
foreach (const FindLocals::Use &use, uses) {
SimpleNameAST *name = use.name;
bool generated = false;
for (unsigned tk = name->firstToken(), end = name->lastToken(); tk != end; ++tk) {
if (translationUnit->tokenAt(tk).generated) {
generated = true;
break;
}
}
if (generated)
continue;
unsigned startLine, startColumn;
unsigned endLine, endColumn;
translationUnit->getTokenStartPosition(name->firstToken(), &startLine, &startColumn);
translationUnit->getTokenEndPosition(name->lastToken() - 1, &endLine, &endColumn);
QTextEdit::ExtraSelection sel;
sel.cursor = textCursor();
sel.cursor.setPosition(document()->findBlockByNumber(startLine - 1).position() + startColumn - 1);
sel.cursor.setPosition(document()->findBlockByLineNumber(endLine - 1).position() + endColumn - 1,
QTextCursor::KeepAnchor);
sel.format = format;
selections.append(sel);
}
break; // done.
}
setExtraSelections(CodeSemanticsSelection, selections);
#ifdef QTCREATOR_WITH_ADVANCED_HIGHLIGHTER