diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginCache.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginCache.java new file mode 100644 index 000000000000..26d747c5b0a7 --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginCache.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.projects; + +import java.util.HashMap; +import java.util.Map; + +/** + * A class that acts as the compiler plugin cache for a project. + * + * @since 2201.8.7 + */ +public class CompilerPluginCache { + + Map> pluginMap; + + /** + * Constructor to initialize plugin cache. + */ + public CompilerPluginCache() { + pluginMap = new HashMap<>(); + } + + /** + * Returns the user data for a particular compiler plugin. + * + * @param key compiler plugin id + * @return data holder map for the plugin + */ + public Map getData(String key) { + if (!pluginMap.containsKey(key)) { + pluginMap.put(key, new HashMap<>()); + } + return pluginMap.get(key); + } + + /** + * Adds a data holder map for a compiler plugin. + * + * @param key string fully qualified name of the compiler plugin + * @param value user data as a map + */ + public void putData(String key, Map value) { + this.pluginMap.put(key, value); + } +} diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginContextIml.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginContextIml.java index aae3a6cae37f..efc2a86bec46 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginContextIml.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginContextIml.java @@ -26,7 +26,9 @@ import io.ballerina.projects.plugins.completion.CompletionProvider; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * The default implementation of the {@code CompilerPluginContext}. @@ -41,13 +43,18 @@ class CompilerPluginContextIml implements CompilerPluginContext { private final List codeModifiers = new ArrayList<>(); private final List lifecycleListeners = new ArrayList<>(); private final List codeActions = new ArrayList<>(); - + private Map compilerPluginUserData = new HashMap(); private final List completionProviders = new ArrayList<>(); CompilerPluginContextIml(CompilerPluginInfo compilerPluginInfo) { this.compilerPluginInfo = compilerPluginInfo; } + CompilerPluginContextIml(CompilerPluginInfo compilerPluginInfo, Map userData) { + this.compilerPluginInfo = compilerPluginInfo; + this.compilerPluginUserData = userData; + } + public void addCodeAnalyzer(CodeAnalyzer codeAnalyzer) { codeAnalyzers.add(new CodeAnalyzerManager.CodeAnalyzerInfo(codeAnalyzer, compilerPluginInfo)); } @@ -103,4 +110,8 @@ public List completionProviders() { public CompilerPluginInfo compilerPluginInfo() { return compilerPluginInfo; } + + public Map userData() { + return this.compilerPluginUserData; + } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginManager.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginManager.java index e864cdf9b2de..7a946223b7e0 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginManager.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginManager.java @@ -60,7 +60,7 @@ static CompilerPluginManager from(PackageCompilation compilation) { List compilerPlugins = loadEngagedCompilerPlugins(directDependencies); List inBuiltCompilerPlugins = loadInBuiltCompilerPlugins(rootPkgNode.packageInstance()); compilerPlugins.addAll(inBuiltCompilerPlugins); - List compilerPluginContexts = initializePlugins(compilerPlugins); + List compilerPluginContexts = initializePlugins(compilerPlugins, compilation); return new CompilerPluginManager(compilation, compilerPluginContexts); } @@ -189,12 +189,23 @@ private static List getDirectDependencies(ResolvedPackageDependency roo .collect(Collectors.toList()); } - private static List initializePlugins(List compilerPlugins) { + private static List initializePlugins(List compilerPlugins, + PackageCompilation compilation) { + // Skip initialization if the compiler plugins are already initialized for the project + if (!compilation.packageContext().project().compilerPluginContexts().isEmpty()) { + return compilation.packageContext().project().compilerPluginContexts(); + } List compilerPluginContexts = new ArrayList<>(compilerPlugins.size()); for (CompilerPluginInfo compilerPluginInfo : compilerPlugins) { - CompilerPluginContextIml pluginContext = new CompilerPluginContextIml(compilerPluginInfo); + CompilerPluginCache pluginCache = + compilation.packageContext().project().projectEnvironmentContext().environment().getService( + CompilerPluginCache.class); + CompilerPluginContextIml pluginContext = new CompilerPluginContextIml(compilerPluginInfo, + pluginCache.getData(compilerPluginInfo.compilerPlugin().getClass().getCanonicalName())); initializePlugin(compilerPluginInfo, pluginContext); compilerPluginContexts.add(pluginContext); + // Add the plugin context to context list in project + compilation.packageContext().project().compilerPluginContexts().add(pluginContext); } return compilerPluginContexts; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Project.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Project.java index bfb31196a631..162260b1d03f 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Project.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Project.java @@ -23,6 +23,8 @@ import org.wso2.ballerinalang.compiler.util.CompilerOptions; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -40,6 +42,7 @@ public abstract class Project { protected ProjectEnvironment projectEnvironment; private final ProjectKind projectKind; private Map toolContextMap; + private List compilerPluginContexts; protected Project(ProjectKind projectKind, Path projectPath, @@ -48,6 +51,7 @@ protected Project(ProjectKind projectKind, this.sourceRoot = projectPath; this.buildOptions = buildOptions; this.projectEnvironment = projectEnvironmentBuilder.build(this); + this.compilerPluginContexts = new ArrayList<>(); } protected Project(ProjectKind projectKind, @@ -57,6 +61,7 @@ protected Project(ProjectKind projectKind, this.sourceRoot = projectPath; this.projectEnvironment = projectEnvironmentBuilder.build(this); this.buildOptions = BuildOptions.builder().build(); + this.compilerPluginContexts = new ArrayList<>(); } void setBuildOptions(BuildOptions buildOptions) { @@ -152,4 +157,8 @@ protected Project resetPackage(Project project) { public abstract Optional documentPath(DocumentId documentId); public abstract void save(); + + List compilerPluginContexts() { + return this.compilerPluginContexts; + } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/environment/EnvironmentBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/environment/EnvironmentBuilder.java index 2386fe10f8e6..2614f8afa491 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/environment/EnvironmentBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/environment/EnvironmentBuilder.java @@ -17,6 +17,7 @@ */ package io.ballerina.projects.environment; +import io.ballerina.projects.CompilerPluginCache; import io.ballerina.projects.internal.environment.BallerinaDistribution; import io.ballerina.projects.internal.environment.BallerinaUserHome; import io.ballerina.projects.internal.environment.DefaultEnvironment; @@ -96,6 +97,7 @@ public Environment build() { CompilerContext compilerContext = populateCompilerContext(); environment.addService(CompilerContext.class, compilerContext); ballerinaDistribution.loadLangLibPackages(compilerContext, packageResolver); + environment.addService(CompilerPluginCache.class, new CompilerPluginCache()); return environment; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerPluginContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerPluginContext.java index f3dfa6ae8bbf..fc681455f67a 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerPluginContext.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerPluginContext.java @@ -20,6 +20,8 @@ import io.ballerina.projects.plugins.codeaction.CodeAction; import io.ballerina.projects.plugins.completion.CompletionProvider; +import java.util.Map; + /** * This class can be used to add various compiler plugin tasks to the current compilation. * @@ -68,4 +70,11 @@ public interface CompilerPluginContext { * @param completionProvider the {@link CompletionProvider} instance */ void addCompletionProvider(CompletionProvider completionProvider); + + /** + * Returns user data for the compiler plugin. + * + * @return Map of user data as Map + */ + Map userData(); } diff --git a/project-api/project-api-test/build.gradle b/project-api/project-api-test/build.gradle index 9f3519c92800..bc351f9d90a1 100644 --- a/project-api/project-api-test/build.gradle +++ b/project-api/project-api-test/build.gradle @@ -73,6 +73,7 @@ dependencies { compilerPluginJar project(':project-api-test-artifact:log-creator-pkg-provided-code-modifier') compilerPluginJar project(':project-api-test-artifact:log-creator-pkg-provided-code-generator') compilerPluginJar project(':project-api-test-artifact:log-creator-pkg-provided-code-analyzer') + compilerPluginJar project(':project-api-test-artifact:pkg-provided-compiler-plugin-with-shared-data') testRuntimeOnly project(":ballerina-lang-test") balRt project(':ballerina-rt') diff --git a/project-api/project-api-test/src/test/java/io/ballerina/projects/test/plugins/CompilerPluginTests.java b/project-api/project-api-test/src/test/java/io/ballerina/projects/test/plugins/CompilerPluginTests.java index d335f0425105..346df2cf6bcf 100644 --- a/project-api/project-api-test/src/test/java/io/ballerina/projects/test/plugins/CompilerPluginTests.java +++ b/project-api/project-api-test/src/test/java/io/ballerina/projects/test/plugins/CompilerPluginTests.java @@ -104,6 +104,8 @@ public void init() { "compiler_plugin_tests/log_creator_pkg_provided_code_generator_im"); BCompileUtil.compileAndCacheBala( "compiler_plugin_tests/log_creator_pkg_provided_code_analyzer_im"); + BCompileUtil.compileAndCacheBala( + "compiler_plugin_tests/pkg_provided_compiler_plugin_with_shared_data"); } @Test @@ -603,6 +605,26 @@ public void testRunCodeGenAndModifyPluginsMethod() { "Invalid compiler plugin file logs after running code generators and modifiers"); } + @Test(description = "Test the usage of BuildContext as a data holder for compiler plugins") + public void testBuildContextForCompilerPlugins() { + Package currentPackage = loadPackage("shared_data_plugin"); + + // Run code modifiers + CodeModifierResult codeModifierResult = currentPackage.runCodeModifierPlugins(); + Assert.assertEquals(codeModifierResult.reportedDiagnostics().diagnosticCount(), 2, + "Unexpected compilation diagnostics from modifier"); + OUT.println("Diagnostics from modifier"); + codeModifierResult.reportedDiagnostics().diagnostics().forEach(OUT::println); + + // Get the compilation + PackageCompilation compilation = codeModifierResult.updatedPackage().get().getCompilation(); + DiagnosticResult diagnosticResult = compilation.diagnosticResult(); + OUT.println("Diagnostics from analyzer"); + diagnosticResult.diagnostics().forEach(OUT::println); + Assert.assertEquals(diagnosticResult.diagnosticCount(), 0, + "Unexpected compilation diagnostic from analyzer"); + } + private Package loadPackage(String path) { Path projectDirPath = RESOURCE_DIRECTORY.resolve(path); BuildProject buildProject = TestUtils.loadBuildProject(projectDirPath); diff --git a/project-api/project-api-test/src/test/resources/compiler_plugin_tests/pkg_provided_compiler_plugin_with_shared_data/Ballerina.toml b/project-api/project-api-test/src/test/resources/compiler_plugin_tests/pkg_provided_compiler_plugin_with_shared_data/Ballerina.toml new file mode 100644 index 000000000000..e3a633ed97dd --- /dev/null +++ b/project-api/project-api-test/src/test/resources/compiler_plugin_tests/pkg_provided_compiler_plugin_with_shared_data/Ballerina.toml @@ -0,0 +1,4 @@ +[package] +org = "foo" +name = "test_pkg" +version = "0.1.0" diff --git a/project-api/project-api-test/src/test/resources/compiler_plugin_tests/pkg_provided_compiler_plugin_with_shared_data/CompilerPlugin.toml b/project-api/project-api-test/src/test/resources/compiler_plugin_tests/pkg_provided_compiler_plugin_with_shared_data/CompilerPlugin.toml new file mode 100644 index 000000000000..bd4342d55d62 --- /dev/null +++ b/project-api/project-api-test/src/test/resources/compiler_plugin_tests/pkg_provided_compiler_plugin_with_shared_data/CompilerPlugin.toml @@ -0,0 +1,5 @@ +[plugin] +class = "io.context.plugins.CompilerPluginWithSharedData" + +[[dependency]] +path = "../../../../../build/compiler-plugin-jars/pkg-provided-compiler-plugin-with-shared-data-1.0.0.jar" diff --git a/project-api/project-api-test/src/test/resources/compiler_plugin_tests/pkg_provided_compiler_plugin_with_shared_data/main.bal b/project-api/project-api-test/src/test/resources/compiler_plugin_tests/pkg_provided_compiler_plugin_with_shared_data/main.bal new file mode 100644 index 000000000000..385a08e208bf --- /dev/null +++ b/project-api/project-api-test/src/test/resources/compiler_plugin_tests/pkg_provided_compiler_plugin_with_shared_data/main.bal @@ -0,0 +1,24 @@ +// Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +public function main() { +} + +function foo() { +} + +function bar() { +} diff --git a/project-api/project-api-test/src/test/resources/compiler_plugin_tests/shared_data_plugin/Ballerina.toml b/project-api/project-api-test/src/test/resources/compiler_plugin_tests/shared_data_plugin/Ballerina.toml new file mode 100644 index 000000000000..9245633e3c43 --- /dev/null +++ b/project-api/project-api-test/src/test/resources/compiler_plugin_tests/shared_data_plugin/Ballerina.toml @@ -0,0 +1,4 @@ +[package] +org = "shared_data" +name = "combined_plugin" +version = "0.1.0" diff --git a/project-api/project-api-test/src/test/resources/compiler_plugin_tests/shared_data_plugin/main.bal b/project-api/project-api-test/src/test/resources/compiler_plugin_tests/shared_data_plugin/main.bal new file mode 100644 index 000000000000..e1c58f0c9aee --- /dev/null +++ b/project-api/project-api-test/src/test/resources/compiler_plugin_tests/shared_data_plugin/main.bal @@ -0,0 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import foo/test_pkg as _; + +function func1() { + +} diff --git a/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/build.gradle b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/build.gradle new file mode 100644 index 000000000000..9a6d8e48cab7 --- /dev/null +++ b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/build.gradle @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply from: "$rootDir/gradle/javaProject.gradle" + +description = 'Compiler Plugin Tests - Plugin with BuildContext usage' +version = '1.0.0' + +dependencies { + implementation project(':ballerina-lang') + implementation project(':ballerina-parser') + implementation project(':ballerina-tools-api') +} + +ext.moduleName = 'io.context.plugins' + +compileJava { + doFirst { + options.compilerArgs = ['--module-path', classpath.asPath,] + classpath = files() + } +} diff --git a/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/spotbugs-exclude.xml b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/spotbugs-exclude.xml new file mode 100644 index 000000000000..3492cae706be --- /dev/null +++ b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/spotbugs-exclude.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/CompilerPluginWithSharedData.java b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/CompilerPluginWithSharedData.java new file mode 100644 index 000000000000..2c311e7bd77c --- /dev/null +++ b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/CompilerPluginWithSharedData.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.context.plugins; + +import io.ballerina.projects.plugins.CompilerPlugin; +import io.ballerina.projects.plugins.CompilerPluginContext; + +/** + * A class that registers a compiler plugin which shares data within the plugin. + * + * @since 2201.8.7 + */ +public class CompilerPluginWithSharedData extends CompilerPlugin { + + @Override + public void init(CompilerPluginContext pluginContext) { + pluginContext.addCodeAnalyzer(new SharedDataTestCodeAnalyzer(pluginContext.userData())); + pluginContext.addCodeModifier(new SharedDataTestCodeModifier(pluginContext.userData())); + } +} diff --git a/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/SharedDataTestCodeAnalyzer.java b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/SharedDataTestCodeAnalyzer.java new file mode 100644 index 000000000000..e0f368febfe8 --- /dev/null +++ b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/SharedDataTestCodeAnalyzer.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.context.plugins; + +import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; +import io.ballerina.compiler.syntax.tree.SyntaxKind; +import io.ballerina.projects.plugins.CodeAnalysisContext; +import io.ballerina.projects.plugins.CodeAnalyzer; +import io.ballerina.tools.diagnostics.DiagnosticFactory; +import io.ballerina.tools.diagnostics.DiagnosticInfo; +import io.ballerina.tools.diagnostics.DiagnosticSeverity; +import io.ballerina.tools.diagnostics.Location; +import io.ballerina.tools.text.LinePosition; +import io.ballerina.tools.text.LineRange; +import io.ballerina.tools.text.TextRange; + +import java.util.Arrays; +import java.util.Map; + +/** + * A class representing a code analyzer that uses shared data within the plugin. + * + * @since 2201.8.7 + */ +public class SharedDataTestCodeAnalyzer extends CodeAnalyzer { + private final Map userData; + + /** + * Constructor accepting user data map. + * + * @param userData map of user data + */ + public SharedDataTestCodeAnalyzer(Map userData) { + this.userData = userData; + } + + @Override + public void init(CodeAnalysisContext analysisContext) { + analysisContext.addSyntaxNodeAnalysisTask(syntaxNodeAnalysisContext -> { + if (syntaxNodeAnalysisContext.node() instanceof FunctionDefinitionNode) { + Object isCompleted = this.userData.get("isCompleted"); + if (isCompleted == null || (isCompleted instanceof Boolean && + !(Boolean) isCompleted)) { + // Report a test diagnostic + DiagnosticInfo diagnosticInfo = new DiagnosticInfo(null, + "diagnostic message from Analyzer", DiagnosticSeverity.ERROR); + syntaxNodeAnalysisContext.reportDiagnostic(DiagnosticFactory.createDiagnostic(diagnosticInfo, + new NullLocation())); + } + } + }, Arrays.asList(SyntaxKind.FUNCTION_DEFINITION)); + } + + private static class NullLocation implements Location { + @Override + public LineRange lineRange() { + LinePosition from = LinePosition.from(0, 0); + return LineRange.from("", from, from); + } + + @Override + public TextRange textRange() { + return TextRange.from(0, 0); + } + } +} diff --git a/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/SharedDataTestCodeModifier.java b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/SharedDataTestCodeModifier.java new file mode 100644 index 000000000000..b8c519a05e64 --- /dev/null +++ b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/SharedDataTestCodeModifier.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.context.plugins; + +import io.ballerina.compiler.syntax.tree.SyntaxKind; +import io.ballerina.projects.Module; +import io.ballerina.projects.ModuleId; +import io.ballerina.projects.ProjectKind; +import io.ballerina.projects.plugins.CodeModifier; +import io.ballerina.projects.plugins.CodeModifierContext; +import io.ballerina.projects.plugins.ModifierTask; +import io.ballerina.projects.plugins.SourceModifierContext; + +import java.io.PrintStream; +import java.util.Map; + +/** + * A class representing a code modifier that uses shared data within the plugin. + * + * @since 2201.8.7 + */ +public class SharedDataTestCodeModifier extends CodeModifier { + private static final PrintStream OUT = System.out; + private final Map userData; + + /** + * Constructor which accepts user data map. + * + * @param userData map of user data + */ + public SharedDataTestCodeModifier(Map userData) { + this.userData = userData; + } + + @Override + public void init(CodeModifierContext modifierContext) { + modifierContext.addSyntaxNodeAnalysisTask(syntaxNodeAnalysisContext -> { + // Report a test diagnostic + Util.reportDiagnostic(syntaxNodeAnalysisContext, CompilationDiagnostic.DIAG_1, new NullLocation()); + }, SyntaxKind.FUNCTION_DEFINITION); + modifierContext.addSourceModifierTask(new ModifyTask()); + modifierContext.addSyntaxNodeAnalysisTask(syntaxNodeAnalysisContext -> { + // Report a test diagnostic + Util.reportDiagnostic(syntaxNodeAnalysisContext, CompilationDiagnostic.DIAG_2, new NullLocation()); + this.userData.put("isCompleted", true); + }, SyntaxKind.FUNCTION_DEFINITION); + } + + private static class ModifyTask implements ModifierTask { + @Override + public void modify(SourceModifierContext modifierContext) { + if (!(modifierContext.currentPackage().project().kind() == ProjectKind.SINGLE_FILE_PROJECT)) { + return; + } + for (ModuleId moduleId : modifierContext.currentPackage().moduleIds()) { + Module module = modifierContext.currentPackage().module(moduleId); + OUT.println("module " + module.moduleId().toString()); + } + } + } +} + diff --git a/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/Util.java b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/Util.java new file mode 100644 index 000000000000..056cf3baa734 --- /dev/null +++ b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/io/context/plugins/Util.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.context.plugins; + +import io.ballerina.projects.plugins.SyntaxNodeAnalysisContext; +import io.ballerina.tools.diagnostics.Diagnostic; +import io.ballerina.tools.diagnostics.DiagnosticCode; +import io.ballerina.tools.diagnostics.DiagnosticFactory; +import io.ballerina.tools.diagnostics.DiagnosticInfo; +import io.ballerina.tools.diagnostics.DiagnosticSeverity; +import io.ballerina.tools.diagnostics.Location; +import io.ballerina.tools.text.LinePosition; +import io.ballerina.tools.text.LineRange; +import io.ballerina.tools.text.TextRange; + +/** + * A class that holds utility functions for the compiler plugin using shared data. + * + * @since 2201.8.7 + */ +public class Util { + + public static void reportDiagnostic(SyntaxNodeAnalysisContext context, CompilationDiagnostic diagnosticCode, + Location location, Object... args) { + DiagnosticInfo diagnosticInfo = new DiagnosticInfo(diagnosticCode.getDiagnosticCode(), + diagnosticCode.getDiagnostic(), diagnosticCode.getDiagnosticSeverity()); + Diagnostic diagnostic = DiagnosticFactory.createDiagnostic(diagnosticInfo, location, args); + context.reportDiagnostic(diagnostic); + } +} + +class NullLocation implements Location { + @Override + public LineRange lineRange() { + LinePosition from = LinePosition.from(0, 0); + return LineRange.from("", from, from); + } + + @Override + public TextRange textRange() { + return TextRange.from(0, 0); + } +} + +// Holds Compilation diagnostics for the modifiers +enum CompilationDiagnostic { + DIAG_1(DiagnosticMessage.WARNING_101, + new DiagnosticCode() { + @Override + public DiagnosticSeverity severity() { + return DiagnosticSeverity.WARNING; + } + + @Override + public String diagnosticId() { + return "0001"; + } + + @Override + public String messageKey() { + return "0001"; + } + }, + DiagnosticSeverity.WARNING), + + DIAG_2(DiagnosticMessage.WARNING_102, + new DiagnosticCode() { + @Override + public DiagnosticSeverity severity() { + return DiagnosticSeverity.WARNING; + } + + @Override + public String diagnosticId() { + return "0002"; + } + + @Override + public String messageKey() { + return "0002"; + } + }, + DiagnosticSeverity.WARNING); + + private final String diagnostic; + private final String diagnosticCode; + private final DiagnosticSeverity diagnosticSeverity; + + CompilationDiagnostic(DiagnosticMessage message, DiagnosticCode diagnosticCode, + DiagnosticSeverity diagnosticSeverity) { + this.diagnostic = message.getMessage(); + this.diagnosticCode = diagnosticCode.diagnosticId(); + this.diagnosticSeverity = diagnosticSeverity; + } + + public String getDiagnostic() { + return diagnostic; + } + + public String getDiagnosticCode() { + return diagnosticCode; + } + + public DiagnosticSeverity getDiagnosticSeverity() { + return this.diagnosticSeverity; + } +} + +// Holds diagnostic messages for the code modifier +enum DiagnosticMessage { + WARNING_101("warning 01 from modifier"), + WARNING_102("warning 02 from modifier"); + + private final String message; + + DiagnosticMessage(String message) { + this.message = message; + } + + public String getMessage() { + return this.message; + } +} diff --git a/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/module-info.java b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/module-info.java new file mode 100644 index 000000000000..5ff6607d5873 --- /dev/null +++ b/project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data/src/main/java/module-info.java @@ -0,0 +1,7 @@ +module io.context.plugins { + requires io.ballerina.lang; + requires io.ballerina.parser; + requires io.ballerina.tools.api; + + exports io.context.plugins; +} diff --git a/settings.gradle b/settings.gradle index 092132f0f9a5..b16b87f5a967 100644 --- a/settings.gradle +++ b/settings.gradle @@ -140,6 +140,7 @@ include(':project-api-test-artifact:simple-code-gen-plugin-with-resource-gen') include(':project-api-test-artifact:init-function-diagnostic-compiler-plugin') include(':project-api-test-artifact:compiler-plugin-with-analyzer-generator-modifier') include(':project-api-test-artifact:sample-openapi-build-tool') +include(':project-api-test-artifact:pkg-provided-compiler-plugin-with-shared-data') include(':identifier-util') include(':ballerina-profiler') @@ -175,6 +176,7 @@ project(':project-api-test-artifact:log-creator-pkg-provided-code-analyzer').pro project(':project-api-test-artifact:simple-code-gen-plugin-with-resource-gen').projectDir = file('project-api/test-artifacts/simple-code-gen-plugin-with-resource-gen') project(':project-api-test-artifact:init-function-diagnostic-compiler-plugin').projectDir = file('project-api/test-artifacts/init-function-diagnostic-compiler-plugin') project(':project-api-test-artifact:compiler-plugin-with-analyzer-generator-modifier').projectDir = file('project-api/test-artifacts/compiler-plugin-with-analyzer-generator-modifier') +project(':project-api-test-artifact:pkg-provided-compiler-plugin-with-shared-data').projectDir = file('project-api/test-artifacts/pkg-provided-compiler-plugin-with-shared-data') project(':project-api-test-artifact:sample-openapi-build-tool').projectDir = file('project-api/test-artifacts/sample-openapi-build-tool') project(':ballerina-lang:internal').projectDir = file('langlib/lang.__internal') project(':ballerina-lang:annotations').projectDir = file('langlib/lang.annotations')