blob: 8e888cbe528a1c43f0a88a3fd38d05e26423c86e [file] [log] [blame]
Haojian Wu10d95c52018-01-17 14:29:25 +00001//=== unittests/Sema/CodeCompleteTest.cpp - Code Complete tests ==============//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/Frontend/CompilerInstance.h"
11#include "clang/Frontend/FrontendActions.h"
12#include "clang/Lex/Preprocessor.h"
13#include "clang/Parse/ParseAST.h"
14#include "clang/Sema/Sema.h"
15#include "clang/Sema/SemaDiagnostic.h"
16#include "clang/Tooling/Tooling.h"
17#include "gtest/gtest.h"
18#include "gmock/gmock.h"
19
20namespace {
21
22using namespace clang;
23using namespace clang::tooling;
24using ::testing::UnorderedElementsAre;
25
26const char TestCCName[] = "test.cc";
27using VisitedContextResults = std::vector<std::string>;
28
29class VisitedContextFinder: public CodeCompleteConsumer {
30public:
31 VisitedContextFinder(VisitedContextResults &Results)
32 : CodeCompleteConsumer(/*CodeCompleteOpts=*/{},
33 /*CodeCompleteConsumer*/ false),
34 VCResults(Results),
35 CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
36
37 void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
38 CodeCompletionResult *Results,
39 unsigned NumResults) override {
40 VisitedContexts = Context.getVisitedContexts();
41 VCResults = getVisitedNamespace();
42 }
43
44 CodeCompletionAllocator &getAllocator() override {
45 return CCTUInfo.getAllocator();
46 }
47
48 CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
49
50 std::vector<std::string> getVisitedNamespace() const {
51 std::vector<std::string> NSNames;
52 for (const auto *Context : VisitedContexts)
53 if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context))
54 NSNames.push_back(NS->getQualifiedNameAsString());
55 return NSNames;
56 }
57
58private:
59 VisitedContextResults& VCResults;
60 CodeCompletionTUInfo CCTUInfo;
61 CodeCompletionContext::VisitedContextSet VisitedContexts;
62};
63
64class CodeCompleteAction : public SyntaxOnlyAction {
65public:
66 CodeCompleteAction(ParsedSourceLocation P, VisitedContextResults &Results)
67 : CompletePosition(std::move(P)), VCResults(Results) {}
68
69 bool BeginInvocation(CompilerInstance &CI) override {
70 CI.getFrontendOpts().CodeCompletionAt = CompletePosition;
71 CI.setCodeCompletionConsumer(new VisitedContextFinder(VCResults));
72 return true;
73 }
74
75private:
76 // 1-based code complete position <Line, Col>;
77 ParsedSourceLocation CompletePosition;
78 VisitedContextResults& VCResults;
79};
80
81ParsedSourceLocation offsetToPosition(llvm::StringRef Code, size_t Offset) {
82 Offset = std::min(Code.size(), Offset);
83 StringRef Before = Code.substr(0, Offset);
84 int Lines = Before.count('\n');
85 size_t PrevNL = Before.rfind('\n');
86 size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
87 return {TestCCName, static_cast<unsigned>(Lines + 1),
88 static_cast<unsigned>(Offset - StartOfLine + 1)};
89}
90
91VisitedContextResults runCodeCompleteOnCode(StringRef Code) {
92 VisitedContextResults Results;
93 auto TokenOffset = Code.find('^');
94 assert(TokenOffset != StringRef::npos &&
95 "Completion token ^ wasn't found in Code.");
96 std::string WithoutToken = Code.take_front(TokenOffset);
97 WithoutToken += Code.drop_front(WithoutToken.size() + 1);
98 assert(StringRef(WithoutToken).find('^') == StringRef::npos &&
99 "expected exactly one completion token ^ inside the code");
100
101 auto Action = llvm::make_unique<CodeCompleteAction>(
102 offsetToPosition(WithoutToken, TokenOffset), Results);
Roman Lebedev497fd982018-02-27 15:54:55 +0000103 clang::tooling::runToolOnCodeWithArgs(Action.release(), Code, {"-std=c++11"},
Haojian Wu10d95c52018-01-17 14:29:25 +0000104 TestCCName);
105 return Results;
106}
107
108TEST(SemaCodeCompleteTest, VisitedNSForValidQualifiedId) {
109 auto VisitedNS = runCodeCompleteOnCode(R"cpp(
110 namespace ns1 {}
111 namespace ns2 {}
112 namespace ns3 {}
113 namespace ns3 { namespace nns3 {} }
114
115 namespace foo {
116 using namespace ns1;
117 namespace ns4 {} // not visited
118 namespace { using namespace ns2; }
119 inline namespace bar { using namespace ns3::nns3; }
120 } // foo
121 namespace ns { foo::^ }
122 )cpp");
123 EXPECT_THAT(VisitedNS, UnorderedElementsAre("foo", "ns1", "ns2", "ns3::nns3",
124 "foo::(anonymous)"));
125}
126
127TEST(SemaCodeCompleteTest, VisitedNSForInvalideQualifiedId) {
128 auto VisitedNS = runCodeCompleteOnCode(R"cpp(
129 namespace ns { foo::^ }
130 )cpp");
131 EXPECT_TRUE(VisitedNS.empty());
132}
133
134} // namespace