1
1
/*
2
- * Copyright 2001-2016 Artima, Inc.
2
+ * Copyright 2001-2019 Artima, Inc.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
15
15
*/
16
16
package org .scalactic .source
17
17
18
+ import org .scalactic .MacroContext .Context
18
19
import org .scalactic .Resources
19
20
20
- import scala .reflect .macros .Context
21
-
22
21
/**
23
22
* Helper class for Position macro. (Will be removed from the public API if possible in a subsequent 3.0.0-RCx release.)
24
23
*/
25
- object PositionMacro {
24
+ object PositionMacro {
25
+ private object sourceCompatHack {
26
+ object internal { object decorators {} }
27
+ }
28
+ import sourceCompatHack ._
26
29
27
30
private [scalactic] lazy val showScalacticFillFilePathnames : Boolean = {
28
31
val value = System .getenv(" SCALACTIC_FILL_FILE_PATHNAMES" )
29
32
value != null && value == " yes"
30
33
}
31
34
32
- /**
33
- * Helper method for Position macro.
34
- */
35
- def genPosition (context : Context ) = {
36
- import context .universe ._
35
+ private class PositionMacroImpl (val universe : scala.reflect.api.Universe ) {
36
+
37
+ private val PositionModule = universe.rootMirror.staticModule(" org.scalactic.source.Position" )
38
+ private val PositionClass = universe.rootMirror.staticClass(" org.scalactic.source.Position" )
39
+ private val Position_apply = PositionModule .typeSignature.declaration(universe.newTermName(" apply" ))
40
+
41
+ def apply (context : Context ): context.Tree = {
42
+ import context .universe ._
43
+
44
+ // On 2.10, this imports the empty object defined above
45
+ // On 2.11+, this imports `Tree.setType` extension method
46
+ import internal .decorators ._
37
47
38
- context.Expr (
39
- Apply (
40
- Select (
41
- Select (
42
- Select (
43
- Select (
44
- Select (
45
- Ident (newTermName(" _root_" )),
46
- newTermName(" org" )
47
- ),
48
- newTermName(" scalactic" )
49
- ),
50
- newTermName(" source" )
51
- ),
52
- newTermName(" Position" )
53
- ),
54
- newTermName(" apply" )
55
- ),
56
- List (
57
- Literal (Constant (context.enclosingPosition.source.file.name)),
58
- Literal (if (showScalacticFillFilePathnames) Constant (context.enclosingPosition.source.path) else Constant (Resources .pleaseDefineScalacticFillFilePathnameEnvVar)),
59
- Literal (Constant (context.enclosingPosition.line))
60
- )
48
+ // Our types don't capture the fact that context.universe eq this.universe, so we have to cast.
49
+ implicit def castSymbol (s : universe.Symbol ): context.universe.Symbol = s.asInstanceOf [context.universe.Symbol ]
50
+ implicit def castType (t : universe.Type ): context.universe.Type = t.asInstanceOf [context.universe.Type ]
51
+
52
+ import treeBuild .{mkAttributedIdent , mkAttributedSelect }
53
+
54
+ // Because this macro is called so frequently, we assign types as we build them, rather
55
+ // than returning an untyped tree and letting the typechecker fill in the types.
56
+ // (`setType` and `mkAttributedXxx` assign Tree.tpe.)
57
+ def strLit (s : String ) = {
58
+ Literal (Constant (s)).setType(definitions.StringClass .toTypeConstructor)
59
+ }
60
+ def intLit (i : Int ) = {
61
+ Literal (Constant (i)).setType(definitions.IntTpe )
62
+ }
63
+ val args = List (
64
+ strLit(context.enclosingPosition.source.file.name),
65
+ if (showScalacticFillFilePathnames) strLit(context.enclosingPosition.source.path) else strLit(Resources .pleaseDefineScalacticFillFilePathnameEnvVar),
66
+ intLit(context.enclosingPosition.line)
61
67
)
62
- )
68
+
69
+ Apply (mkAttributedSelect(mkAttributedIdent(PositionModule ), Position_apply ), args).setType(PositionClass .toTypeConstructor)
70
+ }
63
71
}
64
72
65
- }
73
+ // Cache to avoid needing to lookup of PositionModule/PositionClass/Position_apply each macro expansion.
74
+ private var cache = new java.lang.ref.WeakReference [PositionMacroImpl ](null )
75
+
76
+ /**
77
+ * Helper method for Position macro.
78
+ */
79
+ def genPosition (context : Context ): context.Expr [Position ] = {
80
+ var impl = cache.get()
81
+ if (impl == null || impl.universe != context.universe) {
82
+ impl = new PositionMacroImpl (context.universe)
83
+ cache = new java.lang.ref.WeakReference [PositionMacroImpl ](impl)
84
+ }
85
+ context.Expr [Position ](impl.apply(context))
86
+ }
87
+ }
0 commit comments