Skip to content

Commit 7d600eb

Browse files
committed
ABI/API checker: teach the tool to emit diagnostics to serialized source location for decls
1 parent eabce73 commit 7d600eb

File tree

6 files changed

+139
-70
lines changed

6 files changed

+139
-70
lines changed

include/swift/Basic/SourceManager.h

+5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class SourceManager {
4747
};
4848
std::map<const char *, VirtualFile> VirtualFiles;
4949
mutable std::pair<const char *, const VirtualFile*> CachedVFile = {nullptr, nullptr};
50+
51+
Optional<unsigned> findBufferContainingLocInternal(SourceLoc Loc) const;
5052
public:
5153
SourceManager(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
5254
llvm::vfs::getRealFileSystem())
@@ -115,6 +117,9 @@ class SourceManager {
115117
/// this routine always returns a valid buffer ID.
116118
unsigned findBufferContainingLoc(SourceLoc Loc) const;
117119

120+
/// Whether the source location is pointing to any buffer owned by the SourceManager.
121+
bool isOwning(SourceLoc Loc) const;
122+
118123
/// Adds a memory buffer to the SourceManager, taking ownership of it.
119124
unsigned addNewSourceBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer);
120125

lib/Basic/SourceLoc.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,8 @@ StringRef SourceManager::extractText(CharSourceRange Range,
213213
Range.getByteLength());
214214
}
215215

216-
unsigned SourceManager::findBufferContainingLoc(SourceLoc Loc) const {
216+
Optional<unsigned>
217+
SourceManager::findBufferContainingLocInternal(SourceLoc Loc) const {
217218
assert(Loc.isValid());
218219
// Search the buffers back-to front, so later alias buffers are
219220
// visited first.
@@ -226,9 +227,20 @@ unsigned SourceManager::findBufferContainingLoc(SourceLoc Loc) const {
226227
less_equal(Loc.Value.getPointer(), Buf->getBufferEnd()))
227228
return i;
228229
}
230+
return None;
231+
}
232+
233+
unsigned SourceManager::findBufferContainingLoc(SourceLoc Loc) const {
234+
auto Id = findBufferContainingLocInternal(Loc);
235+
if (Id.hasValue())
236+
return *Id;
229237
llvm_unreachable("no buffer containing location found");
230238
}
231239

240+
bool SourceManager::isOwning(SourceLoc Loc) const {
241+
return findBufferContainingLocInternal(Loc).hasValue();
242+
}
243+
232244
void SourceRange::widen(SourceRange Other) {
233245
if (Other.Start.Value.getPointer() < Start.Value.getPointer())
234246
Start = Other.Start;

test/api-digester/compare-dump-abi.swift

+15-6
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,20 @@
22
// RUN: %empty-directory(%t.mod2)
33
// RUN: %empty-directory(%t.sdk)
44
// RUN: %empty-directory(%t.module-cache)
5-
// RUN: %swift -emit-module -o %t.mod1/cake.swiftmodule %S/Inputs/cake_baseline/cake.swift -parse-as-library -enable-library-evolution -I %S/Inputs/APINotesLeft %clang-importer-sdk-nosource
6-
// RUN: %swift -emit-module -o %t.mod2/cake.swiftmodule %S/Inputs/cake_current/cake.swift -parse-as-library -enable-library-evolution -I %S/Inputs/APINotesRight %clang-importer-sdk-nosource
7-
// RUN: %api-digester -dump-sdk -module cake -o - -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod1 -I %S/Inputs/APINotesLeft -abi > %t.dump1.json
8-
// RUN: %api-digester -dump-sdk -module cake -o - -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod2 -I %S/Inputs/APINotesLeft -abi > %t.dump2.json
9-
// RUN: %api-digester -diagnose-sdk -print-module --input-paths %t.dump1.json -input-paths %t.dump2.json -abi -o %t.result
5+
// RUN: %swift -emit-module -o %t.mod1/cake.swiftmodule %S/Inputs/cake_baseline/cake.swift -parse-as-library -enable-library-evolution -I %S/Inputs/APINotesLeft %clang-importer-sdk-nosource -emit-module-source-info -emit-module-source-info-path %t.mod1/cake.swiftsourceinfo
6+
// RUN: %swift -emit-module -o %t.mod2/cake.swiftmodule %S/Inputs/cake_current/cake.swift -parse-as-library -enable-library-evolution -I %S/Inputs/APINotesRight %clang-importer-sdk-nosource -emit-module-source-info -emit-module-source-info-path %t.mod2/cake.swiftsourceinfo
7+
// RUN: %api-digester -dump-sdk -module cake -o %t.dump1.json -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod1 -I %S/Inputs/APINotesLeft -abi
8+
// RUN: %api-digester -diagnose-sdk -print-module -baseline-path %t.dump1.json -module cake -I %t.mod2 -I %S/Inputs/APINotesLeft -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -o %t.result
109
// RUN: %clang -E -P -x c %S/Outputs/Cake-abi.txt -o - | sed '/^\s*$/d' > %t.abi.expected
1110
// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.abi.result.tmp
12-
// RUN: diff -u %t.abi.expected %t.abi.result.tmp
11+
// RUN: diff -u %t.abi.expected %t.abi.result.tmp
12+
13+
// A compiler-style diag to ensure we have source locations associated with breakages.
14+
// RUN: not %api-digester -diagnose-sdk -print-module -baseline-path %t.dump1.json -module cake -I %t.mod2 -I %S/Inputs/APINotesLeft -module-cache-path %t.module-cache %clang-importer-sdk-nosource -abi -o %t.result -compiler-style-diags 2> %t.abi.compiler.diags
15+
// RUN: %FileCheck %s < %t.abi.compiler.diags
16+
17+
// CHECK: cake_current/cake.swift:31:14: error: cake: Class C4 has changed its super class from APINotesTest.OldType to APINotesTest.NewType
18+
// CHECK: cake_current/cake.swift:33:14: error: cake: Class C5 is now without @objc
19+
// CHECK: cake_current/cake.swift:35:23: error: cake: Func C5.dy_foo() is now with dynamic
20+
// CHECK: cake_current/cake.swift:39:15: error: cake: Struct C6 is now with @frozen
21+
// CHECK: cake_current/cake.swift:41:13: error: cake: Enum IceKind is now without @frozen

tools/swift-api-digester/ModuleAnalyzerNodes.cpp

+31-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ struct swift::ide::api::SDKNodeInitInfo {
2727
SDKContext &Ctx;
2828
DeclKind DKind;
2929
AccessorKind AccKind;
30-
30+
SourceLoc Loc;
3131
#define KEY_STRING(X, Y) StringRef X;
3232
#include "swift/IDE/DigesterEnums.def"
3333
#define KEY_BOOL(X, Y) bool X = false;
@@ -52,6 +52,29 @@ struct swift::ide::api::SDKNodeInitInfo {
5252

5353
SDKContext::SDKContext(CheckerOptions Opts): Diags(SourceMgr), Opts(Opts) {}
5454

55+
DiagnosticEngine &SDKContext::getDiags(SourceLoc Loc) {
56+
// If the location is invalid, we just use the locally created DiagEngine.
57+
if (Loc.isInvalid())
58+
return Diags;
59+
// If the Loc is valid, it may belong to any of the SourceManagers owned by
60+
// the ASTContexts we created, thus we should go through the ASTContxts to find
61+
// the right DiagnosticEngine to use.
62+
for (auto &CI: CIs) {
63+
if (CI->getSourceMgr().isOwning(Loc))
64+
return CI->getDiags();
65+
}
66+
llvm_unreachable("cannot find diagnostic engine to use");
67+
}
68+
69+
void SDKContext::addDiagConsumer(DiagnosticConsumer &Consumer) {
70+
// we may emit diagnostics via any of the diagnostic engine, so add the consumer
71+
// to all of them.
72+
Diags.addConsumer(Consumer);
73+
for (auto &CI: CIs) {
74+
CI->getDiags().addConsumer(Consumer);
75+
}
76+
}
77+
5578
void SDKNodeRoot::registerDescendant(SDKNode *D) {
5679
// Operator doesn't have usr
5780
if (isa<SDKNodeDeclOperator>(D))
@@ -70,7 +93,7 @@ SDKNodeRoot::SDKNodeRoot(SDKNodeInitInfo Info): SDKNode(Info, SDKNodeKind::Root)
7093
JsonFormatVer(Info.JsonFormatVer.hasValue() ? *Info.JsonFormatVer : DIGESTER_JSON_DEFAULT_VERSION) {}
7194

7295
SDKNodeDecl::SDKNodeDecl(SDKNodeInitInfo Info, SDKNodeKind Kind)
73-
: SDKNode(Info, Kind), DKind(Info.DKind), Usr(Info.Usr),
96+
: SDKNode(Info, Kind), DKind(Info.DKind), Usr(Info.Usr), Loc(Info.Loc),
7497
Location(Info.Location), ModuleName(Info.ModuleName),
7598
DeclAttributes(Info.DeclAttrs), IsImplicit(Info.IsImplicit),
7699
IsStatic(Info.IsStatic), IsDeprecated(Info.IsDeprecated),
@@ -1297,7 +1320,7 @@ StringRef SDKContext::getInitKind(Decl *D) {
12971320
}
12981321

12991322
SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Decl *D):
1300-
Ctx(Ctx), DKind(D->getKind()),
1323+
Ctx(Ctx), DKind(D->getKind()), Loc(D->getLoc()),
13011324
Location(calculateLocation(Ctx, D)),
13021325
ModuleName(D->getModuleContext()->getName().str()),
13031326
GenericSig(printGenericSignature(Ctx, D, /*Canonical*/Ctx.checkingABI())),
@@ -2143,6 +2166,9 @@ swift::ide::api::getSDKNodeRoot(SDKContext &SDKCtx,
21432166
if (llvm::errs().has_colors())
21442167
PrintDiags.forceColors();
21452168
CI.addDiagnosticConsumer(&PrintDiags);
2169+
// The PrintDiags is only responsible compiler errors, we should remove the
2170+
// consumer immediately after importing is done.
2171+
SWIFT_DEFER { CI.getDiags().removeConsumer(PrintDiags); };
21462172
if (CI.setup(Invocation)) {
21472173
llvm::errs() << "Failed to setup the compiler instance\n";
21482174
return nullptr;
@@ -2211,7 +2237,7 @@ int swift::ide::api::deserializeSDKDump(StringRef dumpPath, StringRef OutputPath
22112237
}
22122238
PrintingDiagnosticConsumer PDC;
22132239
SDKContext Ctx(Opts);
2214-
Ctx.getDiags().addConsumer(PDC);
2240+
Ctx.addDiagConsumer(PDC);
22152241

22162242
SwiftDeclCollector Collector(Ctx);
22172243
Collector.deSerialize(dumpPath);
@@ -2227,7 +2253,7 @@ int swift::ide::api::findDeclUsr(StringRef dumpPath, CheckerOptions Opts) {
22272253
}
22282254
PrintingDiagnosticConsumer PDC;
22292255
SDKContext Ctx(Opts);
2230-
Ctx.getDiags().addConsumer(PDC);
2256+
Ctx.addDiagConsumer(PDC);
22312257

22322258
SwiftDeclCollector Collector(Ctx);
22332259
Collector.deSerialize(dumpPath);

tools/swift-api-digester/ModuleAnalyzerNodes.h

+8-6
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,9 @@ class SDKContext {
202202
SourceManager &getSourceMgr() {
203203
return SourceMgr;
204204
}
205-
DiagnosticEngine &getDiags() {
206-
return Diags;
207-
}
205+
// Find a DiagnosticEngine to use when emitting diagnostics at the given Loc.
206+
DiagnosticEngine &getDiags(SourceLoc Loc = SourceLoc());
207+
void addDiagConsumer(DiagnosticConsumer &Consumer);
208208
void setCommonVersion(uint8_t Ver) {
209209
assert(!CommonVersion.hasValue());
210210
CommonVersion = Ver;
@@ -337,6 +337,7 @@ struct PlatformIntroVersion {
337337
class SDKNodeDecl: public SDKNode {
338338
DeclKind DKind;
339339
StringRef Usr;
340+
SourceLoc Loc;
340341
StringRef Location;
341342
StringRef ModuleName;
342343
std::vector<DeclAttrKind> DeclAttributes;
@@ -393,20 +394,21 @@ class SDKNodeDecl: public SDKNode {
393394
uint8_t getFixedBinaryOrder() const { return *FixedBinaryOrder; }
394395
PlatformIntroVersion getIntroducingVersion() const { return introVersions; }
395396
StringRef getObjCName() const { return ObjCName; }
397+
SourceLoc getLoc() const { return Loc; }
396398
virtual void jsonize(json::Output &Out) override;
397399
virtual void diagnose(SDKNode *Right) override;
398400

399401
// The first argument of the diag is always screening info.
400402
template<typename ...ArgTypes>
401-
void emitDiag(Diag<StringRef, ArgTypes...> ID,
403+
void emitDiag(SourceLoc Loc,
404+
Diag<StringRef, ArgTypes...> ID,
402405
typename detail::PassArgument<ArgTypes>::type... Args) const {
403406
// Don't emit objc decls if we care about swift exclusively
404407
if (Ctx.getOpts().SwiftOnly) {
405408
if (isObjc())
406409
return;
407410
}
408-
Ctx.getDiags().diagnose(SourceLoc(), ID, getScreenInfo(),
409-
std::move(Args)...);
411+
Ctx.getDiags(Loc).diagnose(Loc, ID, getScreenInfo(), std::move(Args)...);
410412
}
411413
};
412414

0 commit comments

Comments
 (0)