forked from qt-creator/qt-creator
		
	Improved the resolving of member expressions.
This commit is contained in:
		| @@ -623,141 +623,175 @@ bool ResolveExpression::visit(MemberAccessAST *ast) | ||||
|         memberName = ast->member_name->name; | ||||
|  | ||||
|     // Remember the access operator. | ||||
|     const unsigned accessOp = tokenKind(ast->access_token); | ||||
|     const int accessOp = tokenKind(ast->access_token); | ||||
|  | ||||
|     _results = resolveMemberExpression(baseResults, accessOp, memberName); | ||||
|  | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| QList<Symbol *> ResolveExpression::resolveBaseExpression(const QList<Result> &baseResults, int accessOp) const | ||||
| { | ||||
|     QList<Symbol *> classObjectCandidates; | ||||
|  | ||||
|     if (baseResults.isEmpty()) | ||||
|         return classObjectCandidates; | ||||
|  | ||||
|     Result result = baseResults.first(); | ||||
|  | ||||
|     if (accessOp == T_ARROW)  { | ||||
|         FullySpecifiedType ty = result.first.simplified(); | ||||
|  | ||||
|         if (Class *classTy = ty->asClassType()) { | ||||
|             Symbol *symbol = result.second; | ||||
|             if (symbol && ! symbol->isClass()) | ||||
|                 classObjectCandidates.append(classTy); | ||||
|         } else if (NamedType *namedTy = ty->asNamedType()) { | ||||
|             // ### This code is pretty slow. | ||||
|             const QList<Symbol *> candidates = _context.resolve(namedTy->name()); | ||||
|             foreach (Symbol *candidate, candidates) { | ||||
|                 if (candidate->isTypedef()) { | ||||
|                     ty = candidate->type(); | ||||
|                     const ResolveExpression::Result r(ty, candidate); | ||||
|                     result = r; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (NamedType *namedTy = ty->asNamedType()) { | ||||
|             ResolveClass resolveClass; | ||||
|  | ||||
|             const QList<Symbol *> candidates = resolveClass(result, _context); | ||||
|             foreach (Symbol *classObject, candidates) { | ||||
|                 const QList<Result> overloads = resolveArrowOperator(result, namedTy, | ||||
|                                                                      classObject->asClass()); | ||||
|  | ||||
|                 foreach (Result r, overloads) { | ||||
|                     FullySpecifiedType ty = r.first; | ||||
|                     Function *funTy = ty->asFunctionType(); | ||||
|                     if (! funTy) | ||||
|                         continue; | ||||
|  | ||||
|                     ty = funTy->returnType().simplified(); | ||||
|  | ||||
|                     if (PointerType *ptrTy = ty->asPointerType()) { | ||||
|                         if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) { | ||||
|                             const QList<Symbol *> classes = | ||||
|                                     resolveClass(namedTy, result, _context); | ||||
|  | ||||
|                             foreach (Symbol *c, classes) { | ||||
|                                 if (! classObjectCandidates.contains(c)) | ||||
|                                     classObjectCandidates.append(c); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } else if (PointerType *ptrTy = ty->asPointerType()) { | ||||
|             if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) { | ||||
|                 ResolveClass resolveClass; | ||||
|  | ||||
|                 const QList<Symbol *> classes = resolveClass(namedTy, result, | ||||
|                                                              _context); | ||||
|  | ||||
|                 foreach (Symbol *c, classes) { | ||||
|                     if (! classObjectCandidates.contains(c)) | ||||
|                         classObjectCandidates.append(c); | ||||
|                 } | ||||
|             } else if (Class *classTy = ptrTy->elementType()->asClassType()) { | ||||
|                 // typedef struct { int x } *Ptr; | ||||
|                 // Ptr p; | ||||
|                 // p-> | ||||
|                 classObjectCandidates.append(classTy); | ||||
|             } | ||||
|         } | ||||
|     } else if (accessOp == T_DOT) { | ||||
|         FullySpecifiedType ty = result.first.simplified(); | ||||
|  | ||||
|         NamedType *namedTy = 0; | ||||
|  | ||||
|         if (Class *classTy = ty->asClassType()) { | ||||
|             Symbol *symbol = result.second; | ||||
|             if (symbol && ! symbol->isClass()) | ||||
|                 classObjectCandidates.append(classTy); | ||||
|         } else { | ||||
|             namedTy = ty->asNamedType(); | ||||
|             if (! namedTy) { | ||||
|                 Function *fun = ty->asFunctionType(); | ||||
|                 if (fun && fun->scope() && (fun->scope()->isBlockScope() || fun->scope()->isNamespaceScope())) | ||||
|                     namedTy = fun->returnType()->asNamedType(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (namedTy) { | ||||
|             ResolveClass resolveClass; | ||||
|             const QList<Symbol *> symbols = resolveClass(namedTy, result, | ||||
|                                                          _context); | ||||
|             foreach (Symbol *symbol, symbols) { | ||||
|                 if (classObjectCandidates.contains(symbol)) | ||||
|                     continue; | ||||
|                 if (Class *klass = symbol->asClass()) | ||||
|                     classObjectCandidates.append(klass); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return classObjectCandidates; | ||||
| } | ||||
|  | ||||
| QList<ResolveExpression::Result> | ||||
| ResolveExpression::resolveMemberExpression(const QList<Result> &baseResults, | ||||
|                                            unsigned accessOp, | ||||
|                                            Name *memberName) const | ||||
| { | ||||
|     ResolveClass resolveClass; | ||||
|     QList<Result> results; | ||||
|  | ||||
|     if (accessOp == T_ARROW) { | ||||
|         foreach (Result p, baseResults) { | ||||
|             FullySpecifiedType ty = p.first; | ||||
|     const QList<Symbol *> classObjectCandidates = resolveBaseExpression(baseResults, accessOp); | ||||
|     foreach (Symbol *candidate, classObjectCandidates) { | ||||
|         Class *klass = candidate->asClass(); | ||||
|         if (! klass) | ||||
|             continue; | ||||
|  | ||||
|             if (ReferenceType *refTy = ty->asReferenceType()) | ||||
|                 ty = refTy->elementType(); | ||||
|  | ||||
|             if (NamedType *namedTy = ty->asNamedType()) { | ||||
|                 resolveClass.setPointerAccess(true); | ||||
|                 QList<Symbol *> classObjectCandidates = resolveClass(namedTy, p, _context); | ||||
|  | ||||
|                 foreach (Symbol *classObject, classObjectCandidates) { | ||||
|                     results += resolveMember(p, memberName, | ||||
|                                              control()->namedType(classObject->name()), // ### remove the call to namedType | ||||
|                                              classObject->asClass()); | ||||
|                 } | ||||
|  | ||||
|                 if (classObjectCandidates.isEmpty()) { | ||||
|                     resolveClass.setPointerAccess(false); | ||||
|                     classObjectCandidates = resolveClass(namedTy, p, _context); | ||||
|  | ||||
|                     foreach (Symbol *classObject, classObjectCandidates) { | ||||
|                         const QList<Result> overloads = resolveArrowOperator(p, namedTy, | ||||
|                                                                              classObject->asClass()); | ||||
|                         foreach (Result r, overloads) { | ||||
|                             FullySpecifiedType ty = r.first; | ||||
|                             Function *funTy = ty->asFunctionType(); | ||||
|                             if (! funTy) | ||||
|                                 continue; | ||||
|  | ||||
|                             ty = funTy->returnType(); | ||||
|  | ||||
|                             if (ReferenceType *refTy = ty->asReferenceType()) | ||||
|                                 ty = refTy->elementType(); | ||||
|  | ||||
|                             if (PointerType *ptrTy = ty->asPointerType()) { | ||||
|                                 if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) | ||||
|                                     results += resolveMember(r, memberName, namedTy); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } else if (PointerType *ptrTy = ty->asPointerType()) { | ||||
|                 if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) | ||||
|                     results += resolveMember(p, memberName, namedTy); | ||||
|             } | ||||
|         } | ||||
|     } else if (accessOp == T_DOT) { | ||||
|         // The base expression shall be a "class object" of a complete type. | ||||
|         foreach (Result p, baseResults) { | ||||
|             FullySpecifiedType ty = p.first; | ||||
|  | ||||
|             if (ReferenceType *refTy = ty->asReferenceType()) | ||||
|                 ty = refTy->elementType(); | ||||
|  | ||||
|             if (NamedType *namedTy = ty->asNamedType()) | ||||
|                 results += resolveMember(p, memberName, namedTy); | ||||
|             else if (Function *fun = ty->asFunctionType()) { | ||||
|                 if (fun->scope() && (fun->scope()->isBlockScope() || fun->scope()->isNamespaceScope())) { | ||||
|                     ty = fun->returnType(); | ||||
|  | ||||
|                     if (ReferenceType *refTy = ty->asReferenceType()) | ||||
|                         ty = refTy->elementType(); | ||||
|  | ||||
|                     if (NamedType *namedTy = ty->asNamedType()) | ||||
|                         results += resolveMember(p, memberName, namedTy); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         results += resolveMember(memberName, klass); | ||||
|     } | ||||
|  | ||||
|     return results; | ||||
| } | ||||
|  | ||||
| QList<ResolveExpression::Result> | ||||
| ResolveExpression::resolveMember(const Result &p, | ||||
|                                  Name *memberName, | ||||
|                                  NamedType *namedTy) const | ||||
| ResolveExpression::resolveMember(Name *memberName, Class *klass) const | ||||
| { | ||||
|     ResolveClass resolveClass; | ||||
|  | ||||
|     const QList<Symbol *> classObjectCandidates = | ||||
|             resolveClass(namedTy, p, _context); | ||||
|  | ||||
|     QList<Result> results; | ||||
|     foreach (Symbol *classObject, classObjectCandidates) { | ||||
|         results += resolveMember(p, memberName, namedTy, | ||||
|                                  classObject->asClass()); | ||||
|     } | ||||
|     return results; | ||||
| } | ||||
|  | ||||
| QList<ResolveExpression::Result> | ||||
| ResolveExpression::resolveMember(const Result &, | ||||
|                                  Name *memberName, | ||||
|                                  NamedType *namedTy, | ||||
|                                  Class *klass) const | ||||
| { | ||||
|     QList<Scope *> scopes; | ||||
|     _context.expand(klass->members(), _context.visibleScopes(), &scopes); | ||||
|     QList<Result> results; | ||||
|  | ||||
|     QList<Symbol *> candidates = _context.resolve(memberName, scopes); | ||||
|  | ||||
|     foreach (Symbol *candidate, candidates) { | ||||
|         FullySpecifiedType ty = candidate->type(); | ||||
|         Name *unqualifiedNameId = namedTy->name(); | ||||
|         if (QualifiedNameId *q = namedTy->name()->asQualifiedNameId()) | ||||
|             unqualifiedNameId = q->unqualifiedNameId(); | ||||
|         if (TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) { | ||||
|             Substitution subst; | ||||
|             for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) { | ||||
|                 FullySpecifiedType templArgTy = templId->templateArgumentAt(i); | ||||
|                 if (i < klass->templateParameterCount()) { | ||||
|                     subst.append(qMakePair(klass->templateParameterAt(i)->name(), | ||||
|                                            templArgTy)); | ||||
|  | ||||
|         if (Name *className = klass->name()) { | ||||
|             Name *unqualifiedNameId = className; | ||||
|  | ||||
|             if (QualifiedNameId *q = className->asQualifiedNameId()) | ||||
|                 unqualifiedNameId = q->unqualifiedNameId(); | ||||
|  | ||||
|             if (TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) { | ||||
|                 Substitution subst; | ||||
|  | ||||
|                 for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) { | ||||
|                     FullySpecifiedType templArgTy = templId->templateArgumentAt(i); | ||||
|  | ||||
|                     if (i < klass->templateParameterCount()) | ||||
|                         subst.append(qMakePair(klass->templateParameterAt(i)->name(), | ||||
|                                                templArgTy)); | ||||
|                 } | ||||
|  | ||||
|                 Instantiation inst(control(), subst); | ||||
|                 ty = inst(ty); | ||||
|             } | ||||
|             Instantiation inst(control(), subst); | ||||
|             ty = inst(ty); | ||||
|         } | ||||
|  | ||||
|         const Result result(ty, candidate); | ||||
|   | ||||
| @@ -53,14 +53,7 @@ public: | ||||
|                                           unsigned accessOp, | ||||
|                                           Name *memberName) const; | ||||
|  | ||||
|     QList<Result> resolveMember(const Result &result, | ||||
|                                 Name *memberName, | ||||
|                                 NamedType *namedTy) const; | ||||
|  | ||||
|     QList<Result> resolveMember(const Result &result, | ||||
|                                 Name *memberName, | ||||
|                                 NamedType *namedTy, | ||||
|                                 Class *klass) const; | ||||
|     QList<Result> resolveMember(Name *memberName, Class *klass) const; | ||||
|  | ||||
|     QList<Result> resolveArrowOperator(const Result &result, | ||||
|                                        NamedType *namedTy, | ||||
| @@ -70,6 +63,10 @@ public: | ||||
|                                        NamedType *namedTy, | ||||
|                                        Class *klass) const; | ||||
|  | ||||
|  | ||||
|     QList<Symbol *> resolveBaseExpression(const QList<Result> &baseResults, | ||||
|                                           int accessOp) const; | ||||
|  | ||||
| protected: | ||||
|     QList<Result> switchResults(const QList<Result> &symbols); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user