summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala66
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala28
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala40
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala2
-rw-r--r--test/files/run/macroPlugins-macroArgs.check2
-rw-r--r--test/files/run/macroPlugins-macroArgs/Macros_2.scala11
-rw-r--r--test/files/run/macroPlugins-macroArgs/Plugin_1.scala21
-rw-r--r--test/files/run/macroPlugins-macroArgs/Test_3.flags1
-rw-r--r--test/files/run/macroPlugins-macroArgs/Test_3.scala4
-rw-r--r--test/files/run/macroPlugins-macroArgs/scalac-plugin.xml4
-rw-r--r--test/files/run/macroPlugins-macroExpand.check2
-rw-r--r--test/files/run/macroPlugins-macroExpand/Macros_2.scala18
-rw-r--r--test/files/run/macroPlugins-macroExpand/Plugin_1.scala27
-rw-r--r--test/files/run/macroPlugins-macroExpand/Test_3.flags1
-rw-r--r--test/files/run/macroPlugins-macroExpand/Test_3.scala4
-rw-r--r--test/files/run/macroPlugins-macroExpand/scalac-plugin.xml4
-rw-r--r--test/files/run/macroPlugins-macroRuntime.check2
-rw-r--r--test/files/run/macroPlugins-macroRuntime/Macros_2.scala11
-rw-r--r--test/files/run/macroPlugins-macroRuntime/Plugin_1.scala20
-rw-r--r--test/files/run/macroPlugins-macroRuntime/Test_3.flags1
-rw-r--r--test/files/run/macroPlugins-macroRuntime/Test_3.scala4
-rw-r--r--test/files/run/macroPlugins-macroRuntime/scalac-plugin.xml4
-rw-r--r--test/files/run/macroPlugins-namerHooks.check45
-rw-r--r--test/files/run/macroPlugins-namerHooks.scala38
-rw-r--r--test/files/run/macroPlugins-typedMacroBody.check2
-rw-r--r--test/files/run/macroPlugins-typedMacroBody/Macros_2.flags1
-rw-r--r--test/files/run/macroPlugins-typedMacroBody/Macros_2.scala18
-rw-r--r--test/files/run/macroPlugins-typedMacroBody/Plugin_1.scala21
-rw-r--r--test/files/run/macroPlugins-typedMacroBody/Test_3.scala4
-rw-r--r--test/files/run/macroPlugins-typedMacroBody/scalac-plugin.xml4
31 files changed, 379 insertions, 33 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index 5c02516c47..70ff1051c1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -40,7 +40,7 @@ trait Analyzer extends AnyRef
override def keepsTypeParams = false
def apply(unit: CompilationUnit) {
- newNamer(rootContext(unit)).enterSym(unit.body)
+ pluginsEnterSym(newNamer(rootContext(unit)), unit.body)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala
index 09a6a553ee..61becab483 100644
--- a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala
@@ -229,6 +229,41 @@ trait AnalyzerPlugins { self: Analyzer =>
* $nonCumulativeReturnValueDoc.
*/
def pluginsMacroRuntime(expandee: Tree): Option[MacroRuntime] = None
+
+ /**
+ * Creates a symbol for the given tree in lexical context encapsulated by the given namer.
+ *
+ * Default implementation provided in `namer.enterSym` handles MemberDef's and Imports,
+ * doing nothing for other trees (DocDef's are seen through and rewrapped). Typical implementation
+ * of `enterSym` for a particular tree flavor creates a corresponding symbol, assigns it to the tree,
+ * enters the symbol into scope and then might even perform some code generation.
+ *
+ * $nonCumulativeReturnValueDoc.
+ */
+ def pluginsEnterSym(namer: Namer, tree: Tree): Boolean = false
+
+ /**
+ * Makes sure that for the given class definition, there exists a companion object definition.
+ *
+ * Default implementation provided in `namer.ensureCompanionObject` looks up a companion symbol for the class definition
+ * and then checks whether the resulting symbol exists or not. If it exists, then nothing else is done.
+ * If not, a synthetic object definition is created using the provided factory, which is then entered into namer's scope.
+ *
+ * $nonCumulativeReturnValueDoc.
+ */
+ def pluginsEnsureCompanionObject(namer: Namer, cdef: ClassDef, creator: ClassDef => Tree = companionModuleDef(_)): Option[Symbol] = None
+
+ /**
+ * Prepares a list of statements for being typechecked by performing domain-specific type-agnostic code synthesis.
+ *
+ * Trees passed into this method are going to be named, but not typed.
+ * In particular, you can rely on the compiler having called `enterSym` on every stat prior to passing calling this method.
+ *
+ * Default implementation does nothing. Current approaches to code syntheses (generation of underlying fields
+ * for getters/setters, creation of companion objects for case classes, etc) are too disparate and ad-hoc
+ * to be treated uniformly, so I'm leaving this for future work.
+ */
+ def pluginsEnterStats(typer: Typer, stats: List[Tree]): List[Tree] = stats
}
@@ -363,4 +398,35 @@ trait AnalyzerPlugins { self: Analyzer =>
def default = macroRuntime(expandee)
def custom(plugin: MacroPlugin) = plugin.pluginsMacroRuntime(expandee)
})
+
+ /** @see MacroPlugin.pluginsEnterSym */
+ def pluginsEnterSym(namer: Namer, tree: Tree): Context = invoke(new NonCumulativeOp[Context] {
+ def position = tree.pos
+ def description = "enter a symbol for this tree"
+ def default = namer.enterSym(tree)
+ def custom(plugin: MacroPlugin) = {
+ val hasExistingSym = tree.symbol != NoSymbol
+ val result = plugin.pluginsEnterSym(namer, tree)
+ if (result && hasExistingSym) Some(namer.context)
+ else if (result && tree.isInstanceOf[Import]) Some(namer.context.make(tree))
+ else if (result) Some(namer.context)
+ else None
+ }
+ })
+
+ /** @see MacroPlugin.pluginsEnsureCompanionObject */
+ def pluginsEnsureCompanionObject(namer: Namer, cdef: ClassDef, creator: ClassDef => Tree = companionModuleDef(_)): Symbol = invoke(new NonCumulativeOp[Symbol] {
+ def position = cdef.pos
+ def description = "enter a companion symbol for this tree"
+ def default = namer.ensureCompanionObject(cdef, creator)
+ def custom(plugin: MacroPlugin) = plugin.pluginsEnsureCompanionObject(namer, cdef, creator)
+ })
+
+ /** @see MacroPlugin.pluginsEnterStats */
+ def pluginsEnterStats(typer: Typer, stats: List[Tree]): List[Tree] = {
+ // performance opt
+ if (macroPlugins.isEmpty) stats
+ else macroPlugins.foldLeft(stats)((current, plugin) =>
+ if (!plugin.isActive()) current else plugin.pluginsEnterStats(typer, stats))
+ }
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 01d61a253e..ee597528a9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -22,7 +22,7 @@ trait Namers extends MethodSynthesis {
import global._
import definitions._
- private var _lockedCount = 0
+ var _lockedCount = 0
def lockedCount = this._lockedCount
/** Replaces any Idents for which cond is true with fresh TypeTrees().
@@ -107,8 +107,8 @@ trait Namers extends MethodSynthesis {
}
protected def owner = context.owner
- private def contextFile = context.unit.source.file
- private def typeErrorHandler[T](tree: Tree, alt: T): PartialFunction[Throwable, T] = {
+ def contextFile = context.unit.source.file
+ def typeErrorHandler[T](tree: Tree, alt: T): PartialFunction[Throwable, T] = {
case ex: TypeError =>
// H@ need to ensure that we handle only cyclic references
TypeSigError(tree, ex)
@@ -253,7 +253,7 @@ trait Namers extends MethodSynthesis {
case tree @ ValDef(_, _, _, _) => enterValDef(tree)
case tree @ DefDef(_, _, _, _, _, _) => enterDefDef(tree)
case tree @ TypeDef(_, _, _, _) => enterTypeDef(tree)
- case DocDef(_, defn) => enterSym(defn)
+ case DocDef(_, defn) => pluginsEnterSym(this, defn)
case tree @ Import(_, _) =>
assignSymbol(tree)
returnContext = context.make(tree)
@@ -309,7 +309,7 @@ trait Namers extends MethodSynthesis {
* be transferred to the symbol as they are, supply a mask containing
* the flags to keep.
*/
- private def createMemberSymbol(tree: MemberDef, name: Name, mask: Long): Symbol = {
+ def createMemberSymbol(tree: MemberDef, name: Name, mask: Long): Symbol = {
val pos = tree.pos
val isParameter = tree.mods.isParameter
val flags = tree.mods.flags & mask
@@ -327,14 +327,14 @@ trait Namers extends MethodSynthesis {
else owner.newValue(name.toTermName, pos, flags)
}
}
- private def createFieldSymbol(tree: ValDef): TermSymbol =
+ def createFieldSymbol(tree: ValDef): TermSymbol =
owner.newValue(tree.localName, tree.pos, tree.mods.flags & FieldFlags | PrivateLocal)
- private def createImportSymbol(tree: Tree) =
+ def createImportSymbol(tree: Tree) =
NoSymbol.newImport(tree.pos) setInfo completerOf(tree)
/** All PackageClassInfoTypes come from here. */
- private def createPackageSymbol(pos: Position, pid: RefTree): Symbol = {
+ def createPackageSymbol(pos: Position, pid: RefTree): Symbol = {
val pkgOwner = pid match {
case Ident(_) => if (owner.isEmptyPackageClass) rootMirror.RootClass else owner
case Select(qual: RefTree, _) => createPackageSymbol(pos, qual).moduleClass
@@ -393,7 +393,7 @@ trait Namers extends MethodSynthesis {
/** Given a ClassDef or ModuleDef, verifies there isn't a companion which
* has been defined in a separate file.
*/
- private def validateCompanionDefs(tree: ImplDef) {
+ def validateCompanionDefs(tree: ImplDef) {
val sym = tree.symbol orElse { return }
val ctx = if (context.owner.isPackageObjectClass) context.outer else context
val module = if (sym.isModule) sym else ctx.scope lookupModule tree.name
@@ -452,7 +452,7 @@ trait Namers extends MethodSynthesis {
def enterSyms(trees: List[Tree]): Namer = {
trees.foldLeft(this: Namer) { (namer, t) =>
- val ctx = namer enterSym t
+ val ctx = pluginsEnterSym(namer, t)
// for Import trees, enterSym returns a changed context, so we need a new namer
if (ctx eq namer.context) namer
else newNamer(ctx)
@@ -662,7 +662,7 @@ trait Namers extends MethodSynthesis {
tree.symbol setInfo completerOf(tree)
if (mods.isCase) {
- val m = ensureCompanionObject(tree, caseModuleDef)
+ val m = pluginsEnsureCompanionObject(this, tree, caseModuleDef)
m.moduleClass.updateAttachment(new ClassForCaseCompanionAttachment(tree))
}
val hasDefault = impl.body exists {
@@ -670,7 +670,7 @@ trait Namers extends MethodSynthesis {
case _ => false
}
if (hasDefault) {
- val m = ensureCompanionObject(tree)
+ val m = pluginsEnsureCompanionObject(this, tree)
m.updateAttachment(new ConstructorDefaultsAttachment(tree, null))
}
val owner = tree.symbol.owner
@@ -697,7 +697,7 @@ trait Namers extends MethodSynthesis {
def enterIfNotThere(sym: Symbol) { }
def enterSyntheticSym(tree: Tree): Symbol = {
- enterSym(tree)
+ pluginsEnterSym(this, tree)
context.unit.synthetics(tree.symbol) = tree
tree.symbol
}
@@ -931,7 +931,7 @@ trait Namers extends MethodSynthesis {
log("Ensuring companion for derived value class " + cdef.name + " at " + cdef.pos.show)
clazz setFlag FINAL
// Don't force the owner's info lest we create cycles as in SI-6357.
- enclosingNamerWithScope(clazz.owner.rawInfo.decls).ensureCompanionObject(cdef)
+ pluginsEnsureCompanionObject(enclosingNamerWithScope(clazz.owner.rawInfo.decls), cdef)
}
pluginsTp
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 5c1026394a..8ddaccf16c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1863,12 +1863,15 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
protected def enterSym(txt: Context, tree: Tree): Context =
- if (txt eq context) namer.enterSym(tree)
- else newNamer(txt).enterSym(tree)
+ if (txt eq context) pluginsEnterSym(namer, tree)
+ else pluginsEnterSym(newNamer(txt), tree)
/** <!-- 2 --> Check that inner classes do not inherit from Annotation
*/
- def typedTemplate(templ: Template, parents1: List[Tree]): Template = {
+ def typedTemplate(templ0: Template, parents1: List[Tree]): Template = {
+ val templ = templ0
+ // please FIXME: uncommenting this line breaks everything
+ // val templ = treeCopy.Template(templ0, templ0.body, templ0.self, templ0.parents)
val clazz = context.owner
clazz.annotations.map(_.completeInfo())
if (templ.symbol == NoSymbol)
@@ -1896,7 +1899,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
)
// the following is necessary for templates generated later
assert(clazz.info.decls != EmptyScope, clazz)
- enterSyms(context.outer.make(templ, clazz, clazz.info.decls), templ.body)
+ val body1 = pluginsEnterStats(this, templ.body)
+ enterSyms(context.outer.make(templ, clazz, clazz.info.decls), body1)
if (!templ.isErrorTyped) // if `parentTypes` has invalidated the template, don't validate it anymore
validateParentClasses(parents1, selfType)
if (clazz.isCase)
@@ -1910,11 +1914,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members
checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType])
- val body = {
- val body =
- if (isPastTyper || reporter.hasErrors) templ.body
- else templ.body flatMap rewrappingWrapperTrees(namer.addDerivedTrees(Typer.this, _))
- val primaryCtor = treeInfo.firstConstructor(body)
+ val body2 = {
+ val body2 =
+ if (isPastTyper || reporter.hasErrors) body1
+ else body1 flatMap rewrappingWrapperTrees(namer.addDerivedTrees(Typer.this, _))
+ val primaryCtor = treeInfo.firstConstructor(body2)
val primaryCtor1 = primaryCtor match {
case DefDef(_, _, _, _, _, Block(earlyVals :+ global.pendingSuperCall, unit)) =>
val argss = superArgs(parents1.head) getOrElse Nil
@@ -1923,13 +1927,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
deriveDefDef(primaryCtor)(block => Block(earlyVals :+ superCall, unit) setPos pos) setPos pos
case _ => primaryCtor
}
- body mapConserve { case `primaryCtor` => primaryCtor1; case stat => stat }
+ body2 mapConserve { case `primaryCtor` => primaryCtor1; case stat => stat }
}
- val body1 = typedStats(body, templ.symbol)
+ val body3 = typedStats(body2, templ.symbol)
if (clazz.info.firstParent.typeSymbol == AnyValClass)
- validateDerivedValueClass(clazz, body1)
+ validateDerivedValueClass(clazz, body3)
if (clazz.isTrait) {
for (decl <- clazz.info.decls if decl.isTerm && decl.isEarlyInitialized) {
@@ -1937,7 +1941,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
}
- treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe_*
+ treeCopy.Template(templ, parents1, self1, body3) setType clazz.tpe_*
}
/** Remove definition annotations from modifiers (they have been saved
@@ -2319,10 +2323,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
}
- def typedBlock(block: Block, mode: Mode, pt: Type): Block = {
+ def typedBlock(block0: Block, mode: Mode, pt: Type): Block = {
val syntheticPrivates = new ListBuffer[Symbol]
try {
- namer.enterSyms(block.stats)
+ namer.enterSyms(block0.stats)
+ val block = treeCopy.Block(block0, pluginsEnterStats(this, block0.stats), block0.expr)
for (stat <- block.stats) enterLabelDef(stat)
if (phaseId(currentPeriod) <= currentRun.typerPhase.id) {
@@ -3807,7 +3812,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
protected def typedExistentialTypeTree(tree: ExistentialTypeTree, mode: Mode): Tree = {
for (wc <- tree.whereClauses)
- if (wc.symbol == NoSymbol) { namer.enterSym(wc); wc.symbol setFlag EXISTENTIAL }
+ if (wc.symbol == NoSymbol) { pluginsEnterSym(namer, wc); wc.symbol setFlag EXISTENTIAL }
else context.scope enter wc.symbol
val whereClauses1 = typedStats(tree.whereClauses, context.owner)
for (vd @ ValDef(_, _, _, _) <- whereClauses1)
@@ -4954,7 +4959,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val sym: Symbol = tree.symbol
if ((sym ne null) && (sym ne NoSymbol)) sym.initialize
- def typedPackageDef(pdef: PackageDef) = {
+ def typedPackageDef(pdef0: PackageDef) = {
+ val pdef = treeCopy.PackageDef(pdef0, pdef0.pid, pluginsEnterStats(this, pdef0.stats))
val pid1 = typedQualifier(pdef.pid).asInstanceOf[RefTree]
assert(sym.moduleClass ne NoSymbol, sym)
val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls))
diff --git a/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala b/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala
index 51fab3082e..498ff46624 100644
--- a/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala
@@ -52,7 +52,7 @@ trait ReplGlobal extends Global {
def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) {
def apply(unit: CompilationUnit) {
repldbg("Running replPhase on " + unit.body)
- // newNamer(rootContext(unit)).enterSym(unit.body)
+ // pluginsEnterSym(newNamer(rootContext(unit)), unit.body)
}
}
}
diff --git a/test/files/run/macroPlugins-macroArgs.check b/test/files/run/macroPlugins-macroArgs.check
new file mode 100644
index 0000000000..a68f8069b6
--- /dev/null
+++ b/test/files/run/macroPlugins-macroArgs.check
@@ -0,0 +1,2 @@
+hijacked 1
+hijacked 2
diff --git a/test/files/run/macroPlugins-macroArgs/Macros_2.scala b/test/files/run/macroPlugins-macroArgs/Macros_2.scala
new file mode 100644
index 0000000000..d6521dfbcb
--- /dev/null
+++ b/test/files/run/macroPlugins-macroArgs/Macros_2.scala
@@ -0,0 +1,11 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.BlackboxContext
+
+object Macros {
+ def impl(c: BlackboxContext)(arg: c.Tree) = {
+ import c.universe._
+ q"""println($arg)"""
+ }
+
+ def foo(arg: String): Unit = macro impl
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroArgs/Plugin_1.scala b/test/files/run/macroPlugins-macroArgs/Plugin_1.scala
new file mode 100644
index 0000000000..04cedbdc64
--- /dev/null
+++ b/test/files/run/macroPlugins-macroArgs/Plugin_1.scala
@@ -0,0 +1,21 @@
+package macroArgs
+
+import scala.tools.nsc.Global
+import scala.tools.nsc.plugins.{Plugin => NscPlugin}
+
+class Plugin(val global: Global) extends NscPlugin {
+ import global._
+ import analyzer._
+
+ val name = "macroArgs"
+ val description = "A sample analyzer plugin that overrides macroArgs."
+ val components = Nil
+ addMacroPlugin(MacroPlugin)
+
+ object MacroPlugin extends MacroPlugin {
+ override def pluginsMacroArgs(typer: Typer, expandee: Tree): Option[MacroArgs] = {
+ val MacroArgs(c, List(Literal(Constant(s: String)))) = macroArgs(typer, expandee)
+ Some(MacroArgs(c, List(Literal(Constant("hijacked " + s)))))
+ }
+ }
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroArgs/Test_3.flags b/test/files/run/macroPlugins-macroArgs/Test_3.flags
new file mode 100644
index 0000000000..966df731d0
--- /dev/null
+++ b/test/files/run/macroPlugins-macroArgs/Test_3.flags
@@ -0,0 +1 @@
+-Xplugin:. \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroArgs/Test_3.scala b/test/files/run/macroPlugins-macroArgs/Test_3.scala
new file mode 100644
index 0000000000..a54d608178
--- /dev/null
+++ b/test/files/run/macroPlugins-macroArgs/Test_3.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ Macros.foo("1")
+ Macros.foo("2")
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroArgs/scalac-plugin.xml b/test/files/run/macroPlugins-macroArgs/scalac-plugin.xml
new file mode 100644
index 0000000000..0849f0f4ea
--- /dev/null
+++ b/test/files/run/macroPlugins-macroArgs/scalac-plugin.xml
@@ -0,0 +1,4 @@
+<plugin>
+ <name>macro-args</name>
+ <classname>macroArgs.Plugin</classname>
+</plugin> \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroExpand.check b/test/files/run/macroPlugins-macroExpand.check
new file mode 100644
index 0000000000..6f685c2af4
--- /dev/null
+++ b/test/files/run/macroPlugins-macroExpand.check
@@ -0,0 +1,2 @@
+expanded into println("impl1")
+expanded into println("impl2")
diff --git a/test/files/run/macroPlugins-macroExpand/Macros_2.scala b/test/files/run/macroPlugins-macroExpand/Macros_2.scala
new file mode 100644
index 0000000000..f16503b415
--- /dev/null
+++ b/test/files/run/macroPlugins-macroExpand/Macros_2.scala
@@ -0,0 +1,18 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.BlackboxContext
+
+object Macros {
+ def impl1(c: BlackboxContext) = {
+ import c.universe._
+ q"""println("impl1")"""
+ }
+
+ def impl2(c: BlackboxContext) = {
+ import c.universe._
+ q"""println("impl2")"""
+ }
+
+ def foo1: Unit = macro impl1
+
+ def foo2: Unit = macro impl2
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroExpand/Plugin_1.scala b/test/files/run/macroPlugins-macroExpand/Plugin_1.scala
new file mode 100644
index 0000000000..13df85cb23
--- /dev/null
+++ b/test/files/run/macroPlugins-macroExpand/Plugin_1.scala
@@ -0,0 +1,27 @@
+package macroExpand
+
+import scala.tools.nsc.Global
+import scala.tools.nsc.plugins.{Plugin => NscPlugin}
+
+class Plugin(val global: Global) extends NscPlugin {
+ import global._
+ import analyzer._
+ import scala.reflect.internal.Mode
+
+ val name = "macroExpand"
+ val description = "A sample analyzer plugin that overrides macroExpand."
+ val components = Nil
+ addMacroPlugin(MacroPlugin)
+
+ object MacroPlugin extends MacroPlugin {
+ override def pluginsMacroExpand(typer: Typer, expandee: Tree, mode: Mode, pt: Type): Option[Tree] = {
+ object expander extends DefMacroExpander(typer, expandee, mode, pt) {
+ override def onSuccess(expanded: Tree) = {
+ val message = s"expanded into ${expanded.toString}"
+ typer.typed(q"println($message)")
+ }
+ }
+ Some(expander(expandee))
+ }
+ }
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroExpand/Test_3.flags b/test/files/run/macroPlugins-macroExpand/Test_3.flags
new file mode 100644
index 0000000000..966df731d0
--- /dev/null
+++ b/test/files/run/macroPlugins-macroExpand/Test_3.flags
@@ -0,0 +1 @@
+-Xplugin:. \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroExpand/Test_3.scala b/test/files/run/macroPlugins-macroExpand/Test_3.scala
new file mode 100644
index 0000000000..def9b5608a
--- /dev/null
+++ b/test/files/run/macroPlugins-macroExpand/Test_3.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ Macros.foo1
+ Macros.foo2
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroExpand/scalac-plugin.xml b/test/files/run/macroPlugins-macroExpand/scalac-plugin.xml
new file mode 100644
index 0000000000..860150865c
--- /dev/null
+++ b/test/files/run/macroPlugins-macroExpand/scalac-plugin.xml
@@ -0,0 +1,4 @@
+<plugin>
+ <name>macro-expand</name>
+ <classname>macroExpand.Plugin</classname>
+</plugin> \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroRuntime.check b/test/files/run/macroPlugins-macroRuntime.check
new file mode 100644
index 0000000000..af16d1ac36
--- /dev/null
+++ b/test/files/run/macroPlugins-macroRuntime.check
@@ -0,0 +1,2 @@
+hijacked
+hijacked
diff --git a/test/files/run/macroPlugins-macroRuntime/Macros_2.scala b/test/files/run/macroPlugins-macroRuntime/Macros_2.scala
new file mode 100644
index 0000000000..d6521dfbcb
--- /dev/null
+++ b/test/files/run/macroPlugins-macroRuntime/Macros_2.scala
@@ -0,0 +1,11 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.BlackboxContext
+
+object Macros {
+ def impl(c: BlackboxContext)(arg: c.Tree) = {
+ import c.universe._
+ q"""println($arg)"""
+ }
+
+ def foo(arg: String): Unit = macro impl
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroRuntime/Plugin_1.scala b/test/files/run/macroPlugins-macroRuntime/Plugin_1.scala
new file mode 100644
index 0000000000..a55adadb48
--- /dev/null
+++ b/test/files/run/macroPlugins-macroRuntime/Plugin_1.scala
@@ -0,0 +1,20 @@
+package macroRuntime
+
+import scala.tools.nsc.Global
+import scala.tools.nsc.plugins.{Plugin => NscPlugin}
+
+class Plugin(val global: Global) extends NscPlugin {
+ import global._
+ import analyzer._
+
+ val name = "macroRuntime"
+ val description = "A sample analyzer plugin that overrides macroRuntime."
+ val components = Nil
+ addMacroPlugin(MacroPlugin)
+
+ object MacroPlugin extends MacroPlugin {
+ override def pluginsMacroRuntime(expandee: Tree): Option[MacroRuntime] = Some({
+ case MacroArgs(_, List(msg)) => q"""println("hijacked")"""
+ })
+ }
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroRuntime/Test_3.flags b/test/files/run/macroPlugins-macroRuntime/Test_3.flags
new file mode 100644
index 0000000000..966df731d0
--- /dev/null
+++ b/test/files/run/macroPlugins-macroRuntime/Test_3.flags
@@ -0,0 +1 @@
+-Xplugin:. \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroRuntime/Test_3.scala b/test/files/run/macroPlugins-macroRuntime/Test_3.scala
new file mode 100644
index 0000000000..a54d608178
--- /dev/null
+++ b/test/files/run/macroPlugins-macroRuntime/Test_3.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ Macros.foo("1")
+ Macros.foo("2")
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-macroRuntime/scalac-plugin.xml b/test/files/run/macroPlugins-macroRuntime/scalac-plugin.xml
new file mode 100644
index 0000000000..8001af1054
--- /dev/null
+++ b/test/files/run/macroPlugins-macroRuntime/scalac-plugin.xml
@@ -0,0 +1,4 @@
+<plugin>
+ <name>macro-runtime</name>
+ <classname>macroRuntime.Plugin</classname>
+</plugin> \ No newline at end of file
diff --git a/test/files/run/macroPlugins-namerHooks.check b/test/files/run/macroPlugins-namerHooks.check
new file mode 100644
index 0000000000..c2db5935d4
--- /dev/null
+++ b/test/files/run/macroPlugins-namerHooks.check
@@ -0,0 +1,45 @@
+enterSym(package <empty> { case class C extends scala.Product with scala.Serializable { <caseaccessor> <paramaccessor> val x: Int = _; <caseaccessor> <paramaccessor> val y: Int = _; def <init>(x: Int, y: Int) = { super.<init>(); () } } })
+enterSym(case class C extends scala.Product with scala.Serializable { <caseaccessor> <paramaccessor> val x: Int = _; <caseaccessor> <paramaccessor> val y: Int = _; def <init>(x: Int, y: Int) = { super.<init>(); () } })
+ensureCompanionObject(case class C extends scala.Product with scala.Serializable { <caseaccessor> <paramaccessor> val x: Int = _; <caseaccessor> <paramaccessor> val y: Int = _; def <init>(x: Int, y: Int) = { super.<init>(); () } }, ...)
+enterSym(<synthetic> object C extends runtime.this.AbstractFunction2[Int, Int, C] { def <init>() = { super.<init>(); () }; final override <synthetic> def toString() = "C" })
+enterStat(case class C extends scala.Product with scala.Serializable { <caseaccessor> <paramaccessor> val x: Int = _; <caseaccessor> <paramaccessor> val y: Int = _; def <init>(x: Int, y: Int) = { super.<init>(); () } })
+enterSym(<caseaccessor> <paramaccessor> val x: Int = _)
+enterSym(<caseaccessor> <paramaccessor> val y: Int = _)
+enterSym(def <init>(x: Int, y: Int) = { super.<init>(); () })
+enterSym(<synthetic> def copy(x = x, y = y) = new C(x, y))
+enterStat(<caseaccessor> <paramaccessor> private[this] val x: Int = _)
+enterStat(<caseaccessor> <paramaccessor> private[this] val y: Int = _)
+enterStat(def <init>(x: Int, y: Int) = { super.<init>(); () })
+enterSym(<caseaccessor> <paramaccessor> private[this] val x: Int = _)
+enterSym(<caseaccessor> <paramaccessor> private[this] val y: Int = _)
+enterSym(def <init>(x: Int, y: Int) = { super.<init>(); () })
+enterSym(super.<init>())
+enterStat(super.<init>())
+enterSym(<synthetic> def copy$default$1 = x)
+enterSym(<synthetic> def copy$default$2 = y)
+enterSym(<synthetic> var acc: Int = -889275714)
+enterSym(acc = Statics.this.mix(acc, x))
+enterSym(acc = Statics.this.mix(acc, y))
+enterStat(<synthetic> var acc: Int = -889275714)
+enterStat(acc = Statics.this.mix(acc, x))
+enterStat(acc = Statics.this.mix(acc, y))
+enterSym(<synthetic> val C$1: C = x$1.asInstanceOf[C])
+enterStat(<synthetic> val C$1: C = x$1.asInstanceOf[C])
+enterSym(def <init>() = { super.<init>(); () })
+enterSym(final override <synthetic> def toString() = "C")
+enterSym(case <synthetic> def apply(x: Int, y: Int): C = new C(x, y))
+enterSym(case <synthetic> def unapply(x$0: C) = if (x$0.==(null)) scala.this.None else Some(scala.Tuple2(x$0.x, x$0.y)))
+enterStat(def <init>() = { super.<init>(); () })
+enterStat(final override <synthetic> def toString() = "C")
+enterSym(def <init>() = { super.<init>(); () })
+enterSym(final override <synthetic> def toString() = "C")
+enterSym(super.<init>())
+enterStat(super.<init>())
+enterSym(case <synthetic> val x1: Int = x$1)
+enterStat(case <synthetic> val x1: Int = x$1)
+enterSym(case <synthetic> val x1: Any = x$1)
+enterSym(case5(){ if (x1.isInstanceOf[C]) matchEnd4(true) else case6() })
+enterSym(case6(){ matchEnd4(false) })
+enterStat(case <synthetic> val x1: Any = x$1)
+enterStat(case5(){ if (x1.isInstanceOf[C]) matchEnd4(true) else case6() })
+enterStat(case6(){ matchEnd4(false) })
diff --git a/test/files/run/macroPlugins-namerHooks.scala b/test/files/run/macroPlugins-namerHooks.scala
new file mode 100644
index 0000000000..b0f29cbbed
--- /dev/null
+++ b/test/files/run/macroPlugins-namerHooks.scala
@@ -0,0 +1,38 @@
+import scala.tools.partest._
+import scala.tools.nsc._
+
+object Test extends DirectTest {
+ override def extraSettings: String = "-usejavacp"
+
+ def code = """
+ case class C(x: Int, y: Int)
+ """.trim
+
+ def show() {
+ val global = newCompiler()
+ import global._
+ import analyzer._
+
+ val output = collection.mutable.ListBuffer[String]()
+
+ object macroPlugin extends MacroPlugin {
+ override def pluginsEnterSym(namer: Namer, tree: Tree): Boolean = {
+ output += s"enterSym(${tree.toString.replace('\n', ' ')})"
+ namer.enterSym(tree)
+ true
+ }
+ override def pluginsEnsureCompanionObject(namer: Namer, cdef: ClassDef, creator: ClassDef => Tree = companionModuleDef(_)): Option[Symbol] = {
+ output += s"ensureCompanionObject(${cdef.toString.replace('\n', ' ')}, ...)"
+ Some(namer.ensureCompanionObject(cdef, creator))
+ }
+ override def pluginsEnterStats(typer: Typer, stats: List[Tree]): List[Tree] = {
+ stats.foreach(stat => output += s"enterStat(${stat.toString.replace('\n', ' ')})")
+ stats
+ }
+ }
+
+ addMacroPlugin(macroPlugin)
+ compileString(global)(code)
+ println(output.mkString("\n"))
+ }
+}
diff --git a/test/files/run/macroPlugins-typedMacroBody.check b/test/files/run/macroPlugins-typedMacroBody.check
new file mode 100644
index 0000000000..b6f8436189
--- /dev/null
+++ b/test/files/run/macroPlugins-typedMacroBody.check
@@ -0,0 +1,2 @@
+impl1
+impl2
diff --git a/test/files/run/macroPlugins-typedMacroBody/Macros_2.flags b/test/files/run/macroPlugins-typedMacroBody/Macros_2.flags
new file mode 100644
index 0000000000..966df731d0
--- /dev/null
+++ b/test/files/run/macroPlugins-typedMacroBody/Macros_2.flags
@@ -0,0 +1 @@
+-Xplugin:. \ No newline at end of file
diff --git a/test/files/run/macroPlugins-typedMacroBody/Macros_2.scala b/test/files/run/macroPlugins-typedMacroBody/Macros_2.scala
new file mode 100644
index 0000000000..fa8522e729
--- /dev/null
+++ b/test/files/run/macroPlugins-typedMacroBody/Macros_2.scala
@@ -0,0 +1,18 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.BlackboxContext
+
+object Macros {
+ def impl1(c: BlackboxContext) = {
+ import c.universe._
+ q"""println("impl1")"""
+ }
+
+ def impl2(c: BlackboxContext) = {
+ import c.universe._
+ q"""println("impl2")"""
+ }
+
+ def foo1: Unit = macro 1
+
+ def foo2: Unit = macro 2
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-typedMacroBody/Plugin_1.scala b/test/files/run/macroPlugins-typedMacroBody/Plugin_1.scala
new file mode 100644
index 0000000000..4632c36ef5
--- /dev/null
+++ b/test/files/run/macroPlugins-typedMacroBody/Plugin_1.scala
@@ -0,0 +1,21 @@
+package typedMacroBody
+
+import scala.tools.nsc.Global
+import scala.tools.nsc.plugins.{Plugin => NscPlugin}
+
+class Plugin(val global: Global) extends NscPlugin {
+ import global._
+ import analyzer._
+
+ val name = "typedMacroBody"
+ val description = "A sample analyzer plugin that overrides typedMacroBody."
+ val components = Nil
+ addMacroPlugin(MacroPlugin)
+
+ object MacroPlugin extends MacroPlugin {
+ override def pluginsTypedMacroBody(typer: Typer, ddef: DefDef): Option[Tree] = {
+ val DefDef(_, _, _, _, _, Literal(Constant(num: Int))) = ddef
+ Some(typedMacroBody(typer, copyDefDef(ddef)(rhs = Ident(TermName("impl" + num)))))
+ }
+ }
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-typedMacroBody/Test_3.scala b/test/files/run/macroPlugins-typedMacroBody/Test_3.scala
new file mode 100644
index 0000000000..def9b5608a
--- /dev/null
+++ b/test/files/run/macroPlugins-typedMacroBody/Test_3.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ Macros.foo1
+ Macros.foo2
+} \ No newline at end of file
diff --git a/test/files/run/macroPlugins-typedMacroBody/scalac-plugin.xml b/test/files/run/macroPlugins-typedMacroBody/scalac-plugin.xml
new file mode 100644
index 0000000000..e223fa5dca
--- /dev/null
+++ b/test/files/run/macroPlugins-typedMacroBody/scalac-plugin.xml
@@ -0,0 +1,4 @@
+<plugin>
+ <name>typed-macro-body</name>
+ <classname>typedMacroBody.Plugin</classname>
+</plugin> \ No newline at end of file