or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ast-processing.mdindex.mdlanguage-support.mdmetrics.mdrule-framework.mdsymbols-types.md

symbols-types.mddocs/

0

# Symbol Resolution and Type System

1

2

PMD Java provides a sophisticated symbol resolution and type system that enables semantic analysis of Java code. This includes complete support for generics, wildcards, type inference, and modern Java features like sealed classes and records.

3

4

## Capabilities

5

6

### Symbol Resolution

7

8

The symbol system provides resolution of names to their declarations with full support for scoping rules, overloading, and generic type parameters.

9

10

#### Base Symbol Interface

11

12

```java { .api }

13

/**

14

* Represents a named program element that can be referred to by simple name

15

*/

16

public interface JElementSymbol {

17

/**

18

* Gets the name with which this declaration may be referred to

19

*/

20

String getSimpleName();

21

22

/**

23

* Returns true if the simple name of this symbol matches the given name

24

*/

25

default boolean nameEquals(@NonNull String name);

26

27

/**

28

* Returns the type system that created this symbol

29

*/

30

TypeSystem getTypeSystem();

31

32

/**

33

* Returns true if this symbol is a placeholder for an unresolved reference

34

*/

35

default boolean isUnresolved();

36

37

/**

38

* Returns the node that declares this symbol if in the current file

39

*/

40

default @Nullable JavaNode tryGetNode();

41

42

/**

43

* Dispatch to the appropriate visit method of the visitor

44

*/

45

<R, P> R acceptVisitor(SymbolVisitor<R, P> visitor, P param);

46

}

47

```

48

49

#### Class Symbols

50

51

```java { .api }

52

/**

53

* Represents class/interface/enum/annotation/record symbols

54

*/

55

public interface JClassSymbol extends JTypeDeclSymbol, JTypeParameterOwnerSymbol,

56

BoundToNode<ASTTypeDeclaration> {

57

58

/**

59

* Returns the binary name of this type (JLS §13.1)

60

*/

61

@NonNull String getBinaryName();

62

63

/**

64

* Returns the canonical name of this class

65

*/

66

@Nullable String getCanonicalName();

67

68

/**

69

* Returns the method or constructor this symbol is declared in for local classes

70

*/

71

@Nullable JExecutableSymbol getEnclosingMethod();

72

73

/**

74

* Returns the member classes declared directly in this class

75

*/

76

List<JClassSymbol> getDeclaredClasses();

77

78

/**

79

* Returns a class with the given name defined in this class

80

*/

81

@Nullable JClassSymbol getDeclaredClass(String name);

82

83

/**

84

* Returns the methods declared directly in this class (excludes bridges/synthetic)

85

*/

86

List<JMethodSymbol> getDeclaredMethods();

87

88

/**

89

* Returns the constructors declared by this class (excludes synthetic)

90

*/

91

List<JConstructorSymbol> getConstructors();

92

93

/**

94

* Returns the fields declared directly in this class (excludes synthetic)

95

*/

96

List<JFieldSymbol> getDeclaredFields();

97

98

/**

99

* Returns a field with the given name defined in this class

100

*/

101

@Nullable JFieldSymbol getDeclaredField(String name);

102

103

/**

104

* Returns all enum constants (subset of getDeclaredFields())

105

*/

106

default @NonNull List<JFieldSymbol> getEnumConstants();

107

108

/**

109

* Returns all record components (for record types)

110

*/

111

default @NonNull List<JRecordComponentSymbol> getRecordComponents();

112

113

/**

114

* Returns the superclass symbol if it exists

115

*/

116

@Nullable JClassSymbol getSuperclass();

117

118

/**

119

* Returns the direct super-interfaces of this class or interface

120

*/

121

List<JClassSymbol> getSuperInterfaces();

122

123

/**

124

* Returns super interface types under the given substitution

125

*/

126

List<JClassType> getSuperInterfaceTypes(Substitution substitution);

127

128

/**

129

* Returns the superclass type under the given substitution

130

*/

131

@Nullable JClassType getSuperclassType(Substitution substitution);

132

133

/**

134

* Returns the component symbol for array types

135

*/

136

@Nullable JTypeDeclSymbol getArrayComponent();

137

138

// Type checking methods

139

boolean isArray();

140

boolean isPrimitive();

141

boolean isEnum();

142

boolean isRecord();

143

boolean isAnnotation();

144

boolean isLocalClass();

145

boolean isAnonymousClass();

146

boolean isAbstract();

147

boolean isFinal();

148

149

/**

150

* Returns the list of permitted subclasses for sealed types

151

*/

152

default List<JClassSymbol> getPermittedSubtypes();

153

154

/**

155

* Returns true if this type is sealed

156

*/

157

default boolean isSealed();

158

159

/**

160

* Returns simple names of all annotation attributes (for annotation types)

161

*/

162

default PSet<String> getAnnotationAttributeNames();

163

}

164

```

165

166

#### Method Symbols

167

168

```java { .api }

169

/**

170

* Represents method symbols

171

*/

172

public interface JMethodSymbol extends JExecutableSymbol {

173

/**

174

* Returns the return type of this method

175

*/

176

JTypeMirror getReturnType();

177

178

/**

179

* Returns the return type with the given substitution applied

180

*/

181

JTypeMirror getReturnType(Substitution subst);

182

183

/**

184

* Returns true if this is an abstract method

185

*/

186

boolean isAbstract();

187

188

/**

189

* Returns true if this is a default method (interface default)

190

*/

191

boolean isDefault();

192

193

/**

194

* Returns true if this is a native method

195

*/

196

boolean isNative();

197

198

/**

199

* Returns true if this is a synchronized method

200

*/

201

boolean isSynchronized();

202

203

/**

204

* Returns the method signature including parameter types

205

*/

206

JMethodSig getSignature();

207

208

/**

209

* Returns the method signature with substitution applied

210

*/

211

JMethodSig getSignature(Substitution subst);

212

}

213

```

214

215

#### Field Symbols

216

217

```java { .api }

218

/**

219

* Represents field symbols

220

*/

221

public interface JFieldSymbol extends JVariableSymbol {

222

/**

223

* Returns the type of this field

224

*/

225

JTypeMirror getTypeMirror();

226

227

/**

228

* Returns the type with the given substitution applied

229

*/

230

JTypeMirror getTypeMirror(Substitution subst);

231

232

/**

233

* Returns true if this is a static field

234

*/

235

boolean isStatic();

236

237

/**

238

* Returns true if this is a final field

239

*/

240

boolean isFinal();

241

242

/**

243

* Returns true if this is a volatile field

244

*/

245

boolean isVolatile();

246

247

/**

248

* Returns true if this is a transient field

249

*/

250

boolean isTransient();

251

252

/**

253

* Returns true if this field is an enum constant

254

*/

255

boolean isEnumConstant();

256

257

/**

258

* Returns the constant value if this is a compile-time constant

259

*/

260

@Nullable Object getConstantValue();

261

}

262

```

263

264

#### Variable Symbols

265

266

```java { .api }

267

/**

268

* Base interface for variables (local variables, parameters, fields)

269

*/

270

public interface JVariableSymbol extends JElementSymbol {

271

/**

272

* Returns the type of this variable

273

*/

274

JTypeMirror getTypeMirror();

275

276

/**

277

* Returns true if this variable is effectively final

278

*/

279

boolean isEffectivelyFinal();

280

281

/**

282

* Returns the modifiers of this variable

283

*/

284

int getModifiers();

285

}

286

287

/**

288

* Represents local variable symbols

289

*/

290

public interface JLocalVariableSymbol extends JVariableSymbol {

291

/**

292

* Returns true if this is a final local variable

293

*/

294

boolean isFinal();

295

}

296

297

/**

298

* Represents formal parameter symbols

299

*/

300

public interface JFormalParamSymbol extends JVariableSymbol {

301

/**

302

* Returns true if this is a varargs parameter

303

*/

304

boolean isVarargs();

305

306

/**

307

* Returns true if this is a final parameter

308

*/

309

boolean isFinal();

310

}

311

```

312

313

### Symbol Table

314

315

```java { .api }

316

/**

317

* Provides symbol resolution within scopes

318

*/

319

public interface JSymbolTable {

320

/**

321

* Resolve variables by simple name in the current scope

322

*/

323

List<JVariableSymbol> variables();

324

325

/**

326

* Resolve types by simple name in the current scope

327

*/

328

List<JClassSymbol> types();

329

330

/**

331

* Resolve methods by simple name in the current scope

332

*/

333

List<JMethodSymbol> methods();

334

}

335

```

336

337

## Type System

338

339

The type system provides complete representation of Java types including generics, wildcards, and type inference.

340

341

### Base Type Interface

342

343

```java { .api }

344

/**

345

* Type mirrors represent Java types

346

*/

347

public interface JTypeMirror extends JTypeVisitable {

348

/**

349

* Returns the type system that built this type

350

*/

351

TypeSystem getTypeSystem();

352

353

/**

354

* Return annotations on this type

355

*/

356

PSet<SymAnnot> getTypeAnnotations();

357

358

/**

359

* Returns true if this type is the same type or a subtype of the given type

360

*/

361

default boolean isSubtypeOf(@NonNull JTypeMirror other);

362

363

/**

364

* Tests this type's convertibility to the other type

365

*/

366

default Convertibility isConvertibleTo(@NonNull JTypeMirror other);

367

368

/**

369

* Returns the set of (nominal) supertypes of this type

370

*/

371

default Set<JTypeMirror> getSuperTypeSet();

372

373

/**

374

* Returns the erased version of this type (removes generics)

375

*/

376

JTypeMirror getErasure();

377

378

/**

379

* Returns the symbol that declared this type (class/interface/primitive)

380

*/

381

@Nullable JTypeDeclSymbol getSymbol();

382

383

/**

384

* Returns the boxed version of this type (primitive -> wrapper)

385

*/

386

default JTypeMirror box();

387

388

/**

389

* Returns the unboxed version of this type (wrapper -> primitive)

390

*/

391

default JTypeMirror unbox();

392

393

// Type checking methods

394

boolean isPrimitive();

395

boolean isArray();

396

boolean isClassOrInterface();

397

boolean isInterface();

398

boolean isClass();

399

boolean isGeneric();

400

boolean isParameterizedType();

401

boolean isRaw();

402

boolean isTypeVariable();

403

boolean isWildcard();

404

boolean isIntersectionType();

405

boolean isBottom();

406

boolean isTop();

407

}

408

```

409

410

### Primitive Types

411

412

```java { .api }

413

/**

414

* Represents primitive types (int, boolean, etc.)

415

*/

416

public interface JPrimitiveType extends JTypeMirror {

417

/**

418

* Returns the kind of primitive type

419

*/

420

PrimitiveTypeKind getKind();

421

422

/**

423

* Returns the wrapper class type for this primitive

424

*/

425

JClassType box();

426

427

/**

428

* Enumeration of primitive type kinds

429

*/

430

enum PrimitiveTypeKind {

431

BOOLEAN("boolean", boolean.class),

432

BYTE("byte", byte.class),

433

SHORT("short", short.class),

434

INT("int", int.class),

435

LONG("long", long.class),

436

CHAR("char", char.class),

437

FLOAT("float", float.class),

438

DOUBLE("double", double.class);

439

440

String getSimpleName();

441

Class<?> toReflect();

442

}

443

}

444

```

445

446

### Class Types

447

448

```java { .api }

449

/**

450

* Represents class and interface types (possibly generic)

451

*/

452

public interface JClassType extends JTypeMirror {

453

/**

454

* Returns the type arguments of this parameterized type

455

*/

456

List<JTypeMirror> getTypeArgs();

457

458

/**

459

* Returns the generic type declaration

460

*/

461

JGenericDeclaration getGenericTypeDeclaration();

462

463

/**

464

* Returns the raw type (without type arguments)

465

*/

466

JClassType getRawType();

467

468

/**

469

* Returns true if this is a raw type

470

*/

471

boolean isRaw();

472

473

/**

474

* Returns true if this is a parameterized type

475

*/

476

boolean isParameterized();

477

478

/**

479

* Returns the class symbol

480

*/

481

@Override

482

JClassSymbol getSymbol();

483

484

/**

485

* Returns the enclosing type for nested classes

486

*/

487

@Nullable JClassType getEnclosingType();

488

489

/**

490

* Returns a field with the given name accessible from this type

491

*/

492

@Nullable JFieldSymbol getDeclaredField(String fieldName);

493

494

/**

495

* Returns a nested class with the given name

496

*/

497

@Nullable JClassSymbol getDeclaredClass(String name);

498

499

/**

500

* Applies a substitution to this type

501

*/

502

JClassType subst(Substitution substitution);

503

504

/**

505

* Returns the superclass type

506

*/

507

@Nullable JClassType getSuperClass();

508

509

/**

510

* Returns the super interface types

511

*/

512

List<JClassType> getSuperInterfaces();

513

514

/**

515

* Returns all supertypes (direct and indirect)

516

*/

517

Stream<JClassType> streamSuperTypes();

518

}

519

```

520

521

### Array Types

522

523

```java { .api }

524

/**

525

* Represents array types

526

*/

527

public interface JArrayType extends JTypeMirror {

528

/**

529

* Returns the component type of this array

530

*/

531

JTypeMirror getComponentType();

532

533

/**

534

* Returns the element type (ultimate component for multi-dimensional arrays)

535

*/

536

JTypeMirror getElementType();

537

538

/**

539

* Returns the number of array dimensions

540

*/

541

int getNumDimensions();

542

543

/**

544

* Returns the array symbol

545

*/

546

@Override

547

JClassSymbol getSymbol();

548

549

/**

550

* Creates a new array type with additional dimensions

551

*/

552

JArrayType addDimensions(int n);

553

}

554

```

555

556

### Type Variables

557

558

```java { .api }

559

/**

560

* Represents type variables (generic type parameters)

561

*/

562

public interface JTypeVar extends JTypeMirror {

563

/**

564

* Returns the name of this type variable

565

*/

566

String getName();

567

568

/**

569

* Returns the type parameter symbol

570

*/

571

JTypeParameterSymbol getSymbol();

572

573

/**

574

* Returns the upper bounds of this type variable

575

*/

576

List<JTypeMirror> getUpperBounds();

577

578

/**

579

* Returns the lower bounds of this type variable

580

*/

581

List<JTypeMirror> getLowerBounds();

582

}

583

```

584

585

### Wildcard Types

586

587

```java { .api }

588

/**

589

* Represents wildcard types (? extends, ? super)

590

*/

591

public interface JWildcardType extends JTypeMirror {

592

/**

593

* Returns the upper bound (extends clause)

594

*/

595

@Nullable JTypeMirror getUpperBound();

596

597

/**

598

* Returns the lower bound (super clause)

599

*/

600

@Nullable JTypeMirror getLowerBound();

601

602

/**

603

* Returns true if this is an unbounded wildcard (?)

604

*/

605

boolean isUnbounded();

606

607

/**

608

* Returns true if this is an upper bounded wildcard (? extends T)

609

*/

610

boolean isUpperBounded();

611

612

/**

613

* Returns true if this is a lower bounded wildcard (? super T)

614

*/

615

boolean isLowerBounded();

616

}

617

```

618

619

### Type System Factory

620

621

```java { .api }

622

/**

623

* Factory and registry for all types

624

*/

625

public class TypeSystem {

626

// Special type constants

627

public static final JTypeMirror OBJECT = /* ... */;

628

public static final JTypeMirror NULL_TYPE = /* ... */;

629

public static final JTypeMirror ERROR = /* ... */;

630

public static final JTypeMirror UNKNOWN = /* ... */;

631

public static final JTypeMirror NO_TYPE = /* ... */;

632

633

// Primitive type constants

634

public static final JPrimitiveType BOOLEAN = /* ... */;

635

public static final JPrimitiveType BYTE = /* ... */;

636

public static final JPrimitiveType SHORT = /* ... */;

637

public static final JPrimitiveType INT = /* ... */;

638

public static final JPrimitiveType LONG = /* ... */;

639

public static final JPrimitiveType CHAR = /* ... */;

640

public static final JPrimitiveType FLOAT = /* ... */;

641

public static final JPrimitiveType DOUBLE = /* ... */;

642

643

/**

644

* Returns the type mirror for the given class

645

*/

646

public JTypeMirror typeOf(Class<?> clazz);

647

648

/**

649

* Returns the type mirror for the given class symbol

650

*/

651

public JClassType typeOf(JClassSymbol symbol);

652

653

/**

654

* Creates an array type with the given component type

655

*/

656

public JArrayType arrayOf(JTypeMirror componentType);

657

658

/**

659

* Creates a parameterized type

660

*/

661

public JClassType parameterize(JClassSymbol symbol, List<JTypeMirror> typeArgs);

662

663

/**

664

* Creates a wildcard type

665

*/

666

public JWildcardType wildcard(boolean isExtends, @Nullable JTypeMirror bound);

667

668

/**

669

* Returns the least upper bound of the given types

670

*/

671

public JTypeMirror lub(List<JTypeMirror> types);

672

673

/**

674

* Returns the greatest lower bound of the given types

675

*/

676

public JTypeMirror glb(List<JTypeMirror> types);

677

678

/**

679

* Performs type inference for method calls

680

*/

681

public Substitution inferMethodTypeArgs(JMethodSymbol method,

682

List<JTypeMirror> actualArgs);

683

}

684

```

685

686

## Usage Examples

687

688

### Basic Symbol Resolution

689

690

```java

691

// Example: Find all method calls to a specific method

692

public class MethodCallAnalyzer extends JavaVisitorBase<Void, Void> {

693

private String targetMethod;

694

private JClassSymbol targetClass;

695

private List<ASTMethodCall> matchingCalls = new ArrayList<>();

696

697

@Override

698

public Void visit(ASTMethodCall node, Void data) {

699

// Get the method symbol

700

JMethodSymbol methodSymbol = node.getMethodType();

701

702

if (methodSymbol != null && !methodSymbol.isUnresolved()) {

703

// Check if this is the target method

704

if (methodSymbol.nameEquals(targetMethod) &&

705

methodSymbol.getEnclosingClass().equals(targetClass)) {

706

matchingCalls.add(node);

707

}

708

}

709

710

return super.visit(node, data);

711

}

712

}

713

```

714

715

### Type Analysis

716

717

```java

718

// Example: Analyze generic type usage

719

public class GenericTypeAnalyzer extends JavaVisitorBase<Void, Void> {

720

@Override

721

public Void visit(ASTVariableDeclaration node, Void data) {

722

JTypeMirror varType = node.getTypeMirror();

723

724

if (varType.isClassOrInterface()) {

725

JClassType classType = (JClassType) varType;

726

727

if (classType.isParameterized()) {

728

System.out.println("Found parameterized type: " + classType);

729

730

// Analyze type arguments

731

for (JTypeMirror typeArg : classType.getTypeArgs()) {

732

if (typeArg.isWildcard()) {

733

JWildcardType wildcard = (JWildcardType) typeArg;

734

System.out.println(" Wildcard: " + wildcard);

735

736

if (wildcard.isUpperBounded()) {

737

System.out.println(" Upper bound: " + wildcard.getUpperBound());

738

}

739

if (wildcard.isLowerBounded()) {

740

System.out.println(" Lower bound: " + wildcard.getLowerBound());

741

}

742

}

743

}

744

} else if (classType.isRaw()) {

745

System.out.println("Found raw type usage: " + classType);

746

}

747

}

748

749

return super.visit(node, data);

750

}

751

}

752

```

753

754

### Inheritance Analysis

755

756

```java

757

// Example: Find all classes that implement a specific interface

758

public class InterfaceImplementationFinder extends JavaVisitorBase<Void, Void> {

759

private JClassSymbol targetInterface;

760

private List<JClassSymbol> implementations = new ArrayList<>();

761

762

@Override

763

public Void visit(ASTClassDeclaration node, Void data) {

764

JClassSymbol classSymbol = node.getSymbol();

765

766

if (classSymbol != null) {

767

// Check if this class implements the target interface

768

if (implementsInterface(classSymbol, targetInterface)) {

769

implementations.add(classSymbol);

770

}

771

}

772

773

return super.visit(node, data);

774

}

775

776

private boolean implementsInterface(JClassSymbol clazz, JClassSymbol targetIntf) {

777

// Direct implementation check

778

for (JClassSymbol superIntf : clazz.getSuperInterfaces()) {

779

if (superIntf.equals(targetIntf)) {

780

return true;

781

}

782

}

783

784

// Recursive check through superclass

785

JClassSymbol superclass = clazz.getSuperclass();

786

if (superclass != null) {

787

return implementsInterface(superclass, targetIntf);

788

}

789

790

// Recursive check through super-interfaces

791

for (JClassSymbol superIntf : clazz.getSuperInterfaces()) {

792

if (implementsInterface(superIntf, targetIntf)) {

793

return true;

794

}

795

}

796

797

return false;

798

}

799

}

800

```