mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
LLVM has removed llvm::Optional, move over to std::optional. Also clang-format to fix up all the renamed #includes.
260 lines
7.8 KiB
C++
260 lines
7.8 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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 <numeric>
|
|
|
|
using namespace swift;
|
|
using namespace swift::ide;
|
|
|
|
std::optional<std::pair<unsigned, unsigned>>
|
|
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 '<line>:<column>'\n";
|
|
return std::nullopt;
|
|
}
|
|
if (LineCol.substr(0, ColonIdx).getAsInteger(10, Line)) {
|
|
llvm::errs() << "wrong pos format, it should be '<line>:<column>'\n";
|
|
return std::nullopt;
|
|
}
|
|
if (LineCol.substr(ColonIdx+1).getAsInteger(10, Col)) {
|
|
llvm::errs() << "wrong pos format, it should be '<line>:<column>'\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 {
|
|
OS << "<Kind>";
|
|
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 << "</Kind>\n";
|
|
|
|
OS << "<Content>" << ContentRange.str() << "</Content>\n";
|
|
|
|
if (auto Ty = getType()) {
|
|
OS << "<Type>";
|
|
Ty->print(OS);
|
|
OS << "</Type>";
|
|
switch(exit()) {
|
|
case ExitState::Positive: OS << "<Exit>true</Exit>"; break;
|
|
case ExitState::Unsure: OS << "<Exit>unsure</Exit>"; break;
|
|
case ExitState::Negative: OS << "<Exit>false</Exit>"; break;
|
|
}
|
|
OS << "\n";
|
|
}
|
|
|
|
if (RangeContext) {
|
|
OS << "<Context>";
|
|
printContext(OS, RangeContext);
|
|
OS << "</Context>\n";
|
|
}
|
|
|
|
if (CommonExprParent) {
|
|
OS << "<Parent>";
|
|
OS << Expr::getKindName(CommonExprParent->getKind());
|
|
OS << "</Parent>\n";
|
|
}
|
|
|
|
if (!HasSingleEntry) {
|
|
OS << "<Entry>Multi</Entry>\n";
|
|
}
|
|
|
|
if (UnhandledEffects.contains(EffectKind::Throws)) {
|
|
OS << "<Error>Throwing</Error>\n";
|
|
}
|
|
if (UnhandledEffects.contains(EffectKind::Async)) {
|
|
OS << "<Effect>Async</Effect>\n";
|
|
}
|
|
|
|
if (Orphan != OrphanKind::None) {
|
|
OS << "<Orphan>";
|
|
switch (Orphan) {
|
|
case OrphanKind::Continue:
|
|
OS << "Continue";
|
|
break;
|
|
case OrphanKind::Break:
|
|
OS << "Break";
|
|
break;
|
|
case OrphanKind::None:
|
|
llvm_unreachable("cannot enter here.");
|
|
}
|
|
OS << "</Orphan>";
|
|
}
|
|
|
|
for (auto &VD : DeclaredDecls) {
|
|
OS << "<Declared>" << VD.VD->getBaseName() << "</Declared>";
|
|
OS << "<OutscopeReference>";
|
|
if (VD.ReferredAfterRange)
|
|
OS << "true";
|
|
else
|
|
OS << "false";
|
|
OS << "</OutscopeReference>\n";
|
|
}
|
|
for (auto &RD : ReferencedDecls) {
|
|
OS << "<Referenced>" << RD.VD->getBaseName() << "</Referenced>";
|
|
OS << "<Type>";
|
|
RD.Ty->print(OS);
|
|
OS << "</Type>\n";
|
|
}
|
|
|
|
OS << "<ASTNodes>" << ContainedNodes.size() << "</ASTNodes>\n";
|
|
OS << "<end>\n";
|
|
}
|
|
|
|
CharSourceRange ResolvedRangeInfo::
|
|
calculateContentRange(ArrayRef<Token> 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<const char *>(EndLoc.getOpaquePointerValue()) -
|
|
static_cast<const char *>(StartLoc.getOpaquePointerValue());
|
|
return CharSourceRange(StartLoc, Length);
|
|
}
|
|
|
|
bool DeclaredDecl::operator==(const DeclaredDecl& Other) const {
|
|
return VD == Other.VD;
|
|
}
|
|
|
|
ReturnInfo::
|
|
ReturnInfo(ASTContext &Ctx, ArrayRef<ReturnInfo> Branches):
|
|
ReturnType(Ctx.TheErrorType.getPointer()), Exit(ExitState::Unsure) {
|
|
std::set<TypeBase*> AllTypes;
|
|
std::set<ExitState> 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<Expr*, 4> 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<CallArgInfo> swift::ide::
|
|
getCallArgInfo(SourceManager &SM, ArgumentList *Args, LabelRangeEndAt EndKind) {
|
|
std::vector<CallArgInfo> 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::vector<CharSourceRange>, std::optional<unsigned>>
|
|
swift::ide::getCallArgLabelRanges(SourceManager &SM, ArgumentList *Args,
|
|
LabelRangeEndAt EndKind) {
|
|
std::vector<CharSourceRange> Ranges;
|
|
auto InfoVec = getCallArgInfo(SM, Args, EndKind);
|
|
|
|
std::optional<unsigned> 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};
|
|
}
|