//===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/NameLookup.h" #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" #include "swift/Frontend/Frontend.h" #include "swift/Frontend/PrintingDiagnosticConsumer.h" #include "swift/IDE/CommentConversion.h" #include "swift/IDE/Utils.h" #include "swift/Markup/XMLUtils.h" #include "swift/Subsystems.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "clang/Index/USRGeneration.h" #include "clang/Lex/Lexer.h" #include "clang/Basic/CharInfo.h" #include "llvm/Support/MemoryBuffer.h" #include using namespace swift; using namespace swift::ide; Optional> swift::ide::parseLineCol(StringRef LineCol) { unsigned Line, Col; size_t ColonIdx = LineCol.find(':'); if (ColonIdx == StringRef::npos) { llvm::errs() << "wrong pos format, it should be ':'\n"; return None; } if (LineCol.substr(0, ColonIdx).getAsInteger(10, Line)) { llvm::errs() << "wrong pos format, it should be ':'\n"; return None; } if (LineCol.substr(ColonIdx+1).getAsInteger(10, Col)) { llvm::errs() << "wrong pos format, it should be ':'\n"; return None; } if (Line == 0 || Col == 0) { llvm::errs() << "wrong pos format, line/col should start from 1\n"; return None; } return std::make_pair(Line, Col); } void XMLEscapingPrinter::printText(StringRef Text) { swift::markup::appendWithXMLEscaping(OS, Text); } void XMLEscapingPrinter::printXML(StringRef Text) { OS << Text; } SourceManager &NameMatcher::getSourceMgr() const { return SrcFile.getASTContext().SourceMgr; } ResolvedLoc NameMatcher::resolve(UnresolvedLoc 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].Loc, Locs[second].Loc); }); // 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(), { ASTWalker::ParentTy(), CharSourceRange(), {}, None, LabelRangeType::None, /*isActice*/true, /*isInSelector*/false}); 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->getAttrs().getAttributes()) { if (shouldSkip(customAttr->getRangeWithAt())) continue; auto *Arg = customAttr->getArg(); 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 { CustomAttrArg = None; }; if (Arg && !Arg->isImplicit()) CustomAttrArg = Located(Arg, Repr->getLoc()); if (!Repr->walk(*this)) return false; } if (Arg && !Arg->isImplicit()) { if (!Arg->walk(*this)) return false; } } return !isDone(); } bool 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()); } } // 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 !isDone(); if (shouldSkip(D->getSourceRangeIncludingAttrs())) return false; if (!handleCustomAttrs(D)) return false; 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 false; } 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, None); } else if (SubscriptDecl *SD = dyn_cast(D)) { tryResolve(ASTWalker::ParentTy(D), D->getLoc(), LabelRangeType::NoncollapsibleParam, getLabelRanges(SD->getIndices(), getSourceMgr()), 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, 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 !isDone(); } bool NameMatcher::walkToDeclPost(Decl *D) { return !isDone(); } std::pair NameMatcher::walkToStmtPre(Stmt *S) { // FIXME: Even implicit Stmts should have proper ranges that include any // non-implicit Stmts (fix Stmts created for lazy vars). if (!S->isImplicit() && shouldSkip(S->getSourceRange())) return std::make_pair(false, isDone()? nullptr : S); return std::make_pair(true, S); } Stmt *NameMatcher::walkToStmtPost(Stmt *S) { if (isDone()) return nullptr; return S; } Expr *NameMatcher::getApplicableArgFor(Expr *E) { if (ParentCalls.empty()) return nullptr; auto &Last = ParentCalls.back(); return Last.ApplicableTo == E ? Last.Call->getArg() : 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; } std::pair NameMatcher::walkToExprPre(Expr *E) { if (shouldSkip(E)) return std::make_pair(false, isDone()? nullptr : 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(), getApplicableArgFor(E)); } break; case ExprKind::DeclRef: { auto DRE = cast(E); tryResolve(ASTWalker::ParentTy(E), DRE->getNameLoc(), getApplicableArgFor(E)); break; } case ExprKind::UnresolvedDeclRef: { auto UDRE = cast(E); tryResolve(ASTWalker::ParentTy(E), UDRE->getNameLoc(), getApplicableArgFor(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::Subscript: { auto SubExpr = cast(E); // visit and check in source order if (!SubExpr->getBase()->walk(*this)) return {false, nullptr}; auto Labels = getCallArgLabelRanges(getSourceMgr(), SubExpr->getIndex(), LabelRangeEndAt::BeforeElemStart); tryResolve(ASTWalker::ParentTy(E), E->getLoc(), LabelRangeType::CallArg, Labels.first, Labels.second); if (isDone()) break; if (!SubExpr->getIndex()->walk(*this)) return {false, nullptr}; // We already visited the children. if (!walkToExprPost(E)) return {false, nullptr}; return {false, E}; } case ExprKind::Paren: { ParenExpr *P = cast(E); // Handle implicit callAsFunction reference on opening paren auto Labels = getCallArgLabelRanges(getSourceMgr(), P, LabelRangeEndAt::BeforeElemStart); tryResolve(ASTWalker::ParentTy(E), P->getLParenLoc(), LabelRangeType::CallArg, Labels.first, Labels.second); break; } case ExprKind::Tuple: { TupleExpr *T = cast(E); // Handle implicit callAsFunction reference on opening paren auto Labels = getCallArgLabelRanges(getSourceMgr(), T, LabelRangeEndAt::BeforeElemStart); tryResolve(ASTWalker::ParentTy(E), T->getLParenLoc(), LabelRangeType::CallArg, Labels.first, Labels.second); if (isDone()) break; // Handle arg label locations (the index reports property occurrences // on them for memberwise inits) for (unsigned i = 0, e = T->getNumElements(); i != e; ++i) { auto Name = T->getElementName(i); if (!Name.empty()) { tryResolve(ASTWalker::ParentTy(E), T->getElementNameLoc(i)); if (isDone()) break; } if (auto *Elem = T->getElement(i)) { if (!Elem->walk(*this)) return {false, nullptr}; } } // We already visited the children. if (!walkToExprPost(E)) return {false, nullptr}; return {false, E}; } case ExprKind::Binary: { BinaryExpr *BinE = cast(E); // Visit in source order. if (!BinE->getArg()->getElement(0)->walk(*this)) return {false, nullptr}; if (!BinE->getFn()->walk(*this)) return {false, nullptr}; if (!BinE->getArg()->getElement(1)->walk(*this)) return {false, nullptr}; // We already visited the children. if (!walkToExprPost(E)) return {false, nullptr}; return {false, E}; } 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: 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 std::make_pair(!isDone(), isDone()? nullptr : E); } Expr *NameMatcher::walkToExprPost(Expr *E) { if (isDone()) return nullptr; 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(), getApplicableArgFor(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 E; } bool NameMatcher::walkToTypeReprPre(TypeRepr *T) { if (isDone() || shouldSkip(T->getSourceRange())) return false; 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 (CustomAttrArg.hasValue() && CustomAttrArg->Loc == T->getLoc()) { auto Labels = getCallArgLabelRanges(getSourceMgr(), CustomAttrArg->Item, LabelRangeEndAt::BeforeElemStart); tryResolve(ASTWalker::ParentTy(T), T->getLoc(), LabelRangeType::CallArg, Labels.first, Labels.second); } else { tryResolve(ASTWalker::ParentTy(T), T->getLoc()); } } return !isDone(); } bool NameMatcher::walkToTypeReprPost(TypeRepr *T) { return !isDone(); } std::pair NameMatcher::walkToPatternPre(Pattern *P) { if (isDone() || shouldSkip(P->getSourceRange())) return std::make_pair(false, P); tryResolve(ASTWalker::ParentTy(P), P->getStartLoc()); return std::make_pair(!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(); ResolvedLocs.push_back({ASTWalker::ParentTy(), CharSourceRange(), {}, None, LabelRangeType::None, isActive(), isInSelector()}); } } } 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().Loc; } 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, Expr *Arg) { if (NameLoc.isInvalid()) return false; if (NameLoc.isCompound()) { auto Labels = getSelectorLabelRanges(getSourceMgr(), NameLoc); bool Resolved = tryResolve(Node, NameLoc.getBaseNameLoc(), LabelRangeType::Selector, Labels, None); if (!isDone()) { for (auto Label: Labels) { if (tryResolve(Node, Label.getStart())) { Resolved = true; if (isDone()) break; } } } return Resolved; } if (LocsToResolve.back().ResolveArgLocs) { if (Arg) { auto Labels = getCallArgLabelRanges(getSourceMgr(), Arg, 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, None, None); } bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc, LabelRangeType RangeType, ArrayRef LabelRanges, Optional FirstTrailingLabel) { skipLocsBefore(NameLoc); if (isDone()) return false; CharSourceRange Range = Lexer::getCharSourceRangeFromSourceRange(getSourceMgr(), NameLoc); UnresolvedLoc &Next = LocsToResolve.back(); bool WasResolved = false; if (Range.isValid()) { if (NameLoc == Next.Loc) { LocsToResolve.pop_back(); ResolvedLocs.push_back({Node, Range, LabelRanges, FirstTrailingLabel, RangeType, isActive(), isInSelector()}); 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.Loc) { LocsToResolve.pop_back(); ResolvedLocs.push_back({Node, NewRange, {}, None, LabelRangeType::None, isActive(), isInSelector()}); WasResolved = true; } } } return WasResolved; }; void ResolvedRangeInfo::print(llvm::raw_ostream &OS) const { OS << ""; switch (Kind) { case RangeKind::SingleExpression: OS << "SingleExpression"; break; case RangeKind::SingleDecl: OS << "SingleDecl"; break; case RangeKind::MultiTypeMemberDecl: OS << "MultiTypeMemberDecl"; break; case RangeKind::MultiStatement: OS << "MultiStatement"; break; case RangeKind::PartOfExpression: OS << "PartOfExpression"; break; case RangeKind::SingleStatement: OS << "SingleStatement"; break; case RangeKind::Invalid: OS << "Invalid"; break; } OS << "\n"; OS << "" << ContentRange.str() << "\n"; if (auto Ty = getType()) { OS << ""; Ty->print(OS); OS << ""; switch(exit()) { case ExitState::Positive: OS << "true"; break; case ExitState::Unsure: OS << "unsure"; break; case ExitState::Negative: OS << "false"; break; } OS << "\n"; } if (RangeContext) { OS << ""; printContext(OS, RangeContext); OS << "\n"; } if (CommonExprParent) { OS << ""; OS << Expr::getKindName(CommonExprParent->getKind()); OS << "\n"; } if (!HasSingleEntry) { OS << "Multi\n"; } if (ThrowingUnhandledError) { OS << "Throwing\n"; } if (Orphan != OrphanKind::None) { OS << ""; switch (Orphan) { case OrphanKind::Continue: OS << "Continue"; break; case OrphanKind::Break: OS << "Break"; break; case OrphanKind::None: llvm_unreachable("cannot enter here."); } OS << ""; } for (auto &VD : DeclaredDecls) { OS << "" << VD.VD->getBaseName() << ""; OS << ""; if (VD.ReferredAfterRange) OS << "true"; else OS << "false"; OS << "\n"; } for (auto &RD : ReferencedDecls) { OS << "" << RD.VD->getBaseName() << ""; OS << ""; RD.Ty->print(OS); OS << "\n"; } OS << "" << ContainedNodes.size() << "\n"; OS << "\n"; } CharSourceRange ResolvedRangeInfo:: calculateContentRange(ArrayRef Tokens) { if (Tokens.empty()) return CharSourceRange(); auto StartTok = Tokens.front(); auto EndTok = Tokens.back(); auto StartLoc = StartTok.hasComment() ? StartTok.getCommentStart() : StartTok.getLoc(); auto EndLoc = EndTok.getRange().getEnd(); auto Length = static_cast(EndLoc.getOpaquePointerValue()) - static_cast(StartLoc.getOpaquePointerValue()); return CharSourceRange(StartLoc, Length); } bool DeclaredDecl::operator==(const DeclaredDecl& Other) { return VD == Other.VD; } ReturnInfo:: ReturnInfo(ASTContext &Ctx, ArrayRef Branches): ReturnType(Ctx.TheErrorType.getPointer()), Exit(ExitState::Unsure) { std::set AllTypes; std::set AllExitStates; for (auto I : Branches) { AllTypes.insert(I.ReturnType); AllExitStates.insert(I.Exit); } if (AllTypes.size() == 1) { ReturnType = *AllTypes.begin(); } if (AllExitStates.size() == 1) { Exit = *AllExitStates.begin(); } } void swift::ide::getLocationInfoForClangNode(ClangNode ClangNode, ClangImporter *Importer, llvm::Optional> &DeclarationLoc, StringRef &Filename) { clang::ASTContext &ClangCtx = Importer->getClangASTContext(); clang::SourceManager &ClangSM = ClangCtx.getSourceManager(); clang::SourceRange SR = ClangNode.getLocation(); if (auto MD = dyn_cast_or_null(ClangNode.getAsDecl())) { SR = clang::SourceRange(MD->getSelectorStartLoc(), MD->getDeclaratorEndLoc()); } clang::CharSourceRange CharRange = clang::Lexer::makeFileCharRange(clang::CharSourceRange::getTokenRange(SR), ClangSM, ClangCtx.getLangOpts()); if (CharRange.isInvalid()) return; std::pair Decomp = ClangSM.getDecomposedLoc(CharRange.getBegin()); if (!Decomp.first.isInvalid()) { if (auto FE = ClangSM.getFileEntryForID(Decomp.first)) { Filename = FE->getName(); std::pair EndDecomp = ClangSM.getDecomposedLoc(CharRange.getEnd()); DeclarationLoc = { Decomp.second, EndDecomp.second-Decomp.second }; } } } static unsigned getCharLength(SourceManager &SM, SourceRange TokenRange) { SourceLoc CharEndLoc = Lexer::getLocForEndOfToken(SM, TokenRange.End); return SM.getByteDistance(TokenRange.Start, CharEndLoc); } void swift::ide::getLocationInfo(const ValueDecl *VD, llvm::Optional> &DeclarationLoc, StringRef &Filename) { ASTContext &Ctx = VD->getASTContext(); SourceManager &SM = Ctx.SourceMgr; auto ClangNode = VD->getClangNode(); if (VD->getLoc().isValid()) { auto getSignatureRange = [&](const ValueDecl *VD) -> Optional { if (auto FD = dyn_cast(VD)) { SourceRange R = FD->getSignatureSourceRange(); if (R.isValid()) return getCharLength(SM, R); } return None; }; unsigned NameLen; if (auto SigLen = getSignatureRange(VD)) { NameLen = SigLen.getValue(); } else if (VD->hasName()) { NameLen = VD->getBaseName().userFacingName().size(); } else { NameLen = getCharLength(SM, VD->getLoc()); } unsigned DeclBufID = SM.findBufferContainingLoc(VD->getLoc()); DeclarationLoc = { SM.getLocOffsetInBuffer(VD->getLoc(), DeclBufID), NameLen }; Filename = SM.getIdentifierForBuffer(DeclBufID); } else if (ClangNode) { ClangImporter *Importer = static_cast(Ctx.getClangModuleLoader()); return getLocationInfoForClangNode(ClangNode, Importer, DeclarationLoc, Filename); } } CharSourceRange CallArgInfo::getEntireCharRange(const SourceManager &SM) const { return CharSourceRange(SM, LabelRange.getStart(), Lexer::getLocForEndOfToken(SM, ArgExp->getEndLoc())); } static Expr* getSingleNonImplicitChild(Expr *Parent) { // If this expr is non-implicit, we are done. if (!Parent->isImplicit()) return Parent; // Collect all immediate children. llvm::SmallVector Children; Parent->forEachImmediateChildExpr([&](Expr *E) { Children.push_back(E); return E; }); // If more than one children are found, we are not sure the non-implicit node. if (Children.size() != 1) return Parent; // Dig deeper if necessary. return getSingleNonImplicitChild(Children[0]); } std::vector swift::ide:: getCallArgInfo(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind) { std::vector InfoVec; if (auto *TE = dyn_cast(Arg)) { auto FirstTrailing = TE->getUnlabeledTrailingClosureIndexOfPackedArgument(); for (size_t ElemIndex: range(TE->getNumElements())) { Expr *Elem = TE->getElement(ElemIndex); if (isa(Elem)) continue; SourceLoc LabelStart(Elem->getStartLoc()); SourceLoc LabelEnd(LabelStart); bool IsTrailingClosure = FirstTrailing && ElemIndex >= *FirstTrailing; SourceLoc NameLoc = TE->getElementNameLoc(ElemIndex); if (NameLoc.isValid()) { LabelStart = NameLoc; if (EndKind == LabelRangeEndAt::LabelNameOnly || IsTrailingClosure) { LabelEnd = Lexer::getLocForEndOfToken(SM, NameLoc); } } InfoVec.push_back({getSingleNonImplicitChild(Elem), CharSourceRange(SM, LabelStart, LabelEnd), IsTrailingClosure}); } } else if (auto *PE = dyn_cast(Arg)) { Expr *Sub = PE->getSubExpr(); if (Sub && !isa(Sub)) InfoVec.push_back({getSingleNonImplicitChild(Sub), CharSourceRange(Sub->getStartLoc(), 0), PE->hasTrailingClosure() }); } return InfoVec; } std::pair, Optional> swift::ide:: getCallArgLabelRanges(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind) { std::vector Ranges; auto InfoVec = getCallArgInfo(SM, Arg, EndKind); Optional FirstTrailing; auto I = std::find_if(InfoVec.begin(), InfoVec.end(), [](CallArgInfo &Info) { return Info.IsTrailingClosure; }); if (I != InfoVec.end()) FirstTrailing = std::distance(InfoVec.begin(), I); llvm::transform(InfoVec, std::back_inserter(Ranges), [](CallArgInfo &Info) { return Info.LabelRange; }); return {Ranges, FirstTrailing}; }