Skip to content

Commit

Permalink
Merge pull request #24 from SasinduDilshara/unused_function_parameters
Browse files Browse the repository at this point in the history
Add static rule for unused Function parameters
  • Loading branch information
SasinduDilshara authored Oct 31, 2024
2 parents 5453af9 + 833c0b3 commit 8ef5511
Show file tree
Hide file tree
Showing 28 changed files with 580 additions and 145 deletions.
4 changes: 4 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# See: https://help.github.com/articles/about-codeowners/

# These owners will be the default owners for everything in the repo.
* @azinneera
31 changes: 31 additions & 0 deletions .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: "🐞 Report a Bug"
description: Create an issue if something does not work as expected.
labels: ["Type/Bug"]
body:
- type: textarea
id: background
attributes:
label: Description
description: Please share a clear and concise description of the problem.
placeholder: Description
- type: textarea
id: steps
attributes:
label: Steps to Reproduce
description: List the steps you followed when you encountered the issue. Provide sample source code to reproduce the issue where applicable.
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: Enter product/component version.
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment Details (with versions)
description: Mention the environment details (OS, Client, etc.) that the product is running on.
validations:
required: false
11 changes: 11 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: '📚 Documentation Issue'
about: Request a new article, missing topic, or report an issue if a topic is incorrect in the current documentation.
url: https://github.com/ballerina-platform/ballerina-dev-website/issues/new/choose
- name: General Question
url: https://stackoverflow.com/questions/tagged/ballerina
about: "If you have a question then please ask on Stack Overflow using the #ballerina tag."
- name: Chat on Ballerina Discord Channel
url: https://discord.gg/ballerinalang
about: "Chat about anything else with the community."
25 changes: 25 additions & 0 deletions .github/ISSUE_TEMPLATE/improvement.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: "🚀 Improvement Request"
description: Suggest an improvement to the product.
labels: ["Type/Improvement"]
body:
- type: textarea
id: limitation
attributes:
label: Current Limitation
description: Describe the the current limitation.
validations:
required: true
- type: textarea
id: suggestion
attributes:
label: Suggested Improvement
description: Describe the the improvement you suggest.
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: Enter component version.
validations:
required: false
32 changes: 32 additions & 0 deletions .github/ISSUE_TEMPLATE/new-feature.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: "💡 New Feature Request"
description: Suggest new functionality and features for the product.
labels: ["Type/NewFeature"]
body:
- type: textarea
id: problem
attributes:
label: Problem
description: What is the problem this feature will solve?
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: Describe the solution you'd like to have.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives
description: Describe any alternatives have you considered
validations:
required: false
- type: input
id: version
attributes:
label: Version
description: Enter product/component version.
validations:
required: false
18 changes: 18 additions & 0 deletions .github/ISSUE_TEMPLATE/task.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: "✍️ Create a Task"
description: Create a new task.
labels: ["Type/Task"]
body:
- type: textarea
id: description
attributes:
label: Description
description: A clear description of what needs to be done.
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: Enter product/component version.
validations:
required: false
28 changes: 0 additions & 28 deletions .github/ISSUE_TEMPLATE/type_bug.md

This file was deleted.

26 changes: 0 additions & 26 deletions .github/ISSUE_TEMPLATE/type_improvement.md

This file was deleted.

26 changes: 0 additions & 26 deletions .github/ISSUE_TEMPLATE/type_new_feature.md

This file was deleted.

24 changes: 0 additions & 24 deletions .github/ISSUE_TEMPLATE/type_task.md

This file was deleted.

2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ enterprisePluginVersion=3.18.1
# Dependency versions
picoCLIVersion=4.7.5
gsonVersion=2.10.1
ballerinaLangVersion=2201.10.1
ballerinaLangVersion=2201.10.2
puppycrawlCheckstyleVersion=10.12.1
apacheCommonsLang3Version=3.0
commonsIoVersion=2.15.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
* @since 0.1.0
* */
enum CoreRule {
AVOID_CHECKPANIC(RuleFactory.createRule(1, "Avoid checkpanic", RuleKind.CODE_SMELL));
AVOID_CHECKPANIC(RuleFactory.createRule(1, "Avoid checkpanic", RuleKind.CODE_SMELL)),
UNUSED_FUNCTION_PARAMETER(RuleFactory.createRule(2,
"Unused function parameter", RuleKind.CODE_SMELL));

private final Rule rule;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.ballerina.compiler.api.SemanticModel;
import io.ballerina.projects.CompilerPluginCache;
import io.ballerina.projects.Document;
import io.ballerina.projects.DocumentConfig;
Expand Down Expand Up @@ -111,9 +112,10 @@ List<Issue> analyze(List<Rule> inbuiltRules) {
}

private Consumer<DocumentId> analyzeDocument(Module module, ScannerContextImpl scannerContext) {
SemanticModel semanticModel = module.getCompilation().getSemanticModel();
return documentId -> {
Document document = module.document(documentId);
StaticCodeAnalyzer analyzer = new StaticCodeAnalyzer(document, scannerContext);
StaticCodeAnalyzer analyzer = new StaticCodeAnalyzer(document, scannerContext, semanticModel);
analyzer.analyze();
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,26 @@

package io.ballerina.scan.internal;

import io.ballerina.compiler.api.SemanticModel;
import io.ballerina.compiler.api.symbols.Symbol;
import io.ballerina.compiler.syntax.tree.CheckExpressionNode;
import io.ballerina.compiler.syntax.tree.ExplicitAnonymousFunctionExpressionNode;
import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode;
import io.ballerina.compiler.syntax.tree.FunctionSignatureNode;
import io.ballerina.compiler.syntax.tree.ImplicitAnonymousFunctionExpressionNode;
import io.ballerina.compiler.syntax.tree.ImplicitAnonymousFunctionParameters;
import io.ballerina.compiler.syntax.tree.IncludedRecordParameterNode;
import io.ballerina.compiler.syntax.tree.ModulePartNode;
import io.ballerina.compiler.syntax.tree.Node;
import io.ballerina.compiler.syntax.tree.NodeVisitor;
import io.ballerina.compiler.syntax.tree.SimpleNameReferenceNode;
import io.ballerina.compiler.syntax.tree.SyntaxKind;
import io.ballerina.compiler.syntax.tree.SyntaxTree;
import io.ballerina.projects.Document;
import io.ballerina.scan.ScannerContext;

import java.util.Optional;

/**
* {@code StaticCodeAnalyzer} contains the logic to perform core static code analysis on Ballerina documents.
*
Expand All @@ -35,11 +47,13 @@ class StaticCodeAnalyzer extends NodeVisitor {
private final Document document;
private final SyntaxTree syntaxTree;
private final ScannerContext scannerContext;
private final SemanticModel semanticModel;

StaticCodeAnalyzer(Document document, ScannerContextImpl scannerContext) {
StaticCodeAnalyzer(Document document, ScannerContextImpl scannerContext, SemanticModel semanticModel) {
this.document = document;
this.syntaxTree = document.syntaxTree();
this.scannerContext = scannerContext;
this.semanticModel = semanticModel;
}

void analyze() {
Expand All @@ -54,8 +68,63 @@ void analyze() {
@Override
public void visit(CheckExpressionNode checkExpressionNode) {
if (checkExpressionNode.checkKeyword().kind().equals(SyntaxKind.CHECKPANIC_KEYWORD)) {
scannerContext.getReporter().reportIssue(document, checkExpressionNode.location(),
CoreRule.AVOID_CHECKPANIC.rule());
reportIssue(checkExpressionNode, CoreRule.AVOID_CHECKPANIC);
}
}

@Override
public void visit(FunctionDefinitionNode functionDefinitionNode) {
checkUnusedFunctionParameters(functionDefinitionNode.functionSignature());
this.visitSyntaxNode(functionDefinitionNode);
}

@Override
public void visit(ExplicitAnonymousFunctionExpressionNode explicitAnonymousFunctionExpressionNode) {
checkUnusedFunctionParameters(explicitAnonymousFunctionExpressionNode.functionSignature());
this.visitSyntaxNode(explicitAnonymousFunctionExpressionNode);
}

@Override
public void visit(ImplicitAnonymousFunctionExpressionNode implicitAnonymousFunctionExpressionNode) {
Node params = implicitAnonymousFunctionExpressionNode.params();
if (params instanceof ImplicitAnonymousFunctionParameters parameters) {
parameters.parameters().forEach(parameter -> {
reportIssueIfNodeIsUnused(parameter, CoreRule.UNUSED_FUNCTION_PARAMETER);
});
return;
}
if (params instanceof SimpleNameReferenceNode) {
reportIssueIfNodeIsUnused(params, CoreRule.UNUSED_FUNCTION_PARAMETER);
}

this.visitSyntaxNode(implicitAnonymousFunctionExpressionNode.expression());
}

private void checkUnusedFunctionParameters(FunctionSignatureNode functionSignatureNode) {
functionSignatureNode.parameters().forEach(parameter -> {
if (parameter instanceof IncludedRecordParameterNode includedRecordParameterNode) {
includedRecordParameterNode.paramName().ifPresent(name -> {
reportIssueIfNodeIsUnused(name, CoreRule.UNUSED_FUNCTION_PARAMETER);
});
} else {
reportIssueIfNodeIsUnused(parameter, CoreRule.UNUSED_FUNCTION_PARAMETER);
}
this.visitSyntaxNode(parameter);
});
}

private void reportIssueIfNodeIsUnused(Node node, CoreRule coreRule) {
if (isUnusedNode(node)) {
reportIssue(node, coreRule);
}
}

private void reportIssue(Node node, CoreRule coreRule) {
scannerContext.getReporter().reportIssue(document, node.location(), coreRule.rule());
}

private boolean isUnusedNode(Node node) {
Optional<Symbol> symbol = semanticModel.symbol(node);
return symbol.filter(value -> semanticModel.references(value).size() == 1).isPresent();
}
}
Loading

0 comments on commit 8ef5511

Please sign in to comment.