diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 54 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 2 |
4 files changed, 54 insertions, 22 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 06927b6d1d..b92bd4fcea 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1209,8 +1209,7 @@ public: VisibleDeclConsumer &Consumer); bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS, - bool AllowBuiltinCreation = false, - bool EnteringContext = false); + bool EnteringContext = false); void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, AssociatedNamespaceSet &AssociatedNamespaces, @@ -1458,7 +1457,7 @@ public: bool HasTrailingLParen, bool IsAddressOfOperand); - bool DiagnoseEmptyLookup(const CXXScopeSpec &SS, LookupResult &R); + bool DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, LookupResult &R); OwningExprResult LookupInObjCMethod(LookupResult &R, Scope *S, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 77ddbc29dd..c87a274122 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -879,28 +879,25 @@ static void DiagnoseInstanceReference(Sema &SemaRef, /// Diagnose an empty lookup. /// /// \return false if new lookup candidates were found -bool Sema::DiagnoseEmptyLookup(const CXXScopeSpec &SS, +bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, LookupResult &R) { DeclarationName Name = R.getLookupName(); - // We don't know how to recover from bad qualified lookups. - if (!SS.isEmpty()) { - Diag(R.getNameLoc(), diag::err_no_member) - << Name << computeDeclContext(SS, false) - << SS.getRange(); - return true; - } - unsigned diagnostic = diag::err_undeclared_var_use; + unsigned diagnostic_suggest = diag::err_undeclared_var_use_suggest; if (Name.getNameKind() == DeclarationName::CXXOperatorName || Name.getNameKind() == DeclarationName::CXXLiteralOperatorName || - Name.getNameKind() == DeclarationName::CXXConversionFunctionName) + Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { diagnostic = diag::err_undeclared_use; + diagnostic_suggest = diag::err_undeclared_use_suggest; + } - // Fake an unqualified lookup. This is useful when (for example) - // the original lookup would not have found something because it was - // a dependent name. - for (DeclContext *DC = CurContext; DC; DC = DC->getParent()) { + // If the original lookup was an unqualified lookup, fake an + // unqualified lookup. This is useful when (for example) the + // original lookup would not have found something because it was a + // dependent name. + for (DeclContext *DC = SS.isEmpty()? CurContext : 0; + DC; DC = DC->getParent()) { if (isa<CXXRecordDecl>(DC)) { LookupQualifiedName(R, DC); @@ -933,6 +930,33 @@ bool Sema::DiagnoseEmptyLookup(const CXXScopeSpec &SS, } } + // We didn't find anything, so try to correct for a typo. + if (S && CorrectTypo(R, S, &SS) && + (isa<ValueDecl>(*R.begin()) || isa<TemplateDecl>(*R.begin()))) { + if (SS.isEmpty()) + Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + else + Diag(R.getNameLoc(), diag::err_no_member_suggest) + << Name << computeDeclContext(SS, false) << R.getLookupName() + << SS.getRange() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + + // Tell the callee to try to recover. + return false; + } + + // Emit a special diagnostic for failed member lookups. + // FIXME: computing the declaration context might fail here (?) + if (!SS.isEmpty()) { + Diag(R.getNameLoc(), diag::err_no_member) + << Name << computeDeclContext(SS, false) + << SS.getRange(); + return true; + } + // Give up, we can't recover. Diag(R.getNameLoc(), diagnostic) << Name; return true; @@ -1010,7 +1034,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. if (R.empty()) { - if (DiagnoseEmptyLookup(SS, R)) + if (DiagnoseEmptyLookup(S, SS, R)) return ExprError(); assert(!R.empty() && diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 72779c339d..9abbd575dc 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2134,11 +2134,14 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) { /// \param SS the nested-name-specifier that precedes the name we're /// looking for, if present. /// +/// \param EnteringContext whether we're entering the context described by +/// the nested-name-specifier SS. +/// /// \returns true if the typo was corrected, in which case the \p Res /// structure will contain the results of name lookup for the /// corrected name. Otherwise, returns false. bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, - bool AllowBuiltinCreation, bool EnteringContext) { + bool EnteringContext) { // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); if (!Typo) @@ -2190,6 +2193,12 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, // success if we found something that was not ambiguous. Res.clear(); Res.setLookupName(BestName); - LookupParsedName(Res, S, SS, AllowBuiltinCreation, EnteringContext); - return Res.getResultKind() != LookupResult::NotFound && !Res.isAmbiguous(); + LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, EnteringContext); + + if (Res.isAmbiguous()) { + Res.suppressDiagnostics(); + return false; + } + + return Res.getResultKind() != LookupResult::NotFound; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 99dbaba37b..5892081736 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4822,7 +4822,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); - if (SemaRef.DiagnoseEmptyLookup(SS, R)) + if (SemaRef.DiagnoseEmptyLookup(/*Scope=*/0, SS, R)) return Destroy(SemaRef, Fn, Args, NumArgs); assert(!R.empty() && "lookup results empty despite recovery"); |