or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

ast-parsing.mddocs/

0

# AST Parsing

1

2

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.

3

4

## Core Parsing Components

5

6

### ScalaParser

7

8

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

9

10

```java { .api }

11

public final class ScalaParser implements Parser {

12

public ScalaParser();

13

public ASTSource parse(ParserTask task) throws ParseException;

14

}

15

```

16

17

**Usage Example**:

18

19

```java

20

// Create parser instance

21

ScalaParser parser = new ScalaParser();

22

23

// Parse source code from task

24

ParserTask task = ParserTask.forFile(new File("Example.scala"), charset, languageVersion);

25

ASTSource ast = parser.parse(task);

26

27

// Process the resulting AST

28

ast.getChildren().forEach(node -> {

29

System.out.println("Node type: " + node.getClass().getSimpleName());

30

});

31

```

32

33

### ASTSource

34

35

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

36

37

```java { .api }

38

public final class ASTSource extends AbstractScalaNode<Source> implements RootNode {

39

public AstInfo<ASTSource> getAstInfo();

40

public void addTaskInfo(ParserTask task);

41

}

42

```

43

44

**Usage Example**:

45

46

```java

47

ASTSource sourceRoot = parser.parse(task);

48

49

// Get AST metadata

50

AstInfo<ASTSource> info = sourceRoot.getAstInfo();

51

52

// Access root node properties

53

TextRegion region = sourceRoot.getTextRegion();

54

String sourceText = sourceRoot.getText();

55

56

// Navigate to child nodes

57

sourceRoot.descendants(ASTDefnClass.class)

58

.forEach(classNode -> processClassDefinition(classNode));

59

```

60

61

### ScalaTreeBuilder

62

63

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

64

65

```java { .api }

66

final class ScalaTreeBuilder {

67

<T extends Tree> ScalaNode<T> build(T astNode);

68

}

69

```

70

71

**Internal Usage**:

72

73

```java

74

// Used internally by ScalaParser

75

Dialect dialect = ScalaDialect.dialectOf(languageVersion);

76

Source scalametaAst = new ScalametaParser(virtualFile, dialect).parseSource();

77

ASTSource pmdAst = (ASTSource) new ScalaTreeBuilder().build(scalametaAst);

78

```

79

80

### AbstractScalaNode

81

82

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

83

84

```java { .api }

85

abstract class AbstractScalaNode<T extends Tree> extends AbstractNode<AbstractScalaNode<?>, ScalaNode<?>> implements ScalaNode<T> {

86

protected final T node;

87

88

public boolean isImplicit();

89

public T getNode();

90

public TextRegion getTextRegion();

91

public <R, P> R acceptVisitor(AstVisitor<? super P, ? extends R> visitor, P data);

92

}

93

```

94

95

**Key Methods**:

96

97

```java

98

// Check if node represents implicit Scala construct

99

boolean implicit = astNode.isImplicit();

100

101

// Get underlying Scalameta node

102

Tree scalametaNode = astNode.getNode();

103

104

// Access text positioning information

105

TextRegion region = astNode.getTextRegion();

106

```

107

108

### ScalaDialect

109

110

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

111

112

```java { .api }

113

final class ScalaDialect {

114

static scala.meta.Dialect dialectOf(LanguageVersion version);

115

}

116

```

117

118

**Internal Usage**:

119

120

```java

121

// Map PMD language version to Scalameta dialect

122

LanguageVersion version = task.getLanguageVersion();

123

Dialect dialect = ScalaDialect.dialectOf(version); // Returns appropriate scala.meta.Dialect

124

```

125

126

## AST Node Hierarchy

127

128

### Base Node Types

129

130

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

131

132

```java { .api }

133

public abstract class AbstractScalaNode<T extends Tree> extends AbstractNode<AbstractScalaNode<?>, ScalaNode<?>> implements ScalaNode<T> {

134

public <P, R> R acceptVisitor(AstVisitor<? super P, ? extends R> visitor, P data);

135

public boolean isImplicit();

136

public TextRegion getTextRegion();

137

public int compareLocation(Node other);

138

public String getXPathNodeName();

139

}

140

141

public interface ScalaNode<T extends Tree> extends GenericNode<ScalaNode<?>> {

142

boolean isImplicit();

143

}

144

```

145

146

**Usage Example**:

147

148

```java

149

// Work with any Scala AST node

150

public void processNode(ScalaNode<?> node) {

151

// Check if node represents implicit construct

152

if (node.isImplicit()) {

153

System.out.println("Implicit node: " + node.getXPathNodeName());

154

}

155

156

// Get source location

157

TextRegion region = ((AbstractScalaNode<?>) node).getTextRegion();

158

System.out.println("Location: " + region.getStartPos() + "-" + region.getEndPos());

159

}

160

```

161

162

## Declaration and Definition Nodes

163

164

### Method and Function Definitions

165

166

```java { .api }

167

// Method declarations in traits/classes

168

public final class ASTDeclDef extends AbstractScalaNode<Decl.Def> implements DeclNode {

169

// Inherited node methods

170

}

171

172

// Method implementations

173

public final class ASTDefnDef extends AbstractScalaNode<Defn.Def> implements DefnNode {

174

// Inherited node methods

175

}

176

```

177

178

**Usage Example**:

179

180

```java

181

// Find all method definitions in source

182

ast.descendants(ASTDefnDef.class).forEach(method -> {

183

String methodName = method.getText(); // Get source text

184

System.out.println("Found method: " + methodName);

185

});

186

187

// Find abstract method declarations

188

ast.descendants(ASTDeclDef.class).forEach(decl -> {

189

System.out.println("Found method declaration: " + decl.getText());

190

});

191

```

192

193

### Class and Object Definitions

194

195

```java { .api }

196

// Class definitions

197

public final class ASTDefnClass extends AbstractScalaNode<Defn.Class> implements DefnNode {

198

// Inherited node methods

199

}

200

201

// Object definitions (singletons)

202

public final class ASTDefnObject extends AbstractScalaNode<Defn.Object> implements DefnNode {

203

// Inherited node methods

204

}

205

206

// Trait definitions

207

public final class ASTDefnTrait extends AbstractScalaNode<Defn.Trait> implements DefnNode {

208

// Inherited node methods

209

}

210

```

211

212

**Usage Example**:

213

214

```java

215

// Process all class definitions

216

ast.descendants(ASTDefnClass.class).forEach(classNode -> {

217

System.out.println("Class: " + classNode.getText());

218

219

// Find methods in this class

220

classNode.descendants(ASTDefnDef.class).forEach(method -> {

221

System.out.println(" Method: " + method.getText());

222

});

223

});

224

225

// Find all singleton objects

226

ast.descendants(ASTDefnObject.class).forEach(obj -> {

227

System.out.println("Object: " + obj.getText());

228

});

229

```

230

231

### Value and Variable Definitions

232

233

```java { .api }

234

// Immutable values (val)

235

public final class ASTDefnVal extends AbstractScalaNode<Defn.Val> implements DefnNode {

236

// Inherited node methods

237

}

238

239

// Mutable variables (var)

240

public final class ASTDefnVar extends AbstractScalaNode<Defn.Var> implements DefnNode {

241

// Inherited node methods

242

}

243

244

// Type definitions

245

public final class ASTDefnType extends AbstractScalaNode<Defn.Type> implements DefnNode {

246

// Inherited node methods

247

}

248

```

249

250

**Usage Example**:

251

252

```java

253

// Find all value definitions

254

ast.descendants(ASTDefnVal.class).forEach(value -> {

255

System.out.println("Val definition: " + value.getText());

256

});

257

258

// Find mutable variables

259

ast.descendants(ASTDefnVar.class).forEach(variable -> {

260

System.out.println("Var definition: " + variable.getText());

261

});

262

```

263

264

## Expression and Term Nodes

265

266

### Method Calls and Applications

267

268

```java { .api }

269

// Method applications (function calls)

270

public final class ASTTermApply extends AbstractScalaNode<Term.Apply> implements TermNode {

271

// Inherited node methods

272

}

273

274

// Infix method applications (a + b)

275

public final class ASTTermApplyInfix extends AbstractScalaNode<Term.ApplyInfix> implements TermNode {

276

// Inherited node methods

277

}

278

279

// Type applications (List[String])

280

public final class ASTTermApplyType extends AbstractScalaNode<Term.ApplyType> implements TermNode {

281

// Inherited node methods

282

}

283

```

284

285

**Usage Example**:

286

287

```java

288

// Find all method calls

289

ast.descendants(ASTTermApply.class).forEach(call -> {

290

System.out.println("Method call: " + call.getText());

291

});

292

293

// Find infix operations

294

ast.descendants(ASTTermApplyInfix.class).forEach(infix -> {

295

System.out.println("Infix operation: " + infix.getText());

296

});

297

```

298

299

### Control Flow Nodes

300

301

```java { .api }

302

// If expressions

303

public final class ASTTermIf extends AbstractScalaNode<Term.If> implements TermNode {

304

// Inherited node methods

305

}

306

307

// Match expressions (pattern matching)

308

public final class ASTTermMatch extends AbstractScalaNode<Term.Match> implements TermNode {

309

// Inherited node methods

310

}

311

312

// For comprehensions

313

public final class ASTTermFor extends AbstractScalaNode<Term.For> implements TermNode {

314

// Inherited node methods

315

}

316

317

// For-yield expressions

318

public final class ASTTermForYield extends AbstractScalaNode<Term.ForYield> implements TermNode {

319

// Inherited node methods

320

}

321

```

322

323

**Usage Example**:

324

325

```java

326

// Analyze control flow patterns

327

ast.descendants(ASTTermIf.class).forEach(ifExpr -> {

328

System.out.println("If expression: " + ifExpr.getText());

329

});

330

331

ast.descendants(ASTTermMatch.class).forEach(match -> {

332

System.out.println("Pattern match: " + match.getText());

333

334

// Find case clauses within match

335

match.descendants(ASTCase.class).forEach(caseClause -> {

336

System.out.println(" Case: " + caseClause.getText());

337

});

338

});

339

```

340

341

## Literal and Constant Nodes

342

343

### Primitive Literals

344

345

```java { .api }

346

// String literals

347

public final class ASTLitString extends AbstractScalaNode<Lit.String> implements LitNode {

348

// Inherited node methods

349

}

350

351

// Numeric literals

352

public final class ASTLitInt extends AbstractScalaNode<Lit.Int> implements LitNode {

353

// Inherited node methods

354

}

355

356

public final class ASTLitDouble extends AbstractScalaNode<Lit.Double> implements LitNode {

357

// Inherited node methods

358

}

359

360

// Boolean literals

361

public final class ASTLitBoolean extends AbstractScalaNode<Lit.Boolean> implements LitNode {

362

// Inherited node methods

363

}

364

365

// Null literal

366

public final class ASTLitNull extends AbstractScalaNode<Lit.Null> implements LitNode {

367

// Inherited node methods

368

}

369

```

370

371

**Usage Example**:

372

373

```java

374

// Find all string literals

375

ast.descendants(ASTLitString.class).forEach(str -> {

376

System.out.println("String literal: " + str.getText());

377

});

378

379

// Find numeric constants

380

ast.descendants(ASTLitInt.class).forEach(num -> {

381

System.out.println("Integer literal: " + num.getText());

382

});

383

```

384

385

## Package and Import Management

386

387

### Package Declarations

388

389

```java { .api }

390

// Package declarations

391

public final class ASTPkg extends AbstractScalaNode<Pkg> implements PkgNode {

392

// Inherited node methods

393

}

394

395

// Package objects

396

public final class ASTPkgObject extends AbstractScalaNode<Pkg.Object> implements PkgNode {

397

// Inherited node methods

398

}

399

```

400

401

### Import Statements

402

403

```java { .api }

404

// Import statements

405

public final class ASTImport extends AbstractScalaNode<Import> implements ImportNode {

406

// Inherited node methods

407

}

408

409

// Import expressions (what to import)

410

public final class ASTImporter extends AbstractScalaNode<Importer> implements ImportNode {

411

// Inherited node methods

412

}

413

```

414

415

**Usage Example**:

416

417

```java

418

// Analyze imports and packages

419

ast.descendants(ASTImport.class).forEach(importStmt -> {

420

System.out.println("Import: " + importStmt.getText());

421

422

// Analyze specific import expressions

423

importStmt.descendants(ASTImporter.class).forEach(importer -> {

424

System.out.println(" Importing: " + importer.getText());

425

});

426

});

427

428

// Find package declarations

429

ast.descendants(ASTPkg.class).forEach(pkg -> {

430

System.out.println("Package: " + pkg.getText());

431

});

432

```

433

434

## Parsing Configuration

435

436

### Scalameta Integration

437

438

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

439

440

```java

441

// Internal parser configuration (handled automatically)

442

scala.meta.Dialect dialect = ScalaDialect.dialectOf(languageVersion);

443

scala.meta.parsers.Parsed<scala.meta.Source> parsed = dialect.parse(sourceText);

444

```

445

446

### Error Handling

447

448

```java { .api }

449

// Parse exceptions for syntax errors

450

public class ParseException extends Exception {

451

// Standard exception methods

452

}

453

```

454

455

**Usage Example**:

456

457

```java

458

try {

459

ASTSource ast = parser.parse(task);

460

// Process successful parse

461

} catch (ParseException e) {

462

System.err.println("Parse error: " + e.getMessage());

463

// Handle syntax errors in source code

464

}

465

```

466

467

## Integration with PMD Framework

468

469

### Parser Task Configuration

470

471

```java

472

// Configure parsing task

473

ParserTask.Builder builder = ParserTask.builder()

474

.file(sourceFile)

475

.charset(StandardCharsets.UTF_8)

476

.languageVersion(scalaVersion);

477

478

ParserTask task = builder.build();

479

ASTSource ast = parser.parse(task);

480

```

481

482

### AST Processing Pipeline

483

484

The parsed AST integrates with PMD's analysis pipeline:

485

486

1. **Parsing**: Source code → Scalameta AST → PMD AST

487

2. **Validation**: Node consistency and hierarchy validation

488

3. **Analysis**: Rule application and visitor pattern traversal

489

4. **Reporting**: Issue detection and report generation

490

491

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