diff --git a/pkl-core/src/main/java/org/pkl/core/BufferedLogger.java b/pkl-core/src/main/java/org/pkl/core/BufferedLogger.java
index 1f1ce499..11971634 100644
--- a/pkl-core/src/main/java/org/pkl/core/BufferedLogger.java
+++ b/pkl-core/src/main/java/org/pkl/core/BufferedLogger.java
@@ -16,7 +16,7 @@
package org.pkl.core;
/** A logger that keeps messages locally and can return them. */
-public class BufferedLogger implements Logger {
+public final class BufferedLogger implements Logger {
private final StringBuilder builder = new StringBuilder();
private final Logger logger;
diff --git a/pkl-core/src/main/java/org/pkl/core/Loggers.java b/pkl-core/src/main/java/org/pkl/core/Loggers.java
index a9c6b3c7..62c5d941 100644
--- a/pkl-core/src/main/java/org/pkl/core/Loggers.java
+++ b/pkl-core/src/main/java/org/pkl/core/Loggers.java
@@ -21,6 +21,8 @@ import java.io.PrintWriter;
/** Predefined {@link Logger}s. */
@SuppressWarnings("unused")
public final class Loggers {
+ private Loggers() {}
+
/** Returns a logger that discards log messages. */
public static Logger noop() {
return new Logger() {
diff --git a/pkl-core/src/main/java/org/pkl/core/ModuleSource.java b/pkl-core/src/main/java/org/pkl/core/ModuleSource.java
index 574899a2..f008dcaa 100644
--- a/pkl-core/src/main/java/org/pkl/core/ModuleSource.java
+++ b/pkl-core/src/main/java/org/pkl/core/ModuleSource.java
@@ -27,7 +27,7 @@ import org.pkl.core.util.Nullable;
*
Create a new module source via {@link #create(URI, String)}, or one of the various helper
* factory methods.
*/
-public class ModuleSource {
+public final class ModuleSource {
public static ModuleSource create(URI uri, @Nullable String text) {
return new ModuleSource(uri, text);
}
diff --git a/pkl-core/src/main/java/org/pkl/core/Release.java b/pkl-core/src/main/java/org/pkl/core/Release.java
index d647ba52..ede7c53f 100644
--- a/pkl-core/src/main/java/org/pkl/core/Release.java
+++ b/pkl-core/src/main/java/org/pkl/core/Release.java
@@ -27,7 +27,7 @@ import java.util.Set;
* Information about the Pkl release that the current program runs on. This class is the Java
* equivalent of standard library module {@code pkl.release}.
*/
-public class Release {
+public final class Release {
private static final String SOURCE_CODE_HOMEPAGE = "https://github.com/apple/pkl/";
private static final String DOCUMENTATION_HOMEPAGE = "https://pkl-lang.org/main/";
diff --git a/pkl-core/src/main/java/org/pkl/core/RendererException.java b/pkl-core/src/main/java/org/pkl/core/RendererException.java
index a6fc7de0..43f56c81 100644
--- a/pkl-core/src/main/java/org/pkl/core/RendererException.java
+++ b/pkl-core/src/main/java/org/pkl/core/RendererException.java
@@ -15,7 +15,7 @@
*/
package org.pkl.core;
-public class RendererException extends RuntimeException {
+public final class RendererException extends RuntimeException {
public RendererException(String message) {
super(message);
}
diff --git a/pkl-core/src/main/java/org/pkl/core/SecurityManagerException.java b/pkl-core/src/main/java/org/pkl/core/SecurityManagerException.java
index e7ae124f..063cd282 100644
--- a/pkl-core/src/main/java/org/pkl/core/SecurityManagerException.java
+++ b/pkl-core/src/main/java/org/pkl/core/SecurityManagerException.java
@@ -20,7 +20,7 @@ package org.pkl.core;
*
*
{@link SecurityManagerException#getMessage()} is passed to users when errors arise.
*/
-public class SecurityManagerException extends Exception {
+public final class SecurityManagerException extends Exception {
public SecurityManagerException(String message) {
super(message);
}
diff --git a/pkl-core/src/main/java/org/pkl/core/ast/VmModifier.java b/pkl-core/src/main/java/org/pkl/core/ast/VmModifier.java
index 37dc6290..6181cbde 100644
--- a/pkl-core/src/main/java/org/pkl/core/ast/VmModifier.java
+++ b/pkl-core/src/main/java/org/pkl/core/ast/VmModifier.java
@@ -22,6 +22,8 @@ import org.pkl.core.runtime.VmExceptionBuilder;
import org.pkl.core.runtime.VmSet;
public final class VmModifier {
+ private VmModifier() {}
+
// user-facing modifiers
public static final int ABSTRACT = 0x1;
diff --git a/pkl-core/src/main/java/org/pkl/core/ast/builder/ImportsAndReadsParser.java b/pkl-core/src/main/java/org/pkl/core/ast/builder/ImportsAndReadsParser.java
index 4a54f073..a8ec2eda 100644
--- a/pkl-core/src/main/java/org/pkl/core/ast/builder/ImportsAndReadsParser.java
+++ b/pkl-core/src/main/java/org/pkl/core/ast/builder/ImportsAndReadsParser.java
@@ -46,7 +46,7 @@ import org.pkl.core.util.Pair;
*
read expressions
*
*/
-public class ImportsAndReadsParser
+public final class ImportsAndReadsParser
extends AbstractAstBuilder<@Nullable List>> {
/** Parses a module, and collects all imports and reads. */
@@ -69,7 +69,7 @@ public class ImportsAndReadsParser
}
@Override
- public @Nullable List> visitModuleExtendsOrAmendsClause(
+ public List> visitModuleExtendsOrAmendsClause(
ModuleExtendsOrAmendsClauseContext ctx) {
var importStr = doVisitSingleLineConstantStringPart(ctx.stringConstant().ts);
var sourceSection = createSourceSection(ctx.stringConstant());
diff --git a/pkl-core/src/main/java/org/pkl/core/http/HttpClientInitException.java b/pkl-core/src/main/java/org/pkl/core/http/HttpClientInitException.java
index a0a716a5..3ef9409a 100644
--- a/pkl-core/src/main/java/org/pkl/core/http/HttpClientInitException.java
+++ b/pkl-core/src/main/java/org/pkl/core/http/HttpClientInitException.java
@@ -19,7 +19,7 @@ package org.pkl.core.http;
* Indicates that an error occurred while initializing an HTTP client. A common example is an error
* reading or parsing a certificate.
*/
-public class HttpClientInitException extends RuntimeException {
+public final class HttpClientInitException extends RuntimeException {
public HttpClientInitException(String message) {
super(message);
}
diff --git a/pkl-core/src/main/java/org/pkl/core/http/LazyHttpClient.java b/pkl-core/src/main/java/org/pkl/core/http/LazyHttpClient.java
index a9eb6d48..6231c7ea 100644
--- a/pkl-core/src/main/java/org/pkl/core/http/LazyHttpClient.java
+++ b/pkl-core/src/main/java/org/pkl/core/http/LazyHttpClient.java
@@ -29,7 +29,7 @@ import javax.annotation.concurrent.ThreadSafe;
* send.
*/
@ThreadSafe
-class LazyHttpClient implements HttpClient {
+final class LazyHttpClient implements HttpClient {
private final Supplier supplier;
private final Object lock = new Object();
diff --git a/pkl-core/src/main/java/org/pkl/core/module/FileResolver.java b/pkl-core/src/main/java/org/pkl/core/module/FileResolver.java
index 953a066f..30072475 100644
--- a/pkl-core/src/main/java/org/pkl/core/module/FileResolver.java
+++ b/pkl-core/src/main/java/org/pkl/core/module/FileResolver.java
@@ -25,7 +25,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-public class FileResolver {
+public final class FileResolver {
private FileResolver() {}
public static List listElements(URI baseUri) throws IOException {
diff --git a/pkl-core/src/main/java/org/pkl/core/module/ModulePathResolver.java b/pkl-core/src/main/java/org/pkl/core/module/ModulePathResolver.java
index 0a049d47..47a0eb77 100644
--- a/pkl-core/src/main/java/org/pkl/core/module/ModulePathResolver.java
+++ b/pkl-core/src/main/java/org/pkl/core/module/ModulePathResolver.java
@@ -38,7 +38,7 @@ import org.pkl.core.util.LateInit;
*
NOTE: Do not initialize two resolvers for the same jar or zip file. Instead, share the same
* resolver for that jar or zip file.
*/
-public class ModulePathResolver implements AutoCloseable {
+public final class ModulePathResolver implements AutoCloseable {
private final Iterable modulePath;
private final Object lock = new Object();
diff --git a/pkl-core/src/main/java/org/pkl/core/module/PathElement.java b/pkl-core/src/main/java/org/pkl/core/module/PathElement.java
index e3128a83..bc7df11e 100644
--- a/pkl-core/src/main/java/org/pkl/core/module/PathElement.java
+++ b/pkl-core/src/main/java/org/pkl/core/module/PathElement.java
@@ -80,7 +80,7 @@ public class PathElement {
return "PathElement{" + "name='" + name + '\'' + ", isDirectory=" + isDirectory + '}';
}
- public static class TreePathElement extends PathElement {
+ public static final class TreePathElement extends PathElement {
private final EconomicMap children = EconomicMaps.create();
public TreePathElement(String name, boolean isDirectory) {
diff --git a/pkl-core/src/main/java/org/pkl/core/module/ProjectDependenciesManager.java b/pkl-core/src/main/java/org/pkl/core/module/ProjectDependenciesManager.java
index f99d163e..b07ee29d 100644
--- a/pkl-core/src/main/java/org/pkl/core/module/ProjectDependenciesManager.java
+++ b/pkl-core/src/main/java/org/pkl/core/module/ProjectDependenciesManager.java
@@ -35,7 +35,7 @@ import org.pkl.core.runtime.VmExceptionBuilder;
import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.json.Json.JsonParseException;
-public class ProjectDependenciesManager {
+public final class ProjectDependenciesManager {
public static final String PKL_PROJECT_FILENAME = "PklProject";
public static final String PKL_PROJECT_DEPS_FILENAME = "PklProject.deps.json";
diff --git a/pkl-core/src/main/java/org/pkl/core/packages/DependencyMetadata.java b/pkl-core/src/main/java/org/pkl/core/packages/DependencyMetadata.java
index 53f3de17..5f377bbb 100644
--- a/pkl-core/src/main/java/org/pkl/core/packages/DependencyMetadata.java
+++ b/pkl-core/src/main/java/org/pkl/core/packages/DependencyMetadata.java
@@ -70,7 +70,7 @@ import org.pkl.core.util.json.JsonWriter;
*/
@SuppressWarnings({"JavadocLinkAsPlainText", "unused"})
// incorrectly thinks link within sample metadata is a JavaDoc link
-public class DependencyMetadata {
+public final class DependencyMetadata {
public static DependencyMetadata parse(String input) throws JsonParseException {
var parsed = Json.parseObject(input);
diff --git a/pkl-core/src/main/java/org/pkl/core/packages/PackageAssetUri.java b/pkl-core/src/main/java/org/pkl/core/packages/PackageAssetUri.java
index 7c39af5f..6e52146b 100644
--- a/pkl-core/src/main/java/org/pkl/core/packages/PackageAssetUri.java
+++ b/pkl-core/src/main/java/org/pkl/core/packages/PackageAssetUri.java
@@ -25,7 +25,7 @@ import org.pkl.core.util.ErrorMessages;
* The canonical URI of an asset within a package, i.e., a package URI with a fragment path. For
* example, {@code package://example.com/my/package@1.0.0#/my/module.pkl}
*/
-public class PackageAssetUri {
+public final class PackageAssetUri {
private final URI uri;
private final PackageUri packageUri;
private final Path assetPath;
diff --git a/pkl-core/src/main/java/org/pkl/core/packages/PackageLoadError.java b/pkl-core/src/main/java/org/pkl/core/packages/PackageLoadError.java
index 499abb9d..089311f1 100644
--- a/pkl-core/src/main/java/org/pkl/core/packages/PackageLoadError.java
+++ b/pkl-core/src/main/java/org/pkl/core/packages/PackageLoadError.java
@@ -17,7 +17,7 @@ package org.pkl.core.packages;
import org.pkl.core.util.ErrorMessages;
-public class PackageLoadError extends RuntimeException {
+public final class PackageLoadError extends RuntimeException {
private final String messageName;
private final Object[] arguments;
diff --git a/pkl-core/src/main/java/org/pkl/core/packages/PackageResolvers.java b/pkl-core/src/main/java/org/pkl/core/packages/PackageResolvers.java
index 112f7ad3..7f645eb4 100644
--- a/pkl-core/src/main/java/org/pkl/core/packages/PackageResolvers.java
+++ b/pkl-core/src/main/java/org/pkl/core/packages/PackageResolvers.java
@@ -60,7 +60,9 @@ import org.pkl.core.util.Nullable;
import org.pkl.core.util.Pair;
import org.pkl.core.util.json.Json.JsonParseException;
-class PackageResolvers {
+final class PackageResolvers {
+ private PackageResolvers() {}
+
abstract static class AbstractPackageResolver implements PackageResolver {
@GuardedBy("lock")
private final EconomicMap cachedDependencyMetadata;
@@ -245,7 +247,7 @@ class PackageResolvers {
*
*
This gets used when the cache dir is not set.
*/
- static class InMemoryPackageResolver extends AbstractPackageResolver {
+ static final class InMemoryPackageResolver extends AbstractPackageResolver {
@GuardedBy("lock")
private final EconomicMap> cachedEntries =
EconomicMaps.create();
@@ -406,7 +408,7 @@ class PackageResolvers {
*
Uses the built-in zip file system in {@link jdk.nio.zipfs} for reading files from the zip
* archive.
*/
- static class DiskCachedPackageResolver extends AbstractPackageResolver {
+ static final class DiskCachedPackageResolver extends AbstractPackageResolver {
private final Path cacheDir;
private final Path tmpDir;
diff --git a/pkl-core/src/main/java/org/pkl/core/packages/PackageUri.java b/pkl-core/src/main/java/org/pkl/core/packages/PackageUri.java
index 7b61b30e..89b22aed 100644
--- a/pkl-core/src/main/java/org/pkl/core/packages/PackageUri.java
+++ b/pkl-core/src/main/java/org/pkl/core/packages/PackageUri.java
@@ -23,7 +23,7 @@ import org.pkl.core.util.ErrorMessages;
import org.pkl.core.util.IoUtils;
import org.pkl.core.util.Nullable;
-public class PackageUri {
+public final class PackageUri {
private final URI uri;
private final Version version;
private final String pathWithoutVersion;
diff --git a/pkl-core/src/main/java/org/pkl/core/packages/PackageUtils.java b/pkl-core/src/main/java/org/pkl/core/packages/PackageUtils.java
index 6adb29cf..a049eb79 100644
--- a/pkl-core/src/main/java/org/pkl/core/packages/PackageUtils.java
+++ b/pkl-core/src/main/java/org/pkl/core/packages/PackageUtils.java
@@ -20,7 +20,9 @@ import org.pkl.core.util.ErrorMessages;
import org.pkl.core.util.json.Json.FormatException;
import org.pkl.core.util.json.Json.JsonParseException;
-public class PackageUtils {
+public final class PackageUtils {
+ private PackageUtils() {}
+
public static PackageUri parsePackageUriWithoutChecksums(Object obj)
throws JsonParseException, URISyntaxException {
if (!(obj instanceof String string)) {
diff --git a/pkl-core/src/main/java/org/pkl/core/parser/ErrorStrategy.java b/pkl-core/src/main/java/org/pkl/core/parser/ErrorStrategy.java
index 7503f55a..a26df67f 100644
--- a/pkl-core/src/main/java/org/pkl/core/parser/ErrorStrategy.java
+++ b/pkl-core/src/main/java/org/pkl/core/parser/ErrorStrategy.java
@@ -20,7 +20,7 @@ import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.pkl.core.parser.antlr.PklParser;
-class ErrorStrategy extends DefaultErrorStrategy {
+final class ErrorStrategy extends DefaultErrorStrategy {
@Override
protected void reportNoViableAlternative(Parser parser, NoViableAltException e) {
var builder = new StringBuilder();
diff --git a/pkl-core/src/main/java/org/pkl/core/parser/LexParseException.java b/pkl-core/src/main/java/org/pkl/core/parser/LexParseException.java
index 159c3684..25be17f2 100644
--- a/pkl-core/src/main/java/org/pkl/core/parser/LexParseException.java
+++ b/pkl-core/src/main/java/org/pkl/core/parser/LexParseException.java
@@ -67,7 +67,7 @@ public abstract class LexParseException extends RuntimeException {
return this;
}
- public static class LexError extends LexParseException {
+ public static final class LexError extends LexParseException {
public LexError(String message, int line, int column, int length) {
super(message, line, column, length, Integer.MAX_VALUE);
}
@@ -79,7 +79,7 @@ public abstract class LexParseException extends RuntimeException {
}
}
- public static class IncompleteInput extends ParseError {
+ public static final class IncompleteInput extends ParseError {
public IncompleteInput(String message, int line, int column, int length) {
super(message, line, column, length, Integer.MAX_VALUE - 1);
}
diff --git a/pkl-core/src/main/java/org/pkl/core/parser/Lexer.java b/pkl-core/src/main/java/org/pkl/core/parser/Lexer.java
index e9196810..6e5b35ea 100644
--- a/pkl-core/src/main/java/org/pkl/core/parser/Lexer.java
+++ b/pkl-core/src/main/java/org/pkl/core/parser/Lexer.java
@@ -23,7 +23,7 @@ import org.antlr.v4.runtime.*;
import org.pkl.core.parser.antlr.PklLexer;
import org.pkl.core.util.Nullable;
-public class Lexer {
+public final class Lexer {
public static final Set KEYWORD_TYPES;
public static final Set KEYWORD_NAMES;
diff --git a/pkl-core/src/main/java/org/pkl/core/parser/Parser.java b/pkl-core/src/main/java/org/pkl/core/parser/Parser.java
index 4fe45128..435bf01e 100644
--- a/pkl-core/src/main/java/org/pkl/core/parser/Parser.java
+++ b/pkl-core/src/main/java/org/pkl/core/parser/Parser.java
@@ -29,7 +29,7 @@ import org.pkl.core.parser.antlr.PklParser;
import org.pkl.core.parser.antlr.PklParser.*;
import org.pkl.core.util.Nullable;
-public class Parser {
+public final class Parser {
@TruffleBoundary
public PklParser createParser(
TokenStream stream, @Nullable List errorCollector) {
diff --git a/pkl-core/src/main/java/org/pkl/core/project/CanonicalPackageUri.java b/pkl-core/src/main/java/org/pkl/core/project/CanonicalPackageUri.java
index 669f6ca7..7cfcbf07 100644
--- a/pkl-core/src/main/java/org/pkl/core/project/CanonicalPackageUri.java
+++ b/pkl-core/src/main/java/org/pkl/core/project/CanonicalPackageUri.java
@@ -29,7 +29,7 @@ import org.pkl.core.util.ErrorMessages;
* package://example.com/foo/bar@0}. Does not include a URI's userinfo, query params or fragment
* segments.
*/
-public class CanonicalPackageUri {
+public final class CanonicalPackageUri {
private final URI baseUri;
private final int majorVersion;
diff --git a/pkl-core/src/main/java/org/pkl/core/project/DeclaredDependencies.java b/pkl-core/src/main/java/org/pkl/core/project/DeclaredDependencies.java
index 702994d5..1f3c0a88 100644
--- a/pkl-core/src/main/java/org/pkl/core/project/DeclaredDependencies.java
+++ b/pkl-core/src/main/java/org/pkl/core/project/DeclaredDependencies.java
@@ -21,7 +21,7 @@ import org.pkl.core.packages.Dependency.RemoteDependency;
import org.pkl.core.packages.PackageUri;
import org.pkl.core.util.Nullable;
-public class DeclaredDependencies {
+public final class DeclaredDependencies {
private final Map remoteDependencies;
private final Map localDependencies;
private final URI projectFileUri;
diff --git a/pkl-core/src/main/java/org/pkl/core/project/ProjectDependenciesResolver.java b/pkl-core/src/main/java/org/pkl/core/project/ProjectDependenciesResolver.java
index 55489940..d37f3c7f 100644
--- a/pkl-core/src/main/java/org/pkl/core/project/ProjectDependenciesResolver.java
+++ b/pkl-core/src/main/java/org/pkl/core/project/ProjectDependenciesResolver.java
@@ -43,7 +43,7 @@ import org.pkl.core.util.Nullable;
*
*
Resolved dependencies have URI `projectpackage` to indicate that they should be project-local.
*/
-public class ProjectDependenciesResolver {
+public final class ProjectDependenciesResolver {
private final Project project;
private final PackageResolver packageResolver;
private final Writer logWriter;
diff --git a/pkl-core/src/main/java/org/pkl/core/project/ProjectDeps.java b/pkl-core/src/main/java/org/pkl/core/project/ProjectDeps.java
index d8251ffa..d5b61b59 100644
--- a/pkl-core/src/main/java/org/pkl/core/project/ProjectDeps.java
+++ b/pkl-core/src/main/java/org/pkl/core/project/ProjectDeps.java
@@ -75,7 +75,7 @@ import org.pkl.core.util.json.JsonWriter;
*
*
*/
-public class ProjectDeps {
+public final class ProjectDeps {
private static final Set supportedSchemaVersions = Set.of(1);
private final EconomicMap resolvedDependencies;
diff --git a/pkl-core/src/main/java/org/pkl/core/project/ProjectPackager.java b/pkl-core/src/main/java/org/pkl/core/project/ProjectPackager.java
index 9cdd2bbf..f1bffab3 100644
--- a/pkl-core/src/main/java/org/pkl/core/project/ProjectPackager.java
+++ b/pkl-core/src/main/java/org/pkl/core/project/ProjectPackager.java
@@ -78,7 +78,7 @@ import org.pkl.core.util.Pair;
*
thepackage@1.0.0.zip.sha256 - the SHA-256 checksum of the zip archive
*
*/
-public class ProjectPackager {
+public final class ProjectPackager {
/**
* Modification time value for all zip entries in a package, to ensure that archives are
* reproducible.
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/FileSystemManager.java b/pkl-core/src/main/java/org/pkl/core/runtime/FileSystemManager.java
index 6e3fcf8f..127b2a4c 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/FileSystemManager.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/FileSystemManager.java
@@ -40,7 +40,9 @@ import org.pkl.core.util.EconomicMaps;
*
*
File systems are only closed when the last usage of it closes.
*/
-public class FileSystemManager {
+public final class FileSystemManager {
+ private FileSystemManager() {}
+
private static final EconomicMap fileSystems = EconomicMaps.create();
private static final Map counts = new IdentityHashMap<>();
@@ -98,7 +100,7 @@ public class FileSystemManager {
}
}
- private static class Handle extends FileSystem {
+ private static final class Handle extends FileSystem {
final FileSystem delegate;
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/KeyLookupSuggestions.java b/pkl-core/src/main/java/org/pkl/core/runtime/KeyLookupSuggestions.java
index 20d27c6c..7536798f 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/KeyLookupSuggestions.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/KeyLookupSuggestions.java
@@ -22,7 +22,9 @@ import org.pkl.core.ValueFormatter;
import org.pkl.core.util.Nullable;
import org.pkl.core.util.StringSimilarity;
-public class KeyLookupSuggestions {
+public final class KeyLookupSuggestions {
+ private KeyLookupSuggestions() {}
+
private static final StringSimilarity STRING_SIMILARITY = new StringSimilarity();
// 0.77 is just about low enough to consider two three-character
// keys that differ in their first character similar
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/MemberLookupSuggestions.java b/pkl-core/src/main/java/org/pkl/core/runtime/MemberLookupSuggestions.java
index 65005aca..c7248cd7 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/MemberLookupSuggestions.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/MemberLookupSuggestions.java
@@ -24,7 +24,7 @@ import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.Nullable;
import org.pkl.core.util.StringSimilarity;
-public class MemberLookupSuggestions {
+public final class MemberLookupSuggestions {
private static final StringSimilarity STRING_SIMILARITY = new StringSimilarity();
// 0.77 is just about low enough to consider two three-character
// names that differ in their first character similar
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/ProjectModule.java b/pkl-core/src/main/java/org/pkl/core/runtime/ProjectModule.java
index b924196d..fa09d056 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/ProjectModule.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/ProjectModule.java
@@ -17,7 +17,7 @@ package org.pkl.core.runtime;
import static org.pkl.core.PClassInfo.pklProjectUri;
-public class ProjectModule extends StdLibModule {
+public final class ProjectModule extends StdLibModule {
private static final VmTyped instance = VmUtils.createEmptyModule();
static {
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceGenerator.java b/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceGenerator.java
index d04a2ce4..bc5e8a8c 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceGenerator.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceGenerator.java
@@ -24,7 +24,7 @@ import org.pkl.core.StackFrame;
import org.pkl.core.ast.MemberNode;
import org.pkl.core.util.Nullable;
-class StackTraceGenerator {
+final class StackTraceGenerator {
private final VmException exception;
private final List frames = new ArrayList<>();
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceRenderer.java b/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceRenderer.java
index c623cde5..933dc19f 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceRenderer.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceRenderer.java
@@ -21,7 +21,7 @@ import java.util.function.Function;
import org.pkl.core.StackFrame;
import org.pkl.core.util.Nullable;
-public class StackTraceRenderer {
+public final class StackTraceRenderer {
private final Function frameTransformer;
public StackTraceRenderer(Function frameTransformer) {
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/TestRunner.java b/pkl-core/src/main/java/org/pkl/core/runtime/TestRunner.java
index 492d2d12..47da5a83 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/TestRunner.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/TestRunner.java
@@ -32,7 +32,7 @@ import org.pkl.core.util.MutableBoolean;
import org.pkl.core.util.MutableReference;
/** Runs test results examples and facts. */
-public class TestRunner {
+public final class TestRunner {
private static final PklConverter converter = new PklConverter(VmMapping.empty());
private final boolean overwrite;
private final StackFrameTransformer stackFrameTransformer;
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmExceptionBuilder.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmExceptionBuilder.java
index 295e3dfe..9f580183 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/VmExceptionBuilder.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmExceptionBuilder.java
@@ -47,7 +47,7 @@ import org.pkl.core.util.Nullable;
* preferable but isn't currently used. One problem with special formatting is that error
* output doesn't always go to a terminal and hence may be rendered verbatim.)
*/
-public class VmExceptionBuilder {
+public final class VmExceptionBuilder {
private @Nullable Object receiver;
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmExceptionRenderer.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmExceptionRenderer.java
index e88e7624..b1a6d3ea 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/VmExceptionRenderer.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmExceptionRenderer.java
@@ -24,7 +24,7 @@ import org.pkl.core.util.ErrorMessages;
import org.pkl.core.util.Nullable;
import org.pkl.core.util.StringBuilderWriter;
-public class VmExceptionRenderer {
+public final class VmExceptionRenderer {
private final @Nullable StackTraceRenderer stackTraceRenderer;
/**
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmFileDetector.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmFileDetector.java
index 47ca16d6..ab996b89 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/VmFileDetector.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmFileDetector.java
@@ -19,7 +19,7 @@ import java.nio.file.Path;
import java.nio.file.spi.FileTypeDetector;
import org.pkl.core.util.Nullable;
-public class VmFileDetector extends FileTypeDetector {
+public final class VmFileDetector extends FileTypeDetector {
@Override
public @Nullable String probeContentType(Path path) {
var fileName = path.getFileName();
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmStackOverflowException.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmStackOverflowException.java
index 5d6f38e1..3683c241 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/VmStackOverflowException.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmStackOverflowException.java
@@ -17,7 +17,7 @@ package org.pkl.core.runtime;
import java.util.List;
-public class VmStackOverflowException extends VmException {
+public final class VmStackOverflowException extends VmException {
public VmStackOverflowException(StackOverflowError e) {
super("stackOverflow", e, true, new Object[0], List.of(), null, null, null, null);
diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmValueRenderer.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmValueRenderer.java
index b5da886f..1497dad7 100644
--- a/pkl-core/src/main/java/org/pkl/core/runtime/VmValueRenderer.java
+++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmValueRenderer.java
@@ -28,7 +28,7 @@ import org.pkl.core.util.MutableBoolean;
*
Currently prints fully qualified class name for outermost object (if rendered value is an
* object) and omits class names otherwise.
*/
-public class VmValueRenderer {
+public final class VmValueRenderer {
private final int lengthLimit;
private final String leadingOrTrailingNewline;
private final String interiorNewline;
diff --git a/pkl-core/src/main/java/org/pkl/core/service/ExecutorSpiImpl.java b/pkl-core/src/main/java/org/pkl/core/service/ExecutorSpiImpl.java
index 70a820fc..f5072b66 100644
--- a/pkl-core/src/main/java/org/pkl/core/service/ExecutorSpiImpl.java
+++ b/pkl-core/src/main/java/org/pkl/core/service/ExecutorSpiImpl.java
@@ -39,7 +39,7 @@ import org.pkl.executor.spi.v1.ExecutorSpiException;
import org.pkl.executor.spi.v1.ExecutorSpiOptions;
import org.pkl.executor.spi.v1.ExecutorSpiOptions2;
-public class ExecutorSpiImpl implements ExecutorSpi {
+public final class ExecutorSpiImpl implements ExecutorSpi {
private static final int MAX_HTTP_CLIENTS = 3;
// Don't create a new HTTP client for every executor request.
diff --git a/pkl-core/src/main/java/org/pkl/core/stdlib/PathConverterSupport.java b/pkl-core/src/main/java/org/pkl/core/stdlib/PathConverterSupport.java
index 9cdaf021..8b393262 100644
--- a/pkl-core/src/main/java/org/pkl/core/stdlib/PathConverterSupport.java
+++ b/pkl-core/src/main/java/org/pkl/core/stdlib/PathConverterSupport.java
@@ -17,7 +17,8 @@ package org.pkl.core.stdlib;
import org.pkl.core.runtime.Identifier;
-public class PathConverterSupport {
+final class PathConverterSupport {
+ private PathConverterSupport() {}
public static boolean pathMatches(Iterable