1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
//===--- SupportedFeatures.cpp - Supported features printing --------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include <array>
#include <vector>
#include "swift/AST/DiagnosticGroups.h"
#include "swift/Basic/Feature.h"
#include "swift/Frontend/Frontend.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;
namespace swift {
namespace features {
/// The subset of diagnostic groups (called categories by the diagnostic machinery) whose diagnostics should be
/// considered to be part of the migration for this feature.
///
/// When making a feature migratable, ensure that all of the warnings that are used to drive the migration are
/// part of a diagnostic group, and put that diagnostic group into the list for that feature here.
static std::vector<DiagGroupID> migratableCategories(Feature feature) {
switch (feature) {
case Feature::InnerKind::ExistentialAny:
return { DiagGroupID::ExistentialAny };
case Feature::InnerKind::InferIsolatedConformances:
return { DiagGroupID::IsolatedConformances };
case Feature::InnerKind::MemberImportVisibility:
return { DiagGroupID::MemberImportVisibility };
case Feature::InnerKind::NonisolatedNonsendingByDefault:
return { DiagGroupID::NonisolatedNonsendingByDefault };
case Feature::InnerKind::StrictMemorySafety:
return { DiagGroupID::StrictMemorySafety };
// Provide unreachable cases for all of the non-migratable features.
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) case Feature::FeatureName:
#define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version)
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
#define MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Name)
#include "swift/Basic/Features.def"
llvm_unreachable("Not a migratable feature");
}
}
/// For optional language features, return the flag name used by the compiler to enable the feature. For all others,
/// returns an empty optional.
static std::optional<std::string_view> optionalFlagName(Feature feature) {
switch (feature) {
case Feature::StrictMemorySafety:
return "-strict-memory-safety";
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) case Feature::FeatureName:
#define OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Description)
#include "swift/Basic/Features.def"
return std::nullopt;
}
}
/// Print information about what features upcoming/experimental are
/// supported by the compiler.
/// The information includes whether a feature is adoptable and for
/// upcoming features - what is the first mode it's introduced.
void printSupportedFeatures(llvm::raw_ostream &out) {
std::array optional{
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description)
#define OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Description) Feature::FeatureName,
#include "swift/Basic/Features.def"
};
std::array upcoming{
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description)
#define UPCOMING_FEATURE(FeatureName, SENumber, Version) Feature::FeatureName,
#include "swift/Basic/Features.def"
};
std::vector<swift::Feature> experimental{{
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description)
#define EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) Feature::FeatureName,
#include "swift/Basic/Features.def"
}};
// Include only experimental features that are available in production.
llvm::erase_if(experimental, [](auto &feature) {
return feature.isAvailableInProduction();
});
out << "{\n";
auto printFeature = [&out](const Feature &feature) {
out << " ";
out << "{ \"name\": \"" << feature.getName() << "\"";
if (feature.isMigratable()) {
out << ", \"migratable\": true";
auto categories = migratableCategories(feature);
out << ", \"categories\": [";
llvm::interleave(categories, [&out](DiagGroupID diagGroupID) {
out << "\"" << getDiagGroupInfoByID(diagGroupID).name << "\"";
}, [&out] {
out << ", ";
});
out << "]";
}
if (auto version = feature.getLanguageVersion()) {
out << ", \"enabled_in\": \"" << *version << "\"";
}
if (auto flagName = optionalFlagName(feature)) {
out << ", \"flag_name\": \"" << *flagName << "\"";
}
out << " }";
};
out << " \"features\": {\n";
out << " \"optional\": [\n";
llvm::interleave(optional, printFeature, [&out] { out << ",\n"; });
out << "\n ],\n";
out << " \"upcoming\": [\n";
llvm::interleave(upcoming, printFeature, [&out] { out << ",\n"; });
out << "\n ],\n";
out << " \"experimental\": [\n";
llvm::interleave(experimental, printFeature, [&out] { out << ",\n"; });
out << "\n ]\n";
out << " }\n";
out << "}\n";
}
} // end namespace features
} // end namespace swift
|