// Path: core/javac/src/main/java/tech/harmonysoft/oss/traute/javac/text/ExceptionTextGenerator.java
// public interface ExceptionTextGenerator<T> {
// 
//     @NotNull
//     String generate(@NotNull T context);
// }
// 
// Path: core/javac/src/main/java/tech/harmonysoft/oss/traute/javac/common/CompilationUnitProcessingContext.java
// public class CompilationUnitProcessingContext {
// 
//     private final Set<String> imports = new HashSet<>();
// 
//     @NotNull private final TrautePluginSettings          pluginSettings;
//     @NotNull private final TreeMaker                     astFactory;
//     @NotNull private final Names                         symbolsTable;
//     @NotNull private final TrautePluginLogger            logger;
//     @NotNull private final StatsCollector                statsCollector;
//     @NotNull private final ExceptionTextGeneratorManager exceptionTextGeneratorManager;
//     @NotNull private final PackageInfoManager            packageInfoManager;
// 
//     public CompilationUnitProcessingContext(
//             @NotNull TrautePluginSettings pluginSettings,
//             @NotNull TreeMaker astFactory,
//             @NotNull Names symbolsTable,
//             @NotNull TrautePluginLogger logger,
//             @NotNull StatsCollector statsCollector,
//             @NotNull ExceptionTextGeneratorManager exceptionTextGeneratorManager,
//             @NotNull PackageInfoManager packageInfoManager)
//     {
//         this.pluginSettings = pluginSettings;
//         this.statsCollector = statsCollector;
//         this.astFactory = astFactory;
//         this.symbolsTable = symbolsTable;
//         this.logger = logger;
//         this.exceptionTextGeneratorManager = exceptionTextGeneratorManager;
//         this.packageInfoManager = packageInfoManager;
//     }
// 
//     public void addImport(@NotNull String importText) {
//         imports.add(importText);
//     }
// 
//     @NotNull
//     public TrautePluginSettings getPluginSettings() {
//         return pluginSettings;
//     }
// 
//     @NotNull
//     public Set<String> getImports() {
//         return imports;
//     }
// 
//     @NotNull
//     public TreeMaker getAstFactory() {
//         return astFactory;
//     }
// 
//     @NotNull
//     public Names getSymbolsTable() {
//         return symbolsTable;
//     }
// 
//     @NotNull
//     public TrautePluginLogger getLogger() {
//         return logger;
//     }
// 
//     @NotNull
//     public StatsCollector getStatsCollector() {
//         return statsCollector;
//     }
// 
//     @NotNull
//     public ExceptionTextGeneratorManager getExceptionTextGeneratorManager() {
//         return exceptionTextGeneratorManager;
//     }
// 
//     @NotNull
//     public PackageInfoManager getPackageInfoManager() {
//         return packageInfoManager;
//     }
// }
// 
// Path: core/javac/src/main/java/tech/harmonysoft/oss/traute/javac/instrumentation/AbstractInstrumentator.java
// public abstract class AbstractInstrumentator<T extends InstrumentationInfo> implements Instrumentator<T> {
// 
//     @Override
//     public void instrument(@NotNull T instrumentationInfo) {
//         boolean instrumented = mayBeInstrument(instrumentationInfo);
//         if (instrumented) {
//             instrumentationInfo.getContext().getStatsCollector().increment(instrumentationInfo.getType());
//         }
//     }
// 
//     protected abstract boolean mayBeInstrument(@NotNull T instrumentationInfo);
// }
// 
// Path: core/javac/src/main/java/tech/harmonysoft/oss/traute/javac/util/InstrumentationUtil.java
// @NotNull
// public static JCTree.JCIf buildVarCheck(@NotNull TreeMaker factory,
//                                         @NotNull Names symbolsTable,
//                                         @NotNull String variableName,
//                                         @NotNull String errorMessage,
//                                         @NotNull String exceptionToThrow)
// {
//     return factory.If(
//             factory.Parens(
//                     factory.Binary(
//                             JCTree.Tag.EQ,
//                             factory.Ident(
//                                     symbolsTable.fromString(variableName)
//                             ),
//                             factory.Literal(TypeTag.BOT, null))
//             ),
//             factory.Block(0, List.of(
//                     factory.Throw(
//                             factory.NewClass(
//                                     null,
//                                     nil(),
//                                     buildExceptionClassExpression(exceptionToThrow, factory, symbolsTable),
//                                     List.of(factory.Literal(TypeTag.CLASS, errorMessage)),
//                                     null
//                             )
//                     )
//             )),
//             null
//     );
// }


import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Names;
import org.jetbrains.annotations.NotNull;
import tech.harmonysoft.oss.traute.javac.text.ExceptionTextGenerator;
import tech.harmonysoft.oss.traute.javac.common.CompilationUnitProcessingContext;
import tech.harmonysoft.oss.traute.javac.instrumentation.AbstractInstrumentator;
import static tech.harmonysoft.oss.traute.common.instrumentation.InstrumentationType.METHOD_PARAMETER;
import static tech.harmonysoft.oss.traute.javac.util.InstrumentationUtil.buildVarCheck;
package tech.harmonysoft.oss.traute.javac.instrumentation.parameter;



/**
 * <p>Enhances target method in a way to include a {@code null}-check for the target method parameter.</p>
 * <p>Thread-safe.</p>
 */
public class ParameterInstrumentator extends AbstractInstrumentator<ParameterToInstrumentInfo> {

    @Override
    protected boolean mayBeInstrument(@NotNull ParameterToInstrumentInfo info) {
        String parameterName = info.getMethodParameter().getName().toString();
        CompilationUnitProcessingContext context = info.getContext();
        ExceptionTextGenerator<ParameterToInstrumentInfo> generator =
                context.getExceptionTextGeneratorManager().getGenerator(METHOD_PARAMETER, context.getPluginSettings());
        String errorMessage = generator.generate(info);
        TreeMaker factory = context.getAstFactory();
        Names symbolsTable = context.getSymbolsTable();
// Path: core/javac/src/main/java/tech/harmonysoft/oss/traute/javac/text/ExceptionTextGenerator.java
// public interface ExceptionTextGenerator<T> {
// 
//     @NotNull
//     String generate(@NotNull T context);
// }
// 
// Path: core/javac/src/main/java/tech/harmonysoft/oss/traute/javac/common/CompilationUnitProcessingContext.java
// public class CompilationUnitProcessingContext {
// 
//     private final Set<String> imports = new HashSet<>();
// 
//     @NotNull private final TrautePluginSettings          pluginSettings;
//     @NotNull private final TreeMaker                     astFactory;
//     @NotNull private final Names                         symbolsTable;
//     @NotNull private final TrautePluginLogger            logger;
//     @NotNull private final StatsCollector                statsCollector;
//     @NotNull private final ExceptionTextGeneratorManager exceptionTextGeneratorManager;
//     @NotNull private final PackageInfoManager            packageInfoManager;
// 
//     public CompilationUnitProcessingContext(
//             @NotNull TrautePluginSettings pluginSettings,
//             @NotNull TreeMaker astFactory,
//             @NotNull Names symbolsTable,
//             @NotNull TrautePluginLogger logger,
//             @NotNull StatsCollector statsCollector,
//             @NotNull ExceptionTextGeneratorManager exceptionTextGeneratorManager,
//             @NotNull PackageInfoManager packageInfoManager)
//     {
//         this.pluginSettings = pluginSettings;
//         this.statsCollector = statsCollector;
//         this.astFactory = astFactory;
//         this.symbolsTable = symbolsTable;
//         this.logger = logger;
//         this.exceptionTextGeneratorManager = exceptionTextGeneratorManager;
//         this.packageInfoManager = packageInfoManager;
//     }
// 
//     public void addImport(@NotNull String importText) {
//         imports.add(importText);
//     }
// 
//     @NotNull
//     public TrautePluginSettings getPluginSettings() {
//         return pluginSettings;
//     }
// 
//     @NotNull
//     public Set<String> getImports() {
//         return imports;
//     }
// 
//     @NotNull
//     public TreeMaker getAstFactory() {
//         return astFactory;
//     }
// 
//     @NotNull
//     public Names getSymbolsTable() {
//         return symbolsTable;
//     }
// 
//     @NotNull
//     public TrautePluginLogger getLogger() {
//         return logger;
//     }
// 
//     @NotNull
//     public StatsCollector getStatsCollector() {
//         return statsCollector;
//     }
// 
//     @NotNull
//     public ExceptionTextGeneratorManager getExceptionTextGeneratorManager() {
//         return exceptionTextGeneratorManager;
//     }
// 
//     @NotNull
//     public PackageInfoManager getPackageInfoManager() {
//         return packageInfoManager;
//     }
// }
// 
// Path: core/javac/src/main/java/tech/harmonysoft/oss/traute/javac/instrumentation/AbstractInstrumentator.java
// public abstract class AbstractInstrumentator<T extends InstrumentationInfo> implements Instrumentator<T> {
// 
//     @Override
//     public void instrument(@NotNull T instrumentationInfo) {
//         boolean instrumented = mayBeInstrument(instrumentationInfo);
//         if (instrumented) {
//             instrumentationInfo.getContext().getStatsCollector().increment(instrumentationInfo.getType());
//         }
//     }
// 
//     protected abstract boolean mayBeInstrument(@NotNull T instrumentationInfo);
// }
// 
// Path: core/javac/src/main/java/tech/harmonysoft/oss/traute/javac/util/InstrumentationUtil.java
// @NotNull
// public static JCTree.JCIf buildVarCheck(@NotNull TreeMaker factory,
//                                         @NotNull Names symbolsTable,
//                                         @NotNull String variableName,
//                                         @NotNull String errorMessage,
//                                         @NotNull String exceptionToThrow)
// {
//     return factory.If(
//             factory.Parens(
//                     factory.Binary(
//                             JCTree.Tag.EQ,
//                             factory.Ident(
//                                     symbolsTable.fromString(variableName)
//                             ),
//                             factory.Literal(TypeTag.BOT, null))
//             ),
//             factory.Block(0, List.of(
//                     factory.Throw(
//                             factory.NewClass(
//                                     null,
//                                     nil(),
//                                     buildExceptionClassExpression(exceptionToThrow, factory, symbolsTable),
//                                     List.of(factory.Literal(TypeTag.CLASS, errorMessage)),
//                                     null
//                             )
//                     )
//             )),
//             null
//     );
// }


// Path: core/javac/src/main/java/tech/harmonysoft/oss/traute/javac/instrumentation/parameter/ParameterInstrumentator.java
import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Names;
import org.jetbrains.annotations.NotNull;
import tech.harmonysoft.oss.traute.javac.text.ExceptionTextGenerator;
import tech.harmonysoft.oss.traute.javac.common.CompilationUnitProcessingContext;
import tech.harmonysoft.oss.traute.javac.instrumentation.AbstractInstrumentator;
import static tech.harmonysoft.oss.traute.common.instrumentation.InstrumentationType.METHOD_PARAMETER;
import static tech.harmonysoft.oss.traute.javac.util.InstrumentationUtil.buildVarCheck;

package tech.harmonysoft.oss.traute.javac.instrumentation.parameter;



/**
 * <p>Enhances target method in a way to include a {@code null}-check for the target method parameter.</p>
 * <p>Thread-safe.</p>
 */
public class ParameterInstrumentator extends AbstractInstrumentator<ParameterToInstrumentInfo> {

    @Override
    protected boolean mayBeInstrument(@NotNull ParameterToInstrumentInfo info) {
        String parameterName = info.getMethodParameter().getName().toString();
        CompilationUnitProcessingContext context = info.getContext();
        ExceptionTextGenerator<ParameterToInstrumentInfo> generator =
                context.getExceptionTextGeneratorManager().getGenerator(METHOD_PARAMETER, context.getPluginSettings());
        String errorMessage = generator.generate(info);
        TreeMaker factory = context.getAstFactory();
        Names symbolsTable = context.getSymbolsTable();
        JCTree.JCBlock body = info.getBody();