diff --git a/include/swift/AST/DefineDiagnosticMacros.h b/include/swift/AST/DefineDiagnosticMacros.h index c71691ef21e1a..88b12ec9798bf 100644 --- a/include/swift/AST/DefineDiagnosticMacros.h +++ b/include/swift/AST/DefineDiagnosticMacros.h @@ -18,8 +18,8 @@ #ifdef DEFINE_DIAGNOSTIC_MACROS #if !(defined(DIAG) || (defined(GROUPED_ERROR) && defined(GROUPED_WARNING) && \ - defined(NOTE) && defined(REMARK))) -#error Must define either DIAG or the set {GROUPED_ERROR,GROUPED_WARNING,NOTE,REMARK} + defined(NOTE) && defined(GROUPED_REMARK))) +#error Must define either DIAG or the set {GROUPED_ERROR,GROUPED_WARNING,NOTE,GROUPED_REMARK} #endif #ifndef GROUPED_ERROR @@ -47,9 +47,14 @@ DIAG(NOTE, ID, no_group, Options, Text, Signature) #endif +#ifndef GROUPED_REMARK +#define GROUPED_REMARK(ID, Group, Options, Text, Signature) \ + DIAG(REMARK, ID, Group, Options, Text, Signature) +#endif + #ifndef REMARK #define REMARK(ID, Options, Text, Signature) \ - DIAG(REMARK, ID, no_group, Options, Text, Signature) + GROUPED_REMARK(ID, no_group, Options, Text, Signature) #endif #ifndef FIXIT @@ -69,6 +74,7 @@ #endif #undef REMARK +#undef GROUPED_REMARK #undef NOTE #undef WARNING #undef GROUPED_WARNING diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 7f4a45a3a06eb..ad17e0a1bc3e7 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -31,6 +31,7 @@ #include "swift/Localization/LocalizationFormat.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" @@ -53,6 +54,7 @@ namespace swift { class SourceFile; class ParamDecl; class AnyPattern; + class DiagnosticOptions; /// Enumeration describing all of possible diagnostics. /// @@ -639,6 +641,9 @@ namespace swift { /// values of this map to Swift clients. WarningGroupBehaviorMap warningGroupBehaviorMap; + /// Groups with remarks enabled. All remarks are disabled by default. + llvm::SmallSet enabledRemarkGroups; + /// For compiler-internal purposes only, track which diagnostics should /// be ignored completely. For example, this is used by LLDB to /// suppress certain errors in expression evaluation. @@ -721,6 +726,17 @@ namespace swift { return ruleRefArray; } + void enableRemarkGroup(DiagGroupID Group) { + if (!enabledRemarkGroups.insert(Group).second) + return; + for (auto SubGroup : getDiagGroupInfoByID(Group).subgroups) + enableRemarkGroup(SubGroup); + } + + bool isRemarkGroupEnabled(DiagGroupID Group) const { + return enabledRemarkGroups.contains(Group); + } + void resetHadAnyError() { anyErrorOccurred = false; fatalErrorOccurred = false; @@ -742,6 +758,7 @@ namespace swift { std::swap(suppressNotes, other.suppressNotes); std::swap(suppressRemarks, other.suppressRemarks); std::swap(warningGroupBehaviorMap, other.warningGroupBehaviorMap); + std::swap(enabledRemarkGroups, other.enabledRemarkGroups); std::swap(fatalErrorOccurred, other.fatalErrorOccurred); std::swap(anyErrorOccurred, other.anyErrorOccurred); std::swap(previousBehavior, other.previousBehavior); @@ -987,6 +1004,14 @@ namespace swift { return state.getWarningGroupBehaviorControlRefArray(); } + void enableRemarkGroup(DiagGroupID Group) { + state.enableRemarkGroup(Group); + } + + bool isRemarkGroupEnabled(DiagGroupID Group) const { + return state.isRemarkGroupEnabled(Group); + } + /// Whether to print diagnostic names after their messages void setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode val) { printDiagnosticNamesMode = val; @@ -1282,7 +1307,17 @@ namespace swift { void forwardTentativeDiagnosticsTo(DiagnosticEngine &targetEngine); public: - DiagnosticKind declaredDiagnosticKindFor(const DiagID id); + static DiagnosticKind declaredDiagnosticKindFor(const DiagID id); + + /// Returns diagnostic documentation path, using the user-provided path if + /// explicitly set, or falling back to the docs.swift.org URL. + static std::string + resolveDiagnosticDocumentationPath(const DiagnosticOptions &opts); + + /// Returns the local diagnostic documentation path derived from the + /// compiler's executable path. + static std::string + resolveLocalDiagnosticDocumentationPath(llvm::StringRef mainExecutablePath); /// Get a localized format string for the given `DiagID`. If no localization /// is available, returns the default string. diff --git a/include/swift/AST/DiagnosticGroups.def b/include/swift/AST/DiagnosticGroups.def index 36acddc4516d3..a7d4fa43752f7 100644 --- a/include/swift/AST/DiagnosticGroups.def +++ b/include/swift/AST/DiagnosticGroups.def @@ -40,6 +40,7 @@ GROUP(no_group,none,"") +GROUP(AccessNote,ToolchainLocalDocumentation,"access-note") GROUP(ActorIsolatedCall,none,"actor-isolated-call") GROUP(ActorIsolatedMutatingAsync,none,"actor-isolated-mutating-async") GROUP(AlwaysAvailableDomain,none,"always-available-domain") @@ -47,10 +48,12 @@ GROUP(AvailabilityUnrecognizedName,none,"availability-unrecognized-name") GROUP(ClangDeclarationImport,none,"clang-declaration-import") GROUP(CompilationCaching,none,"compilation-caching") GROUP(ConformanceIsolation,none,"conformance-isolation") -GROUP(ForeignReferenceType,none,"foreign-reference-type") +GROUP(CrossImport,ToolchainLocalDocumentation,"cross-import") +GROUP(DependencyScan,ToolchainLocalDocumentation | FrontendOnly,"dependency-scan") +GROUP(DependencyScanCache,ToolchainLocalDocumentation | FrontendOnly,"dependency-scan-cache") GROUP(DeprecatedDeclaration,none,"deprecated-declaration") -GROUP(DynamicExclusivity,DefaultIgnoreWarnings,"dynamic-exclusivity") GROUP(DynamicCallable,none,"dynamic-callable-requirements") +GROUP(DynamicExclusivity,DefaultIgnoreWarnings,"dynamic-exclusivity") GROUP(EmbeddedRestrictions,DefaultIgnoreWarnings,"embedded-restrictions") GROUP(ErrorInFutureSwiftVersion,none,"error-in-future-swift-version") GROUP(ExclusivityViolation,none,"exclusivity-violation") @@ -58,20 +61,30 @@ GROUP(ExistentialAny,none,"existential-any") GROUP(ExistentialMemberAccess,none,"existential-member-access-limitations") GROUP(ExistentialType,ToolchainLocalDocumentation,"existential-type") GROUP(ExplicitSendable,DefaultIgnoreWarnings,"explicit-sendable-annotations") +GROUP(ForeignReferenceType,none,"foreign-reference-type") GROUP(ImplementationOnlyDeprecated,none,"implementation-only-deprecated") GROUP(ImplicitStrongCapture,none,"implicit-strong-capture") +GROUP(IndexingSystemModule,ToolchainLocalDocumentation,"indexing-system-module") GROUP(IsolatedConformances,none,"isolated-conformances") +GROUP(MacroExpansions,ToolchainLocalDocumentation | FrontendOnly,"macro-expansions") +GROUP(MacroLoading,ToolchainLocalDocumentation,"macro-loading") GROUP(MemberImportVisibility,none,"member-import-visibility") GROUP(MissingModuleOnKnownPaths,none,"missing-module-on-known-paths") -GROUP(OptionObsoletedByModuleSelectors,none,"option-obsoleted-by-module-selectors") +GROUP(ModularizationIssue,ToolchainLocalDocumentation,"modularization-issue") +GROUP(ModuleAPIImport,ToolchainLocalDocumentation,"module-api-import") +GROUP(ModuleInterfaceRebuild,ToolchainLocalDocumentation | FrontendOnly,"module-interface-rebuild") +GROUP(ModuleLoading,ToolchainLocalDocumentation,"module-loading") GROUP(ModuleNotTestable,none,"module-not-testable") +GROUP(ModuleSerialization,ToolchainLocalDocumentation,"module-serialization") GROUP(ModuleVersionMissing,none,"module-version-missing") GROUP(MultipleInheritance,none,"multiple-inheritance") GROUP(MutableGlobalVariable,none,"mutable-global-variable") GROUP(NominalTypes,none,"nominal-types") GROUP(NonisolatedNonsendingByDefault,none,"nonisolated-nonsending-by-default") -GROUP(OpaqueTypeInference,none,"opaque-type-inference") +GROUP(OldSuppressedAssociatedTypes,none,"old-suppressed-associatedtypes") GROUP(OSLog,none,"oslog") +GROUP(OpaqueTypeInference,none,"opaque-type-inference") +GROUP(OptionObsoletedByModuleSelectors,none,"option-obsoleted-by-module-selectors") GROUP(PerformanceHints,DefaultIgnoreWarnings,"performance-hints") GROUP(PreconcurrencyImport,DefaultIgnoreWarnings,"preconcurrency-import") GROUP(PropertyWrappers,none,"property-wrapper-requirements") @@ -79,22 +92,21 @@ GROUP(ProtocolTypeNonConformance,none,"protocol-type-non-conformance") GROUP(RegionIsolation,none,"region-isolation") GROUP(ResultBuilderMethods,none,"result-builder-methods") GROUP(ReturnTypeImplicitCopy,ToolchainLocalDocumentation,"return-type-implicit-copy") +GROUP(SemanticCopies,DefaultIgnoreWarnings,"semantic-copies") GROUP(SendableClosureCaptures,none,"sendable-closure-captures") GROUP(SendableMetatypes,none,"sendable-metatypes") -GROUP(SemanticCopies,DefaultIgnoreWarnings,"semantic-copies") GROUP(SendingClosureRisksDataRace,none,"sending-closure-risks-data-race") GROUP(SendingRisksDataRace,none,"sending-risks-data-race") GROUP(StrictLanguageFeatures,none,"strict-language-features") -GROUP(UnrecognizedStrictLanguageFeatures,DefaultIgnoreWarnings,"strict-language-features") GROUP(StrictMemorySafety,none,"strict-memory-safety") GROUP(StringInterpolationConformance,none,"string-interpolation-conformance") GROUP(TemporaryPointers,none,"temporary-pointers") GROUP(TrailingClosureMatching,none,"trailing-closure-matching") GROUP(UnknownWarningGroup,none,"unknown-warning-group") +GROUP(UnrecognizedStrictLanguageFeatures,DefaultIgnoreWarnings,"strict-language-features") GROUP(UntypedThrows,DefaultIgnoreWarnings,"untyped-throws") GROUP(UseAnyAppleOSAvailability,DefaultIgnoreWarnings,"use-any-apple-os-availability") GROUP(WeakMutability,none,"weak-mutability") -GROUP(OldSuppressedAssociatedTypes,none,"old-suppressed-associatedtypes") GROUP_LINK(PerformanceHints,ExistentialType) GROUP_LINK(PerformanceHints,ReturnTypeImplicitCopy) @@ -105,5 +117,7 @@ GROUP_LINK(RegionIsolation,SendingRisksDataRace) GROUP_LINK(StrictLanguageFeatures, UnrecognizedStrictLanguageFeatures) +GROUP_LINK(DependencyScan,DependencyScanCache) + #define UNDEFINE_DIAGNOSTIC_GROUPS_MACROS #include "swift/AST/DefineDiagnosticGroupsMacros.h" diff --git a/include/swift/AST/DiagnosticGroups.h b/include/swift/AST/DiagnosticGroups.h index 24006d38597af..b017d071606c4 100644 --- a/include/swift/AST/DiagnosticGroups.h +++ b/include/swift/AST/DiagnosticGroups.h @@ -22,7 +22,6 @@ #include "llvm/ADT/ArrayRef.h" #include #include -#include namespace swift { enum class DiagnosticGroupOptions { @@ -36,6 +35,9 @@ enum class DiagnosticGroupOptions { /// The documentation file for this diagnostic group is distributed in the toolchain /// directly. ToolchainLocalDocumentation = 1 << 1, + + /// This diagnostic group is not accessible through the compiler driver. + FrontendOnly = 1 << 2, }; enum class DiagID : uint32_t; @@ -61,6 +63,7 @@ struct DiagGroupInfo { llvm::ArrayRef diagnostics; bool defaultIgnoreWarnings : 1; bool toolchainLocalDocumentation : 1; + bool frontendOnly : 1; constexpr DiagGroupInfo(DiagGroupID groupID, std::string_view name, std::string_view documentationFile, @@ -68,11 +71,13 @@ struct DiagGroupInfo { llvm::ArrayRef subgroups, llvm::ArrayRef diagnostics, bool defaultIgnoreWarnings, - bool toolchainLocalDocumentation) + bool toolchainLocalDocumentation, + bool frontendOnly) : id(groupID), name(name), documentationFile(documentationFile), supergroups(supergroups), subgroups(subgroups), diagnostics(diagnostics), defaultIgnoreWarnings(defaultIgnoreWarnings), - toolchainLocalDocumentation(toolchainLocalDocumentation) {} + toolchainLocalDocumentation(toolchainLocalDocumentation), + frontendOnly(frontendOnly) {} constexpr DiagGroupInfo(DiagGroupID groupID, std::string_view name, OptionSet options, @@ -83,10 +88,24 @@ struct DiagGroupInfo { : DiagGroupInfo(groupID, name, documentationFile, supergroups, subgroups, diagnostics, options.contains(DiagnosticGroupOptions::DefaultIgnoreWarnings), - options.contains(DiagnosticGroupOptions::ToolchainLocalDocumentation)) {} + options.contains(DiagnosticGroupOptions::ToolchainLocalDocumentation), + options.contains(DiagnosticGroupOptions::FrontendOnly)) {} void traverseDepthFirst( llvm::function_ref func) const; + + /// Returns the documentation URL for a diagnostic group, using the local + /// toolchain path for toolchain-local groups or the remote URL otherwise. + std::string getDocumentationURL(llvm::StringRef docsPath, + llvm::StringRef localDocsPath) const; + + /// Returns true if this group contains GROUPED_REMARK diagnostics. Does NOT + /// consider subgroups (see hasTransitiveRemarks). + bool hasDirectRemarks() const; + + /// Returns true if this group or any of its subgroups contain GROUPED_REMARK + /// diagnostics. + bool hasTransitiveRemarks() const; }; // Add OptionSet aliases so that the '|' operator in the `DiagnosticGroups.def` @@ -94,9 +113,11 @@ struct DiagGroupInfo { static constexpr OptionSet none = DiagnosticGroupOptions::none; static constexpr OptionSet DefaultIgnoreWarnings = DiagnosticGroupOptions::DefaultIgnoreWarnings; static constexpr OptionSet ToolchainLocalDocumentation = DiagnosticGroupOptions::ToolchainLocalDocumentation; +static constexpr OptionSet FrontendOnly = DiagnosticGroupOptions::FrontendOnly; extern const std::array diagnosticGroupsInfo; const DiagGroupInfo &getDiagGroupInfoByID(DiagGroupID id); std::optional getDiagGroupIDByName(std::string_view name); +std::optional getCustomRemarkOptionForGroup(DiagGroupID id); } // end namespace swift diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index 2e3bb30e61091..5f76b72485ffd 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -222,33 +222,30 @@ NOTE(scanner_cycle_source_target_shadow_module, none, ERROR(error_scanner_extra, none, "failed inside dependency scanner: '%0'", (StringRef)) -REMARK(warn_scanner_deserialize_failed, none, +GROUPED_REMARK(warn_scanner_deserialize_failed, DependencyScanCache, none, "Incremental module scan: Failed to load module scanning dependency cache from: '%0', re-building scanner cache from scratch.", (StringRef)) -REMARK(remark_reuse_cache, none, +GROUPED_REMARK(remark_reuse_cache, DependencyScanCache, none, "Incremental module scan: Re-using serialized module scanning dependency cache from: '%0'.", (StringRef)) -REMARK(remark_scanner_uncached_lookups, none, - "Module Dependency Scanner queries executed: '%0'.", (unsigned)) - -REMARK(remark_save_cache, none, +GROUPED_REMARK(remark_save_cache, DependencyScanCache, none, "Incremental module scan: Serializing module scanning dependency cache to: '%0'.", (StringRef)) -REMARK(remark_scanner_stale_result_invalidate, none, +GROUPED_REMARK(remark_scanner_stale_result_invalidate, DependencyScanCache, none, "Incremental module scan: Dependency info for module '%0' invalidated due to a modified input" " since last scan: '%1'.", (StringRef, StringRef)) -REMARK(remark_scanner_invalidate_upstream, none, +GROUPED_REMARK(remark_scanner_invalidate_upstream, DependencyScanCache, none, "Incremental module scan: Dependency info for module '%0' invalidated due to an out-of-date" " dependency.", (StringRef)) -REMARK(remark_scanner_invalidate_configuration, none, +GROUPED_REMARK(remark_scanner_invalidate_configuration, DependencyScanCache, none, "Incremental module scan: Dependency info for module '%0' invalidated due to wrong configuration.", (StringRef)) -REMARK(remark_scanner_invalidate_cas_error, none, +GROUPED_REMARK(remark_scanner_invalidate_cas_error, DependencyScanCache, none, "Incremental module scan: Dependency info for module '%0' invalidated due to cas error: %1", (StringRef, StringRef)) -REMARK(remark_scanner_invalidate_missing_cas, none, +GROUPED_REMARK(remark_scanner_invalidate_missing_cas, DependencyScanCache, none, "Incremental module scan: Dependency info for module '%0' invalidated due to missing CAS input '%1'.", (StringRef, StringRef)) //------------------------------------------------------------------------------ diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 2c60cf563cd13..3243541b2d52d 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -307,7 +307,7 @@ ERROR(error_index_failed_status_check,none, "failed file status check: %0", (StringRef)) ERROR(error_index_inputs_more_than_outputs,none, "index output filenames do not match input source files", ()) -REMARK(remark_indexing_system_module,none, +GROUPED_REMARK(remark_indexing_system_module,IndexingSystemModule,none, "indexing system module at %0" "%select{|; skipping because of a broken swiftinterface}1", (StringRef, bool)) @@ -434,7 +434,7 @@ WARNING(warning_module_shadowing_may_break_module_interface,none, "https://github.com/apple/swift/issues/56573 for workarounds", (DescriptiveDeclKind, FullyQualified, /*shadowedModule=*/ModuleDecl *, /*interfaceModule*/ModuleDecl *)) -REMARK(rebuilding_module_from_interface,none, +GROUPED_REMARK(rebuilding_module_from_interface,ModuleInterfaceRebuild,none, "rebuilding module '%0' from interface '%1'", (StringRef, StringRef)) NOTE(sdk_version_pbm_version,none, "SDK build version is '%0'; prebuilt modules were " @@ -478,10 +478,10 @@ ERROR(error_creating_remark_serializer,none, ERROR(invalid_can_import_module_version,none, "invalid version passed to -module-can-import-version: '%0'", (StringRef)) -REMARK(interface_file_lock_failure,none, +GROUPED_REMARK(interface_file_lock_failure,ModuleInterfaceRebuild,none, "building module interface without lock file", ()) -REMARK(interface_file_lock_timed_out,none, +GROUPED_REMARK(interface_file_lock_timed_out,ModuleInterfaceRebuild,none, "timed out waiting to acquire lock file for module interface '%0'", (StringRef)) ERROR(error_option_required,none, "option '%0' is required", (StringRef)) @@ -510,8 +510,8 @@ GROUPED_ERROR(error_caching_no_cas_fs, CompilationCaching, none, GROUPED_ERROR(error_option_incompatible, CompilationCaching, none, "'%0' is incompatible with '%1'", (StringRef, StringRef)) -REMARK(replay_output, none, "replay output file '%0': key '%1'", (StringRef, StringRef)) -REMARK(output_cache_miss, none, "cache miss for input file '%0': key '%1'", (StringRef, StringRef)) +GROUPED_REMARK(replay_output, CompilationCaching, none, "replay output file '%0': key '%1'", (StringRef, StringRef)) +GROUPED_REMARK(output_cache_miss, CompilationCaching, none, "cache miss for input file '%0': key '%1'", (StringRef, StringRef)) // CAS related diagnostics GROUPED_ERROR(error_invalid_cas_id, CompilationCaching, none, "CAS cannot parse id '%0': %1", (StringRef, StringRef)) @@ -638,5 +638,13 @@ NOTE(dependency_scan_unexpected_variant_extra_arg_note, none, ERROR(bridging_header_and_pch_internal_mismatch,none, "bridging header and precompiled header options mismatch on internal vs. public import", ()) +ERROR(error_remark_group_not_found,none, + "no diagnostic group found with name '%0'", (StringRef)) +ERROR(error_remarkless_group,none, + "diagnostic group '%0' contains no remark diagnostics", (StringRef)) +ERROR(error_remark_option_redirect,none, + "diagnostic group '%0' cannot be enabled with '-R %0' since it requires " + "an additional argument; use '%1' instead", (StringRef, StringRef)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index c15ffbe85382f..6c37b3c0d7178 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -880,13 +880,13 @@ ERROR(sema_opening_import,Fatal, NOTE(sema_module_aliased,none, "module name '%0' is aliased to '%1'", (StringRef, StringRef)) -REMARK(serialization_skipped_invalid_decl,none, +GROUPED_REMARK(serialization_skipped_invalid_decl,ModuleSerialization,none, "serialization skipped invalid %kind0", (const Decl *)) -REMARK(serialization_skipped_invalid_type,none, +GROUPED_REMARK(serialization_skipped_invalid_type,ModuleSerialization,none, "serialization skipped for invalid type %0", (TypeRepr *)) -REMARK(serialization_skipped_invalid_type_unknown_name,none, +GROUPED_REMARK(serialization_skipped_invalid_type_unknown_name,ModuleSerialization,none, "serialization skipped for invalid type", ()) ERROR(serialization_failed,none, @@ -1019,16 +1019,16 @@ ERROR(cxx_stdlib_kind_mismatch,none, "module %0 was built with %1, but current compilation uses %2", (Identifier, StringRef, StringRef)) -ERROR(modularization_issue_decl_moved,Fatal, +GROUPED_ERROR(modularization_issue_decl_moved,ModularizationIssue,Fatal, "reference to %select{declaration|type}0 '%1' broken by a context change; " "'%1' was expected to be in %2, but now a candidate is found only in %3", (bool, StringRef, const ModuleDecl*, const ModuleDecl*)) -ERROR(modularization_issue_decl_type_changed,Fatal, +GROUPED_ERROR(modularization_issue_decl_type_changed,ModularizationIssue,Fatal, "reference to %select{declaration|type}0 '%1' broken by a context change; " "the declaration kind of '%1' %select{from %2|}5 changed since building '%3'" "%select{|, it was in %2 and now a candidate is found only in %4}5", (bool, StringRef, const ModuleDecl*, StringRef, const ModuleDecl*, bool)) -ERROR(modularization_issue_decl_not_found,Fatal, +GROUPED_ERROR(modularization_issue_decl_not_found,ModularizationIssue,Fatal, "reference to %select{declaration|type}0 '%1' broken by a context change; " "'%1' is not found, it was expected to be in %2", (bool, StringRef, const ModuleDecl*)) @@ -1087,13 +1087,13 @@ NOTE(modularization_issue_worked_around,none, "attempting to recover from the previous modularization issue", ()) -ERROR(modularization_issue_conformance_xref_error,none, +GROUPED_ERROR(modularization_issue_conformance_xref_error,ModularizationIssue,none, "Conformance of %0 to %1 not found in referenced module %2", (DeclName, DeclName, DeclName)) NOTE(modularization_issue_conformance_xref_note,none, "Breaks conformances of '%0' to %1", (StringRef, DeclName)) -ERROR(modularization_issue_conformance_error,none, +GROUPED_ERROR(modularization_issue_conformance_error,ModularizationIssue,none, "Listed conformances of '%0' " "do not match current requirement signature of %1; " "%2 conformances for %3 requirements", @@ -1287,31 +1287,31 @@ ERROR(module_allowable_client_violation,none, "module %0 doesn't allow importation from module %1", (Identifier, Identifier)) -REMARK(cross_import_added,none, +GROUPED_REMARK(cross_import_added,CrossImport,none, "import of %0 and %1 triggered a cross-import of %2", (Identifier, Identifier, Identifier)) -REMARK(module_loaded,none, +GROUPED_REMARK(module_loaded,ModuleLoading,none, "loaded module %0" "%select{| (overlay for a clang dependency)}1" "; source: '%2', loaded: '%3'", (Identifier, unsigned, StringRef, StringRef)) -REMARK(module_api_import,none, +GROUPED_REMARK(module_api_import,ModuleAPIImport,none, "%select{|implicitly used }4" "%kind0 is imported via %1" "%select{, which reexports definition from %2|}3", (const Decl *, ModuleDecl *, ModuleDecl *, bool, bool)) -REMARK(module_api_import_conformance,none, +GROUPED_REMARK(module_api_import_conformance,ModuleAPIImport,none, "conformance of %0 to %kind1 used here is imported via %2" "%select{ which reexports the definition from %3|}4", (const Type, const Decl *, ModuleDecl *, ModuleDecl *, bool)) -REMARK(module_api_import_aliases,none, +GROUPED_REMARK(module_api_import_aliases,ModuleAPIImport,none, "typealias underlying type %kind0 is imported via %1" "%select{, which reexports definition from %2|}3", (const Decl *, ModuleDecl *, ModuleDecl *, bool)) -REMARK(macro_loaded,none, +GROUPED_REMARK(macro_loaded,MacroLoading,none, "loaded macro implementation module %0 from " "%select{shared library '%2'|executable '%2'|" "compiler plugin server '%2' with shared library '%3'}1", @@ -1321,7 +1321,7 @@ ERROR(resolved_macro_changed,none, "resolved macro library '%0' failed verification: %1", (StringRef, StringRef)) -REMARK(transitive_dependency_behavior,none, +GROUPED_REMARK(transitive_dependency_behavior,ModuleLoading,none, "%1 has %select{a required|an optional|an ignored}2 " "transitive dependency on '%0'", (StringRef, Identifier, unsigned)) @@ -2449,19 +2449,19 @@ WARNING(dependency_scan_module_incompatible, none, "module file '%0' is incompatible with this Swift compiler: %1", (StringRef, StringRef)) -REMARK(dependency_scan_number_swift_queries, none, +GROUPED_REMARK(dependency_scan_number_swift_queries, DependencyScan, none, "Number of Swift module queries: '%0'", (uint32_t)) -REMARK(dependency_scan_number_named_clang_queries, none, +GROUPED_REMARK(dependency_scan_number_named_clang_queries, DependencyScan, none, "Number of named Clang module queries: '%0'", (uint32_t)) -REMARK(dependency_scan_number_swift_dependencies, none, +GROUPED_REMARK(dependency_scan_number_swift_dependencies, DependencyScan, none, "Number of recorded Swift module dependencies: '%0'", (uint32_t)) -REMARK(dependency_scan_number_named_clang_dependencies, none, +GROUPED_REMARK(dependency_scan_number_named_clang_dependencies, DependencyScan, none, "Number of recorded Clang module dependencies queried by-name from a Swift client: '%0'", (uint32_t)) -REMARK(dependency_scan_number_clang_dependencies, none, +GROUPED_REMARK(dependency_scan_number_clang_dependencies, DependencyScan, none, "Number of recorded Clang module dependencies: '%0'", (uint32_t)) @@ -8090,21 +8090,21 @@ WARNING(access_notes_file_io_error,none, "ignored access notes file at '%0' because it cannot be read: %1", (StringRef, StringRef)) -REMARK(attr_added_by_access_note, none, +GROUPED_REMARK(attr_added_by_access_note, AccessNote, none, "implicitly added '%1' to this %kindonly2, as " WHICH_ACCESS_NOTE(0), (StringRef, StringRef, const ValueDecl *)) NOTE(fixit_attr_added_by_access_note, none, "add '%0' explicitly to silence this warning", (StringRef)) -REMARK(attr_removed_by_access_note, none, +GROUPED_REMARK(attr_removed_by_access_note, AccessNote, none, "implicitly removed '%1' from this %kindonly2, as " WHICH_ACCESS_NOTE(0), (StringRef, StringRef, const ValueDecl *)) NOTE(fixit_attr_removed_by_access_note, none, "remove '%0' explicitly to silence this warning", (StringRef)) -REMARK(attr_objc_name_changed_by_access_note, none, +GROUPED_REMARK(attr_objc_name_changed_by_access_note, AccessNote, none, "implicitly changed Objective-C name of this %kindonly1 to %2, as " WHICH_ACCESS_NOTE(0), (StringRef, const ValueDecl *, ObjCSelector)) @@ -8115,11 +8115,11 @@ NOTE(fixit_attr_objc_name_changed_by_access_note, none, // Bad access note diagnostics. These are usually emitted as remarks, but // '-Raccess-note=all-validate' emits them as errors. -ERROR(attr_objc_name_conflicts_with_access_note, none, +GROUPED_ERROR(attr_objc_name_conflicts_with_access_note, AccessNote, none, "ignored access note: did not change Objective-C name of this " "%kindonly1 from %2 to %3, even though it was " WHICH_ACCESS_NOTE(0), (StringRef, const ValueDecl *, ObjCSelector, ObjCSelector)) -ERROR(wrap_invalid_attr_added_by_access_note, none, +GROUPED_ERROR(wrap_invalid_attr_added_by_access_note, AccessNote, none, "ignored access note: %0; did not implicitly add '%2' to this " "%kindonly3, even though it was " WHICH_ACCESS_NOTE(1), (DiagnosticInfo *, StringRef, StringRef, const ValueDecl *)) @@ -9245,7 +9245,7 @@ NOTE(perf_hint_add_thrown_error_type,none, ERROR(unsafe_self_dependent_result_attr_on_invalid_decl,none, "invalid use of @_unsafeSelfDependentResult", ()) -REMARK(macro_expansion_line, none, "macro content: |%0|", (StringRef)) +GROUPED_REMARK(macro_expansion_line, MacroExpansions, none, "macro content: |%0|", (StringRef)) GROUPED_WARNING(oslog_missing_string_section,OSLog,none, "global variable 'osLogStringSectionName' is missing from the OSLog module; defaulting to '__TEXT,__oslogstring,cstring_literals'", ()) diff --git a/include/swift/Basic/DiagnosticOptions.h b/include/swift/Basic/DiagnosticOptions.h index d027c1d0d7d41..ada77fa5a97c1 100644 --- a/include/swift/Basic/DiagnosticOptions.h +++ b/include/swift/Basic/DiagnosticOptions.h @@ -16,10 +16,13 @@ #include "swift/Basic/PrintDiagnosticNamesMode.h" #include "swift/Basic/WarningGroupBehaviorRule.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SmallVector.h" #include namespace swift { +enum class DiagGroupID : uint32_t; + /// Options for controlling diagnostics. class DiagnosticOptions { public: @@ -85,6 +88,9 @@ class DiagnosticOptions { /// These will be diagnosed when the DiagnosticEngine is configured. llvm::SmallVector UnknownWarningGroups; + /// Remark groups enabled via -R . + llvm::SmallVector EnabledRemarkGroups; + /// When printing diagnostics, include either the diagnostic name /// (diag::whatever) at the end or the associated diagnostic group. PrintDiagnosticNamesMode PrintDiagnosticNames = diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 8c9fe7f729682..01801d4c14ba2 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -337,6 +337,13 @@ class FrontendOptions { /// exit. bool PrintSupportedFeatures = false; + /// Indicates that the frontend should list all diagnostic groups with remark + /// diagnostics and then exit. + bool PrintRemarkHelp = false; + + /// Like PrintRemarkHelp but excludes FrontendOnly groups. + bool PrintRemarkHelpForDriver = false; + /// See the \ref SILOptions.EmitVerboseSIL flag. bool EmitVerboseSIL = false; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 29d1daa4e12b1..6f0840e538e71 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -191,7 +191,8 @@ def verify_generic_signatures : Separate<["-"], "verify-generic-signatures">, HelpText<"Verify the generic signatures in the given module">; def expansion_remarks: Flag<["-"], "Rmacro-expansions">, - HelpText<"Show remarks for each line in macro expansions">; + HelpText<"Show remarks for each line in macro expansions">, + Alias, AliasArgs<["MacroExpansions"]>; def show_diagnostics_after_fatal : Flag<["-"], "show-diagnostics-after-fatal">, HelpText<"Keep emitting subsequent diagnostics after a fatal error">; @@ -294,10 +295,12 @@ def dependency_scan_cache_path : Separate<["-"], "dependency-scan-cache-path">, HelpText<"The path to output the dependency scanner's internal state.">; def dependency_scan_cache_remarks : Flag<["-"], "Rdependency-scan-cache">, - HelpText<"Emit remarks indicating use of the serialized module dependency scanning cache.">; + HelpText<"Emit remarks indicating use of the serialized module dependency scanning cache.">, + Alias, AliasArgs<["DependencyScanCache"]>; def dependency_scan_remarks : Flag<["-"], "Rdependency-scan">, - HelpText<"Emit remarks for various steps taken by the dependency scanner.">; + HelpText<"Emit remarks for various steps taken by the dependency scanner.">, + Alias, AliasArgs<["DependencyScan"]>; def parallel_scan : Flag<["-"], "parallel-scan">, HelpText<"Perform dependency scanning in-parallel.">; @@ -912,7 +915,17 @@ def warn_long_expression_type_checking_EQ : Joined<["-"], "warn-long-expression- Alias; def Rmodule_interface_rebuild : Flag<["-"], "Rmodule-interface-rebuild">, - HelpText<"Emits a remark if an imported module needs to be re-compiled from its module interface">; + HelpText<"Emits a remark if an imported module needs to be re-compiled from its module interface">, + Alias, AliasArgs<["ModuleInterfaceRebuild"]>; + +def Rhelp_swiftc : Flag<["-"], "Rhelp-swiftc">, + Flags<[HelpHidden]>, + HelpText<"List diagnostic groups that support remark output, excluding frontend-only groups">; + +def enable_remark_swiftc : Separate<["-"], "Rswiftc">, + Flags<[HelpHidden, CacheInvariant]>, + HelpText<"Enable remarks in diagnostic group , excluding frontend-only groups">, + MetaVarName<"">; def downgrade_typecheck_interface_error : Flag<["-"], "downgrade-typecheck-interface-error">, HelpText<"Downgrade error to warning when typechecking emitted module interfaces">; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index d2e51289e1138..d98dba3e995e1 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -464,27 +464,43 @@ def emit_loaded_module_trace_path_EQ : Joined<["-"], "emit-loaded-module-trace-p Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath, SupplementaryOutput, CacheInvariant]>, Alias; + +def Rhelp : Flag<["-"], "Rhelp">, + Flags<[FrontendOption]>, + HelpText<"List diagnostic groups that support remark output">; + +def enable_remark : Separate<["-"], "R">, + Flags<[FrontendOption, CacheInvariant]>, + HelpText<"Enable remarks in diagnostic group . List groups with -Rhelp.">, + MetaVarName<"">; + def emit_cross_import_remarks : Flag<["-"], "Rcross-import">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, - HelpText<"Emit a remark if a cross-import of a module is triggered.">; + HelpText<"Emit a remark if a cross-import of a module is triggered.">, + Alias, AliasArgs<["CrossImport"]>; def remark_loading_module : Flag<["-"], "Rmodule-loading">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, - HelpText<"Emit remarks about loaded module">; + HelpText<"Emit remarks about loaded module">, + Alias, AliasArgs<["ModuleLoading"]>; def remark_module_recovery : Flag<["-"], "Rmodule-recovery">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, - HelpText<"Emit remarks about contextual inconsistencies in loaded modules">; + HelpText<"Emit remarks about contextual inconsistencies in loaded modules">, + Alias, AliasArgs<["ModularizationIssue"]>; def remark_module_api_import : Flag<["-"], "Rmodule-api-import">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, - HelpText<"Emit remarks about the import bridging in each element composing the API">; + HelpText<"Emit remarks about the import bridging in each element composing the API">, + Alias, AliasArgs<["ModuleAPIImport"]>; def remark_macro_loading : Flag<["-"], "Rmacro-loading">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, - HelpText<"Emit remarks about loaded macro implementations">; + HelpText<"Emit remarks about loaded macro implementations">, + Alias, AliasArgs<["MacroLoading"]>; def remark_indexing_system_module : Flag<["-"], "Rindexing-system-module">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, - HelpText<"Emit a remark when indexing a system module">; + HelpText<"Emit a remark when indexing a system module">, + Alias, AliasArgs<["IndexingSystemModule"]>; def remark_skip_explicit_interface_build : Flag<["-"], "Rskip-explicit-interface-build">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, @@ -492,7 +508,8 @@ def remark_skip_explicit_interface_build : Flag<["-"], "Rskip-explicit-interface def remark_module_serialization : Flag<["-"], "Rmodule-serialization">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, - HelpText<"Emit remarks about module serialization">; + HelpText<"Emit remarks about module serialization">, + Alias, AliasArgs<["ModuleSerialization"]>; def emit_tbd : Flag<["-"], "emit-tbd">, HelpText<"Emit a TBD file">, @@ -2342,7 +2359,8 @@ def no_cache_compile_job: Flag<["-"], "no-cache-compile-job">, def cache_remarks: Flag<["-"], "Rcache-compile-job">, Flags<[FrontendOption, NewDriverOnlyOption, CacheInvariant]>, - HelpText<"Show remarks for compiler caching">; + HelpText<"Show remarks for compiler caching">, + Alias, AliasArgs<["CompilationCaching"]>; def cache_disable_replay: Flag<["-"], "cache-disable-replay">, Flags<[FrontendOption, NewDriverOnlyOption, CacheInvariant]>, diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 614af67504f6f..eca34a607f7d6 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -36,6 +36,7 @@ #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/Assertions.h" +#include "swift/Basic/DiagnosticOptions.h" #include "swift/Basic/SourceManager.h" #include "swift/Bridging/ASTGen.h" #include "swift/Config.h" @@ -57,7 +58,7 @@ static_assert(IsTriviallyDestructible::value, "ZeroArgDiagnostic is meant to be trivially destructable"); namespace { -enum class DiagnosticOptions { +enum class DiagnosticProperties { /// No options. none, @@ -98,14 +99,14 @@ struct StoredDiagnosticInfo { isAPIDigesterBreakage(isAPIDigesterBreakage), isDeprecation(deprecation), isNoUsage(noUsage), groupID(groupID) {} - constexpr StoredDiagnosticInfo(DiagnosticKind k, DiagnosticOptions opts, + constexpr StoredDiagnosticInfo(DiagnosticKind k, DiagnosticProperties opts, DiagGroupID groupID) : StoredDiagnosticInfo(k, - opts == DiagnosticOptions::PointsToFirstBadToken, - opts == DiagnosticOptions::Fatal, - opts == DiagnosticOptions::APIDigesterBreakage, - opts == DiagnosticOptions::Deprecation, - opts == DiagnosticOptions::NoUsage, + opts == DiagnosticProperties::PointsToFirstBadToken, + opts == DiagnosticProperties::Fatal, + opts == DiagnosticProperties::APIDigesterBreakage, + opts == DiagnosticProperties::Deprecation, + opts == DiagnosticProperties::NoUsage, groupID) {} }; } // end anonymous namespace @@ -113,17 +114,17 @@ struct StoredDiagnosticInfo { // TODO: categorization static const constexpr StoredDiagnosticInfo storedDiagnosticInfos[] = { #define GROUPED_ERROR(ID, Group, Options, Text, Signature) \ - StoredDiagnosticInfo(DiagnosticKind::Error, DiagnosticOptions::Options, \ + StoredDiagnosticInfo(DiagnosticKind::Error, DiagnosticProperties::Options, \ DiagGroupID::Group), #define GROUPED_WARNING(ID, Group, Options, Text, Signature) \ - StoredDiagnosticInfo(DiagnosticKind::Warning, DiagnosticOptions::Options, \ + StoredDiagnosticInfo(DiagnosticKind::Warning, DiagnosticProperties::Options, \ DiagGroupID::Group), #define NOTE(ID, Options, Text, Signature) \ - StoredDiagnosticInfo(DiagnosticKind::Note, DiagnosticOptions::Options, \ - DiagGroupID::no_group), -#define REMARK(ID, Options, Text, Signature) \ - StoredDiagnosticInfo(DiagnosticKind::Remark, DiagnosticOptions::Options, \ + StoredDiagnosticInfo(DiagnosticKind::Note, DiagnosticProperties::Options, \ DiagGroupID::no_group), +#define GROUPED_REMARK(ID, Group, Options, Text, Signature) \ + StoredDiagnosticInfo(DiagnosticKind::Remark, DiagnosticProperties::Options, \ + DiagGroupID::Group), #include "swift/AST/DiagnosticsAll.def" }; static_assert(sizeof(storedDiagnosticInfos) / sizeof(StoredDiagnosticInfo) == @@ -1451,6 +1452,15 @@ DiagnosticState::determineBehavior(const Diagnostic &diag, if (suppressRemarks) lvl = DiagnosticBehavior::Ignore; } + + if (lvl == DiagnosticBehavior::Remark) { + auto groupID = diag.getGroupID(); + if (groupID != DiagGroupID::no_group && + !getCustomRemarkOptionForGroup(groupID) && + !isRemarkGroupEnabled(groupID)) + lvl = DiagnosticBehavior::Ignore; + } + return lvl; } @@ -1533,6 +1543,8 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic, if (behavior == DiagnosticBehavior::Ignore) return std::nullopt; + auto groupID = diagnostic.getGroupID(); + // Figure out the source location. SourceLoc loc = diagnostic.getLocOrDeclLoc(); if (loc.isInvalid() && diagnostic.getDecl()) { @@ -1548,7 +1560,6 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic, loc = evaluateOrDefault(eval, req, SourceLoc()); } - auto groupID = diagnostic.getGroupID(); StringRef CategoryName; if (auto wrapped = diagnostic.getWrappedDiagnostic()) CategoryName = wrapped.value()->getCategoryName(); @@ -1741,29 +1752,11 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { if (groupID != DiagGroupID::no_group) { const auto &diagGroup = getDiagGroupInfoByID(groupID); - auto getDiagnosticGroupDocURL = - [&](const DiagGroupInfo &diagGroup) -> std::string { - if (diagGroup.toolchainLocalDocumentation) { - std::string localPath(getLocalDiagnosticDocumentationPath()); - if (!localPath.empty()) { - if (localPath.back() != '/') - localPath += "/"; - localPath += diagGroup.documentationFile; - localPath += ".md"; - return localPath; - } - return ""; - } - - std::string docURL(getDiagnosticDocumentationPath()); - if (!docURL.empty() && docURL.back() != '/') - docURL += "/"; - docURL += diagGroup.documentationFile; - return docURL; - }; - // Set the leaf category's documentation URL. - info->setCategoryDocumentationURL(getDiagnosticGroupDocURL(diagGroup)); + std::string docURL = + diagGroup.getDocumentationURL(getDiagnosticDocumentationPath(), + getLocalDiagnosticDocumentationPath()); + info->setCategoryDocumentationURL(docURL); // Append parent groups by walking up supergroups. auto currentID = groupID; @@ -1773,10 +1766,9 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { break; auto parentID = current.supergroups[0]; const auto &parent = getDiagGroupInfoByID(parentID); - std::string parentDocURL(getDiagnosticDocumentationPath()); - if (!parentDocURL.empty() && parentDocURL.back() != '/') - parentDocURL += "/"; - parentDocURL += parent.documentationFile; + std::string parentDocURL = + parent.getDocumentationURL(getDiagnosticDocumentationPath(), + getLocalDiagnosticDocumentationPath()); info->CategoryChain.push_back( {StringRef(parent.name), std::move(parentDocURL)}); currentID = parentID; @@ -1799,6 +1791,24 @@ DiagnosticKind DiagnosticEngine::declaredDiagnosticKindFor(const DiagID id) { return storedDiagnosticInfos[(unsigned)id].kind; } +std::string +DiagnosticEngine::resolveDiagnosticDocumentationPath(const DiagnosticOptions &opts) { + if (opts.DiagnosticDocumentationPath.empty()) + return "https://docs.swift.org/compiler/documentation/diagnostics"; + return opts.DiagnosticDocumentationPath; +} + +std::string +DiagnosticEngine::resolveLocalDiagnosticDocumentationPath( + llvm::StringRef mainExecutablePath) { + llvm::SmallString<128> localDocsPath(mainExecutablePath); + llvm::sys::path::remove_filename(localDocsPath); // Remove /swift-frontend + llvm::sys::path::remove_filename(localDocsPath); // Remove /bin + llvm::sys::path::append(localDocsPath, "share", "doc", "swift", + "diagnostics"); + return std::string(localDocsPath); +} + llvm::StringRef DiagnosticEngine::getFormatStringForDiagnostic(DiagID id) { llvm::StringRef message = diagnosticStrings[(unsigned)id]; if (auto localizationProducer = localization.get()) { diff --git a/lib/AST/DiagnosticGroups.cpp b/lib/AST/DiagnosticGroups.cpp index 98dd7bc5d8098..5e35274c20a16 100644 --- a/lib/AST/DiagnosticGroups.cpp +++ b/lib/AST/DiagnosticGroups.cpp @@ -16,7 +16,13 @@ //===----------------------------------------------------------------------===// #include "swift/AST/DiagnosticGroups.h" +#include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticList.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Path.h" +#include +#include #include namespace swift { @@ -234,4 +240,61 @@ CHECK_NOT_EMPTY(UnknownWarningGroup) } // end namespace validation +std::string +DiagGroupInfo::getDocumentationURL(llvm::StringRef docsPath, llvm::StringRef localDocsPath) const { + if (toolchainLocalDocumentation) { + if (!localDocsPath.empty()) { + llvm::SmallString<128> localPath(localDocsPath); + llvm::sys::path::append(localPath, documentationFile); + localPath += ".md"; + return std::string(localPath); + } + return ""; + } + + std::string docURL(docsPath); + if (!docURL.empty() && docURL.back() != '/') + docURL += "/"; + docURL += documentationFile; + return docURL; +} + +static bool hasDynamicRemarks(DiagGroupID id) { + // ModularizationIssue has no GROUPED_REMARK diagnostics — its errors have + // their diagnostic level overriden to Remark at the call site when + // EnableModuleRecoveryRemarks is set, so we won't find any remarks + // statically. + return DiagGroupID::ModularizationIssue == id; +} + +bool DiagGroupInfo::hasDirectRemarks() const { + if (hasDynamicRemarks(id)) + return true; + for (DiagID diag : diagnostics) { + if (DiagnosticEngine::declaredDiagnosticKindFor(diag) == + DiagnosticKind::Remark) + return true; + } + return false; +} + +bool DiagGroupInfo::hasTransitiveRemarks() const { + if (hasDirectRemarks()) + return true; + for (auto subGroupID : subgroups) { + if (getDiagGroupInfoByID(subGroupID).hasTransitiveRemarks()) + return true; + } + return false; +} + +std::optional getCustomRemarkOptionForGroup(DiagGroupID id) { + // Not worth adding this to DiagnosticGroups.def for 1 group, but if more + // groups need a custom option in the future we should probably add a + // CUSTOM_REMARK_OPTION macro there. + if (id == DiagGroupID::AccessNote) + return "-Raccess-note="; + return std::nullopt; +} + } // end namespace swift diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index c9da70345432b..cdb8756f8fbcb 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -448,6 +448,18 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, // Pass through any subsystem flags. inputArgs.AddAllArgs(arguments, options::OPT_Xllvm); inputArgs.AddAllArgs(arguments, options::OPT_Xcc); + + // remap -Rhelp to -Rhelp-swiftc to avoid listing frontend-only groups when + // invoked from the driver + if (inputArgs.hasArg(options::OPT_Rhelp)) + arguments.push_back("-Rhelp-swiftc"); + + // remap -R to -Rswiftc to avoid matching frontend-only groups when + // invoked from the driver + for (const auto *A : inputArgs.filtered(options::OPT_enable_remark)) { + arguments.push_back("-Rswiftc"); + arguments.push_back(A->getValue()); + } } void ToolChain::addPlatformSpecificPluginFrontendArgs( diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 826d8182ba048..edf95ccab7fed 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -158,10 +158,6 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.SerializeDependencyScannerCache |= Args.hasArg(OPT_serialize_dependency_scan_cache); Opts.ReuseDependencyScannerCache |= Args.hasArg(OPT_reuse_dependency_scan_cache); Opts.ValidatePriorDependencyScannerCache |= Args.hasArg(OPT_validate_prior_dependency_scan_cache); - Opts.EmitDependencyScannerRemarks |= Args.hasArg(OPT_dependency_scan_remarks); - Opts.EmitDependencyScannerCacheRemarks |= - Args.hasArg(OPT_dependency_scan_cache_remarks) || - Opts.EmitDependencyScannerRemarks; Opts.ParallelDependencyScan = Args.hasFlag(OPT_parallel_scan, OPT_no_parallel_scan, true); @@ -189,9 +185,6 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.SerializeModuleInterfaceDependencyHashes |= Args.hasArg(OPT_serialize_module_interface_dependency_hashes); - Opts.RemarkOnRebuildFromModuleInterface |= - Args.hasArg(OPT_Rmodule_interface_rebuild); - Opts.DowngradeInterfaceVerificationError |= Args.hasArg(OPT_downgrade_typecheck_interface_error); computePrintStatsOptions(); @@ -223,6 +216,14 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.PrintSupportedFeatures = true; } + if (Args.hasArg(OPT_Rhelp)) { + Opts.PrintRemarkHelp = true; + } + + if (Args.hasArg(OPT_Rhelp_swiftc)) { + Opts.PrintRemarkHelpForDriver = true; + } + if (const Arg *A = Args.getLastArg(OPT_verify_generic_signatures)) { Opts.VerifyGenericSignaturesInModule = A->getValue(); } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index fa810d2b93977..e87aae20547cd 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -11,6 +11,8 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Driver.h" +#include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticGroups.h" #include "swift/AST/SILOptions.h" #include "swift/Basic/DiagnosticOptions.h" #include "swift/Frontend/Frontend.h" @@ -22,6 +24,7 @@ #include "swift/Basic/LanguageMode.h" #include "swift/Basic/Platform.h" #include "swift/Basic/Version.h" +#include "swift/Frontend/FrontendOptions.h" #include "swift/Option/Options.h" #include "swift/Option/SanitizerOptions.h" #include "swift/Parse/Lexer.h" @@ -30,6 +33,7 @@ #include "swift/Strings.h" #include "swift/SymbolGraphGen/SymbolGraphOptions.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" @@ -41,6 +45,7 @@ #include "llvm/Support/VersionTuple.h" #include "llvm/Support/WithColor.h" #include "llvm/TargetParser/Triple.h" +#include using namespace swift; using namespace llvm::opt; @@ -834,7 +839,6 @@ static bool ParseCASArgs(CASOptions &Opts, ArgList &Args, using namespace options; Opts.EnableCaching |= Args.hasFlag( OPT_cache_compile_job, OPT_no_cache_compile_job, /*Default=*/false); - Opts.EnableCachingRemarks |= Args.hasArg(OPT_cache_remarks); Opts.CacheSkipReplay |= Args.hasArg(OPT_cache_disable_replay); Opts.WriteOutputHashXAttr |= Args.hasArg(OPT_write_output_hash_xattr); if (const Arg *A = Args.getLastArg(OPT_cas_path)) @@ -1110,6 +1114,92 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args, return HadError; } +static bool ParseEnabledRemarks(LangOptions &Opts, ArgList &Args, + DiagnosticEngine &Diags, + DiagnosticOptions &DiagOpts, + FrontendOptions &FrontendOpts, + CASOptions &CASOpts) { + bool HadError = false; + for (const llvm::opt::Arg *RemarkOpt : Args.filtered( + options::OPT_enable_remark, options::OPT_enable_remark_swiftc)) { + StringRef GroupName = RemarkOpt->getValue(); + std::optional GroupID = getDiagGroupIDByName(GroupName); + if (!GroupID) { + Diags.diagnose({}, diag::error_remark_group_not_found, GroupName); + HadError = true; + continue; + } + const DiagGroupInfo &Group = getDiagGroupInfoByID(*GroupID); + const bool includeFrontendOnly = + RemarkOpt->getOption().getID() == options::OPT_enable_remark; + if (Group.frontendOnly && !includeFrontendOnly) { + Diags.diagnose({}, diag::error_remark_group_not_found, GroupName); + HadError = true; + continue; + } + + // Set the legacy boolean flags so that existing call-site checks continue + // to work until the diagnostic engine checks isRemarkGroupEnabled directly. + switch (*GroupID) { + case DiagGroupID::CompilationCaching: + CASOpts.EnableCachingRemarks = true; + break; + case DiagGroupID::CrossImport: + Opts.EnableCrossImportRemarks = true; + break; + case DiagGroupID::ModuleLoading: + Opts.EnableModuleLoadingRemarks = true; + break; + case DiagGroupID::ModularizationIssue: + Opts.EnableModuleRecoveryRemarks = true; + break; + case DiagGroupID::ModuleSerialization: + Opts.EnableModuleSerializationRemarks = true; + break; + case DiagGroupID::ModuleAPIImport: + Opts.EnableModuleApiImportRemarks = true; + break; + case DiagGroupID::MacroLoading: + Opts.EnableMacroLoadingRemarks = true; + break; + case DiagGroupID::IndexingSystemModule: + Opts.EnableIndexingSystemModuleRemarks = true; + break; + case DiagGroupID::MacroExpansions: + Opts.RemarkMacroExpansions = true; + break; + case DiagGroupID::ModuleInterfaceRebuild: + FrontendOpts.RemarkOnRebuildFromModuleInterface = true; + break; + case DiagGroupID::DependencyScan: + FrontendOpts.EmitDependencyScannerRemarks = true; + FrontendOpts.EmitDependencyScannerCacheRemarks = true; + break; + case DiagGroupID::DependencyScanCache: + FrontendOpts.EmitDependencyScannerCacheRemarks = true; + break; + default: + if (auto customOption = getCustomRemarkOptionForGroup(*GroupID)) { + Diags.diagnose({}, diag::error_remark_option_redirect, GroupName, + *customOption); + HadError = true; + continue; + } + break; + } + + if (!Group.hasTransitiveRemarks()) { + Diags.diagnose({}, diag::error_remarkless_group, GroupName); + HadError = true; + continue; + } + + DiagOpts.EnabledRemarkGroups.push_back(*GroupID); + } + + return HadError; +} + static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, DiagnosticEngine &Diags, ModuleInterfaceOptions &ModuleInterfaceOpts, @@ -1565,16 +1655,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, OPT_disable_cross_import_overlays, Opts.EnableCrossImportOverlays); - Opts.EnableCrossImportRemarks = Args.hasArg(OPT_emit_cross_import_remarks); - - Opts.EnableModuleLoadingRemarks = Args.hasArg(OPT_remark_loading_module); - Opts.EnableModuleRecoveryRemarks = Args.hasArg(OPT_remark_module_recovery); - Opts.EnableModuleSerializationRemarks = - Args.hasArg(OPT_remark_module_serialization); - Opts.EnableModuleApiImportRemarks = Args.hasArg(OPT_remark_module_api_import); - Opts.EnableMacroLoadingRemarks = Args.hasArg(OPT_remark_macro_loading); - Opts.EnableIndexingSystemModuleRemarks = Args.hasArg(OPT_remark_indexing_system_module); - if (Args.hasArg(OPT_experimental_skip_non_exportable_decls)) { // Only allow -experimental-skip-non-exportable-decls if either library // evolution is enabled (in which case the module's ABI is independent of @@ -1847,9 +1927,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.DumpMacroExpansions = Args.hasArg( OPT_dump_macro_expansions); - Opts.RemarkMacroExpansions = Args.hasArg( - OPT_expansion_remarks); - Opts.DumpSourceFileImports = Args.hasArg( OPT_dump_source_file_imports); @@ -2950,18 +3027,15 @@ static void configureDiagnosticEngine( Diagnostics.setWarningGroupControlRules(Options.WarningGroupControlRules); Diagnostics.setPrintDiagnosticNamesMode(Options.PrintDiagnosticNames); - std::string docsPath = Options.DiagnosticDocumentationPath; - if (docsPath.empty()) { - // Point at the latest Markdown documentation on GitHub. - docsPath = "https://docs.swift.org/compiler/documentation/diagnostics"; - } - Diagnostics.setDiagnosticDocumentationPath(docsPath); + for (auto groupID : Options.EnabledRemarkGroups) + Diagnostics.enableRemarkGroup(groupID); + + Diagnostics.setDiagnosticDocumentationPath( + DiagnosticEngine::resolveDiagnosticDocumentationPath(Options)); - llvm::SmallString<128> localDocsPath(mainExecutablePath); - llvm::sys::path::remove_filename(localDocsPath); // Remove /swift-frontend - llvm::sys::path::remove_filename(localDocsPath); // Remove /bin - llvm::sys::path::append(localDocsPath, "share", "doc", "swift", "diagnostics"); - Diagnostics.setLocalDiagnosticDocumentationPath(std::string(localDocsPath)); + Diagnostics.setLocalDiagnosticDocumentationPath( + DiagnosticEngine::resolveLocalDiagnosticDocumentationPath( + mainExecutablePath)); if (!Options.LocalizationCode.empty()) { std::string locPath = Options.LocalizationPath; @@ -4407,6 +4481,11 @@ bool CompilerInvocation::parseArgs( return true; } + if (ParseEnabledRemarks(LangOpts, ParsedArgs, Diags, DiagnosticOpts, + FrontendOpts, CASOpts)) { + return true; + } + if (ParseTypeCheckerArgs(TypeCheckerOpts, ParsedArgs, Diags, LangOpts, FrontendOpts)) { return true; } diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index ff300d352a393..3507cc6ed236a 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -645,6 +645,8 @@ bool CompilerInstance::setupForReplay(const CompilerInvocation &Invoke, // regular compilation. Invocation = Invoke; + setUpDiagnosticOptions(); + setSharedCASInstances(CAS, Cache); if (setupCASIfNeeded(Args)) { Error = "Setting up CAS failed"; diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index bdd54c7595987..36da4bc2c2993 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -16,6 +16,7 @@ #include "ModuleInterfaceBuilder.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticsFrontend.h" +#include "swift/AST/DiagnosticGroups.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/FileSystem.h" #include "swift/AST/Module.h" @@ -2001,6 +2002,8 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( LoaderOpts.remarkOnRebuildFromInterface; if (LoaderOpts.remarkOnRebuildFromInterface) { GenericArgs.push_back("-Rmodule-interface-rebuild"); + genericSubInvocation.getDiagnosticOptions().EnabledRemarkGroups.push_back( + DiagGroupID::ModuleInterfaceRebuild); } // This flag only matters when we are verifying an textual interface. frontendOpts.DowngradeInterfaceVerificationError = diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 151a4767d197b..255285bbc5e30 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -27,6 +27,8 @@ #include "swift/AST/ASTMangler.h" #include "swift/AST/AvailabilityScope.h" #include "swift/AST/DiagnosticConsumer.h" +#include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticGroups.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/FileSystem.h" @@ -80,6 +82,8 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallVectorExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" @@ -94,6 +98,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" #include "llvm/Support/JSON.h" #include "llvm/Support/Path.h" #include "llvm/Support/VirtualOutputBackend.h" @@ -2488,6 +2493,47 @@ collectSupplementaryOutputPaths(ArrayRef Args, return paths; } +static void printRemarkHelp(const CompilerInvocation &Invocation) { + bool excludeFrontendOnly = Invocation.getFrontendOptions().PrintRemarkHelpForDriver; + std::string docsPath = DiagnosticEngine::resolveDiagnosticDocumentationPath( + Invocation.getDiagnosticOptions()); + std::string localDocsPath = + DiagnosticEngine::resolveLocalDiagnosticDocumentationPath( + Invocation.getFrontendOptions().MainExecutablePath); + + const auto remarkGroups = llvm::filter_to_vector( + diagnosticGroupsInfo, [excludeFrontendOnly](const auto &group) { + if (group.documentationFile.empty()) + return false; + if (excludeFrontendOnly && group.frontendOnly) + return false; + return group.hasDirectRemarks(); + }); + + constexpr StringLiteral columnSep = " | "; + StringRef docsHeading = "Documentation"; + StringRef groupHeading = "Group with remarks"; + size_t maxLenGroup = groupHeading.size(); + size_t maxLenDocs = docsHeading.size(); + SmallVector urls; + urls.reserve(remarkGroups.size()); + for (const auto &group : remarkGroups) { + urls.push_back(group.getDocumentationURL(docsPath, localDocsPath)); + maxLenGroup = std::max(maxLenGroup, group.name.size()); + maxLenDocs = std::max(maxLenDocs, urls.back().size()); + } + + llvm::outs() << llvm::left_justify(groupHeading, maxLenGroup) << columnSep + << docsHeading << "\n"; + llvm::outs() << std::string(maxLenGroup + maxLenDocs + columnSep.size(), '-') + << "\n"; + + for (const auto &[group, url] : llvm::zip_equal(remarkGroups, urls)) { + llvm::outs() << llvm::left_justify(group.name, maxLenGroup) << columnSep + << url << "\n"; + } +} + int swift::performFrontend(ArrayRef Args, const char *Argv0, void *MainAddr, FrontendObserver *observer) { @@ -2633,6 +2679,12 @@ int swift::performFrontend(ArrayRef Args, return finishDiagProcessing(0, /*verifierEnabled*/ false); } + if (Invocation.getFrontendOptions().PrintRemarkHelp || + Invocation.getFrontendOptions().PrintRemarkHelpForDriver) { + printRemarkHelp(Invocation); + return finishDiagProcessing(0, /*verifierEnabled*/ false); + } + if (Invocation.getFrontendOptions().RequestedAction == FrontendOptions::ActionType::NoneAction) { Instance->getDiags().diagnose(SourceLoc(), diff --git a/test/SourceKit/Diagnostics/remarks.swift b/test/SourceKit/Diagnostics/remarks.swift index f4febb0dd772a..927fe6fa060b7 100644 --- a/test/SourceKit/Diagnostics/remarks.swift +++ b/test/SourceKit/Diagnostics/remarks.swift @@ -9,7 +9,10 @@ public typealias Foo = String // CHECK-NEXT: key.filepath: "{{.*}}", // CHECK-NEXT: key.severity: source.diagnostic.severity.remark, // CHECK-NEXT: key.id: "module_api_import", -// CHECK-NEXT: key.description: "struct 'String' is imported via 'Swift'" +// CHECK-NEXT: key.description: "struct 'String' is imported via 'Swift'", +// CHECK-NEXT: key.educational_note_paths: [ +// CHECK-NEXT: "{{.*}}module-api-import.md" +// CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } diff --git a/test/diagnostics/check-diagnostic-docs.test b/test/diagnostics/check-diagnostic-docs.test new file mode 100644 index 0000000000000..3fc247b82c052 --- /dev/null +++ b/test/diagnostics/check-diagnostic-docs.test @@ -0,0 +1,24 @@ +# RUN: %target-swift-ide-test -list-diagnostic-groups > %t.txt +# RUN: %{python} %s %t.txt %swift_src_root/userdocs/diagnostics + +""" +If this test fails you've forgotten to create documentation for the diagnostic +group you added. Don't forget to mark your diagnostic group as +ToolchainLocalDocumentation if the documentation is not available at +https://docs.swift.org/compiler/documentation/diagnostics/diagnostic-groups/ +""" + +import sys, os + +groups_file, docs_dir = sys.argv[1], sys.argv[2] +missing = [] +with open(groups_file) as f: + for line in f: + doc_file = line.split()[1] + target = os.path.join(docs_dir, doc_file + ".md") + if not os.path.isfile(target): + missing.append(target) +if missing: + for f in missing: + print("missing: " + f, file=sys.stderr) + sys.exit(1) diff --git a/test/diagnostics/remark-help.test b/test/diagnostics/remark-help.test new file mode 100644 index 0000000000000..f8b086875149d --- /dev/null +++ b/test/diagnostics/remark-help.test @@ -0,0 +1,24 @@ +RUN: %target-swift-frontend -Rhelp | %FileCheck %s --check-prefixes BOTH,FRONTEND-ONLY + +RUN: %target-swift-frontend -Rhelp-swiftc | %FileCheck %s --check-prefix BOTH +RUN: %target-swiftc_driver -Rhelp | %FileCheck %s --check-prefix BOTH + +RUN: %target-swiftc_driver -driver-print-jobs -Rhelp %s 2>&1 | %FileCheck %s +CHECK: BUILD_DIR/bin/swift-frontend -frontend -Rhelp-swiftc + +BOTH: Group with remarks | Documentation +BOTH-NEXT: -----------------------------------{{-+}} +BOTH-NEXT: AccessNote | BUILD_DIR/share/doc/swift/diagnostics/access-note.md +BOTH-NEXT: CompilationCaching | https://docs.swift.org/compiler/documentation/diagnostics/compilation-caching +BOTH-NEXT: CrossImport | BUILD_DIR/share/doc/swift/diagnostics/cross-import.md +FRONTEND-ONLY-NEXT: DependencyScan | BUILD_DIR/share/doc/swift/diagnostics/dependency-scan.md +FRONTEND-ONLY-NEXT: DependencyScanCache | BUILD_DIR/share/doc/swift/diagnostics/dependency-scan-cache.md +BOTH-NEXT: IndexingSystemModule | BUILD_DIR/share/doc/swift/diagnostics/indexing-system-module.md +FRONTEND-ONLY-NEXT: MacroExpansions | BUILD_DIR/share/doc/swift/diagnostics/macro-expansions.md +BOTH-NEXT: MacroLoading | BUILD_DIR/share/doc/swift/diagnostics/macro-loading.md +BOTH-NEXT: ModularizationIssue | BUILD_DIR/share/doc/swift/diagnostics/modularization-issue.md +BOTH-NEXT: ModuleAPIImport | BUILD_DIR/share/doc/swift/diagnostics/module-api-import.md +FRONTEND-ONLY-NEXT: ModuleInterfaceRebuild | BUILD_DIR/share/doc/swift/diagnostics/module-interface-rebuild.md +BOTH-NEXT: ModuleLoading | BUILD_DIR/share/doc/swift/diagnostics/module-loading.md +BOTH-NEXT: ModuleSerialization | BUILD_DIR/share/doc/swift/diagnostics/module-serialization.md + diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index e418174e69757..81a8dbfb72917 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -21,6 +21,7 @@ #include "swift/AST/DebuggerClient.h" #include "swift/AST/DiagnosticConsumer.h" #include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticGroups.h" #include "swift/AST/ImportCache.h" #include "swift/AST/NameLookupRequests.h" #include "swift/AST/PluginRegistry.h" @@ -120,6 +121,7 @@ enum class ActionType { TypeContextInfo, ConformingMethodList, SignatureHelp, + ListDiagnosticGroups, }; class NullDebuggerClient : public DebuggerClient { @@ -256,7 +258,10 @@ Action(llvm::cl::desc("Mode:"), llvm::cl::init(ActionType::None), "conforming-methods", "Perform conforming method analysis for expression"), clEnumValN(ActionType::SignatureHelp, "signature-help", - "Perform signature help"))); + "Perform signature help"), + clEnumValN(ActionType::ListDiagnosticGroups, + "list-diagnostic-groups", + "List all diagnostic groups and their documentation files"))); static llvm::cl::opt SourceFilename("source-filename", llvm::cl::desc("Name of the source file"), @@ -4561,6 +4566,15 @@ int main(int argc, char *argv[]) { return 0; } + if (options::Action == ActionType::ListDiagnosticGroups) { + for (const auto &group : diagnosticGroupsInfo) { + if (group.documentationFile.empty()) + continue; + llvm::outs() << group.name << " " << group.documentationFile << "\n"; + } + return 0; + } + if (options::SourceFilename.empty()) { llvm::errs() << "source file required\n"; llvm::cl::PrintHelpMessage(); @@ -4967,6 +4981,9 @@ int main(int argc, char *argv[]) { options::CodeCompletionToken, options::CodeCompletionDiagnostics); break; + case ActionType::ListDiagnosticGroups: + llvm_unreachable("handled earlier"); + case ActionType::SyntaxColoring: ExitCode = doSyntaxColoring(InitInvok, options::SourceFilename, diff --git a/userdocs/diagnostics/access-note.md b/userdocs/diagnostics/access-note.md new file mode 100644 index 0000000000000..faf763053fbc6 --- /dev/null +++ b/userdocs/diagnostics/access-note.md @@ -0,0 +1,37 @@ +# Invalid or successful access notes (AccessNote) + +Remarks to verify application of access notes, and errors diagnosing access note failures. + +## Overview + +By providing an access notes file, you can annotate Swift declarations with `@objc` without modifying the source code. To verify that they are applied correctly you can enable remark output during compilation. + +Available options: + - -Raccess-note=none + - don't emit access note diagnostics + - -Raccess-note=failure + - emit remark for access notes that were not applied because of a failure + - -Raccess-note=all + - in addition to failures, also emit remarks for successfully applied access notes + - -Raccess-note=all-validate + - emit remarks for successfully applied access notes, and emit *errors* for failures + +## Using access notes + +Access notes use the YAML file format and can be supplied using `-access-notes-path foo.accessnotes`. Example file: + +```yaml +--- +Reason: this text is included in diagnostics +Notes: +- Name: 'TypeName.methodName(_:)' + ObjC: true + ObjCName: 'customObjCSelector:' + Dynamic: true +- Name: 'getter:Foo.someComputedProp()' + ObjCName: 'getSomeComputedProp' +- Name: 'setter:Foo.someComputedProp()' + ObjCName: 'setSomeComputedProp:' +``` + +`-Raccess-note=` is a frontend-only option intended for testing and debugging. It is not exposed in the compiler driver. diff --git a/userdocs/diagnostics/cross-import.md b/userdocs/diagnostics/cross-import.md new file mode 100644 index 0000000000000..e015ecc0f4630 --- /dev/null +++ b/userdocs/diagnostics/cross-import.md @@ -0,0 +1,27 @@ +# Added cross import (CrossImport) + +Remarks when importing a module triggers cross import of another module. + +## Overview + +Enable the remarks with `-Rcross-import`. This can be used to test that the cross import is working as intended. + +## Using cross imports + +A module declares cross-imports via a .swiftcrossimport directory next to its .swiftmodule, containing .swiftoverlay YAML files named after the "bystander" module: + +``` +FooKit.swiftcrossimport/ + BarKit.swiftoverlay +``` + +The overlay file is YAML: +```yaml +%YAML 1.2 +--- +version: 1 +modules: + - name: _FooBarAdditions +``` + +When both `FooKit` and `BarKit` are imported, `_FooBarAdditions` is implicitly imported as well. This allows shipping integrations between modules that don't explicitly depend on each other. diff --git a/userdocs/diagnostics/dependency-scan-cache.md b/userdocs/diagnostics/dependency-scan-cache.md new file mode 100644 index 0000000000000..e0c899df3eac3 --- /dev/null +++ b/userdocs/diagnostics/dependency-scan-cache.md @@ -0,0 +1,8 @@ +# Dependency scan cache remarks (DependencyScanCache) + +Remarks indicating use of the serialized module dependency scanning cache. + +## Overview + +Enable the remarks using -Rdependency-scan-cache. This option is intended for testing purposes and is not exposed in the compiler driver. + diff --git a/userdocs/diagnostics/dependency-scan.md b/userdocs/diagnostics/dependency-scan.md new file mode 100644 index 0000000000000..367386ed28974 --- /dev/null +++ b/userdocs/diagnostics/dependency-scan.md @@ -0,0 +1,7 @@ +# Dependency scan remarks (DependencyScan) + +Remarks for various steps taken by the dependency scanner. + +## Overview + +Enable the remarks using -Rdependency-scan. This option is intended for testing purposes and is not exposed in the compiler driver. diff --git a/userdocs/diagnostics/diagnostic-groups.md b/userdocs/diagnostics/diagnostic-groups.md index a7a2b8457bb9c..a6e82509bba38 100644 --- a/userdocs/diagnostics/diagnostic-groups.md +++ b/userdocs/diagnostics/diagnostic-groups.md @@ -24,6 +24,9 @@ Or upgrade all warnings except deprecated declaration to errors: -warnings-as-errors -Wwarning DeprecatedDeclaration ``` +For groups containing remarks, those remarks can be enabled using `-R `. +You can list the remark groups supported by your particular toolchain version using `-Rhelp`. + ## Groups with warnings - - @@ -46,6 +49,7 @@ Or upgrade all warnings except deprecated declaration to errors: - - - +- - - - @@ -55,8 +59,23 @@ Or upgrade all warnings except deprecated declaration to errors: - +## Groups with remarks +- +- +- +- +- +- +- +- +- +- +- + + ## Topics - +- - - - @@ -64,6 +83,8 @@ Or upgrade all warnings except deprecated declaration to errors: - - - +- +- - - - @@ -75,11 +96,19 @@ Or upgrade all warnings except deprecated declaration to errors: - - - +- +- - - +- +- - - - +- +- +- +- - - - @@ -90,11 +119,14 @@ Or upgrade all warnings except deprecated declaration to errors: - - - +- +- - - - - - +- - - - diff --git a/userdocs/diagnostics/indexing-system-module.md b/userdocs/diagnostics/indexing-system-module.md new file mode 100644 index 0000000000000..d6a49475ef24e --- /dev/null +++ b/userdocs/diagnostics/indexing-system-module.md @@ -0,0 +1,8 @@ +# Indexing system module remarks (IndexingSystemModule) + +Remarks when system modules are indexed. + +## Overview + +Enable using -Rindexing-system-module. + diff --git a/userdocs/diagnostics/macro-expansions.md b/userdocs/diagnostics/macro-expansions.md new file mode 100644 index 0000000000000..f2bb698bd9421 --- /dev/null +++ b/userdocs/diagnostics/macro-expansions.md @@ -0,0 +1,8 @@ +# Macro expansion remarks (MacroExpansions) + +Emits a remark for each line in a macro expansion. + +## Overview + +Enable using `-Rmacro-expansion`. This option is intended for testing purposes and is not exposed in the compiler driver. See also `-dump-macro-expansion`. + diff --git a/userdocs/diagnostics/macro-loading.md b/userdocs/diagnostics/macro-loading.md new file mode 100644 index 0000000000000..25c123dc31da9 --- /dev/null +++ b/userdocs/diagnostics/macro-loading.md @@ -0,0 +1,8 @@ +# Macro loading remarks (MacroLoading) + +Emits a remark for each loaded macro implementation. + +## Overview + +Enable using `-Rmacro-loading`. This can be used to debug macro issues by verifying that the compiler found and loaded the macro. + diff --git a/userdocs/diagnostics/modularization-issue.md b/userdocs/diagnostics/modularization-issue.md new file mode 100644 index 0000000000000..4b1ffbb273aa1 --- /dev/null +++ b/userdocs/diagnostics/modularization-issue.md @@ -0,0 +1,9 @@ +# Modularization errors (ModularizationIssue) + +Errors detected when loading a module. + +## Overview + +Emits a errors when a module's public API refers to a declaration or type that is not found in the module. This could be because it's not public, or because it's imported without being reexported. The compiler should normally prevent this from happening; please file a bug report if you encounter one of these errors. + +For debugging purposes these errors can be downgraded to remarks using -Rmodule-recovery. diff --git a/userdocs/diagnostics/module-api-import.md b/userdocs/diagnostics/module-api-import.md new file mode 100644 index 0000000000000..fd288d14f1fb0 --- /dev/null +++ b/userdocs/diagnostics/module-api-import.md @@ -0,0 +1,7 @@ +# Module API import remarks (ModuleAPIImport) + +Emits a remark about the import bridging in each element composing the API. + +## Overview + +Enable using `-Rmodule-api-import`. For each declaration referenced from another module, a remark is emitted with information about the module it is imported from. If it was reexported, the original module is also noted. diff --git a/userdocs/diagnostics/module-interface-rebuild.md b/userdocs/diagnostics/module-interface-rebuild.md new file mode 100644 index 0000000000000..7e0ddc6f57c8a --- /dev/null +++ b/userdocs/diagnostics/module-interface-rebuild.md @@ -0,0 +1,8 @@ +# Module interface rebuild remarks (ModuleInterfaceRebuild) + +Emits a remark if an imported module needs to be re-compiled from its module interface. + +## Overview + +Enable using `-Rmodule-interface-rebuild`. This option is intended for testing purposes and is not exposed in the compiler driver. + diff --git a/userdocs/diagnostics/module-loading.md b/userdocs/diagnostics/module-loading.md new file mode 100644 index 0000000000000..56328d9d977d9 --- /dev/null +++ b/userdocs/diagnostics/module-loading.md @@ -0,0 +1,7 @@ +# Module loading remarks (ModuleLoading) + +Emits a remark about a loaded module. + +## Overview + +Enable using `-Rmodule-loading`. Used for debugging which module an import is resolved to, and where it's located. diff --git a/userdocs/diagnostics/module-serialization.md b/userdocs/diagnostics/module-serialization.md new file mode 100644 index 0000000000000..30e4932126c52 --- /dev/null +++ b/userdocs/diagnostics/module-serialization.md @@ -0,0 +1,7 @@ +# Skipped serialization remarks (ModuleSerialization) + +Emits remarks when the serializer skips invalid constructs. + +## Overview + +These remarks can be enabled with -Rmodule-serialization. Each construct highlighted because of these remarks should also have an associated error emitted (regardless of whether the remark is enabled). diff --git a/userdocs/diagnostics/region-isolation.md b/userdocs/diagnostics/region-isolation.md new file mode 100644 index 0000000000000..845d388628e70 --- /dev/null +++ b/userdocs/diagnostics/region-isolation.md @@ -0,0 +1,8 @@ +# Region isolation warnings (RegionIsolation) + +Warnings that identify cases where sending risks causing a data race. + +## Overview + +See sub-categories SendingRisksDataRace and SendingClosureRisksDataRace. + diff --git a/userdocs/diagnostics/weak-mutability.md b/userdocs/diagnostics/weak-mutability.md new file mode 100644 index 0000000000000..536098a99f2c4 --- /dev/null +++ b/userdocs/diagnostics/weak-mutability.md @@ -0,0 +1,7 @@ +# Redundantly mutable weak variables (WeakMutability) + +Warnings that identify `weak` variables that are never updated. + +## Overview + +This is the `weak var` equivalent of the always-on warning for `var`s that are never mutated. Note that replacing `weak var` with `let` makes it a strong reference. This may cause a memory leak in cases where `weak` is actually appropriate, so replacing `weak var` with `let` is not always the correct course of action. There is no such thing as `weak let`, since a weak reference is automatically reassigned to `nil` when the referenced object is deallocated. diff --git a/utils/generate-doc-index.swift b/utils/generate-doc-index.swift index c5ed36d05a8fc..f3c46b4e8e503 100755 --- a/utils/generate-doc-index.swift +++ b/utils/generate-doc-index.swift @@ -38,6 +38,9 @@ Or upgrade all warnings except deprecated declaration to errors: ```sh -warnings-as-errors -Wwarning DeprecatedDeclaration ``` + +For groups containing remarks, those remarks can be enabled using `-R `. +You can list the remark groups supported by your particular toolchain version using `-Rhelp`. """ let featuresDocFileName = "upcoming-language-features.md" @@ -96,7 +99,8 @@ do { func generateIndex() throws { let groupsWithWarnings = try groupNamesWithWarnings() - let docs = try retrieveDocs(groupsWithWarnings).sorted { a, b in + let groupsWithRemarks = try groupNamesWithRemarks() + let docs = try retrieveDocs(groupsWithWarnings, groupsWithRemarks).sorted { a, b in return a.title < b.title } @@ -112,13 +116,19 @@ func generateIndex() throws { try groupsHandle.write(contentsOf: ref.data(using: .utf8)!) } + try groupsHandle.write(contentsOf: "\n\n## Groups with remarks\n".data(using: .utf8)!) + for doc in docs where doc.kind == .groupWithRemarks { + let ref = "- \n" + try groupsHandle.write(contentsOf: ref.data(using: .utf8)!) + } + try groupsHandle.write(contentsOf: topicsHeader.data(using: .utf8)!) try featuresHandle.write(contentsOf: topicsHeader.data(using: .utf8)!) for doc in docs { let handle: FileHandle switch doc.kind { - case .group, .groupWithWarnings: + case .group, .groupWithWarnings, .groupWithRemarks: handle = groupsHandle case .feature: handle = featuresHandle @@ -142,7 +152,7 @@ func createIndex(name: String, header: String) throws -> FileHandle { return handle } -func retrieveDocs(_ groupsWithWarnings: Set) throws -> [UserDoc] { +func retrieveDocs(_ groupsWithWarnings: Set, _ groupsWithRemarks: Set) throws -> [UserDoc] { let groups = Dictionary(try matches(in: "\(swiftSourceDir)/\(groupsFileName)", with: groupRegex) { (file: String($0.file), name: String($0.name)) }, uniquingKeysWith: { a, b in a }) @@ -180,6 +190,8 @@ func retrieveDocs(_ groupsWithWarnings: Set) throws -> [UserDoc] { kind = .feature } else if groupsWithWarnings.contains(groupName) { kind = .groupWithWarnings + } else if groupsWithRemarks.contains(groupName) { + kind = .groupWithRemarks } else { kind = .group } @@ -190,7 +202,23 @@ func retrieveDocs(_ groupsWithWarnings: Set) throws -> [UserDoc] { return docs } +enum DiagKind { + case warning, remark + + var asString: String { + switch (self) { + case .warning: "WARNING" + case .remark: "REMARK" + } + } +} func groupNamesWithWarnings() throws -> Set { + return try groupNames(with: .warning) +} +func groupNamesWithRemarks() throws -> Set { + return try groupNames(with: .remark) +} +func groupNames(with kind: DiagKind) throws -> Set { let includePath = "\(swiftSourceDir)/\(swiftIncludeDir)" let defPaths = try FileManager.default.subpathsOfDirectory(atPath: includePath) .compactMap { subpath in @@ -200,7 +228,7 @@ func groupNamesWithWarnings() throws -> Set { return nil } - enum WarningGroupState { + enum GroupState { case outside, inside, name } @@ -208,13 +236,13 @@ func groupNamesWithWarnings() throws -> Set { for path in defPaths { let file = try String(contentsOfFile: path, encoding: .utf8) - var state = WarningGroupState.outside + var state = GroupState.outside for line in file.components(separatedBy: .newlines) { var line = Substring(line) switch state { case .outside: - if !line.hasPrefix("GROUPED_WARNING") { + if !line.hasPrefix("GROUPED_"+kind.asString) { continue } @@ -266,6 +294,7 @@ struct UserDoc { enum Kind { case group case groupWithWarnings + case groupWithRemarks case feature }