CodeCompleteTest.cpp 4.5 KB

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