r322661 - [Sema] Add visited contexts to CodeCompleteContext
Haojian Wu via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 17 06:29:25 PST 2018
Author: hokein
Date: Wed Jan 17 06:29:25 2018
New Revision: 322661
URL: http://llvm.org/viewvc/llvm-project?rev=322661&view=rev
Log:
[Sema] Add visited contexts to CodeCompleteContext
Summary:
This would allow code completion clients to know which context is visited during Sema code completion.
Also some changes:
* add `EnteredContext` callback in VisibleDeclConsumer.
* add a simple unittest for sema code completion (only for visited contexts at the moment).
Reviewers: ilya-biryukov
Reviewed By: ilya-biryukov
Subscribers: mgorny, bkramer, cfe-commits
Differential Revision: https://reviews.llvm.org/D42071
Added:
cfe/trunk/unittests/Sema/CodeCompleteTest.cpp
Modified:
cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
cfe/trunk/include/clang/Sema/Lookup.h
cfe/trunk/lib/Sema/SemaCodeComplete.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/unittests/Sema/CMakeLists.txt
Modified: cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h?rev=322661&r1=322660&r2=322661&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h (original)
+++ cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h Wed Jan 17 06:29:25 2018
@@ -268,6 +268,8 @@ public:
CCC_Recovery
};
+ using VisitedContextSet = llvm::SmallPtrSet<DeclContext*, 8>;
+
private:
enum Kind Kind;
@@ -285,6 +287,10 @@ private:
/// "a::b::"
llvm::Optional<CXXScopeSpec> ScopeSpecifier;
+ /// \brief A set of declaration contexts visited by Sema when doing lookup for
+ /// code completion.
+ VisitedContextSet VisitedContexts;
+
public:
/// \brief Construct a new code-completion context of the given kind.
CodeCompletionContext(enum Kind Kind) : Kind(Kind), SelIdents(None) { }
@@ -328,6 +334,16 @@ public:
this->ScopeSpecifier = std::move(SS);
}
+ /// \brief Adds a visited context.
+ void addVisitedContext(DeclContext* Ctx) {
+ VisitedContexts.insert(Ctx);
+ }
+
+ /// \brief Retrieves all visited contexts.
+ const VisitedContextSet &getVisitedContexts() const {
+ return VisitedContexts;
+ }
+
llvm::Optional<const CXXScopeSpec *> getCXXScopeSpecifier() {
if (ScopeSpecifier)
return ScopeSpecifier.getPointer();
Modified: cfe/trunk/include/clang/Sema/Lookup.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Lookup.h?rev=322661&r1=322660&r2=322661&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Lookup.h (original)
+++ cfe/trunk/include/clang/Sema/Lookup.h Wed Jan 17 06:29:25 2018
@@ -784,6 +784,12 @@ public:
/// class of the context we searched.
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
bool InBaseClass) = 0;
+
+ /// \brief Callback to inform the client that Sema entered into a new context
+ /// to find a visible declaration.
+ //
+ /// \param Ctx the context which Sema entered.
+ virtual void EnteredContext(DeclContext *Ctx) {}
};
/// \brief A class for storing results from argument-dependent lookup.
Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=322661&r1=322660&r2=322661&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Wed Jan 17 06:29:25 2018
@@ -318,6 +318,11 @@ namespace {
/// \brief Ignore this declaration, if it is seen again.
void Ignore(const Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); }
+ /// \brief Add a visited context.
+ void addVisitedContext(DeclContext *Ctx) {
+ CompletionContext.addVisitedContext(Ctx);
+ }
+
/// \name Name lookup predicates
///
/// These predicates can be passed to the name lookup functions to filter the
@@ -1280,7 +1285,7 @@ namespace {
class CodeCompletionDeclConsumer : public VisibleDeclConsumer {
ResultBuilder &Results;
DeclContext *CurContext;
-
+
public:
CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext)
: Results(Results), CurContext(CurContext) { }
@@ -1295,6 +1300,10 @@ namespace {
false, Accessible);
Results.AddResult(Result, CurContext, Hiding, InBaseClass);
}
+
+ void EnteredContext(DeclContext* Ctx) override {
+ Results.addVisitedContext(Ctx);
+ }
};
}
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=322661&r1=322660&r2=322661&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Jan 17 06:29:25 2018
@@ -3507,6 +3507,8 @@ static void LookupVisibleDecls(DeclConte
if (Visited.visitedContext(Ctx->getPrimaryContext()))
return;
+ Consumer.EnteredContext(Ctx);
+
// Outside C++, lookup results for the TU live on identifiers.
if (isa<TranslationUnitDecl>(Ctx) &&
!Result.getSema().getLangOpts().CPlusPlus) {
Modified: cfe/trunk/unittests/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Sema/CMakeLists.txt?rev=322661&r1=322660&r2=322661&view=diff
==============================================================================
--- cfe/trunk/unittests/Sema/CMakeLists.txt (original)
+++ cfe/trunk/unittests/Sema/CMakeLists.txt Wed Jan 17 06:29:25 2018
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(SemaTests
ExternalSemaSourceTest.cpp
+ CodeCompleteTest.cpp
)
target_link_libraries(SemaTests
Added: cfe/trunk/unittests/Sema/CodeCompleteTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Sema/CodeCompleteTest.cpp?rev=322661&view=auto
==============================================================================
--- cfe/trunk/unittests/Sema/CodeCompleteTest.cpp (added)
+++ cfe/trunk/unittests/Sema/CodeCompleteTest.cpp Wed Jan 17 06:29:25 2018
@@ -0,0 +1,134 @@
+//=== unittests/Sema/CodeCompleteTest.cpp - Code Complete tests ==============//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+namespace {
+
+using namespace clang;
+using namespace clang::tooling;
+using ::testing::UnorderedElementsAre;
+
+const char TestCCName[] = "test.cc";
+using VisitedContextResults = std::vector<std::string>;
+
+class VisitedContextFinder: public CodeCompleteConsumer {
+public:
+ VisitedContextFinder(VisitedContextResults &Results)
+ : CodeCompleteConsumer(/*CodeCompleteOpts=*/{},
+ /*CodeCompleteConsumer*/ false),
+ VCResults(Results),
+ CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
+
+ void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
+ CodeCompletionResult *Results,
+ unsigned NumResults) override {
+ VisitedContexts = Context.getVisitedContexts();
+ VCResults = getVisitedNamespace();
+ }
+
+ CodeCompletionAllocator &getAllocator() override {
+ return CCTUInfo.getAllocator();
+ }
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
+
+ std::vector<std::string> getVisitedNamespace() const {
+ std::vector<std::string> NSNames;
+ for (const auto *Context : VisitedContexts)
+ if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context))
+ NSNames.push_back(NS->getQualifiedNameAsString());
+ return NSNames;
+ }
+
+private:
+ VisitedContextResults& VCResults;
+ CodeCompletionTUInfo CCTUInfo;
+ CodeCompletionContext::VisitedContextSet VisitedContexts;
+};
+
+class CodeCompleteAction : public SyntaxOnlyAction {
+public:
+ CodeCompleteAction(ParsedSourceLocation P, VisitedContextResults &Results)
+ : CompletePosition(std::move(P)), VCResults(Results) {}
+
+ bool BeginInvocation(CompilerInstance &CI) override {
+ CI.getFrontendOpts().CodeCompletionAt = CompletePosition;
+ CI.setCodeCompletionConsumer(new VisitedContextFinder(VCResults));
+ return true;
+ }
+
+private:
+ // 1-based code complete position <Line, Col>;
+ ParsedSourceLocation CompletePosition;
+ VisitedContextResults& VCResults;
+};
+
+ParsedSourceLocation offsetToPosition(llvm::StringRef Code, size_t Offset) {
+ Offset = std::min(Code.size(), Offset);
+ StringRef Before = Code.substr(0, Offset);
+ int Lines = Before.count('\n');
+ size_t PrevNL = Before.rfind('\n');
+ size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
+ return {TestCCName, static_cast<unsigned>(Lines + 1),
+ static_cast<unsigned>(Offset - StartOfLine + 1)};
+}
+
+VisitedContextResults runCodeCompleteOnCode(StringRef Code) {
+ VisitedContextResults Results;
+ auto TokenOffset = Code.find('^');
+ assert(TokenOffset != StringRef::npos &&
+ "Completion token ^ wasn't found in Code.");
+ std::string WithoutToken = Code.take_front(TokenOffset);
+ WithoutToken += Code.drop_front(WithoutToken.size() + 1);
+ assert(StringRef(WithoutToken).find('^') == StringRef::npos &&
+ "expected exactly one completion token ^ inside the code");
+
+ auto Action = llvm::make_unique<CodeCompleteAction>(
+ offsetToPosition(WithoutToken, TokenOffset), Results);
+ clang::tooling::runToolOnCodeWithArgs(Action.release(), Code, {"-std=c++11"},
+ TestCCName);
+ return Results;
+}
+
+TEST(SemaCodeCompleteTest, VisitedNSForValidQualifiedId) {
+ auto VisitedNS = runCodeCompleteOnCode(R"cpp(
+ namespace ns1 {}
+ namespace ns2 {}
+ namespace ns3 {}
+ namespace ns3 { namespace nns3 {} }
+
+ namespace foo {
+ using namespace ns1;
+ namespace ns4 {} // not visited
+ namespace { using namespace ns2; }
+ inline namespace bar { using namespace ns3::nns3; }
+ } // foo
+ namespace ns { foo::^ }
+ )cpp");
+ EXPECT_THAT(VisitedNS, UnorderedElementsAre("foo", "ns1", "ns2", "ns3::nns3",
+ "foo::(anonymous)"));
+}
+
+TEST(SemaCodeCompleteTest, VisitedNSForInvalideQualifiedId) {
+ auto VisitedNS = runCodeCompleteOnCode(R"cpp(
+ namespace ns { foo::^ }
+ )cpp");
+ EXPECT_TRUE(VisitedNS.empty());
+}
+
+} // namespace
More information about the cfe-commits
mailing list