本文整理汇总了C++中SourceLoc::isInvalid方法的典型用法代码示例。如果您正苦于以下问题:C++ SourceLoc::isInvalid方法的具体用法?C++ SourceLoc::isInvalid怎么用?C++ SourceLoc::isInvalid使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类SourceLoc
的用法示例。
在下文中一共展示了SourceLoc::isInvalid方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: getDeclStartPosition
static SourceLoc getDeclStartPosition(SourceFile &File) {
SourceManager &SM = File.getASTContext().SourceMgr;
SourceLoc Winner;
auto tryUpdateStart = [&](SourceLoc Loc) -> bool {
if (Loc.isInvalid())
return false;
if (Winner.isInvalid()) {
Winner = Loc;
return true;
}
if (SM.isBeforeInBuffer(Loc, Winner)) {
Winner = Loc;
return true;
}
return false;
};
for (auto D : File.Decls) {
if (tryUpdateStart(D->getStartLoc())) {
tryUpdateStart(D->getAttrs().getStartLoc());
auto RawComment = D->getRawComment();
if (!RawComment.isEmpty())
tryUpdateStart(RawComment.Comments.front().Range.getStart());
}
}
return Winner;
}
示例2: passCallArgNames
bool SemaAnnotator::passCallArgNames(Expr *Fn, TupleExpr *TupleE) {
ValueDecl *D = extractDecl(Fn);
if (!D)
return true; // continue.
ArrayRef<Identifier> ArgNames = TupleE->getElementNames();
ArrayRef<SourceLoc> ArgLocs = TupleE->getElementNameLocs();
for (auto i : indices(ArgNames)) {
Identifier Name = ArgNames[i];
if (Name.empty())
continue;
SourceLoc Loc = ArgLocs[i];
if (Loc.isInvalid())
continue;
CharSourceRange Range{ Loc, Name.getLength() };
bool Continue = SEWalker.visitCallArgName(Name, Range, D);
if (!Continue) {
Cancelled = true;
return false;
}
}
return true;
}
示例3: getLineNumber
static unsigned getLineNumber(DCType *DC) {
SourceLoc loc = DC->getLoc();
if (loc.isInvalid())
return 0;
const ASTContext &ctx = static_cast<const DeclContext *>(DC)->getASTContext();
return ctx.SourceMgr.getLineAndColumn(loc).first;
}
示例4: addLocToRecord
void SerializedDiagnosticConsumer::
emitDiagnosticMessage(SourceManager &SM,
SourceLoc Loc,
DiagnosticKind Kind,
StringRef Text,
const DiagnosticInfo &Info) {
// Emit the diagnostic to bitcode.
llvm::BitstreamWriter &Stream = State->Stream;
RecordData &Record = State->Record;
AbbreviationMap &Abbrevs = State->Abbrevs;
StringRef filename = "";
if (Loc.isValid())
filename = SM.getIdentifierForBuffer(SM.findBufferContainingLoc(Loc));
// Emit the RECORD_DIAG record.
Record.clear();
Record.push_back(RECORD_DIAG);
Record.push_back(getDiagnosticLevel(Kind));
addLocToRecord(Loc, SM, filename, Record);
// FIXME: Swift diagnostics currently have no category.
Record.push_back(0);
// FIXME: Swift diagnostics currently have no flags.
Record.push_back(0);
// Emit the message.
Record.push_back(Text.size());
Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Text);
// If the location is invalid, do not emit source ranges or fixits.
if (Loc.isInvalid())
return;
// Emit source ranges.
auto RangeAbbrev = State->Abbrevs.get(RECORD_SOURCE_RANGE);
for (const auto &R : Info.Ranges) {
if (R.isInvalid())
continue;
State->Record.clear();
State->Record.push_back(RECORD_SOURCE_RANGE);
addRangeToRecord(R, SM, filename, State->Record);
State->Stream.EmitRecordWithAbbrev(RangeAbbrev, State->Record);
}
// Emit FixIts.
auto FixItAbbrev = State->Abbrevs.get(RECORD_FIXIT);
for (const auto &F : Info.FixIts) {
if (F.getRange().isValid()) {
State->Record.clear();
State->Record.push_back(RECORD_FIXIT);
addRangeToRecord(F.getRange(), SM, filename, State->Record);
State->Record.push_back(F.getText().size());
Stream.EmitRecordWithBlob(FixItAbbrev, Record, F.getText());
}
}
}
示例5: lookupVisibleDecls
void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer,
const DeclContext *DC,
LazyResolver *TypeResolver,
bool IncludeTopLevel,
SourceLoc Loc) {
if (Loc.isInvalid()) {
lookupVisibleDeclsImpl(Consumer, DC, TypeResolver, IncludeTopLevel, Loc);
return;
}
// Filtering out unusable values.
class LocalConsumer : public VisibleDeclConsumer {
const SourceManager &SM;
SourceLoc Loc;
VisibleDeclConsumer &Consumer;
bool isUsableValue(ValueDecl *VD, DeclVisibilityKind Reason) {
// Check "use within its own initial value" case.
if (auto *varD = dyn_cast<VarDecl>(VD))
if (auto *PBD = varD->getParentPatternBinding())
if (!PBD->isImplicit() &&
SM.rangeContainsTokenLoc(PBD->getSourceRange(), Loc))
return false;
switch (Reason) {
case DeclVisibilityKind::LocalVariable:
// Use of 'TypeDecl's before declaration is allowed.
if (isa<TypeDecl>(VD))
return true;
return SM.isBeforeInBuffer(VD->getLoc(), Loc);
case DeclVisibilityKind::VisibleAtTopLevel:
// TODO: Implement forward reference rule for script mode? Currently,
// it's not needed because the rest of the file hasn't been parsed.
// See: https://bugs.swift.org/browse/SR-284 for the rule.
return true;
default:
// Other visibility kind are always usable.
return true;
}
}
public:
LocalConsumer(const SourceManager &SM, SourceLoc Loc,
VisibleDeclConsumer &Consumer)
: SM(SM), Loc(Loc), Consumer(Consumer) {}
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) {
if (isUsableValue(VD, Reason))
Consumer.foundDecl(VD, Reason);
}
} LocalConsumer(DC->getASTContext().SourceMgr, Loc, Consumer);
lookupVisibleDeclsImpl(LocalConsumer, DC, TypeResolver, IncludeTopLevel, Loc);
}
示例6: handlePrimaryAST
void handlePrimaryAST(ASTUnitRef AstUnit) override {
auto &CompInst = AstUnit->getCompilerInstance();
auto &SrcFile = AstUnit->getPrimarySourceFile();
trace::TracedOperation TracedOp;
SmallVector<std::pair<unsigned, unsigned>, 8> Ranges;
auto Action = [&]() {
if (trace::enabled()) {
trace::SwiftInvocation SwiftArgs;
Invok->raw(SwiftArgs.Args.Args, SwiftArgs.Args.PrimaryFile);
trace::initTraceFiles(SwiftArgs, CompInst);
TracedOp.start(trace::OperationKind::RelatedIdents, SwiftArgs,
{std::make_pair("Offset", std::to_string(Offset))});
}
unsigned BufferID = SrcFile.getBufferID().getValue();
SourceLoc Loc =
Lexer::getLocForStartOfToken(CompInst.getSourceMgr(), BufferID, Offset);
if (Loc.isInvalid())
return;
SemaLocResolver Resolver(SrcFile);
SemaToken SemaTok = Resolver.resolve(Loc);
if (SemaTok.isInvalid())
return;
if (SemaTok.IsKeywordArgument)
return;
ValueDecl *VD = SemaTok.CtorTyRef ? SemaTok.CtorTyRef : SemaTok.ValueD;
if (!VD)
return; // This was a module reference.
// Only accept pointing to an identifier.
if (!SemaTok.IsRef &&
(isa<ConstructorDecl>(VD) ||
isa<DestructorDecl>(VD) ||
isa<SubscriptDecl>(VD)))
return;
if (VD->getName().isOperator())
return;
RelatedIdScanner Scanner(SrcFile, BufferID, VD, Ranges);
if (DeclContext *LocalDC = VD->getDeclContext()->getLocalContext()) {
Scanner.walk(LocalDC);
} else {
Scanner.walk(SrcFile);
}
};
Action();
RelatedIdentsInfo Info;
Info.Ranges = Ranges;
Receiver(Info);
}
示例7: assert
Optional<FileSpecificDiagnosticConsumer::Subconsumer *>
FileSpecificDiagnosticConsumer::subconsumerForLocation(SourceManager &SM,
SourceLoc loc) {
// Diagnostics with invalid locations always go to every consumer.
if (loc.isInvalid())
return None;
// What if a there's a FileSpecificDiagnosticConsumer but there are no
// subconsumers in it? (This situation occurs for the fix-its
// FileSpecificDiagnosticConsumer.) In such a case, bail out now.
if (Subconsumers.empty())
return None;
// This map is generated on first use and cached, to allow the
// FileSpecificDiagnosticConsumer to be set up before the source files are
// actually loaded.
if (ConsumersOrderedByRange.empty()) {
// It's possible to get here while a bridging header PCH is being
// attached-to, if there's some sort of AST-reader warning or error, which
// happens before CompilerInstance::setUpInputs(), at which point _no_
// source buffers are loaded in yet. In that case we return None, rather
// than trying to build a nonsensical map (and actually crashing since we
// can't find buffers for the inputs).
assert(!Subconsumers.empty());
if (!SM.getIDForBufferIdentifier(Subconsumers.begin()->getInputFileName())
.hasValue()) {
assert(llvm::none_of(Subconsumers, [&](const Subconsumer &subconsumer) {
return SM.getIDForBufferIdentifier(subconsumer.getInputFileName())
.hasValue();
}));
return None;
}
auto *mutableThis = const_cast<FileSpecificDiagnosticConsumer*>(this);
mutableThis->computeConsumersOrderedByRange(SM);
}
// This std::lower_bound call is doing a binary search for the first range
// that /might/ contain 'loc'. Specifically, since the ranges are sorted
// by end location, it's looking for the first range where the end location
// is greater than or equal to 'loc'.
const ConsumerAndRange *possiblyContainingRangeIter = std::lower_bound(
ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(), loc,
[](const ConsumerAndRange &entry, SourceLoc loc) -> bool {
return entry.endsAfter(loc);
});
if (possiblyContainingRangeIter != ConsumersOrderedByRange.end() &&
possiblyContainingRangeIter->contains(loc)) {
auto *consumerAndRangeForLocation =
const_cast<ConsumerAndRange *>(possiblyContainingRangeIter);
return &(*this)[*consumerAndRangeForLocation];
}
return None;
}
示例8: compare
Optional<FileSpecificDiagnosticConsumer::ConsumerSpecificInformation *>
FileSpecificDiagnosticConsumer::consumerSpecificInformationForLocation(
SourceManager &SM, SourceLoc loc) const {
// Diagnostics with invalid locations always go to every consumer.
if (loc.isInvalid())
return None;
// This map is generated on first use and cached, to allow the
// FileSpecificDiagnosticConsumer to be set up before the source files are
// actually loaded.
if (ConsumersOrderedByRange.empty()) {
// It's possible to get here while a bridging header PCH is being
// attached-to, if there's some sort of AST-reader warning or error, which
// happens before CompilerInstance::setUpInputs(), at which point _no_
// source buffers are loaded in yet. In that case we return None, rather
// than trying to build a nonsensical map (and actually crashing since we
// can't find buffers for the inputs).
assert(!SubConsumers.empty());
if (!SM.getIDForBufferIdentifier(SubConsumers.begin()->first).hasValue()) {
assert(llvm::none_of(SubConsumers, [&](const ConsumerPair &pair) {
return SM.getIDForBufferIdentifier(pair.first).hasValue();
}));
return None;
}
auto *mutableThis = const_cast<FileSpecificDiagnosticConsumer*>(this);
mutableThis->computeConsumersOrderedByRange(SM);
}
// This std::lower_bound call is doing a binary search for the first range
// that /might/ contain 'loc'. Specifically, since the ranges are sorted
// by end location, it's looking for the first range where the end location
// is greater than or equal to 'loc'.
const ConsumerSpecificInformation *possiblyContainingRangeIter =
std::lower_bound(
ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(), loc,
[](const ConsumerSpecificInformation &entry, SourceLoc loc) -> bool {
auto compare = std::less<const char *>();
return compare(getRawLoc(entry.range.getEnd()).getPointer(),
getRawLoc(loc).getPointer());
});
if (possiblyContainingRangeIter != ConsumersOrderedByRange.end() &&
possiblyContainingRangeIter->range.contains(loc)) {
return const_cast<ConsumerSpecificInformation *>(
possiblyContainingRangeIter);
}
return None;
}
示例9: subconsumerForLocation
Optional<FileSpecificDiagnosticConsumer::Subconsumer *>
FileSpecificDiagnosticConsumer::findSubconsumerForNonNote(
SourceManager &SM, const SourceLoc loc,
const SourceLoc bufferIndirectlyCausingDiagnostic) {
const auto subconsumer = subconsumerForLocation(SM, loc);
if (!subconsumer)
return None; // No place to put it; might be in an imported module
if ((*subconsumer)->getConsumer())
return subconsumer; // A primary file with a .dia file
// Try to put it in the responsible primary input
if (bufferIndirectlyCausingDiagnostic.isInvalid())
return None;
const auto currentPrimarySubconsumer =
subconsumerForLocation(SM, bufferIndirectlyCausingDiagnostic);
assert(!currentPrimarySubconsumer ||
(*currentPrimarySubconsumer)->getConsumer() &&
"current primary must have a .dia file");
return currentPrimarySubconsumer;
}
示例10: startEntityRef
bool IndexSwiftASTWalker::startEntityRef(ValueDecl *D, SourceLoc Loc) {
if (!shouldIndex(D))
return false;
if (Loc.isInvalid())
return false;
if (isa<AbstractFunctionDecl>(D)) {
CallRefEntityInfo Info;
if (initCallRefEntityInfo(ExprStack.back(), getParentExpr(), D, Loc, Info))
return false;
return startEntity(D, Info);
} else {
EntityInfo Info;
if (initEntityInfo(D, Loc, /*isRef=*/true, Info))
return false;
return startEntity(D, Info);
}
}
示例11: startEntityDecl
bool IndexSwiftASTWalker::startEntityDecl(ValueDecl *D) {
if (!shouldIndex(D))
return false;
SourceLoc Loc = D->getLoc();
if (Loc.isInvalid() && !IsModuleFile)
return false;
if (isa<FuncDecl>(D)) {
FuncDeclEntityInfo Info;
if (initFuncDeclEntityInfo(D, Info))
return false;
return startEntity(D, Info);
} else {
EntityInfo Info;
if (initEntityInfo(D, Loc, /*isRef=*/false, Info))
return false;
return startEntity(D, Info);
}
}
示例12: emitDiagnostic
void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
auto behavior = state.determineBehavior(diagnostic.getID());
if (behavior == DiagnosticState::Behavior::Ignore)
return;
// Figure out the source location.
SourceLoc loc = diagnostic.getLoc();
if (loc.isInvalid() && diagnostic.getDecl()) {
const Decl *decl = diagnostic.getDecl();
// If a declaration was provided instead of a location, and that declaration
// has a location we can point to, use that location.
loc = decl->getLoc();
if (loc.isInvalid()) {
// There is no location we can point to. Pretty-print the declaration
// so we can point to it.
SourceLoc ppLoc = PrettyPrintedDeclarations[decl];
if (ppLoc.isInvalid()) {
class TrackingPrinter : public StreamPrinter {
SmallVectorImpl<std::pair<const Decl *, uint64_t>> &Entries;
public:
TrackingPrinter(
SmallVectorImpl<std::pair<const Decl *, uint64_t>> &Entries,
raw_ostream &OS) :
StreamPrinter(OS), Entries(Entries) {}
void printDeclLoc(const Decl *D) override {
Entries.push_back({ D, OS.tell() });
}
};
SmallVector<std::pair<const Decl *, uint64_t>, 8> entries;
llvm::SmallString<128> buffer;
llvm::SmallString<128> bufferName;
{
// Figure out which declaration to print. It's the top-most
// declaration (not a module).
const Decl *ppDecl = decl;
auto dc = decl->getDeclContext();
// FIXME: Horrible, horrible hackaround. We're not getting a
// DeclContext everywhere we should.
if (!dc) {
return;
}
while (!dc->isModuleContext()) {
switch (dc->getContextKind()) {
case DeclContextKind::Module:
llvm_unreachable("Not in a module context!");
break;
case DeclContextKind::FileUnit:
case DeclContextKind::TopLevelCodeDecl:
break;
case DeclContextKind::ExtensionDecl:
ppDecl = cast<ExtensionDecl>(dc);
break;
case DeclContextKind::GenericTypeDecl:
ppDecl = cast<GenericTypeDecl>(dc);
break;
case DeclContextKind::SerializedLocal:
case DeclContextKind::Initializer:
case DeclContextKind::AbstractClosureExpr:
case DeclContextKind::AbstractFunctionDecl:
case DeclContextKind::SubscriptDecl:
break;
}
dc = dc->getParent();
}
// Build the module name path (in reverse), which we use to
// build the name of the buffer.
SmallVector<StringRef, 4> nameComponents;
while (dc) {
nameComponents.push_back(cast<Module>(dc)->getName().str());
dc = dc->getParent();
}
for (unsigned i = nameComponents.size(); i; --i) {
bufferName += nameComponents[i-1];
bufferName += '.';
}
if (auto value = dyn_cast<ValueDecl>(ppDecl)) {
bufferName += value->getNameStr();
} else if (auto ext = dyn_cast<ExtensionDecl>(ppDecl)) {
bufferName += ext->getExtendedType().getString();
}
// Pretty-print the declaration we've picked.
llvm::raw_svector_ostream out(buffer);
TrackingPrinter printer(entries, out);
ppDecl->print(printer, PrintOptions::printForDiagnostics());
}
//.........这里部分代码省略.........
示例13: fixItChangeInoutArgType
void AssignmentFailure::fixItChangeInoutArgType(const Expr *arg,
Type actualType,
Type neededType) const {
auto *DC = getDC();
auto *DRE = dyn_cast<DeclRefExpr>(arg);
if (!DRE)
return;
auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl());
if (!VD)
return;
// Don't emit for non-local variables.
// (But in script-mode files, we consider module-scoped
// variables in the same file to be local variables.)
auto VDC = VD->getDeclContext();
bool isLocalVar = VDC->isLocalContext();
if (!isLocalVar && VDC->isModuleScopeContext()) {
auto argFile = DC->getParentSourceFile();
auto varFile = VDC->getParentSourceFile();
isLocalVar = (argFile == varFile && argFile->isScriptMode());
}
if (!isLocalVar)
return;
SmallString<32> scratch;
SourceLoc endLoc; // Filled in if we decide to diagnose this
SourceLoc startLoc; // Left invalid if we're inserting
auto isSimpleTypelessPattern = [](Pattern *P) -> bool {
if (auto VP = dyn_cast_or_null<VarPattern>(P))
P = VP->getSubPattern();
return P && isa<NamedPattern>(P);
};
auto typeRange = VD->getTypeSourceRangeForDiagnostics();
if (typeRange.isValid()) {
startLoc = typeRange.Start;
endLoc = typeRange.End;
} else if (isSimpleTypelessPattern(VD->getParentPattern())) {
endLoc = VD->getNameLoc();
scratch += ": ";
}
if (endLoc.isInvalid())
return;
scratch += neededType.getString();
// Adjust into the location where we actually want to insert
endLoc = Lexer::getLocForEndOfToken(getASTContext().SourceMgr, endLoc);
// Since we already adjusted endLoc, this will turn an insertion
// into a zero-character replacement.
if (!startLoc.isValid())
startLoc = endLoc;
emitDiagnostic(VD->getLoc(), diag::inout_change_var_type_if_possible,
actualType, neededType)
.fixItReplaceChars(startLoc, endLoc, scratch);
}
示例14: ParserStatus
ParserStatus
Parser::parseParameterClause(SourceLoc &leftParenLoc,
SmallVectorImpl<ParsedParameter> ¶ms,
SourceLoc &rightParenLoc,
DefaultArgumentInfo *defaultArgs,
ParameterContextKind paramContext) {
assert(params.empty() && leftParenLoc.isInvalid() &&
rightParenLoc.isInvalid() && "Must start with empty state");
// Consume the starting '(';
leftParenLoc = consumeToken(tok::l_paren);
// Trivial case: empty parameter list.
if (Tok.is(tok::r_paren)) {
rightParenLoc = consumeToken(tok::r_paren);
return ParserStatus();
}
// Parse the parameter list.
bool isClosure = paramContext == ParameterContextKind::Closure;
return parseList(tok::r_paren, leftParenLoc, rightParenLoc, tok::comma,
/*OptionalSep=*/false, /*AllowSepAfterLast=*/false,
diag::expected_rparen_parameter,
[&]() -> ParserStatus {
ParsedParameter param;
ParserStatus status;
SourceLoc StartLoc = Tok.getLoc();
unsigned defaultArgIndex = defaultArgs ? defaultArgs->NextIndex++ : 0;
// Attributes.
bool FoundCCToken;
parseDeclAttributeList(param.Attrs, FoundCCToken,
/*stop at type attributes*/true, true);
if (FoundCCToken) {
if (CodeCompletion) {
CodeCompletion->completeDeclAttrKeyword(nullptr, isInSILMode(), true);
} else {
status |= makeParserCodeCompletionStatus();
}
}
// ('inout' | 'let' | 'var')?
if (Tok.is(tok::kw_inout)) {
param.LetVarInOutLoc = consumeToken();
param.SpecifierKind = ParsedParameter::InOut;
} else if (Tok.is(tok::kw_let)) {
param.LetVarInOutLoc = consumeToken();
param.SpecifierKind = ParsedParameter::Let;
} else if (Tok.is(tok::kw_var)) {
diagnose(Tok.getLoc(), diag::var_parameter_not_allowed)
.fixItRemove(Tok.getLoc());
param.LetVarInOutLoc = consumeToken();
param.SpecifierKind = ParsedParameter::Var;
}
// Redundant specifiers are fairly common, recognize, reject, and recover
// from this gracefully.
if (Tok.isAny(tok::kw_inout, tok::kw_let, tok::kw_var)) {
diagnose(Tok, diag::parameter_inout_var_let)
.fixItRemove(Tok.getLoc());
consumeToken();
param.isInvalid = true;
}
if (startsParameterName(*this, isClosure)) {
// identifier-or-none for the first name
if (Tok.is(tok::kw__)) {
param.FirstNameLoc = consumeToken();
} else {
assert(Tok.canBeArgumentLabel() && "startsParameterName() lied");
param.FirstName = Context.getIdentifier(Tok.getText());
param.FirstNameLoc = consumeToken();
}
// identifier-or-none? for the second name
if (Tok.canBeArgumentLabel()) {
if (!Tok.is(tok::kw__))
param.SecondName = Context.getIdentifier(Tok.getText());
param.SecondNameLoc = consumeToken();
}
// Operators and closures cannot have API names.
if ((paramContext == ParameterContextKind::Operator ||
paramContext == ParameterContextKind::Closure) &&
!param.FirstName.empty() &&
param.SecondNameLoc.isValid()) {
diagnose(param.FirstNameLoc, diag::parameter_operator_keyword_argument,
isClosure)
.fixItRemoveChars(param.FirstNameLoc, param.SecondNameLoc);
param.FirstName = param.SecondName;
param.FirstNameLoc = param.SecondNameLoc;
param.SecondName = Identifier();
param.SecondNameLoc = SourceLoc();
}
// (':' type)?
if (consumeIf(tok::colon)) {
auto type = parseType(diag::expected_parameter_type);
//.........这里部分代码省略.........
示例15: ParsingTypeTuple
/// parseTypeTupleBody
/// type-tuple:
/// '(' type-tuple-body? ')'
/// type-tuple-body:
/// type-tuple-element (',' type-tuple-element)* '...'?
/// type-tuple-element:
/// identifier ':' type
/// type
ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
Parser::StructureMarkerRAII ParsingTypeTuple(*this, Tok);
SourceLoc RPLoc, LPLoc = consumeToken(tok::l_paren);
SourceLoc EllipsisLoc;
unsigned EllipsisIdx;
SmallVector<TypeRepr *, 8> ElementsR;
ParserStatus Status = parseList(tok::r_paren, LPLoc, RPLoc,
tok::comma, /*OptionalSep=*/false,
/*AllowSepAfterLast=*/false,
diag::expected_rparen_tuple_type_list,
[&] () -> ParserStatus {
// If this is an inout marker in an argument list, consume the inout.
SourceLoc InOutLoc;
consumeIf(tok::kw_inout, InOutLoc);
// If the tuple element starts with "ident :", then
// the identifier is an element tag, and it is followed by a type
// annotation.
if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) {
// Consume the name
Identifier name;
if (!Tok.is(tok::kw__))
name = Context.getIdentifier(Tok.getText());
SourceLoc nameLoc = consumeToken();
// Consume the ':'.
consumeToken(tok::colon);
// Parse the type annotation.
ParserResult<TypeRepr> type = parseType(diag::expected_type);
if (type.hasCodeCompletion())
return makeParserCodeCompletionStatus();
if (type.isNull())
return makeParserError();
// If an 'inout' marker was specified, build the type. Note that we bury
// the inout locator within the named locator. This is weird but required
// by sema apparently.
if (InOutLoc.isValid())
type = makeParserResult(new (Context) InOutTypeRepr(type.get(),
InOutLoc));
ElementsR.push_back(
new (Context) NamedTypeRepr(name, type.get(), nameLoc));
} else {
// Otherwise, this has to be a type.
ParserResult<TypeRepr> type = parseType();
if (type.hasCodeCompletion())
return makeParserCodeCompletionStatus();
if (type.isNull())
return makeParserError();
if (InOutLoc.isValid())
type = makeParserResult(new (Context) InOutTypeRepr(type.get(),
InOutLoc));
ElementsR.push_back(type.get());
}
// Parse '= expr' here so we can complain about it directly, rather
// than dying when we see it.
if (Tok.is(tok::equal)) {
SourceLoc equalLoc = consumeToken(tok::equal);
auto init = parseExpr(diag::expected_init_value);
auto inFlight = diagnose(equalLoc, diag::tuple_type_init);
if (init.isNonNull())
inFlight.fixItRemove(SourceRange(equalLoc, init.get()->getEndLoc()));
}
if (Tok.isEllipsis()) {
if (EllipsisLoc.isValid()) {
diagnose(Tok, diag::multiple_ellipsis_in_tuple)
.highlight(EllipsisLoc)
.fixItRemove(Tok.getLoc());
(void)consumeToken();
} else {
EllipsisLoc = consumeToken();
EllipsisIdx = ElementsR.size() - 1;
}
}
return makeParserSuccess();
});
if (EllipsisLoc.isValid() && ElementsR.empty()) {
EllipsisLoc = SourceLoc();
}
if (EllipsisLoc.isInvalid())
EllipsisIdx = ElementsR.size();
return makeParserResult(Status,
//.........这里部分代码省略.........