summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaLookup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaLookup.cpp')
-rw-r--r--lib/Sema/SemaLookup.cpp1007
1 files changed, 622 insertions, 385 deletions
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 306e95a..0fd0e08 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -31,7 +31,9 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/Support/ErrorHandling.h"
+#include <limits>
#include <list>
#include <set>
#include <vector>
@@ -89,7 +91,7 @@ namespace {
UnqualUsingDirectiveSet() {}
void visitScopeChain(Scope *S, Scope *InnermostFileScope) {
- // C++ [namespace.udir]p1:
+ // C++ [namespace.udir]p1:
// During unqualified name lookup, the names appear as if they
// were declared in the nearest enclosing namespace which contains
// both the using-directive and the nominated namespace.
@@ -104,7 +106,7 @@ namespace {
} else {
Scope::udir_iterator I = S->using_directives_begin(),
End = S->using_directives_end();
-
+
for (; I != End; ++I)
visit(*I, InnermostFileDC);
}
@@ -175,7 +177,7 @@ namespace {
while (!Common->Encloses(EffectiveDC))
Common = Common->getParent();
Common = Common->getPrimaryContext();
-
+
list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common));
}
@@ -183,11 +185,8 @@ namespace {
std::sort(list.begin(), list.end(), UnqualUsingEntry::Comparator());
}
- typedef ListTy::iterator iterator;
typedef ListTy::const_iterator const_iterator;
-
- iterator begin() { return list.begin(); }
- iterator end() { return list.end(); }
+
const_iterator begin() const { return list.begin(); }
const_iterator end() const { return list.end(); }
@@ -211,7 +210,8 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
IDNS = Decl::IDNS_Ordinary;
if (CPlusPlus) {
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace;
- if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend;
+ if (Redeclaration)
+ IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend;
}
break;
@@ -237,7 +237,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
IDNS = Decl::IDNS_Tag;
}
break;
-
+ case Sema::LookupLabel:
+ IDNS = Decl::IDNS_Label;
+ break;
+
case Sema::LookupMemberName:
IDNS = Decl::IDNS_Member;
if (CPlusPlus)
@@ -260,9 +263,9 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
case Sema::LookupObjCProtocolName:
IDNS = Decl::IDNS_ObjCProtocol;
break;
-
+
case Sema::LookupAnyName:
- IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member
+ IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member
| Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol
| Decl::IDNS_Type;
break;
@@ -271,8 +274,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
}
void LookupResult::configure() {
- IDNS = getIDNS(LookupKind,
- SemaRef.getLangOptions().CPlusPlus,
+ IDNS = getIDNS(LookupKind, SemaRef.getLangOptions().CPlusPlus,
isForRedeclaration());
// If we're looking for one of the allocation or deallocation
@@ -293,7 +295,6 @@ void LookupResult::configure() {
}
}
-#ifndef NDEBUG
void LookupResult::sanity() const {
assert(ResultKind != NotFound || Decls.size() == 0);
assert(ResultKind != Found || Decls.size() == 1);
@@ -302,12 +303,12 @@ void LookupResult::sanity() const {
isa<FunctionTemplateDecl>((*begin())->getUnderlyingDecl())));
assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved());
assert(ResultKind != Ambiguous || Decls.size() > 1 ||
- (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects));
+ (Decls.size() == 1 && (Ambiguity == AmbiguousBaseSubobjects ||
+ Ambiguity == AmbiguousBaseSubobjectTypes)));
assert((Paths != NULL) == (ResultKind == Ambiguous &&
(Ambiguity == AmbiguousBaseSubobjectTypes ||
Ambiguity == AmbiguousBaseSubobjects)));
}
-#endif
// Necessary because CXXBasePaths is not complete in Sema.h
void LookupResult::deletePaths(CXXBasePaths *Paths) {
@@ -317,7 +318,7 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) {
/// Resolves the result kind of this lookup.
void LookupResult::resolveKind() {
unsigned N = Decls.size();
-
+
// Fast case: no possible ambiguity.
if (N == 0) {
assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation);
@@ -340,13 +341,13 @@ void LookupResult::resolveKind() {
llvm::SmallPtrSet<NamedDecl*, 16> Unique;
llvm::SmallPtrSet<QualType, 16> UniqueTypes;
-
+
bool Ambiguous = false;
bool HasTag = false, HasFunction = false, HasNonFunction = false;
bool HasFunctionTemplate = false, HasUnresolved = false;
unsigned UniqueTagIndex = 0;
-
+
unsigned I = 0;
while (I < N) {
NamedDecl *D = Decls[I]->getUnderlyingDecl();
@@ -367,14 +368,14 @@ void LookupResult::resolveKind() {
}
}
}
-
+
if (!Unique.insert(D)) {
// If it's not unique, pull something off the back (and
// continue at this index).
Decls[I] = Decls[--N];
continue;
- }
-
+ }
+
// Otherwise, do some decl type analysis and then continue.
if (isa<UnresolvedUsingValueDecl>(D)) {
@@ -407,8 +408,13 @@ void LookupResult::resolveKind() {
// But it's still an error if there are distinct tag types found,
// even if they're not visible. (ref?)
if (HideTags && HasTag && !Ambiguous &&
- (HasFunction || HasNonFunction || HasUnresolved))
- Decls[UniqueTagIndex] = Decls[--N];
+ (HasFunction || HasNonFunction || HasUnresolved)) {
+ if (Decls[UniqueTagIndex]->getDeclContext()->getRedeclContext()->Equals(
+ Decls[UniqueTagIndex? 0 : N-1]->getDeclContext()->getRedeclContext()))
+ Decls[UniqueTagIndex] = Decls[--N];
+ else
+ Ambiguous = true;
+ }
Decls.set_size(N);
@@ -453,7 +459,7 @@ void LookupResult::print(llvm::raw_ostream &Out) {
Out << Decls.size() << " result(s)";
if (isAmbiguous()) Out << ", ambiguous";
if (Paths) Out << ", base paths present";
-
+
for (iterator I = begin(), E = end(); I != E; ++I) {
Out << "\n";
(*I)->print(Out, 2);
@@ -480,12 +486,21 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return false;
- NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
- S.TUScope, R.isForRedeclaration(),
- R.getNameLoc());
- if (D)
+ if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II,
+ BuiltinID, S.TUScope,
+ R.isForRedeclaration(),
+ R.getNameLoc())) {
R.addDecl(D);
- return (D != NULL);
+ return true;
+ }
+
+ if (R.isForRedeclaration()) {
+ // If we're redeclaring this function anyway, forget that
+ // this was a builtin at all.
+ S.Context.BuiltinInfo.ForgetBuiltin(BuiltinID, S.Context.Idents);
+ }
+
+ return false;
}
}
}
@@ -500,16 +515,16 @@ static bool CanDeclareSpecialMemberFunction(ASTContext &Context,
// Don't do it if the class is invalid.
if (Class->isInvalidDecl())
return false;
-
+
// We need to have a definition for the class.
if (!Class->getDefinition() || Class->isDependentContext())
return false;
-
+
// We can't be in the middle of defining the class.
if (const RecordType *RecordTy
= Context.getTypeDeclType(Class)->getAs<RecordType>())
return !RecordTy->isBeingDefined();
-
+
return false;
}
@@ -520,46 +535,46 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
// If the default constructor has not yet been declared, do so now.
if (!Class->hasDeclaredDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
-
+
// If the copy constructor has not yet been declared, do so now.
if (!Class->hasDeclaredCopyConstructor())
DeclareImplicitCopyConstructor(Class);
-
+
// If the copy assignment operator has not yet been declared, do so now.
if (!Class->hasDeclaredCopyAssignment())
DeclareImplicitCopyAssignment(Class);
// If the destructor has not yet been declared, do so now.
if (!Class->hasDeclaredDestructor())
- DeclareImplicitDestructor(Class);
+ DeclareImplicitDestructor(Class);
}
-/// \brief Determine whether this is the name of an implicitly-declared
+/// \brief Determine whether this is the name of an implicitly-declared
/// special member function.
static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) {
switch (Name.getNameKind()) {
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
return true;
-
+
case DeclarationName::CXXOperatorName:
return Name.getCXXOverloadedOperator() == OO_Equal;
-
+
default:
- break;
+ break;
}
-
+
return false;
}
/// \brief If there are any implicit member functions with the given name
/// that need to be declared in the given declaration context, do so.
-static void DeclareImplicitMemberFunctionsWithName(Sema &S,
+static void DeclareImplicitMemberFunctionsWithName(Sema &S,
DeclarationName Name,
const DeclContext *DC) {
if (!DC)
return;
-
+
switch (Name.getNameKind()) {
case DeclarationName::CXXConstructorName:
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
@@ -572,26 +587,26 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
S.DeclareImplicitCopyConstructor(const_cast<CXXRecordDecl *>(Record));
}
break;
-
+
case DeclarationName::CXXDestructorName:
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
if (Record->getDefinition() && !Record->hasDeclaredDestructor() &&
CanDeclareSpecialMemberFunction(S.Context, Record))
S.DeclareImplicitDestructor(const_cast<CXXRecordDecl *>(Record));
break;
-
+
case DeclarationName::CXXOperatorName:
if (Name.getCXXOverloadedOperator() != OO_Equal)
break;
-
+
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
if (Record->getDefinition() && !Record->hasDeclaredCopyAssignment() &&
CanDeclareSpecialMemberFunction(S.Context, Record))
S.DeclareImplicitCopyAssignment(const_cast<CXXRecordDecl *>(Record));
break;
-
+
default:
- break;
+ break;
}
}
@@ -603,7 +618,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// Lazily declare C++ special member functions.
if (S.getLangOptions().CPlusPlus)
DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC);
-
+
// Perform lookup into this declaration context.
DeclContext::lookup_const_iterator I, E;
for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
@@ -624,7 +639,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
return Found;
// C++ [temp.mem]p6:
- // A specialization of a conversion function template is not found by
+ // A specialization of a conversion function template is not found by
// name lookup. Instead, any conversion function templates visible in the
// context of the use are considered. [...]
const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
@@ -632,50 +647,51 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
return Found;
const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions();
- for (UnresolvedSetImpl::iterator U = Unresolved->begin(),
+ for (UnresolvedSetImpl::iterator U = Unresolved->begin(),
UEnd = Unresolved->end(); U != UEnd; ++U) {
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
if (!ConvTemplate)
continue;
-
+
// When we're performing lookup for the purposes of redeclaration, just
- // add the conversion function template. When we deduce template
- // arguments for specializations, we'll end up unifying the return
+ // add the conversion function template. When we deduce template
+ // arguments for specializations, we'll end up unifying the return
// type of the new declaration with the type of the function template.
if (R.isForRedeclaration()) {
R.addDecl(ConvTemplate);
Found = true;
continue;
}
-
+
// C++ [temp.mem]p6:
- // [...] For each such operator, if argument deduction succeeds
- // (14.9.2.3), the resulting specialization is used as if found by
+ // [...] For each such operator, if argument deduction succeeds
+ // (14.9.2.3), the resulting specialization is used as if found by
// name lookup.
//
// When referencing a conversion function for any purpose other than
// a redeclaration (such that we'll be building an expression with the
- // result), perform template argument deduction and place the
+ // result), perform template argument deduction and place the
// specialization into the result set. We do this to avoid forcing all
// callers to perform special deduction for conversion functions.
TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc());
FunctionDecl *Specialization = 0;
-
- const FunctionProtoType *ConvProto
+
+ const FunctionProtoType *ConvProto
= ConvTemplate->getTemplatedDecl()->getType()->getAs<FunctionProtoType>();
assert(ConvProto && "Nonsensical conversion function template type");
// Compute the type of the function that we would expect the conversion
// function to have, if it were to match the name given.
// FIXME: Calling convention!
- FunctionType::ExtInfo ConvProtoInfo = ConvProto->getExtInfo();
+ FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo();
+ EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_Default);
+ EPI.HasExceptionSpec = false;
+ EPI.HasAnyExceptionSpec = false;
+ EPI.NumExceptions = 0;
QualType ExpectedType
= R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
- 0, 0, ConvProto->isVariadic(),
- ConvProto->getTypeQuals(),
- false, false, 0, 0,
- ConvProtoInfo.withCallingConv(CC_Default));
-
+ 0, 0, EPI);
+
// Perform template argument deduction against the type that we would
// expect the function to have.
if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType,
@@ -691,7 +707,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// Performs C++ unqualified lookup into the given file context.
static bool
-CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context,
+CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context,
DeclContext *NS, UnqualUsingDirectiveSet &UDirs) {
assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!");
@@ -729,7 +745,7 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
DeclContext *DC = static_cast<DeclContext *>(S->getEntity());
DeclContext *Lexical = 0;
- for (Scope *OuterS = S->getParent(); OuterS;
+ for (Scope *OuterS = S->getParent(); OuterS;
OuterS = OuterS->getParent()) {
if (OuterS->getEntity()) {
Lexical = static_cast<DeclContext *>(OuterS->getEntity());
@@ -745,12 +761,12 @@ static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
//
// Example:
//
- // namespace N {
- // class C { };
+ // namespace N {
+ // class C { };
//
// template<class T> class B {
// void f(T);
- // };
+ // };
// }
//
// template<class C> void N::B<C>::f(C) {
@@ -759,24 +775,24 @@ static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
//
// In this example, the lexical context we return is the
// TranslationUnit, while the semantic context is the namespace N.
- if (!Lexical || !DC || !S->getParent() ||
+ if (!Lexical || !DC || !S->getParent() ||
!S->getParent()->isTemplateParamScope())
return std::make_pair(Lexical, false);
- // Find the outermost template parameter scope.
+ // Find the outermost template parameter scope.
// For the example, this is the scope for the template parameters of
// template<class C>.
Scope *OutermostTemplateScope = S->getParent();
while (OutermostTemplateScope->getParent() &&
OutermostTemplateScope->getParent()->isTemplateParamScope())
OutermostTemplateScope = OutermostTemplateScope->getParent();
-
+
// Find the namespace context in which the original scope occurs. In
// the example, this is namespace N.
DeclContext *Semantic = DC;
while (!Semantic->isFileContext())
Semantic = Semantic->getParent();
-
+
// Find the declaration context just outside of the template
// parameter scope. This is the context in which the template is
// being lexically declaration (a namespace context). In the
@@ -800,7 +816,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
if (DeclContext *DC = static_cast<DeclContext *>(PreS->getEntity()))
DeclareImplicitMemberFunctionsWithName(*this, Name, DC);
}
-
+
// Implicitly declare member functions with the name we're looking for, if in
// fact we are in a scope where it matters.
@@ -883,7 +899,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
if (ObjCInterfaceDecl *Class = Method->getClassInterface()) {
ObjCInterfaceDecl *ClassDeclared;
if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(
- Name.getAsIdentifierInfo(),
+ Name.getAsIdentifierInfo(),
ClassDeclared)) {
if (R.isAcceptableDecl(Ivar)) {
R.addDecl(Ivar);
@@ -913,6 +929,10 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// FIXME: This really, really shouldn't be happening.
if (!S) return false;
+ // If we are looking for members, no need to look into global/namespace scope.
+ if (R.getLookupKind() == LookupMemberName)
+ return false;
+
// Collect UsingDirectiveDecls in all scopes, and recursively all
// nominated namespaces by those using-directives.
//
@@ -958,7 +978,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
Ctx = OutsideOfTemplateParamDC;
OutsideOfTemplateParamDC = 0;
}
-
+
if (Ctx) {
DeclContext *OuterCtx;
bool SearchAfterTemplateScope;
@@ -972,24 +992,24 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// non-transparent context.
if (Ctx->isTransparentContext())
continue;
-
+
// If we have a context, and it's not a context stashed in the
// template parameter scope for an out-of-line definition, also
// look into that context.
if (!(Found && S && S->isTemplateParamScope())) {
assert(Ctx->isFileContext() &&
"We should have been looking only at file context here already.");
-
+
// Look into context considering using-directives.
if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs))
Found = true;
}
-
+
if (Found) {
R.resolveKind();
return true;
}
-
+
if (R.isForRedeclaration() && !Ctx->isTransparentContext())
return false;
}
@@ -1042,7 +1062,6 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
if (!getLangOptions().CPlusPlus) {
// Unqualified name lookup in C/Objective-C is purely lexical, so
// search in the declarations attached to the name.
-
if (NameKind == Sema::LookupRedeclarationWithLinkage) {
// Find the nearest non-transparent declaration scope.
while (!(S->getFlags() & Scope::DeclScope) ||
@@ -1228,16 +1247,48 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
}
/// \brief Callback that looks for any member of a class with the given name.
-static bool LookupAnyMember(const CXXBaseSpecifier *Specifier,
+static bool LookupAnyMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
-
+
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
Path.Decls = BaseRecord->lookup(N);
return Path.Decls.first != Path.Decls.second;
}
+/// \brief Determine whether the given set of member declarations contains only
+/// static members, nested types, and enumerators.
+template<typename InputIterator>
+static bool HasOnlyStaticMembers(InputIterator First, InputIterator Last) {
+ Decl *D = (*First)->getUnderlyingDecl();
+ if (isa<VarDecl>(D) || isa<TypeDecl>(D) || isa<EnumConstantDecl>(D))
+ return true;
+
+ if (isa<CXXMethodDecl>(D)) {
+ // Determine whether all of the methods are static.
+ bool AllMethodsAreStatic = true;
+ for(; First != Last; ++First) {
+ D = (*First)->getUnderlyingDecl();
+
+ if (!isa<CXXMethodDecl>(D)) {
+ assert(isa<TagDecl>(D) && "Non-function must be a tag decl");
+ break;
+ }
+
+ if (!cast<CXXMethodDecl>(D)->isStatic()) {
+ AllMethodsAreStatic = false;
+ break;
+ }
+ }
+
+ if (AllMethodsAreStatic)
+ return true;
+ }
+
+ return false;
+}
+
/// \brief Perform qualified name lookup into a given context.
///
/// Qualified name lookup (C++ [basic.lookup.qual]) is used to find
@@ -1256,7 +1307,7 @@ static bool LookupAnyMember(const CXXBaseSpecifier *Specifier,
/// search. If the lookup criteria permits, name lookup may also search
/// in the parent contexts or (for C++ classes) base classes.
///
-/// \param InUnqualifiedLookup true if this is qualified name lookup that
+/// \param InUnqualifiedLookup true if this is qualified name lookup that
/// occurs as part of unqualified name lookup.
///
/// \returns true if lookup succeeded, false if it failed.
@@ -1307,7 +1358,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// If we're performing qualified name lookup into a dependent class,
// then we are actually looking into a current instantiation. If we have any
- // dependent base classes, then we either have to delay lookup until
+ // dependent base classes, then we either have to delay lookup until
// template instantiation time (at which point all bases will be available)
// or we have to fail.
if (!InUnqualifiedLookup && LookupRec->isDependentContext() &&
@@ -1315,7 +1366,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
R.setNotFoundInCurrentInstantiation();
return false;
}
-
+
// Perform lookup into our base classes.
CXXBasePaths Paths;
Paths.setOrigin(LookupRec);
@@ -1328,7 +1379,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
case LookupRedeclarationWithLinkage:
BaseCallback = &CXXRecordDecl::FindOrdinaryMember;
break;
-
+
case LookupTagName:
BaseCallback = &CXXRecordDecl::FindTagMember;
break;
@@ -1336,21 +1387,22 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
case LookupAnyName:
BaseCallback = &LookupAnyMember;
break;
-
+
case LookupUsingDeclName:
// This lookup is for redeclarations only.
-
+
case LookupOperatorName:
case LookupNamespaceName:
case LookupObjCProtocolName:
+ case LookupLabel:
// These lookups will never find a member in a C++ class (or base class).
return false;
-
+
case LookupNestedNameSpecifierName:
BaseCallback = &CXXRecordDecl::FindNestedNameSpecifierMember;
break;
}
-
+
if (!LookupRec->lookupInBases(BaseCallback,
R.getLookupName().getAsOpaquePtr(), Paths))
return false;
@@ -1363,10 +1415,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// and includes members from distinct sub-objects, there is an
// ambiguity and the program is ill-formed. Otherwise that set is
// the result of the lookup.
- // FIXME: support using declarations!
QualType SubobjectType;
int SubobjectNumber = 0;
AccessSpecifier SubobjectAccess = AS_none;
+
for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
Path != PathEnd; ++Path) {
const CXXBasePathElement &PathElement = Path->back();
@@ -1374,51 +1426,54 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Pick the best (i.e. most permissive i.e. numerically lowest) access
// across all paths.
SubobjectAccess = std::min(SubobjectAccess, Path->Access);
-
+
// Determine whether we're looking at a distinct sub-object or not.
if (SubobjectType.isNull()) {
// This is the first subobject we've looked at. Record its type.
SubobjectType = Context.getCanonicalType(PathElement.Base->getType());
SubobjectNumber = PathElement.SubobjectNumber;
- } else if (SubobjectType
+ continue;
+ }
+
+ if (SubobjectType
!= Context.getCanonicalType(PathElement.Base->getType())) {
// We found members of the given name in two subobjects of
- // different types. This lookup is ambiguous.
+ // different types. If the declaration sets aren't the same, this
+ // this lookup is ambiguous.
+ if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) {
+ CXXBasePaths::paths_iterator FirstPath = Paths.begin();
+ DeclContext::lookup_iterator FirstD = FirstPath->Decls.first;
+ DeclContext::lookup_iterator CurrentD = Path->Decls.first;
+
+ while (FirstD != FirstPath->Decls.second &&
+ CurrentD != Path->Decls.second) {
+ if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() !=
+ (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl())
+ break;
+
+ ++FirstD;
+ ++CurrentD;
+ }
+
+ if (FirstD == FirstPath->Decls.second &&
+ CurrentD == Path->Decls.second)
+ continue;
+ }
+
R.setAmbiguousBaseSubobjectTypes(Paths);
return true;
- } else if (SubobjectNumber != PathElement.SubobjectNumber) {
+ }
+
+ if (SubobjectNumber != PathElement.SubobjectNumber) {
// We have a different subobject of the same type.
// C++ [class.member.lookup]p5:
// A static member, a nested type or an enumerator defined in
// a base class T can unambiguously be found even if an object
// has more than one base class subobject of type T.
- Decl *FirstDecl = *Path->Decls.first;
- if (isa<VarDecl>(FirstDecl) ||
- isa<TypeDecl>(FirstDecl) ||
- isa<EnumConstantDecl>(FirstDecl))
+ if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second))
continue;
- if (isa<CXXMethodDecl>(FirstDecl)) {
- // Determine whether all of the methods are static.
- bool AllMethodsAreStatic = true;
- for (DeclContext::lookup_iterator Func = Path->Decls.first;
- Func != Path->Decls.second; ++Func) {
- if (!isa<CXXMethodDecl>(*Func)) {
- assert(isa<TagDecl>(*Func) && "Non-function must be a tag decl");
- break;
- }
-
- if (!cast<CXXMethodDecl>(*Func)->isStatic()) {
- AllMethodsAreStatic = false;
- break;
- }
- }
-
- if (AllMethodsAreStatic)
- continue;
- }
-
// We have found a nonstatic member name in multiple, distinct
// subobjects. Name lookup is ambiguous.
R.setAmbiguousBaseSubobjects(Paths);
@@ -1453,13 +1508,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
///
/// @param SS An optional C++ scope-specifier, e.g., "::N::M".
///
-/// @param Name The name of the entity that name lookup will
-/// search for.
-///
-/// @param Loc If provided, the source location where we're performing
-/// name lookup. At present, this is only used to produce diagnostics when
-/// C library functions (like "malloc") are implicitly declared.
-///
/// @param EnteringContext Indicates whether we are going to enter the
/// context of the scope-specifier SS (if present).
///
@@ -1525,21 +1573,21 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects)
<< Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths)
<< LookupRange;
-
+
DeclContext::lookup_iterator Found = Paths->front().Decls.first;
while (isa<CXXMethodDecl>(*Found) &&
cast<CXXMethodDecl>(*Found)->isStatic())
++Found;
-
+
Diag((*Found)->getLocation(), diag::note_ambiguous_member_found);
-
+
return true;
}
case LookupResult::AmbiguousBaseSubobjectTypes: {
Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types)
<< Name << LookupRange;
-
+
CXXBasePaths *Paths = Result.getBasePaths();
std::set<Decl *> DeclsPrinted;
for (CXXBasePaths::paths_iterator Path = Paths->begin(),
@@ -1582,7 +1630,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
case LookupResult::AmbiguousReference: {
Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange;
-
+
LookupResult::iterator DI = Result.begin(), DE = Result.end();
for (; DI != DE; ++DI)
Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI;
@@ -1648,11 +1696,12 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
addAssociatedClassesAndNamespaces(Result, Arg.getAsType());
break;
- case TemplateArgument::Template: {
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion: {
// [...] the namespaces in which any template template arguments are
// defined; and the classes in which any member templates used as
// template template arguments are defined.
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
if (ClassTemplateDecl *ClassTemplate
= dyn_cast<ClassTemplateDecl>(Template.getAsTemplateDecl())) {
DeclContext *Ctx = ClassTemplate->getDeclContext();
@@ -1663,7 +1712,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
}
break;
}
-
+
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::Expression:
@@ -1713,7 +1762,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
// -- If T is a template-id, its associated namespaces and classes are
// the namespace in which the template is defined; for member
- // templates, the member template’s class; the namespaces and classes
+ // templates, the member template's class; the namespaces and classes
// associated with the types of the template arguments provided for
// template type parameters (excluding template template parameters); the
// namespaces in which any template template arguments are defined; and
@@ -1840,7 +1889,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// -- If T is an enumeration type, its associated namespace is
// the namespace in which it is defined. If it is class
- // member, its associated class is the member’s class; else
+ // member, its associated class is the member's class; else
// it has no associated class.
case Type::Enum: {
EnumDecl *Enum = cast<EnumType>(T)->getDecl();
@@ -2032,7 +2081,7 @@ NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name,
}
/// \brief Find the protocol with the given name, if any.
-ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II,
+ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II,
SourceLocation IdLoc) {
Decl *D = LookupSingleName(TUScope, II, IdLoc,
LookupObjCProtocolName);
@@ -2089,7 +2138,7 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
if (!Class->hasDeclaredCopyConstructor())
DeclareImplicitCopyConstructor(Class);
}
-
+
CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class));
DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T);
return Class->lookup(Name);
@@ -2097,7 +2146,7 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
/// \brief Look for the destructor of the given class.
///
-/// During semantic analysis, this routine should be used in lieu of
+/// During semantic analysis, this routine should be used in lieu of
/// CXXRecordDecl::getDestructor().
///
/// \returns The destructor for this class.
@@ -2233,7 +2282,7 @@ public:
/// of declarations.
class ShadowMapEntry {
typedef llvm::SmallVector<NamedDecl *, 4> DeclVector;
-
+
/// \brief Contains either the solitary NamedDecl * or a vector
/// of declarations.
llvm::PointerUnion<NamedDecl *, DeclVector*> DeclOrVector;
@@ -2245,7 +2294,7 @@ public:
void Destroy();
// Iteration.
- typedef NamedDecl **iterator;
+ typedef NamedDecl * const *iterator;
iterator begin();
iterator end();
};
@@ -2315,7 +2364,7 @@ void VisibleDeclsRecord::ShadowMapEntry::Add(NamedDecl *ND) {
DeclOrVector = ND;
return;
}
-
+
if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) {
// 1 -> 2 elements: create the vector of results and push in the
// existing declaration.
@@ -2335,18 +2384,18 @@ void VisibleDeclsRecord::ShadowMapEntry::Destroy() {
}
}
-VisibleDeclsRecord::ShadowMapEntry::iterator
+VisibleDeclsRecord::ShadowMapEntry::iterator
VisibleDeclsRecord::ShadowMapEntry::begin() {
if (DeclOrVector.isNull())
return 0;
- if (DeclOrVector.dyn_cast<NamedDecl *>())
- return &reinterpret_cast<NamedDecl*&>(DeclOrVector);
+ if (DeclOrVector.is<NamedDecl *>())
+ return DeclOrVector.getAddrOf<NamedDecl *>();
return DeclOrVector.get<DeclVector *>()->begin();
}
-VisibleDeclsRecord::ShadowMapEntry::iterator
+VisibleDeclsRecord::ShadowMapEntry::iterator
VisibleDeclsRecord::ShadowMapEntry::end() {
if (DeclOrVector.isNull())
return 0;
@@ -2360,7 +2409,7 @@ VisibleDeclsRecord::ShadowMapEntry::end() {
NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
// Look through using declarations.
ND = ND->getUnderlyingDecl();
-
+
unsigned IDNS = ND->getIdentifierNamespace();
std::list<ShadowMap>::reverse_iterator SM = ShadowMaps.rbegin();
for (std::list<ShadowMap>::reverse_iterator SMEnd = ShadowMaps.rend();
@@ -2369,12 +2418,12 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
if (Pos == SM->end())
continue;
- for (ShadowMapEntry::iterator I = Pos->second.begin(),
+ for (ShadowMapEntry::iterator I = Pos->second.begin(),
IEnd = Pos->second.end();
I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
if ((*I)->hasTagIdentifierNamespace() &&
- (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
+ (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
Decl::IDNS_ObjCProtocol)))
continue;
@@ -2391,7 +2440,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
ND->isFunctionOrFunctionTemplate() &&
SM == ShadowMaps.rbegin())
continue;
-
+
// We've found a declaration that hides this one.
return *I;
}
@@ -2411,22 +2460,44 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Make sure we don't visit the same context twice.
if (Visited.visitedContext(Ctx->getPrimaryContext()))
return;
-
+
if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
Result.getSema().ForceDeclarationOfImplicitMembers(Class);
// Enumerate all of the results in this context.
- for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
+ for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
CurCtx = CurCtx->getNextContext()) {
- for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
+ for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
DEnd = CurCtx->decls_end();
D != DEnd; ++D) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
if (Result.isAcceptableDecl(ND)) {
Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass);
Visited.add(ND);
}
-
+ } else if (ObjCForwardProtocolDecl *ForwardProto
+ = dyn_cast<ObjCForwardProtocolDecl>(*D)) {
+ for (ObjCForwardProtocolDecl::protocol_iterator
+ P = ForwardProto->protocol_begin(),
+ PEnd = ForwardProto->protocol_end();
+ P != PEnd;
+ ++P) {
+ if (Result.isAcceptableDecl(*P)) {
+ Consumer.FoundDecl(*P, Visited.checkHidden(*P), InBaseClass);
+ Visited.add(*P);
+ }
+ }
+ } else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) {
+ for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end();
+ I != IEnd; ++I) {
+ ObjCInterfaceDecl *IFace = I->getInterface();
+ if (Result.isAcceptableDecl(IFace)) {
+ Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), InBaseClass);
+ Visited.add(IFace);
+ }
+ }
+ }
+
// Visit transparent contexts and inline namespaces inside this context.
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) {
if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
@@ -2441,7 +2512,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
ShadowContextRAII Shadow(Visited);
DeclContext::udir_iterator I, E;
for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) {
- LookupVisibleDecls((*I)->getNominatedNamespace(), Result,
+ LookupVisibleDecls((*I)->getNominatedNamespace(), Result,
QualifiedNameLookup, InBaseClass, Consumer, Visited);
}
}
@@ -2455,16 +2526,16 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
BEnd = Record->bases_end();
B != BEnd; ++B) {
QualType BaseType = B->getType();
-
+
// Don't look into dependent bases, because name lookup can't look
// there anyway.
if (BaseType->isDependentType())
continue;
-
+
const RecordType *Record = BaseType->getAs<RecordType>();
if (!Record)
continue;
-
+
// FIXME: It would be nice to be able to determine whether referencing
// a particular member would be ambiguous. For example, given
//
@@ -2483,21 +2554,21 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// or
//
// c->A::member
-
+
// Find results in this base class (and its bases).
ShadowContextRAII Shadow(Visited);
LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup,
true, Consumer, Visited);
}
}
-
+
// Traverse the contexts of Objective-C classes.
if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
// Traverse categories.
for (ObjCCategoryDecl *Category = IFace->getCategoryList();
Category; Category = Category->getNextClassCategory()) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Category, Result, QualifiedNameLookup, false,
+ LookupVisibleDecls(Category, Result, QualifiedNameLookup, false,
Consumer, Visited);
}
@@ -2506,7 +2577,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
I = IFace->all_referenced_protocol_begin(),
E = IFace->all_referenced_protocol_end(); I != E; ++I) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
Visited);
}
@@ -2516,35 +2587,35 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup,
true, Consumer, Visited);
}
-
+
// If there is an implementation, traverse it. We do this to find
// synthesized ivars.
if (IFace->getImplementation()) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(IFace->getImplementation(), Result,
+ LookupVisibleDecls(IFace->getImplementation(), Result,
QualifiedNameLookup, true, Consumer, Visited);
}
} else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) {
for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(),
E = Protocol->protocol_end(); I != E; ++I) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
Visited);
}
} else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) {
for (ObjCCategoryDecl::protocol_iterator I = Category->protocol_begin(),
E = Category->protocol_end(); I != E; ++I) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
Visited);
}
-
+
// If there is an implementation, traverse it.
if (Category->getImplementation()) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Category->getImplementation(), Result,
+ LookupVisibleDecls(Category->getImplementation(), Result,
QualifiedNameLookup, true, Consumer, Visited);
- }
+ }
}
}
@@ -2555,8 +2626,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
if (!S)
return;
- if (!S->getEntity() ||
- (!S->getParent() &&
+ if (!S->getEntity() ||
+ (!S->getParent() &&
!Visited.alreadyVisitedContext((DeclContext *)S->getEntity())) ||
((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
// Walk through the declarations in this Scope.
@@ -2569,7 +2640,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
}
}
}
-
+
// FIXME: C++ [temp.local]p8
DeclContext *Entity = 0;
if (S->getEntity()) {
@@ -2578,7 +2649,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
// where we hit the context stored in the next outer scope.
Entity = (DeclContext *)S->getEntity();
DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
-
+
for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx);
Ctx = Ctx->getLookupParent()) {
if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) {
@@ -2586,9 +2657,27 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
// For instance methods, look for ivars in the method's interface.
LookupResult IvarResult(Result.getSema(), Result.getLookupName(),
Result.getNameLoc(), Sema::LookupMemberName);
- if (ObjCInterfaceDecl *IFace = Method->getClassInterface())
- LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
+ if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) {
+ LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
/*InBaseClass=*/false, Consumer, Visited);
+
+ // Look for properties from which we can synthesize ivars, if
+ // permitted.
+ if (Result.getSema().getLangOptions().ObjCNonFragileABI2 &&
+ IFace->getImplementation() &&
+ Result.getLookupKind() == Sema::LookupOrdinaryName) {
+ for (ObjCInterfaceDecl::prop_iterator
+ P = IFace->prop_begin(),
+ PEnd = IFace->prop_end();
+ P != PEnd; ++P) {
+ if (Result.getSema().canSynthesizeProvisionalIvar(*P) &&
+ !IFace->lookupInstanceVariable((*P)->getIdentifier())) {
+ Consumer.FoundDecl(*P, Visited.checkHidden(*P), false);
+ Visited.add(*P);
+ }
+ }
+ }
+ }
}
// We've already performed all of the name lookup that we need
@@ -2599,8 +2688,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
if (Ctx->isFunctionOrMethod())
continue;
-
- LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false,
+
+ LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false,
/*InBaseClass=*/false, Consumer, Visited);
}
} else if (!S->getParent()) {
@@ -2610,14 +2699,14 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
// FIXME: We would like the translation unit's Scope object to point to the
// translation unit, so we don't need this special "if" branch. However,
// doing so would force the normal C++ name-lookup code to look into the
- // translation unit decl when the IdentifierInfo chains would suffice.
+ // translation unit decl when the IdentifierInfo chains would suffice.
// Once we fix that problem (which is part of a more general "don't look
// in DeclContexts unless we have to" optimization), we can eliminate this.
Entity = Result.getSema().Context.getTranslationUnitDecl();
- LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false,
+ LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false,
/*InBaseClass=*/false, Consumer, Visited);
- }
-
+ }
+
if (Entity) {
// Lookup visible declarations in any namespaces found by using
// directives.
@@ -2625,7 +2714,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity);
for (; UI != UEnd; ++UI)
LookupVisibleDecls(const_cast<DeclContext *>(UI->getNominatedNamespace()),
- Result, /*QualifiedNameLookup=*/false,
+ Result, /*QualifiedNameLookup=*/false,
/*InBaseClass=*/false, Consumer, Visited);
}
@@ -2667,13 +2756,41 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
if (!IncludeGlobalScope)
Visited.visitedContext(Context.getTranslationUnitDecl());
ShadowContextRAII Shadow(Visited);
- ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true,
+ ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true,
/*InBaseClass=*/false, Consumer, Visited);
}
-//----------------------------------------------------------------------------
+/// LookupOrCreateLabel - Do a name lookup of a label with the specified name.
+/// If isLocalLabel is true, then this is a definition of an __label__ label
+/// name, otherwise it is a normal label definition or use.
+LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
+ bool isLocalLabel) {
+ // Do a lookup to see if we have a label with this name already.
+ NamedDecl *Res = 0;
+
+ // Local label definitions always shadow existing labels.
+ if (!isLocalLabel)
+ Res = LookupSingleName(CurScope, II, Loc, LookupLabel, NotForRedeclaration);
+
+ // If we found a label, check to see if it is in the same context as us. When
+ // in a Block, we don't want to reuse a label in an enclosing function.
+ if (Res && Res->getDeclContext() != CurContext)
+ Res = 0;
+
+ if (Res == 0) {
+ // If not forward referenced or defined already, create the backing decl.
+ Res = LabelDecl::Create(Context, CurContext, Loc, II);
+ Scope *S = isLocalLabel ? CurScope : CurScope->getFnParent();
+ assert(S && "Not in a function?");
+ PushOnScopeChains(Res, S, true);
+ }
+
+ return cast<LabelDecl>(Res);
+}
+
+//===----------------------------------------------------------------------===//
// Typo correction
-//----------------------------------------------------------------------------
+//===----------------------------------------------------------------------===//
namespace {
class TypoCorrectionConsumer : public VisibleDeclConsumer {
@@ -2682,46 +2799,44 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer {
/// \brief The results found that have the smallest edit distance
/// found (so far) with the typo name.
- llvm::SmallVector<NamedDecl *, 4> BestResults;
+ ///
+ /// The boolean value indicates whether there is a keyword with this name.
+ llvm::StringMap<bool, llvm::BumpPtrAllocator> BestResults;
- /// \brief The keywords that have the smallest edit distance.
- llvm::SmallVector<IdentifierInfo *, 4> BestKeywords;
-
/// \brief The best edit distance found so far.
unsigned BestEditDistance;
-
+
public:
explicit TypoCorrectionConsumer(IdentifierInfo *Typo)
- : Typo(Typo->getName()) { }
+ : Typo(Typo->getName()),
+ BestEditDistance((std::numeric_limits<unsigned>::max)()) { }
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass);
+ void FoundName(llvm::StringRef Name);
void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword);
- typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator;
- iterator begin() const { return BestResults.begin(); }
- iterator end() const { return BestResults.end(); }
- void clear_decls() { BestResults.clear(); }
-
- bool empty() const { return BestResults.empty() && BestKeywords.empty(); }
-
- typedef llvm::SmallVector<IdentifierInfo *, 4>::const_iterator
- keyword_iterator;
- keyword_iterator keyword_begin() const { return BestKeywords.begin(); }
- keyword_iterator keyword_end() const { return BestKeywords.end(); }
- bool keyword_empty() const { return BestKeywords.empty(); }
- unsigned keyword_size() const { return BestKeywords.size(); }
-
- unsigned getBestEditDistance() const { return BestEditDistance; }
+ typedef llvm::StringMap<bool, llvm::BumpPtrAllocator>::iterator iterator;
+ iterator begin() { return BestResults.begin(); }
+ iterator end() { return BestResults.end(); }
+ void erase(iterator I) { BestResults.erase(I); }
+ unsigned size() const { return BestResults.size(); }
+ bool empty() const { return BestResults.empty(); }
+
+ bool &operator[](llvm::StringRef Name) {
+ return BestResults[Name];
+ }
+
+ unsigned getBestEditDistance() const { return BestEditDistance; }
};
}
-void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
+void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
bool InBaseClass) {
// Don't consider hidden names for typo correction.
if (Hiding)
return;
-
+
// Only consider entities with identifiers for names, ignoring
// special names (constructors, overloaded operators, selectors,
// etc.).
@@ -2729,48 +2844,114 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
if (!Name)
return;
+ FoundName(Name->getName());
+}
+
+void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) {
+ using namespace std;
+
+ // Use a simple length-based heuristic to determine the minimum possible
+ // edit distance. If the minimum isn't good enough, bail out early.
+ unsigned MinED = abs((int)Name.size() - (int)Typo.size());
+ if (MinED > BestEditDistance || (MinED && Typo.size() / MinED < 3))
+ return;
+
+ // Compute an upper bound on the allowable edit distance, so that the
+ // edit-distance algorithm can short-circuit.
+ unsigned UpperBound = min(unsigned((Typo.size() + 2) / 3), BestEditDistance);
+
// Compute the edit distance between the typo and the name of this
// entity. If this edit distance is not worse than the best edit
// distance we've seen so far, add it to the list of results.
- unsigned ED = Typo.edit_distance(Name->getName());
- if (!BestResults.empty() || !BestKeywords.empty()) {
- if (ED < BestEditDistance) {
- // This result is better than any we've seen before; clear out
- // the previous results.
- BestResults.clear();
- BestKeywords.clear();
- BestEditDistance = ED;
- } else if (ED > BestEditDistance) {
- // This result is worse than the best results we've seen so far;
- // ignore it.
- return;
- }
- } else
+ unsigned ED = Typo.edit_distance(Name, true, UpperBound);
+ if (ED == 0)
+ return;
+
+ if (ED < BestEditDistance) {
+ // This result is better than any we've seen before; clear out
+ // the previous results.
+ BestResults.clear();
BestEditDistance = ED;
+ } else if (ED > BestEditDistance) {
+ // This result is worse than the best results we've seen so far;
+ // ignore it.
+ return;
+ }
- BestResults.push_back(ND);
+ // Add this name to the list of results. By not assigning a value, we
+ // keep the current value if we've seen this name before (either as a
+ // keyword or as a declaration), or get the default value (not a keyword)
+ // if we haven't seen it before.
+ (void)BestResults[Name];
}
-void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context,
+void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context,
llvm::StringRef Keyword) {
// Compute the edit distance between the typo and this keyword.
// If this edit distance is not worse than the best edit
// distance we've seen so far, add it to the list of results.
unsigned ED = Typo.edit_distance(Keyword);
- if (!BestResults.empty() || !BestKeywords.empty()) {
- if (ED < BestEditDistance) {
- BestResults.clear();
- BestKeywords.clear();
- BestEditDistance = ED;
- } else if (ED > BestEditDistance) {
- // This result is worse than the best results we've seen so far;
- // ignore it.
- return;
- }
- } else
+ if (ED < BestEditDistance) {
+ BestResults.clear();
BestEditDistance = ED;
-
- BestKeywords.push_back(&Context.Idents.get(Keyword));
+ } else if (ED > BestEditDistance) {
+ // This result is worse than the best results we've seen so far;
+ // ignore it.
+ return;
+ }
+
+ BestResults[Keyword] = true;
+}
+
+/// \brief Perform name lookup for a possible result for typo correction.
+static void LookupPotentialTypoResult(Sema &SemaRef,
+ LookupResult &Res,
+ IdentifierInfo *Name,
+ Scope *S, CXXScopeSpec *SS,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ Sema::CorrectTypoContext CTC) {
+ Res.suppressDiagnostics();
+ Res.clear();
+ Res.setLookupName(Name);
+ if (MemberContext) {
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(MemberContext)) {
+ if (CTC == Sema::CTC_ObjCIvarLookup) {
+ if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(Name)) {
+ Res.addDecl(Ivar);
+ Res.resolveKind();
+ return;
+ }
+ }
+
+ if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration(Name)) {
+ Res.addDecl(Prop);
+ Res.resolveKind();
+ return;
+ }
+ }
+
+ SemaRef.LookupQualifiedName(Res, MemberContext);
+ return;
+ }
+
+ SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false,
+ EnteringContext);
+
+ // Fake ivar lookup; this should really be part of
+ // LookupParsedName.
+ if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) {
+ if (Method->isInstanceMethod() && Method->getClassInterface() &&
+ (Res.empty() ||
+ (Res.isSingleResult() &&
+ Res.getFoundDecl()->isDefinedOutsideFunctionOrMethod()))) {
+ if (ObjCIvarDecl *IV
+ = Method->getClassInterface()->lookupInstanceVariable(Name)) {
+ Res.addDecl(IV);
+ Res.resolveKind();
+ }
+ }
+ }
}
/// \brief Try to "correct" a typo in the source code by finding
@@ -2790,7 +2971,7 @@ void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context,
/// \param MemberContext if non-NULL, the context in which to look for
/// a member access expression.
///
-/// \param EnteringContext whether we're entering the context described by
+/// \param EnteringContext whether we're entering the context described by
/// the nested-name-specifier SS.
///
/// \param CTC The context in which typo correction occurs, which impacts the
@@ -2804,21 +2985,13 @@ void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context,
/// may contain the results of name lookup for the correct name or it may be
/// empty.
DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
- DeclContext *MemberContext,
+ DeclContext *MemberContext,
bool EnteringContext,
CorrectTypoContext CTC,
const ObjCObjectPointerType *OPT) {
if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking)
return DeclarationName();
- // Provide a stop gap for files that are just seriously broken. Trying
- // to correct all typos can turn into a HUGE performance penalty, causing
- // some files to take minutes to get rejected by the parser.
- // FIXME: Is this the right solution?
- if (TyposCorrected == 20)
- return DeclarationName();
- ++TyposCorrected;
-
// We only attempt to correct typos for identifiers.
IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
if (!Typo)
@@ -2833,17 +3006,18 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
// instantiation.
if (!ActiveTemplateInstantiations.empty())
return DeclarationName();
-
+
TypoCorrectionConsumer Consumer(Typo);
-
+
// Perform name lookup to find visible, similarly-named entities.
+ bool IsUnqualifiedLookup = false;
if (MemberContext) {
LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer);
// Look in qualified interfaces.
if (OPT) {
- for (ObjCObjectPointerType::qual_iterator
- I = OPT->qual_begin(), E = OPT->qual_end();
+ for (ObjCObjectPointerType::qual_iterator
+ I = OPT->qual_begin(), E = OPT->qual_end();
I != E; ++I)
LookupVisibleDecls(*I, Res.getLookupKind(), Consumer);
}
@@ -2851,10 +3025,54 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
DeclContext *DC = computeDeclContext(*SS, EnteringContext);
if (!DC)
return DeclarationName();
-
+
+ // Provide a stop gap for files that are just seriously broken. Trying
+ // to correct all typos can turn into a HUGE performance penalty, causing
+ // some files to take minutes to get rejected by the parser.
+ if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
+ return DeclarationName();
+ ++TyposCorrected;
+
LookupVisibleDecls(DC, Res.getLookupKind(), Consumer);
} else {
- LookupVisibleDecls(S, Res.getLookupKind(), Consumer);
+ IsUnqualifiedLookup = true;
+ UnqualifiedTyposCorrectedMap::iterator Cached
+ = UnqualifiedTyposCorrected.find(Typo);
+ if (Cached == UnqualifiedTyposCorrected.end()) {
+ // Provide a stop gap for files that are just seriously broken. Trying
+ // to correct all typos can turn into a HUGE performance penalty, causing
+ // some files to take minutes to get rejected by the parser.
+ if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
+ return DeclarationName();
+
+ // For unqualified lookup, look through all of the names that we have
+ // seen in this translation unit.
+ for (IdentifierTable::iterator I = Context.Idents.begin(),
+ IEnd = Context.Idents.end();
+ I != IEnd; ++I)
+ Consumer.FoundName(I->getKey());
+
+ // Walk through identifiers in external identifier sources.
+ if (IdentifierInfoLookup *External
+ = Context.Idents.getExternalIdentifierLookup()) {
+ llvm::OwningPtr<IdentifierIterator> Iter(External->getIdentifiers());
+ do {
+ llvm::StringRef Name = Iter->Next();
+ if (Name.empty())
+ break;
+
+ Consumer.FoundName(Name);
+ } while (true);
+ }
+ } else {
+ // Use the cached value, unless it's a keyword. In the keyword case, we'll
+ // end up adding the keyword below.
+ if (Cached->second.first.empty())
+ return DeclarationName();
+
+ if (!Cached->second.second)
+ Consumer.FoundName(Cached->second.first);
+ }
}
// Add context-dependent keywords.
@@ -2868,39 +3086,46 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
WantExpressionKeywords = true;
WantCXXNamedCasts = true;
WantRemainingKeywords = true;
-
+
if (ObjCMethodDecl *Method = getCurMethodDecl())
if (Method->getClassInterface() &&
Method->getClassInterface()->getSuperClass())
Consumer.addKeywordResult(Context, "super");
-
+
break;
-
+
case CTC_NoKeywords:
break;
-
+
case CTC_Type:
WantTypeSpecifiers = true;
break;
-
+
case CTC_ObjCMessageReceiver:
Consumer.addKeywordResult(Context, "super");
// Fall through to handle message receivers like expressions.
-
+
case CTC_Expression:
if (getLangOptions().CPlusPlus)
WantTypeSpecifiers = true;
WantExpressionKeywords = true;
// Fall through to get C++ named casts.
-
+
case CTC_CXXCasts:
WantCXXNamedCasts = true;
break;
-
+
+ case CTC_ObjCPropertyLookup:
+ // FIXME: Add "isa"?
+ break;
+
case CTC_MemberLookup:
if (getLangOptions().CPlusPlus)
Consumer.addKeywordResult(Context, "template");
break;
+
+ case CTC_ObjCIvarLookup:
+ break;
}
if (WantTypeSpecifiers) {
@@ -2912,67 +3137,67 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
// storage-specifiers as well
"extern", "inline", "static", "typedef"
};
-
+
const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]);
for (unsigned I = 0; I != NumCTypeSpecs; ++I)
Consumer.addKeywordResult(Context, CTypeSpecs[I]);
-
+
if (getLangOptions().C99)
Consumer.addKeywordResult(Context, "restrict");
if (getLangOptions().Bool || getLangOptions().CPlusPlus)
Consumer.addKeywordResult(Context, "bool");
-
+
if (getLangOptions().CPlusPlus) {
Consumer.addKeywordResult(Context, "class");
Consumer.addKeywordResult(Context, "typename");
Consumer.addKeywordResult(Context, "wchar_t");
-
+
if (getLangOptions().CPlusPlus0x) {
Consumer.addKeywordResult(Context, "char16_t");
Consumer.addKeywordResult(Context, "char32_t");
Consumer.addKeywordResult(Context, "constexpr");
Consumer.addKeywordResult(Context, "decltype");
Consumer.addKeywordResult(Context, "thread_local");
- }
+ }
}
-
+
if (getLangOptions().GNUMode)
Consumer.addKeywordResult(Context, "typeof");
}
-
+
if (WantCXXNamedCasts && getLangOptions().CPlusPlus) {
Consumer.addKeywordResult(Context, "const_cast");
Consumer.addKeywordResult(Context, "dynamic_cast");
Consumer.addKeywordResult(Context, "reinterpret_cast");
Consumer.addKeywordResult(Context, "static_cast");
}
-
+
if (WantExpressionKeywords) {
Consumer.addKeywordResult(Context, "sizeof");
if (getLangOptions().Bool || getLangOptions().CPlusPlus) {
Consumer.addKeywordResult(Context, "false");
Consumer.addKeywordResult(Context, "true");
}
-
+
if (getLangOptions().CPlusPlus) {
- const char *CXXExprs[] = {
- "delete", "new", "operator", "throw", "typeid"
+ const char *CXXExprs[] = {
+ "delete", "new", "operator", "throw", "typeid"
};
const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]);
for (unsigned I = 0; I != NumCXXExprs; ++I)
Consumer.addKeywordResult(Context, CXXExprs[I]);
-
+
if (isa<CXXMethodDecl>(CurContext) &&
cast<CXXMethodDecl>(CurContext)->isInstance())
Consumer.addKeywordResult(Context, "this");
-
+
if (getLangOptions().CPlusPlus0x) {
Consumer.addKeywordResult(Context, "alignof");
Consumer.addKeywordResult(Context, "nullptr");
}
}
}
-
+
if (WantRemainingKeywords) {
if (getCurFunctionOrMethodDecl() || getCurBlock()) {
// Statements.
@@ -2981,18 +3206,18 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]);
for (unsigned I = 0; I != NumCStmts; ++I)
Consumer.addKeywordResult(Context, CStmts[I]);
-
+
if (getLangOptions().CPlusPlus) {
Consumer.addKeywordResult(Context, "catch");
Consumer.addKeywordResult(Context, "try");
}
-
+
if (S && S->getBreakParent())
Consumer.addKeywordResult(Context, "break");
-
+
if (S && S->getContinueParent())
Consumer.addKeywordResult(Context, "continue");
-
+
if (!getCurFunction()->SwitchStack.empty()) {
Consumer.addKeywordResult(Context, "case");
Consumer.addKeywordResult(Context, "default");
@@ -3013,7 +3238,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
Consumer.addKeywordResult(Context, "virtual");
}
}
-
+
if (getLangOptions().CPlusPlus) {
Consumer.addKeywordResult(Context, "using");
@@ -3021,122 +3246,134 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
Consumer.addKeywordResult(Context, "static_assert");
}
}
-
+
// If we haven't found anything, we're done.
- if (Consumer.empty())
+ if (Consumer.empty()) {
+ // If this was an unqualified lookup, note that no correction was found.
+ if (IsUnqualifiedLookup)
+ (void)UnqualifiedTyposCorrected[Typo];
+
return DeclarationName();
+ }
- // Only allow a single, closest name in the result set (it's okay to
- // have overloads of that name, though).
- DeclarationName BestName;
- NamedDecl *BestIvarOrPropertyDecl = 0;
- bool FoundIvarOrPropertyDecl = false;
-
- // Check all of the declaration results to find the best name so far.
- for (TypoCorrectionConsumer::iterator I = Consumer.begin(),
+ // Make sure that the user typed at least 3 characters for each correction
+ // made. Otherwise, we don't even both looking at the results.
+
+ // We also suppress exact matches; those should be handled by a
+ // different mechanism (e.g., one that introduces qualification in
+ // C++).
+ unsigned ED = Consumer.getBestEditDistance();
+ if (ED > 0 && Typo->getName().size() / ED < 3) {
+ // If this was an unqualified lookup, note that no correction was found.
+ if (IsUnqualifiedLookup)
+ (void)UnqualifiedTyposCorrected[Typo];
+
+ return DeclarationName();
+ }
+
+ // Weed out any names that could not be found by name lookup.
+ bool LastLookupWasAccepted = false;
+ for (TypoCorrectionConsumer::iterator I = Consumer.begin(),
IEnd = Consumer.end();
- I != IEnd; ++I) {
- if (!BestName)
- BestName = (*I)->getDeclName();
- else if (BestName != (*I)->getDeclName())
- return DeclarationName();
+ I != IEnd; /* Increment in loop. */) {
+ // Keywords are always found.
+ if (I->second) {
+ ++I;
+ continue;
+ }
+
+ // Perform name lookup on this name.
+ IdentifierInfo *Name = &Context.Idents.get(I->getKey());
+ LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext,
+ EnteringContext, CTC);
- // \brief Keep track of either an Objective-C ivar or a property, but not
- // both.
- if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I)) {
- if (FoundIvarOrPropertyDecl)
- BestIvarOrPropertyDecl = 0;
- else {
- BestIvarOrPropertyDecl = *I;
- FoundIvarOrPropertyDecl = true;
+ switch (Res.getResultKind()) {
+ case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::Ambiguous:
+ // We didn't find this name in our scope, or didn't like what we found;
+ // ignore it.
+ Res.suppressDiagnostics();
+ {
+ TypoCorrectionConsumer::iterator Next = I;
+ ++Next;
+ Consumer.erase(I);
+ I = Next;
}
+ LastLookupWasAccepted = false;
+ break;
+
+ case LookupResult::Found:
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ ++I;
+ LastLookupWasAccepted = true;
+ break;
+ }
+
+ if (Res.isAmbiguous()) {
+ // We don't deal with ambiguities.
+ Res.suppressDiagnostics();
+ Res.clear();
+ return DeclarationName();
}
}
- // Now check all of the keyword results to find the best name.
- switch (Consumer.keyword_size()) {
- case 0:
- // No keywords matched.
- break;
-
- case 1:
- // If we already have a name
- if (!BestName) {
- // We did not have anything previously,
- BestName = *Consumer.keyword_begin();
- } else if (BestName.getAsIdentifierInfo() == *Consumer.keyword_begin()) {
- // We have a declaration with the same name as a context-sensitive
- // keyword. The keyword takes precedence.
- BestIvarOrPropertyDecl = 0;
- FoundIvarOrPropertyDecl = false;
- Consumer.clear_decls();
- } else if (CTC == CTC_ObjCMessageReceiver &&
- (*Consumer.keyword_begin())->isStr("super")) {
- // In an Objective-C message send, give the "super" keyword a slight
- // edge over entities not in function or method scope.
- for (TypoCorrectionConsumer::iterator I = Consumer.begin(),
- IEnd = Consumer.end();
- I != IEnd; ++I) {
- if ((*I)->getDeclName() == BestName) {
- if ((*I)->getDeclContext()->isFunctionOrMethod())
- return DeclarationName();
- }
- }
-
- // Everything found was outside a function or method; the 'super'
- // keyword takes precedence.
- BestIvarOrPropertyDecl = 0;
- FoundIvarOrPropertyDecl = false;
- Consumer.clear_decls();
- BestName = *Consumer.keyword_begin();
- } else {
- // Name collision; we will not correct typos.
+ // If only a single name remains, return that result.
+ if (Consumer.size() == 1) {
+ IdentifierInfo *Name = &Context.Idents.get(Consumer.begin()->getKey());
+ if (Consumer.begin()->second) {
+ Res.suppressDiagnostics();
+ Res.clear();
+
+ // Don't correct to a keyword that's the same as the typo; the keyword
+ // wasn't actually in scope.
+ if (ED == 0) {
+ Res.setLookupName(Typo);
return DeclarationName();
}
- break;
-
- default:
- // Name collision; we will not correct typos.
- return DeclarationName();
- }
-
- // BestName is the closest viable name to what the user
- // typed. However, to make sure that we don't pick something that's
- // way off, make sure that the user typed at least 3 characters for
- // each correction.
- unsigned ED = Consumer.getBestEditDistance();
- if (ED == 0 || !BestName.getAsIdentifierInfo() ||
- (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3)
- return DeclarationName();
- // Perform name lookup again with the name we chose, and declare
- // success if we found something that was not ambiguous.
- Res.clear();
- Res.setLookupName(BestName);
-
- // If we found an ivar or property, add that result; no further
- // lookup is required.
- if (BestIvarOrPropertyDecl)
- Res.addDecl(BestIvarOrPropertyDecl);
- // If we're looking into the context of a member, perform qualified
- // name lookup on the best name.
- else if (!Consumer.keyword_empty()) {
- // The best match was a keyword. Return it.
- return BestName;
- } else if (MemberContext)
- LookupQualifiedName(Res, MemberContext);
- // Perform lookup as if we had just parsed the best name.
- else
- LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false,
- EnteringContext);
+ } else if (!LastLookupWasAccepted) {
+ // Perform name lookup on this name.
+ LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext,
+ EnteringContext, CTC);
+ }
- if (Res.isAmbiguous()) {
+ // Record the correction for unqualified lookup.
+ if (IsUnqualifiedLookup)
+ UnqualifiedTyposCorrected[Typo]
+ = std::make_pair(Name->getName(), Consumer.begin()->second);
+
+ return &Context.Idents.get(Consumer.begin()->getKey());
+ }
+ else if (Consumer.size() > 1 && CTC == CTC_ObjCMessageReceiver
+ && Consumer["super"]) {
+ // Prefix 'super' when we're completing in a message-receiver
+ // context.
Res.suppressDiagnostics();
- return DeclarationName();
+ Res.clear();
+
+ // Don't correct to a keyword that's the same as the typo; the keyword
+ // wasn't actually in scope.
+ if (ED == 0) {
+ Res.setLookupName(Typo);
+ return DeclarationName();
+ }
+
+ // Record the correction for unqualified lookup.
+ if (IsUnqualifiedLookup)
+ UnqualifiedTyposCorrected[Typo]
+ = std::make_pair("super", Consumer.begin()->second);
+
+ return &Context.Idents.get("super");
}
- if (Res.getResultKind() != LookupResult::NotFound)
- return BestName;
-
+ Res.suppressDiagnostics();
+ Res.setLookupName(Typo);
+ Res.clear();
+ // Record the correction for unqualified lookup.
+ if (IsUnqualifiedLookup)
+ (void)UnqualifiedTyposCorrected[Typo];
+
return DeclarationName();
}
OpenPOWER on IntegriCloud