Skip to content

Commit fadeb69

Browse files
author
Jedd Haberstro
committed
Fixed action hyperlinking in route files when route definition starts with '@'.
Changed action's regular expressions to account for optional starting '@' character. When searching for the method, if there does not exist a matching method on a module that matches the route action type name, then do a corresponding search for the method over classes. Fix #119
1 parent bb5a48c commit fadeb69

File tree

4 files changed

+137
-36
lines changed

4 files changed

+137
-36
lines changed

org.scala-ide.play2.tests/src/org/scalaide/play2/routeeditor/hyperlink/RouteHyperlinkDetectorTest.scala

+103-33
Original file line numberDiff line numberDiff line change
@@ -44,166 +44,236 @@ class RouteHyperlinkDetectorTest extends RouteTest {
4444

4545
@Test
4646
def scalaControllerNoParameterAction() {
47-
testWithAnswer("""GET / controllers.ScalaA@pplication.intro""", "controllers.ScalaApplication.intro")
47+
testWithAnswer("""GET / controllers.ScalaA~pplication.intro""", "controllers.ScalaApplication.intro")
4848
}
4949

5050
@Test
5151
def scalaControllerNoParameterAction2() {
52-
testWithAnswer("""GET / controllers.ScalaApplication@.withEmptyParams""", "controllers.ScalaApplication.withEmptyParams()")
52+
testWithAnswer("""GET / controllers.ScalaApplication~.withEmptyParams""", "controllers.ScalaApplication.withEmptyParams()")
5353
}
5454

5555
@Test
5656
def scalaControllerEmptyParametersAction() {
57-
testWithAnswer("""GET / controllers.ScalaA@pplication.intro()""", "controllers.ScalaApplication.intro")
57+
testWithAnswer("""GET / controllers.ScalaA~pplication.intro()""", "controllers.ScalaApplication.intro")
5858
}
5959

6060
@Test
6161
def scalaControllerEmptyParametersAction2() {
62-
testWithAnswer("""GET / controllers.ScalaApplication@.withEmptyParams()""", "controllers.ScalaApplication.withEmptyParams()")
62+
testWithAnswer("""GET / controllers.ScalaApplication~.withEmptyParams()""", "controllers.ScalaApplication.withEmptyParams()")
6363
}
6464

6565
@Test
6666
def scalaControllerIntAction() {
67-
testWithAnswer("""GET /:a controllers.ScalaApplicati@on.pInt(a: Int)""", "controllers.ScalaApplication.pInt(Int)")
67+
testWithAnswer("""GET /:a controllers.ScalaApplicati~on.pInt(a: Int)""", "controllers.ScalaApplication.pInt(Int)")
6868
}
6969

7070
@Test
7171
def scalaControllerStringAction() {
72-
testWithAnswer("""GET /:a controllers.ScalaApplicatio@n.pString(a)""", "controllers.ScalaApplication.pString(String)")
72+
testWithAnswer("""GET /:a controllers.ScalaApplicatio~n.pString(a)""", "controllers.ScalaApplication.pString(String)")
7373
}
7474

7575
@Test
7676
def scalaControllerRefAction() {
77-
testWithAnswer("""GET /:a controllers.ScalaApplicatio@n.pRef(a: model.Element)""", "controllers.ScalaApplication.pRef(model.Element)")
77+
testWithAnswer("""GET /:a controllers.ScalaApplicatio~n.pRef(a: model.Element)""", "controllers.ScalaApplication.pRef(model.Element)")
7878
}
7979

8080
@Test
8181
def scalaControllerOverloadedIntAction() {
82-
testWithAnswer("""GET /:a controllers.ScalaApplicati@on.overloaded(a: Int)""", "controllers.ScalaApplication.overloaded(Int)")
82+
testWithAnswer("""GET /:a controllers.ScalaApplicati~on.overloaded(a: Int)""", "controllers.ScalaApplication.overloaded(Int)")
8383
}
8484

8585
@Test
8686
def scalaControllerOverloadedStringAction() {
87-
testWithAnswer("""GET /:a controllers.ScalaApplicati@on.overloaded(a)""", "controllers.ScalaApplication.overloaded(String)")
87+
testWithAnswer("""GET /:a controllers.ScalaApplicati~on.overloaded(a)""", "controllers.ScalaApplication.overloaded(String)")
8888
}
8989

9090
@Test
9191
def scalaControllerOverloadedRefAction() {
92-
testWithAnswer("""GET /:a controllers.ScalaApplicati@on.overloaded(a: model.Element)""", "controllers.ScalaApplication.overloaded(model.Element)")
92+
testWithAnswer("""GET /:a controllers.ScalaApplicati~on.overloaded(a: model.Element)""", "controllers.ScalaApplication.overloaded(model.Element)")
9393
}
9494

9595
@Test
9696
def scalaControllerOverloadedStringRefAction() {
97-
testWithAnswer("""GET /:a controllers.ScalaApplicati@on.overloaded(b, a: model.Element)""", "controllers.ScalaApplication.overloaded(String,model.Element)")
97+
testWithAnswer("""GET /:a controllers.ScalaApplicati~on.overloaded(b, a: model.Element)""", "controllers.ScalaApplication.overloaded(String,model.Element)")
9898
}
9999

100100
@Test
101101
def scalaNoMatch {
102-
testWithoutAnswer("""GET / some.unexisting.p@ackage.Application.index""")
102+
testWithoutAnswer("""GET / some.unexisting.p~ackage.Application.index""")
103103
}
104104

105105
@Test
106106
def scalaWrongParameterTypes {
107-
testWithoutAnswer("""GET /:s controllers.Sca@laApplication.pInt(s)""")
107+
testWithoutAnswer("""GET /:s controllers.Sca~laApplication.pInt(s)""")
108108
}
109109

110110
@Test
111111
def scalaWrongParameterTypesOverloaded {
112-
testWithoutAnswer("""GET /:s [email protected](s, i: Int)""")
112+
testWithoutAnswer("""GET /:s controllers.ScalaAppl~ication.overloaded(s, i: Int)""")
113+
}
114+
115+
@Test
116+
def scalaControllerClassNoParameterAction() {
117+
testWithAnswer("""GET / @controllers.ScalaC~lass.intro""", "controllers.ScalaClass.intro")
118+
}
119+
120+
@Test
121+
def scalaControllerClassNoParameterAction2() {
122+
testWithAnswer("""GET / @controllers.ScalaClass~.withEmptyParams""", "controllers.ScalaClass.withEmptyParams()")
123+
}
124+
125+
@Test
126+
def scalaControllerClassEmptyParametersAction() {
127+
testWithAnswer("""GET / @controllers.ScalaC~lass.intro()""", "controllers.ScalaClass.intro")
128+
}
129+
130+
@Test
131+
def scalaControllerClassEmptyParametersAction2() {
132+
testWithAnswer("""GET / @controllers.ScalaClass~.withEmptyParams()""", "controllers.ScalaClass.withEmptyParams()")
133+
}
134+
135+
@Test
136+
def scalaControllerClassIntAction() {
137+
testWithAnswer("""GET /:a @controllers.ScalaCla~ss.pInt(a: Int)""", "controllers.ScalaClass.pInt(Int)")
138+
}
139+
140+
@Test
141+
def scalaControllerClassStringAction() {
142+
testWithAnswer("""GET /:a @controllers.ScalaClas~s.pString(a)""", "controllers.ScalaClass.pString(String)")
143+
}
144+
145+
@Test
146+
def scalaControllerClassRefAction() {
147+
testWithAnswer("""GET /:a @controllers.ScalaClas~s.pRef(a: model.Element)""", "controllers.ScalaClass.pRef(model.Element)")
148+
}
149+
150+
@Test
151+
def scalaControllerClassOverloadedIntAction() {
152+
testWithAnswer("""GET /:a @controllers.ScalaCla~ss.overloaded(a: Int)""", "controllers.ScalaClass.overloaded(Int)")
153+
}
154+
155+
@Test
156+
def scalaControllerClassOverloadedStringAction() {
157+
testWithAnswer("""GET /:a @controllers.ScalaCla~ss.overloaded(a)""", "controllers.ScalaClass.overloaded(String)")
158+
}
159+
160+
@Test
161+
def scalaControllerClassOverloadedRefAction() {
162+
testWithAnswer("""GET /:a @controllers.ScalaCla~ss.overloaded(a: model.Element)""", "controllers.ScalaClass.overloaded(model.Element)")
163+
}
164+
165+
@Test
166+
def scalaControllerClassOverloadedStringRefAction() {
167+
testWithAnswer("""GET /:a @controllers.ScalaCla~ss.overloaded(b, a: model.Element)""", "controllers.ScalaClass.overloaded(String,model.Element)")
168+
}
169+
170+
@Test
171+
def scalaClassNoMatch {
172+
testWithoutAnswer("""GET / @some.unexisting.p~ackage.Class.index""")
173+
}
174+
175+
@Test
176+
def scalaClassWrongParameterTypes {
177+
testWithoutAnswer("""GET /:s controllers.Sca~laClass.pInt(s)""")
178+
}
179+
180+
@Test
181+
def scalaClassWrongParameterTypesOverloaded {
182+
testWithoutAnswer("""GET /:s controllers.ScalaCl~ass.overloaded(s, i: Int)""")
113183
}
114184

115185
@Test
116186
def javaControllerNoParameterAction() {
117-
testWithAnswer("""GET / controllers.JavaAp@plication.intro""", "controllers.JavaApplication.intro()QObject;")
187+
testWithAnswer("""GET / controllers.JavaAp~plication.intro""", "controllers.JavaApplication.intro()QObject;")
118188
}
119189

120190
@Test
121191
def javaControllerNoParameterAction2() {
122-
testWithAnswer("""GET / controllers.JavaAp@plication.withEmptyParams""", "controllers.JavaApplication.withEmptyParams()QObject;")
192+
testWithAnswer("""GET / controllers.JavaAp~plication.withEmptyParams""", "controllers.JavaApplication.withEmptyParams()QObject;")
123193
}
124194

125195
@Test
126196
def javaControllerEmptyParametersAction() {
127-
testWithAnswer("""GET / controllers.JavaAp@plication.intro()""", "controllers.JavaApplication.intro()QObject;")
197+
testWithAnswer("""GET / controllers.JavaAp~plication.intro()""", "controllers.JavaApplication.intro()QObject;")
128198
}
129199

130200
@Test
131201
def javaControllerEmptyParametersAction2() {
132-
testWithAnswer("""GET / controllers.JavaApplication.@withEmptyParams()""", "controllers.JavaApplication.withEmptyParams()QObject;")
202+
testWithAnswer("""GET / controllers.JavaApplication.~withEmptyParams()""", "controllers.JavaApplication.withEmptyParams()QObject;")
133203
}
134204

135205
@Test
136206
def javaControllerIntAction() {
137-
testWithAnswer("""GET /:a controllers.JavaApplicatio@n.pInt(a: Int)""", "controllers.JavaApplication.pInt(I)QObject;")
207+
testWithAnswer("""GET /:a controllers.JavaApplicatio~n.pInt(a: Int)""", "controllers.JavaApplication.pInt(I)QObject;")
138208
}
139209

140210
@Test
141211
def javaControllerStringAction() {
142-
testWithAnswer("""GET /:a controllers.JavaApplication@.pString(a)""", "controllers.JavaApplication.pString(QString;)QObject;")
212+
testWithAnswer("""GET /:a controllers.JavaApplication~.pString(a)""", "controllers.JavaApplication.pString(QString;)QObject;")
143213
}
144214

145215
@Test
146216
def javaControllerRefAction() {
147-
testWithAnswer("""GET /:a controllers.JavaApplication@.pRef(a: model.Element)""", "controllers.JavaApplication.pRef(QElement;)QObject;")
217+
testWithAnswer("""GET /:a controllers.JavaApplication~.pRef(a: model.Element)""", "controllers.JavaApplication.pRef(QElement;)QObject;")
148218
}
149219

150220
@Test
151221
def javaControllerOverloadedIntAction() {
152-
testWithAnswer("""GET /:a controllers.JavaApplicatio@n.overloaded(a: Int)""", "controllers.JavaApplication.overloaded(I)QObject;")
222+
testWithAnswer("""GET /:a controllers.JavaApplicatio~n.overloaded(a: Int)""", "controllers.JavaApplication.overloaded(I)QObject;")
153223
}
154224

155225
@Test
156226
def javaControllerOverloadedStringAction() {
157-
testWithAnswer("""GET /:a controllers.JavaApplicatio@n.overloaded(a)""", "controllers.JavaApplication.overloaded(QString;)QObject;")
227+
testWithAnswer("""GET /:a controllers.JavaApplicatio~n.overloaded(a)""", "controllers.JavaApplication.overloaded(QString;)QObject;")
158228
}
159229

160230
@Test
161231
def javaControllerOverloadedRefAction() {
162-
testWithAnswer("""GET /:a controllers.JavaApplicatio@n.overloaded(a: model.Element)""", "controllers.JavaApplication.overloaded(QElement;)QObject;")
232+
testWithAnswer("""GET /:a controllers.JavaApplicatio~n.overloaded(a: model.Element)""", "controllers.JavaApplication.overloaded(QElement;)QObject;")
163233
}
164234

165235
@Test
166236
def javaControllerOverloadedStringRefAction() {
167-
testWithAnswer("""GET /:a controllers.JavaApplicatio@n.overloaded(b, a: model.Element)""", "controllers.JavaApplication.overloaded(QString;QElement;)QObject;")
237+
testWithAnswer("""GET /:a controllers.JavaApplicatio~n.overloaded(b, a: model.Element)""", "controllers.JavaApplication.overloaded(QString;QElement;)QObject;")
168238
}
169239

170240
@Test
171241
def javaNoMatch {
172-
testWithoutAnswer("""GET / some.unexisting.p@ackage.Application.index""")
242+
testWithoutAnswer("""GET / some.unexisting.p~ackage.Application.index""")
173243
}
174244

175245
@Test
176246
def javaWrongParameterTypes {
177-
testWithoutAnswer("""GET /:s some.unexisting@.package.Application.pInt(s)""")
247+
testWithoutAnswer("""GET /:s some.unexisting~.package.Application.pInt(s)""")
178248
}
179249

180250
@Test
181251
def javaWrongParameterTypesOverloaded {
182-
testWithoutAnswer("""GET /:s some.unexisting.packa@ge.Application.overloaded(s, i: Int)""")
252+
testWithoutAnswer("""GET /:s some.unexisting.packa~ge.Application.overloaded(s, i: Int)""")
183253
}
184254

185255
private def testWithAnswer(
186256
content: String,
187257
expectedLabel: String) {
188258

189-
val file = RouteFile(content)
259+
val file = RouteFile(content, List('~'))
190260

191-
val actual = RouteHyperlinkComputer.detectHyperlinks(project, file.document, new Region(file.caretOffset('@'), 0), createJavaHyperlink)
261+
val actual = RouteHyperlinkComputer.detectHyperlinks(project, file.document, new Region(file.caretOffset('~'), 0), createJavaHyperlink)
192262

193263
actual match {
194264
case Some(hyperlink) =>
195265
assertEquals("Wrong label", expectedLabel, hyperlink.getTypeLabel())
196-
assertEquals("Wrong region", file.document.getPartition(file.caretOffset('@')), hyperlink.getHyperlinkRegion())
266+
assertEquals("Wrong region", file.document.getPartition(file.caretOffset('~')), hyperlink.getHyperlinkRegion())
197267
case _ =>
198268
fail("Wrong detectHyperlink result. Expected: Some(hyperlink), was: %s".format(actual))
199269
}
200270
}
201271

202272
private def testWithoutAnswer(content: String) {
203273

204-
val file = RouteFile(content)
274+
val file = RouteFile(content, List('~'))
205275

206-
val actual = RouteHyperlinkComputer.detectHyperlinks(project, file.document, new Region(file.caretOffset('@'), 0), createJavaHyperlink)
276+
val actual = RouteHyperlinkComputer.detectHyperlinks(project, file.document, new Region(file.caretOffset('~'), 0), createJavaHyperlink)
207277

208278
actual match {
209279
case None =>

org.scala-ide.play2.tests/test-workspace/routeHyperlink/app/controllers/ScalaApplication.scala

+21
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,26 @@ object ScalaApplication {
2020

2121
def overloaded(b: Element): AnyRef = ???
2222

23+
def overloaded(s: String, b: Element): AnyRef = ???
24+
}
25+
26+
class ScalaClass {
27+
28+
def intro: AnyRef = ???
29+
30+
def withEmptyParams(): AnyRef = ???
31+
32+
def pInt(a: Int): AnyRef = ???
33+
34+
def pString(a: String): AnyRef = ???
35+
36+
def pRef(a: Element): AnyRef = ???
37+
38+
def overloaded(b: Int): AnyRef = ???
39+
40+
def overloaded(c: String): AnyRef = ???
41+
42+
def overloaded(b: Element): AnyRef = ???
43+
2344
def overloaded(s: String, b: Element): AnyRef = ???
2445
}

org.scala-ide.play2/src/org/scalaide/play2/routeeditor/RouteAction.scala

+6-2
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@ object RouteAction {
99

1010
/** Regex for the an action with parameters.
1111
* "package.Object.action(...xxx...)"
12+
* or
13+
* "@package.Class.action(...xxx...)"
1214
*/
13-
private final val ActionWithParametersRegex = """([^\(]*)\.([^\.\(]*)\(([^\)]*)\)""".r
15+
private final val ActionWithParametersRegex = """@?([^\(]*)\.([^\.\(]*)\(([^\)]*)\)""".r
1416

1517
/** Regex for the an action without parameters.
1618
* "package.Object.action"
19+
* or
20+
* "@package.Class.action"
1721
*/
18-
private final val ActionWithoutParametersRegex = """([^\(]*)\.([^\.\(]*)""".r
22+
private final val ActionWithoutParametersRegex = """@?([^\(]*)\.([^\.\(]*)""".r
1923

2024
/** Regex for the individual parameters.
2125
* The support format is: "page: Int ?= 1"

org.scala-ide.play2/src/org/scalaide/play2/routeeditor/hyperlink/RouteHyperlinkComputer.scala

+7-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ object RouteHyperlinkComputer {
4444
val obj = rootMirror.getModuleIfDefined(routeAction.typeName)
4545

4646
// method or methods of the object with the given name
47-
val method = obj.info.member(newTermName(routeAction.methodName))
47+
val objMethod = obj.info.member(newTermName(routeAction.methodName))
48+
49+
// if the method of the object doesn't exist, than perhaps routeAction.typeName is actually a class
50+
// so let's try getting the class and searching it's methods for routeAction.methodName
51+
val method =
52+
if (objMethod.exists) objMethod
53+
else rootMirror.getClassIfDefined(routeAction.typeName).info.member(newTermName(routeAction.methodName))
4854

4955
if (!method.exists) {
5056
None

0 commit comments

Comments
 (0)