Changeset View
Changeset View
Standalone View
Standalone View
duchain/declarationbuilder.cpp
Context not available. | |||||
1198 | return lhsExpressions; | 1198 | return lhsExpressions; | ||
---|---|---|---|---|---|
1199 | } | 1199 | } | ||
1200 | 1200 | | |||
1201 | QList<DeclarationBuilder::SourceType> DeclarationBuilder::sourcesOfAssignment(ExpressionAst* items, | 1201 | QVector<DeclarationBuilder::SourceType> | ||
1202 | int fillWhenLengthMissing) const | 1202 | DeclarationBuilder::unpackAssignmentSource(const SourceType& source, | ||
1203 | int fillWhenLengthMissing) const | ||||
1203 | { | 1204 | { | ||
1204 | QList<SourceType> sources; | 1205 | QVector<SourceType> sources; | ||
1205 | QList<ExpressionAst*> values; | 1206 | if ( const IndexedContainer::Ptr container = source.type.cast<IndexedContainer>() ) { | ||
1206 | 1207 | // RHS is a tuple or similar, unpack that. | |||
1207 | // TODO rework this function. It doesn't make much sense like this and could work much better. | 1208 | for (int i = 0; i < container->typesCount(); ++i) { | ||
1208 | if ( items && items->astType == Ast::TupleAstType ) { | 1209 | sources << SourceType{ | ||
1209 | values = static_cast<TupleAst*>(items)->elements; | 1210 | container->typeAt(i).abstractType(), | ||
1210 | } | 1211 | DeclarationPointer(), | ||
1211 | else { | 1212 | false | ||
1212 | // This handles the a, b, c = [1, 2, 3] case. Since the assignment can also be like | 1213 | }; | ||
1213 | // d = [1, 2, 3]; a, b, c = d we can't generally know the amount of elements | | |||
1214 | // in the right operand; so all elements are treated to have the same type. | | |||
1215 | if ( fillWhenLengthMissing > 0 ) { | | |||
1216 | ExpressionVisitor v(currentContext()); | | |||
1217 | v.visitNode(items); | | |||
1218 | auto container = ListType::Ptr::dynamicCast(v.lastType()); | | |||
1219 | if ( container ) { | | |||
1220 | AbstractType::Ptr content = container->contentType().abstractType(); | | |||
1221 | for ( ; fillWhenLengthMissing != 0; fillWhenLengthMissing-- ) { | | |||
1222 | sources << SourceType{ content, KDevelop::DeclarationPointer(), false }; | | |||
1223 | } | | |||
1224 | return sources; | | |||
1225 | } | | |||
1226 | } | 1214 | } | ||
1227 | | ||||
1228 | // Otherwise, proceed normally. | | |||
1229 | values << items; | | |||
1230 | } | | |||
1231 | | ||||
1232 | foreach ( ExpressionAst* value, values ) { | | |||
1233 | ExpressionVisitor v(currentContext()); | | |||
1234 | v.visitNode(value); | | |||
1235 | | ||||
1236 | sources << SourceType{ | | |||
1237 | v.lastType(), | | |||
1238 | DeclarationPointer(Helper::resolveAliasDeclaration(v.lastDeclaration().data())), | | |||
1239 | v.isAlias() | | |||
1240 | }; | | |||
1241 | } | 1215 | } | ||
1242 | return sources; | 1216 | else if ( auto container = ListType::Ptr::dynamicCast(source.type) ) { | ||
1243 | } | 1217 | // RHS is a list or similar, can't tell contents apart. | ||
1244 | 1218 | // Return content type * requested length. | |||
1245 | DeclarationBuilder::SourceType DeclarationBuilder::selectSource(const QList<ExpressionAst*>& targets, | 1219 | AbstractType::Ptr content = container->contentType().abstractType(); | ||
1246 | const QList<DeclarationBuilder::SourceType>& sources, | 1220 | for ( ; fillWhenLengthMissing != 0; fillWhenLengthMissing-- ) { | ||
1247 | int index, ExpressionAst* rhs) const | 1221 | sources << SourceType{ content, DeclarationPointer(), false }; | ||
1248 | { | | |||
1249 | bool canUnpack = targets.length() == sources.length(); | | |||
1250 | SourceType element; | | |||
1251 | // If the length of the right and the left side matches, exact unpacking can be done. | | |||
1252 | // example code: a, b, c = 3, 4, 5 | | |||
1253 | // If the left side only contains one entry, unpacking never happens, and the left side | | |||
1254 | // is instead assigned a container type if applicable | | |||
1255 | // example code: a = 3, 4, 5 | | |||
1256 | if ( canUnpack ) { | | |||
1257 | element = sources.at(index); | | |||
1258 | } | | |||
1259 | else if ( targets.length() == 1 ) { | | |||
1260 | ExpressionVisitor v(currentContext()); | | |||
1261 | v.visitNode(rhs); | | |||
1262 | element = SourceType{ | | |||
1263 | v.lastType(), | | |||
1264 | DeclarationPointer(Helper::resolveAliasDeclaration(v.lastDeclaration().data())), | | |||
1265 | v.isAlias() | | |||
1266 | }; | | |||
1267 | } | | |||
1268 | else if ( ! sources.isEmpty() ) { | | |||
1269 | // the assignment is of the form "foo, bar, ... = ..." (tuple unpacking) | | |||
1270 | // this one is for the case that the tuple unpacking is not written down explicitly, for example | | |||
1271 | // a = (1, 2, 3); b, c, d = a | | |||
1272 | // the other case (b, c, d = 1, 2, 3) is handled above. | | |||
1273 | if ( const IndexedContainer::Ptr container = sources.first().type.cast<IndexedContainer>() ) { | | |||
1274 | if ( container->typesCount() == targets.length() ) { | | |||
1275 | element.type = container->typeAt(index).abstractType(); | | |||
1276 | element.isAlias = false; | | |||
1277 | } | | |||
1278 | } | 1222 | } | ||
1279 | } | 1223 | } | ||
1280 | if ( ! element.type ) { | 1224 | return sources; | ||
1281 | // use mixed if none of the previous ways of determining the type worked. | | |||
1282 | element.type = AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed)); | | |||
1283 | element.declaration = nullptr; | | |||
1284 | element.isAlias = false; | | |||
1285 | } | | |||
1286 | return element; | | |||
1287 | } | 1225 | } | ||
1288 | 1226 | | |||
1289 | void DeclarationBuilder::assignToName(NameAst* target, const DeclarationBuilder::SourceType& element) | 1227 | void DeclarationBuilder::assignToName(NameAst* target, const DeclarationBuilder::SourceType& element) | ||
Context not available. | |||||
1417 | } | 1355 | } | ||
1418 | } | 1356 | } | ||
1419 | 1357 | | |||
1358 | void DeclarationBuilder::assignToTuple(TupleAst* tuple, const DeclarationBuilder::SourceType& element) { | ||||
1359 | auto sources = unpackAssignmentSource(element, tuple->elements.length()); | ||||
1360 | int ii = 0; | ||||
1361 | bool foundStarred = false; | ||||
1362 | foreach ( ExpressionAst* target, tuple->elements ) { | ||||
1363 | // Fallback, if we ran out of known types. | ||||
1364 | auto source = SourceType{ | ||||
1365 | AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed)), | ||||
1366 | DeclarationPointer(), | ||||
1367 | false | ||||
1368 | }; | ||||
1369 | | ||||
1370 | if ( target->astType == Ast::StarredAstType ) { | ||||
1371 | // PEP-3132. `a, *b, c = 1, 2, 3, 4 -> b = [2, 3]` | ||||
1372 | // Starred expression is assigned a list of the values not used by unstarred ones. | ||||
1373 | DUChainReadLocker lock; | ||||
1374 | auto type = ExpressionVisitor::typeObjectForIntegralType<ListType>("list"); | ||||
1375 | lock.unlock(); | ||||
1376 | if ( !foundStarred ) { // Only allowed once, return unknown list. | ||||
1377 | // Count sources not used by other targets, slurp that many into list. | ||||
1378 | int leftovers = sources.length() - tuple->elements.length() + 1; | ||||
1379 | for ( ; leftovers > 0; leftovers--, ii++ ) { | ||||
1380 | type->addContentType<Python::UnsureType>(sources.at(ii).type); | ||||
1381 | } | ||||
1382 | } | ||||
1383 | source.type = AbstractType::Ptr::staticCast(type); | ||||
1384 | // List is assigned to the child expression. | ||||
1385 | target = static_cast<StarredAst*>(target)->value; | ||||
1386 | foundStarred = true; | ||||
1387 | } | ||||
1388 | else if ( ii < sources.length() ) { | ||||
1389 | source = sources.at(ii); | ||||
1390 | ii++; | ||||
1391 | } | ||||
1392 | assignToUnknown(target, source); | ||||
1393 | } | ||||
1394 | } | ||||
1395 | | ||||
1396 | void DeclarationBuilder::assignToUnknown(ExpressionAst* target, const DeclarationBuilder::SourceType& element) { | ||||
1397 | // Must be a nicer way to do this. | ||||
1398 | if ( target->astType == Ast::TupleAstType ) { | ||||
1399 | // Assignments of the form "a, b = 1, 2" or "a, b = c" | ||||
1400 | assignToTuple(static_cast<TupleAst*>(target), element); | ||||
1401 | } | ||||
1402 | else if ( target->astType == Ast::NameAstType ) { | ||||
1403 | // Assignments of the form "a = 3" | ||||
1404 | assignToName(static_cast<NameAst*>(target), element); | ||||
1405 | } | ||||
1406 | else if ( target->astType == Ast::SubscriptAstType ) { | ||||
1407 | // Assignments of the form "a[0] = 3" | ||||
1408 | assignToSubscript(static_cast<SubscriptAst*>(target), element); | ||||
1409 | } | ||||
1410 | else if ( target->astType == Ast::AttributeAstType ) { | ||||
1411 | // Assignments of the form "a.b = 3" | ||||
1412 | assignToAttribute(static_cast<AttributeAst*>(target), element); | ||||
1413 | } | ||||
1414 | } | ||||
1415 | | ||||
1420 | void DeclarationBuilder::visitAssignment(AssignmentAst* node) | 1416 | void DeclarationBuilder::visitAssignment(AssignmentAst* node) | ||
1421 | { | 1417 | { | ||
1422 | AstDefaultVisitor::visitAssignment(node); | 1418 | AstDefaultVisitor::visitAssignment(node); | ||
1423 | // Because of tuple unpacking, it is required to gather the left- and right hand side | | |||
1424 | // expressions / types first, then match them together in a second step. | | |||
1425 | const QList<ExpressionAst*>& targets = targetsOfAssignment(node->targets); | | |||
1426 | const QList<SourceType>& sources = sourcesOfAssignment(node->value, targets.size() > 1 ? targets.size() : -1); | | |||
1427 | 1419 | | |||
1428 | // Now all the information about left- and right hand side entries is ready, | 1420 | ExpressionVisitor v(currentContext()); | ||
1429 | // and creation / updating of variables can start. | 1421 | v.visitNode(node->value); | ||
1430 | int i = 0; | 1422 | auto sourceType = SourceType{ | ||
1431 | foreach ( ExpressionAst* target, targets ) { | 1423 | v.lastType(), | ||
1432 | SourceType element(selectSource(targets, sources, i, node->value)); | 1424 | DeclarationPointer(Helper::resolveAliasDeclaration(v.lastDeclaration().data())), | ||
1425 | v.isAlias() | ||||
1426 | }; | ||||
1433 | 1427 | | |||
1434 | // Handling the tuple unpacking stuff is done now, and we can proceed as if there was no tuple unpacking involved. | 1428 | foreach(ExpressionAst* target, node->targets) { | ||
1435 | if ( target->astType == Ast::NameAstType ) { | 1429 | assignToUnknown(target, sourceType); | ||
1436 | // Assignments of the form "a = 3" | | |||
1437 | assignToName(static_cast<NameAst*>(target), element); | | |||
1438 | } | | |||
1439 | else if ( target->astType == Ast::SubscriptAstType ) { | | |||
1440 | // Assignments of the form "a[0] = 3" | | |||
1441 | assignToSubscript(static_cast<SubscriptAst*>(target), element); | | |||
1442 | } | | |||
1443 | else if ( target->astType == Ast::AttributeAstType ) { | | |||
1444 | // Assignments of the form "a.b = 3" | | |||
1445 | assignToAttribute(static_cast<AttributeAst*>(target), element); | | |||
1446 | } | | |||
1447 | i += 1; | | |||
1448 | } | 1430 | } | ||
1449 | } | 1431 | } | ||
1450 | 1432 | | |||
Context not available. |