Skip to content

Commit

Permalink
Smart imports + Decorate type expressions + Refactors
Browse files Browse the repository at this point in the history
- Avoid importing types with same name, refer to them with fully qualified name.
- Export arrays correctly, even though Famix does not represent them.
- WIP stub export
  • Loading branch information
Gabriel-Darbord committed Jan 30, 2024
1 parent 796f89d commit 35b5d56
Show file tree
Hide file tree
Showing 20 changed files with 345 additions and 37 deletions.
12 changes: 12 additions & 0 deletions src/Famix-Value-Entities-Extensions/FamixValueOfType.extension.st
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,15 @@ FamixValueOfType >> value: anObject [

self subclassResponsibility
]

{ #category : #'*Famix-Value-Entities-Extensions' }
FamixValueOfType >> varName [
"Basic variable name of a value."

^ self typedEntity
ifNotNil: [ :typedEntity | typedEntity name ]
ifNil: [
attributeInObjects size = 1
ifTrue: [ attributeInObjects first attribute name ]
ifFalse: [ self type baseName uncapitalized ] ]
]
8 changes: 8 additions & 0 deletions src/Famix-Value-Entities/FamixValueOfObjectAttribute.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,11 @@ FamixValueOfObjectAttribute >> value: anObject [
<generated>
value := anObject
]

{ #category : #generate }
FamixValueOfObjectAttribute >> varName [

^ self attribute
ifNotNil: [ :attribute | attribute name ]
ifNil: [ value varName ]
]
21 changes: 21 additions & 0 deletions src/Famix-Value-Entities/FamixValueOfType.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,27 @@ FamixValueOfType >> addValueInDictionary: anObject [
^ self valueInDictionaries add: anObject
]

{ #category : #'ston persistence' }
FamixValueOfType >> asJsonString [
"Currently does not work. Ideas:
- Find a way to serialize any object while handling circular dependencies.
- Use the json stored in the root value to read it into raw objects and traverse the path to this value."

self flag: #TODO.
^ self asNeoJSONObject asString
]

{ #category : #'ston persistence' }
FamixValueOfType >> asNeoJSONObject [

self flag: #TODO. "see #asJsonString"
^ self typedEntity
ifNotNil: [ "at root"
NeoJSONObject fromString: (self cacheAt: #json ifAbsent: '{}') ]
ifNil: [ "how to iterate until root?"
NeoJSONObject fromString: (self cacheAt: #json ifAbsent: '{}') ]
]

{ #category : #accessing }
FamixValueOfType >> attributeInObjects [
"Relation named: #attributeInObjects type: #FamixValueOfObjectAttribute opposite: #value"
Expand Down
6 changes: 6 additions & 0 deletions src/Famix-Value-Entities/FamixValueUnknownType.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ FamixValueUnknownType >> acceptValueVisitor: visitor forObject: object [
self error: 'Exporting an unknown type is not (yet?) supported.'
]

{ #category : #converting }
FamixValueUnknownType >> asFASTJavaTypeExpressionOn: visitor [

^ FASTBuilder current referType: self
]

{ #category : #testing }
FamixValueUnknownType >> isUnknownType [

Expand Down
35 changes: 35 additions & 0 deletions src/Famix-Value-Exporter/FASTBuilder.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Class {
#name : #FASTBuilder,
#superclass : #Object,
#instVars : [
'model'
],
#classVars : [
'Current'
],
#category : #'Famix-Value-Exporter'
}

{ #category : #accessing }
FASTBuilder class >> current [

^ Current ifNil: [ Current := self new ]
]

{ #category : #accessing }
FASTBuilder >> beCurrent [

Current := self
]

{ #category : #accessing }
FASTBuilder >> model [

^ model ifNil: [ model := FASTJavaModel new ]
]

{ #category : #accessing }
FASTBuilder >> model: aFASTModel [

model := aFASTModel
]
97 changes: 97 additions & 0 deletions src/Famix-Value-Exporter/FASTJavaBuilder.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
Class {
#name : #FASTJavaBuilder,
#superclass : #FASTBuilder,
#instVars : [
'imports',
'typeNameDictionary',
'registeredTypes'
],
#category : #'Famix-Value-Exporter'
}

{ #category : #temp }
FASTJavaBuilder >> fullyQualifiedPackageNameFor: aFamixJavaPackage [

^ aFamixJavaPackage parentPackage
ifNil: [ self model newTypeName name: aFamixJavaPackage name ]
ifNotNil: [ :parentPackage |
self model newQualifiedTypeName
name: aFamixJavaPackage name;
namespace: (self fullyQualifiedPackageNameFor: parentPackage) ]
]

{ #category : #temp }
FASTJavaBuilder >> fullyQualifiedTypeNameFor: aFamixJavaType [

^ self model newQualifiedTypeName
name: aFamixJavaType baseName;
namespace:
(self fullyQualifiedPackageNameFor: aFamixJavaType typeContainer)
]

{ #category : #initialization }
FASTJavaBuilder >> initialize [

self reset
]

{ #category : #temp }
FASTJavaBuilder >> makeImportDeclaration: aFamixType [

^ self model newImportDeclaration qualifiedName:
(model newQualifiedName name: aFamixType mooseNameWithDots)
]

{ #category : #temp }
FASTJavaBuilder >> makeImportDeclarations [

^ typeNameDictionary values collect: [ :type |
self makeImportDeclaration: type ]
]

{ #category : #temp }
FASTJavaBuilder >> processType: aFamixType [

| type |
type := aFamixType isParameterizedType
ifTrue: [
aFamixType arguments do: [ :argument |
self processType: argument ].
aFamixType parameterizableClass ]
ifFalse: [ aFamixType ].
type needsJavaImport ifTrue: [ self registerType: type ]
]

{ #category : #temp }
FASTJavaBuilder >> referType: aFamixType [

| registeredType |
self processType: aFamixType.
registeredType := typeNameDictionary
at: aFamixType name
ifAbsent: nil.
^ self model newClassTypeExpression typeName:
((registeredType == aFamixType or: [
aFamixType needsJavaImport not or: [
aFamixType isParameterizedType and: [
registeredType == aFamixType parameterizableClass ] ] ])
ifTrue: [ "has import"
model newTypeName name: aFamixType baseName ]
ifFalse: [ "no import"
self fullyQualifiedTypeNameFor: aFamixType ])
]

{ #category : #temp }
FASTJavaBuilder >> registerType: aFamixType [
"If the type is in the typeNameDict, it will be imported."

registeredTypes add: aFamixType.
typeNameDictionary at: aFamixType name ifAbsentPut: aFamixType
]

{ #category : #initialization }
FASTJavaBuilder >> reset [

typeNameDictionary := Dictionary new.
registeredTypes := IdentitySet new
]
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ FASTJavaVariableExpression >> accessedAttributesOf: aFamixJavaClass [
^ (((method := invoc famixInvocation anyCandidate) parameters
ifNotEmpty: [ method ]
ifEmpty: [ "TODO: investigate why we need to do this"
method invokingMethods anyOneIfOnlyOneElement ]) parameters
at: (invoc arguments indexOf: self)) allAccessedAttributesOf:
| methods |
(methods := method invokingMethods) size = 1 ifFalse: [
self error: 'Only one method expected' ].
methods anyOne ]) parameters at:
(invoc arguments indexOf: self)) allAccessedAttributesOf:
aFamixJavaClass ].
self error: 'TODO: what else can be using the parameter?'.
^ nil
Expand Down
18 changes: 8 additions & 10 deletions src/Famix-Value-Exporter/FamixJavaAttribute.extension.st
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,20 @@ FamixJavaAttribute >> initializerMatchesValues: objectAttributes [
"Assume I have a source and an initializer expression.
Return whether the representations of primitive objects, given as argument, match those of my initializer expression, regardless of order.
For example, if my representation in Java was:
public static MY_ATTRIBUTE = MyClass(1, 'foo');
public static MyClass MY_ATTRIBUTE = new MyClass(1, 'foo');
Then I would match: { 1. 'foo' } or { 'foo'. 1 }"

| found source |
found := objectAttributes copy.
source := self sourceText.
source := source
| toFind source |
toFind := objectAttributes copy.
source := (source := self sourceText)
copyFrom: (source indexOf: $() + 1
to: (source lastIndexOf: $)) - 1.
source splitJavaArguments do: [ :match |
source splitJavaArguments do: [ :argument |
| index |
index := found indexOf: match.
index = 0
(index := toFind indexOf: argument) = 0
ifTrue: [ ^ false ]
ifFalse: [ found removeAt: index ] ].
^ found isEmpty
ifFalse: [ toFind removeAt: index ] ].
^ toFind isEmpty
]

{ #category : #'*Famix-Value-Exporter' }
Expand Down
18 changes: 16 additions & 2 deletions src/Famix-Value-Exporter/FamixJavaType.extension.st
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ FamixJavaType >> acceptValueVisitor: visitor forCollection: collection [
{ #category : #'*Famix-Value-Exporter' }
FamixJavaType >> acceptValueVisitor: visitor forObject: object [

^ visitor visitObjectOfRegularType: object
^ self isStub
ifTrue: [ visitor visitObjectStub: object ]
ifFalse: [ visitor visitObjectOfRegularType: object ]
]

{ #category : #'*Famix-Value-Exporter' }
FamixJavaType >> asFASTJavaTypeExpressionOn: visitor [
"^ visitor makeClassTypeExpression: self typeName"

^ visitor makeClassTypeExpression: self typeName
^ FASTBuilder current referType: self
]

{ #category : #'*Famix-Value-Exporter' }
Expand All @@ -38,6 +41,17 @@ FamixJavaType >> concreteTypeNameOn: stream [
stream nextPutAll: name
]

{ #category : #'*Famix-Value-Exporter' }
FamixJavaType >> decorate: aFamixJavaType asFASTJavaTypeExpressionOn: visitor [
"This method allows for more control by having access to both the static (argument) and dynamic (self) types of a value.
The default behavior handles when the static type is a parameter type, then it uses the dynamic type.
See Famix-Value-Types for special cases."

^ aFamixJavaType isParameterType
ifTrue: [ self asFASTJavaTypeExpressionOn: visitor ]
ifFalse: [ aFamixJavaType asFASTJavaTypeExpressionOn: visitor ]
]

{ #category : #'*Famix-Value-Exporter' }
FamixJavaType >> typeName [
"Includes type arguments, e.g. List<Map<String, Integer>>"
Expand Down
6 changes: 4 additions & 2 deletions src/Famix-Value-Exporter/FamixTClass.extension.st
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ FamixTClass >> constructorsOrderedByScore [
{ #category : #'*Famix-Value-Exporter' }
FamixTClass >> findSetterOf: aFamixAttribute [

^ self allMethods
^ self methods
detect: [ :method |
method isSetterLax and: [
method accesses anySatisfy: [ :access |
access variable == aFamixAttribute ] ] ]
ifNone: nil
ifNone: [
self superclass ifNotNil: [ :superclass |
superclass findSetterOf: aFamixAttribute ] ]
]

{ #category : #'*Famix-Value-Exporter' }
Expand Down
6 changes: 6 additions & 0 deletions src/Famix-Value-Exporter/FamixTParameterizedType.extension.st
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ FamixTParameterizedType >> constructorScore [
^ parameterizableClass constructorScore
]

{ #category : #'*Famix-Value-Exporter' }
FamixTParameterizedType >> findSetterOf: aFamixAttribute [

^ parameterizableClass findSetterOf: aFamixAttribute
]

{ #category : #'*Famix-Value-Exporter' }
FamixTParameterizedType >> publicConstructorsWithMostImpact [

Expand Down
9 changes: 3 additions & 6 deletions src/Famix-Value-Exporter/FamixValue2ASTVisitor.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,9 @@ FamixValue2ASTVisitor >> varNameDict [
{ #category : #naming }
FamixValue2ASTVisitor >> varNameFor: value [

^ self varNameDict at: value ifAbsentPut: [
(value typedEntity ifNotNil: [ value typedEntity name ] ifNil: [
value attributeInObjects size = 1
ifTrue: [ value attributeInObjects first attribute name ]
ifFalse: [ value type baseName uncapitalized ] ])
, self nextId asString ]
^ self varNameDict
at: value
ifAbsentPut: [ value varName , self nextId asString ]
]

{ #category : #visiting }
Expand Down
Loading

0 comments on commit 35b5d56

Please sign in to comment.