//===----------------------------------------------------------------------===// // // 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; std::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 std::nullopt; } if (LineCol.substr(0, ColonIdx).getAsInteger(10, Line)) { llvm::errs() << "wrong pos format, it should be ':'\n"; return std::nullopt; } if (LineCol.substr(ColonIdx+1).getAsInteger(10, Col)) { llvm::errs() << "wrong pos format, it should be ':'\n"; return std::nullopt; } if (Line == 0 || Col == 0) { llvm::errs() << "wrong pos format, line/col should start from 1\n"; return std::nullopt; } return std::make_pair(Line, Col); } void XMLEscapingPrinter::printText(StringRef Text) { swift::markup::appendWithXMLEscaping(OS, Text); } void XMLEscapingPrinter::printXML(StringRef Text) { OS << Text; } void ResolvedRangeInfo::print(llvm::raw_ostream &OS, const PrintOptions &PO) 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, PO); 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 (UnhandledEffects.contains(EffectKind::Throws)) { OS << "Throwing\n"; } if (UnhandledEffects.contains(EffectKind::Async)) { OS << "Async\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, PO); 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) const { 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(); } } 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, ArgumentList *Args, LabelRangeEndAt EndKind) { std::vector InfoVec; auto *OriginalArgs = Args->getOriginalArgs(); for (auto ElemIndex : indices(*OriginalArgs)) { auto *Elem = OriginalArgs->getExpr(ElemIndex); SourceLoc LabelStart(Elem->getStartLoc()); SourceLoc LabelEnd(LabelStart); bool IsTrailingClosure = OriginalArgs->isTrailingClosureIndex(ElemIndex); auto NameLoc = OriginalArgs->getLabelLoc(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}); } return InfoVec; } std::pair, std::optional> swift::ide::getCallArgLabelRanges(SourceManager &SM, ArgumentList *Args, LabelRangeEndAt EndKind) { std::vector Ranges; auto InfoVec = getCallArgInfo(SM, Args, EndKind); std::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}; }