Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -1313,6 +1313,9 @@ R.setShadowed(); continue; } + } else if (NameKind == LookupObjCImplicitSelfParam && + !isa(*I)) { + continue; } else { // We found something in this scope, we should not look at the // namespace scope Index: clang/unittests/Sema/SemaLookupTest.cpp =================================================================== --- clang/unittests/Sema/SemaLookupTest.cpp +++ clang/unittests/Sema/SemaLookupTest.cpp @@ -1,4 +1,6 @@ #include "clang/AST/DeclarationName.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Parse/ParseAST.h" @@ -10,6 +12,7 @@ using namespace llvm; using namespace clang; using namespace clang::tooling; +using namespace clang::ast_matchers; namespace { @@ -57,4 +60,84 @@ file_contents, {"-x", "objective-c++"}, "test.mm")); } + +using ExprMatcher = internal::Matcher; +using StmtMatcher = internal::Matcher; + +AST_MATCHER(ObjCIvarRefExpr, isFreeIvar) { + return Node.isFreeIvar(); +} + +ExprMatcher objcIvarRefTo(StringRef Name) { + return declRefExpr(hasAncestor(objcIvarRefExpr(allOf(isFreeIvar(), + hasDeclaration(namedDecl( + hasName(Name))))) + .bind("ivarref"))) + .bind("selfref"); +} + +StmtMatcher withEnclosingMethod(ExprMatcher Matcher) { + return expr(Matcher, + hasAncestor(objcMethodDecl(isDefinition()).bind("method"))) + .bind("expr"); +} + +class IvarLookupImplicitSelf : public ASTFrontendAction { + std::unique_ptr + CreateASTConsumer(CompilerInstance &CI, StringRef /* Unused */) override { + return std::make_unique(); + } + + void ExecuteAction() override { + CompilerInstance &CI = getCompilerInstance(); + ASSERT_FALSE(CI.hasSema()); + CI.createSema(getTranslationUnitKind(), nullptr); + ASSERT_TRUE(CI.hasSema()); + Sema &S = CI.getSema(); + ParseAST(S); + + ASTContext &Ctx = S.getASTContext(); + const auto Results = + match(withEnclosingMethod(objcIvarRefTo("_ivar")), Ctx); + const auto *MD = selectFirst("method", Results); + const auto *SelfRef = selectFirst("selfref", Results); + ASSERT_TRUE(MD && SelfRef); + + // When name lookup is occurring correctly, the SelfRef should refer to the + // Method's ImplicitParamDecl of 'self'. + const auto *SelfDecl = SelfRef->getDecl(); + EXPECT_TRUE(isa(SelfDecl) && + MD->getSelfDecl() == SelfDecl); + } +}; + +constexpr StringRef ImplicitIvarFileContents = R"objcxx( +__attribute__((objc_root_class)) +@interface Foo +@end +extern Foo *CreateFoo(); +@implementation Foo { + int _ivar; +} +- (void)foo { + { + Foo *self = CreateFoo(); + _ivar = 42; + } +} +@end + )objcxx"; + +TEST(SemaLookupTest, ImplicitIvarSelfRefLookupObjCpp) { + ASSERT_TRUE(runToolOnCodeWithArgs(std::make_unique(), + ImplicitIvarFileContents, + {"-x", "objective-c++"}, "test.mm")); +} + +TEST(SemaLookupTest, ImplicitIvarSelfRefLookupObjC) { + ASSERT_TRUE(runToolOnCodeWithArgs(std::make_unique(), + ImplicitIvarFileContents, + {"-x", "objective-c"}, "test.m")); +} + } // namespace