or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

ast-parsing.mdast-traversal.mdcopy-paste-detection.mdindex.mdlanguage-module.mdrule-development.md
tile.json

ast-parsing.mddocs/

AST Parsing

AST parsing capabilities transform Scala source code into PMD-compatible abstract syntax trees using Scalameta parsers. The parsing system provides complete coverage of Scala language constructs through 140+ AST node types.

Core Parsing Components

ScalaParser

Main parser implementation that converts Scala source code into PMD-compatible AST structures.

public final class ScalaParser implements Parser {
    public ScalaParser();
    public ASTSource parse(ParserTask task) throws ParseException;
}

Usage Example:

// Create parser instance
ScalaParser parser = new ScalaParser();

// Parse source code from task
ParserTask task = ParserTask.forFile(new File("Example.scala"), charset, languageVersion);
ASTSource ast = parser.parse(task);

// Process the resulting AST
ast.getChildren().forEach(node -> {
    System.out.println("Node type: " + node.getClass().getSimpleName());
});

ASTSource

Root node representing a complete Scala source file, serving as the entry point for AST analysis.

public final class ASTSource extends AbstractScalaNode<Source> implements RootNode {
    public AstInfo<ASTSource> getAstInfo();
    public void addTaskInfo(ParserTask task);
}

Usage Example:

ASTSource sourceRoot = parser.parse(task);

// Get AST metadata
AstInfo<ASTSource> info = sourceRoot.getAstInfo();

// Access root node properties
TextRegion region = sourceRoot.getTextRegion();
String sourceText = sourceRoot.getText();

// Navigate to child nodes
sourceRoot.descendants(ASTDefnClass.class)
    .forEach(classNode -> processClassDefinition(classNode));

ScalaTreeBuilder

Internal component that converts Scalameta AST structures to PMD-compatible node hierarchies.

final class ScalaTreeBuilder {
    <T extends Tree> ScalaNode<T> build(T astNode);
}

Internal Usage:

// Used internally by ScalaParser
Dialect dialect = ScalaDialect.dialectOf(languageVersion);
Source scalametaAst = new ScalametaParser(virtualFile, dialect).parseSource();
ASTSource pmdAst = (ASTSource) new ScalaTreeBuilder().build(scalametaAst);

AbstractScalaNode

Base class for all Scala AST nodes, providing PMD integration and common node functionality.

abstract class AbstractScalaNode<T extends Tree> extends AbstractNode<AbstractScalaNode<?>, ScalaNode<?>> implements ScalaNode<T> {
    protected final T node;
    
    public boolean isImplicit();
    public T getNode();
    public TextRegion getTextRegion();
    public <R, P> R acceptVisitor(AstVisitor<? super P, ? extends R> visitor, P data);
}

Key Methods:

// Check if node represents implicit Scala construct
boolean implicit = astNode.isImplicit();

// Get underlying Scalameta node
Tree scalametaNode = astNode.getNode();

// Access text positioning information
TextRegion region = astNode.getTextRegion();

ScalaDialect

Internal utility that maps PMD language versions to appropriate Scalameta dialect configurations.

final class ScalaDialect {
    static scala.meta.Dialect dialectOf(LanguageVersion version);
}

Internal Usage:

// Map PMD language version to Scalameta dialect
LanguageVersion version = task.getLanguageVersion();
Dialect dialect = ScalaDialect.dialectOf(version); // Returns appropriate scala.meta.Dialect

AST Node Hierarchy

Base Node Types

All Scala AST nodes extend from common base types providing core functionality.

public abstract class AbstractScalaNode<T extends Tree> extends AbstractNode<AbstractScalaNode<?>, ScalaNode<?>> implements ScalaNode<T> {
    public <P, R> R acceptVisitor(AstVisitor<? super P, ? extends R> visitor, P data);
    public boolean isImplicit();
    public TextRegion getTextRegion();
    public int compareLocation(Node other);
    public String getXPathNodeName();
}

public interface ScalaNode<T extends Tree> extends GenericNode<ScalaNode<?>> {
    boolean isImplicit();
}

Usage Example:

// Work with any Scala AST node
public void processNode(ScalaNode<?> node) {
    // Check if node represents implicit construct
    if (node.isImplicit()) {
        System.out.println("Implicit node: " + node.getXPathNodeName());
    }
    
    // Get source location
    TextRegion region = ((AbstractScalaNode<?>) node).getTextRegion();
    System.out.println("Location: " + region.getStartPos() + "-" + region.getEndPos());
}

Declaration and Definition Nodes

Method and Function Definitions

// Method declarations in traits/classes
public final class ASTDeclDef extends AbstractScalaNode<Decl.Def> implements DeclNode {
    // Inherited node methods
}

// Method implementations
public final class ASTDefnDef extends AbstractScalaNode<Defn.Def> implements DefnNode {
    // Inherited node methods
}

Usage Example:

// Find all method definitions in source
ast.descendants(ASTDefnDef.class).forEach(method -> {
    String methodName = method.getText(); // Get source text
    System.out.println("Found method: " + methodName);
});

// Find abstract method declarations
ast.descendants(ASTDeclDef.class).forEach(decl -> {
    System.out.println("Found method declaration: " + decl.getText());
});

Class and Object Definitions

// Class definitions
public final class ASTDefnClass extends AbstractScalaNode<Defn.Class> implements DefnNode {
    // Inherited node methods
}

// Object definitions (singletons)
public final class ASTDefnObject extends AbstractScalaNode<Defn.Object> implements DefnNode {
    // Inherited node methods
}

// Trait definitions
public final class ASTDefnTrait extends AbstractScalaNode<Defn.Trait> implements DefnNode {
    // Inherited node methods
}

Usage Example:

// Process all class definitions
ast.descendants(ASTDefnClass.class).forEach(classNode -> {
    System.out.println("Class: " + classNode.getText());
    
    // Find methods in this class
    classNode.descendants(ASTDefnDef.class).forEach(method -> {
        System.out.println("  Method: " + method.getText());
    });
});

// Find all singleton objects
ast.descendants(ASTDefnObject.class).forEach(obj -> {
    System.out.println("Object: " + obj.getText());
});

Value and Variable Definitions

// Immutable values (val)
public final class ASTDefnVal extends AbstractScalaNode<Defn.Val> implements DefnNode {
    // Inherited node methods
}

// Mutable variables (var)
public final class ASTDefnVar extends AbstractScalaNode<Defn.Var> implements DefnNode {
    // Inherited node methods
}

// Type definitions
public final class ASTDefnType extends AbstractScalaNode<Defn.Type> implements DefnNode {
    // Inherited node methods
}

Usage Example:

// Find all value definitions
ast.descendants(ASTDefnVal.class).forEach(value -> {
    System.out.println("Val definition: " + value.getText());
});

// Find mutable variables
ast.descendants(ASTDefnVar.class).forEach(variable -> {
    System.out.println("Var definition: " + variable.getText());
});

Expression and Term Nodes

Method Calls and Applications

// Method applications (function calls)
public final class ASTTermApply extends AbstractScalaNode<Term.Apply> implements TermNode {
    // Inherited node methods
}

// Infix method applications (a + b)
public final class ASTTermApplyInfix extends AbstractScalaNode<Term.ApplyInfix> implements TermNode {
    // Inherited node methods
}

// Type applications (List[String])
public final class ASTTermApplyType extends AbstractScalaNode<Term.ApplyType> implements TermNode {
    // Inherited node methods
}

Usage Example:

// Find all method calls
ast.descendants(ASTTermApply.class).forEach(call -> {
    System.out.println("Method call: " + call.getText());
});

// Find infix operations
ast.descendants(ASTTermApplyInfix.class).forEach(infix -> {
    System.out.println("Infix operation: " + infix.getText());
});

Control Flow Nodes

// If expressions
public final class ASTTermIf extends AbstractScalaNode<Term.If> implements TermNode {
    // Inherited node methods
}

// Match expressions (pattern matching)
public final class ASTTermMatch extends AbstractScalaNode<Term.Match> implements TermNode {
    // Inherited node methods
}

// For comprehensions
public final class ASTTermFor extends AbstractScalaNode<Term.For> implements TermNode {
    // Inherited node methods
}

// For-yield expressions
public final class ASTTermForYield extends AbstractScalaNode<Term.ForYield> implements TermNode {
    // Inherited node methods
}

Usage Example:

// Analyze control flow patterns
ast.descendants(ASTTermIf.class).forEach(ifExpr -> {
    System.out.println("If expression: " + ifExpr.getText());
});

ast.descendants(ASTTermMatch.class).forEach(match -> {
    System.out.println("Pattern match: " + match.getText());
    
    // Find case clauses within match
    match.descendants(ASTCase.class).forEach(caseClause -> {
        System.out.println("  Case: " + caseClause.getText());
    });
});

Literal and Constant Nodes

Primitive Literals

// String literals
public final class ASTLitString extends AbstractScalaNode<Lit.String> implements LitNode {
    // Inherited node methods
}

// Numeric literals
public final class ASTLitInt extends AbstractScalaNode<Lit.Int> implements LitNode {
    // Inherited node methods
}

public final class ASTLitDouble extends AbstractScalaNode<Lit.Double> implements LitNode {
    // Inherited node methods
}

// Boolean literals
public final class ASTLitBoolean extends AbstractScalaNode<Lit.Boolean> implements LitNode {
    // Inherited node methods
}

// Null literal
public final class ASTLitNull extends AbstractScalaNode<Lit.Null> implements LitNode {
    // Inherited node methods
}

Usage Example:

// Find all string literals
ast.descendants(ASTLitString.class).forEach(str -> {
    System.out.println("String literal: " + str.getText());
});

// Find numeric constants
ast.descendants(ASTLitInt.class).forEach(num -> {
    System.out.println("Integer literal: " + num.getText());
});

Package and Import Management

Package Declarations

// Package declarations
public final class ASTPkg extends AbstractScalaNode<Pkg> implements PkgNode {
    // Inherited node methods
}

// Package objects
public final class ASTPkgObject extends AbstractScalaNode<Pkg.Object> implements PkgNode {
    // Inherited node methods
}

Import Statements

// Import statements
public final class ASTImport extends AbstractScalaNode<Import> implements ImportNode {
    // Inherited node methods
}

// Import expressions (what to import)
public final class ASTImporter extends AbstractScalaNode<Importer> implements ImportNode {
    // Inherited node methods
}

Usage Example:

// Analyze imports and packages
ast.descendants(ASTImport.class).forEach(importStmt -> {
    System.out.println("Import: " + importStmt.getText());
    
    // Analyze specific import expressions
    importStmt.descendants(ASTImporter.class).forEach(importer -> {
        System.out.println("  Importing: " + importer.getText());
    });
});

// Find package declarations
ast.descendants(ASTPkg.class).forEach(pkg -> {
    System.out.println("Package: " + pkg.getText());
});

Parsing Configuration

Scalameta Integration

The parser integrates with Scalameta's parsing infrastructure to support all Scala language constructs:

// Internal parser configuration (handled automatically)
scala.meta.Dialect dialect = ScalaDialect.dialectOf(languageVersion);
scala.meta.parsers.Parsed<scala.meta.Source> parsed = dialect.parse(sourceText);

Error Handling

// Parse exceptions for syntax errors
public class ParseException extends Exception {
    // Standard exception methods
}

Usage Example:

try {
    ASTSource ast = parser.parse(task);
    // Process successful parse
} catch (ParseException e) {
    System.err.println("Parse error: " + e.getMessage());
    // Handle syntax errors in source code
}

Integration with PMD Framework

Parser Task Configuration

// Configure parsing task
ParserTask.Builder builder = ParserTask.builder()
    .file(sourceFile)
    .charset(StandardCharsets.UTF_8)
    .languageVersion(scalaVersion);

ParserTask task = builder.build();
ASTSource ast = parser.parse(task);

AST Processing Pipeline

The parsed AST integrates with PMD's analysis pipeline:

  1. Parsing: Source code → Scalameta AST → PMD AST
  2. Validation: Node consistency and hierarchy validation
  3. Analysis: Rule application and visitor pattern traversal
  4. Reporting: Issue detection and report generation

This parsing system provides the foundation for all static analysis capabilities in the PMD Scala module.