scala.tools.nsc.Global Scala Examples

The following examples show how to use scala.tools.nsc.Global. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: AnalyzerPlugin.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.tools.nsc.plugins.{Plugin, PluginComponent}
import scala.tools.nsc.{Global, Phase}

final class AnalyzerPlugin(val global: Global) extends Plugin { plugin =>

  override def init(options: List[String], error: String => Unit): Boolean = {
    options.foreach { option =>
      val level = option.charAt(0) match {
        case '-' => Level.Off
        case '*' => Level.Info
        case '+' => Level.Error
        case _ => Level.Warn
      }
      val nameArg = if (level != Level.Warn) option.drop(1) else option
      if (nameArg == "_") {
        rules.foreach(_.level = level)
      } else {
        val (name, arg) = nameArg.split(":", 2) match {
          case Array(n, a) => (n, a)
          case Array(n) => (n, null)
        }
        rulesByName.get(name) match {
          case Some(rule) =>
            rule.level = level
            rule.argument = arg
          case None =>
            error(s"Unrecognized AVS analyzer rule: $name")
        }
      }
    }
    true
  }

  private lazy val rules = List(
    new ImportJavaUtil(global),
    new VarargsAtLeast(global),
    new CheckMacroPrivate(global),
    new ExplicitGenerics(global),
    new ValueEnumExhaustiveMatch(global),
    new ShowAst(global),
    new FindUsages(global),
    new CheckBincompat(global),
    new Any2StringAdd(global),
    new ThrowableObjects(global)
  )

  private lazy val rulesByName = rules.map(r => (r.name, r)).toMap

  val name = "AVSystemAnalyzer"
  val description = "AVSystem custom Scala static analyzer"
  val components: List[PluginComponent] = List(component)

  private object component extends PluginComponent {
    val global: plugin.global.type = plugin.global
    val runsAfter = List("typer")
    override val runsBefore = List("patmat", "silencer")
    val phaseName = "avsAnalyze"

    import global._

    def newPhase(prev: Phase) = new StdPhase(prev) {
      def apply(unit: CompilationUnit): Unit =
        rules.foreach(rule => if (rule.level != Level.Off) rule.analyze(unit.asInstanceOf[rule.global.CompilationUnit]))
    }
  }

} 
Example 2
Source File: CompanionUtils.scala    From chimney   with Apache License 2.0 5 votes vote down vote up
package io.scalaland.chimney.internal.utils

import scala.reflect.macros.{blackbox, runtime}
import scala.tools.nsc.Global

trait CompanionUtils {

  val c: blackbox.Context

  // Copied from Magnolia: https://github.com/propensive/magnolia/blob/master/core/shared/src/main/scala/globalutil.scala

  // From Shapeless: https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/generic.scala#L698
  // Cut-n-pasted (with most original comments) and slightly adapted from
  // https://github.com/scalamacros/paradise/blob/c14c634923313dd03f4f483be3d7782a9b56de0e/plugin/src/main/scala/org/scalamacros/paradise/typechecker/Namers.scala#L568-L613
  def patchedCompanionRef(c: blackbox.Context)(tpe: c.Type): c.Tree = {
    // see https://github.com/scalamacros/paradise/issues/7
    // also see https://github.com/scalamacros/paradise/issues/64

    val global = c.universe.asInstanceOf[Global]
    val typer = c.asInstanceOf[runtime.Context].callsiteTyper.asInstanceOf[global.analyzer.Typer]
    val ctx = typer.context
    val globalType = tpe.asInstanceOf[global.Type]
    val original = globalType.typeSymbol
    val owner = original.owner
    val companion = original.companion.orElse {
      import global.{abort => aabort, _}
      implicit class PatchedContext(ctx: global.analyzer.Context) {
        trait PatchedLookupResult { def suchThat(criterion: Symbol => Boolean): Symbol }
        def patchedLookup(name: Name, expectedOwner: Symbol) = new PatchedLookupResult {
          override def suchThat(criterion: Symbol => Boolean): Symbol = {
            var res: Symbol = NoSymbol
            var ctx = PatchedContext.this.ctx
            while (res == NoSymbol && ctx.outer != ctx) {
              // NOTE: original implementation says `val s = ctx.scope lookup name`
              // but we can't use it, because Scope.lookup returns wrong results when the lookup is ambiguous
              // and that triggers https://github.com/scalamacros/paradise/issues/64
              val s = {
                val lookupResult = ctx.scope.lookupAll(name).filter(criterion).toList
                lookupResult match {
                  case Nil          => NoSymbol
                  case List(unique) => unique
                  case _ =>
                    aabort(s"unexpected multiple results for a companion symbol lookup for $original#{$original.id}")
                }
              }
              if (s != NoSymbol && s.owner == expectedOwner)
                res = s
              else
                ctx = ctx.outer
            }
            res
          }
        }
      }

      ctx.patchedLookup(original.name.companionName, owner) suchThat { sym =>
        (original.isTerm || sym.hasModuleFlag) && (sym isCoDefinedWith original)
      }
    }

    global.gen.mkAttributedRef(globalType.prefix, companion).asInstanceOf[c.Tree]
  }
} 
Example 3
Source File: InjectReporter.scala    From scala-clippy   with Apache License 2.0 5 votes vote down vote up
package com.softwaremill.clippy

import scala.reflect.internal.util.Position
import scala.tools.nsc.plugins.PluginComponent
import scala.tools.nsc.{Global, Phase}


abstract class InjectReporter(
    handleError: (Position, String) => String,
    getFatalWarningAdvice: String => Option[Warning],
    superGlobal: Global
) extends PluginComponent {

  override val global = superGlobal
  def colorsConfig: ColorsConfig
  def isEnabled: Boolean
  override val runsAfter  = List[String]("parser")
  override val runsBefore = List[String]("namer")
  override val phaseName  = "inject-clippy-reporter"

  override def newPhase(prev: Phase) = new Phase(prev) {

    override def name = phaseName

    override def description = "Switches the reporter to Clippy's reporter chain"

    override def run(): Unit =
      if (isEnabled) {
        val r = global.reporter
        global.reporter = new FailOnWarningsReporter(
          new DelegatingReporter(r, handleError, colorsConfig),
          getFatalWarningAdvice,
          colorsConfig
        )
      }
  }

} 
Example 4
Source File: Definitions.scala    From scalaz-plugin   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package scalaz.plugin

import scala.tools.nsc.Global

abstract class Definitions {
  val global: Global
  import global._, analyzer._

  def init(): Unit = {
    ScalazPackage
    ScalazMetaPackage
    MinimalAttr
  }

  

  lazy val ScalazPackage     = ensurePackage(rootMirror.RootClass, "scalaz")
  lazy val ScalazMetaPackage = ensurePackage(ScalazPackage.moduleClass, "meta")

  lazy val UnmixinAttr: ClassSymbol   = rootMirror.getRequiredClass("scalaz.meta.unmixin")
  lazy val InstancesAttr: ClassSymbol = rootMirror.getRequiredClass("scalaz.meta.instances")

  lazy val TypeclassClass: ClassSymbol = rootMirror.getRequiredClass("scalaz.meta.Typeclass")
  lazy val TypeclassType: Type         = TypeclassClass.tpe
  lazy val OrphanAttr: ClassSymbol     = rootMirror.getRequiredClass("scalaz.meta.orphan")
  lazy val EnableOrphansFlag: ClassSymbol =
    rootMirror.getRequiredClass("scalaz.meta.features.orphans")

  lazy val MinimalAttr =
    rootMirror.getClassIfDefined(TypeName("scalaz.meta.minimal")).orElse {
      val scope = newScope
      val ann = ScalazMetaPackage.moduleClass
        .newClassWithInfo(
          TypeName("minimal"),
          definitions.StaticAnnotationClass.typeOfThis :: Nil,
          scope,
          newFlags = Flag.SYNTHETIC
        )
      val ctor = ann.newConstructor(NoPosition)
      val param = ctor
        .newValueParameter(TermName("defns"))
        .setInfo(typeRef(NoPrefix, definitions.RepeatedParamClass, definitions.AnyTpe :: Nil))
      ann.info.decls.enter {
        ctor.setInfo(MethodType(param :: Nil, ann.typeOfThis))
      }

      ScalazMetaPackage.moduleClass.info.decls.enter(ann)
    }

  private def ensurePackage(owner: Symbol, name: String): Symbol = {
    val emptyTempl = (
      Template(Nil, noSelfType, Nil)
        setSymbol NoSymbol
        setType NoType
    )
    rootMirror.getPackageIfDefined(TermName(owner.name + name)).orElse {
      newNamer(NoContext.make(emptyTempl, owner, owner.info.decls))
        .createPackageSymbol(NoPosition, Ident(TermName(name)))
    }
  }
} 
Example 5
Source File: SCTags.scala    From sctags   with Apache License 2.0 5 votes vote down vote up
package sctags

import scala.tools.nsc.{Settings, Global}
import scala.tools.nsc.reporters.StoreReporter

import scala.collection.mutable.ListBuffer


import java.io.File
import java.io.PrintStream

object SCTags extends Parsing with TagGeneration
{

  import FileUtils._;

  var outputFile: String = "tags";
  var recurse = false;
  var etags = false

  def parseOpt(args:List[String]): List[String] =
    args match {
      case ("-f" |"-o")         :: file :: rest => outputFile = file; parseOpt(rest)
      case ("-R" |"--recurse" ) :: rest => recurse = true;            parseOpt(rest)
      case ("-e" |"--etags"   ) :: rest => etags = true;              parseOpt(rest)
      case files  => files
    }

  def error(str: String) = System.err.println("Error: " + str);
  val settings = new Settings(error);
  val reporter = new StoreReporter;
  val compiler = new Global(settings, reporter);


  def run(fnames: Seq[String]) {
    val files = new ListBuffer[File]
    fnames foreach { fname =>
      val file = new File(fname)
      if (file.isDirectory) {
        if (recurse)
          files ++= listFilesRecursive(file, {(f: File) => f.getName.endsWith(".scala")})
        else
          System.err.println("Skipping directory " + fname);
      } else {
        if (file.getName.endsWith(".scala"))
          files += file
        else
          System.err.println("Skipping file " + fname);
      }
    }

    if (files.nonEmpty) {
      val tags = files.map(f => (f.getPath, generateTags(parse(f))))
      val output = outputFile match {
        case "-" => Console.out
        case "tags" if etags =>  new PrintStream("TAGS")
        case x => new PrintStream(x)
      }

      if (etags) {
        ETags.generate(tags, output)
      } else {
        CTags.generate(tags, output)
      }
    }
  }

  def main(args: Array[String]): Unit = {
    val fnames = parseOpt(args.toList)
    run(fnames)
  }
} 
Example 6
Source File: Parsing.scala    From sctags   with Apache License 2.0 5 votes vote down vote up
package sctags

import scala.tools.nsc.{Global, CompilationUnits}
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.ast.Trees
import scala.tools.nsc.ast.parser.SyntaxAnalyzer
import scala.reflect.internal.util.BatchSourceFile

import java.io.File;

trait Parsing { this: SCTags.type =>
  import compiler.syntaxAnalyzer._
  import compiler._

  def parse(af: AbstractFile): Tree =
    parse(new CompilationUnit(new BatchSourceFile(af)))

  def parse(f: File): Tree =
    parse(AbstractFile.getFile(f))

  def parse(fname: String): Tree =
    parse(AbstractFile.getFile(fname))

  def parse(cu: CompilationUnit): Tree = {
    new compiler.Run
    val parser = new UnitParser(cu)
    val tree = parser.compilationUnit
    compiler.analyzer.newNamer(compiler.analyzer.rootContext(cu, tree, false)).enterSym(tree)
    tree
  }
} 
Example 7
Source File: AnnotationDataBuilder.scala    From ScalaClean   with Apache License 2.0 5 votes vote down vote up
package org.scalaclean.analysis.plugin

import org.scalaclean.analysis.{AnnotationData, ExtensionData}

import scala.tools.nsc.Global

object AnnotationDataBuilder {
  def buildSimpleAnnotation(g: Global)(annotated: g.Tree, annotation: g.AnnotationInfo): ExtensionData = {
    def print(assoc: g.ClassfileAnnotArg): String = {
      import g._
      assoc match {
        case LiteralAnnotArg(const) => const.value.toString
        case ArrayAnnotArg(args) => args.map(print).mkString(";")
        case NestedAnnotArg(annInfo) =>
          val clazz = annInfo.tpe.typeSymbol.fullName
          //TODO if we really need it
          clean(s"@$clazz(<TODO>)")
        case UnmappableAnnotArg => ???
        case ScalaSigBytes(_) => ???
      }
    }

    val clazz = annotation.tpe.typeSymbol.fullName
    val targetPos = annotated.pos
    val pos = annotation.pos
    var values = Map.empty[String, String]
    annotation.assocs foreach {
      case (name, assoc) => values = values.updated(name.toString, clean(print(assoc)))
    }
    //TODO cope better with trees - this should cope with @foo(1,2,"hello")
    //TODO cope better with trees - need @foo(x = 1, y = 2, z = "hello")
    for (i <- annotation.scalaArgs.indices) {
      values = values.updated(i.toString, clean(annotation.constantAtIndex(i).map(_.value.toString).getOrElse("<<<TODO>>>")))
    }
    val start = if (pos.isDefined) pos.start - targetPos.start else Int.MinValue
    val end = if (pos.isDefined) pos.end - targetPos.start else Int.MinValue
    AnnotationData(start, end, clazz, values)
  }

  private def clean(s: String): String = s. //
    replace(',', ';').
    replace("\n", "\\n").
    replace("\r", "\\r")

} 
Example 8
Source File: ScalaCleanCompilerPlugin.scala    From ScalaClean   with Apache License 2.0 5 votes vote down vote up
package org.scalaclean.analysis

import org.scalaclean.analysis.plugin.{ExtensionPlugin, ExtensionPluginFactory, JunitPlugin, ModsPlugin}

import scala.tools.nsc.Global
import scala.tools.nsc.plugins.{Plugin, PluginComponent}

class ScalaCleanCompilerPlugin(override val global: Global) extends Plugin {

  override val name: String = "scalaclean-analysis-plugin"
  override val description: String = "ScalaClean analysis plugin"

  val component = new ScalaCompilerPluginComponent(global)

  //hardcoded for the moment
  component.extensions += ModsPlugin.create(component, "")
  component.extensions += JunitPlugin.create(component, "")

  override def processOptions(
                               options: List[String],
                               error: String => Unit): Unit = {

    import scala.reflect.runtime.universe
    val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)

    val realOptions = options.distinct
    component.options = realOptions
    for (option <- realOptions) {
      if (option == "debug:true") {
        component.debug = true
      } else if (option.startsWith("extension:")) {
        val end = {
          val end = option.indexOf(':', 10)
          if (end == -1) option.length else end
        }
        val fqn = option.substring(10, end)
        val module = runtimeMirror.staticModule(fqn)
        runtimeMirror.reflectModule(module).instance match {
          case valid: ExtensionPluginFactory => component.extensions += valid.create(component, option.substring(end))
          case null => throw new IllegalArgumentException("not a valid Extension FQN - expected the name of an object")
          case invalid => throw new IllegalArgumentException(s"not a valid Extension FQN - ${invalid.getClass.getName} is not a ${classOf[ExtensionDescriptor[_]].getName}")
        }
      } else if (option.startsWith("srcdirs:")) {
        component.sourceDirs = option.substring(8).split(java.io.File.pathSeparatorChar).toList
      } else
        error(s"Option not recognised: $option")
    }
  }

  override val optionsHelp: Option[String] = Some( //
    s"""-P:$name:debug:true        Set debugging on the ScalaClean analysis plugin
       |-P:$name:srcdirs           The path of sources, separated by ${java.io.File.pathSeparatorChar}
       |-P:$name:extension:<fqn>   Add an extension dataset. FQN is the fully qualified name of the appropriate ExtensionDescriptor object
       |""".stripMargin)

  override val components: List[PluginComponent] = List(component)
} 
Example 9
Source File: AnalyzerTest.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import org.scalactic.source.Position
import org.scalatest.Assertions

import scala.reflect.internal.util.BatchSourceFile
import scala.tools.nsc.plugins.Plugin
import scala.tools.nsc.{Global, Settings}

trait AnalyzerTest { this: Assertions =>
  val settings = new Settings
  settings.usejavacp.value = true
  settings.pluginOptions.value ++= List("AVSystemAnalyzer:+_")

  val compiler: Global = new Global(settings) { global =>
    override protected def loadRoughPluginsList(): List[Plugin] =
      new AnalyzerPlugin(global) :: super.loadRoughPluginsList()
  }

  def compile(source: String): Unit = {
    compiler.reporter.reset()
    val run = new compiler.Run
    run.compileSources(List(new BatchSourceFile("test.scala", source)))
  }

  def assertErrors(source: String)(implicit pos: Position): Unit = {
    compile(source)
    assert(compiler.reporter.hasErrors)
  }

  def assertErrors(errors: Int, source: String)(implicit pos: Position): Unit = {
    compile(source)
    assert(compiler.reporter.errorCount == errors)
  }

  def assertNoErrors(source: String)(implicit pos: Position): Unit = {
    compile(source)
    assert(!compiler.reporter.hasErrors)
  }
} 
Example 10
Source File: ExplicitGenerics.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.tools.nsc.Global

class ExplicitGenerics(g: Global) extends AnalyzerRule(g, "explicitGenerics") {

  import global._

  lazy val explicitGenericsAnnotTpe = classType("com.avsystem.commons.annotation.explicitGenerics")

  def analyze(unit: CompilationUnit) = if (explicitGenericsAnnotTpe != NoType) {
    def requiresExplicitGenerics(sym: Symbol): Boolean =
      sym != NoSymbol && (sym :: sym.overrides).flatMap(_.annotations).exists(_.tree.tpe <:< explicitGenericsAnnotTpe)

    def analyzeTree(tree: Tree): Unit = analyzer.macroExpandee(tree) match {
      case `tree` | EmptyTree =>
        tree match {
          case t@TypeApply(pre, args) if requiresExplicitGenerics(pre.symbol) =>
            val inferredTypeParams = args.forall {
              case tt: TypeTree => tt.original == null || tt.original == EmptyTree
              case _ => false
            }
            if (inferredTypeParams) {
              report(t.pos, s"${pre.symbol} requires that its type arguments are explicit (not inferred)")
            }
          case _ =>
        }
        tree.children.foreach(analyzeTree)
      case prevTree =>
        analyzeTree(prevTree)
    }
    analyzeTree(unit.body)
  }
} 
Example 11
Source File: CheckMacroPrivate.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.tools.nsc.Global

class CheckMacroPrivate(g: Global) extends AnalyzerRule(g, "macroPrivate") {

  import global._

  lazy val macroPrivateAnnotTpe = classType("com.avsystem.commons.annotation.macroPrivate")

  def analyze(unit: CompilationUnit) = if (macroPrivateAnnotTpe != NoType) {
    def analyzeTree(tree: Tree): Unit = analyzer.macroExpandee(tree) match {
      case `tree` | EmptyTree =>
        tree match {
          case _: Ident | _: Select | _: SelectFromTypeTree | _: New
            if tree.symbol != null && tree.pos != NoPosition =>

            val sym = tree.symbol
            val macroPrivate = (sym :: sym.overrides).iterator
              .flatMap(_.annotations).exists(_.tree.tpe <:< macroPrivateAnnotTpe)
            if (macroPrivate) {
              report(tree.pos, s"$sym can only be used in macro-generated code")
            }
          case _ =>
        }
        tree.children.foreach(analyzeTree)
      case prevTree =>
        analyzeTree(prevTree)
    }
    analyzeTree(unit.body)
  }
} 
Example 12
Source File: ValueEnumExhaustiveMatch.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.collection.mutable
import scala.tools.nsc.Global

class ValueEnumExhaustiveMatch(g: Global) extends AnalyzerRule(g, "valueEnumExhaustiveMatch") {

  import global._

  lazy val valueEnumTpe: Type = classType("com.avsystem.commons.misc.ValueEnum")
  lazy val ExistentialType(_, TypeRef(miscPackageTpe, valueEnumCompanionSym, _)) =
    classType("com.avsystem.commons.misc.ValueEnumCompanion")

  def analyze(unit: CompilationUnit): Unit = if (valueEnumTpe != NoType) {
    unit.body.foreach(analyzeTree {
      case tree@Match(selector, cases) if selector.tpe <:< valueEnumTpe =>
        val expectedCompanionTpe = TypeRef(miscPackageTpe, valueEnumCompanionSym, List(selector.tpe))
        val companion = selector.tpe.typeSymbol.companion
        val companionTpe = companion.toType
        if (companionTpe <:< expectedCompanionTpe) {
          val unmatched = new mutable.LinkedHashSet[Symbol]
          companionTpe.decls.iterator
            .filter(s => s.isVal && s.isFinal && !s.isLazy && s.typeSignature <:< selector.tpe)
            .map(_.getterIn(companion)).filter(_.isPublic).foreach(unmatched.add)

          def findMatchedEnums(pattern: Tree): Unit = pattern match {
            case Bind(_, body) => findMatchedEnums(body)
            case Alternative(patterns) => patterns.foreach(findMatchedEnums)
            case Ident(termNames.WILDCARD) => unmatched.clear()
            case _: Ident | _: Select => unmatched.remove(pattern.symbol)
            case _: Literal =>
            case _ => unmatched.clear()
          }

          cases.iterator.foreach {
            case CaseDef(pattern, EmptyTree, _) => findMatchedEnums(pattern)
            case _ => unmatched.clear()
          }

          if (unmatched.nonEmpty) {
            val what =
              if (unmatched.size > 1) "inputs: " + unmatched.map(_.nameString).mkString(", ")
              else "input: " + unmatched.head.nameString
            report(tree.pos, "match may not be exhaustive.\nIt would fail on the following " + what)
          }
        }
    })
  }
} 
Example 13
Source File: ThrowableObjects.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.tools.nsc.Global

class ThrowableObjects(g: Global) extends AnalyzerRule(g, "throwableObjects", Level.Warn) {

  import global._

  private lazy val throwableTpe = typeOf[Throwable]
  private lazy val throwableSym = throwableTpe.dealias.typeSymbol

  def analyze(unit: CompilationUnit): Unit = unit.body.foreach {
    case md: ModuleDef =>
      val tpe = md.symbol.typeSignature
      def fillInStackTraceSym: Symbol =
        tpe.member(TermName("fillInStackTrace")).alternatives.find(_.paramLists == List(Nil)).get

      if (tpe <:< throwableTpe && fillInStackTraceSym.owner == throwableSym) {
        report(md.pos, "objects should never extend Throwable unless they have no stack trace")
      }
    case _ =>
  }
} 
Example 14
Source File: ShowAst.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.tools.nsc.Global

class ShowAst(g: Global) extends AnalyzerRule(g, "showAst", Level.Error) {

  import global._

  lazy val showAstAnnotType: Type = classType("com.avsystem.commons.annotation.showAst")

  def analyze(unit: CompilationUnit) = if (showAstAnnotType != NoType) {
    def analyzeTree(tree: Tree): Unit = analyzer.macroExpandee(tree) match {
      case `tree` | EmptyTree =>
        tree match {
          case Annotated(annot, arg) if annot.tpe <:< showAstAnnotType =>
            report(arg.pos, showCode(arg))
          case Typed(expr, tpt) if tpt.tpe.annotations.exists(_.tpe <:< showAstAnnotType) =>
            report(expr.pos, showCode(expr))
          case _: MemberDef if tree.symbol.annotations.exists(_.tpe <:< showAstAnnotType) =>
            report(tree.pos, showCode(tree))
          case _ =>
        }
        tree.children.foreach(analyzeTree)
      case prevTree =>
        analyzeTree(prevTree)
    }
    analyzeTree(unit.body)
  }
} 
Example 15
Source File: ScaladocExtractor.scala    From naptime   with Apache License 2.0 5 votes vote down vote up
package org.coursera.naptime.sbt

import sbt.File

import scala.reflect.internal.util.Position
import scala.tools.nsc.Global
import scala.tools.nsc.doc.DocFactory
import scala.tools.nsc.doc.Settings
import scala.tools.nsc.doc.base.CommentFactoryBase
import scala.tools.nsc.doc.base.LinkTo
import scala.tools.nsc.doc.base.LinkToExternal
import scala.tools.nsc.doc.base.LinkToMember
import scala.tools.nsc.doc.base.MemberLookupBase
import scala.tools.nsc.doc.base.comment.Comment
import scala.tools.nsc.doc.model.MemberEntity
import scala.tools.nsc.reporters.AbstractReporter

object ScaladocExtractor {

  class ScaladocCommentFactory(compiler: Global, settings: Settings)
    extends CommentFactoryBase with MemberLookupBase {

    override val global: compiler.type = compiler

    override def internalLink(sym: global.Symbol, site: global.Symbol): Option[LinkTo] = None

    override def findExternalLink(sym: global.Symbol, name: String): Option[LinkToExternal] = None

    override def warnNoLink: Boolean = false

    override def toString(link: LinkTo): String = link.toString

    override def chooseLink(links: List[LinkTo]): LinkTo = {
      val members = links.collect {
        case linkToMember@LinkToMember(member: MemberEntity, _) => (member, linkToMember)
      }
      if (members.isEmpty) {
        links.head
      } else {
        members.min(Ordering[MemberEntity].on[(MemberEntity, LinkTo)](_._1))._2
      }
    }

    private[this] def parseComment(symbol: compiler.Symbol, docComment: compiler.DocComment): Comment = {
      parseAtSymbol(docComment.raw, "", docComment.pos, Some(symbol))
    }

    def getComments: Map[String, Comment] = {
      compiler.docComments.map { case (symbol, docComment) =>
        symbol.fullName -> parseComment(symbol, docComment)
      }.toMap
    }
  }

  def analyze(sourceFiles: Seq[File]): Map[String, Comment] = {
    val settings = new Settings(error => (), message => ())
    val scalaLibraryPath = ScalaLibraryLocator.getPath.getOrElse {
      throw new Exception("Could not get path to SBT's Scala library for Scaladoc generation")
    }
    
    settings.bootclasspath.append(scalaLibraryPath)
    settings.classpath.append(scalaLibraryPath)

    val reporter = new BlackHoleReporter(settings)
    val docFactory = new DocFactory(reporter, settings)
    val compiler = docFactory.compiler
    docFactory.makeUniverse(Left(sourceFiles.toList.map(_.getAbsolutePath)))

    val commentFactory = new ScaladocCommentFactory(compiler, settings)
    commentFactory.getComments
  }
}

class BlackHoleReporter(override val settings: Settings) extends AbstractReporter {
  override def display(pos: Position, msg: String, severity: Severity): Unit = ()
  override def displayPrompt(): Unit = ()
} 
Example 16
Source File: AnalyzerRule.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import java.io.{PrintWriter, StringWriter}

import scala.tools.nsc.Global
import scala.util.control.NonFatal

abstract class AnalyzerRule(val global: Global, val name: String, defaultLevel: Level = Level.Warn) {

  import global._

  var level: Level = defaultLevel
  var argument: String = _

  protected def classType(fullName: String): Type =
    try rootMirror.staticClass(fullName).asType.toType.erasure catch {
      case _: ScalaReflectionException => NoType
    }

  protected def analyzeTree(fun: PartialFunction[Tree, Unit])(tree: Tree): Unit =
    try fun.applyOrElse(tree, (_: Tree) => ()) catch {
      case NonFatal(t) =>
        val sw = new StringWriter
        t.printStackTrace(new PrintWriter(sw))
        reporter.error(tree.pos, s"Analyzer rule $this failed: " + sw.toString)
    }

  private def adjustMsg(msg: String): String = s"[AVS] $msg"

  protected def report(pos: Position, message: String): Unit =
    level match {
      case Level.Off =>
      case Level.Info => reporter.echo(pos, adjustMsg(message))
      case Level.Warn => reporter.warning(pos, adjustMsg(message))
      case Level.Error => reporter.error(pos, adjustMsg(message))
    }

  def analyze(unit: CompilationUnit): Unit

  override def toString: String =
    getClass.getSimpleName
}

sealed trait Level
object Level {
  case object Off extends Level
  case object Info extends Level
  case object Warn extends Level
  case object Error extends Level
} 
Example 17
Source File: VarargsAtLeast.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.tools.nsc.Global

class VarargsAtLeast(g: Global) extends AnalyzerRule(g, "varargsAtLeast") {

  import global._

  lazy val atLeastAnnotTpe = classType("com.avsystem.commons.annotation.atLeast")

  def analyze(unit: CompilationUnit): Unit = if (atLeastAnnotTpe != NoType) {
    def isVarargParam(tree: Tree) = tree match {
      case Typed(_, Ident(typeNames.WILDCARD_STAR)) => true
      case _ => false
    }

    unit.body.foreach(analyzeTree {
      case t@Apply(fun, args)
        if fun.tpe.params.lastOption.map(_.tpe.typeSymbol).contains(definitions.RepeatedParamClass) &&
          !args.lastOption.exists(isVarargParam) =>

        val required =
          fun.tpe.params.last.annotations.find(_.tree.tpe <:< atLeastAnnotTpe).map(_.tree.children.tail).collect {
            case List(Literal(Constant(n: Int))) => n
          }.getOrElse(0)

        val actual = args.size - fun.tpe.params.size + 1

        if (actual < required) {
          report(t.pos,
            s"This method requires at least $required arguments for its repeated parameter, $actual passed.")
        }
    })
  }
} 
Example 18
Source File: CheckBincompat.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.tools.nsc.Global

class CheckBincompat(g: Global) extends AnalyzerRule(g, "bincompat") {

  import global._

  private lazy val bincompatAnnotType = classType("com.avsystem.commons.annotation.bincompat")

  def analyze(unit: CompilationUnit): Unit =
    unit.body.foreach(analyzeTree {
      case tree@(_: Ident | _: Select | _: New) if tree.symbol != null &&
        tree.symbol.annotations.exists(_.tree.tpe <:< bincompatAnnotType) =>
        report(tree.pos, "Symbols annotated as @bincompat exist only for binary compatibility " +
          "and should not be used directly")
    })
} 
Example 19
Source File: Any2StringAdd.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.tools.nsc.Global

class Any2StringAdd(g: Global) extends AnalyzerRule(g, "any2stringadd", Level.Off) {

  import global._

  private lazy val any2stringaddSym =
    typeOf[Predef.type].member(TermName("any2stringadd")).alternatives.find(_.isMethod).get

  def analyze(unit: CompilationUnit): Unit = {
    unit.body.foreach(analyzeTree {
      case t if t.symbol == any2stringaddSym =>
        report(t.pos, "concatenating arbitrary values with strings is disabled, " +
          "use explicit toString or string interpolation")
    })
  }
} 
Example 20
Source File: ImportJavaUtil.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.tools.nsc.Global

class ImportJavaUtil(g: Global) extends AnalyzerRule(g, "importJavaUtil") {

  import global._

  def analyze(unit: CompilationUnit): Unit = {
    unit.body.foreach(analyzeTree {
      case tree@q"import java.util" =>
        report(tree.pos, "Don't import java.util: either import with rename (e.g. import java.{util => ju}) " +
          "or use type aliases from JavaInterop (e.g. JList, JSet, etc)")
    })
  }
} 
Example 21
Source File: FindUsages.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package analyzer

import scala.tools.nsc.Global

class FindUsages(g: Global) extends AnalyzerRule(g, "findUsages") {

  import global._

  lazy val rejectedSymbols: Set[String] =
    if (argument == null) Set.empty else argument.split(";").toSet

  override def analyze(unit: CompilationUnit): Unit = if (rejectedSymbols.nonEmpty) {
    unit.body.foreach { tree =>
      if (tree.symbol != null && rejectedSymbols.contains(tree.symbol.fullName)) {
        report(tree.pos, s"found usage of ${tree.symbol.fullName}")
      }
    }
  }
} 
Example 22
Source File: Runtimes.scala    From AppCrawler   with Apache License 2.0 5 votes vote down vote up
package com.testerhome.appcrawler

import java.io.File

import scala.reflect.internal.util.ScalaClassLoader.URLClassLoader
import scala.tools.nsc.interpreter.IMain
import scala.tools.nsc.{Global, Settings}


class Runtimes(val outputDir:String="") extends CommonLog{
  private val settingsCompile=new Settings()

  if(outputDir.nonEmpty){
    val tempDir=new File(outputDir)
    if(tempDir.exists()==false){
      tempDir.mkdir()
    }
    settingsCompile.outputDirs.setSingleOutput(this.outputDir)
  }

  settingsCompile.deprecation.value = true // enable detailed deprecation warnings
  settingsCompile.unchecked.value = true // enable detailed unchecked warnings
  settingsCompile.usejavacp.value = true

  val global = new Global(settingsCompile)
  val run = new global.Run

  private val settingsEval=new Settings()
  settingsEval.deprecation.value = true // enable detailed deprecation warnings
  settingsEval.unchecked.value = true // enable detailed unchecked warnings
  settingsEval.usejavacp.value = true

  val interpreter = new IMain(settingsEval)

  def compile(fileNames:List[String]): Unit ={
    run.compile(fileNames)
  }

  def eval(code:String): Unit ={
    interpreter.interpret(code)
  }
  def reset(): Unit ={

  }



}

object Runtimes extends CommonLog{
  var instance=new Runtimes()
  var isLoaded=false
  def apply(): Unit ={

  }
  def eval(code:String): Unit ={
    if(isLoaded==false){
      log.info("first import")
      instance.eval("val driver=com.testerhome.appcrawler.AppCrawler.crawler.driver")
      instance.eval("def crawl(depth:Int)=com.testerhome.appcrawler.AppCrawler.crawler.crawl(depth)")
      isLoaded=true
    }
    log.info(code)
    instance.eval(code)
    log.info("eval finish")
  }

  def compile(fileNames:List[String]): Unit ={
    instance.compile(fileNames)
    isLoaded=false
  }
  def init(classDir:String=""): Unit ={
    instance=new Runtimes(classDir)
  }
  def reset(): Unit ={

  }
  def loadPlugins(pluginDir:String=""): List[Plugin] ={
    val pluginDirFile=new java.io.File(pluginDir)
    if(pluginDirFile.exists()==false){
      log.warn(s"no ${pluginDir} directory, skip")
      return Nil
    }
    val pluginFiles=pluginDirFile.list().filter(_.endsWith(".scala")).toList
    val pluginClassNames=pluginFiles.map(_.split(".scala").head)
    log.info(s"find plugins in ${pluginDir}")
    log.info(pluginFiles)
    log.info(pluginClassNames)
    val runtimes=new Runtimes(pluginDir)
    runtimes.compile(pluginFiles.map(pluginDirFile.getCanonicalPath+File.separator+_))
    val urls=Seq(pluginDirFile.toURI.toURL, getClass.getProtectionDomain.getCodeSource.getLocation)
    val loader=new URLClassLoader(urls, Thread.currentThread().getContextClassLoader)
    pluginClassNames.map(loader.loadClass(_).newInstance().asInstanceOf[Plugin])
  }
} 
Example 23
Source File: TypedHolesPlugin.scala    From scala-typed-holes   with Apache License 2.0 5 votes vote down vote up
package holes

import scala.collection.mutable
import scala.tools.nsc.{Global, Phase}
import scala.tools.nsc.transform.Transform
import scala.tools.nsc.ast.TreeDSL
import scala.tools.nsc.plugins.{Plugin, PluginComponent}

class TypedHolesPlugin(val global: Global) extends Plugin {
  val name = "typed-holes"
  val description = "Treat use of ??? as a hole and give a useful warning about it"

  private var logLevel: LogLevel = LogLevel.Warn

  override def init(options: List[String], error: String => Unit): Boolean = {
    for (option <- options) {
      if (option.startsWith("log-level:")) {
        option.substring("log-level:".length).toLowerCase match {
          case "info" =>
            logLevel = LogLevel.Info
          case "warn" =>
            logLevel = LogLevel.Warn
          case "error" =>
            logLevel = LogLevel.Error
          case other =>
            error(s"Unexpected log level value: '$other'")
        }
      } else {
        error(s"Unrecognised option: $option")
      }
    }
    true
  }

  val components = List(
    new NamedHolesComponent(this, global),
    new TypedHolesComponent(this, global, () => logLevel)
  )

} 
Example 24
Source File: NamedHolesComponent.scala    From scala-typed-holes   with Apache License 2.0 5 votes vote down vote up
package holes

import scala.tools.nsc.{Global, Phase}
import scala.tools.nsc.transform.Transform
import scala.tools.nsc.ast.TreeDSL
import scala.tools.nsc.plugins.{Plugin, PluginComponent}

class NamedHolesComponent(plugin: Plugin, val global: Global)
  extends PluginComponent with TreeDSL with Transform {

  override val phaseName: String = "named-holes"
  override val runsAfter: List[String] = List("parser")
  override val runsBefore: List[String] = List("namer")

  import global._

  override def newTransformer(unit: CompilationUnit): Transformer =
    new NamedHolesTransformer(unit)

  class NamedHolesTransformer(unit: CompilationUnit) extends Transformer {

    object NamedHole {
      val pattern = "^__([a-zA-Z0-9_]+)$".r

      def unapply(name: Name): Option[String] =
        pattern.unapplySeq(name.decoded.toString).flatMap(_.headOption)
    }

    override def transform(tree: Tree): Tree = {
      val t = super.transform(tree)
      t match {
        case Ident(NamedHole(name)) =>
          atPos(t.pos)(treeCopy.Ident(t, TermName("$qmark$qmark$qmark")))
            .updateAttachment(HoleName(name))
        case _ =>
          t
      }
    }

  }

} 
Example 25
Source File: NoMapIdentity.scala    From better-monadic-for   with MIT License 5 votes vote down vote up
package com.olegpy.bm4

import scala.reflect.internal.{Definitions, ModifierFlags, SymbolTable}
import scala.tools.nsc.Global
import scala.tools.nsc.ast.TreeDSL
import scala.tools.nsc.transform.TypingTransformers


trait NoMapIdentity extends TreeUtils {
  import global._

  def noMapIdentity: Boolean

  object NoMapIdentity {
    def unapply(tree: Tree): Option[Tree] = tree match {
      case _ if !noMapIdentity => None

      // plain monomorphic map
      case q"${sel @ q"$body.map"}[..$_](${IdentityFunction()})"
        if sel.hasAttachment[ForAttachment.type] &&
          tree.tpe =:= body.tpe =>
        Some(replaceTree(tree, body))

      // map with implicit parameters
      case q"${sel @ q"$body.map"}[..$_](${IdentityFunction()})(..$_)"
        if sel.hasAttachment[ForAttachment.type] &&
          tree.tpe =:= body.tpe =>
        Some(replaceTree(tree, body))

      // map on implicit conversion with implicit parameters (e.g. simulacrum ops)
      case q"${sel @ q"$_($body)(..$_).map"}[..$_](${IdentityFunction()})"
        if sel.hasAttachment[ForAttachment.type] &&
          body.tpe.widen =:= tree.tpe // body.tpe will be inferred to singleton type
        =>
        Some(replaceTree(tree, body))
      case _ =>
        None
    }
  }

  object IdentityFunction {
    def unapply(tree: Tree): Boolean = tree match {
      case Function(ValDef(mods, TermName(x), tpt, _) :: Nil, i @ Ident(TermName(x2)))
        if (x == x2) &&
          mods.flags == ModifierFlags.PARAM &&
          (i.tpe =:= tpt.tpe) =>
        true
      case Function(ValDef(_, _, tpt, EmptyTree) :: Nil, LiteralUnit(u))
        if tpt.tpe =:= definitions.UnitTpe && tpt.tpe =:= u.tpe =>
        true
      case _ =>
        false
    }
  }

  object LiteralUnit {
    def unapply(tree: Tree): Option[Tree] = tree match {
      case u @ Literal(Constant(())) =>
        Some(u)

      // In Scala 2:13, we get `(x$1: Unit @unchecked) match { case _ => () }`
      case u @ Match(Typed(Ident(TermName(x)), tpt),
                     List(
                       CaseDef(Ident(termNames.WILDCARD), EmptyTree, Literal(Constant(())))))
        if tpt.tpe =:= definitions.UnitTpe =>
        Some(u)

      case _ =>
        None
    }
  }
} 
Example 26
Source File: CompilerSetup.scala    From perf_tester   with Apache License 2.0 5 votes vote down vote up
package benchmarks

import java.io.File
import java.nio.file.{Files, Path}

import benchmarks.Main.rootPath

import scala.reflect.internal.util.Position
import scala.tools.nsc.{Global, Settings}
import scala.tools.nsc.reporters.Reporter
import scala.util.Try
import collection.JavaConverters._

case class CompilerSetup(rootPath: Path, providedScalacOptions: List[String]) {
  val outputDir: Path = rootPath.resolve("output")
  val currentOutput: Path = outputDir.resolve("classes")
	val scalacOptions = providedScalacOptions ++
    Try(Files.readAllLines(rootPath.resolve("scalac.opts")).asScala.flatMap(_.split(" +"))).getOrElse(Nil)

  IO.cleanDir(outputDir)
  Files.createDirectories(currentOutput)


  val cpJars = IO.jarsIn(rootPath.resolve("cpJars"))

  val reporter: Reporter = new Reporter { // We are ignoring all
    override protected def info0(pos: Position, msg: String, severity: this.Severity, force: Boolean): Unit = {
    //   println(s"[$severity] $pos: $msg") // Uncomment for to get compilation messages
    }
  }

  val settings: Settings = new Settings( msg => throw new RuntimeException(s"[ERROR] $msg") )
  configure(settings)

  val global: Global = new Global(settings, reporter)

  def configure(settings: Settings): Unit = {
    settings.outputDirs.setSingleOutput(currentOutput.toAbsolutePath.toString)
    settings.classpath.append(cpJars.mkString(File.pathSeparator))
    settings.processArguments(scalacOptions, processAll = true)
  }
} 
Example 27
Source File: IntegrationTest.scala    From scala-sculpt   with Apache License 2.0 5 votes vote down vote up
// Copyright (C) 2015-2020 Lightbend Inc. <http://lightbend.com>

package com.lightbend.tools.sculpt

import scala.tools.nsc.{ Settings, Global }
import scala.tools.nsc.io.VirtualDirectory
import scala.reflect.internal.util.BatchSourceFile

object Scaffold {

  val classes: String = {
    // this will be e.g. "2.11" or "2.12"
    val majorScalaVersion = {
      val v = scala.util.Properties.versionNumberString
      if (v matches ".*-(pre-\\w+|M\\d+|RC\\d+)") {
        v
      } else {
        v.split('.').take(2).mkString(".")
      }
    }
    val relative = s"./target/scala-$majorScalaVersion/classes"
    val file = new java.io.File(relative)
    assert(file.exists)
    file.getAbsolutePath
  }

  def defaultSettings: Settings = {
    val settings = new Settings
    settings.processArgumentString(
      s"-usejavacp -Xplugin:$classes -Xplugin-require:sculpt")
    settings.outputDirs.setSingleOutput(
      new VirtualDirectory("(memory)", None))
    settings
  }

  def analyze(code: String, classMode: Boolean = false): String = {
    val out = java.io.File.createTempFile("sculpt", "json", null)
    val modeSetting =
      if (classMode)
        " -P:sculpt:mode=class"
      else
        ""
    val settings = defaultSettings
    settings.processArgumentString(s"-P:sculpt:out=$out$modeSetting")
    val sources = List(new BatchSourceFile("<test>", code))
    val compiler = new Global(settings)
    (new compiler.Run).compileSources(sources)
    scala.io.Source.fromFile(out).mkString
  }

}

class IntegrationTest extends munit.FunSuite {
  def check(s: Sample): Unit = {
    assert(s.json == Scaffold.analyze(s.source))
    assert(s.classJson == Scaffold.analyze(s.source, classMode = true))
  }
  for (sample <- Samples.samples)
    test(sample.name) {
      check(sample)
    }
}