1 #include "clang/AST/DeclarationName.h" 2 #include "clang/Frontend/CompilerInstance.h" 3 #include "clang/Frontend/FrontendAction.h" 4 #include "clang/Parse/ParseAST.h" 5 #include "clang/Sema/Lookup.h" 6 #include "clang/Sema/Sema.h" 7 #include "clang/Tooling/Tooling.h" 8 #include "gtest/gtest.h" 9 10 using namespace llvm; 11 using namespace clang; 12 using namespace clang::tooling; 13 14 namespace { 15 16 class LookupAction : public ASTFrontendAction { 17 std::unique_ptr<ASTConsumer> 18 CreateASTConsumer(CompilerInstance &CI, StringRef /*Unused*/) override { 19 return std::make_unique<clang::ASTConsumer>(); 20 } 21 22 void ExecuteAction() override { 23 CompilerInstance &CI = getCompilerInstance(); 24 ASSERT_FALSE(CI.hasSema()); 25 CI.createSema(getTranslationUnitKind(), nullptr); 26 ASSERT_TRUE(CI.hasSema()); 27 Sema &S = CI.getSema(); 28 ParseAST(S); 29 30 ASTContext &Ctx = S.getASTContext(); 31 auto Name = &Ctx.Idents.get("Foo"); 32 LookupResult R_cpp(S, Name, SourceLocation(), Sema::LookupOrdinaryName); 33 S.LookupName(R_cpp, S.TUScope, /*AllowBuiltinCreation=*/false, 34 /*ForceNoCPlusPlus=*/false); 35 // By this point, parsing is done and S.TUScope is nullptr 36 // CppLookupName will perform an early return with no results if the Scope 37 // we pass in is nullptr. We expect to find nothing. 38 ASSERT_TRUE(R_cpp.empty()); 39 40 // On the other hand, the non-C++ path doesn't care if the Scope passed in 41 // is nullptr. We'll force the non-C++ path with a flag. 42 LookupResult R_nocpp(S, Name, SourceLocation(), Sema::LookupOrdinaryName); 43 S.LookupName(R_nocpp, S.TUScope, /*AllowBuiltinCreation=*/false, 44 /*ForceNoCPlusPlus=*/true); 45 ASSERT_TRUE(!R_nocpp.empty()); 46 } 47 }; 48 49 TEST(SemaLookupTest, ForceNoCPlusPlusPath) { 50 const char *file_contents = R"objcxx( 51 @protocol Foo 52 @end 53 @interface Foo <Foo> 54 @end 55 )objcxx"; 56 ASSERT_TRUE(runToolOnCodeWithArgs(std::make_unique<LookupAction>(), 57 file_contents, {"-x", "objective-c++"}, 58 "test.mm")); 59 } 60 } // namespace 61