61 lines · cpp
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 10using namespace llvm;11using namespace clang;12using namespace clang::tooling;13 14namespace {15 16class 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 nullptr36 // CppLookupName will perform an early return with no results if the Scope37 // 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 in41 // 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 49TEST(SemaLookupTest, ForceNoCPlusPlusPath) {50 const char *file_contents = R"objcxx(51@protocol Foo52@end53@interface Foo <Foo>54@end55 )objcxx";56 ASSERT_TRUE(runToolOnCodeWithArgs(std::make_unique<LookupAction>(),57 file_contents, {"-x", "objective-c++"},58 "test.mm"));59}60} // namespace61