Commit 27f92695 authored by Roberto Raggi's avatar Roberto Raggi

Initial work on smart highlight of local symbols. For-statements and symbols...

Initial work on smart highlight of local symbols. For-statements and symbols genarated from a macro expansion are not yet highlighted.
parent 44d8b28a
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QTime> #include <QtCore/QTime>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QStack>
#include <QtGui/QAction> #include <QtGui/QAction>
#include <QtGui/QHeaderView> #include <QtGui/QHeaderView>
#include <QtGui/QLayout> #include <QtGui/QLayout>
...@@ -109,6 +110,217 @@ public: ...@@ -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 class FunctionDefinitionUnderCursor: protected ASTVisitor
{ {
QTextCursor _textCursor; QTextCursor _textCursor;
...@@ -620,6 +832,7 @@ void CPPEditor::simplifyDeclarations() ...@@ -620,6 +832,7 @@ void CPPEditor::simplifyDeclarations()
const QString fileName = file()->fileName(); const QString fileName = file()->fileName();
const QByteArray preprocessedCode = snapshot.preprocessedCode(plainText, fileName); const QByteArray preprocessedCode = snapshot.preprocessedCode(plainText, fileName);
Document::Ptr doc = snapshot.documentFromSource(preprocessedCode, fileName); Document::Ptr doc = snapshot.documentFromSource(preprocessedCode, fileName);
doc->check();
SimplifyDeclarations simplify(this, doc); SimplifyDeclarations simplify(this, doc);
simplify(textCursor()); simplify(textCursor());
...@@ -692,6 +905,7 @@ void CPPEditor::updateMethodBoxIndexNow() ...@@ -692,6 +905,7 @@ void CPPEditor::updateMethodBoxIndexNow()
const Snapshot snapshot = m_modelManager->snapshot(); const Snapshot snapshot = m_modelManager->snapshot();
const QByteArray preprocessedCode = snapshot.preprocessedCode(toPlainText(), file()->fileName()); const QByteArray preprocessedCode = snapshot.preprocessedCode(toPlainText(), file()->fileName());
Document::Ptr doc = snapshot.documentFromSource(preprocessedCode, file()->fileName()); Document::Ptr doc = snapshot.documentFromSource(preprocessedCode, file()->fileName());
doc->check();
Control *control = doc->control(); Control *control = doc->control();
TranslationUnit *translationUnit = doc->translationUnit(); TranslationUnit *translationUnit = doc->translationUnit();
AST *ast = translationUnit->ast(); AST *ast = translationUnit->ast();
...@@ -699,14 +913,34 @@ void CPPEditor::updateMethodBoxIndexNow() ...@@ -699,14 +913,34 @@ void CPPEditor::updateMethodBoxIndexNow()
FunctionDefinitionUnderCursor functionDefinitionUnderCursor(control); FunctionDefinitionUnderCursor functionDefinitionUnderCursor(control);
FunctionDefinitionAST *currentFunctionDefinition = functionDefinitionUnderCursor(ast, textCursor()); FunctionDefinitionAST *currentFunctionDefinition = functionDefinitionUnderCursor(ast, textCursor());
QTextCharFormat format; QTextCharFormat format;
format.setUnderlineColor(Qt::darkGray); format.setUnderlineColor(Qt::darkGray);
format.setUnderlineStyle(QTextCharFormat::DashUnderline); format.setUnderlineStyle(QTextCharFormat::DashUnderline);
ProcessDeclarators processDeclarators(control); FindLocals findLocals(control);
const QList<DeclaratorIdAST *> declarators = processDeclarators(currentFunctionDefinition); const FindLocals::UseMap useMap = findLocals(currentFunctionDefinition);
foreach (DeclaratorIdAST *declarator, declarators) { 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 (! good)
continue;
foreach (const FindLocals::Use &use, uses) {
SimpleNameAST *name = use.name;
bool generated = false; bool generated = false;
for (unsigned tk = declarator->firstToken(), end = declarator->lastToken(); tk != end; ++tk) { for (unsigned tk = name->firstToken(), end = name->lastToken(); tk != end; ++tk) {
if (translationUnit->tokenAt(tk).generated) { if (translationUnit->tokenAt(tk).generated) {
generated = true; generated = true;
break; break;
...@@ -716,8 +950,8 @@ void CPPEditor::updateMethodBoxIndexNow() ...@@ -716,8 +950,8 @@ void CPPEditor::updateMethodBoxIndexNow()
continue; continue;
unsigned startLine, startColumn; unsigned startLine, startColumn;
unsigned endLine, endColumn; unsigned endLine, endColumn;
translationUnit->getTokenStartPosition(declarator->firstToken(), &startLine, &startColumn); translationUnit->getTokenStartPosition(name->firstToken(), &startLine, &startColumn);
translationUnit->getTokenEndPosition(declarator->lastToken() - 1, &endLine, &endColumn); translationUnit->getTokenEndPosition(name->lastToken() - 1, &endLine, &endColumn);
QTextEdit::ExtraSelection sel; QTextEdit::ExtraSelection sel;
sel.cursor = textCursor(); sel.cursor = textCursor();
sel.cursor.setPosition(document()->findBlockByNumber(startLine - 1).position() + startColumn - 1); sel.cursor.setPosition(document()->findBlockByNumber(startLine - 1).position() + startColumn - 1);
...@@ -726,6 +960,9 @@ void CPPEditor::updateMethodBoxIndexNow() ...@@ -726,6 +960,9 @@ void CPPEditor::updateMethodBoxIndexNow()
sel.format = format; sel.format = format;
selections.append(sel); selections.append(sel);
} }
break; // done.
}
setExtraSelections(CodeSemanticsSelection, selections); setExtraSelections(CodeSemanticsSelection, selections);
#ifdef QTCREATOR_WITH_ADVANCED_HIGHLIGHTER #ifdef QTCREATOR_WITH_ADVANCED_HIGHLIGHTER
......
...@@ -122,6 +122,18 @@ void CheckDeclaration::checkFunctionArguments(Function *fun) ...@@ -122,6 +122,18 @@ void CheckDeclaration::checkFunctionArguments(Function *fun)
} }
} }
unsigned CheckDeclaration::locationOfDeclaratorId(DeclaratorAST *declarator) const
{
if (declarator && declarator->core_declarator) {
if (DeclaratorIdAST *declaratorId = declarator->core_declarator->asDeclaratorId())
return declaratorId->firstToken();
else if (NestedDeclaratorAST *nested = declarator->core_declarator->asNestedDeclarator())
return locationOfDeclaratorId(nested->declarator);
}
return 0;
}
bool CheckDeclaration::visit(SimpleDeclarationAST *ast) bool CheckDeclaration::visit(SimpleDeclarationAST *ast)
{ {
FullySpecifiedType ty = semantic()->check(ast->decl_specifier_seq, _scope); FullySpecifiedType ty = semantic()->check(ast->decl_specifier_seq, _scope);
...@@ -164,11 +176,13 @@ bool CheckDeclaration::visit(SimpleDeclarationAST *ast) ...@@ -164,11 +176,13 @@ bool CheckDeclaration::visit(SimpleDeclarationAST *ast)
FullySpecifiedType declTy = semantic()->check(it->declarator, qualTy, FullySpecifiedType declTy = semantic()->check(it->declarator, qualTy,
_scope, &name); _scope, &name);
unsigned location = 0; unsigned location = locationOfDeclaratorId(it->declarator);
if (! location) {
if (it->declarator) if (it->declarator)
location = it->declarator->firstToken(); location = it->declarator->firstToken();
else else
location = ast->firstToken(); location = ast->firstToken();
}
Function *fun = 0; Function *fun = 0;
if (declTy && 0 != (fun = declTy->asFunctionType())) { if (declTy && 0 != (fun = declTy->asFunctionType())) {
...@@ -355,10 +369,13 @@ bool CheckDeclaration::visit(NamespaceAliasDefinitionAST *) ...@@ -355,10 +369,13 @@ bool CheckDeclaration::visit(NamespaceAliasDefinitionAST *)
bool CheckDeclaration::visit(ParameterDeclarationAST *ast) bool CheckDeclaration::visit(ParameterDeclarationAST *ast)
{ {
unsigned sourceLocation = 0; unsigned sourceLocation = locationOfDeclaratorId(ast->declarator);
if (! sourceLocation) {
if (ast->declarator) if (ast->declarator)
sourceLocation = ast->declarator->firstToken(); sourceLocation = ast->declarator->firstToken();
else
sourceLocation = ast->firstToken();
}
Name *argName = 0; Name *argName = 0;
FullySpecifiedType ty = semantic()->check(ast->type_specifier, _scope); FullySpecifiedType ty = semantic()->check(ast->type_specifier, _scope);
......
...@@ -72,6 +72,8 @@ protected: ...@@ -72,6 +72,8 @@ protected:
using ASTVisitor::visit; using ASTVisitor::visit;
unsigned locationOfDeclaratorId(DeclaratorAST *declarator) const;
virtual bool visit(SimpleDeclarationAST *ast); virtual bool visit(SimpleDeclarationAST *ast);
virtual bool visit(EmptyDeclarationAST *ast); virtual bool visit(EmptyDeclarationAST *ast);
virtual bool visit(AccessDeclarationAST *ast); virtual bool visit(AccessDeclarationAST *ast);
......
...@@ -144,6 +144,8 @@ bool CheckStatement::visit(ExpressionStatementAST *ast) ...@@ -144,6 +144,8 @@ bool CheckStatement::visit(ExpressionStatementAST *ast)
bool CheckStatement::visit(ForStatementAST *ast) bool CheckStatement::visit(ForStatementAST *ast)
{ {
Block *block = control()->newBlock(ast->for_token); Block *block = control()->newBlock(ast->for_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
block->setEndOffset(tokenAt(ast->lastToken()).offset);
ast->symbol = block; ast->symbol = block;
_scope->enterSymbol(block); _scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members()); Scope *previousScope = switchScope(block->members());
...@@ -158,6 +160,8 @@ bool CheckStatement::visit(ForStatementAST *ast) ...@@ -158,6 +160,8 @@ bool CheckStatement::visit(ForStatementAST *ast)
bool CheckStatement::visit(IfStatementAST *ast) bool CheckStatement::visit(IfStatementAST *ast)
{ {
Block *block = control()->newBlock(ast->if_token); Block *block = control()->newBlock(ast->if_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
block->setEndOffset(tokenAt(ast->lastToken()).offset);
ast->symbol = block; ast->symbol = block;
_scope->enterSymbol(block); _scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members()); Scope *previousScope = switchScope(block->members());
...@@ -198,6 +202,8 @@ bool CheckStatement::visit(ReturnStatementAST *ast) ...@@ -198,6 +202,8 @@ bool CheckStatement::visit(ReturnStatementAST *ast)
bool CheckStatement::visit(SwitchStatementAST *ast) bool CheckStatement::visit(SwitchStatementAST *ast)
{ {
Block *block = control()->newBlock(ast->switch_token); Block *block = control()->newBlock(ast->switch_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
block->setEndOffset(tokenAt(ast->lastToken()).offset);
ast->symbol = block; ast->symbol = block;
_scope->enterSymbol(block); _scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members()); Scope *previousScope = switchScope(block->members());
...@@ -219,6 +225,8 @@ bool CheckStatement::visit(TryBlockStatementAST *ast) ...@@ -219,6 +225,8 @@ bool CheckStatement::visit(TryBlockStatementAST *ast)
bool CheckStatement::visit(CatchClauseAST *ast) bool CheckStatement::visit(CatchClauseAST *ast)
{ {
Block *block = control()->newBlock(ast->catch_token); Block *block = control()->newBlock(ast->catch_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
block->setEndOffset(tokenAt(ast->lastToken()).offset);
ast->symbol = block; ast->symbol = block;
_scope->enterSymbol(block); _scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members()); Scope *previousScope = switchScope(block->members());
...@@ -231,6 +239,8 @@ bool CheckStatement::visit(CatchClauseAST *ast) ...@@ -231,6 +239,8 @@ bool CheckStatement::visit(CatchClauseAST *ast)
bool CheckStatement::visit(WhileStatementAST *ast) bool CheckStatement::visit(WhileStatementAST *ast)
{ {
Block *block = control()->newBlock(ast->while_token); Block *block = control()->newBlock(ast->while_token);
block->setStartOffset(tokenAt(ast->firstToken()).offset);
block->setEndOffset(tokenAt(ast->lastToken()).offset);
ast->symbol = block; ast->symbol = block;
_scope->enterSymbol(block); _scope->enterSymbol(block);
Scope *previousScope = switchScope(block->members()); Scope *previousScope = switchScope(block->members());
......
...@@ -328,7 +328,13 @@ FullySpecifiedType Block::type() const ...@@ -328,7 +328,13 @@ FullySpecifiedType Block::type() const
{ return FullySpecifiedType(); } { return FullySpecifiedType(); }
void Block::visitSymbol0(SymbolVisitor *visitor) void Block::visitSymbol0(SymbolVisitor *visitor)
{ visitor->visit(this); } {
if (visitor->visit(this)) {
for (unsigned i = 0; i < memberCount(); ++i) {
visitSymbol(memberAt(i), visitor);
}
}
}
Enum::Enum(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name) Enum::Enum(TranslationUnit *translationUnit, unsigned sourceLocation, Name *name)
: ScopedSymbol(translationUnit, sourceLocation, name) : ScopedSymbol(translationUnit, sourceLocation, name)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment