diff options
author | Roberto Raggi <roberto.raggi@nokia.com> | 2010-05-25 14:53:21 +0200 |
---|---|---|
committer | Roberto Raggi <roberto.raggi@nokia.com> | 2010-05-25 17:15:22 +0200 |
commit | b68a16f1b5d69d63e7adaa67810b99c73bcfb979 (patch) | |
tree | f697265b0b7e07ed0cfb3b45aeda0fb17f6c499a /src/libs/cplusplus/CheckUndefinedSymbols.cpp | |
parent | 2a0f901e16faa4838a0bd09f7d41dc46256589ff (diff) | |
download | qt-creator-b68a16f1b5d69d63e7adaa67810b99c73bcfb979.tar.gz |
Highlight user defined types.
Diffstat (limited to 'src/libs/cplusplus/CheckUndefinedSymbols.cpp')
-rw-r--r-- | src/libs/cplusplus/CheckUndefinedSymbols.cpp | 334 |
1 files changed, 331 insertions, 3 deletions
diff --git a/src/libs/cplusplus/CheckUndefinedSymbols.cpp b/src/libs/cplusplus/CheckUndefinedSymbols.cpp index eba07d4b88..7de0f7c77d 100644 --- a/src/libs/cplusplus/CheckUndefinedSymbols.cpp +++ b/src/libs/cplusplus/CheckUndefinedSymbols.cpp @@ -36,16 +36,211 @@ #include <TranslationUnit.h> #include <Scope.h> #include <AST.h> +#include <SymbolVisitor.h> #include <QCoreApplication> #include <QDebug> 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) : ASTVisitor(unit), _context(context) { _fileName = context.thisDocument()->fileName(); + CollectTypes collectTypes(context.thisDocument(), context.snapshot()); + _potentialTypes = collectTypes.types(); + _scopes = collectTypes.scopes(); } CheckUndefinedSymbols::~CheckUndefinedSymbols() @@ -84,17 +279,19 @@ bool CheckUndefinedSymbols::visit(UsingDirectiveAST *ast) return false; } -bool CheckUndefinedSymbols::visit(SimpleDeclarationAST *ast) +bool CheckUndefinedSymbols::visit(SimpleDeclarationAST *) { return true; } bool CheckUndefinedSymbols::visit(NamedTypeSpecifierAST *ast) { +#if 0 if (ast->name) { 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); const QList<Symbol *> candidates = _context.lookup(ast->name->name, enclosingScope); @@ -108,8 +305,9 @@ bool CheckUndefinedSymbols::visit(NamedTypeSpecifierAST *ast) if (! ty) warning(ast->name, QCoreApplication::translate("CheckUndefinedSymbols", "Expected a type-name")); } +#endif - return false; + return true; } 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(); 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; +} |