diff --git a/CMakeLists.txt b/CMakeLists.txt index b3ce322696ecb..64d3f871c8de6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -872,6 +872,7 @@ if(SWIFT_BUILD_SWIFT_SYNTAX) message(WARNING "Force setting BOOTSTRAPPING=HOSTTOOLS because Swift parser integration is enabled") set(BOOTSTRAPPING_MODE "HOSTTOOLS") endif() + add_definitions(-DSWIFT_BUILD_SWIFT_SYNTAX) endif() if(BOOTSTRAPPING_MODE MATCHES "HOSTTOOLS|.*-WITH-HOSTLIBS") diff --git a/include/swift/AST/DiagnosticsRefactoring.def b/include/swift/AST/DiagnosticsRefactoring.def index 8778d511fd60a..7af78eafe7b42 100644 --- a/include/swift/AST/DiagnosticsRefactoring.def +++ b/include/swift/AST/DiagnosticsRefactoring.def @@ -26,6 +26,8 @@ ERROR(invalid_name, none, "'%0' is not a valid name", (StringRef)) +ERROR(extract_function_not_supported_swiftsyntax_missing, none, "Extract Function is not supported because sourcekitd was built without swift-syntax", ()) + ERROR(invalid_location, none, "given location is not valid", ()) ERROR(arity_mismatch, none, "the given new name '%0' does not match the arity of the old name '%1'", (StringRef, StringRef)) diff --git a/include/swift/IDE/IDEBridging.h b/include/swift/IDE/IDEBridging.h index 3e29eb8b3d8d5..3b262937a6a55 100644 --- a/include/swift/IDE/IDEBridging.h +++ b/include/swift/IDE/IDEBridging.h @@ -160,24 +160,4 @@ class BridgedResolvedLocVector { void *getOpaqueValue() const; }; -#ifdef __cplusplus -extern "C" { -#endif - -/// Entry point to run the NameMatcher written in swift-syntax. -/// -/// - Parameters: -/// - sourceFilePtr: A pointer to an `ExportedSourceFile`, used to access the -/// syntax tree -/// - locations: Pointer to a buffer of `BridgedSourceLoc` that should be -/// resolved by the name matcher. -/// - locationsCount: Number of elements in `locations`. -/// - Returns: The opaque value of a `BridgedResolvedLocVector`. -void *swift_SwiftIDEUtilsBridging_runNameMatcher(const void *sourceFilePtr, - BridgedSourceLoc *locations, - size_t locationsCount); -#ifdef __cplusplus -} -#endif - #endif diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index 42a7445458d2e..a823af60a3056 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -307,73 +307,6 @@ struct CallingParent { CallExpr *Call; }; - -/// Finds the parse-only AST nodes and corresponding name and param/argument -/// label ranges for a given list of input name start locations -/// -/// Resolved locations also indicate the nature of the matched occurrence (e.g. -/// whether it is within active/inactive code, or a selector or string literal). -class NameMatcher: public ASTWalker { - SourceFile &SrcFile; - std::vector LocsToResolve; - std::vector ResolvedLocs; - ArrayRef TokensToCheck; - - /// The \c ArgumentList of a parent \c CustomAttr (if one exists) and - /// the \c SourceLoc of the type name it applies to. - llvm::Optional> CustomAttrArgList; - unsigned InactiveConfigRegionNestings = 0; - unsigned SelectorNestings = 0; - - /// The stack of parent CallExprs and the innermost expression they apply to. - std::vector ParentCalls; - - SourceManager &getSourceMgr() const; - - SourceLoc nextLoc() const; - bool isDone() const { return LocsToResolve.empty(); }; - bool isActive() const { return !InactiveConfigRegionNestings; }; - bool isInSelector() const { return SelectorNestings; }; - bool checkComments(); - void skipLocsBefore(SourceLoc Start); - bool shouldSkip(Expr *E); - bool shouldSkip(SourceRange Range); - bool shouldSkip(CharSourceRange Range); - bool tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc); - bool tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc, - ArgumentList *Args); - bool tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc, - LabelRangeType RangeType, ArrayRef LabelLocs, - llvm::Optional FirstTrailingLabel); - bool handleCustomAttrs(Decl *D); - ArgumentList *getApplicableArgsFor(Expr* E); - - MacroWalking getMacroWalkingBehavior() const override { - return MacroWalking::Arguments; - } - - PreWalkResult walkToExprPre(Expr *E) override; - PostWalkResult walkToExprPost(Expr *E) override; - PreWalkAction walkToDeclPre(Decl *D) override; - PreWalkResult walkToStmtPre(Stmt *S) override; - PreWalkAction walkToTypeReprPre(TypeRepr *T) override; - PreWalkResult walkToPatternPre(Pattern *P) override; - bool shouldWalkIntoGenericParams() override { return true; } - bool shouldWalkIntoUncheckedMacroDefinitions() override { return true; } - - PreWalkResult - walkToArgumentListPre(ArgumentList *ArgList) override; - - // FIXME: Remove this - bool shouldWalkAccessorsTheOldWay() override { return true; } - -public: - explicit NameMatcher(SourceFile &SrcFile) : SrcFile(SrcFile) { } - std::vector resolve(ArrayRef Locs, - ArrayRef Tokens); - ResolvedLoc resolve(SourceLoc Loc); -}; - enum class RangeKind : int8_t { Invalid = -1, SingleExpression, @@ -715,6 +648,19 @@ bool isDynamicRef(Expr *Base, ValueDecl *D, llvm::function_ref get void getReceiverType(Expr *Base, SmallVectorImpl &Types); +#if SWIFT_BUILD_SWIFT_SYNTAX +/// Entry point to run the NameMatcher written in swift-syntax. +/// +/// - Parameters: +/// - sourceFile: The source file from which to load the SwiftSyntax tree +/// - locations: The locations to resolve +/// - Returns: A list of `ResolvedLoc` that have been resolved. This list might +/// be shorteder than `locations` if some locations could not be resolved and +/// the resolved locations might be in a different order than `locations`. +std::vector runNameMatcher(const SourceFile &sourceFile, + ArrayRef locations); +#endif + } // namespace ide } // namespace swift diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index d46046c2baba1..89e69e9187403 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -154,13 +154,6 @@ target_link_libraries(swiftAST INTERFACE clangAPINotes clangBasic) -if(SWIFT_BUILD_SWIFT_SYNTAX) - target_compile_definitions(swiftAST - PRIVATE - SWIFT_BUILD_SWIFT_SYNTAX - ) -endif() - target_link_libraries(swiftAST PUBLIC swiftBasic PRIVATE swiftMarkup) diff --git a/lib/DriverTool/CMakeLists.txt b/lib/DriverTool/CMakeLists.txt index ec46f3083ff33..c728f08399eeb 100644 --- a/lib/DriverTool/CMakeLists.txt +++ b/lib/DriverTool/CMakeLists.txt @@ -35,13 +35,6 @@ if(NOT SWIFT_BUILT_STANDALONE) add_dependencies(swiftDriverTool clang-resource-headers) endif() -if (SWIFT_BUILD_SWIFT_SYNTAX) - target_compile_definitions(swiftDriverTool - PRIVATE - SWIFT_BUILD_SWIFT_SYNTAX - ) -endif() - set_swift_llvm_is_available(swiftDriverTool) set(LLVM_TARGET_DEFINITIONS SwiftCacheToolOptions.td) diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 5b8aab15a6b14..4c928fcce0cd6 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -38,10 +38,3 @@ target_link_libraries(swiftFrontend PRIVATE swiftSymbolGraphGen) set_swift_llvm_is_available(swiftFrontend) - -if (SWIFT_BUILD_SWIFT_SYNTAX) - target_compile_definitions(swiftFrontend - PRIVATE - SWIFT_BUILD_SWIFT_SYNTAX - ) -endif() diff --git a/lib/IDE/CMakeLists.txt b/lib/IDE/CMakeLists.txt index f89074a7ae77e..7b03bb48cc2a4 100644 --- a/lib/IDE/CMakeLists.txt +++ b/lib/IDE/CMakeLists.txt @@ -46,4 +46,10 @@ target_link_libraries(swiftIDE PRIVATE swiftParse swiftSema) +if (SWIFT_BUILD_SWIFT_SYNTAX) + target_link_libraries(swiftIDE PRIVATE + swiftIDEUtilsBridging + ) +endif() + set_swift_llvm_is_available(swiftIDE) diff --git a/lib/IDE/SwiftSourceDocInfo.cpp b/lib/IDE/SwiftSourceDocInfo.cpp index 1347f6b058a04..4b96c4436b39d 100644 --- a/lib/IDE/SwiftSourceDocInfo.cpp +++ b/lib/IDE/SwiftSourceDocInfo.cpp @@ -70,631 +70,6 @@ void XMLEscapingPrinter::printXML(StringRef Text) { OS << Text; } -SourceManager &NameMatcher::getSourceMgr() const { - return SrcFile.getASTContext().SourceMgr; -} - -ResolvedLoc NameMatcher::resolve(SourceLoc Loc) { - return resolve(Loc, {}).front(); -} - -std::vector NameMatcher::resolve(ArrayRef Locs, - ArrayRef Tokens) { - - // Note the original indices and sort them in reverse source order - std::vector MapToOriginalIndex(Locs.size()); - std::iota(MapToOriginalIndex.begin(), MapToOriginalIndex.end(), 0); - std::sort(MapToOriginalIndex.begin(), MapToOriginalIndex.end(), - [this, Locs](size_t first, size_t second) { - return first != second && !getSourceMgr().isBeforeInBuffer( - Locs[first], Locs[second]); - }); - - // Add the locs themselves - LocsToResolve.clear(); - llvm::transform(MapToOriginalIndex, std::back_inserter(LocsToResolve), - [&](size_t index) { return Locs[index]; }); - - InactiveConfigRegionNestings = 0; - SelectorNestings = 0; - TokensToCheck = Tokens; - ResolvedLocs.clear(); - SrcFile.walk(*this); - checkComments(); - - // handle any unresolved locs past the end of the last AST node or comment - std::vector Remaining(Locs.size() - ResolvedLocs.size(), - {CharSourceRange(), - {}, - llvm::None, - LabelRangeType::None, - /*isActive*/ true, - ResolvedLocContext::Comment}); - ResolvedLocs.insert(ResolvedLocs.end(), Remaining.begin(), Remaining.end()); - - // return in the original order - std::vector Ordered(ResolvedLocs.size()); - for(size_t Index = 0; Index < ResolvedLocs.size(); ++Index) { - size_t Flipped = ResolvedLocs.size() - 1 - Index; - Ordered[MapToOriginalIndex[Flipped]] = ResolvedLocs[Index]; - } - return Ordered; -} - -static std::vector getLabelRanges(const ParameterList* List, - const SourceManager &SM) { - std::vector LabelRanges; - for (ParamDecl *Param: *List) { - if (Param->isImplicit()) - continue; - - SourceLoc NameLoc = Param->getArgumentNameLoc(); - SourceLoc ParamLoc = Param->getNameLoc(); - size_t NameLength; - if (NameLoc.isValid()) { - LabelRanges.push_back(Lexer::getCharSourceRangeFromSourceRange( - SM, SourceRange(NameLoc, ParamLoc))); - } else { - NameLoc = ParamLoc; - NameLength = Param->getNameStr().size(); - if (SM.extractText({NameLoc, 1}) == "`") - NameLength += 2; - LabelRanges.push_back(CharSourceRange(NameLoc, NameLength)); - } - } - return LabelRanges; -} - -static std::vector getEnumParamListInfo(SourceManager &SM, - ParameterList *PL) { - std::vector LabelRanges; - for (ParamDecl *Param: *PL) { - if (Param->isImplicit()) - continue; - - SourceLoc LabelStart; - if (auto *repr = Param->getTypeRepr()) - LabelStart = repr->getLoc(); - SourceLoc LabelEnd(LabelStart); - - if (Param->getNameLoc().isValid()) { - LabelStart = Param->getNameLoc(); - } - LabelRanges.push_back(CharSourceRange(SM, LabelStart, LabelEnd)); - } - return LabelRanges; -} - -bool NameMatcher::handleCustomAttrs(Decl *D) { - // CustomAttrs of non-param VarDecls are handled when this method is called - // on their containing PatternBindingDecls (see below). - if (isa(D) && !isa(D)) - return true; - - if (auto *PBD = dyn_cast(D)) { - if (auto *SingleVar = PBD->getSingleVar()) { - D = SingleVar; - } else { - return true; - } - } - - for (auto *customAttr : - D->getParsedAttrs().getAttributes()) { - if (shouldSkip(customAttr->getRangeWithAt())) - continue; - auto *Args = customAttr->getArgs(); - if (auto *Repr = customAttr->getTypeRepr()) { - // Note the associated call arguments of the semantic initializer call - // in case we're resolving an explicit initializer call within the - // CustomAttr's type, e.g. on `Wrapper` in `@Wrapper(wrappedValue: 10)`. - SWIFT_DEFER { CustomAttrArgList = llvm::None; }; - if (Args && !Args->isImplicit()) - CustomAttrArgList = Located(Args, Repr->getLoc()); - if (!Repr->walk(*this)) - return false; - } - if (Args && !customAttr->isImplicit()) { - if (!Args->walk(*this)) - return false; - } - } - return !isDone(); -} - -ASTWalker::PreWalkAction NameMatcher::walkToDeclPre(Decl *D) { - // Handle occurrences in any preceding doc comments - RawComment R = D->getRawComment(); - if (!R.isEmpty()) { - for(SingleRawComment C: R.Comments) { - while(!shouldSkip(C.Range)) - tryResolve(ASTWalker::ParentTy(), nextLoc()); - } - } - if (isDone()) - return Action::Stop(); - - // FIXME: Even implicit Decls should have proper ranges if they include any - // non-implicit children (fix implicit Decls created for lazy vars). - if (D->isImplicit()) - return Action::Continue(); - - if (shouldSkip(D->getSourceRangeIncludingAttrs())) - return Action::SkipChildren(); - - if (!handleCustomAttrs(D)) - return Action::Stop(); - - if (auto *ICD = dyn_cast(D)) { - for (auto Clause : ICD->getClauses()) { - if (!Clause.isActive) - ++InactiveConfigRegionNestings; - - for (auto Member : Clause.Elements) { - Member.walk(*this); - } - - if (!Clause.isActive) { - assert(InactiveConfigRegionNestings > 0); - --InactiveConfigRegionNestings; - } - } - return Action::SkipChildren(); - } else if (AbstractFunctionDecl *AFD = dyn_cast(D)) { - std::vector LabelRanges; - if (AFD->getNameLoc() == nextLoc()) { - auto ParamList = AFD->getParameters(); - LabelRanges = getLabelRanges(ParamList, getSourceMgr()); - } - tryResolve(ASTWalker::ParentTy(D), D->getLoc(), LabelRangeType::Param, - LabelRanges, llvm::None); - } else if (SubscriptDecl *SD = dyn_cast(D)) { - tryResolve(ASTWalker::ParentTy(D), D->getLoc(), - LabelRangeType::NoncollapsibleParam, - getLabelRanges(SD->getIndices(), getSourceMgr()), llvm::None); - } else if (EnumElementDecl *EED = dyn_cast(D)) { - if (auto *ParamList = EED->getParameterList()) { - auto LabelRanges = getEnumParamListInfo(getSourceMgr(), ParamList); - tryResolve(ASTWalker::ParentTy(D), D->getLoc(), LabelRangeType::CallArg, - LabelRanges, llvm::None); - } else { - tryResolve(ASTWalker::ParentTy(D), D->getLoc()); - } - } else if (ImportDecl *ID = dyn_cast(D)) { - for(const ImportPath::Element &Element: ID->getImportPath()) { - tryResolve(ASTWalker::ParentTy(D), Element.Loc); - if (isDone()) - break; - } - } else if (isa(D) || isa(D) || - isa(D)) { - tryResolve(ASTWalker::ParentTy(D), D->getLoc()); - } - return Action::StopIf(isDone()); -} - -ASTWalker::PreWalkResult NameMatcher::walkToStmtPre(Stmt *S) { - if (isDone()) - return Action::Stop(); - - // FIXME: Even implicit Stmts should have proper ranges that include any - // non-implicit Stmts (fix Stmts created for lazy vars). - auto ShouldSkip = !S->isImplicit() && shouldSkip(S->getSourceRange()); - return Action::SkipChildrenIf(ShouldSkip, S); -} - -ArgumentList *NameMatcher::getApplicableArgsFor(Expr *E) { - if (ParentCalls.empty()) - return nullptr; - auto &Last = ParentCalls.back(); - return Last.ApplicableTo == E ? Last.Call->getArgs() : nullptr; -} - -static Expr *extractNameExpr(Expr *Fn) { - Fn = Fn->getSemanticsProvidingExpr(); - switch (Fn->getKind()) { - case ExprKind::DeclRef: - case ExprKind::UnresolvedDeclRef: - case ExprKind::UnresolvedMember: - case ExprKind::UnresolvedDot: - return Fn; - default: - break; - } - if (auto *SAE = dyn_cast(Fn)) - return extractNameExpr(SAE->getFn()); - if (auto *ACE = dyn_cast(Fn)) - if (auto *Unwrapped = ACE->getUnwrappedCurryThunkExpr()) - return extractNameExpr(Unwrapped); - return nullptr; -} - -ASTWalker::PreWalkResult -NameMatcher::walkToArgumentListPre(ArgumentList *ArgList) { - if (!ArgList->isImplicit()) { - auto Labels = getCallArgLabelRanges(getSourceMgr(), ArgList, - LabelRangeEndAt::BeforeElemStart); - tryResolve(Parent, ArgList->getStartLoc(), LabelRangeType::CallArg, - Labels.first, Labels.second); - } - if (isDone()) - return Action::Stop(); - - // Handle arg label locations (the index reports property occurrences on them - // for memberwise inits). - for (auto Arg : *ArgList) { - auto Name = Arg.getLabel(); - auto *E = Arg.getExpr(); - if (!Name.empty()) { - tryResolve(Parent, Arg.getLabelLoc()); - if (isDone()) - return Action::Stop(); - } - if (!E->walk(*this)) - return Action::Stop(); - } - // TODO: We should consider changing Action::SkipChildren to still call - // walkToArgumentListPost, which would eliminate the need for this. - auto postWalkResult = walkToArgumentListPost(ArgList); - switch (postWalkResult.Action.Action) { - case PostWalkAction::Stop: - return Action::Stop(); - case PostWalkAction::Continue: - // We already visited the children. - return Action::SkipChildren(*postWalkResult.Value); - } - llvm_unreachable("Unhandled case in switch!"); -} - -ASTWalker::PreWalkResult NameMatcher::walkToExprPre(Expr *E) { - if (isDone()) - return Action::Stop(); - if (shouldSkip(E)) - return Action::SkipChildren(E); - - if (isa(E)) { - ++SelectorNestings; - } - - // only match name locations of expressions apparent in the original source - if (!E->isImplicit()) { - - if (auto *CE = dyn_cast(E)) { - // Keep a stack of parent CallExprs along with the expression their - // arguments belong to. - if (!CE->isImplicit()) { - if (auto *ApplicableExpr = extractNameExpr(CE->getFn())) - ParentCalls.push_back({ApplicableExpr, CE}); - } - } - - // Try to resolve against the below kinds *before* their children are - // visited to ensure visitation happens in source order. - switch (E->getKind()) { - case ExprKind::UnresolvedMember: { - auto UME = cast(E); - tryResolve(ASTWalker::ParentTy(E), UME->getNameLoc(), - getApplicableArgsFor(E)); - } break; - case ExprKind::DeclRef: { - auto DRE = cast(E); - tryResolve(ASTWalker::ParentTy(E), DRE->getNameLoc(), - getApplicableArgsFor(E)); - break; - } - case ExprKind::UnresolvedDeclRef: { - auto UDRE = cast(E); - tryResolve(ASTWalker::ParentTy(E), UDRE->getNameLoc(), - getApplicableArgsFor(E)); - break; - } - case ExprKind::StringLiteral: - // Handle multple locations in a single string literal - do { - tryResolve(ASTWalker::ParentTy(E), nextLoc()); - } while (!shouldSkip(E)); - break; - case ExprKind::Binary: { - BinaryExpr *BinE = cast(E); - // Visit in source order. - if (!BinE->getLHS()->walk(*this)) - return Action::Stop(); - if (!BinE->getFn()->walk(*this)) - return Action::Stop(); - if (!BinE->getRHS()->walk(*this)) - return Action::Stop(); - - // TODO: We should consider changing Action::SkipChildren to still call - // walkToArgumentListPost, which would eliminate the need for this. - auto postWalkResult = walkToExprPost(E); - switch (postWalkResult.Action.Action) { - case PostWalkAction::Stop: - return Action::Stop(); - case PostWalkAction::Continue: - // We already visited the children. - return Action::SkipChildren(*postWalkResult.Value); - } - llvm_unreachable("Unhandled case in switch!"); - } - case ExprKind::KeyPath: { - KeyPathExpr *KP = cast(E); - - // Swift keypath components are visited already, so there's no need to - // handle them specially. - if (!KP->isObjC()) - break; - - for (auto Component: KP->getComponents()) { - switch (Component.getKind()) { - case KeyPathExpr::Component::Kind::UnresolvedProperty: - case KeyPathExpr::Component::Kind::Property: - tryResolve(ASTWalker::ParentTy(E), Component.getLoc()); - break; - case KeyPathExpr::Component::Kind::DictionaryKey: - case KeyPathExpr::Component::Kind::Invalid: - case KeyPathExpr::Component::Kind::CodeCompletion: - break; - case KeyPathExpr::Component::Kind::OptionalForce: - case KeyPathExpr::Component::Kind::OptionalChain: - case KeyPathExpr::Component::Kind::OptionalWrap: - case KeyPathExpr::Component::Kind::UnresolvedSubscript: - case KeyPathExpr::Component::Kind::Subscript: - case KeyPathExpr::Component::Kind::Identity: - case KeyPathExpr::Component::Kind::TupleElement: - llvm_unreachable("Unexpected component in ObjC KeyPath expression"); - break; - } - } - break; - } - default: // ignored - break; - } - } - return Action::StopIf(isDone(), E); -} - -ASTWalker::PostWalkResult NameMatcher::walkToExprPost(Expr *E) { - if (isDone()) - return Action::Stop(); - - if (!E->isImplicit()) { - // Try to resolve against the below kinds *after* their children have been - // visited to ensure visitation happens in source order. - switch (E->getKind()) { - case ExprKind::MemberRef: - tryResolve(ASTWalker::ParentTy(E), E->getLoc()); - break; - case ExprKind::UnresolvedDot: { - auto UDE = cast(E); - tryResolve(ASTWalker::ParentTy(E), UDE->getNameLoc(), - getApplicableArgsFor(E)); - break; - } - default: - break; - } - - if (auto *CE = dyn_cast(E)) { - if (!ParentCalls.empty() && ParentCalls.back().Call == CE) - ParentCalls.pop_back(); - } - } - - if (isa(E)) { - assert(SelectorNestings > 0); - --SelectorNestings; - } - - return Action::StopIf(isDone(), E); -} - -ASTWalker::PreWalkAction NameMatcher::walkToTypeReprPre(TypeRepr *T) { - if (isDone()) - return Action::Stop(); - if (shouldSkip(T->getSourceRange())) - return Action::SkipChildren(); - - if (isa(T)) { - // If we're walking a CustomAttr's type we may have an associated call - // argument to resolve with from its semantic initializer. - if (CustomAttrArgList.has_value() && CustomAttrArgList->Loc == T->getLoc()) { - auto Labels = - getCallArgLabelRanges(getSourceMgr(), CustomAttrArgList->Item, - LabelRangeEndAt::BeforeElemStart); - tryResolve(ASTWalker::ParentTy(T), T->getLoc(), LabelRangeType::CallArg, - Labels.first, Labels.second); - } else { - tryResolve(ASTWalker::ParentTy(T), T->getLoc()); - } - } - return Action::StopIf(isDone()); -} - -ASTWalker::PreWalkResult NameMatcher::walkToPatternPre(Pattern *P) { - if (isDone()) - return Action::Stop(); - if (shouldSkip(P->getSourceRange())) - return Action::SkipChildren(P); - - tryResolve(ASTWalker::ParentTy(P), P->getStartLoc()); - return Action::StopIf(isDone(), P); -} - -bool NameMatcher::checkComments() { - if (isDone()) - return false; - TokensToCheck = TokensToCheck.drop_while([this](const Token &tok) -> bool { - return getSourceMgr().isBeforeInBuffer(tok.getRange().getEnd(), nextLoc()); - }); - if (TokensToCheck.empty()) - return false; - - const Token &next = TokensToCheck.front(); - if (next.is(swift::tok::comment) && next.getRange().contains(nextLoc()) && - !next.getText().startswith("///")) - return tryResolve(ASTWalker::ParentTy(), nextLoc()); - return false; -} - -void NameMatcher::skipLocsBefore(SourceLoc Start) { - while (!isDone() && getSourceMgr().isBeforeInBuffer(nextLoc(), Start)) { - if (!checkComments()) { - LocsToResolve.pop_back(); - ResolvedLocContext Context = isInSelector() ? ResolvedLocContext::Selector - : ResolvedLocContext::Comment; - ResolvedLocs.push_back({CharSourceRange(), - {}, - llvm::None, - LabelRangeType::None, - isActive(), - Context}); - } - } -} - -bool NameMatcher::shouldSkip(Expr *E) { - if (isa(E) && Parent.getAsExpr()) { - // Attempting to get the CharSourceRange from the SourceRange of a - // StringLiteralExpr that is a segment of an interpolated string gives - // incorrect ranges. Use the CharSourceRange of the corresponding token - // instead. - - auto ExprStart = E->getStartLoc(); - auto RemaingTokens = TokensToCheck.drop_while([&](const Token &tok) -> bool { - return getSourceMgr().isBeforeInBuffer(tok.getRange().getStart(), ExprStart); - }); - - if (!RemaingTokens.empty() && RemaingTokens.front().getLoc() == ExprStart) - return shouldSkip(RemaingTokens.front().getRange()); - } - return shouldSkip(E->getSourceRange()); -} - -bool NameMatcher::shouldSkip(SourceRange Range) { - return shouldSkip(Lexer::getCharSourceRangeFromSourceRange(getSourceMgr(), - Range)); -} - -bool NameMatcher::shouldSkip(CharSourceRange Range) { - if (isDone()) - return true; - if (Range.isInvalid()) - return false; - - skipLocsBefore(Range.getStart()); - return isDone() || !Range.contains(nextLoc()); -} - -SourceLoc NameMatcher::nextLoc() const { - assert(!LocsToResolve.empty()); - return LocsToResolve.back(); -} - -std::vector getSelectorLabelRanges(SourceManager &SM, - DeclNameLoc NameLoc) { - SourceLoc Loc; - std::vector Ranges; - size_t index = 0; - while((Loc = NameLoc.getArgumentLabelLoc(index++)).isValid()) { - CharSourceRange Range = Lexer::getCharSourceRangeFromSourceRange(SM, - SourceRange(Loc)); - Ranges.push_back(Range); - } - - return Ranges; -} - -bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc, - ArgumentList *Args) { - if (NameLoc.isInvalid()) - return false; - - if (NameLoc.isCompound()) { - auto Labels = getSelectorLabelRanges(getSourceMgr(), NameLoc); - bool Resolved = - tryResolve(Node, NameLoc.getBaseNameLoc(), LabelRangeType::CompoundName, - Labels, llvm::None); - if (!isDone()) { - for (auto Label: Labels) { - if (tryResolve(Node, Label.getStart())) { - Resolved = true; - if (isDone()) - break; - } - } - } - return Resolved; - } - - if (Args) { - auto Labels = getCallArgLabelRanges(getSourceMgr(), Args, - LabelRangeEndAt::BeforeElemStart); - return tryResolve(Node, NameLoc.getBaseNameLoc(), LabelRangeType::CallArg, - Labels.first, Labels.second); - } - - return tryResolve(Node, NameLoc.getBaseNameLoc()); -} - -bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc) { - assert(!isDone()); - return tryResolve(Node, NameLoc, LabelRangeType::None, llvm::None, - llvm::None); -} - -bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc, - LabelRangeType RangeType, - ArrayRef LabelRanges, - llvm::Optional FirstTrailingLabel) { - skipLocsBefore(NameLoc); - if (isDone()) - return false; - - ResolvedLocContext Context = ResolvedLocContext::Default; - if (Node.isNull()) { - Context = ResolvedLocContext::Comment; - } else if (isa_and_nonnull(Node.getAsExpr())) { - Context = ResolvedLocContext::StringLiteral; - } else if (isInSelector()) { - Context = ResolvedLocContext::Selector; - } - - CharSourceRange Range = Lexer::getCharSourceRangeFromSourceRange(getSourceMgr(), - NameLoc); - SourceLoc &Next = LocsToResolve.back(); - bool WasResolved = false; - if (Range.isValid()) { - if (NameLoc == Next) { - LocsToResolve.pop_back(); - ResolvedLocs.push_back({Range, LabelRanges, FirstTrailingLabel, RangeType, - isActive(), Context}); - if (isDone()) - return true; - WasResolved = true; - } - - if (Range.getByteLength() > 1 && - (Range.str().front() == '_' || Range.str().front() == '$')) { - // Also try after any leading _ or $ for name references of wrapped - // properties, e.g. 'foo' in '_foo' and '$foo' occurrences. - auto NewRange = CharSourceRange(Range.getStart().getAdvancedLoc(1), - Range.getByteLength() - 1); - if (NewRange.getStart() == Next) { - LocsToResolve.pop_back(); - ResolvedLocs.push_back({NewRange, - {}, - llvm::None, - LabelRangeType::None, - isActive(), - Context}); - WasResolved = true; - } - } - } - return WasResolved; -} - void ResolvedRangeInfo::print(llvm::raw_ostream &OS) const { OS << ""; switch (Kind) { diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 954f7c69bb9e0..96bd14894621a 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -1094,3 +1094,36 @@ void swift::ide::getReceiverType(Expr *Base, Types.push_back(TyD); } } + +#if SWIFT_BUILD_SWIFT_SYNTAX +extern "C" { +/// Low-level entry point to run the NameMatcher written in swift-syntax. +/// +/// - Parameters: +/// - sourceFilePtr: A pointer to an `ExportedSourceFile`, used to access the +/// syntax tree +/// - locations: Pointer to a buffer of `BridgedSourceLoc` that should be +/// resolved by the name matcher. +/// - locationsCount: Number of elements in `locations`. +/// - Returns: The opaque value of a `BridgedResolvedLocVector`. +void *swift_SwiftIDEUtilsBridging_runNameMatcher(const void *sourceFilePtr, + BridgedSourceLoc *locations, + size_t locationsCount); +} + +std::vector +swift::ide::runNameMatcher(const SourceFile &sourceFile, + ArrayRef locations) { + std::vector bridgedUnresolvedLocs; + bridgedUnresolvedLocs.reserve(locations.size()); + for (SourceLoc loc : locations) { + bridgedUnresolvedLocs.push_back(BridgedSourceLoc(loc)); + } + + BridgedResolvedLocVector bridgedResolvedLocs = + swift_SwiftIDEUtilsBridging_runNameMatcher( + sourceFile.getExportedSourceFile(), bridgedUnresolvedLocs.data(), + bridgedUnresolvedLocs.size()); + return bridgedResolvedLocs.takeUnbridged(); +} +#endif // SWIFT_BUILD_SWIFT_SYNTAX diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index 367a540ee8681..4b51d767fe362 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -51,11 +51,6 @@ if (SWIFT_BUILD_SWIFT_SYNTAX) SwiftSyntaxMacros swiftASTGen ) - - target_compile_definitions(swiftParse - PRIVATE - SWIFT_BUILD_SWIFT_SYNTAX - ) endif() if(SWIFT_BUILD_REGEX_PARSER_IN_COMPILER) diff --git a/lib/Refactoring/CMakeLists.txt b/lib/Refactoring/CMakeLists.txt index b4ecc091a62a7..5974b8d6b205e 100644 --- a/lib/Refactoring/CMakeLists.txt +++ b/lib/Refactoring/CMakeLists.txt @@ -50,10 +50,6 @@ target_link_libraries(swiftRefactoring PRIVATE swiftSema) if(SWIFT_BUILD_SWIFT_SYNTAX) - target_compile_definitions(swiftRefactoring - PRIVATE - SWIFT_BUILD_SWIFT_SYNTAX - ) target_link_libraries(swiftRefactoring PRIVATE swiftIDEUtilsBridging ) diff --git a/lib/Refactoring/ExtractFunction.cpp b/lib/Refactoring/ExtractFunction.cpp index 6b3f3a8ed2ef0..0c9a91d6d8946 100644 --- a/lib/Refactoring/ExtractFunction.cpp +++ b/lib/Refactoring/ExtractFunction.cpp @@ -77,6 +77,7 @@ static SourceLoc getNewFuncInsertLoc(DeclContext *DC, return SourceLoc(); } +#if SWIFT_BUILD_SWIFT_SYNTAX static std::vector getNotableRegions(StringRef SourceText, unsigned NameOffset, StringRef Name) { auto InputBuffer = @@ -99,8 +100,7 @@ getNotableRegions(StringRef SourceText, unsigned NameOffset, StringRef Name) { SourceLoc NameLoc = SM.getLocForOffset(BufferId, NameOffset); auto LineAndCol = SM.getLineAndColumnInBuffer(NameLoc); - NameMatcher Matcher(*Instance->getPrimarySourceFile()); - auto Resolved = Matcher.resolve(llvm::makeArrayRef(NameLoc), llvm::None); + auto Resolved = runNameMatcher(*Instance->getPrimarySourceFile(), NameLoc); assert(!Resolved.empty() && "Failed to resolve generated func name loc"); RenameLoc RenameConfig = {LineAndCol.first, LineAndCol.second, @@ -122,6 +122,7 @@ getNotableRegions(StringRef SourceText, unsigned NameOffset, StringRef Name) { return NoteRegions; } +#endif // SWIFT_BUILD_SWIFT_SYNTAX bool RefactoringActionExtractFunction::isApplicable( const ResolvedRangeInfo &Info, DiagnosticEngine &Diag) { @@ -142,6 +143,11 @@ bool RefactoringActionExtractFunction::isApplicable( } bool RefactoringActionExtractFunction::performChange() { +#if !SWIFT_BUILD_SWIFT_SYNTAX + DiagEngine.diagnose(SourceLoc(), + diag::extract_function_not_supported_swiftsyntax_missing); + return true; +#else // Check if the new name is ok. if (!Lexer::isIdentifier(PreferredName)) { DiagEngine.diagnose(SourceLoc(), diag::invalid_name, PreferredName); @@ -300,4 +306,5 @@ bool RefactoringActionExtractFunction::performChange() { EditConsumer.accept(SM, RangeInfo.ContentRange, CallStr, NotableCallRegions); return false; +#endif } diff --git a/lib/Refactoring/LocalRename.cpp b/lib/Refactoring/LocalRename.cpp index a6640b25a6829..4d09a461af09f 100644 --- a/lib/Refactoring/LocalRename.cpp +++ b/lib/Refactoring/LocalRename.cpp @@ -16,6 +16,7 @@ #include "swift/AST/USRGeneration.h" #include "swift/Basic/StringExtras.h" #include "swift/Frontend/PrintingDiagnosticConsumer.h" +#include "swift/IDE/IDEBridging.h" #include "swift/Index/Index.h" using namespace swift::refactoring; @@ -44,6 +45,28 @@ struct RenameRefInfo { bool IsArgLabel; ///< Whether Loc is on an arg label, rather than base name. }; +#if SWIFT_BUILD_SWIFT_SYNTAX +/// Returns `true` if the `RefInfo` points to a location that doesn't have any +/// arguments. For example, returns `true` for `Foo.init` but `false` for +/// `Foo.init()` or `Foo.init(a: 1)`. +static bool +isReferenceWithoutArguments(const llvm::Optional &refInfo) { + if (!refInfo) { + return false; + } + if (refInfo->IsArgLabel) { + return false; + } + std::vector resolvedLocs = + runNameMatcher(*refInfo->SF, refInfo->Loc); + if (!resolvedLocs.empty()) { + ResolvedLoc resolvedLoc = resolvedLocs.front(); + return resolvedLoc.labelRanges.empty(); + } + return false; +} +#endif // SWIFT_BUILD_SWIFT_SYNTAX + static llvm::Optional renameAvailabilityInfo(const ValueDecl *VD, llvm::Optional RefInfo) { @@ -88,12 +111,11 @@ renameAvailabilityInfo(const ValueDecl *VD, if (!CD->getParameters()->size()) return llvm::None; - if (RefInfo && !RefInfo->IsArgLabel) { - NameMatcher Matcher(*(RefInfo->SF)); - auto Resolved = Matcher.resolve({RefInfo->Loc}); - if (Resolved.labelRanges.empty()) - return llvm::None; +#if SWIFT_BUILD_SWIFT_SYNTAX + if (isReferenceWithoutArguments(RefInfo)) { + return llvm::None; } +#endif } // Disallow renaming 'callAsFunction' method with no arguments. @@ -104,12 +126,11 @@ renameAvailabilityInfo(const ValueDecl *VD, if (!FD->getParameters()->size()) return llvm::None; - if (RefInfo && !RefInfo->IsArgLabel) { - NameMatcher Matcher(*(RefInfo->SF)); - auto Resolved = Matcher.resolve({RefInfo->Loc}); - if (Resolved.labelRanges.empty()) - return llvm::None; +#if SWIFT_BUILD_SWIFT_SYNTAX + if (isReferenceWithoutArguments(RefInfo)) { + return llvm::None; } +#endif } } } diff --git a/lib/Refactoring/SyntacticRename.cpp b/lib/Refactoring/SyntacticRename.cpp index 63c6040e630fc..bbd979ccc76e6 100644 --- a/lib/Refactoring/SyntacticRename.cpp +++ b/lib/Refactoring/SyntacticRename.cpp @@ -74,18 +74,8 @@ swift::ide::resolveRenameLocations(ArrayRef RenameLocs, assert(UnresolvedLocs.size() == RenameLocs.size()); - std::vector BridgedUnresolvedLocs; - BridgedUnresolvedLocs.reserve(UnresolvedLocs.size()); - for (SourceLoc Loc : UnresolvedLocs) { - BridgedUnresolvedLocs.push_back(BridgedSourceLoc(Loc)); - } - - BridgedResolvedLocVector bridgedResolvedLocs = - swift_SwiftIDEUtilsBridging_runNameMatcher(SF.getExportedSourceFile(), - BridgedUnresolvedLocs.data(), - BridgedUnresolvedLocs.size()); - const std::vector &resolvedLocsInSourceOrder = - bridgedResolvedLocs.takeUnbridged(); + std::vector resolvedLocsInSourceOrder = + runNameMatcher(SF, UnresolvedLocs); // Callers need to corrolate the `ResolvedLoc` with the `RenameLoc` that they // originated from. Match them. diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index d38b061429e13..b93fe296aa178 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -88,10 +88,6 @@ target_link_libraries(swiftSema PRIVATE swiftSerialization) if (SWIFT_BUILD_SWIFT_SYNTAX) - target_compile_definitions(swiftSema - PRIVATE - SWIFT_BUILD_SWIFT_SYNTAX - ) target_link_libraries(swiftSema PRIVATE swiftASTGen) endif() diff --git a/test/SourceKit/Refactoring/basic.swift b/test/SourceKit/Refactoring/basic.swift index 07c1aaa959841..cd414806678ca 100644 --- a/test/SourceKit/Refactoring/basic.swift +++ b/test/SourceKit/Refactoring/basic.swift @@ -152,7 +152,7 @@ func hasCallToAsyncAlternative(c: ConvertAsync) { // RUN: %sourcekitd-test -req=cursor -pos=95:10 -cursor-action %s -- %s | %FileCheck %s -check-prefix=CHECK-GLOBAL // RUN: %sourcekitd-test -req=cursor -pos=96:10 -cursor-action %s -- %s | %FileCheck %s -check-prefix=CHECK-GLOBAL // RUN: %sourcekitd-test -req=cursor -pos=96:25 -cursor-action %s -- %s | %FileCheck %s -check-prefix=CHECK-GLOBAL -// RUN: %sourcekitd-test -req=cursor -pos=97:11 -cursor-action %s -- %s | %FileCheck %s -check-prefix=CHECK-GLOBAL +// RUN: %sourcekitd-test -req=cursor -pos=97:11 -cursor-action %s -- %s | %FileCheck %s -check-prefix=CHECK-NORENAME // RUN: %sourcekitd-test -req=cursor -pos=97:27 -cursor-action %s -- %s | %FileCheck %s -check-prefix=CHECK-GLOBAL // RUN: %sourcekitd-test -req=cursor -pos=98:11 -cursor-action %s -- %s | %FileCheck %s -check-prefix=CHECK-NORENAME diff --git a/tools/SourceKit/lib/SwiftLang/CMakeLists.txt b/tools/SourceKit/lib/SwiftLang/CMakeLists.txt index 63da43d1fb1f6..31f596e5a0019 100644 --- a/tools/SourceKit/lib/SwiftLang/CMakeLists.txt +++ b/tools/SourceKit/lib/SwiftLang/CMakeLists.txt @@ -68,10 +68,3 @@ target_link_libraries(SourceKitSwiftLang PRIVATE clangAPINotes clangBasic) add_dependencies(SourceKitSwiftLang clang-tablegen-targets) - -if(SWIFT_BUILD_SWIFT_SYNTAX) - target_compile_definitions(SourceKitSwiftLang - PRIVATE - SWIFT_BUILD_SWIFT_SYNTAX - ) -endif()