@@ -181,7 +181,7 @@ class SCIPState {
181
181
//
182
182
// FIXME(varun): This seems redundant, get rid of it.
183
183
184
- GemMetadata gemMetadata ;
184
+ GemMapping gemMap ;
185
185
186
186
public:
187
187
UnorderedMap<core::FileRef, vector<scip::Occurrence>> occurrenceMap;
@@ -207,9 +207,9 @@ class SCIPState {
207
207
vector<scip::SymbolInformation> externalSymbols;
208
208
209
209
public:
210
- SCIPState (GemMetadata metadata )
210
+ SCIPState (GemMapping gemMap )
211
211
: symbolStringCache(), localOccurrenceCache(), symbolOccurrenceCache(), potentialRefOnlySymbols(),
212
- gemMetadata (metadata ), occurrenceMap(), emittedSymbols(), symbolMap(), documents(), externalSymbols() {}
212
+ gemMap (gemMap ), occurrenceMap(), emittedSymbols(), symbolMap(), documents(), externalSymbols() {}
213
213
~SCIPState () = default ;
214
214
SCIPState (SCIPState &&) = default;
215
215
SCIPState &operator =(SCIPState &&other) = default ;
@@ -241,7 +241,7 @@ class SCIPState {
241
241
status = scip::utils::emitSymbolString (*symbol, output);
242
242
} else {
243
243
scip::Symbol symbol;
244
- status = symRef.symbolForExpr (gs, this ->gemMetadata , {}, symbol);
244
+ status = symRef.symbolForExpr (gs, this ->gemMap , {}, symbol);
245
245
if (!status.ok ()) {
246
246
return status;
247
247
}
@@ -402,7 +402,7 @@ class SCIPState {
402
402
auto occLoc = loc.has_value () ? core::Loc (file, loc.value ()) : symRef.symbolLoc (gs);
403
403
scip::Symbol symbol;
404
404
auto untypedSymRef = symRef.withoutType ();
405
- auto status = untypedSymRef.symbolForExpr (gs, this ->gemMetadata , occLoc, symbol);
405
+ auto status = untypedSymRef.symbolForExpr (gs, this ->gemMap , occLoc, symbol);
406
406
if (!status.ok ()) {
407
407
return status;
408
408
}
@@ -1114,18 +1114,40 @@ namespace sorbet::pipeline::semantic_extension {
1114
1114
using LocalSymbolTable = UnorderedMap<core::LocalVariable, core::Loc>;
1115
1115
1116
1116
class SCIPSemanticExtension : public SemanticExtension {
1117
- public:
1118
1117
string indexFilePath;
1119
- string gemMetadataString;
1120
- scip_indexer::GemMetadata gemMetadata;
1118
+ string gemMetadataArg;
1119
+ string gemMapPath;
1120
+ scip_indexer::GemMapping gemMap;
1121
1121
1122
1122
using SCIPState = sorbet::scip_indexer::SCIPState;
1123
1123
1124
+ public:
1125
+ using StateMap = UnorderedMap<thread::id, shared_ptr<SCIPState>>;
1126
+
1127
+ private:
1124
1128
mutable struct {
1125
- UnorderedMap<thread::id, shared_ptr<SCIPState>> states;
1129
+ StateMap states;
1126
1130
absl::Mutex mtx;
1127
1131
} mutableState;
1128
1132
1133
+ public:
1134
+ SCIPSemanticExtension (string indexFilePath, string gemMetadataArg, string gemMapPath,
1135
+ scip_indexer::GemMapping gemMap, StateMap states)
1136
+ : indexFilePath(indexFilePath), gemMetadataArg(gemMetadataArg), gemMapPath(gemMapPath),
1137
+ gemMap (gemMap), mutableState{states, {}} {}
1138
+
1139
+ ~SCIPSemanticExtension () {}
1140
+
1141
+ virtual unique_ptr<SemanticExtension> deepCopy (const core::GlobalState &from, core::GlobalState &to) override {
1142
+ // FIXME: Technically, this would copy the state too, but we haven't implemented
1143
+ // deep-copying for it because it doesn't matter for scip-ruby.
1144
+ StateMap map;
1145
+ return make_unique<SCIPSemanticExtension>(this ->indexFilePath , this ->gemMetadataArg , this ->gemMapPath ,
1146
+ this ->gemMap , map);
1147
+ };
1148
+ virtual void merge (const core::GlobalState &from, core::GlobalState &to, core::NameSubstitution &subst) override {};
1149
+
1150
+ private:
1129
1151
// Return a shared_ptr here as we need a stable address to avoid an invalid reference
1130
1152
// on table resizing, and we need to maintain at least two pointers,
1131
1153
// an "owning ref" from the table and a mutable borrow from the caller.
@@ -1141,24 +1163,26 @@ class SCIPSemanticExtension : public SemanticExtension {
1141
1163
1142
1164
// We will move the state out later, so use a no-op deleter.
1143
1165
return mutableState.states [this_thread::get_id ()] =
1144
- shared_ptr<SCIPState>(new SCIPState (gemMetadata ), [](SCIPState *) {});
1166
+ shared_ptr<SCIPState>(new SCIPState (gemMap ), [](SCIPState *) {});
1145
1167
}
1146
1168
}
1147
1169
1148
1170
bool doNothing () const {
1149
1171
return this ->indexFilePath .empty ();
1150
1172
}
1151
1173
1174
+ public:
1152
1175
void run (core::MutableContext &ctx, ast::ClassDef *cd) const override {}
1153
1176
1154
1177
virtual void prepareForTypechecking (const core::GlobalState &gs) override {
1155
- auto maybeMetadata = scip_indexer::GemMetadata::tryParse (this ->gemMetadataString );
1178
+ auto maybeMetadata = scip_indexer::GemMetadata::tryParse (this ->gemMetadataArg );
1179
+ scip_indexer::GemMetadata currentGem;
1156
1180
if (maybeMetadata.has_value ()) {
1157
- this -> gemMetadata = maybeMetadata.value ();
1181
+ currentGem = maybeMetadata.value ();
1158
1182
} // TODO: Issue error for incorrect format in string...
1159
- if (this -> gemMetadata .name ().empty () || this -> gemMetadata .version ().empty ()) {
1160
- auto [metadata , errors] = scip_indexer::GemMetadata::readFromConfig (OSFileSystem ());
1161
- this -> gemMetadata = metadata ;
1183
+ if (currentGem .name ().empty () || currentGem .version ().empty ()) {
1184
+ auto [gem , errors] = scip_indexer::GemMetadata::readFromConfig (OSFileSystem ());
1185
+ currentGem = gem ;
1162
1186
for (auto &error : errors) {
1163
1187
if (auto e = gs.beginError (core::Loc (), scip_indexer::SCIPRubyDebug)) {
1164
1188
e.setHeader (" {}: {}" ,
@@ -1167,6 +1191,10 @@ class SCIPSemanticExtension : public SemanticExtension {
1167
1191
}
1168
1192
}
1169
1193
}
1194
+ this ->gemMap .markCurrentGem (currentGem);
1195
+ if (!this ->gemMapPath .empty ()) {
1196
+ this ->gemMap .populateFromNDJSON (gs, OSFileSystem ().readFile (this ->gemMapPath ));
1197
+ }
1170
1198
};
1171
1199
1172
1200
virtual void finishTypecheckFile (const core::GlobalState &gs, const core::FileRef &file) const override {
@@ -1269,27 +1297,25 @@ class SCIPSemanticExtension : public SemanticExtension {
1269
1297
traversal.traverse (cfg);
1270
1298
scipStateRef.clearFunctionLocalCaches ();
1271
1299
}
1272
-
1273
- virtual unique_ptr<SemanticExtension> deepCopy (const core::GlobalState &from, core::GlobalState &to) override {
1274
- return make_unique<SCIPSemanticExtension>(this ->indexFilePath , this ->gemMetadataString , this ->gemMetadata );
1275
- };
1276
- virtual void merge (const core::GlobalState &from, core::GlobalState &to, core::NameSubstitution &subst) override {};
1277
-
1278
- SCIPSemanticExtension (string indexFilePath, string gemMetadataString, scip_indexer::GemMetadata gemMetadata)
1279
- : indexFilePath(indexFilePath), gemMetadataString(gemMetadataString), gemMetadata(gemMetadata), mutableState() {
1280
- }
1281
- ~SCIPSemanticExtension () {}
1282
1300
};
1283
1301
1284
1302
class SCIPSemanticExtensionProvider : public SemanticExtensionProvider {
1285
1303
public:
1286
1304
void injectOptions (cxxopts::Options &optsBuilder) const override {
1287
- optsBuilder.add_options (" indexer" )(" index-file" , " Output SCIP index to a directory, which must already exist" ,
1288
- cxxopts::value<string>())(
1289
- " gem-metadata" ,
1305
+ // clang-format off
1306
+ optsBuilder.add_options (" indexer" )
1307
+ (" index-file" ,
1308
+ " Output SCIP index to a directory, which must already exist" ,
1309
+ cxxopts::value<string>())
1310
+ (" gem-metadata" ,
1290
1311
" Metadata in 'name@version' format to be used for cross-repository code navigation. For repositories which "
1291
1312
" index every commit, the SHA should be used for the version instead of a git tag (or equivalent)." ,
1313
+ cxxopts::value<string>())
1314
+ (" gem-map-path" ,
1315
+ " Path to newline delimited JSON file which describes how to map paths to gem name and versions. See the"
1316
+ " scip-ruby docs on GitHub for information about the JSON schema." ,
1292
1317
cxxopts::value<string>());
1318
+ // clang-format on
1293
1319
};
1294
1320
unique_ptr<SemanticExtension> readOptions (cxxopts::ParseResult &providedOptions) const override {
1295
1321
if (providedOptions.count (" version" ) > 0 ) {
@@ -1308,12 +1334,22 @@ class SCIPSemanticExtensionProvider : public SemanticExtensionProvider {
1308
1334
} else {
1309
1335
indexFilePath = " index.scip" ;
1310
1336
}
1311
- auto gemMetadataString =
1312
- providedOptions.count (" gem-metadata" ) > 0 ? providedOptions[" gem-metadata" ].as <string>() : " " ;
1313
- return make_unique<SCIPSemanticExtension>(indexFilePath, gemMetadataString, scip_indexer::GemMetadata ());
1337
+ string gemMapPath{};
1338
+ if (providedOptions.count (" gem-map-path" ) > 0 ) {
1339
+ gemMapPath = providedOptions[" gem-map-path" ].as <string>();
1340
+ }
1341
+ string gemMetadataArg{};
1342
+ if (providedOptions.count (" gem-metadata" ) > 0 ) {
1343
+ gemMetadataArg = providedOptions[" gem-metadata" ].as <string>();
1344
+ }
1345
+ scip_indexer::GemMapping gemMap{};
1346
+ SCIPSemanticExtension::StateMap stateMap;
1347
+ return make_unique<SCIPSemanticExtension>(indexFilePath, gemMetadataArg, gemMapPath, gemMap, stateMap);
1314
1348
};
1315
1349
virtual unique_ptr<SemanticExtension> defaultInstance () const override {
1316
- return make_unique<SCIPSemanticExtension>(" index.scip" , " " , scip_indexer::GemMetadata ());
1350
+ scip_indexer::GemMapping gemMap{};
1351
+ SCIPSemanticExtension::StateMap stateMap;
1352
+ return make_unique<SCIPSemanticExtension>(" index.scip" , " " , " " , gemMap, stateMap);
1317
1353
};
1318
1354
static vector<SemanticExtensionProvider *> getProviders ();
1319
1355
virtual ~SCIPSemanticExtensionProvider () = default ;
0 commit comments