mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[SourceKit] Delete C++ NameMatcher
The C++ `NameMatcher` has bee completely replaced by the swift-syntax `NameMatcher` now.
This commit is contained in:
@@ -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<ResolvedLoc> NameMatcher::resolve(ArrayRef<SourceLoc> Locs,
|
||||
ArrayRef<Token> Tokens) {
|
||||
|
||||
// Note the original indices and sort them in reverse source order
|
||||
std::vector<size_t> 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<ResolvedLoc> 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<ResolvedLoc> 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<CharSourceRange> getLabelRanges(const ParameterList* List,
|
||||
const SourceManager &SM) {
|
||||
std::vector<CharSourceRange> 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<CharSourceRange> getEnumParamListInfo(SourceManager &SM,
|
||||
ParameterList *PL) {
|
||||
std::vector<CharSourceRange> 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<VarDecl>(D) && !isa<ParamDecl>(D))
|
||||
return true;
|
||||
|
||||
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
|
||||
if (auto *SingleVar = PBD->getSingleVar()) {
|
||||
D = SingleVar;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto *customAttr :
|
||||
D->getParsedAttrs().getAttributes<CustomAttr, true>()) {
|
||||
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<ArgumentList *>(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<IfConfigDecl>(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<AbstractFunctionDecl>(D)) {
|
||||
std::vector<CharSourceRange> 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<SubscriptDecl>(D)) {
|
||||
tryResolve(ASTWalker::ParentTy(D), D->getLoc(),
|
||||
LabelRangeType::NoncollapsibleParam,
|
||||
getLabelRanges(SD->getIndices(), getSourceMgr()), llvm::None);
|
||||
} else if (EnumElementDecl *EED = dyn_cast<EnumElementDecl>(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<ImportDecl>(D)) {
|
||||
for(const ImportPath::Element &Element: ID->getImportPath()) {
|
||||
tryResolve(ASTWalker::ParentTy(D), Element.Loc);
|
||||
if (isDone())
|
||||
break;
|
||||
}
|
||||
} else if (isa<ValueDecl>(D) || isa<ExtensionDecl>(D) ||
|
||||
isa<PrecedenceGroupDecl>(D)) {
|
||||
tryResolve(ASTWalker::ParentTy(D), D->getLoc());
|
||||
}
|
||||
return Action::StopIf(isDone());
|
||||
}
|
||||
|
||||
ASTWalker::PreWalkResult<Stmt *> 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<SelfApplyExpr>(Fn))
|
||||
return extractNameExpr(SAE->getFn());
|
||||
if (auto *ACE = dyn_cast<AutoClosureExpr>(Fn))
|
||||
if (auto *Unwrapped = ACE->getUnwrappedCurryThunkExpr())
|
||||
return extractNameExpr(Unwrapped);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ASTWalker::PreWalkResult<ArgumentList *>
|
||||
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<Expr *> NameMatcher::walkToExprPre(Expr *E) {
|
||||
if (isDone())
|
||||
return Action::Stop();
|
||||
if (shouldSkip(E))
|
||||
return Action::SkipChildren(E);
|
||||
|
||||
if (isa<ObjCSelectorExpr>(E)) {
|
||||
++SelectorNestings;
|
||||
}
|
||||
|
||||
// only match name locations of expressions apparent in the original source
|
||||
if (!E->isImplicit()) {
|
||||
|
||||
if (auto *CE = dyn_cast<CallExpr>(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<UnresolvedMemberExpr>(E);
|
||||
tryResolve(ASTWalker::ParentTy(E), UME->getNameLoc(),
|
||||
getApplicableArgsFor(E));
|
||||
} break;
|
||||
case ExprKind::DeclRef: {
|
||||
auto DRE = cast<DeclRefExpr>(E);
|
||||
tryResolve(ASTWalker::ParentTy(E), DRE->getNameLoc(),
|
||||
getApplicableArgsFor(E));
|
||||
break;
|
||||
}
|
||||
case ExprKind::UnresolvedDeclRef: {
|
||||
auto UDRE = cast<UnresolvedDeclRefExpr>(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<BinaryExpr>(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<KeyPathExpr>(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<Expr *> 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<UnresolvedDotExpr>(E);
|
||||
tryResolve(ASTWalker::ParentTy(E), UDE->getNameLoc(),
|
||||
getApplicableArgsFor(E));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (auto *CE = dyn_cast<CallExpr>(E)) {
|
||||
if (!ParentCalls.empty() && ParentCalls.back().Call == CE)
|
||||
ParentCalls.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
if (isa<ObjCSelectorExpr>(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<IdentTypeRepr>(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<Pattern *> 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<StringLiteralExpr>(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<CharSourceRange> getSelectorLabelRanges(SourceManager &SM,
|
||||
DeclNameLoc NameLoc) {
|
||||
SourceLoc Loc;
|
||||
std::vector<CharSourceRange> 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<CharSourceRange> LabelRanges,
|
||||
llvm::Optional<unsigned> FirstTrailingLabel) {
|
||||
skipLocsBefore(NameLoc);
|
||||
if (isDone())
|
||||
return false;
|
||||
|
||||
ResolvedLocContext Context = ResolvedLocContext::Default;
|
||||
if (Node.isNull()) {
|
||||
Context = ResolvedLocContext::Comment;
|
||||
} else if (isa_and_nonnull<StringLiteralExpr>(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 << "<Kind>";
|
||||
switch (Kind) {
|
||||
|
||||
Reference in New Issue
Block a user