-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathImportEnumInfo.h
177 lines (149 loc) · 5.82 KB
/
ImportEnumInfo.h
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//===--- ImportEnumInfo.h - Importable Clang enums information --*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
//
// This file provides ImportEnumInfo, which describes a Clang enum ready to be
// imported
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_CLANG_IMPORT_ENUM_H
#define SWIFT_CLANG_IMPORT_ENUM_H
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/DenseMap.h"
namespace clang {
class EnumDecl;
class Preprocessor;
class MacroInfo;
}
namespace swift {
namespace importer {
/// Describes how a particular C enumeration type will be imported
/// into Swift. All of the possibilities have the same storage
/// representation, but can be used in different ways.
enum class EnumKind {
/// The enumeration type should map to a frozen enum, which means that
/// all of the cases are independent and there are no private cases.
FrozenEnum,
/// The enumeration type should map to a non-frozen enum, which means that
/// all of the cases are independent, but there may be values not represented
/// in the listed cases.
NonFrozenEnum,
/// The enumeration type should map to an option set, which means that
/// the constants represent combinations of independent flags.
Options,
/// The enumeration type should map to a distinct type, but we don't
/// know the intended semantics of the enum constants, so conservatively
/// map them to independent constants.
Unknown,
/// The enumeration constants should simply map to the appropriate
/// integer values.
Constants,
};
class EnumInfo {
/// The kind
EnumKind kind = EnumKind::Unknown;
/// The enum's common constant name prefix, which will be stripped from
/// constants
StringRef constantNamePrefix = StringRef();
/// The name of the NS error domain for Cocoa error enums.
StringRef nsErrorDomain = StringRef();
public:
EnumInfo() = default;
EnumInfo(const clang::EnumDecl *decl, clang::Preprocessor &pp) {
classifyEnum(decl, pp);
determineConstantNamePrefix(decl);
}
EnumKind getKind() const { return kind; }
StringRef getConstantNamePrefix() const { return constantNamePrefix; }
/// Whether this maps to an enum who also provides an error domain
bool isErrorEnum() const {
switch (getKind()) {
case EnumKind::FrozenEnum:
case EnumKind::NonFrozenEnum:
return !nsErrorDomain.empty();
case EnumKind::Options:
case EnumKind::Unknown:
case EnumKind::Constants:
return false;
}
llvm_unreachable("unhandled kind");
}
/// For this error enum, extract the name of the error domain constant
StringRef getErrorDomain() const {
assert(isErrorEnum() && "not error enum");
return nsErrorDomain;
}
private:
void determineConstantNamePrefix(const clang::EnumDecl *);
void classifyEnum(const clang::EnumDecl *, clang::Preprocessor &);
};
/// Provide a cache of enum infos, so that we don't have to re-calculate their
/// information.
class EnumInfoCache {
clang::Preprocessor &clangPP;
llvm::DenseMap<const clang::EnumDecl *, EnumInfo> enumInfos;
// Never copy
EnumInfoCache(const EnumInfoCache &) = delete;
EnumInfoCache &operator = (const EnumInfoCache &) = delete;
public:
explicit EnumInfoCache(clang::Preprocessor &cpp) : clangPP(cpp) {}
EnumInfo getEnumInfo(const clang::EnumDecl *decl);
EnumKind getEnumKind(const clang::EnumDecl *decl) {
return getEnumInfo(decl).getKind();
}
/// The prefix to be stripped from the names of the enum constants within the
/// given enum.
StringRef getEnumConstantNamePrefix(const clang::EnumDecl *decl) {
return getEnumInfo(decl).getConstantNamePrefix();
}
};
// Utility functions of primary interest to enum constant naming
/// Returns the common prefix of two strings at camel-case word granularity.
///
/// For example, given "NSFooBar" and "NSFooBas", returns "NSFoo"
/// (not "NSFooBa"). The returned StringRef is a slice of the "a" argument.
///
/// If either string has a non-identifier character immediately after the
/// prefix, \p followedByNonIdentifier will be set to \c true. If both strings
/// have identifier characters after the prefix, \p followedByNonIdentifier will
/// be set to \c false. Otherwise, \p followedByNonIdentifier will not be
/// changed from its initial value.
///
/// This is used to derive the common prefix of enum constants so we can elide
/// it from the Swift interface.
StringRef getCommonWordPrefix(StringRef a, StringRef b,
bool &followedByNonIdentifier);
/// Returns the common word-prefix of two strings, allowing the second string
/// to be a common English plural form of the first.
///
/// For example, given "NSProperty" and "NSProperties", the full "NSProperty"
/// is returned. Given "NSMagicArmor" and "NSMagicArmory", only
/// "NSMagic" is returned.
///
/// The "-s", "-es", and "-ies" patterns cover every plural NS_OPTIONS name
/// in Cocoa and Cocoa Touch.
///
/// \see getCommonWordPrefix
StringRef getCommonPluralPrefix(StringRef singular, StringRef plural);
/// Returns the underlying integer type of an enum. If clang treats the type as
/// an elaborated type, an unwrapped type is returned.
const clang::Type *getUnderlyingType(const clang::EnumDecl *decl);
inline bool isCFOptionsMacro(StringRef macroName) {
return llvm::StringSwitch<bool>(macroName)
.Case("CF_OPTIONS", true)
.Case("NS_OPTIONS", true)
.Default(false);
}
}
}
#endif // SWIFT_CLANG_IMPORT_ENUM_H