[Code completion] Add code completion support for macro expansions.

This commit is contained in:
Doug Gregor
2022-11-26 23:34:20 -08:00
parent a9ee5dd142
commit af6b30a195
9 changed files with 167 additions and 25 deletions

View File

@@ -118,6 +118,7 @@ struct RequestedCachedModule {
const ModuleDecl *TheModule;
bool OnlyTypes;
bool OnlyPrecedenceGroups;
bool OnlyMacros;
};
} // end namespace ide

View File

@@ -43,6 +43,9 @@ bool DefaultFilter(ValueDecl *VD, DeclVisibilityKind Kind,
bool KeyPathFilter(ValueDecl *decl, DeclVisibilityKind,
DynamicLookupInfo dynamicLookupInfo);
bool MacroFilter(ValueDecl *decl, DeclVisibilityKind,
DynamicLookupInfo dynamicLookupInfo);
/// Returns \c true only if the completion is happening for top-level
/// declrarations. i.e.:
///
@@ -134,6 +137,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
bool IsUnwrappedOptional = false;
SourceLoc DotLoc;
bool NeedLeadingDot = false;
bool NeedLeadingMacroPound = false;
bool NeedOptionalUnwrap = false;
unsigned NumBytesToEraseForOptionalUnwrap = 0;
@@ -184,41 +188,50 @@ public:
const ModuleDecl *TheModule;
bool OnlyTypes;
bool OnlyPrecedenceGroups;
bool OnlyMacros;
bool NeedLeadingDot;
bool NeedPound;
bool IncludeModuleQualifier;
static RequestedResultsTy fromModule(const ModuleDecl *TheModule) {
return {TheModule, false, false, false, true};
return {TheModule, false, false, false, false, false, true};
}
RequestedResultsTy onlyTypes() const {
return {TheModule, true, false, NeedLeadingDot, IncludeModuleQualifier};
return {TheModule, true, false, false, NeedLeadingDot, false,
IncludeModuleQualifier};
}
RequestedResultsTy onlyPrecedenceGroups() const {
assert(!OnlyTypes && "onlyTypes() already includes precedence groups");
return {TheModule, false, true, false, true};
return {TheModule, false, true, false, false, false, true};
}
RequestedResultsTy onlyMacros(bool needPound) const {
return {TheModule, false, false, true, false, needPound, false};
}
RequestedResultsTy needLeadingDot(bool NeedDot) const {
return {TheModule, OnlyTypes, OnlyPrecedenceGroups, NeedDot,
IncludeModuleQualifier};
return {TheModule, OnlyTypes, OnlyPrecedenceGroups, OnlyMacros, NeedDot,
NeedPound, IncludeModuleQualifier};
}
RequestedResultsTy withModuleQualifier(bool IncludeModule) const {
return {TheModule, OnlyTypes, OnlyPrecedenceGroups, NeedLeadingDot,
IncludeModule};
return {TheModule, OnlyTypes, OnlyPrecedenceGroups, OnlyMacros,
NeedLeadingDot, NeedPound, IncludeModule};
}
static RequestedResultsTy toplevelResults() {
return {nullptr, false, false, false, true};
return {nullptr, false, false, false, false, true, true};
}
friend bool operator==(const RequestedResultsTy &LHS,
const RequestedResultsTy &RHS) {
return LHS.TheModule == RHS.TheModule && LHS.OnlyTypes == RHS.OnlyTypes &&
LHS.OnlyPrecedenceGroups == RHS.OnlyPrecedenceGroups &&
LHS.OnlyMacros == RHS.OnlyMacros &&
LHS.NeedLeadingDot == RHS.NeedLeadingDot &&
LHS.NeedPound == RHS.NeedPound &&
LHS.IncludeModuleQualifier == RHS.IncludeModuleQualifier;
}
};
@@ -450,6 +463,7 @@ public:
void addEnumElementRef(const EnumElementDecl *EED, DeclVisibilityKind Reason,
DynamicLookupInfo dynamicLookupInfo,
bool HasTypeContext);
void addMacroExpansion(const MacroDecl *MD, DeclVisibilityKind Reason);
void addKeyword(
StringRef Name, Type TypeAnnotation = Type(),
@@ -551,6 +565,8 @@ public:
void addObjCPoundKeywordCompletions(bool needPound);
void getMacroCompletions(bool needPound);
struct FilteredDeclConsumer : public swift::VisibleDeclConsumer {
swift::VisibleDeclConsumer &Consumer;
DeclFilter Filter;
@@ -612,7 +628,7 @@ public:
void getTypeCompletionsInDeclContext(SourceLoc Loc,
bool ModuleQualifier = true);
void getToplevelCompletions(bool OnlyTypes);
void getToplevelCompletions(bool OnlyTypes, bool OnlyMacros);
void lookupExternalModuleDecls(const ModuleDecl *TheModule,
ArrayRef<std::string> AccessPath,
@@ -632,17 +648,17 @@ template <>
struct DenseMapInfo<RequestedResultsTy> {
static inline RequestedResultsTy getEmptyKey() {
return {DenseMapInfo<swift::ModuleDecl *>::getEmptyKey(), false, false,
false, false};
false, false, false, false};
}
static inline RequestedResultsTy getTombstoneKey() {
return {DenseMapInfo<swift::ModuleDecl *>::getTombstoneKey(), false, false,
false, false};
false, false, false, false};
}
static unsigned getHashValue(const RequestedResultsTy &Val) {
return hash_combine(
DenseMapInfo<swift::ModuleDecl *>::getHashValue(Val.TheModule),
Val.OnlyTypes, Val.OnlyPrecedenceGroups, Val.NeedLeadingDot,
Val.IncludeModuleQualifier);
Val.OnlyTypes, Val.OnlyPrecedenceGroups, Val.OnlyMacros,
Val.NeedLeadingDot, Val.NeedPound, Val.IncludeModuleQualifier);
}
static bool isEqual(const RequestedResultsTy &LHS,
const RequestedResultsTy &RHS) {

View File

@@ -53,6 +53,7 @@ void AfterPoundExprCompletion::deliverResults(
Lookup.addPoundAvailable(ParentStmtKind);
Lookup.addPoundLiteralCompletions(/*needPound=*/false);
Lookup.addObjCPoundKeywordCompletions(/*needPound=*/false);
Lookup.getMacroCompletions(/*needPound=*/false);
}
deliverCompletionResults(CompletionCtx, Lookup, DC, Consumer);

View File

@@ -1332,7 +1332,7 @@ void swift::ide::deliverCompletionResults(
if (!Result.second)
return; // already handled.
RequestedModules.push_back({std::move(K), TheModule,
Request.OnlyTypes, Request.OnlyPrecedenceGroups});
Request.OnlyTypes, Request.OnlyPrecedenceGroups, Request.OnlyMacros});
auto TheModuleName = TheModule->getName();
if (Request.IncludeModuleQualifier &&
@@ -1350,7 +1350,7 @@ void swift::ide::deliverCompletionResults(
}
} else {
// Add results from current module.
Lookup.getToplevelCompletions(Request.OnlyTypes);
Lookup.getToplevelCompletions(Request.OnlyTypes, Request.OnlyMacros);
// Add the qualifying module name
auto curModule = SF.getParentModule();

View File

@@ -18,7 +18,7 @@ using namespace swift::ide;
static MutableArrayRef<CodeCompletionResult *> copyCodeCompletionResults(
CodeCompletionResultSink &targetSink, CodeCompletionCache::Value &source,
bool onlyTypes, bool onlyPrecedenceGroups,
bool onlyTypes, bool onlyPrecedenceGroups, bool onlyMacros,
const ExpectedTypeContext *TypeContext, const DeclContext *DC,
bool CanCurrDeclContextHandleAsync) {
@@ -69,7 +69,12 @@ static MutableArrayRef<CodeCompletionResult *> copyCodeCompletionResults(
} else if (onlyPrecedenceGroups) {
shouldIncludeResult = [](const ContextFreeCodeCompletionResult *R) -> bool {
return R->getAssociatedDeclKind() ==
CodeCompletionDeclKind::PrecedenceGroup;
CodeCompletionDeclKind::PrecedenceGroup;
};
} else if (onlyMacros) {
shouldIncludeResult = [](const ContextFreeCodeCompletionResult *R) -> bool {
return R->getAssociatedDeclKind() ==
CodeCompletionDeclKind::Macro;
};
} else {
shouldIncludeResult = [](const ContextFreeCodeCompletionResult *R) -> bool {
@@ -148,7 +153,7 @@ void SimpleCachingCodeCompletionConsumer::handleResultsAndModules(
assert(V.has_value());
auto newItems = copyCodeCompletionResults(
context.getResultSink(), **V, R.OnlyTypes, R.OnlyPrecedenceGroups,
TypeContext, DC, CanCurrDeclContextHandleAsync);
R.OnlyMacros, TypeContext, DC, CanCurrDeclContextHandleAsync);
postProcessCompletionResults(newItems, context.CodeCompletionKind, DC,
&context.getResultSink());
}

View File

@@ -127,6 +127,11 @@ bool swift::ide::KeyPathFilter(ValueDecl *decl, DeclVisibilityKind,
(isa<VarDecl>(decl) && decl->getDeclContext()->isTypeContext());
}
bool swift::ide::MacroFilter(ValueDecl *decl, DeclVisibilityKind,
DynamicLookupInfo dynamicLookupInfo) {
return isa<MacroDecl>(decl);
}
bool swift::ide::isCodeCompletionAtTopLevel(const DeclContext *DC) {
if (DC->isModuleScopeContext())
return true;
@@ -1773,6 +1778,36 @@ void CompletionLookup::addEnumElementRef(const EnumElementDecl *EED,
Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific);
}
void CompletionLookup::addMacroExpansion(const MacroDecl *MD,
DeclVisibilityKind Reason) {
if (!MD->hasName() || !MD->isAccessibleFrom(CurrDeclContext) ||
MD->shouldHideFromEditor())
return;
CodeCompletionResultBuilder Builder(
Sink, CodeCompletionResultKind::Declaration,
getSemanticContext(MD, Reason, DynamicLookupInfo()));
Builder.setAssociatedDecl(MD);
if (NeedLeadingMacroPound) {
Builder.addTextChunk("#");
}
addValueBaseName(Builder, MD->getBaseIdentifier());
Type macroType = MD->getInterfaceType();
if (MD->parameterList && macroType->is<FunctionType>()) {
Builder.addLeftParen();
addCallArgumentPatterns(Builder, macroType->castTo<FunctionType>(),
MD->parameterList,
MD->getGenericSignature());
Builder.addRightParen();
}
addTypeAnnotation(
Builder, MD->getResultInterfaceType(), MD->getGenericSignature());
}
void CompletionLookup::addKeyword(StringRef Name, Type TypeAnnotation,
SemanticContextKind SK,
CodeCompletionKeywordKind KeyKind,
@@ -2056,6 +2091,11 @@ void CompletionLookup::foundDecl(ValueDecl *D, DeclVisibilityKind Reason,
addSubscriptCall(SD, Reason, dynamicLookupInfo);
return;
}
if (auto *MD = dyn_cast<MacroDecl>(D)) {
addMacroExpansion(MD, Reason);
return;
}
return;
case LookupKind::EnumElement:
@@ -2724,6 +2764,11 @@ void CompletionLookup::addObjCPoundKeywordCompletions(bool needPound) {
}
}
void CompletionLookup::getMacroCompletions(bool needPound) {
RequestedCachedResults.insert(
RequestedResultsTy::toplevelResults().onlyMacros(needPound));
}
void CompletionLookup::getValueCompletionsInDeclContext(SourceLoc Loc,
DeclFilter Filter,
bool LiteralCompletions,
@@ -3137,18 +3182,21 @@ void CompletionLookup::getTypeCompletionsInDeclContext(SourceLoc Loc,
ModuleQualifier));
}
void CompletionLookup::getToplevelCompletions(bool OnlyTypes) {
void CompletionLookup::getToplevelCompletions(bool OnlyTypes, bool OnlyMacros) {
Kind = OnlyTypes ? LookupKind::TypeInDeclContext
: LookupKind::ValueInDeclContext;
NeedLeadingDot = false;
NeedLeadingMacroPound = !OnlyMacros;
UsableFilteringDeclConsumer UsableFilteringConsumer(
Ctx.SourceMgr, CurrDeclContext, Ctx.SourceMgr.getCodeCompletionLoc(),
*this);
AccessFilteringDeclConsumer AccessFilteringConsumer(CurrDeclContext,
UsableFilteringConsumer);
DeclFilter Filter = OnlyMacros ? MacroFilter : DefaultFilter;
FilteredDeclConsumer FilteringConsumer(AccessFilteringConsumer, Filter);
CurrModule->lookupVisibleDecls({}, AccessFilteringConsumer,
CurrModule->lookupVisibleDecls({}, FilteringConsumer,
NLKind::UnqualifiedLookup);
}

View File

@@ -1775,6 +1775,10 @@ ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
}
case tok::pound:
if (peekToken().is(tok::code_complete) &&
Tok.getLoc().getAdvancedLoc(1) == peekToken().getLoc()) {
return parseExprPoundCodeCompletion(/*ParentKind*/None);
}
if (Context.LangOpts.hasFeature(Feature::Macros)) {
return parseExprMacroExpansion(isExprBasic);
}
@@ -1782,10 +1786,6 @@ ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
Tok.getLoc().getAdvancedLoc(1) == peekToken().getLoc()) {
return parseExprPoundUnknown(SourceLoc());
}
if (peekToken().is(tok::code_complete) &&
Tok.getLoc().getAdvancedLoc(1) == peekToken().getLoc()) {
return parseExprPoundCodeCompletion(/*ParentKind*/None);
}
goto UnknownCharacter;
// Eat an invalid token in an expression context. Error tokens are diagnosed

View File

@@ -0,0 +1,71 @@
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POUND_EXPR_1 -enable-experimental-feature Macros| %FileCheck %s -check-prefix=POUND_EXPR_INTCONTEXT
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POUND_EXPR_2 -enable-experimental-feature Macros | %FileCheck %s -check-prefix=POUND_EXPR_STRINGCONTEXT
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=BARE_EXPR_1 -enable-experimental-feature Macros| %FileCheck %s -check-prefix=BARE_EXPR_INTCONTEXT
// REQUIRES: objc_interop
import ObjectiveC
macro myLine: Int = A.B
macro myFilename<T: ExpressiblyByStringLiteral>: T = A.B
macro myStringify<T>(_: T) -> (T, String) = A.B
struct Color { }
macro myColorLiteral(red: Float, green: Float, blue: Float, alpha: Float) -> Color = A.B
func useInt(_ str: Int) -> Bool {}
func useString(_ str: String) -> Bool {}
func test1() {
let _ = useInt(##^POUND_EXPR_1^#)
let _ = useString(##^POUND_EXPR_2^#)
let _ = useInt(#^BARE_EXPR_1^#)
}
// POUND_EXPR_INTCONTEXT: Begin completions, 11 items
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#function]/None: function[#String#]; name=function
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#file]/None: file[#String#]; name=file
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#fileID]/None: fileID[#String#]; name=fileID
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#filePath]/None: filePath[#String#]; name=filePath
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#line]/None/TypeRelation[Convertible]: line[#Int#]; name=line
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#column]/None/TypeRelation[Convertible]: column[#Int#]; name=column
// POUND_EXPR_INTCONTEXT-DAG: Keyword[#dsohandle]/None: dsohandle[#UnsafeRawPointer#]; name=dsohandle
// POUND_EXPR_INTCONTEXT-DAG: Decl[Macro]/CurrModule: myFilename[#T#]; name=myFilename
// POUND_EXPR_INTCONTEXT-DAG: Decl[Macro]/CurrModule/TypeRelation[Convertible]: myLine[#Int#]; name=myLine
// POUND_EXPR_INTCONTEXT-DAG: Decl[Macro]/CurrModule: myStringify({#T#})[#(T, String)#]; name=myStringify()
// POUND_EXPR_INTCONTEXT-DAG: Decl[Macro]/CurrModule: myColorLiteral({#red: Float#}, {#green: Float#}, {#blue: Float#}, {#alpha: Float#})[#Color#]; name=myColorLiteral(red:green:blue:alpha:)
// POUND_EXPR_INTCONTEXT: End completions
// POUND_EXPR_STRINGCONTEXT: Begin completions, 12 items
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#function]/None/TypeRelation[Convertible]: function[#String#];
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#file]/None/TypeRelation[Convertible]: file[#String#];
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#fileID]/None/TypeRelation[Convertible]: fileID[#String#];
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#filePath]/None/TypeRelation[Convertible]: filePath[#String#];
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#line]/None: line[#Int#];
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#column]/None: column[#Int#];
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword[#dsohandle]/None: dsohandle[#UnsafeRawPointer#];
// POUND_EXPR_STRINGCONTEXT-DAG: Keyword/None/TypeRelation[Convertible]: keyPath({#@objc property sequence#})[#String#];
// POUND_EXPR_STRINGCONTEXT-DAG: Decl[Macro]/CurrModule: myColorLiteral({#red: Float#}, {#green: Float#}, {#blue: Float#}, {#alpha: Float#})[#Color#]; name=myColorLiteral(red:green:blue:alpha:)
// POUND_EXPR_STRINGCONTEXT-DAG: Decl[Macro]/CurrModule: myFilename[#T#]; name=myFilename
// POUND_EXPR_STRINGCONTEXT-DAG: Decl[Macro]/CurrModule: myLine[#Int#]; name=myLine
// POUND_EXPR_STRINGCONTEXT-DAG: Decl[Macro]/CurrModule: myStringify({#T#})[#(T, String)#]; name=myStringify()
// POUND_EXPR_STRINGCONTEXT: End completions
// BARE_EXPR_INTCONTEXT: Begin completions,
// BARE_EXPR_INTCONTEXT-DAG: Keyword[#fileID]/None: #fileID[#String#]; name=#fileID
// BARE_EXPR_INTCONTEXT-DAG: Keyword[#file]/None: #file[#String#]; name=#file
// BARE_EXPR_INTCONTEXT-DAG: Keyword[#filePath]/None: #filePath[#String#]; name=#filePath
// BARE_EXPR_INTCONTEXT-DAG: Keyword[#function]/None: #function[#String#]; name=#function
// BARE_EXPR_INTCONTEXT-DAG: Keyword[#line]/None/TypeRelation[Convertible]: #line[#Int#]; name=#line
// BARE_EXPR_INTCONTEXT-DAG: Keyword[#column]/None/TypeRelation[Convertible]: #column[#Int#]; name=#column
// BARE_EXPR_INTCONTEXT-DAG: Keyword[#dsohandle]/None: #dsohandle[#UnsafeRawPointer#]; name=#dsohandle
// BARE_EXPR_INTCONTEXT-DAG: Decl[Macro]/CurrModule: #myFilename[#T#]; name=#myFilename
// BARE_EXPR_INTCONTEXT-DAG: Decl[Struct]/CurrModule: Color[#Color#]; name=Color
// BARE_EXPR_INTCONTEXT-DAG: Decl[FreeFunction]/CurrModule/TypeRelation[Invalid]: test1()[#Void#]; name=test1()
// BARE_EXPR_INTCONTEXT-DAG: Decl[Macro]/CurrModule/TypeRelation[Convertible]: #myLine[#Int#]; name=#myLine
// BARE_EXPR_INTCONTEXT-DAG: Decl[FreeFunction]/CurrModule: useInt({#(str): Int#})[#Bool#]; name=useInt(:)
// BARE_EXPR_INTCONTEXT-DAG: Decl[Macro]/CurrModule: #myStringify({#T#})[#(T, String)#]; name=#myStringify()
// BARE_EXPR_INTCONTEXT-DAG: Decl[FreeFunction]/CurrModule: useString({#(str): String#})[#Bool#]; name=useString(:)
// BARE_EXPR_INTCONTEXT-DAG: Decl[Macro]/CurrModule: #myColorLiteral({#red: Float#}, {#green: Float#}, {#blue: Float#}, {#alpha: Float#})[#Color#]; name=#myColorLiteral(red:green:blue:alpha:)
// BARE_EXPR_INTCONTEXT: End completions

View File

@@ -412,7 +412,7 @@ UIdent SwiftLangSupport::getUIDForCodeCompletionDeclKind(
case CodeCompletionDeclKind::InstanceVar: return KindRefVarInstance;
case CodeCompletionDeclKind::LocalVar: return KindRefVarLocal;
case CodeCompletionDeclKind::GlobalVar: return KindRefVarGlobal;
case CodeCompletionDeclKind::Macro: return KindRefMacro;
case CodeCompletionDeclKind::Macro: return KindRefMacro;
}
}