diff options
Diffstat (limited to 'lib/Sema/SemaExprMember.cpp')
-rw-r--r-- | lib/Sema/SemaExprMember.cpp | 132 |
1 files changed, 76 insertions, 56 deletions
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index ef78982..af1cf90 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -10,7 +10,7 @@ // This file implements semantic analysis member access expressions. // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Overload.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -21,6 +21,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" using namespace clang; using namespace sema; @@ -89,7 +90,6 @@ enum IMAKind { /// conservatively answer "yes", in which case some errors will simply /// not be caught until template-instantiation. static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, - Scope *CurScope, const LookupResult &R) { assert(!R.empty() && (*R.begin())->isCXXClassMember()); @@ -204,6 +204,9 @@ static void diagnoseInstanceReference(Sema &SemaRef, SourceRange Range(Loc); if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); + // Look through using shadow decls and aliases. + Rep = Rep->getUnderlyingDecl(); + DeclContext *FunctionLevelDC = SemaRef.getFunctionLevelDeclContext(); CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FunctionLevelDC); CXXRecordDecl *ContextClass = Method ? Method->getParent() : nullptr; @@ -236,7 +239,7 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { - switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) { + switch (ClassifyImplicitMemberAccess(*this, R)) { case IMA_Instance: return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true); @@ -536,9 +539,17 @@ namespace { // FunctionTemplateDecl and are declared in the current record or, for a C++ // classes, one of its base classes. class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback { - public: +public: explicit RecordMemberExprValidatorCCC(const RecordType *RTy) - : Record(RTy->getDecl()) {} + : Record(RTy->getDecl()) { + // Don't add bare keywords to the consumer since they will always fail + // validation by virtue of not being associated with any decls. + WantTypeSpecifiers = false; + WantExpressionKeywords = false; + WantCXXNamedCasts = false; + WantFunctionLikeCasts = false; + WantRemainingKeywords = false; + } bool ValidateCandidate(const TypoCorrection &candidate) override { NamedDecl *ND = candidate.getCorrectionDecl(); @@ -554,8 +565,8 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record)) { // Accept candidates that occur in any of the current class' base classes. for (const auto &BS : RD->bases()) { - if (const RecordType *BSTy = dyn_cast_or_null<RecordType>( - BS.getType().getTypePtrOrNull())) { + if (const RecordType *BSTy = + dyn_cast_or_null<RecordType>(BS.getType().getTypePtrOrNull())) { if (BSTy->getDecl()->containsDecl(ND)) return true; } @@ -565,17 +576,19 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback { return false; } - private: +private: const RecordDecl *const Record; }; } -static bool -LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, - SourceRange BaseRange, const RecordType *RTy, - SourceLocation OpLoc, CXXScopeSpec &SS, - bool HasTemplateArgs) { +static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, + Expr *BaseExpr, + const RecordType *RTy, + SourceLocation OpLoc, bool IsArrow, + CXXScopeSpec &SS, bool HasTemplateArgs, + TypoExpr *&TE) { + SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange(); RecordDecl *RDecl = RTy->getDecl(); if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) && SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), @@ -600,7 +613,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, if (SemaRef.RequireCompleteDeclContext(SS, DC)) { SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) - << SS.getRange() << DC; + << SS.getRange() << DC; return true; } @@ -608,47 +621,48 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, if (!isa<TypeDecl>(DC)) { SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) - << DC << SS.getRange(); + << DC << SS.getRange(); return true; } } // The record definition is complete, now look up the member. - SemaRef.LookupQualifiedName(R, DC); + SemaRef.LookupQualifiedName(R, DC, SS); if (!R.empty()) return false; - // We didn't find anything with the given name, so try to correct - // for typos. - DeclarationName Name = R.getLookupName(); - RecordMemberExprValidatorCCC Validator(RTy); - TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(), - R.getLookupKind(), nullptr, - &SS, Validator, - Sema::CTK_ErrorRecovery, DC); - R.clear(); - if (Corrected.isResolved() && !Corrected.isKeyword()) { - R.setLookupName(Corrected.getCorrection()); - for (TypoCorrection::decl_iterator DI = Corrected.begin(), - DIEnd = Corrected.end(); - DI != DIEnd; ++DI) { - R.addDecl(*DI); - } - R.resolveKind(); - - // If we're typo-correcting to an overloaded name, we don't yet have enough - // information to do overload resolution, so we don't know which previous - // declaration to point to. - if (Corrected.isOverloaded()) - Corrected.setCorrectionDecl(nullptr); - bool DroppedSpecifier = - Corrected.WillReplaceSpecifier() && - Name.getAsString() == Corrected.getAsString(SemaRef.getLangOpts()); - SemaRef.diagnoseTypo(Corrected, - SemaRef.PDiag(diag::err_no_member_suggest) - << Name << DC << DroppedSpecifier << SS.getRange()); - } + DeclarationName Typo = R.getLookupName(); + SourceLocation TypoLoc = R.getNameLoc(); + TE = SemaRef.CorrectTypoDelayed( + R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS, + llvm::make_unique<RecordMemberExprValidatorCCC>(RTy), + [=, &SemaRef](const TypoCorrection &TC) { + if (TC) { + assert(!TC.isKeyword() && + "Got a keyword as a correction for a member!"); + bool DroppedSpecifier = + TC.WillReplaceSpecifier() && + Typo.getAsString() == TC.getAsString(SemaRef.getLangOpts()); + SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest) + << Typo << DC << DroppedSpecifier + << SS.getRange()); + } else { + SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << DC << BaseRange; + } + }, + [=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable { + R.clear(); // Ensure there's no decls lingering in the shared state. + R.suppressDiagnostics(); + R.setLookupName(TC.getCorrection()); + for (NamedDecl *ND : TC) + R.addDecl(ND); + R.resolveKind(); + return SemaRef.BuildMemberReferenceExpr( + BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(), + nullptr, R, nullptr); + }, + Sema::CTK_ErrorRecovery, DC); return false; } @@ -678,12 +692,15 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, // Implicit member accesses. if (!Base) { + TypoExpr *TE = nullptr; QualType RecordTy = BaseType; if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType(); - if (LookupMemberExprInRecord(*this, R, SourceRange(), - RecordTy->getAs<RecordType>(), - OpLoc, SS, TemplateArgs != nullptr)) + if (LookupMemberExprInRecord(*this, R, nullptr, + RecordTy->getAs<RecordType>(), OpLoc, IsArrow, + SS, TemplateArgs != nullptr, TE)) return ExprError(); + if (TE) + return TE; // Explicit member accesses. } else { @@ -1211,13 +1228,16 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, // Handle field access to simple records. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { - if (LookupMemberExprInRecord(S, R, BaseExpr.get()->getSourceRange(), - RTy, OpLoc, SS, HasTemplateArgs)) + TypoExpr *TE = nullptr; + if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, + OpLoc, IsArrow, SS, HasTemplateArgs, TE)) return ExprError(); // Returning valid-but-null is how we indicate to the caller that - // the lookup result was filled in. - return ExprResult((Expr *)nullptr); + // the lookup result was filled in. If typo correction was attempted and + // failed, the lookup result will have been cleared--that combined with the + // valid-but-null ExprResult will trigger the appropriate diagnostics. + return ExprResult(TE); } // Handle ivar access to Objective-C objects. @@ -1262,11 +1282,11 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (!IV) { // Attempt to correct for typos in ivar names. - DeclFilterCCC<ObjCIvarDecl> Validator; - Validator.IsObjCIvarLookup = IsArrow; + auto Validator = llvm::make_unique<DeclFilterCCC<ObjCIvarDecl>>(); + Validator->IsObjCIvarLookup = IsArrow; if (TypoCorrection Corrected = S.CorrectTypo( R.getLookupNameInfo(), Sema::LookupMemberName, nullptr, nullptr, - Validator, Sema::CTK_ErrorRecovery, IDecl)) { + std::move(Validator), Sema::CTK_ErrorRecovery, IDecl)) { IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>(); S.diagnoseTypo( Corrected, |