Skip to content

Commit 277aef4

Browse files
committed
[SourceKit/CursorInfo] Include line and column in result
Add line/column in addition to offset so clients need not map it themselves. For serialized locations only output offset/line/column if the file is currently up to date with the one loaded in the semantic source manager.
1 parent 34eea60 commit 277aef4

File tree

10 files changed

+207
-175
lines changed

10 files changed

+207
-175
lines changed

include/swift/IDE/Utils.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,16 +124,6 @@ std::unique_ptr<llvm::MemoryBuffer>
124124
replacePlaceholders(std::unique_ptr<llvm::MemoryBuffer> InputBuf,
125125
bool *HadPlaceholder = nullptr);
126126

127-
void getLocationInfo(
128-
const ValueDecl *VD,
129-
llvm::Optional<std::pair<unsigned, unsigned>> &DeclarationLoc,
130-
StringRef &Filename);
131-
132-
void getLocationInfoForClangNode(ClangNode ClangNode,
133-
ClangImporter *Importer,
134-
llvm::Optional<std::pair<unsigned, unsigned>> &DeclarationLoc,
135-
StringRef &Filename);
136-
137127
Optional<std::pair<unsigned, unsigned>> parseLineCol(StringRef LineCol);
138128

139129
class XMLEscapingPrinter : public StreamPrinter {

lib/IDE/SwiftSourceDocInfo.cpp

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -798,89 +798,6 @@ ReturnInfo(ASTContext &Ctx, ArrayRef<ReturnInfo> Branches):
798798
}
799799
}
800800

801-
void swift::ide::getLocationInfoForClangNode(ClangNode ClangNode,
802-
ClangImporter *Importer,
803-
llvm::Optional<std::pair<unsigned, unsigned>> &DeclarationLoc,
804-
StringRef &Filename) {
805-
clang::ASTContext &ClangCtx = Importer->getClangASTContext();
806-
clang::SourceManager &ClangSM = ClangCtx.getSourceManager();
807-
808-
clang::SourceRange SR = ClangNode.getLocation();
809-
if (auto MD = dyn_cast_or_null<clang::ObjCMethodDecl>(ClangNode.getAsDecl())) {
810-
SR = clang::SourceRange(MD->getSelectorStartLoc(),
811-
MD->getDeclaratorEndLoc());
812-
}
813-
814-
clang::CharSourceRange CharRange =
815-
clang::Lexer::makeFileCharRange(clang::CharSourceRange::getTokenRange(SR),
816-
ClangSM, ClangCtx.getLangOpts());
817-
if (CharRange.isInvalid())
818-
return;
819-
820-
std::pair<clang::FileID, unsigned>
821-
Decomp = ClangSM.getDecomposedLoc(CharRange.getBegin());
822-
if (!Decomp.first.isInvalid()) {
823-
if (auto FE = ClangSM.getFileEntryForID(Decomp.first)) {
824-
Filename = FE->getName();
825-
826-
std::pair<clang::FileID, unsigned>
827-
EndDecomp = ClangSM.getDecomposedLoc(CharRange.getEnd());
828-
829-
DeclarationLoc = { Decomp.second, EndDecomp.second-Decomp.second };
830-
}
831-
}
832-
}
833-
834-
static unsigned getCharLength(SourceManager &SM, SourceRange TokenRange) {
835-
SourceLoc CharEndLoc = Lexer::getLocForEndOfToken(SM, TokenRange.End);
836-
return SM.getByteDistance(TokenRange.Start, CharEndLoc);
837-
}
838-
839-
void swift::ide::getLocationInfo(
840-
const ValueDecl *VD,
841-
llvm::Optional<std::pair<unsigned, unsigned>> &DeclarationLoc,
842-
StringRef &Filename) {
843-
ASTContext &Ctx = VD->getASTContext();
844-
SourceManager &SM = Ctx.SourceMgr;
845-
846-
auto ClangNode = VD->getClangNode();
847-
848-
SourceLoc Loc = VD->getLoc(/*SerializedOK=*/false);
849-
if (Loc.isValid()) {
850-
auto getSignatureRange = [&](const ValueDecl *VD) -> Optional<unsigned> {
851-
if (auto FD = dyn_cast<AbstractFunctionDecl>(VD)) {
852-
SourceRange R = FD->getSignatureSourceRange();
853-
if (R.isValid())
854-
return getCharLength(SM, R);
855-
}
856-
return None;
857-
};
858-
unsigned NameLen;
859-
if (auto SigLen = getSignatureRange(VD)) {
860-
NameLen = SigLen.getValue();
861-
} else if (VD->hasName()) {
862-
NameLen = VD->getBaseName().userFacingName().size();
863-
} else {
864-
NameLen = getCharLength(SM, Loc);
865-
}
866-
867-
unsigned DeclBufID = SM.findBufferContainingLoc(Loc);
868-
DeclarationLoc = { SM.getLocOffsetInBuffer(Loc, DeclBufID),
869-
NameLen };
870-
Filename = SM.getIdentifierForBuffer(DeclBufID);
871-
872-
} else if (auto *Positions =
873-
VD->getSerializedLocs(/*Resolve=*/false).Positions) {
874-
Filename = Positions->SourceFilePath;
875-
// TODO: Add location if it is up-to-date
876-
} else if (ClangNode) {
877-
ClangImporter *Importer =
878-
static_cast<ClangImporter*>(Ctx.getClangModuleLoader());
879-
return getLocationInfoForClangNode(ClangNode, Importer,
880-
DeclarationLoc, Filename);
881-
}
882-
}
883-
884801
CharSourceRange CallArgInfo::getEntireCharRange(const SourceManager &SM) const {
885802
return CharSourceRange(SM, LabelRange.getStart(),
886803
Lexer::getLocForEndOfToken(SM, ArgExp->getEndLoc()));

test/SourceKit/CursorInfo/cursor_info.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ func checkAnyIsAKeyword(x: Any) {}
284284
// CHECK5-NEXT: (Int) -> (){{$}}
285285

286286
// RUN: %sourcekitd-test -req=global-config -req-opts=optimize_for_ide=0 == -req=cursor -pos=9:32 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %s | %FileCheck -check-prefix=CHECK6 %s
287-
// CHECK6: source.lang.swift.ref.function.free ({{.*}}/FooSwiftModule.swift)
287+
// CHECK6: source.lang.swift.ref.function.free ({{.*}}/FooSwiftModule.swift:2:13-2:13)
288288
// CHECK6-NEXT: fooSwiftFunc
289289
// CHECK6-NEXT: s:14FooSwiftModule03fooB4FuncSiyF
290290
// CHECK6-NEXT: source.lang.swift

tools/SourceKit/include/SourceKit/Core/LangSupport.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,14 @@ struct ReferencedDeclInfo {
405405
IsSPI(SPI), ParentContexts(Parents) {}
406406
};
407407

408+
struct LocationInfo {
409+
StringRef Filename;
410+
unsigned Offset = 0;
411+
unsigned Length = 0;
412+
unsigned Line = 0;
413+
unsigned Column = 0;
414+
};
415+
408416
struct CursorSymbolInfo {
409417
UIdent Kind;
410418
UIdent DeclarationLang;
@@ -430,11 +438,8 @@ struct CursorSymbolInfo {
430438
/// Non-empty if a generated interface editor document has previously been
431439
/// opened for the module the symbol came from.
432440
StringRef ModuleInterfaceName;
433-
/// This is an (offset,length) pair. It is set only if the declaration has a
434-
/// source location.
435-
llvm::Optional<std::pair<unsigned, unsigned>> DeclarationLoc = None;
436-
/// Set only if the declaration has a source location.
437-
StringRef Filename;
441+
/// Filename is non-empty if there's a source location.
442+
LocationInfo Location;
438443
/// For methods this lists the USRs of the overrides in the class hierarchy.
439444
ArrayRef<StringRef> OverrideUSRs;
440445
/// Related declarations, overloaded functions etc., in annotated XML form.

tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2295,6 +2295,17 @@ ImmutableTextSnapshotRef SwiftEditorDocument::getLatestSnapshot() const {
22952295
return Impl.EditableBuffer->getSnapshot();
22962296
}
22972297

2298+
std::pair<unsigned, unsigned>
2299+
SwiftEditorDocument::getLineAndColumn(unsigned Offset) {
2300+
llvm::sys::ScopedLock L(Impl.AccessMtx);
2301+
2302+
auto SyntaxInfo = Impl.getSyntaxInfo();
2303+
auto &SM = SyntaxInfo->getSourceManager();
2304+
2305+
auto Loc = SM.getLocForOffset(SyntaxInfo->getBufferID(), Offset);
2306+
return SM.getLineAndColumnInBuffer(Loc);
2307+
}
2308+
22982309
void SwiftEditorDocument::reportDocumentStructure(SourceFile &SrcFile,
22992310
EditorConsumer &Consumer) {
23002311
ide::SyntaxModelContext ModelContext(SrcFile);

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class SwiftEditorDocument :
105105
void removeCachedAST();
106106

107107
ImmutableTextSnapshotRef getLatestSnapshot() const;
108+
std::pair<unsigned, unsigned> getLineAndColumn(unsigned Offset);
108109

109110
void parse(ImmutableTextSnapshotRef Snapshot, SwiftLangSupport &Lang,
110111
bool BuildSyntaxTree,

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 131 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -600,38 +600,46 @@ mapOffsetToNewerSnapshot(unsigned Offset,
600600
return None;
601601
}
602602

603-
/// Tries to remap the location from a previous snapshot to the latest one.
604-
static llvm::Optional<std::pair<unsigned, unsigned>>
605-
tryRemappingLocToLatestSnapshot(SwiftLangSupport &Lang,
606-
std::pair<unsigned, unsigned> Range,
607-
StringRef Filename,
608-
ArrayRef<ImmutableTextSnapshotRef> PreviousASTSnaps) {
609-
ImmutableTextSnapshotRef LatestSnap;
610-
if (auto EditorDoc = Lang.getEditorDocuments()->findByPath(Filename))
611-
LatestSnap = EditorDoc->getLatestSnapshot();
603+
/// Tries to remap the location from a previous snapshot to the latest one and
604+
/// then sets the location's line and column.
605+
static void mapLocToLatestSnapshot(
606+
SwiftLangSupport &Lang, LocationInfo &Location,
607+
ArrayRef<ImmutableTextSnapshotRef> PreviousASTSnaps) {
608+
auto EditorDoc = Lang.getEditorDocuments()->findByPath(Location.Filename);
609+
if (!EditorDoc)
610+
return;
611+
612+
ImmutableTextSnapshotRef LatestSnap = EditorDoc->getLatestSnapshot();
612613
if (!LatestSnap)
613-
return Range;
614+
return;
614615

615616
for (auto &PrevSnap : PreviousASTSnaps) {
616617
if (PrevSnap->isFromSameBuffer(LatestSnap)) {
617618
if (PrevSnap->getStamp() == LatestSnap->getStamp())
618-
return Range;
619+
break;
619620

620-
auto OptBegin = mapOffsetToNewerSnapshot(Range.first,
621+
auto OptBegin = mapOffsetToNewerSnapshot(Location.Offset,
621622
PrevSnap, LatestSnap);
622-
if (!OptBegin.hasValue())
623-
return None;
623+
if (!OptBegin.hasValue()) {
624+
Location.Filename = StringRef();
625+
return;
626+
}
624627

625-
auto OptEnd = mapOffsetToNewerSnapshot(Range.first+Range.second,
628+
auto OptEnd = mapOffsetToNewerSnapshot(Location.Offset +
629+
Location.Length,
626630
PrevSnap, LatestSnap);
627-
if (!OptEnd.hasValue())
628-
return None;
631+
if (!OptEnd.hasValue()) {
632+
Location.Filename = StringRef();
633+
return;
634+
}
629635

630-
return std::make_pair(*OptBegin, *OptEnd-*OptBegin);
636+
Location.Offset = *OptBegin;
637+
Location.Length = *OptEnd - *OptBegin;
631638
}
632639
}
633640

634-
return Range;
641+
std::tie(Location.Line, Location.Column) =
642+
EditorDoc->getLineAndColumn(Location.Offset);
635643
}
636644

637645

@@ -802,6 +810,106 @@ static ArrayRef<T> copyAndClearArray(llvm::BumpPtrAllocator &Allocator,
802810
return Ref;
803811
}
804812

813+
static void setLocationInfoForClangNode(ClangNode ClangNode,
814+
ClangImporter *Importer,
815+
LocationInfo &Location) {
816+
clang::ASTContext &ClangCtx = Importer->getClangASTContext();
817+
clang::SourceManager &ClangSM = ClangCtx.getSourceManager();
818+
819+
clang::SourceRange SR = ClangNode.getLocation();
820+
if (auto MD = dyn_cast_or_null<clang::ObjCMethodDecl>(ClangNode.getAsDecl())) {
821+
SR = clang::SourceRange(MD->getSelectorStartLoc(),
822+
MD->getDeclaratorEndLoc());
823+
}
824+
825+
clang::CharSourceRange CharRange =
826+
clang::Lexer::makeFileCharRange(clang::CharSourceRange::getTokenRange(SR),
827+
ClangSM, ClangCtx.getLangOpts());
828+
if (CharRange.isInvalid())
829+
return;
830+
831+
std::pair<clang::FileID, unsigned>
832+
Decomp = ClangSM.getDecomposedLoc(CharRange.getBegin());
833+
if (!Decomp.first.isInvalid()) {
834+
if (auto FE = ClangSM.getFileEntryForID(Decomp.first)) {
835+
Location.Filename = FE->getName();
836+
837+
std::pair<clang::FileID, unsigned>
838+
EndDecomp = ClangSM.getDecomposedLoc(CharRange.getEnd());
839+
840+
Location.Offset = Decomp.second;
841+
Location.Length = EndDecomp.second-Decomp.second;
842+
Location.Line = ClangSM.getLineNumber(Decomp.first, Decomp.second);
843+
Location.Column = ClangSM.getColumnNumber(Decomp.first, Decomp.second);
844+
}
845+
}
846+
}
847+
848+
static unsigned getCharLength(SourceManager &SM, SourceRange TokenRange) {
849+
SourceLoc CharEndLoc = Lexer::getLocForEndOfToken(SM, TokenRange.End);
850+
return SM.getByteDistance(TokenRange.Start, CharEndLoc);
851+
}
852+
853+
static void setLocationInfo(const ValueDecl *VD,
854+
LocationInfo &Location) {
855+
ASTContext &Ctx = VD->getASTContext();
856+
SourceManager &SM = Ctx.SourceMgr;
857+
858+
auto ClangNode = VD->getClangNode();
859+
860+
SourceLoc Loc = VD->getLoc(/*SerializedOK=*/false);
861+
if (Loc.isValid()) {
862+
auto getSignatureRange = [&](const ValueDecl *VD) -> Optional<unsigned> {
863+
if (auto FD = dyn_cast<AbstractFunctionDecl>(VD)) {
864+
SourceRange R = FD->getSignatureSourceRange();
865+
if (R.isValid())
866+
return getCharLength(SM, R);
867+
}
868+
return None;
869+
};
870+
unsigned NameLen;
871+
if (auto SigLen = getSignatureRange(VD)) {
872+
NameLen = SigLen.getValue();
873+
} else if (VD->hasName()) {
874+
NameLen = VD->getBaseName().userFacingName().size();
875+
} else {
876+
NameLen = getCharLength(SM, Loc);
877+
}
878+
879+
unsigned DeclBufID = SM.findBufferContainingLoc(Loc);
880+
Location.Filename = SM.getIdentifierForBuffer(DeclBufID);
881+
Location.Offset = SM.getLocOffsetInBuffer(Loc, DeclBufID);
882+
Location.Length = NameLen;
883+
std::tie(Location.Line, Location.Column) = SM.getLineAndColumnInBuffer(
884+
Loc, DeclBufID);
885+
} else if (auto *Positions =
886+
VD->getSerializedLocs(/*Resolve=*/false).Positions) {
887+
Location.Filename = Positions->SourceFilePath;
888+
889+
// Only add position information if the file is up to date
890+
if (auto *File = dyn_cast<LoadedFile>(
891+
VD->getDeclContext()->getModuleScopeContext())) {
892+
File->collectBasicSourceFileInfo([&](const BasicSourceFileInfo &Info) {
893+
auto Stat = SM.getFileSystem()->status(Info.getFilePath());
894+
if (!Stat)
895+
return;
896+
897+
if (Stat->getLastModificationTime() == Info.getLastModified() &&
898+
Stat->getSize() == Info.getFileSize()) {
899+
Location.Offset = Positions->Loc.Offset;
900+
Location.Length = 0;
901+
Location.Line = Positions->Loc.Line;
902+
Location.Column = Positions->Loc.Column;
903+
}
904+
});
905+
}
906+
} else if (ClangNode) {
907+
ClangImporter *Importer =
908+
static_cast<ClangImporter*>(Ctx.getClangModuleLoader());
909+
setLocationInfoForClangNode(ClangNode, Importer, Location);
910+
}
911+
}
912+
805913
static llvm::Error
806914
fillSymbolInfo(CursorSymbolInfo &Symbol, const DeclInfo &DInfo,
807915
ModuleDecl *MainModule, SourceLoc CursorLoc, bool AddSymbolGraph,
@@ -934,12 +1042,10 @@ fillSymbolInfo(CursorSymbolInfo &Symbol, const DeclInfo &DInfo,
9341042
Lang.getIFaceGenContexts().find(Symbol.ModuleName, Invoc))
9351043
Symbol.ModuleInterfaceName = IFaceGenRef->getDocumentName();
9361044

937-
getLocationInfo(DInfo.OriginalProperty, Symbol.DeclarationLoc,
938-
Symbol.Filename);
939-
if (Symbol.DeclarationLoc.hasValue()) {
940-
Symbol.DeclarationLoc = tryRemappingLocToLatestSnapshot(
941-
Lang, *Symbol.DeclarationLoc, Symbol.Filename, PreviousSnaps);
942-
if (!Symbol.DeclarationLoc.hasValue()) {
1045+
setLocationInfo(DInfo.OriginalProperty, Symbol.Location);
1046+
if (!Symbol.Location.Filename.empty()) {
1047+
mapLocToLatestSnapshot(Lang, Symbol.Location, PreviousSnaps);
1048+
if (Symbol.Location.Filename.empty()) {
9431049
return llvm::createStringError(
9441050
llvm::inconvertibleErrorCode(),
9451051
"Failed to remap declaration to latest snapshot.");

0 commit comments

Comments
 (0)