All Downloads are FREE. Search and download functionalities are using the official Maven repository.

.scala-fortify_2.13.15.1.1.4.source-code.Closure.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 2016-2024 Lightbend, Inc. All rights reserved.
 * No information contained herein may be reproduced or transmitted in any form
 * or by any means without the express written permission of Lightbend, Inc.
 */

package com.lightbend.tools.fortify.plugin

import scala.tools.nsc

import com.fortify.frontend.nst

import nst._
import nodes._

trait Closure[T <: nsc.ast.Trees with nsc.symtab.SymbolTable]
    extends TranslatorHelpers[T] {

  val global: T
  import global._

  val seenSymbols: collection.mutable.ListBuffer[Symbol]

  def closure(source: SourceFile): STExternalDeclarations = {
    var clazzes = Vector[STClassDecl]()
    val visited = collection.mutable.Set.empty[Symbol]
    while (seenSymbols.nonEmpty) {
      val batch = seenSymbols.toList.distinct.filterNot(visited)
      seenSymbols.clear()
      visited ++= batch
      for (symbol <- batch if source != symbol.pos.source && includeInClosure(symbol)) {
        val clazz = toClassDecl(symbol)
        val decls = symbol.info.decls.toList
          .sortBy(_.fullName) ++ (if (symbol.isJavaDefined && symbol.companion.hasCompleteInfo)
                                    symbol.companion.info.decls.toList
                                      .sortBy(_.fullName)
                                  else
                                    Seq())
        // lightbend/scala-fortify#437
        val sam = definitions.samOf(symbol.tpe) // maybe NoSymbol
        for (decl <- decls if decl == sam || alwaysInclude(decl) || visited(decl) && !omitMethod(decl))
          if (decl.isMethod)
            clazz.addFunction(toFunDecl(decl, paramNamesFromSymbol(decl)))
          else if (isField(decl)) {
            val field = toFieldDecl(decl)
            clazz.addField(field)
            if (symbol.isModule)
              field.addModifiers(NSTModifiers.Static)
          }
        clazzes :+= clazz
      }
    }
    val result = new STExternalDeclarations
    for (clazz <- clazzes.sortBy(_.toString))
      result.addClass(clazz)
    result
  }

  // in this context we only have the symbol, we don't have access
  // to the tree, so we can't call vparamss.  the names retrieved
  // this way might not match the ones in the trees, but it doesn't
  // matter during closure generation
  private def paramNamesFromSymbol(symbol: Symbol): List[Symbol] = {
    // we would like to just call symbol.asMethod here, but we encountered
    // a strange case, involving a method-local case class, where the
    // accessor for the case class companion object was spuriously considered
    // to be overloaded, so .asMethod would fail even though .alternatives.size
    // equaled 1.  so let's just call alternatives.head instead, but also include
    // this require call, to alert us to any other unexpected cases that might
    // crop up in the future
    require(symbol.alternatives.size == 1, symbol.alternatives.toString)
    symbol.alternatives.head.paramLists.flatten
  }

  // lightbend/scala-fortify#456
  private def alwaysInclude(symbol: Symbol): Boolean =
    overrides(symbol).contains(definitions.Object_equals)

  // Array.{apply,update} are special because their type parameter
  // isn't erased (because array types aren't erased at the JVM
  // level). That means we'll output a signature containing a generic
  // type, if we're not careful. But it's actually better to just omit
  // them entirely since they are never called in code we generate, we
  // always generate NST array syntax directly.
  private def omitMethod(symbol: Symbol): Boolean =
    symbol == definitions.Array_apply ||
      symbol == definitions.Array_update ||
      // also should never be called, and doesn't exist as a real method
      // anyway
      symbol == definitions.String_+

  private def includeInClosure(symbol: Symbol): Boolean =
    symbol.isClass &&
      !(symbol.isJavaDefined && symbol.isModuleClass) &&
      !symbol.isPrimitiveValueClass

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy