forked from qt-creator/qt-creator
Introduced Snapshot::findMatchingDefinition().
This commit is contained in:
@@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include "CppDocument.h"
|
#include "CppDocument.h"
|
||||||
#include "FastPreprocessor.h"
|
#include "FastPreprocessor.h"
|
||||||
|
#include "LookupContext.h"
|
||||||
|
#include "Overview.h"
|
||||||
|
|
||||||
#include <Control.h>
|
#include <Control.h>
|
||||||
#include <TranslationUnit.h>
|
#include <TranslationUnit.h>
|
||||||
@@ -36,8 +38,10 @@
|
|||||||
#include <Semantic.h>
|
#include <Semantic.h>
|
||||||
#include <Literals.h>
|
#include <Literals.h>
|
||||||
#include <Symbols.h>
|
#include <Symbols.h>
|
||||||
|
#include <Names.h>
|
||||||
#include <AST.h>
|
#include <AST.h>
|
||||||
#include <Scope.h>
|
#include <Scope.h>
|
||||||
|
#include <SymbolVisitor.h>
|
||||||
|
|
||||||
#include <QtCore/QByteArray>
|
#include <QtCore/QByteArray>
|
||||||
#include <QtCore/QBitArray>
|
#include <QtCore/QBitArray>
|
||||||
@@ -570,3 +574,120 @@ void Snapshot::simplified_helper(Document::Ptr doc, Snapshot *snapshot) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class FindMatchingDefinition: public SymbolVisitor
|
||||||
|
{
|
||||||
|
Symbol *_declaration;
|
||||||
|
QList<Function *> _result;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FindMatchingDefinition(Symbol *declaration)
|
||||||
|
: _declaration(declaration) {}
|
||||||
|
|
||||||
|
QList<Function *> result() const { return _result; }
|
||||||
|
|
||||||
|
using SymbolVisitor::visit;
|
||||||
|
|
||||||
|
virtual bool visit(Function *fun)
|
||||||
|
{
|
||||||
|
if (_declaration->identifier()->isEqualTo(fun->identifier()))
|
||||||
|
_result.append(fun);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit(Block *)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // end of anonymous namespace
|
||||||
|
|
||||||
|
Symbol *Snapshot::findMatchingDefinition(Symbol *symbol) const
|
||||||
|
{
|
||||||
|
if (! symbol->identifier())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Document::Ptr thisDocument = document(QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()));
|
||||||
|
if (! thisDocument) {
|
||||||
|
qWarning() << "undefined document:" << symbol->fileName();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LookupContext thisContext(thisDocument, *this);
|
||||||
|
const QList<Symbol *> declarationCandidates = thisContext.lookup(symbol->name(), symbol);
|
||||||
|
if (declarationCandidates.isEmpty()) {
|
||||||
|
qWarning() << "unresolved declaration:" << symbol->fileName() << symbol->line() << symbol->column();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol *declaration = declarationCandidates.first();
|
||||||
|
Function *declarationTy = declaration->type()->asFunctionType();
|
||||||
|
if (! declarationTy) {
|
||||||
|
qWarning() << "not a function:" << declaration->fileName() << declaration->line() << declaration->column();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Document::Ptr doc, *this) {
|
||||||
|
if (! doc->control()->findIdentifier(declaration->identifier()->chars(),
|
||||||
|
declaration->identifier()->size()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FindMatchingDefinition candidates(declaration);
|
||||||
|
candidates.accept(doc->globalNamespace());
|
||||||
|
|
||||||
|
const QList<Function *> result = candidates.result();
|
||||||
|
if (! result.isEmpty()) {
|
||||||
|
LookupContext context(doc, *this);
|
||||||
|
|
||||||
|
QList<Function *> viableFunctions;
|
||||||
|
|
||||||
|
foreach (Function *fun, result) {
|
||||||
|
const QList<Symbol *> declarations = context.lookup(fun->name(), fun);
|
||||||
|
|
||||||
|
if (declarations.contains(declaration))
|
||||||
|
viableFunctions.append(fun);
|
||||||
|
|
||||||
|
else if (false)
|
||||||
|
qDebug() << "does not contain" << declaration->fileName() << declaration->line() << declaration->column();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viableFunctions.isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
else if (viableFunctions.length() == 1)
|
||||||
|
return viableFunctions.first();
|
||||||
|
|
||||||
|
Function *best = 0;
|
||||||
|
|
||||||
|
foreach (Function *fun, viableFunctions) {
|
||||||
|
if (fun->identity()->isEqualTo(declaration->identity()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
else if (fun->argumentCount() == declarationTy->argumentCount()) {
|
||||||
|
if (! best)
|
||||||
|
best = fun;
|
||||||
|
|
||||||
|
unsigned argc = 0;
|
||||||
|
for (; argc < declarationTy->argumentCount(); ++argc) {
|
||||||
|
Symbol *arg = fun->argumentAt(argc);
|
||||||
|
Symbol *otherArg = declarationTy->argumentAt(argc);
|
||||||
|
if (! arg->type().isEqualTo(otherArg->type()))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == declarationTy->argumentCount())
|
||||||
|
best = fun;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! best)
|
||||||
|
best = viableFunctions.first();
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -364,6 +364,8 @@ public:
|
|||||||
Document::Ptr documentFromSource(const QByteArray &preprocessedCode,
|
Document::Ptr documentFromSource(const QByteArray &preprocessedCode,
|
||||||
const QString &fileName) const;
|
const QString &fileName) const;
|
||||||
|
|
||||||
|
Symbol *findMatchingDefinition(Symbol *symbol) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void simplified_helper(Document::Ptr doc, Snapshot *snapshot) const;
|
void simplified_helper(Document::Ptr doc, Snapshot *snapshot) const;
|
||||||
|
|
||||||
|
|||||||
@@ -46,12 +46,12 @@
|
|||||||
|
|
||||||
using namespace CPlusPlus;
|
using namespace CPlusPlus;
|
||||||
|
|
||||||
static void fullyQualifiedName(Symbol *symbol, QList<const Name *> *names)
|
static void fullyQualifiedName_helper(Symbol *symbol, QList<const Name *> *names)
|
||||||
{
|
{
|
||||||
if (! symbol)
|
if (! symbol)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fullyQualifiedName(symbol->enclosingSymbol(), names);
|
fullyQualifiedName_helper(symbol->enclosingSymbol(), names);
|
||||||
|
|
||||||
if (symbol->name() && (symbol->isClass() || symbol->isNamespace())) {
|
if (symbol->name() && (symbol->isClass() || symbol->isNamespace())) {
|
||||||
if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
|
if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
|
||||||
@@ -119,6 +119,13 @@ LookupContext &LookupContext::operator = (const LookupContext &other)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<const Name *> LookupContext::fullyQualifiedName(Symbol *symbol)
|
||||||
|
{
|
||||||
|
QList<const Name *> names;
|
||||||
|
fullyQualifiedName_helper(symbol, &names);
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
QSharedPointer<CreateBindings> LookupContext::bindings() const
|
QSharedPointer<CreateBindings> LookupContext::bindings() const
|
||||||
{
|
{
|
||||||
if (! _bindings)
|
if (! _bindings)
|
||||||
@@ -230,8 +237,7 @@ QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
|
|||||||
if (fun->name() && fun->name()->isQualifiedNameId()) {
|
if (fun->name() && fun->name()->isQualifiedNameId()) {
|
||||||
const QualifiedNameId *q = fun->name()->asQualifiedNameId();
|
const QualifiedNameId *q = fun->name()->asQualifiedNameId();
|
||||||
|
|
||||||
QList<const Name *> path;
|
QList<const Name *> path = fullyQualifiedName(scope->owner());
|
||||||
fullyQualifiedName(scope->owner(), &path);
|
|
||||||
|
|
||||||
for (unsigned index = 0; index < q->nameCount() - 1; ++index) { // ### TODO remove me.
|
for (unsigned index = 0; index < q->nameCount() - 1; ++index) { // ### TODO remove me.
|
||||||
const Name *name = q->nameAt(index);
|
const Name *name = q->nameAt(index);
|
||||||
@@ -681,8 +687,7 @@ ClassOrNamespace *CreateBindings::globalNamespace() const
|
|||||||
|
|
||||||
ClassOrNamespace *CreateBindings::findClassOrNamespace(Symbol *symbol)
|
ClassOrNamespace *CreateBindings::findClassOrNamespace(Symbol *symbol)
|
||||||
{
|
{
|
||||||
QList<const Name *> names;
|
const QList<const Name *> names = LookupContext::fullyQualifiedName(symbol);
|
||||||
fullyQualifiedName(symbol, &names);
|
|
||||||
|
|
||||||
if (names.isEmpty())
|
if (names.isEmpty())
|
||||||
return _globalNamespace;
|
return _globalNamespace;
|
||||||
|
|||||||
@@ -231,6 +231,8 @@ public:
|
|||||||
|
|
||||||
Control *control() const; // ### deprecate
|
Control *control() const; // ### deprecate
|
||||||
|
|
||||||
|
static QList<const Name *> fullyQualifiedName(Symbol *symbol);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Control *_control;
|
Control *_control;
|
||||||
|
|
||||||
|
|||||||
@@ -1271,7 +1271,7 @@ void CPPEditor::switchDeclarationDefinition()
|
|||||||
if (declaration)
|
if (declaration)
|
||||||
openCppEditorAt(linkToSymbol(declaration));
|
openCppEditorAt(linkToSymbol(declaration));
|
||||||
} else if (lastSymbol->type()->isFunctionType()) {
|
} else if (lastSymbol->type()->isFunctionType()) {
|
||||||
if (Symbol *def = findDefinition(lastSymbol))
|
if (Symbol *def = findDefinition(lastSymbol, snapshot))
|
||||||
openCppEditorAt(linkToSymbol(def));
|
openCppEditorAt(linkToSymbol(def));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1444,7 +1444,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor,
|
|||||||
if (Symbol *symbol = result.lastVisibleSymbol()) {
|
if (Symbol *symbol = result.lastVisibleSymbol()) {
|
||||||
Symbol *def = 0;
|
Symbol *def = 0;
|
||||||
if (resolveTarget && !lastSymbol->isFunction())
|
if (resolveTarget && !lastSymbol->isFunction())
|
||||||
def = findDefinition(symbol);
|
def = findDefinition(symbol, snapshot);
|
||||||
|
|
||||||
link = linkToSymbol(def ? def : symbol);
|
link = linkToSymbol(def ? def : symbol);
|
||||||
link.begin = beginOfToken;
|
link.begin = beginOfToken;
|
||||||
@@ -1482,91 +1482,15 @@ void CPPEditor::jumpToDefinition()
|
|||||||
openLink(findLinkAt(textCursor()));
|
openLink(findLinkAt(textCursor()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *CPPEditor::findDefinition(Symbol *symbol)
|
Symbol *CPPEditor::findDefinition(Symbol *symbol, const Snapshot &snapshot)
|
||||||
{
|
{
|
||||||
if (symbol->isFunction())
|
if (symbol->isFunction())
|
||||||
return 0; // symbol is a function definition.
|
return 0; // symbol is a function definition.
|
||||||
|
|
||||||
Function *funTy = symbol->type()->asFunctionType();
|
else if (! symbol->type()->isFunctionType())
|
||||||
if (! funTy)
|
return 0; // not a function declaration
|
||||||
return 0; // symbol does not have function type.
|
|
||||||
|
|
||||||
const Name *name = symbol->name();
|
return snapshot.findMatchingDefinition(symbol);
|
||||||
if (! name)
|
|
||||||
return 0; // skip anonymous functions!
|
|
||||||
|
|
||||||
if (const QualifiedNameId *q = name->asQualifiedNameId())
|
|
||||||
name = q->unqualifiedNameId();
|
|
||||||
|
|
||||||
// map from file names to function definitions.
|
|
||||||
QMap<QString, QList<Function *> > functionDefinitions;
|
|
||||||
|
|
||||||
// find function definitions.
|
|
||||||
FindFunctionDefinitions findFunctionDefinitions;
|
|
||||||
|
|
||||||
// save the current snapshot
|
|
||||||
const Snapshot snapshot = m_modelManager->snapshot();
|
|
||||||
|
|
||||||
foreach (Document::Ptr doc, snapshot) {
|
|
||||||
if (Scope *globals = doc->globalSymbols()) {
|
|
||||||
QList<Function *> *localFunctionDefinitions =
|
|
||||||
&functionDefinitions[doc->fileName()];
|
|
||||||
|
|
||||||
findFunctionDefinitions(name, globals,
|
|
||||||
localFunctionDefinitions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// a dummy document.
|
|
||||||
Document::Ptr expressionDocument = Document::create("<empty>");
|
|
||||||
|
|
||||||
Function *bestMatch = 0;
|
|
||||||
int bestScore = -1;
|
|
||||||
|
|
||||||
QMapIterator<QString, QList<Function *> > it(functionDefinitions);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
|
|
||||||
// get the instance of the document.
|
|
||||||
Document::Ptr thisDocument = snapshot.document(it.key());
|
|
||||||
|
|
||||||
foreach (Function *f, it.value()) {
|
|
||||||
int score = 0; // current function's score
|
|
||||||
|
|
||||||
const int funTyArgsCount = funTy->argumentCount();
|
|
||||||
const int fArgsCount = f->argumentCount();
|
|
||||||
|
|
||||||
// max score if arguments count equals
|
|
||||||
if (funTyArgsCount == fArgsCount)
|
|
||||||
score += funTyArgsCount + 1;
|
|
||||||
else
|
|
||||||
score += (funTyArgsCount < fArgsCount) ? funTyArgsCount : fArgsCount;
|
|
||||||
|
|
||||||
// +1 to score for every equal parameter
|
|
||||||
unsigned minCount = (funTyArgsCount < fArgsCount) ? funTyArgsCount : fArgsCount;
|
|
||||||
for (unsigned i = 0; i < minCount; ++i)
|
|
||||||
if (Symbol *funTyArg = funTy->argumentAt(i))
|
|
||||||
if (Symbol *fArg = f->argumentAt(i))
|
|
||||||
if (funTyArg->type().isEqualTo(fArg->type()))
|
|
||||||
score++;
|
|
||||||
|
|
||||||
if (score > bestScore) {
|
|
||||||
// create a lookup context
|
|
||||||
const DeprecatedLookupContext context(f, expressionDocument,
|
|
||||||
thisDocument, snapshot);
|
|
||||||
|
|
||||||
// search the matching definition for the function declaration `symbol'.
|
|
||||||
foreach (Symbol *s, context.resolve(f->name())) {
|
|
||||||
if (s == symbol) {
|
|
||||||
bestMatch = f;
|
|
||||||
bestScore = score;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bestMatch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned CPPEditor::editorRevision() const
|
unsigned CPPEditor::editorRevision() const
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ private:
|
|||||||
|
|
||||||
CPlusPlus::Symbol *markSymbols();
|
CPlusPlus::Symbol *markSymbols();
|
||||||
bool sortedMethodOverview() const;
|
bool sortedMethodOverview() const;
|
||||||
CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol);
|
CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot);
|
||||||
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
|
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
|
||||||
|
|
||||||
TextEditor::ITextEditor *openCppEditorAt(const QString &fileName, int line,
|
TextEditor::ITextEditor *openCppEditorAt(const QString &fileName, int line,
|
||||||
|
|||||||
Reference in New Issue
Block a user