diff --git a/src/Famix-Python-Entities/FamixPythonImport.class.st b/src/Famix-Python-Entities/FamixPythonImport.class.st index f624d1f..173f003 100644 --- a/src/Famix-Python-Entities/FamixPythonImport.class.st +++ b/src/Famix-Python-Entities/FamixPythonImport.class.st @@ -80,6 +80,12 @@ FamixPythonImport >> displayStringOn: aStream [ aStream nextPutAll: ')' ] +{ #category : 'testing' } +FamixPythonImport >> hasAlias [ + + ^ alias isNotNil +] + { #category : 'accessing' } FamixPythonImport >> isFromImport [ diff --git a/src/Famix-Python-Importer-Tests/FamixPythonProject1Test.class.st b/src/Famix-Python-Importer-Tests/FamixPythonProject1Test.class.st index abfbe20..3426de5 100644 --- a/src/Famix-Python-Importer-Tests/FamixPythonProject1Test.class.st +++ b/src/Famix-Python-Importer-Tests/FamixPythonProject1Test.class.st @@ -2210,6 +2210,51 @@ FamixPythonProject1Test >> testReadAccessFromImportedGlobalWithNamespace [ self assert: (module accesses anySatisfy: [ :anAccess | anAccess variable = global ]) ] +{ #category : 'tests - accesses' } +FamixPythonProject1Test >> testReadAccessFromImportedGlobalWithNamespaceAlias [ + + | global module access | + global := self globalVariableNamed: 'subSubPackage1Variable'. + module := self moduleNamed: 'moduleWithImportsAndAliases'. + + access := global incomingAccesses detect: [ :anAccess | anAccess accessor = module ]. + + self assert: access class equals: FamixPythonAccess. + self assert: access source equals: module. + self assert: access accessor equals: module. + self assert: access target equals: global. + self assert: access variable equals: global. + self deny: access isWrite. + self assert: access isRead. + self assert: (module accesses anySatisfy: [ :anAccess | anAccess variable = global ]) +] + +{ #category : 'tests - accesses' } +FamixPythonProject1Test >> testReadAccessFromImportedGlobalWithNamespaceAliasSourceAnchor [ + + | global module access | + global := self globalVariableNamed: 'subSubPackage1Variable'. + module := self moduleNamed: 'moduleWithImportsAndAliases'. + + access := global incomingAccesses detect: [ :anAccess | anAccess accessor = module ]. + + self assert: access sourceAnchor isNotNil. + self assert: access sourceText equals: 'rss.subSubPackage1Variable' +] + +{ #category : 'tests - accesses' } +FamixPythonProject1Test >> testReadAccessFromImportedGlobalWithNamespaceSourceAnchor [ + + | global module access | + global := self globalVariableNamed: 'rootPackage2Variable'. + module := self moduleNamed: 'moduleAtRoot'. + + access := global incomingAccesses detect: [ :anAccess | anAccess accessor = module ]. + + self assert: access sourceAnchor isNotNil. + self assert: access sourceText equals: 'root2.rootPackage2Variable' +] + { #category : 'tests - accesses' } FamixPythonProject1Test >> testReadAccessFromLambda [ diff --git a/src/Famix-Python-Importer/FamixPythonImporterVisitor.class.st b/src/Famix-Python-Importer/FamixPythonImporterVisitor.class.st index 54f0b1d..61d40f3 100644 --- a/src/Famix-Python-Importer/FamixPythonImporterVisitor.class.st +++ b/src/Famix-Python-Importer/FamixPythonImporterVisitor.class.st @@ -741,16 +741,25 @@ FamixPythonImporterVisitor >> visitClassDefinition: aClassDef [ { #category : 'generated' } FamixPythonImporterVisitor >> visitFieldAccessExpression: aFieldAccessExpression [ + | source | + source := aFieldAccessExpression source. + self flag: #todo. "Manage invocations." - (aFieldAccessExpression parent isFunctionCallExpression and: [ aFieldAccessExpression parent receiver = aFieldAccessExpression ]) ifTrue: [ - ^ aFieldAccessExpression source ]. + aFieldAccessExpression isReceiverOfFunctionCall ifTrue: [ ^ source ]. - (self currentEntity withAllParents flatCollect: [ :entity | (entity query outgoing local dependenciesOfType: FamixPythonImport) reject: #isFromImport ]) + "Symbol resolution of accesses and references to imported entities. + Example: + + import moduleAtRoot + print(moduleAtRoot.moduleVariable) + " + self currentEntity allEffectiveSimpleImports detect: [ :import | | importPath | - importPath := import importPath , '.'. - - (aFieldAccessExpression source beginsWith: importPath) and: [ ((aFieldAccessExpression source withoutPrefix: importPath) includes: $.) not ] ] + importPath := (import hasAlias + ifTrue: [ import alias ] + ifFalse: [ import importPath ]) , '.'. + (source beginsWith: importPath) and: [ ((source withoutPrefix: importPath) includes: $.) not ] ] ifFound: [ :import | self resolve: ((FamixPythonImportedAccessOrReferenceResolvable identifier: aFieldAccessExpression name import: import) @@ -760,11 +769,11 @@ FamixPythonImporterVisitor >> visitFieldAccessExpression: aFieldAccessExpression | association | association := entity createAccessOrReferenceFrom: currentEntity node: aFieldAccessExpression. self setSourceAnchor: association from: aFieldAccessExpression ]. - ^ aFieldAccessExpression source ]. + ^ source ]. + + aFieldAccessExpression source traceCr. - " aFieldAccessExpression source traceCr. -" - ^ aFieldAccessExpression source + ^ source ] { #category : 'visiting' } diff --git a/src/Famix-Python-Importer/PyFieldAccessExpressionNode.extension.st b/src/Famix-Python-Importer/PyFieldAccessExpressionNode.extension.st index c51be21..311ef44 100644 --- a/src/Famix-Python-Importer/PyFieldAccessExpressionNode.extension.st +++ b/src/Famix-Python-Importer/PyFieldAccessExpressionNode.extension.st @@ -16,6 +16,12 @@ PyFieldAccessExpressionNode >> isInternalInstanceVariableAccess [ ^ self receiver isSelf ] +{ #category : '*Famix-Python-Importer' } +PyFieldAccessExpressionNode >> isReceiverOfFunctionCall [ + + ^ self parent isFunctionCallExpression and: [ self parent receiver = self ] +] + { #category : '*Famix-Python-Importer' } PyFieldAccessExpressionNode >> name [ ^ self nameToken value diff --git a/src/Famix-Python-Importer/TEntityMetaLevelDependency.extension.st b/src/Famix-Python-Importer/TEntityMetaLevelDependency.extension.st new file mode 100644 index 0000000..ccece5a --- /dev/null +++ b/src/Famix-Python-Importer/TEntityMetaLevelDependency.extension.st @@ -0,0 +1,8 @@ +Extension { #name : 'TEntityMetaLevelDependency' } + +{ #category : '*Famix-Python-Importer' } +TEntityMetaLevelDependency >> allEffectiveSimpleImports [ + "Return all the imports effective in this entity, but not from imponts." + + ^ self withAllParents flatCollect: [ :entity | (entity query outgoing local dependenciesOfType: FamixPythonImport) reject: #isFromImport ] +]