Skip to content

Commit

Permalink
Manage comments that are right before an entity
Browse files Browse the repository at this point in the history
  • Loading branch information
jecisc committed Feb 13, 2025
1 parent 2f69160 commit 1947c92
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 18 deletions.
9 changes: 7 additions & 2 deletions src/Famix-Python-Entities/FamixPythonGlobalVariable.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
|---|
| `parentScope` | `FamixTGlobalVariable` | `globalVariables` | `FamixTWithGlobalVariables` | Scope declaring the global variable. belongsTo implementation|
### Children
| Relation | Origin | Opposite | Type | Comment |
|---|
| `comments` | `FamixTWithComments` | `commentedEntity` | `FamixTComment` | List of comments for the entity|
### Incoming dependencies
| Relation | Origin | Opposite | Type | Comment |
|---|
Expand Down Expand Up @@ -35,8 +40,8 @@
Class {
#name : 'FamixPythonGlobalVariable',
#superclass : 'FamixPythonNamedEntity',
#traits : 'FamixTGlobalVariable + FamixTImportable + FamixTInvocationsReceiver + FamixTShadowable + FamixTShadower',
#classTraits : 'FamixTGlobalVariable classTrait + FamixTImportable classTrait + FamixTInvocationsReceiver classTrait + FamixTShadowable classTrait + FamixTShadower classTrait',
#traits : 'FamixTGlobalVariable + FamixTImportable + FamixTInvocationsReceiver + FamixTShadowable + FamixTShadower + FamixTWithComments',
#classTraits : 'FamixTGlobalVariable classTrait + FamixTImportable classTrait + FamixTInvocationsReceiver classTrait + FamixTShadowable classTrait + FamixTShadower classTrait + FamixTWithComments classTrait',
#category : 'Famix-Python-Entities-Entities',
#package : 'Famix-Python-Entities',
#tag : 'Entities'
Expand Down
1 change: 1 addition & 0 deletions src/Famix-Python-Generator/FamixPythonGenerator.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ FamixPythonGenerator >> defineHierarchy [
globalVariable --|> #TImportable.
globalVariable --|> #TShadowable.
globalVariable --|> #TShadower.
globalVariable --|> #TWithComments.

implicitVariable --|> namedEntity.
implicitVariable --|> #TImplicitVariable.
Expand Down
52 changes: 52 additions & 0 deletions src/Famix-Python-Importer-Tests/FamixPythonProject1Test.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,58 @@ FamixPythonProject1Test >> testClassesWithSameNameButDifferentParents [
(self packageNamed: 'subpackage1') }
]

{ #category : 'tests - comments' }
FamixPythonProject1Test >> testCommentBeforeClass [

| comment |
comment := self model allComments detect: [ :aComment |
aComment sourceText beginsWith: '# Comment before class' ].

self assert: comment class equals: FamixPythonComment.
self assert: comment commentedEntity equals: (self classNamed: 'Student')
]

{ #category : 'tests - comments' }
FamixPythonProject1Test >> testCommentBeforeFunction [

| comment |
comment := self model allComments detect: [ :aComment |
aComment sourceText beginsWith: '# Comment before function' ].

self assert: comment class equals: FamixPythonComment.
self assert: comment commentedEntity equals: (self functionNamed: 'function_with_comment_before')
]

{ #category : 'tests - comments' }
FamixPythonProject1Test >> testCommentBeforeGlobale [

| comment |
comment := self model allComments detect: [ :aComment | aComment sourceText beginsWith: '# Comment before global' ].

self assert: comment class equals: FamixPythonComment.
self assert: comment commentedEntity equals: (self globalVariableNamed: 'globalInModuleAtRoot2')
]

{ #category : 'tests - comments' }
FamixPythonProject1Test >> testCommentBeforeIVar [

| comment |
comment := self model allComments detect: [ :aComment | aComment sourceText beginsWith: '# Comment before ivar' ].

self assert: comment class equals: FamixPythonComment.
self assert: comment commentedEntity equals:((self classNamed: 'Person') attributes detect: [ :attribute | attribute name = 'name' ])
]

{ #category : 'tests - comments' }
FamixPythonProject1Test >> testCommentBeforeMethod [

| comment |
comment := self model allComments detect: [ :aComment | aComment sourceText beginsWith: '# Comment before method' ].

self assert: comment class equals: FamixPythonComment.
self assert: comment commentedEntity equals: (self methodNamed: 'set_name')
]

{ #category : 'tests - comments' }
FamixPythonProject1Test >> testCommentInClass [

Expand Down
54 changes: 38 additions & 16 deletions src/Famix-Python-Importer/FamixPythonImporterVisitor.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,45 @@ FamixPythonImporterVisitor >> createClass: classDefinitionNode [
^ self setSourceAnchor: class from: classDefinitionNode
]

{ #category : 'visiting' }
{ #category : 'comments' }
FamixPythonImporterVisitor >> createCommentFromInterval: commentInterval node: aFileNode entitiesInFile: entitiesInFile [

"Before checking if the comment is inside an entity, we check that it is not right before the declaration of an entity.
For that we check with the entity the closest after the comment"
((entitiesInFile select: [ :entity | entity sourceAnchor startPos > commentInterval second ]) detectMin: [ :entity | entity sourceAnchor startPos ]) ifNotNil: [
:entity |
(aFileNode hasOnlySpacesAndTabsBetween: commentInterval second + 1 and: entity sourceAnchor startPos - 1) ifTrue: [
| comment |
comment := self model newComment.
comment commentedEntity: entity.
self
setSourceAnchorTo: comment
fileName: (self relativeFilePath: aFileNode)
start: commentInterval first
end: commentInterval last.
^ comment ] ].


^ entitiesInFile
detect: [ :entity | entity sourceAnchor includesInterval: commentInterval ]
ifFound: [ :commentedEntity |
| comment |
comment := self model newComment.
comment commentedEntity: commentedEntity.
self
setSourceAnchorTo: comment
fileName: (self relativeFilePath: aFileNode)
start: commentInterval first
end: commentInterval last ]
ifNone: [ self error: 'All comments should be at least in the top module/package.' ]
]

{ #category : 'comments' }
FamixPythonImporterVisitor >> createCommentsFor: aFileNode [
"Comments are not represented by nodes in SmaCC. A FileNode can return the intervals of the comments so we need to find to whose entity those comments are attached to."

self flag: #todo. "Reify as class"
self flag: #todo. "Remove duplication of comment creation"
aFileNode comments ifNotEmpty: [ :commentIntervals |
| entitiesInFile intervals |
"Sorting by the number of characters allows us to have the most atomic entities first. Imagine we have an inner function in a function. If a comment is an the inner function, it is also in the function containing it. So we want to check the inner function first because it's the most inner entity that should have the comment attached."
Expand All @@ -85,25 +120,12 @@ FamixPythonImporterVisitor >> createCommentsFor: aFileNode [
intervals := OrderedCollection new.
commentIntervals do: [ :interval |
intervals ifEmpty: [ intervals add: interval ] ifNotEmpty: [ "We can merge if we have only spaces and tabs between the comments."
((aFileNode sourceFrom: intervals last second + 1 to: interval first - 1) allSatisfy: [ :character |
character isSpaceSeparator or: [ character = Character tab ] ])
(aFileNode hasOnlySpacesAndTabsBetween: intervals last second + 1 and: interval first - 1)
ifTrue: [ intervals last at: 2 put: interval second ]
ifFalse: [ intervals add: interval ] ] ].
intervals collect: [ :i | aFileNode sourceFrom: i first to: i second ].

intervals do: [ :commentInterval |
entitiesInFile
detect: [ :entity | entity sourceAnchor includesInterval: commentInterval ]
ifFound: [ :commentedEntity |
| comment |
comment := self model newComment.
comment commentedEntity: commentedEntity.
self
setSourceAnchorTo: comment
fileName: (self relativeFilePath: aFileNode)
start: commentInterval first
end: commentInterval last ]
ifNone: [ self error: 'All comments should be at least in the top module/package.' ] ] ]
intervals do: [ :commentInterval | self createCommentFromInterval: commentInterval node: aFileNode entitiesInFile: entitiesInFile ] ]
]

{ #category : 'private-entity-creation' }
Expand Down
6 changes: 6 additions & 0 deletions src/Famix-Python-Importer/PyFileNode.extension.st
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
Extension { #name : 'PyFileNode' }

{ #category : '*Famix-Python-Importer' }
PyFileNode >> hasOnlySpacesAndTabsBetween: start and: end [

^ (self sourceFrom: start to: end) allSatisfy: [ :character | character isSpaceSeparator or: [ character = Character tab ] ]
]

{ #category : '*Famix-Python-Importer' }
PyFileNode >> packageName [
"If we have a __init__.py file, the package name should be the name of the parent folder"
Expand Down

0 comments on commit 1947c92

Please sign in to comment.