Skip to content

Commit b63d89b

Browse files
authored
Merge pull request #39923 from NuriAmari/diagnostics-revamp
[WIP] Improve ClangImporter Diagnostics
2 parents 801337e + 130f2de commit b63d89b

36 files changed

+1567
-78
lines changed

include/swift/AST/ASTContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,9 @@ class ASTContext final {
11601160
InheritedProtocolConformance *
11611161
getInheritedConformance(Type type, ProtocolConformance *inherited);
11621162

1163+
/// Check if \p decl is included in LazyContexts.
1164+
bool isLazyContext(const DeclContext *decl);
1165+
11631166
/// Get the lazy data for the given declaration.
11641167
///
11651168
/// \param lazyLoader If non-null, the lazy loader to use when creating the

include/swift/AST/ClangModuleLoader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ class ClangModuleLoader : public ModuleLoader {
182182
/// Imports a clang decl directly, rather than looking up its name.
183183
virtual Decl *importDeclDirectly(const clang::NamedDecl *decl) = 0;
184184

185+
/// Emits any import diagnostics associated with the provided decl.
186+
virtual void diagnoseDeclDirectly(const clang::NamedDecl *decl) = 0;
187+
185188
/// Instantiate and import class template using given arguments.
186189
///
187190
/// This method will find the clang::ClassTemplateSpecialization decl if

include/swift/AST/DiagnosticEngine.h

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
#include "llvm/Support/SaveAndRestore.h"
3434
#include "llvm/Support/VersionTuple.h"
3535

36+
namespace clang {
37+
class NamedDecl;
38+
}
39+
3640
namespace swift {
3741
class Decl;
3842
class DeclAttribute;
@@ -116,7 +120,8 @@ namespace swift {
116120
VersionTuple,
117121
LayoutConstraint,
118122
ActorIsolation,
119-
Diagnostic
123+
Diagnostic,
124+
ClangDecl
120125
};
121126

122127
namespace diag {
@@ -149,6 +154,7 @@ namespace swift {
149154
LayoutConstraint LayoutConstraintVal;
150155
ActorIsolation ActorIsolationVal;
151156
DiagnosticInfo *DiagnosticVal;
157+
const clang::NamedDecl *ClangDecl;
152158
};
153159

154160
public:
@@ -251,6 +257,9 @@ namespace swift {
251257
DiagnosticVal(D) {
252258
}
253259

260+
DiagnosticArgument(const clang::NamedDecl *ND)
261+
: Kind(DiagnosticArgumentKind::ClangDecl), ClangDecl(ND) {}
262+
254263
/// Initializes a diagnostic argument using the underlying type of the
255264
/// given enum.
256265
template<
@@ -356,6 +365,11 @@ namespace swift {
356365
assert(Kind == DiagnosticArgumentKind::Diagnostic);
357366
return DiagnosticVal;
358367
}
368+
369+
const clang::NamedDecl *getAsClangDecl() const {
370+
assert(Kind == DiagnosticArgumentKind::ClangDecl);
371+
return ClangDecl;
372+
}
359373
};
360374

361375
/// Describes the current behavior to take with a diagnostic.
@@ -1327,18 +1341,20 @@ namespace swift {
13271341
builder();
13281342
}
13291343

1330-
/// Temporary on-stack storage and unescaping for encoded diagnostic
1331-
/// messages.
1332-
class EncodedDiagnosticMessage {
1333-
llvm::SmallString<128> Buf;
1344+
void printClangDeclName(const clang::NamedDecl *ND, llvm::raw_ostream &os);
13341345

1335-
public:
1336-
/// \param S A string with an encoded message
1337-
EncodedDiagnosticMessage(StringRef S);
1346+
/// Temporary on-stack storage and unescaping for encoded diagnostic
1347+
/// messages.
1348+
class EncodedDiagnosticMessage {
1349+
llvm::SmallString<128> Buf;
13381350

1339-
/// The unescaped message to display to the user.
1340-
const StringRef Message;
1341-
};
1351+
public:
1352+
/// \param S A string with an encoded message
1353+
EncodedDiagnosticMessage(StringRef S);
1354+
1355+
/// The unescaped message to display to the user.
1356+
const StringRef Message;
1357+
};
13421358

13431359
/// Returns a value that can be used to select between accessor kinds in
13441360
/// diagnostics.

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,30 @@ WARNING(import_multiple_mainactor_attr,none,
100100

101101
ERROR(module_map_not_found, none, "module map file '%0' not found", (StringRef))
102102

103+
NOTE(macro_not_imported_unsupported_operator, none, "operator not supported in macro arithmetic", ())
104+
NOTE(macro_not_imported_unsupported_named_operator, none, "operator '%0' not supported in macro arithmetic", (StringRef))
105+
NOTE(macro_not_imported_invalid_string_literal, none, "invalid string literal", ())
106+
NOTE(macro_not_imported_invalid_numeric_literal, none, "invalid numeric literal", ())
107+
NOTE(macro_not_imported_unsupported_literal, none, "only numeric and string macro literals supported", ())
108+
NOTE(macro_not_imported_nested_cast, none, "non-null nested casts not supported", ())
109+
110+
ERROR(macro_not_imported_function_like, none, "macro '%0' not imported: function like macros not supported", (StringRef))
111+
ERROR(macro_not_imported_unsupported_structure, none, "macro '%0' not imported: structure not supported", (StringRef))
112+
ERROR(macro_not_imported, none, "macro '%0' not imported", (StringRef))
113+
114+
NOTE(return_type_not_imported, none, "return type not imported", ())
115+
NOTE(parameter_type_not_imported, none, "parameter %0 not imported", (const clang::NamedDecl*))
116+
NOTE(incomplete_interface, none, "interface %0 is incomplete", (const clang::NamedDecl*))
117+
NOTE(incomplete_protocol, none, "protocol %0 is incomplete", (const clang::NamedDecl*))
118+
NOTE(unsupported_builtin_type, none, "built-in type '%0' not supported", (StringRef))
119+
120+
WARNING(record_field_not_imported, none, "field %0 not imported", (const clang::NamedDecl*))
121+
WARNING(invoked_func_not_imported, none, "function %0 not imported", (const clang::NamedDecl*))
122+
WARNING(record_method_not_imported, none, "method %0 not imported", (const clang::NamedDecl*))
123+
WARNING(objc_property_not_imported, none, "property %0 not imported", (const clang::NamedDecl*))
124+
125+
NOTE(forward_declared_interface_label, none, "interface %0 forward declared here", (const clang::NamedDecl*))
126+
NOTE(forward_declared_protocol_label, none, "protocol %0 forward declared here", (const clang::NamedDecl*))
127+
103128
#define UNDEFINE_DIAGNOSTIC_MACROS
104129
#include "DefineDiagnosticMacros.h"

include/swift/AST/LazyResolver.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ class alignas(void*) LazyMemberLoader {
8585
loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N,
8686
uint64_t contextData) = 0;
8787

88+
virtual void diagnoseMissingNamedMember(const IterableDeclContext *IDC,
89+
DeclName name) = 0;
90+
8891
/// Populates the given vector with all conformances for \p D.
8992
///
9093
/// The implementation should \em not call setConformances on \p D.

include/swift/Basic/LangOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,12 @@ namespace swift {
320320
/// Enable experimental flow-sensitive concurrent captures.
321321
bool EnableExperimentalFlowSensitiveConcurrentCaptures = false;
322322

323+
/// Enable experimental ClangImporter diagnostics.
324+
bool EnableExperimentalClangImporterDiagnostics = false;
325+
326+
/// Enable experimental eager Clang module diagnostics.
327+
bool EnableExperimentalEagerClangModuleDiagnostics = false;
328+
323329
/// Enable inference of Sendable conformances for public types.
324330
bool EnableInferPublicSendable = false;
325331

include/swift/ClangImporter/ClangImporter.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace clang {
4040
class EnumDecl;
4141
class MacroInfo;
4242
class Module;
43+
class ModuleMacro;
4344
class NamedDecl;
4445
class Sema;
4546
class TargetInfo;
@@ -109,6 +110,11 @@ class DWARFImporterDelegate {
109110
virtual void anchor();
110111
};
111112

113+
typedef llvm::PointerUnion<const clang::Decl *, const clang::MacroInfo *,
114+
const clang::ModuleMacro *, const clang::Type *,
115+
const clang::Token *>
116+
ImportDiagnosticTarget;
117+
112118
/// Class that imports Clang modules into Swift, mapping directly
113119
/// from Clang ASTs over to Swift ASTs.
114120
class ClangImporter final : public ClangModuleLoader {
@@ -509,6 +515,9 @@ class ClangImporter final : public ClangModuleLoader {
509515

510516
/// Imports a clang decl directly, rather than looking up it's name.
511517
Decl *importDeclDirectly(const clang::NamedDecl *decl) override;
518+
519+
/// Emits any pending diagnostics associated with the provided decl.
520+
void diagnoseDeclDirectly(const clang::NamedDecl *decl) override;
512521
};
513522

514523
ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,

include/swift/Option/FrontendOptions.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,14 @@ def enable_experimental_flow_sensitive_concurrent_captures :
287287
Flag<["-"], "enable-experimental-flow-sensitive-concurrent-captures">,
288288
HelpText<"Enable flow-sensitive concurrent captures">;
289289

290+
def enable_experimental_clang_importer_diagnostics :
291+
Flag<["-"], "enable-experimental-clang-importer-diagnostics">,
292+
HelpText<"Enable experimental diagnostics when importing C, C++, and Objective-C libraries">;
293+
294+
def enable_experimental_eager_clang_module_diagnostics :
295+
Flag<["-"], "enable-experimental-eager-clang-module-diagnostics">,
296+
HelpText<"Enable experimental eager diagnostics reporting on the importability of all referenced C, C++, and Objective-C libraries">;
297+
290298
def enable_resilience : Flag<["-"], "enable-resilience">,
291299
HelpText<"Deprecated, use -enable-library-evolution instead">;
292300
}

lib/AST/ASTContext.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2462,6 +2462,10 @@ ASTContext::getInheritedConformance(Type type, ProtocolConformance *inherited) {
24622462
return result;
24632463
}
24642464

2465+
bool ASTContext::isLazyContext(const DeclContext *dc) {
2466+
return getImpl().LazyContexts.count(dc) != 0;
2467+
}
2468+
24652469
LazyContextData *ASTContext::getOrCreateLazyContextData(
24662470
const DeclContext *dc,
24672471
LazyMemberLoader *lazyLoader) {

lib/AST/DiagnosticEngine.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
//===----------------------------------------------------------------------===//
1717

1818
#include "swift/AST/DiagnosticEngine.h"
19-
#include "swift/AST/DiagnosticsCommon.h"
2019
#include "swift/AST/ASTContext.h"
2120
#include "swift/AST/ASTPrinter.h"
2221
#include "swift/AST/Decl.h"
2322
#include "swift/AST/DiagnosticSuppression.h"
23+
#include "swift/AST/DiagnosticsCommon.h"
2424
#include "swift/AST/Module.h"
2525
#include "swift/AST/Pattern.h"
2626
#include "swift/AST/PrintOptions.h"
@@ -30,6 +30,8 @@
3030
#include "swift/Config.h"
3131
#include "swift/Localization/LocalizationFormat.h"
3232
#include "swift/Parse/Lexer.h" // bad dependency
33+
#include "clang/AST/ASTContext.h"
34+
#include "clang/AST/Decl.h"
3335
#include "llvm/ADT/SmallString.h"
3436
#include "llvm/ADT/Twine.h"
3537
#include "llvm/Support/CommandLine.h"
@@ -566,6 +568,11 @@ static bool isMainActor(Type type) {
566568
return false;
567569
}
568570

571+
void swift::printClangDeclName(const clang::NamedDecl *ND,
572+
llvm::raw_ostream &os) {
573+
ND->getNameForDiagnostic(os, ND->getASTContext().getPrintingPolicy(), false);
574+
}
575+
569576
/// Format a single diagnostic argument and write it to the given
570577
/// stream.
571578
static void formatDiagnosticArgument(StringRef Modifier,
@@ -832,6 +839,13 @@ static void formatDiagnosticArgument(StringRef Modifier,
832839
diagArg->FormatArgs);
833840
break;
834841
}
842+
843+
case DiagnosticArgumentKind::ClangDecl:
844+
assert(Modifier.empty() && "Improper modifier for ClangDecl argument");
845+
Out << FormatOpts.OpeningQuotationMark;
846+
printClangDeclName(Arg.getAsClangDecl(), Out);
847+
Out << FormatOpts.ClosingQuotationMark;
848+
break;
835849
}
836850
}
837851

lib/AST/NameLookup.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1494,12 +1494,22 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
14941494
populateLookupTableEntryFromExtensions(ctx, Table, baseName, decl);
14951495
}
14961496

1497-
Table.markLazilyComplete(name.getBaseName());
1497+
Table.markLazilyComplete(baseName);
14981498
}
14991499

15001500
// Look for a declaration with this name.
15011501
auto known = Table.find(name);
15021502
if (known == Table.end()) {
1503+
// Diagnose the missing member if:
1504+
// - The flag enabling ClangImporter diagnostics is passed.
1505+
// - The containing decl is a ClangDecl.
1506+
// - The containing decl (and DeclContext) is lazy.
1507+
if (ctx.LangOpts.EnableExperimentalClangImporterDiagnostics &&
1508+
ctx.isLazyContext(decl) && decl->getDecl()->getClangDecl()) {
1509+
auto ci =
1510+
ctx.getOrCreateLazyIterableContextData(decl, /*lazyLoader=*/nullptr);
1511+
ci->loader->diagnoseMissingNamedMember(decl, name);
1512+
}
15031513
return TinyPtrVector<ValueDecl *>();
15041514
}
15051515

0 commit comments

Comments
 (0)