@@ -2,11 +2,11 @@ package com.github.danielwegener.intellij.cucumber.scala
22
33import java .util .{Collection => JavaCollection }
44
5+ import com .github .danielwegener .intellij .cucumber .scala .CucumberScalaExtension .JavaList
56import com .github .danielwegener .intellij .cucumber .scala .steps .ScalaStepDefinition
67import com .intellij .openapi .diagnostic .Logger
78import com .intellij .openapi .module .{Module , ModuleUtilCore }
89import com .intellij .openapi .project .Project
9- import com .intellij .psi .search .GlobalSearchScope
1010import com .intellij .psi .{JavaPsiFacade , PsiElement , PsiFile }
1111import org .jetbrains .annotations .NotNull
1212import org .jetbrains .plugins .cucumber .psi .GherkinFile
@@ -25,20 +25,21 @@ import scala.util.Try
2525
2626object CucumberScalaExtension {
2727 val LOG : Logger = Logger .getInstance(classOf [CucumberScalaExtension ])
28+
29+ type JavaList [T ] = java.util.List [T ]
2830}
2931
3032class CucumberScalaExtension extends AbstractCucumberExtension {
31-
32- val CUCUMBER_RUNTIME_SCALA_STEP_DEF_TRAIT = " cucumber.api.scala.ScalaDsl"
33+ private final val CUCUMBER_RUNTIME_SCALA_STEP_DEF_TRAIT = " cucumber.api.scala.ScalaDsl"
3334
3435 override def isStepLikeFile (@ NotNull child : PsiElement , @ NotNull parent : PsiElement ): Boolean = {
3536 child.isInstanceOf [ScalaFile ]
3637 }
3738
3839 override def isWritableStepLikeFile (@ NotNull child : PsiElement , @ NotNull parent : PsiElement ): Boolean = {
39-
4040 child match {
41- case scalaFile : ScalaFile if Option (scalaFile.getContainingFile).map(_.getVirtualFile).exists(_.isWritable) => true
41+ case scalaFile : ScalaFile =>
42+ Option (scalaFile.getContainingFile).map(_.getVirtualFile).exists(_.isWritable)
4243 case _ => false
4344 }
4445 }
@@ -47,59 +48,69 @@ class CucumberScalaExtension extends AbstractCucumberExtension {
4748 override val getStepFileType : BDDFrameworkType = new BDDFrameworkType (ScalaFileType .INSTANCE )
4849
4950 @ NotNull
50- override def getStepDefinitionCreator : StepDefinitionCreator = throw new UnsupportedOperationException ( " You cannot automatically create Steps yet. " )
51-
52- override def loadStepsFor ( featureFile : PsiFile , module : Module ) : java.util. List [ AbstractStepDefinition ] = {
51+ override def getStepDefinitionCreator : StepDefinitionCreator = {
52+ throw new UnsupportedOperationException ( " You cannot automatically create Steps yet. " )
53+ }
5354
54- val dependenciesScope : GlobalSearchScope = module.getModuleWithDependenciesAndLibrariesScope( true )
55+ override def loadStepsFor ( featureFile : PsiFile , module : Module ) : JavaList [ AbstractStepDefinition ] = {
5556 val project : Project = featureFile.getProject
5657
57- val stepDefs = for {
58- cucumberDslClass <- JavaPsiFacade .getInstance(project).findClasses(CUCUMBER_RUNTIME_SCALA_STEP_DEF_TRAIT , dependenciesScope)
59- scalaDslInheritingClass <- psi.stubs.util.ScalaInheritors .withStableScalaInheritors(cucumberDslClass).collect { case sc : ScClass => sc; case sct : ScTrait => sct }
60- glueCodeClass <- classAndItsInheritors(scalaDslInheritingClass, dependenciesScope)
58+ val stepDefinitions = for {
59+ glueCodeClass <- findGlueCodeClass(module, project)
6160 scConstructorBody <- glueCodeClass.extendsBlock.templateBody.toSeq
6261 outerMethodCall <- scConstructorBody.getChildren.collect { case mc : ScMethodCall => mc }
63- } yield new ScalaStepDefinition (outerMethodCall)
64-
65- JavaConverters .seqAsJavaList(stepDefs)
66-
67- }
68-
69- def classAndItsInheritors (parentOfHierarchy : ScTypeDefinition , scope : GlobalSearchScope ): Iterable [ScTypeDefinition ] = {
70-
71- @ tailrec
72- def rec (queue : List [ScTypeDefinition ], akku : Set [ScTypeDefinition ]): Set [ScTypeDefinition ] = {
73- queue match {
74- case Nil => akku
75- case a =>
76- val newChildren = ScalaInheritors .findInheritorObjects(a.head)
77- .collect { case sc : ScClass => sc; case sct : ScTrait => sct }
78- .filterNot(akku.contains _)
79- rec(a.tail ::: newChildren.toList, akku + a.head)
80-
81- }
82-
83- }
62+ } yield ScalaStepDefinition (outerMethodCall)
8463
85- rec( List (parentOfHierarchy), Set .empty )
64+ JavaConverters .seqAsJavaList(stepDefinitions )
8665 }
8766
8867 override def getStepDefinitionContainers (featureFile : GherkinFile ): JavaCollection [_ <: PsiFile ] = {
8968 val project : Project = featureFile.getProject
9069 val maybeModule = Option (ModuleUtilCore .findModuleForPsiElement(featureFile))
9170
92- val stepDefs = for {
71+ val stepFiles = for {
9372 module <- maybeModule.toSeq
94- searchScope = module.getModuleContentScope
95- globalSearchScope = module.getModuleWithDependenciesAndLibrariesScope(true )
96- cucumberDslClass <- JavaPsiFacade .getInstance(project).findClasses(CUCUMBER_RUNTIME_SCALA_STEP_DEF_TRAIT , globalSearchScope).toSeq
97- scalaDslInheritingClass@ (some : ScClass ) <- psi.stubs.util.ScalaInheritors .withStableScalaInheritors(cucumberDslClass)
98- glueCodeClass <- classAndItsInheritors(scalaDslInheritingClass, searchScope)
73+ glueCodeClass <- findGlueCodeClass(module, project)
9974 containingFile <- Try (glueCodeClass.getContainingFile).toOption
10075 } yield containingFile
10176
102- JavaConverters .seqAsJavaList(stepDefs)
77+ JavaConverters .seqAsJavaList(stepFiles)
78+ }
79+
80+
81+ private def findGlueCodeClass (module : Module , project : Project ) = {
82+ val dependencies = module.getModuleWithDependenciesAndLibrariesScope(true )
83+ val psiFacade = JavaPsiFacade .getInstance(project)
84+
85+ for {
86+ cucumberDslClass <- psiFacade.findClasses(CUCUMBER_RUNTIME_SCALA_STEP_DEF_TRAIT , dependencies).toSeq
87+ scalaDslInheritingClass@ (some : ScClass ) <- psi.stubs.util.ScalaInheritors .withStableScalaInheritors(cucumberDslClass)
88+ glueCodeClass <- classAndItsInheritors(scalaDslInheritingClass)
89+ } yield glueCodeClass
10390 }
10491
92+ private def classAndItsInheritors (parent : ScTypeDefinition ): Iterable [ScTypeDefinition ] = {
93+
94+ @ tailrec
95+ def rec (queue : Seq [ScTypeDefinition ], accumulator : Set [ScTypeDefinition ]): Set [ScTypeDefinition ] = {
96+ queue match {
97+ case Seq () => accumulator
98+ case queueHead +: queueTail =>
99+
100+ val newChildren = ScalaInheritors .findInheritorObjects(queueHead).collect {
101+ case sc : ScClass => sc
102+ case sct : ScTrait => sct
103+ }
104+
105+ val childrenToExplore = newChildren
106+ .map(_.asInstanceOf [ScTypeDefinition ])
107+ .diff(accumulator)
108+ .toSeq
109+
110+ rec(queueTail ++ childrenToExplore, accumulator + queueHead)
111+ }
112+ }
113+
114+ rec(Seq (parent), Set .empty)
115+ }
105116}
0 commit comments