Skip to content

Commit 47d7f52

Browse files
committedJul 11, 2018
[clangd] Uprank delcarations when "using q::name" is present in the main file
Having `using qualified::name;` for some symbol is an important signal for clangd code completion as the user is more likely to use such symbol. This patch helps to uprank the relevant symbols by saving UsingShadowDecl in the new field of CodeCompletionResult and checking whether the corresponding UsingShadowDecl is located in the main file later in ClangD code completion routine. While the relative importance of such signal is a subject to change in the future, this patch simply bumps DeclProximity score to the value of 1.0 which should be enough for now. The patch was tested using `$ ninja check-clang check-clang-tools` No unexpected failures were noticed after running the relevant testsets. Reviewers: sammccall, ioeric Subscribers: MaskRay, jkorous, cfe-commits Differential Revision: https://reviews.llvm.org/D49012 llvm-svn: 336810
1 parent 09832e3 commit 47d7f52

File tree

4 files changed

+89
-28
lines changed

4 files changed

+89
-28
lines changed
 

Diff for: ‎clang-tools-extra/clangd/Quality.cpp

+15-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ static bool hasDeclInMainFile(const Decl &D) {
4141
return false;
4242
}
4343

44+
static bool hasUsingDeclInMainFile(const CodeCompletionResult &R) {
45+
const auto &Context = R.Declaration->getASTContext();
46+
const auto &SourceMgr = Context.getSourceManager();
47+
if (R.ShadowDecl) {
48+
const auto Loc = SourceMgr.getExpansionLoc(R.ShadowDecl->getLocation());
49+
if (SourceMgr.isWrittenInMainFile(Loc))
50+
return true;
51+
}
52+
return false;
53+
}
54+
4455
static SymbolQualitySignals::SymbolCategory categorize(const NamedDecl &ND) {
4556
class Switch
4657
: public ConstDeclVisitor<Switch, SymbolQualitySignals::SymbolCategory> {
@@ -231,8 +242,10 @@ void SymbolRelevanceSignals::merge(const CodeCompletionResult &SemaCCResult) {
231242
// We boost things that have decls in the main file. We give a fixed score
232243
// for all other declarations in sema as they are already included in the
233244
// translation unit.
234-
float DeclProximity =
235-
hasDeclInMainFile(*SemaCCResult.Declaration) ? 1.0 : 0.6;
245+
float DeclProximity = (hasDeclInMainFile(*SemaCCResult.Declaration) ||
246+
hasUsingDeclInMainFile(SemaCCResult))
247+
? 1.0
248+
: 0.6;
236249
SemaProximityScore = std::max(DeclProximity, SemaProximityScore);
237250
}
238251

Diff for: ‎clang-tools-extra/unittests/clangd/QualityTests.cpp

+50-10
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,31 @@ TEST(QualityTests, SymbolQualitySignalExtraction) {
7777
TEST(QualityTests, SymbolRelevanceSignalExtraction) {
7878
TestTU Test;
7979
Test.HeaderCode = R"cpp(
80-
int header();
81-
int header_main();
82-
)cpp";
80+
int header();
81+
int header_main();
82+
83+
namespace hdr { class Bar {}; } // namespace hdr
84+
85+
#define DEFINE_FLAG(X) \
86+
namespace flags { \
87+
int FLAGS_##X; \
88+
} \
89+
90+
DEFINE_FLAG(FOO)
91+
)cpp";
8392
Test.Code = R"cpp(
84-
int ::header_main() {}
85-
int main();
93+
using hdr::Bar;
8694
87-
[[deprecated]]
88-
int deprecated() { return 0; }
95+
using flags::FLAGS_FOO;
96+
97+
int ::header_main() {}
98+
int main();
8999
90-
namespace { struct X { void y() { int z; } }; }
91-
struct S{}
100+
[[deprecated]]
101+
int deprecated() { return 0; }
102+
103+
namespace { struct X { void y() { int z; } }; }
104+
struct S{}
92105
)cpp";
93106
auto AST = Test.build();
94107

@@ -111,6 +124,32 @@ TEST(QualityTests, SymbolRelevanceSignalExtraction) {
111124
EXPECT_FLOAT_EQ(Relevance.SemaProximityScore, 1.0f)
112125
<< "Current file and header";
113126

127+
auto constructShadowDeclCompletionResult = [&](const std::string DeclName) {
128+
auto *Shadow =
129+
*dyn_cast<UsingDecl>(
130+
&findAnyDecl(AST,
131+
[&](const NamedDecl &ND) {
132+
if (const UsingDecl *Using =
133+
dyn_cast<UsingDecl>(&ND))
134+
if (Using->shadow_size() &&
135+
Using->getQualifiedNameAsString() == DeclName)
136+
return true;
137+
return false;
138+
}))
139+
->shadow_begin();
140+
CodeCompletionResult Result(Shadow->getTargetDecl(), 42);
141+
Result.ShadowDecl = Shadow;
142+
return Result;
143+
};
144+
145+
Relevance = {};
146+
Relevance.merge(constructShadowDeclCompletionResult("Bar"));
147+
EXPECT_FLOAT_EQ(Relevance.SemaProximityScore, 1.0f)
148+
<< "Using declaration in main file";
149+
Relevance.merge(constructShadowDeclCompletionResult("FLAGS_FOO"));
150+
EXPECT_FLOAT_EQ(Relevance.SemaProximityScore, 1.0f)
151+
<< "Using declaration in main file";
152+
114153
Relevance = {};
115154
Relevance.merge(CodeCompletionResult(&findAnyDecl(AST, "X"), 42));
116155
EXPECT_EQ(Relevance.Scope, SymbolRelevanceSignals::FileScope);
@@ -191,7 +230,8 @@ TEST(QualityTests, SymbolRelevanceSignalsSanity) {
191230
}
192231

193232
TEST(QualityTests, SortText) {
194-
EXPECT_LT(sortText(std::numeric_limits<float>::infinity()), sortText(1000.2f));
233+
EXPECT_LT(sortText(std::numeric_limits<float>::infinity()),
234+
sortText(1000.2f));
195235
EXPECT_LT(sortText(1000.2f), sortText(1));
196236
EXPECT_LT(sortText(1), sortText(0.3f));
197237
EXPECT_LT(sortText(0.3f), sortText(0));

Diff for: ‎clang/include/clang/Sema/CodeCompleteConsumer.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ class LangOptions;
4545
class NamedDecl;
4646
class NestedNameSpecifier;
4747
class Preprocessor;
48-
class Sema;
4948
class RawComment;
49+
class Sema;
50+
class UsingShadowDecl;
5051

5152
/// Default priority values for code-completion results based
5253
/// on their kind.
@@ -836,6 +837,12 @@ class CodeCompletionResult {
836837
/// informative rather than required.
837838
NestedNameSpecifier *Qualifier = nullptr;
838839

840+
/// If this Decl was unshadowed by using declaration, this can store a
841+
/// pointer to the UsingShadowDecl which was used in the unshadowing process.
842+
/// This information can be used to uprank CodeCompletionResults / which have
843+
/// corresponding `using decl::qualified::name;` nearby.
844+
const UsingShadowDecl *ShadowDecl = nullptr;
845+
839846
/// Build a result that refers to a declaration.
840847
CodeCompletionResult(const NamedDecl *Declaration, unsigned Priority,
841848
NestedNameSpecifier *Qualifier = nullptr,
@@ -847,7 +854,7 @@ class CodeCompletionResult {
847854
QualifierIsInformative(QualifierIsInformative),
848855
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
849856
DeclaringEntity(false), Qualifier(Qualifier) {
850-
//FIXME: Add assert to check FixIts range requirements.
857+
// FIXME: Add assert to check FixIts range requirements.
851858
computeCursorKindAndAvailability(Accessible);
852859
}
853860

Diff for: ‎clang/lib/Sema/SemaCodeComplete.cpp

+15-14
Original file line numberDiff line numberDiff line change
@@ -859,12 +859,12 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
859859
}
860860

861861
// Look through using declarations.
862-
if (const UsingShadowDecl *Using =
863-
dyn_cast<UsingShadowDecl>(R.Declaration)) {
864-
MaybeAddResult(Result(Using->getTargetDecl(),
865-
getBasePriority(Using->getTargetDecl()),
866-
R.Qualifier),
867-
CurContext);
862+
if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
863+
CodeCompletionResult Result(Using->getTargetDecl(),
864+
getBasePriority(Using->getTargetDecl()),
865+
R.Qualifier);
866+
Result.ShadowDecl = Using;
867+
MaybeAddResult(Result, CurContext);
868868
return;
869869
}
870870

@@ -977,10 +977,11 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
977977

978978
// Look through using declarations.
979979
if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
980-
AddResult(Result(Using->getTargetDecl(),
981-
getBasePriority(Using->getTargetDecl()),
982-
R.Qualifier),
983-
CurContext, Hiding);
980+
CodeCompletionResult Result(Using->getTargetDecl(),
981+
getBasePriority(Using->getTargetDecl()),
982+
R.Qualifier);
983+
Result.ShadowDecl = Using;
984+
AddResult(Result, CurContext, Hiding);
984985
return;
985986
}
986987

@@ -1004,10 +1005,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
10041005
if (AsNestedNameSpecifier) {
10051006
R.StartsNestedNameSpecifier = true;
10061007
R.Priority = CCP_NestedNameSpecifier;
1007-
}
1008-
else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass &&
1009-
isa<CXXRecordDecl>(R.Declaration->getDeclContext()
1010-
->getRedeclContext()))
1008+
} else if (Filter == &ResultBuilder::IsMember && !R.Qualifier &&
1009+
InBaseClass &&
1010+
isa<CXXRecordDecl>(
1011+
R.Declaration->getDeclContext()->getRedeclContext()))
10111012
R.QualifierIsInformative = true;
10121013

10131014
// If this result is supposed to have an informative qualifier, add one.

0 commit comments

Comments
 (0)
Please sign in to comment.