mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[SourceKit] Use recored #if regions in "active regions" request
* Record each IfConfig clause location info in SourceFile * Update SILProfiler to handle them * Update SwiftLangSupport::findActiveRegionsInFile() to use the recorded regions instead of walking into AST to find #if regions rdar://118082146
This commit is contained in:
@@ -49,36 +49,41 @@ enum class RestrictedImportKind {
|
|||||||
using ImportAccessLevel = std::optional<AttributedImport<ImportedModule>>;
|
using ImportAccessLevel = std::optional<AttributedImport<ImportedModule>>;
|
||||||
|
|
||||||
/// Stores range information for a \c #if block in a SourceFile.
|
/// Stores range information for a \c #if block in a SourceFile.
|
||||||
class IfConfigRangeInfo final {
|
class IfConfigClauseRangeInfo final {
|
||||||
/// The range of the entire \c #if block, including \c #else and \c #endif.
|
public:
|
||||||
CharSourceRange WholeRange;
|
enum ClauseKind {
|
||||||
|
// Active '#if', '#elseif', or '#else' clause.
|
||||||
|
ActiveClause,
|
||||||
|
// Inactive '#if', '#elseif', or '#else' clause.
|
||||||
|
InactiveClause,
|
||||||
|
// '#endif' directive.
|
||||||
|
EndDirective,
|
||||||
|
};
|
||||||
|
|
||||||
/// The range of the active selected body, if there is one. This does not
|
private:
|
||||||
/// include the outer syntax of the \c #if. This may be invalid, which
|
/// Source location of '#if', '#elseif', etc.
|
||||||
/// indicates there is no active body.
|
SourceLoc DirectiveLoc;
|
||||||
CharSourceRange ActiveBodyRange;
|
/// Character source location of body starts.
|
||||||
|
SourceLoc BodyLoc;
|
||||||
|
/// Location of the end of the body.
|
||||||
|
SourceLoc EndLoc;
|
||||||
|
|
||||||
|
ClauseKind Kind;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IfConfigRangeInfo(CharSourceRange wholeRange, CharSourceRange activeBodyRange)
|
IfConfigClauseRangeInfo(SourceLoc DirectiveLoc, SourceLoc BodyLoc,
|
||||||
: WholeRange(wholeRange), ActiveBodyRange(activeBodyRange) {
|
SourceLoc EndLoc, ClauseKind Kind)
|
||||||
assert(wholeRange.getByteLength() > 0 && "Range must be non-empty");
|
: DirectiveLoc(DirectiveLoc), BodyLoc(BodyLoc), EndLoc(EndLoc),
|
||||||
assert(activeBodyRange.isInvalid() || wholeRange.contains(activeBodyRange));
|
Kind(Kind) {
|
||||||
|
assert(DirectiveLoc.isValid() && BodyLoc.isValid() && EndLoc.isValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
CharSourceRange getWholeRange() const { return WholeRange; }
|
SourceLoc getStartLoc() const { return DirectiveLoc; }
|
||||||
SourceLoc getStartLoc() const { return WholeRange.getStart(); }
|
CharSourceRange getDirectiveRange(const SourceManager &SM) const;
|
||||||
|
CharSourceRange getWholeRange(const SourceManager &SM) const;
|
||||||
|
CharSourceRange getBodyRange(const SourceManager &SM) const;
|
||||||
|
|
||||||
friend bool operator==(const IfConfigRangeInfo &lhs,
|
ClauseKind getKind() const { return Kind; }
|
||||||
const IfConfigRangeInfo &rhs) {
|
|
||||||
return lhs.WholeRange == rhs.WholeRange &&
|
|
||||||
lhs.ActiveBodyRange == rhs.ActiveBodyRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve the ranges produced by subtracting the active body range from
|
|
||||||
/// the whole range. This includes both inactive branches as well as the
|
|
||||||
/// other syntax of the \c #if.
|
|
||||||
SmallVector<CharSourceRange, 2>
|
|
||||||
getRangesWithoutActiveBody(const SourceManager &SM) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A file containing Swift source code.
|
/// A file containing Swift source code.
|
||||||
@@ -244,9 +249,9 @@ private:
|
|||||||
ParserStatePtr DelayedParserState =
|
ParserStatePtr DelayedParserState =
|
||||||
ParserStatePtr(/*ptr*/ nullptr, /*deleter*/ nullptr);
|
ParserStatePtr(/*ptr*/ nullptr, /*deleter*/ nullptr);
|
||||||
|
|
||||||
struct IfConfigRangesData {
|
struct IfConfigClauseRangesData {
|
||||||
/// All the \c #if source ranges in this file.
|
/// All the \c #if source ranges in this file.
|
||||||
std::vector<IfConfigRangeInfo> Ranges;
|
std::vector<IfConfigClauseRangeInfo> Ranges;
|
||||||
|
|
||||||
/// Whether the elemnts in \c Ranges are sorted in source order within
|
/// Whether the elemnts in \c Ranges are sorted in source order within
|
||||||
/// this file. We flip this to \c false any time a new range gets recorded,
|
/// this file. We flip this to \c false any time a new range gets recorded,
|
||||||
@@ -255,7 +260,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Stores all the \c #if source range info in this file.
|
/// Stores all the \c #if source range info in this file.
|
||||||
mutable IfConfigRangesData IfConfigRanges;
|
mutable IfConfigClauseRangesData IfConfigClauseRanges;
|
||||||
|
|
||||||
friend class HasImportsMatchingFlagRequest;
|
friend class HasImportsMatchingFlagRequest;
|
||||||
|
|
||||||
@@ -500,12 +505,16 @@ public:
|
|||||||
const_cast<SourceFile *>(this)->MissingImportedModules.insert(module);
|
const_cast<SourceFile *>(this)->MissingImportedModules.insert(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Record the source range info for a parsed \c #if block.
|
/// Record the source range info for a parsed \c #if clause.
|
||||||
void recordIfConfigRangeInfo(IfConfigRangeInfo ranges);
|
void recordIfConfigClauseRangeInfo(const IfConfigClauseRangeInfo &range);
|
||||||
|
|
||||||
/// Retrieve the source range infos for any \c #if blocks contained within a
|
/// Retrieve the source range info for any \c #if clauses in the file.
|
||||||
|
ArrayRef<IfConfigClauseRangeInfo> getIfConfigClauseRanges() const;
|
||||||
|
|
||||||
|
/// Retrieve the source range infos for any \c #if clauses contained within a
|
||||||
/// given source range of this file.
|
/// given source range of this file.
|
||||||
ArrayRef<IfConfigRangeInfo> getIfConfigsWithin(SourceRange outer) const;
|
ArrayRef<IfConfigClauseRangeInfo>
|
||||||
|
getIfConfigClausesWithin(SourceRange outer) const;
|
||||||
|
|
||||||
void getMissingImportedModules(
|
void getMissingImportedModules(
|
||||||
SmallVectorImpl<ImportedModule> &imports) const override;
|
SmallVectorImpl<ImportedModule> &imports) const override;
|
||||||
|
|||||||
@@ -2778,56 +2778,66 @@ SourceFile::getImportAccessLevel(const ModuleDecl *targetModule) const {
|
|||||||
return restrictiveImport;
|
return restrictiveImport;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallVector<CharSourceRange, 2>
|
CharSourceRange
|
||||||
IfConfigRangeInfo::getRangesWithoutActiveBody(const SourceManager &SM) const {
|
IfConfigClauseRangeInfo::getDirectiveRange(const SourceManager &SM) const {
|
||||||
SmallVector<CharSourceRange, 2> result;
|
return CharSourceRange(SM, DirectiveLoc, BodyLoc);
|
||||||
if (ActiveBodyRange.isValid()) {
|
}
|
||||||
// Split the whole range by the active range.
|
|
||||||
result.emplace_back(SM, WholeRange.getStart(), ActiveBodyRange.getStart());
|
CharSourceRange
|
||||||
result.emplace_back(SM, ActiveBodyRange.getEnd(), WholeRange.getEnd());
|
IfConfigClauseRangeInfo::getBodyRange(const SourceManager &SM) const {
|
||||||
} else {
|
return CharSourceRange(SM, BodyLoc, EndLoc);
|
||||||
// No active body, we just return the whole range.
|
}
|
||||||
result.push_back(WholeRange);
|
|
||||||
|
CharSourceRange
|
||||||
|
IfConfigClauseRangeInfo::getWholeRange(const SourceManager &SM) const {
|
||||||
|
return CharSourceRange(SM, DirectiveLoc, EndLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceFile::recordIfConfigClauseRangeInfo(
|
||||||
|
const IfConfigClauseRangeInfo &range) {
|
||||||
|
IfConfigClauseRanges.Ranges.push_back(range);
|
||||||
|
IfConfigClauseRanges.IsSorted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayRef<IfConfigClauseRangeInfo> SourceFile::getIfConfigClauseRanges() const {
|
||||||
|
if (!IfConfigClauseRanges.IsSorted) {
|
||||||
|
auto &SM = getASTContext().SourceMgr;
|
||||||
|
// Sort the ranges if we need to.
|
||||||
|
llvm::sort(
|
||||||
|
IfConfigClauseRanges.Ranges, [&](const IfConfigClauseRangeInfo &lhs,
|
||||||
|
const IfConfigClauseRangeInfo &rhs) {
|
||||||
|
return SM.isBeforeInBuffer(lhs.getStartLoc(), rhs.getStartLoc());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Be defensive and eliminate duplicates in case we've parsed twice.
|
||||||
|
auto newEnd = llvm::unique(
|
||||||
|
IfConfigClauseRanges.Ranges, [&](const IfConfigClauseRangeInfo &lhs,
|
||||||
|
const IfConfigClauseRangeInfo &rhs) {
|
||||||
|
if (lhs.getStartLoc() != rhs.getStartLoc())
|
||||||
|
return false;
|
||||||
|
assert(lhs.getBodyRange(SM) == rhs.getBodyRange(SM) &&
|
||||||
|
"range changed on a re-parse?");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
IfConfigClauseRanges.Ranges.erase(newEnd,
|
||||||
|
IfConfigClauseRanges.Ranges.end());
|
||||||
|
IfConfigClauseRanges.IsSorted = true;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
return IfConfigClauseRanges.Ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceFile::recordIfConfigRangeInfo(IfConfigRangeInfo ranges) {
|
ArrayRef<IfConfigClauseRangeInfo>
|
||||||
IfConfigRanges.Ranges.push_back(ranges);
|
SourceFile::getIfConfigClausesWithin(SourceRange outer) const {
|
||||||
IfConfigRanges.IsSorted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayRef<IfConfigRangeInfo>
|
|
||||||
SourceFile::getIfConfigsWithin(SourceRange outer) const {
|
|
||||||
auto &SM = getASTContext().SourceMgr;
|
auto &SM = getASTContext().SourceMgr;
|
||||||
assert(SM.getRangeForBuffer(BufferID).contains(outer.Start) &&
|
assert(SM.getRangeForBuffer(BufferID).contains(outer.Start) &&
|
||||||
"Range not within this file?");
|
"Range not within this file?");
|
||||||
|
|
||||||
if (!IfConfigRanges.IsSorted) {
|
|
||||||
// Sort the ranges if we need to.
|
|
||||||
llvm::sort(IfConfigRanges.Ranges, [&](IfConfigRangeInfo lhs,
|
|
||||||
IfConfigRangeInfo rhs) {
|
|
||||||
return SM.isBeforeInBuffer(lhs.getStartLoc(), rhs.getStartLoc());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Be defensive and eliminate duplicates in case we've parsed twice.
|
|
||||||
auto newEnd = std::unique(
|
|
||||||
IfConfigRanges.Ranges.begin(), IfConfigRanges.Ranges.end(),
|
|
||||||
[&](const IfConfigRangeInfo &lhs, const IfConfigRangeInfo &rhs) {
|
|
||||||
if (lhs.getWholeRange() != rhs.getWholeRange())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
assert(lhs == rhs && "Active ranges changed on a re-parse?");
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
IfConfigRanges.Ranges.erase(newEnd, IfConfigRanges.Ranges.end());
|
|
||||||
IfConfigRanges.IsSorted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// First let's find the first #if that is after the outer start loc.
|
// First let's find the first #if that is after the outer start loc.
|
||||||
auto ranges = llvm::ArrayRef(IfConfigRanges.Ranges);
|
auto ranges = getIfConfigClauseRanges();
|
||||||
auto lower = llvm::lower_bound(
|
auto lower = llvm::lower_bound(
|
||||||
ranges, outer.Start, [&](IfConfigRangeInfo range, SourceLoc loc) {
|
ranges, outer.Start,
|
||||||
|
[&](const IfConfigClauseRangeInfo &range, SourceLoc loc) {
|
||||||
return SM.isBeforeInBuffer(range.getStartLoc(), loc);
|
return SM.isBeforeInBuffer(range.getStartLoc(), loc);
|
||||||
});
|
});
|
||||||
if (lower == ranges.end() ||
|
if (lower == ranges.end() ||
|
||||||
@@ -2836,7 +2846,8 @@ SourceFile::getIfConfigsWithin(SourceRange outer) const {
|
|||||||
}
|
}
|
||||||
// Next let's find the first #if that's after the outer end loc.
|
// Next let's find the first #if that's after the outer end loc.
|
||||||
auto upper = llvm::upper_bound(
|
auto upper = llvm::upper_bound(
|
||||||
ranges, outer.End, [&](SourceLoc loc, IfConfigRangeInfo range) {
|
ranges, outer.End,
|
||||||
|
[&](SourceLoc loc, const IfConfigClauseRangeInfo &range) {
|
||||||
return SM.isBeforeInBuffer(loc, range.getStartLoc());
|
return SM.isBeforeInBuffer(loc, range.getStartLoc());
|
||||||
});
|
});
|
||||||
return llvm::ArrayRef(lower, upper - lower);
|
return llvm::ArrayRef(lower, upper - lower);
|
||||||
|
|||||||
@@ -889,10 +889,12 @@ Result Parser::parseIfConfigRaw(
|
|||||||
ClauseLoc, Condition, isActive, IfConfigElementsRole::Skipped);
|
ClauseLoc, Condition, isActive, IfConfigElementsRole::Skipped);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the active body range for the SourceManager.
|
// Record the clause range info in SourceFile.
|
||||||
if (shouldEvaluate && isActive) {
|
if (shouldEvaluate) {
|
||||||
assert(!activeBodyRange.isValid() && "Multiple active regions?");
|
auto kind = isActive ? IfConfigClauseRangeInfo::ActiveClause
|
||||||
activeBodyRange = CharSourceRange(SourceMgr, bodyStart, Tok.getLoc());
|
: IfConfigClauseRangeInfo::InactiveClause;
|
||||||
|
SF.recordIfConfigClauseRangeInfo(
|
||||||
|
{ClauseLoc, bodyStart, Tok.getLoc(), kind});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Tok.isNot(tok::pound_elseif, tok::pound_else))
|
if (Tok.isNot(tok::pound_elseif, tok::pound_else))
|
||||||
@@ -905,11 +907,11 @@ Result Parser::parseIfConfigRaw(
|
|||||||
SourceLoc EndLoc;
|
SourceLoc EndLoc;
|
||||||
bool HadMissingEnd = parseEndIfDirective(EndLoc);
|
bool HadMissingEnd = parseEndIfDirective(EndLoc);
|
||||||
|
|
||||||
// Record the #if ranges on the SourceManager.
|
// Record the '#end' ranges in SourceFile.
|
||||||
if (!HadMissingEnd && shouldEvaluate) {
|
if (!HadMissingEnd && shouldEvaluate) {
|
||||||
auto wholeRange = Lexer::getCharSourceRangeFromSourceRange(
|
SourceLoc EndOfEndLoc = getEndOfPreviousLoc();
|
||||||
SourceMgr, SourceRange(startLoc, EndLoc));
|
SF.recordIfConfigClauseRangeInfo({EndLoc, EndOfEndLoc, EndOfEndLoc,
|
||||||
SF.recordIfConfigRangeInfo({wholeRange, activeBodyRange});
|
IfConfigClauseRangeInfo::EndDirective});
|
||||||
}
|
}
|
||||||
return finish(EndLoc, HadMissingEnd);
|
return finish(EndLoc, HadMissingEnd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1165,14 +1165,37 @@ public:
|
|||||||
Counter.getLLVMCounter()));
|
Counter.getLLVMCounter()));
|
||||||
}
|
}
|
||||||
// Add any skipped regions present in the outer range.
|
// Add any skipped regions present in the outer range.
|
||||||
for (auto IfConfig : SF->getIfConfigsWithin(OuterRange)) {
|
for (auto clause : SF->getIfConfigClausesWithin(OuterRange)) {
|
||||||
for (auto SkipRange : IfConfig.getRangesWithoutActiveBody(SM)) {
|
CharSourceRange SkipRange;
|
||||||
auto Start = SM.getLineAndColumnInBuffer(SkipRange.getStart());
|
switch (clause.getKind()) {
|
||||||
auto End = SM.getLineAndColumnInBuffer(SkipRange.getEnd());
|
case IfConfigClauseRangeInfo::ActiveClause:
|
||||||
assert(Start.first <= End.first && "region start and end out of order");
|
case IfConfigClauseRangeInfo::EndDirective:
|
||||||
Regions.push_back(MappedRegion::skipped(Start.first, Start.second,
|
SkipRange = clause.getDirectiveRange(SM);
|
||||||
End.first, End.second));
|
break;
|
||||||
|
case IfConfigClauseRangeInfo::InactiveClause:
|
||||||
|
SkipRange = clause.getWholeRange(SM);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (SkipRange.getByteLength() == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto Start = SM.getLineAndColumnInBuffer(SkipRange.getStart());
|
||||||
|
auto End = SM.getLineAndColumnInBuffer(SkipRange.getEnd());
|
||||||
|
assert(Start.first <= End.first && "region start and end out of order");
|
||||||
|
|
||||||
|
// If this is consecutive with the last one, expand it.
|
||||||
|
if (!Regions.empty()) {
|
||||||
|
auto &last = Regions.back();
|
||||||
|
if (last.RegionKind == MappedRegion::Kind::Skipped &&
|
||||||
|
last.EndLine == Start.first && last.EndCol == Start.second) {
|
||||||
|
last.EndLine = End.first;
|
||||||
|
last.EndCol = End.second;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Regions.push_back(MappedRegion::skipped(Start.first, Start.second,
|
||||||
|
End.first, End.second));
|
||||||
}
|
}
|
||||||
return SILCoverageMap::create(M, SF, Filename, Name, PGOFuncName, Hash,
|
return SILCoverageMap::create(M, SF, Filename, Name, PGOFuncName, Hash,
|
||||||
Regions, CounterBuilder.getExpressions());
|
Regions, CounterBuilder.getExpressions());
|
||||||
|
|||||||
19
test/SourceKit/ActiveRegions/nested2.swift
Normal file
19
test/SourceKit/ActiveRegions/nested2.swift
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
func foo() -> Int {
|
||||||
|
#if true
|
||||||
|
#if true
|
||||||
|
return 1
|
||||||
|
#else
|
||||||
|
return 2
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return 3
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// RUN: %sourcekitd-test -req=active-regions %s -- -D FLAG_1 -module-name active_regions %s | %FileCheck -check-prefix=CHECK1 %s
|
||||||
|
// CHECK1: START IF CONFIGS
|
||||||
|
// CHECK1-NEXT: 2:3 - active
|
||||||
|
// CHECK1-NEXT: 3:3 - active
|
||||||
|
// CHECK1-NEXT: 5:3 - inactive
|
||||||
|
// CHECK1-NEXT: 8:3 - inactive
|
||||||
|
// CHECK1-NEXT: END IF CONFIGS
|
||||||
18
test/SourceKit/ActiveRegions/postfix.swift
Normal file
18
test/SourceKit/ActiveRegions/postfix.swift
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
struct Value {
|
||||||
|
var prop1: Int = 0
|
||||||
|
var prop2: Int = 0
|
||||||
|
}
|
||||||
|
func test(value: Value) {
|
||||||
|
let _ = value
|
||||||
|
#if false
|
||||||
|
.prop1
|
||||||
|
#else
|
||||||
|
.prop2
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// RUN: %sourcekitd-test -req=active-regions %s -- -module-name active_regions %s | %FileCheck -check-prefix=CHECK1 %s
|
||||||
|
// CHECK1: START IF CONFIGS
|
||||||
|
// CHECK1-NEXT: 7:1 - inactive
|
||||||
|
// CHECK1-NEXT: 9:1 - active
|
||||||
|
// CHECK1-NEXT: END IF CONFIGS
|
||||||
@@ -2652,36 +2652,6 @@ void SwiftLangSupport::findRelatedIdentifiersInFile(
|
|||||||
// SwiftLangSupport::findActiveRegionsInFile
|
// SwiftLangSupport::findActiveRegionsInFile
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
namespace {
|
|
||||||
class IfConfigScanner : public SourceEntityWalker {
|
|
||||||
unsigned BufferID = -1;
|
|
||||||
SmallVectorImpl<IfConfigInfo> &Infos;
|
|
||||||
bool Cancelled = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit IfConfigScanner(unsigned BufferID,
|
|
||||||
SmallVectorImpl<IfConfigInfo> &Infos)
|
|
||||||
: BufferID(BufferID), Infos(Infos) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool walkToDeclPre(Decl *D, CharSourceRange Range) override {
|
|
||||||
if (Cancelled)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (auto *IfDecl = dyn_cast<IfConfigDecl>(D)) {
|
|
||||||
for (auto &Clause : IfDecl->getClauses()) {
|
|
||||||
unsigned Offset = D->getASTContext().SourceMgr.getLocOffsetInBuffer(
|
|
||||||
Clause.Loc, BufferID);
|
|
||||||
Infos.emplace_back(Offset, Clause.isActive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
void SwiftLangSupport::findActiveRegionsInFile(
|
void SwiftLangSupport::findActiveRegionsInFile(
|
||||||
StringRef PrimaryFilePath, StringRef InputBufferName,
|
StringRef PrimaryFilePath, StringRef InputBufferName,
|
||||||
ArrayRef<const char *> Args, SourceKitCancellationToken CancellationToken,
|
ArrayRef<const char *> Args, SourceKitCancellationToken CancellationToken,
|
||||||
@@ -2717,16 +2687,25 @@ void SwiftLangSupport::findActiveRegionsInFile(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallVector<IfConfigInfo> Configs;
|
auto &SM = SF->getASTContext().SourceMgr;
|
||||||
IfConfigScanner Scanner(*SF->getBufferID(), Configs);
|
auto BufferID = *SF->getBufferID();
|
||||||
Scanner.walk(SF);
|
|
||||||
|
|
||||||
// Sort by offset so nested decls are reported
|
SmallVector<IfConfigInfo> Configs;
|
||||||
// in source order (not tree order).
|
for (auto &range : SF->getIfConfigClauseRanges()) {
|
||||||
llvm::sort(Configs,
|
bool isActive = false;
|
||||||
[](const IfConfigInfo &LHS, const IfConfigInfo &RHS) -> bool {
|
switch (range.getKind()) {
|
||||||
return LHS.Offset < RHS.Offset;
|
case IfConfigClauseRangeInfo::ActiveClause:
|
||||||
});
|
isActive = true;
|
||||||
|
break;
|
||||||
|
case IfConfigClauseRangeInfo::InactiveClause:
|
||||||
|
isActive = false;
|
||||||
|
break;
|
||||||
|
case IfConfigClauseRangeInfo::EndDirective:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto offset = SM.getLocOffsetInBuffer(range.getStartLoc(), BufferID);
|
||||||
|
Configs.emplace_back(offset, isActive);
|
||||||
|
}
|
||||||
ActiveRegionsInfo Info;
|
ActiveRegionsInfo Info;
|
||||||
Info.Configs = Configs;
|
Info.Configs = Configs;
|
||||||
Receiver(RequestResult<ActiveRegionsInfo>::fromResult(Info));
|
Receiver(RequestResult<ActiveRegionsInfo>::fromResult(Info));
|
||||||
|
|||||||
Reference in New Issue
Block a user