From 87a961f0d27ee6b95f282390d451479cb1bb50fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20Chi=C8=99?= Date: Mon, 21 Oct 2024 09:37:25 +0200 Subject: [PATCH] [feenkcom/gtoolkit#4072] Pass on the analysis for extension methods --- .../GtExtensionMethodWrapper.class.st | 34 ++++++++- ...onMethodsBaseImageOverridesReport.class.st | 18 +++++ ...sBaseImageOverridesReportBuilder.class.st} | 73 +++++++++++-------- .../GtExtensionMethodsPackageWrapper.class.st | 48 +++++++++++- .../GtExtensionMethodsProjectBuilder.class.st | 4 +- .../GtExtensionMethodsProjectWrapper.class.st | 29 ++++++++ 6 files changed, 170 insertions(+), 36 deletions(-) create mode 100644 src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsBaseImageOverridesReport.class.st rename src/GToolkit-Utility-ExtensionMethodsAnalysis/{GtExtensionMethodsBaseImageOverridesBuilder.class.st => GtExtensionMethodsBaseImageOverridesReportBuilder.class.st} (62%) diff --git a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodWrapper.class.st b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodWrapper.class.st index 9563442..34d71bd 100644 --- a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodWrapper.class.st +++ b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodWrapper.class.st @@ -3,7 +3,8 @@ Class { #superclass : #Object, #instVars : [ 'currentCompiledMethod', - 'previousSourceCode' + 'previousSourceCode', + 'changeType' ], #category : #'GToolkit-Utility-ExtensionMethodsAnalysis' } @@ -14,6 +15,16 @@ GtExtensionMethodWrapper class >> forCompiledMethod: aCompiledMethod [ currentCompiledMethod: aCompiledMethod ] +{ #category : #accessing } +GtExtensionMethodWrapper >> changeType [ + ^ changeType +] + +{ #category : #accessing } +GtExtensionMethodWrapper >> changeType: aSymbol [ + changeType := aSymbol +] + { #category : #accessing } GtExtensionMethodWrapper >> currentCompiledMethod [ ^ currentCompiledMethod @@ -57,6 +68,27 @@ GtExtensionMethodWrapper >> gtViewTwoPanesDiffFor: aView [ yourself ] +{ #category : #testing } +GtExtensionMethodWrapper >> isNewMethod [ + ^ changeType = #isNewMethod +] + +{ #category : #testing } +GtExtensionMethodWrapper >> isOverrideOrReplace [ + ^ self isOverridingSupperclassMethod or: [ + self isReplacingMethodInClass ] +] + +{ #category : #testing } +GtExtensionMethodWrapper >> isOverridingSupperclassMethod [ + ^ changeType = #isOverridingSupperclassMethod +] + +{ #category : #testing } +GtExtensionMethodWrapper >> isReplacingMethodInClass [ + ^ changeType = #isReplacingMethodInClass +] + { #category : #accessing } GtExtensionMethodWrapper >> methodClass [ ^ currentCompiledMethod methodClass diff --git a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsBaseImageOverridesReport.class.st b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsBaseImageOverridesReport.class.st new file mode 100644 index 0000000..b5ec23a --- /dev/null +++ b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsBaseImageOverridesReport.class.st @@ -0,0 +1,18 @@ +Class { + #name : #GtExtensionMethodsBaseImageOverridesReport, + #superclass : #Object, + #instVars : [ + 'baseImageExtensionMethodsData' + ], + #category : #'GToolkit-Utility-ExtensionMethodsAnalysis' +} + +{ #category : #accessing } +GtExtensionMethodsBaseImageOverridesReport >> baseImageExtensionMethodsData [ + ^ baseImageExtensionMethodsData +] + +{ #category : #accessing } +GtExtensionMethodsBaseImageOverridesReport >> baseImageExtensionMethodsData: anObject [ + baseImageExtensionMethodsData := anObject +] diff --git a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsBaseImageOverridesBuilder.class.st b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsBaseImageOverridesReportBuilder.class.st similarity index 62% rename from src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsBaseImageOverridesBuilder.class.st rename to src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsBaseImageOverridesReportBuilder.class.st index bf63593..33ceca8 100644 --- a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsBaseImageOverridesBuilder.class.st +++ b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsBaseImageOverridesReportBuilder.class.st @@ -6,7 +6,7 @@ To perform this: - it checks if any of those methods replaces or overrides a method in a reference image " Class { - #name : #GtExtensionMethodsBaseImageOverridesBuilder, + #name : #GtExtensionMethodsBaseImageOverridesReportBuilder, #superclass : #Object, #instVars : [ 'imageName', @@ -17,36 +17,34 @@ Class { } { #category : #analysis } -GtExtensionMethodsBaseImageOverridesBuilder class >> forGToolkit [ - ^ self new buildWrapperForGToolkit +GtExtensionMethodsBaseImageOverridesReportBuilder class >> forGToolkit [ + ^ self new buildReportForGToolkit ] { #category : #analysis } -GtExtensionMethodsBaseImageOverridesBuilder >> buildWrapperForComparisonResult: aResult forExtensionMethods: aCollection inProject: aProject [ - | targetMethods | +GtExtensionMethodsBaseImageOverridesReportBuilder >> buildReportForComparisonResult: aResult forExtensionMethods: aCollection inProject: aProject [ aCollection withIndexDo: [ :aMethodWrapper :anIndex | - (aResult at: anIndex) ifNotNil: [ :aSourceCode | - aMethodWrapper previousSourceCode: aSourceCode ] ]. - - targetMethods := aCollection withIndexSelect: [ :aMethodWrapper :anIndex | - (aResult at: anIndex) notNil ]. + aMethodWrapper changeType: (aResult at: anIndex) first. + aMethodWrapper isOverrideOrReplace ifTrue: [ + aMethodWrapper previousSourceCode: (aResult + at: anIndex) second ] ]. ^ GtExtensionMethodsProjectBuilder new - buildProjectWrapperForMethodWrappers: targetMethods + buildProjectWrapperForMethodWrappers: aCollection inProject: aProject ] { #category : #analysis } -GtExtensionMethodsBaseImageOverridesBuilder >> buildWrapperForGToolkit [ - ^ self buildWrapperForProject: BaselineOfGToolkit fullBaselineProject +GtExtensionMethodsBaseImageOverridesReportBuilder >> buildReportForGToolkit [ + ^ self buildReportForProject: BaselineOfGToolkit fullBaselineProject ] { #category : #analysis } -GtExtensionMethodsBaseImageOverridesBuilder >> buildWrapperForProject: aProject [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> buildReportForProject: aProject [ | wrapperProject extensionMethods analysisCode analysisResult | wrapperProject := GtExtensionMethodsProjectBuilder new - buildWrapperForProject: aProject. + buildReportForProject: aProject. extensionMethods := wrapperProject extensionMethods. analysisCode := self detectionCodeForMethods: extensionMethods. @@ -55,13 +53,13 @@ GtExtensionMethodsBaseImageOverridesBuilder >> buildWrapperForProject: aProject analysisResult := self comparisonResultsForAnalysisCode: analysisCode. ^ self - buildWrapperForComparisonResult: analysisResult + buildReportForComparisonResult: analysisResult forExtensionMethods: extensionMethods inProject: aProject ] { #category : #utils } -GtExtensionMethodsBaseImageOverridesBuilder >> comparisonResultsForAnalysisCode: analysisSourceCode [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> comparisonResultsForAnalysisCode: analysisSourceCode [ | command newProcess arguments resultString | command := GtVirtualMachine instance @@ -89,11 +87,11 @@ GtExtensionMethodsBaseImageOverridesBuilder >> comparisonResultsForAnalysisCode: ] { #category : #utils } -GtExtensionMethodsBaseImageOverridesBuilder >> detectionCodeForMethods: aCollection [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> detectionCodeForMethods: aCollection [ | expensionsData | expensionsData := aCollection asArray collect: [ :aMethod | - {aMethod methodClass name . aMethod selector asString } ]. + { aMethod methodClass name . aMethod selector asString } ]. ^ String streamContents: [ :aStream | aStream << '| expensionsData |'; lf. @@ -104,10 +102,10 @@ GtExtensionMethodsBaseImageOverridesBuilder >> detectionCodeForMethods: aCollect isMeta := false. (className endsWith: ' class') ifTrue: [ - className := className withoutSuffix: ' class'. + className := (className withoutSuffix: ' class') asSymbol. isMeta := true ]. (className endsWith: ' classTrait') ifTrue: [ - className := className withoutSuffix: ' classTrait'. + className := (className withoutSuffix: ' classTrait') asSymbol. isMeta := true ]. Smalltalk globals @@ -119,15 +117,26 @@ GtExtensionMethodsBaseImageOverridesBuilder >> detectionCodeForMethods: aCollect targetClass := aClass classSide ]. targetClass classAndMethodFor: array second asSymbol - do: [ :c :m | m sourceCode ] - ifAbsent: [ nil ] ] - ifAbsent: [ nil ] ] + do: [ :methodClas :foundMethod | + targetClass = methodClas + ifTrue: [ + { + #isReplacingMethodInClass. + foundMethod sourceCode + }] + ifFalse: [ + { + #isOverridingSupperclassMethod. + foundMethod sourceCode + } ] ] + ifAbsent: [ {#isNewMethod} ] ] + ifAbsent: [ {#isMissingClass} ] ] ] sourceNode sourceCode). aStream << ' value: expensionsData' ] ] { #category : #utils } -GtExtensionMethodsBaseImageOverridesBuilder >> ensureImageDownloaded [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> ensureImageDownloaded [ | targetFolder | targetFolder := self targetFolder. (targetFolder / self imageName) exists @@ -143,39 +152,39 @@ GtExtensionMethodsBaseImageOverridesBuilder >> ensureImageDownloaded [ ] { #category : #accessing } -GtExtensionMethodsBaseImageOverridesBuilder >> imageArchiveName [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> imageArchiveName [ ^ imageArchiveName ifNil: [ 'Pharo10-SNAPSHOT.build.521.sha.14f5413.arch.64bit.zip' ] ] { #category : #accessing } -GtExtensionMethodsBaseImageOverridesBuilder >> imageArchiveName: anArchiveName [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> imageArchiveName: anArchiveName [ imageArchiveName := anArchiveName ] { #category : #accessing } -GtExtensionMethodsBaseImageOverridesBuilder >> imageName [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> imageName [ ^ imageName ifNil: [ 'Pharo10-SNAPSHOT-64bit-14f5413.image' ] ] { #category : #accessing } -GtExtensionMethodsBaseImageOverridesBuilder >> imageName: anImageName [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> imageName: anImageName [ imageName := anImageName ] { #category : #accessing } -GtExtensionMethodsBaseImageOverridesBuilder >> imageUrl [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> imageUrl [ ^ imageUrl ifNil: [ 'https://dl.feenk.com/pharo/', self imageArchiveName ] ] { #category : #accessing } -GtExtensionMethodsBaseImageOverridesBuilder >> imageUrl: anUrlString [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> imageUrl: anUrlString [ imageUrl := anUrlString ] { #category : #accessing } -GtExtensionMethodsBaseImageOverridesBuilder >> targetFolder [ +GtExtensionMethodsBaseImageOverridesReportBuilder >> targetFolder [ ^ FileLocator localDirectory / 'analysis-extension-methods' ] diff --git a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsPackageWrapper.class.st b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsPackageWrapper.class.st index ba8539f..9473d86 100644 --- a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsPackageWrapper.class.st +++ b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsPackageWrapper.class.st @@ -32,18 +32,33 @@ GtExtensionMethodsPackageWrapper >> extensionsDescription [ << ('extension method' asPluralBasedOn: self numberOfExtensions) ] ] +{ #category : #accessing } +GtExtensionMethodsPackageWrapper >> groupByMethodChangeType [ + | extensionMethodsGroup | + extensionMethodsGroup := self extensionMethods + groupedBy: [ :each | each changeType ]. + + ^ extensionMethodsGroup +] + { #category : #'accessing - grouping' } GtExtensionMethodsPackageWrapper >> groupedByClass [ ^ self extensionMethods groupedBy: [ :aMethod | aMethod methodClass ] ] +{ #category : #'accessing - grouping' } +GtExtensionMethodsPackageWrapper >> groupedByExtendedClassPackage [ + ^ self extensionMethods groupedBy: [ :aMethod | + aMethod methodClass package ] +] + { #category : #'gt - extensions' } GtExtensionMethodsPackageWrapper >> gtViewExtensionMethodsByClassFor: aView [ ^ aView columnedList - title: 'By class'; + title: 'By extended class'; priority: 45; items: [ self groupedByClass associations sorted: [ :assoc | assoc value size ] descending ]; @@ -52,6 +67,20 @@ GtExtensionMethodsPackageWrapper >> gtViewExtensionMethodsByClassFor: aView [ send: [ :assoc | assoc value ] ] +{ #category : #'gt - extensions' } +GtExtensionMethodsPackageWrapper >> gtViewExtensionMethodsByExtendedClassPackageFor: aView [ + + + ^ aView columnedList + title: 'By extended class package'; + priority: 46; + items: [ self groupedByExtendedClassPackage associations + sorted: [ :assoc | assoc value size ] descending ]; + column: 'Package' text: [ :assoc | assoc key ]; + column: 'Number of Extension Methods' text: [ :assoc | assoc value size ]; + send: [ :assoc | assoc value ] +] + { #category : #'gt - extensions' } GtExtensionMethodsPackageWrapper >> gtViewExtensionMethodsFor: aView [ @@ -65,6 +94,23 @@ GtExtensionMethodsPackageWrapper >> gtViewExtensionMethodsFor: aView [ column: 'Package' text: [ :aMethod | aMethod package name ] ] +{ #category : #'gt - extensions' } +GtExtensionMethodsPackageWrapper >> gtViewGroupsByChangeTypeFor: aView [ + + + ^ aView columnedList + title: 'By change type'; + priority: 49; + items: [ + self groupByMethodChangeType associations ]; + column: 'Change type' text: [ :assoc | + assoc key capitalized "piecesCutWhereCamelCase asCommaString" ]; + column: 'Number of methods' text: [ :assoc | + assoc value size ]; + send: [ :assoc | + assoc value ] +] + { #category : #testing } GtExtensionMethodsPackageWrapper >> hasExtensionMethods [ ^ self numberOfExtensions > 0 diff --git a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsProjectBuilder.class.st b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsProjectBuilder.class.st index 5af97bd..fd4a3aa 100644 --- a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsProjectBuilder.class.st +++ b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsProjectBuilder.class.st @@ -21,7 +21,7 @@ GtExtensionMethodsProjectBuilder class >> forGToolkit [ ^ self new - buildWrapperForProject: BaselineOfGToolkit fullBaselineProject + buildReportForProject: BaselineOfGToolkit fullBaselineProject ] { #category : #analysis } @@ -65,7 +65,7 @@ GtExtensionMethodsProjectBuilder >> buildProjectWrapperForMethods: aCollection i ] { #category : #analysis } -GtExtensionMethodsProjectBuilder >> buildWrapperForProject: aProject [ +GtExtensionMethodsProjectBuilder >> buildReportForProject: aProject [ | systemExtensions | systemExtensions := self extensionsToSystemClassesForProject: aProject. diff --git a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsProjectWrapper.class.st b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsProjectWrapper.class.st index 52dcac8..c874cd2 100644 --- a/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsProjectWrapper.class.st +++ b/src/GToolkit-Utility-ExtensionMethodsAnalysis/GtExtensionMethodsProjectWrapper.class.st @@ -19,6 +19,18 @@ GtExtensionMethodsProjectWrapper >> extensionMethods [ aPackage extensionMethods ] ] +{ #category : #'accessing - grouping' } +GtExtensionMethodsProjectWrapper >> groupByMethodChangeType [ + | extensionMethodsGroup | + extensionMethodsGroup := self extensionMethods + groupedBy: [ :each | each changeType ]. + + ^ extensionMethodsGroup collect: [ :aGroup | + GtExtensionMethodsProjectBuilder new + buildProjectWrapperForMethodWrappers: aGroup + inProject: self project ] +] + { #category : #'gt - extensions' } GtExtensionMethodsProjectWrapper >> gtViewExtensionMethodsFor: aView [ @@ -31,6 +43,23 @@ GtExtensionMethodsProjectWrapper >> gtViewExtensionMethodsFor: aView [ column: 'Package' text: [ :aMethod | aMethod package name ] ] +{ #category : #'gt - extensions' } +GtExtensionMethodsProjectWrapper >> gtViewGroupsByChangeTypeFor: aView [ + + + ^ aView columnedList + title: 'Extension Methods (by change type)'; + priority: 55; + items: [ + self groupByMethodChangeType associations ]; + column: 'Change type' text: [ :assoc | + assoc key capitalized "piecesCutWhereCamelCase asCommaString" ]; + column: 'Number of methods' text: [ :assoc | + assoc value numberOfExtensions ]; + send: [ :assoc | + assoc value ] +] + { #category : #'gt - extensions' } GtExtensionMethodsProjectWrapper >> gtViewPackageWrappersFor: aView [