Skip to content

Commit

Permalink
minor refactor along the same theme
Browse files Browse the repository at this point in the history
  • Loading branch information
matanox committed Dec 4, 2015
1 parent d7244d8 commit 7af1a69
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 145 deletions.
Original file line number Diff line number Diff line change
@@ -1,41 +1,84 @@
package org.canve.compilerPlugin
import tools.nsc.Global

case class ExtractedSymbol
(symbolCompilerId: SymbolCompilerId,
name: String,
kind: String,
qualifiedId: QualifiedID,
class ExtractedSymbol(

/*
* the symbol id drawn from the compiler - only guaranteed to be unique within a single
* compilation, meaning a single project's compilation
*/
val symbolCompilerId: SymbolCompilerId,

signatureString: Option[String] = None,
/* symbol's name, or None if the symbol is anonymous */
val name: Option[String],

notSynthetic: Boolean,
definingProject: DefiningProject) extends SymbolSerialization {
/* symbol's kind - package, class, object, method, etc.. */
val kind: String,

/* an identifier similar to Java's FQN, to help uniquely identify a symbol across projects */
val qualifyingPath: QualifyingPath,

/* symbol's type signature, as a string */
val signatureString: Option[String] = None,

/*
* this is a delicate definition, will likely receive a finer definition going forward.
* informally speaking it marks whether the symbol is a contrived one added by the compiler,
* or just a regular one very directly associated to a source code element.
*/
val nonSynthetic: Boolean,

/*
* says whether the symbol's implementation is defined in the current project, or externally to it.
* for example a symbol may be one that has its implementation coming from a library, or from a depended-upon
* subproject summoned into the compilation classpath by sbt or other tool. In those cases, this marks that
* the symbol's implementation resides externally, not within the project being compiled.
*/
val implementation: ImplementationLoc)

val qualifiedIdAndSignature: FurtherQualifiedID =
qualifiedId.pickle + (signatureString match {
case Some(s) => " * " + s
case None => ""
})

def definitionCode(implicit extractedModel: ExtractedModel): Option[Code] =
extractedModel.codes.get.get(symbolCompilerId)
extends SymbolSerialization {

/* getter for symbol's code description, the latter kept in a separate collection */
def definitionCode(implicit extractedModel: ExtractedModel): Option[Code] =
extractedModel.codes.get.get(symbolCompilerId)

/* more inclusive serialization for this class - for logging */
override def toString =
List(symbolCompilerId,
name,
kind,
qualifiedId,
signatureString,
notSynthetic,
definingProject,
qualifiedIdAndSignature).map(_.toString).mkString(",")
/* more inclusive serialization for this class - for logging */
override def toString =
List(symbolCompilerId,
name,
kind,
qualifyingPath,
signatureString,
nonSynthetic,
implementation).map(_.toString).mkString(",")

/* symbol and its code info joined into a string - for logging */
def toJoinedString(implicit extractedModel: ExtractedModel) = toString + ",code: " + definitionCode.toString
/* symbol and its code info joined into a string - for logging */
def toJoinedString(implicit extractedModel: ExtractedModel) = toString + ",code: " + definitionCode.toString

var ownersTraversed = false
var ownersTraversed = false
}

object ExtractedSymbol {

/*
* just the obvious apply, to provide a case class instantiation style
*/
def apply(
symbolCompilerId: SymbolCompilerId,
name: Option[String],
kind: String,
qualifyingPath: QualifyingPath,
signatureString: Option[String],
nonSynthetic: Boolean,
implementation: ImplementationLoc) =
new ExtractedSymbol(
symbolCompilerId,
name,
kind,
qualifyingPath,
signatureString,
nonSynthetic,
implementation)
}

/*
Expand All @@ -60,16 +103,24 @@ case class Point(init: Int) extends Position { def apply = init }
/*
* types for whether a symbol is defined in
* the current project, or is an external one
* being referenced by this project
*/

abstract class DefiningProject
object ProjectDefined extends DefiningProject
object ExternallyDefined extends DefiningProject
abstract class ImplementationLoc
object ProjectDefined extends ImplementationLoc
object ExternallyDefined extends ImplementationLoc

/*
* a lame join type of a symbol and its extracted code, wherever helpful
* case class and companion
*/
case class FQI(qPath: QualifyingPath, signatureString: Option[String])

object FQI {
def apply(s: ExtractedSymbol) = new FQI(s.qualifyingPath, s.signatureString)
}

/*
* a lame join type of a symbol and its extracted code, if helpful
*/
case class SymbolCodeJoin(
extractedModel: ExtractedModel,
symbol: ExtractedSymbol) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,34 @@ class ExtractedModel(global: Global) extends ContainsExtractedGraph {

def add(global: Global)(s: global.Symbol): ExtractedSymbol = {
graph.vertex(s.id) match {

case Some(v: graph.Vertex) =>
//throw ExtractionException(s"graph already has symbol with id ${s.id}")
TraversalSymbolRevisit.increment
v.data

case None =>
val qualifiedId = QualifiedID.compute(global)(s)
val qualifyingPath = QualifyingPath(global)(s)

/*
* determine whether the symbol at hand is defined in the current project,
*/
val definingProject = s.sourceFile match {
case null => ExternallyDefined // no source file included in this project for this entity
val implementation = s.sourceFile match {
case null => ExternallyDefined // no source file for this entity = external symbol
case _ => ProjectDefined
}

/*
* add the symbol to the extracted model
*/
val extractedSymbol =
ExtractedSymbol(
symbolCompilerId = s.id,
name = s.nameString,
name = maybeName(global)(s),
kind = s.kindString,
qualifiedId = qualifiedId,
notSynthetic = !(s.isSynthetic),
definingProject = definingProject,
qualifyingPath = qualifyingPath,
nonSynthetic = !(s.isSynthetic),
implementation = implementation,
signatureString = s.signatureString match {
case("<_>") => None
case signatureString@_ => Some(signatureString)
Expand All @@ -60,7 +62,7 @@ class ExtractedModel(global: Global) extends ContainsExtractedGraph {
* pass on to attempt to extract the symbol's source code,
* if it is defined in the current project
*/
definingProject match {
implementation match {
case ProjectDefined => codes(global)(s, AttemptCodeExtract(global)(s))
case ExternallyDefined => // no source file included in this project for this entity
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object Output {
Log(s"writing extracted type relations and call graph for project ${PluginArgs.projectName}...")

writeOutputFile(PluginArgs.projectName, "symbols",
"definition,notSynthetic,id,name,kind,qualifiedId,signature\n" +
"implementation,nonSynthetic,id,name,kind,qualifiedId,signature\n" +
(extractedModel.graph.vertexIterator.map(_.data.toCsvRow)).mkString("\n"))

println("before output")
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.canve.compilerPlugin
import tools.nsc.Global
import Util._

/*
* A Qualified Identification of a symbol, that does not rely on its compiler assigned id,
* is useful for correlating symbols across project boundaries. Here we provide the necessary class
* for creating and using such an identification, which we will call for brevity QI.
*/

/* The class and factory */

case class QualifyingPath(value: List[QualificationUnit]) {

/*
* if any anonymous object is part of the qualification chain, then (by definition) the
* chain cannot be considered by any means unique - anonymous objects may sit side-by-side
* under the same program context, and having no name, cannot be easily differentiated.
*/
val fullyNamed: Boolean = value.forall(_.name.isDefined)

def pickle = value.map(kindAndName => "(" + kindAndName.kind + "|" + kindAndName.name + ")").mkString(".")
}

/*
* companion object providing both a constructor from a global.symbol and
* a constructor from string-pickled input
*/
object QualifyingPath {

def apply(s: String): QualifyingPath =
QualifyingPath(s.split('.').toList.map(s =>
QualificationUnit(
s.takeWhile(_!='|').drop(1),
deSerializeOption[String](s) match {
case None => None
case Some(s) => Some(s.dropWhile(_!='|').drop(1).dropRight(1))
})))

def apply(global: Global)(s: global.Symbol): QualifyingPath = {
val kindNameList: List[QualificationUnit] =
s.ownerChain.reverse.map(owner => QualificationUnit(global)(owner))

assert(kindNameList.head.kind == "package")
assert(kindNameList.head.name.get == "<root>")

QualifyingPath(kindNameList.drop(1))
}
}


/* auxiliary class and factory */

case class QualificationUnit(kind: String, name: Option[String])

object QualificationUnit {
def apply(global: Global)(s: global.Symbol): QualificationUnit = {
new QualificationUnit(s.kindString, maybeName(global)(s))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ trait SymbolSerialization {
def toCsvRow(implicit extractedModel: ExtractedModel): String = {
// Note: escaping for csv is for now handled here by hand (likely a tad faster)
List(
definingProject match {
implementation match {
case ProjectDefined => "project"
case ExternallyDefined => "external" },
notSynthetic,
nonSynthetic,
symbolCompilerId,
name,
kind,
qualifiedId.pickle,
qualifyingPath.pickle,
"\"" + signatureString + "\"" // escaped as it contains, typically, commas
).mkString(",")
}
Expand All @@ -29,12 +29,12 @@ object SymbolFromCsvRow {
import Util._
def apply(projectName: String, rowMap: Map[String, String]): ExtractedSymbol = {
ExtractedSymbol(symbolCompilerId = rowMap("id").toInt,
name = rowMap("name"),
name = deSerializeOption(rowMap("name")),
kind = rowMap("kind"),
notSynthetic = rowMap("notSynthetic").toBoolean,
qualifiedId = QualifiedID.unpickle(rowMap("qualifiedId")),
nonSynthetic = rowMap("nonSynthetic").toBoolean,
qualifyingPath = QualifyingPath(rowMap("qualifiedId")),
signatureString = deSerializeOption(rowMap("signature")),
definingProject = rowMap("definition") match {
implementation = rowMap("implementation") match {
case "project" => ProjectDefined
case "external" => ExternallyDefined
})
Expand Down
Loading

0 comments on commit 7af1a69

Please sign in to comment.