mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Test] Add range-info test driver to swift-ide-test. NFC
This commit is contained in:
@@ -209,13 +209,15 @@ struct ResolvedRangeInfo {
|
|||||||
RangeKind Kind;
|
RangeKind Kind;
|
||||||
Type Ty;
|
Type Ty;
|
||||||
StringRef Content;
|
StringRef Content;
|
||||||
ResolvedRangeInfo(RangeKind Kind, Type Ty, StringRef Content) : Kind(Kind),
|
ResolvedRangeInfo(RangeKind Kind, Type Ty, StringRef Content): Kind(Kind),
|
||||||
Ty(Ty), Content(Content) {}
|
Ty(Ty), Content(Content) {}
|
||||||
|
ResolvedRangeInfo(): ResolvedRangeInfo(RangeKind::Invalid, Type(), StringRef()) {}
|
||||||
|
void print(llvm::raw_ostream &OS);
|
||||||
};
|
};
|
||||||
|
|
||||||
class RangeResolver : public SourceEntityWalker {
|
class RangeResolver : public SourceEntityWalker {
|
||||||
struct Implementation;
|
struct Implementation;
|
||||||
Implementation &Impl;
|
Implementation *Impl;
|
||||||
bool walkToExprPre(Expr *E) override;
|
bool walkToExprPre(Expr *E) override;
|
||||||
bool walkToExprPost(Expr *E) override;
|
bool walkToExprPost(Expr *E) override;
|
||||||
bool walkToStmtPre(Stmt *S) override;
|
bool walkToStmtPre(Stmt *S) override;
|
||||||
@@ -224,6 +226,7 @@ class RangeResolver : public SourceEntityWalker {
|
|||||||
bool walkToDeclPost(Decl *D) override;
|
bool walkToDeclPost(Decl *D) override;
|
||||||
public:
|
public:
|
||||||
RangeResolver(SourceFile &File, SourceLoc Start, SourceLoc End);
|
RangeResolver(SourceFile &File, SourceLoc Start, SourceLoc End);
|
||||||
|
RangeResolver(SourceFile &File, unsigned Offset, unsigned Length);
|
||||||
ResolvedRangeInfo resolve();
|
ResolvedRangeInfo resolve();
|
||||||
~RangeResolver();
|
~RangeResolver();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "clang/Basic/Module.h"
|
#include "clang/Basic/Module.h"
|
||||||
#include "clang/Index/USRGeneration.h"
|
#include "clang/Index/USRGeneration.h"
|
||||||
#include "clang/Lex/Lexer.h"
|
#include "clang/Lex/Lexer.h"
|
||||||
|
#include "clang/Basic/CharInfo.h"
|
||||||
|
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
|
|
||||||
@@ -174,6 +175,25 @@ bool SemaLocResolver::visitModuleReference(ModuleEntity Mod,
|
|||||||
return !tryResolve(Mod, Range.getStart());
|
return !tryResolve(Mod, Range.getStart());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResolvedRangeInfo::print(llvm::raw_ostream &OS) {
|
||||||
|
OS << "<Kind>";
|
||||||
|
switch (Kind) {
|
||||||
|
case RangeKind::SingleExpression: OS << "SingleExpression"; break;
|
||||||
|
case RangeKind::SingleDecl: OS << "SingleDecl"; break;
|
||||||
|
case RangeKind::MultiStatement: OS << "MultiStatement"; break;
|
||||||
|
case RangeKind::SingleStatement: OS << "SingleStatement"; break;
|
||||||
|
case RangeKind::Invalid: OS << "Invalid"; break;
|
||||||
|
}
|
||||||
|
OS << "</Kind>\n";
|
||||||
|
|
||||||
|
OS << "<Content>" << Content << "</Content>\n";
|
||||||
|
if (Ty) {
|
||||||
|
OS << "<Type>";
|
||||||
|
Ty->print(OS);
|
||||||
|
OS << "</Type>\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct RangeResolver::Implementation {
|
struct RangeResolver::Implementation {
|
||||||
SourceFile &File;
|
SourceFile &File;
|
||||||
private:
|
private:
|
||||||
@@ -214,9 +234,47 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
static SourceLoc getNonwhitespaceLocBefore(SourceManager &SM,
|
||||||
|
unsigned BufferID,
|
||||||
|
unsigned Offset) {
|
||||||
|
CharSourceRange entireRange = SM.getRangeForBuffer(BufferID);
|
||||||
|
StringRef Buffer = SM.extractText(entireRange);
|
||||||
|
|
||||||
|
const char *BufStart = Buffer.data();
|
||||||
|
if (Offset >= Buffer.size())
|
||||||
|
return SourceLoc();
|
||||||
|
|
||||||
|
for (unsigned Off = Offset; Off != 0; Off --) {
|
||||||
|
if (!clang::isWhitespace(*(BufStart + Off))) {
|
||||||
|
return SM.getLocForOffset(BufferID, Off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clang::isWhitespace(*BufStart) ? SourceLoc() :
|
||||||
|
SM.getLocForOffset(BufferID, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SourceLoc getNonwhitespaceLocAfter(SourceManager &SM,
|
||||||
|
unsigned BufferID,
|
||||||
|
unsigned Offset) {
|
||||||
|
CharSourceRange entireRange = SM.getRangeForBuffer(BufferID);
|
||||||
|
StringRef Buffer = SM.extractText(entireRange);
|
||||||
|
|
||||||
|
const char *BufStart = Buffer.data();
|
||||||
|
if (Offset >= Buffer.size())
|
||||||
|
return SourceLoc();
|
||||||
|
|
||||||
|
for (unsigned Off = Offset; Off < Buffer.size(); Off ++) {
|
||||||
|
if (!clang::isWhitespace(*(BufStart + Off))) {
|
||||||
|
return SM.getLocForOffset(BufferID, Off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SourceLoc();
|
||||||
|
}
|
||||||
|
|
||||||
Implementation(SourceFile &File, SourceLoc Start, SourceLoc End) :
|
Implementation(SourceFile &File, SourceLoc Start, SourceLoc End) :
|
||||||
File(File), Start(Start), End(End), Content(getContent()) {}
|
File(File), Start(Start), End(End), Content(getContent()) {}
|
||||||
|
|
||||||
|
public:
|
||||||
bool hasResult() { return Result.hasValue(); }
|
bool hasResult() { return Result.hasValue(); }
|
||||||
void enter(ASTNode Node) { ContextStack.emplace_back(Node); }
|
void enter(ASTNode Node) { ContextStack.emplace_back(Node); }
|
||||||
void leave(ASTNode Node) {
|
void leave(ASTNode Node) {
|
||||||
@@ -224,6 +282,29 @@ public:
|
|||||||
ContextStack.pop_back();
|
ContextStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Implementation *createInstance(SourceFile &File, unsigned StartOff,
|
||||||
|
unsigned Length) {
|
||||||
|
SourceManager &SM = File.getASTContext().SourceMgr;
|
||||||
|
unsigned BufferId = File.getBufferID().getValue();
|
||||||
|
SourceLoc StartLoc = Implementation::getNonwhitespaceLocAfter(SM, BufferId,
|
||||||
|
StartOff);
|
||||||
|
SourceLoc EndLoc = Implementation::getNonwhitespaceLocBefore(SM, BufferId,
|
||||||
|
StartOff + Length - 1);
|
||||||
|
StartLoc = Lexer::getLocForStartOfToken(SM, StartLoc);
|
||||||
|
EndLoc = Lexer::getLocForStartOfToken(SM, EndLoc);
|
||||||
|
return StartLoc.isInvalid() || EndLoc.isInvalid() ? nullptr :
|
||||||
|
new Implementation(File, StartLoc, EndLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Implementation *createInstance(SourceFile &File, SourceLoc Start,
|
||||||
|
SourceLoc End) {
|
||||||
|
SourceManager &SM = File.getASTContext().SourceMgr;
|
||||||
|
unsigned BufferId = File.getBufferID().getValue();
|
||||||
|
unsigned StartOff = SM.getLocOffsetInBuffer(Start, BufferId);
|
||||||
|
unsigned EndOff = SM.getLocOffsetInBuffer(End, BufferId);
|
||||||
|
return createInstance(File, StartOff, EndOff - StartOff);
|
||||||
|
}
|
||||||
|
|
||||||
void analyze(ASTNode Node) {
|
void analyze(ASTNode Node) {
|
||||||
auto &DCInfo = getCurrentDC();
|
auto &DCInfo = getCurrentDC();
|
||||||
switch (getRangeMatchKind(Node.getSourceRange())) {
|
switch (getRangeMatchKind(Node.getSourceRange())) {
|
||||||
@@ -283,53 +364,58 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
RangeResolver::RangeResolver(SourceFile &File, SourceLoc Start, SourceLoc End) :
|
RangeResolver::RangeResolver(SourceFile &File, SourceLoc Start, SourceLoc End) :
|
||||||
Impl(*new Implementation(File, Start, End)) {}
|
Impl(Implementation::createInstance(File, Start, End)) {}
|
||||||
|
|
||||||
RangeResolver::~RangeResolver() { delete &Impl; }
|
RangeResolver::RangeResolver(SourceFile &File, unsigned Offset, unsigned Length) :
|
||||||
|
Impl(Implementation::createInstance(File, Offset, Length)) {}
|
||||||
|
|
||||||
|
RangeResolver::~RangeResolver() { if (Impl) delete Impl; }
|
||||||
|
|
||||||
bool RangeResolver::walkToExprPre(Expr *E) {
|
bool RangeResolver::walkToExprPre(Expr *E) {
|
||||||
if (!Impl.shouldEnter(E))
|
if (!Impl->shouldEnter(E))
|
||||||
return false;
|
return false;
|
||||||
Impl.analyze(E);
|
Impl->analyze(E);
|
||||||
Impl.enter(E);
|
Impl->enter(E);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RangeResolver::walkToStmtPre(Stmt *S) {
|
bool RangeResolver::walkToStmtPre(Stmt *S) {
|
||||||
if (!Impl.shouldEnter(S))
|
if (!Impl->shouldEnter(S))
|
||||||
return false;
|
return false;
|
||||||
Impl.analyze(S);
|
Impl->analyze(S);
|
||||||
Impl.enter(S);
|
Impl->enter(S);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool RangeResolver::walkToDeclPre(Decl *D, CharSourceRange Range) {
|
bool RangeResolver::walkToDeclPre(Decl *D, CharSourceRange Range) {
|
||||||
if (!Impl.shouldEnter(D))
|
if (!Impl->shouldEnter(D))
|
||||||
return false;
|
return false;
|
||||||
Impl.analyze(D);
|
Impl->analyze(D);
|
||||||
Impl.enter(D);
|
Impl->enter(D);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RangeResolver::walkToExprPost(Expr *E) {
|
bool RangeResolver::walkToExprPost(Expr *E) {
|
||||||
Impl.leave(E);
|
Impl->leave(E);
|
||||||
return !Impl.hasResult();
|
return !Impl->hasResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RangeResolver::walkToStmtPost(Stmt *S) {
|
bool RangeResolver::walkToStmtPost(Stmt *S) {
|
||||||
Impl.leave(S);
|
Impl->leave(S);
|
||||||
return !Impl.hasResult();
|
return !Impl->hasResult();
|
||||||
};
|
};
|
||||||
|
|
||||||
bool RangeResolver::walkToDeclPost(Decl *D) {
|
bool RangeResolver::walkToDeclPost(Decl *D) {
|
||||||
Impl.leave(D);
|
Impl->leave(D);
|
||||||
return !Impl.hasResult();
|
return !Impl->hasResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedRangeInfo RangeResolver::resolve() {
|
ResolvedRangeInfo RangeResolver::resolve() {
|
||||||
Impl.enter(ASTNode());
|
if (!Impl)
|
||||||
walk(Impl.File);
|
return ResolvedRangeInfo();
|
||||||
return Impl.getResult();
|
Impl->enter(ASTNode());
|
||||||
|
walk(Impl->File);
|
||||||
|
return Impl->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
void swift::ide::getLocationInfoForClangNode(ClangNode ClangNode,
|
void swift::ide::getLocationInfoForClangNode(ClangNode ClangNode,
|
||||||
|
|||||||
40
test/IDE/range_info_basics.swift
Normal file
40
test/IDE/range_info_basics.swift
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
func foo() -> Int{
|
||||||
|
var aaa = 1 + 2
|
||||||
|
aaa = aaa + 3
|
||||||
|
if aaa == 3 { aaa = 4 }
|
||||||
|
return aaa
|
||||||
|
}
|
||||||
|
|
||||||
|
func foo1() -> Int { return 0 }
|
||||||
|
class C { func foo() {} }
|
||||||
|
struct S { func foo() {} }
|
||||||
|
|
||||||
|
|
||||||
|
// RUN: %target-swift-ide-test -range -pos=8:1 -end-pos 8:32 -source-filename %s | %FileCheck %s -check-prefix=CHECK1
|
||||||
|
// RUN: %target-swift-ide-test -range -pos=9:1 -end-pos 9:26 -source-filename %s | %FileCheck %s -check-prefix=CHECK2
|
||||||
|
// RUN: %target-swift-ide-test -range -pos=10:1 -end-pos 10:27 -source-filename %s | %FileCheck %s -check-prefix=CHECK3
|
||||||
|
// RUN: %target-swift-ide-test -range -pos=3:1 -end-pos=4:26 -source-filename %s | %FileCheck %s -check-prefix=CHECK4
|
||||||
|
// RUN: %target-swift-ide-test -range -pos=3:1 -end-pos=5:13 -source-filename %s | %FileCheck %s -check-prefix=CHECK5
|
||||||
|
// RUN: %target-swift-ide-test -range -pos=4:1 -end-pos=5:13 -source-filename %s | %FileCheck %s -check-prefix=CHECK6
|
||||||
|
|
||||||
|
// CHECK1: <Kind>SingleDecl</Kind>
|
||||||
|
// CHECK1-NEXT: <Content>func foo1() -> Int { return 0 }</Content>
|
||||||
|
|
||||||
|
// CHECK2: <Kind>SingleDecl</Kind>
|
||||||
|
// CHECK2-NEXT: <Content>class C { func foo() {} }</Content>
|
||||||
|
|
||||||
|
// CHECK3: <Kind>SingleDecl</Kind>
|
||||||
|
// CHECK3-NEXT: <Content>struct S { func foo() {} }</Content>
|
||||||
|
|
||||||
|
// CHECK4: <Kind>MultiStatement</Kind>
|
||||||
|
// CHECK4-NEXT: <Content>aaa = aaa + 3
|
||||||
|
// CHECK4-NEXT: if aaa == 3 { aaa = 4 }</Content>
|
||||||
|
|
||||||
|
// CHECK5: <Kind>MultiStatement</Kind>
|
||||||
|
// CHECK5-NEXT: <Content>aaa = aaa + 3
|
||||||
|
// CHECK5-NEXT: if aaa == 3 { aaa = 4 }
|
||||||
|
// CHECK5-NEXT: return aaa</Content>
|
||||||
|
|
||||||
|
// CHECK6: <Kind>MultiStatement</Kind>
|
||||||
|
// CHECK6-NEXT: if aaa == 3 { aaa = 4 }
|
||||||
|
// CHECK6-NEXT: return aaa</Content>
|
||||||
@@ -493,7 +493,7 @@ static StringRef getSourceToken(unsigned Offset,
|
|||||||
return L.getTokenAt(Loc).getText();
|
return L.getTokenAt(Loc).getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
static llvm::Optional<unsigned>
|
static llvm::Optional<unsigned>
|
||||||
mapOffsetToOlderSnapshot(unsigned Offset,
|
mapOffsetToOlderSnapshot(unsigned Offset,
|
||||||
ImmutableTextSnapshotRef NewSnap,
|
ImmutableTextSnapshotRef NewSnap,
|
||||||
ImmutableTextSnapshotRef OldSnap) {
|
ImmutableTextSnapshotRef OldSnap) {
|
||||||
@@ -519,7 +519,7 @@ mapOffsetToOlderSnapshot(unsigned Offset,
|
|||||||
return Offset;
|
return Offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static llvm::Optional<unsigned>
|
static llvm::Optional<unsigned>
|
||||||
mapOffsetToNewerSnapshot(unsigned Offset,
|
mapOffsetToNewerSnapshot(unsigned Offset,
|
||||||
ImmutableTextSnapshotRef OldSnap,
|
ImmutableTextSnapshotRef OldSnap,
|
||||||
ImmutableTextSnapshotRef NewSnap) {
|
ImmutableTextSnapshotRef NewSnap) {
|
||||||
@@ -1023,43 +1023,6 @@ static void resolveRange(SwiftLangSupport &Lang,
|
|||||||
unsigned Length;
|
unsigned Length;
|
||||||
std::function<void(const RangeInfo&)> Receiver;
|
std::function<void(const RangeInfo&)> Receiver;
|
||||||
|
|
||||||
static SourceLoc getNonwhitespaceLocBefore(SourceManager &SM,
|
|
||||||
unsigned BufferID,
|
|
||||||
unsigned Offset) {
|
|
||||||
CharSourceRange entireRange = SM.getRangeForBuffer(BufferID);
|
|
||||||
StringRef Buffer = SM.extractText(entireRange);
|
|
||||||
|
|
||||||
const char *BufStart = Buffer.data();
|
|
||||||
if (Offset >= Buffer.size())
|
|
||||||
return SourceLoc();
|
|
||||||
|
|
||||||
for (unsigned Off = Offset; Off != 0; Off --) {
|
|
||||||
if (!clang::isWhitespace(*(BufStart + Off))) {
|
|
||||||
return SM.getLocForOffset(BufferID, Off);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return clang::isWhitespace(*BufStart) ? SourceLoc() :
|
|
||||||
SM.getLocForOffset(BufferID, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static SourceLoc getNonwhitespaceLocAfter(SourceManager &SM,
|
|
||||||
unsigned BufferID,
|
|
||||||
unsigned Offset) {
|
|
||||||
CharSourceRange entireRange = SM.getRangeForBuffer(BufferID);
|
|
||||||
StringRef Buffer = SM.extractText(entireRange);
|
|
||||||
|
|
||||||
const char *BufStart = Buffer.data();
|
|
||||||
if (Offset >= Buffer.size())
|
|
||||||
return SourceLoc();
|
|
||||||
|
|
||||||
for (unsigned Off = Offset; Off < Buffer.size(); Off ++) {
|
|
||||||
if (!clang::isWhitespace(*(BufStart + Off))) {
|
|
||||||
return SM.getLocForOffset(BufferID, Off);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SourceLoc();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RangeInfoConsumer(StringRef InputFile, unsigned Offset, unsigned Length,
|
RangeInfoConsumer(StringRef InputFile, unsigned Offset, unsigned Length,
|
||||||
SwiftLangSupport &Lang, SwiftInvocationRef ASTInvok,
|
SwiftLangSupport &Lang, SwiftInvocationRef ASTInvok,
|
||||||
@@ -1070,25 +1033,10 @@ static void resolveRange(SwiftLangSupport &Lang,
|
|||||||
|
|
||||||
void handlePrimaryAST(ASTUnitRef AstUnit) override {
|
void handlePrimaryAST(ASTUnitRef AstUnit) override {
|
||||||
auto &CompIns = AstUnit->getCompilerInstance();
|
auto &CompIns = AstUnit->getCompilerInstance();
|
||||||
|
|
||||||
unsigned BufferID = AstUnit->getPrimarySourceFile().getBufferID().getValue();
|
|
||||||
SourceManager &SM = CompIns.getSourceMgr();
|
|
||||||
SourceLoc StartLoc = getNonwhitespaceLocAfter(SM, BufferID, Offset);
|
|
||||||
SourceLoc EndLoc = getNonwhitespaceLocBefore(SM, BufferID,
|
|
||||||
Offset + Length - 1);
|
|
||||||
|
|
||||||
StartLoc = Lexer::getLocForStartOfToken(SM, StartLoc);
|
|
||||||
EndLoc = Lexer::getLocForStartOfToken(SM, EndLoc);
|
|
||||||
|
|
||||||
if (StartLoc.isInvalid() || EndLoc.isInvalid()) {
|
|
||||||
Receiver({});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trace::enabled()) {
|
if (trace::enabled()) {
|
||||||
// FIXME: Implement tracing
|
// FIXME: Implement tracing
|
||||||
}
|
}
|
||||||
RangeResolver Resolver(AstUnit->getPrimarySourceFile(), StartLoc, EndLoc);
|
RangeResolver Resolver(AstUnit->getPrimarySourceFile(), Offset, Length);
|
||||||
ResolvedRangeInfo Info = Resolver.resolve();
|
ResolvedRangeInfo Info = Resolver.resolve();
|
||||||
|
|
||||||
CompilerInvocation CompInvok;
|
CompilerInvocation CompInvok;
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ enum class ActionType {
|
|||||||
GenerateModuleAPIDescription,
|
GenerateModuleAPIDescription,
|
||||||
DiffModuleAPI,
|
DiffModuleAPI,
|
||||||
ReconstructType,
|
ReconstructType,
|
||||||
|
Range,
|
||||||
};
|
};
|
||||||
|
|
||||||
class NullDebuggerClient : public DebuggerClient {
|
class NullDebuggerClient : public DebuggerClient {
|
||||||
@@ -208,6 +209,9 @@ Action(llvm::cl::desc("Mode:"), llvm::cl::init(ActionType::None),
|
|||||||
clEnumValN(ActionType::PrintModuleGroups,
|
clEnumValN(ActionType::PrintModuleGroups,
|
||||||
"print-module-groups",
|
"print-module-groups",
|
||||||
"Print group names in a module"),
|
"Print group names in a module"),
|
||||||
|
clEnumValN(ActionType::Range,
|
||||||
|
"range",
|
||||||
|
"Print information about a given range"),
|
||||||
clEnumValEnd));
|
clEnumValEnd));
|
||||||
|
|
||||||
static llvm::cl::opt<std::string>
|
static llvm::cl::opt<std::string>
|
||||||
@@ -523,6 +527,9 @@ DeclToPrint("decl-to-print",
|
|||||||
static llvm::cl::opt<std::string>
|
static llvm::cl::opt<std::string>
|
||||||
LineColumnPair("pos", llvm::cl::desc("Line:Column pair"));
|
LineColumnPair("pos", llvm::cl::desc("Line:Column pair"));
|
||||||
|
|
||||||
|
static llvm::cl::opt<std::string>
|
||||||
|
EndLineColumnPair("end-pos", llvm::cl::desc("Line:Column pair"));
|
||||||
|
|
||||||
static llvm::cl::opt<std::string>
|
static llvm::cl::opt<std::string>
|
||||||
USR("usr", llvm::cl::desc("USR"));
|
USR("usr", llvm::cl::desc("USR"));
|
||||||
|
|
||||||
@@ -2615,6 +2622,48 @@ static int doReconstructType(const CompilerInvocation &InitInvok,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int doPrintRangeInfo(const CompilerInvocation &InitInvok,
|
||||||
|
StringRef SourceFileName,
|
||||||
|
StringRef StartPos,
|
||||||
|
StringRef EndPos) {
|
||||||
|
auto StartOp = parseLineCol(StartPos);
|
||||||
|
auto EndOp = parseLineCol(EndPos);
|
||||||
|
if (!StartOp.hasValue() || !EndOp.hasValue())
|
||||||
|
return 1;
|
||||||
|
auto StartLineCol = StartOp.getValue();
|
||||||
|
auto EndLineCol = EndOp.getValue();
|
||||||
|
CompilerInvocation Invocation(InitInvok);
|
||||||
|
Invocation.addInputFilename(SourceFileName);
|
||||||
|
Invocation.getLangOptions().DisableAvailabilityChecking = false;
|
||||||
|
|
||||||
|
CompilerInstance CI;
|
||||||
|
|
||||||
|
// Display diagnostics to stderr.
|
||||||
|
PrintingDiagnosticConsumer PrintDiags;
|
||||||
|
CI.addDiagnosticConsumer(&PrintDiags);
|
||||||
|
if (CI.setup(Invocation))
|
||||||
|
return 1;
|
||||||
|
CI.performSema();
|
||||||
|
SourceFile *SF = nullptr;
|
||||||
|
for (auto Unit : CI.getMainModule()->getFiles()) {
|
||||||
|
SF = dyn_cast<SourceFile>(Unit);
|
||||||
|
if (SF)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(SF && "no source file?");
|
||||||
|
assert(SF->getBufferID().hasValue() && "no buffer id?");
|
||||||
|
SourceManager &SM = SF->getASTContext().SourceMgr;
|
||||||
|
unsigned bufferID = SF->getBufferID().getValue();
|
||||||
|
SourceLoc StartLoc = SM.getLocForLineCol(bufferID, StartLineCol.first,
|
||||||
|
StartLineCol.second);
|
||||||
|
SourceLoc EndLoc = SM.getLocForLineCol(bufferID, EndLineCol.first,
|
||||||
|
EndLineCol.second);
|
||||||
|
RangeResolver Resolver(*SF, StartLoc, EndLoc);
|
||||||
|
ResolvedRangeInfo Result = Resolver.resolve();
|
||||||
|
Result.print(llvm::outs());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int doPrintUSRs(const CompilerInvocation &InitInvok,
|
static int doPrintUSRs(const CompilerInvocation &InitInvok,
|
||||||
StringRef SourceFilename) {
|
StringRef SourceFilename) {
|
||||||
CompilerInvocation Invocation(InitInvok);
|
CompilerInvocation Invocation(InitInvok);
|
||||||
@@ -3026,6 +3075,11 @@ int main(int argc, char *argv[]) {
|
|||||||
case ActionType::ReconstructType:
|
case ActionType::ReconstructType:
|
||||||
ExitCode = doReconstructType(InitInvok, options::SourceFilename);
|
ExitCode = doReconstructType(InitInvok, options::SourceFilename);
|
||||||
break;
|
break;
|
||||||
|
case ActionType::Range:
|
||||||
|
ExitCode = doPrintRangeInfo(InitInvok, options::SourceFilename,
|
||||||
|
options::LineColumnPair,
|
||||||
|
options::EndLineColumnPair);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options::PrintStats)
|
if (options::PrintStats)
|
||||||
|
|||||||
Reference in New Issue
Block a user