Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add static rule for unused Function parameters #24

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
eb08ccc
Create CODEOWNERS file
anupama-pathirage Sep 23, 2024
c5a4bcf
Merge pull request #22 from ballerina-platform/anupama-pathirage-patch-1
SasinduDilshara Sep 24, 2024
ddba9f1
Update CODEOWNERS
anupama-pathirage Oct 1, 2024
4fe2e4e
Merge pull request #23 from ballerina-platform/anupama-pathirage-patch-2
ThisaruGuruge Oct 1, 2024
3f0b233
Add static rule implementation for unused func params
SasinduDilshara Oct 2, 2024
fc3c5b6
Update scan cmd tests with unused function args test
SasinduDilshara Oct 8, 2024
a92d47c
refactor unused function parameter test file
SasinduDilshara Oct 8, 2024
ba32fc2
Add warning comments test files in unused function parameter rule
SasinduDilshara Oct 8, 2024
bba45c4
Update assertion text files for windows tests
SasinduDilshara Oct 8, 2024
88ed2cf
Add analyzer for anonymous function parameters
SasinduDilshara Oct 9, 2024
797b59f
Remove unused imports in static code rule tests
SasinduDilshara Oct 9, 2024
927847c
Refactor the unused function parameter analyzer
SasinduDilshara Oct 9, 2024
ea70e3a
Merge branch 'static-code-analysis-tool' of https://github.com/baller…
SasinduDilshara Oct 9, 2024
7b6c4d7
Refactor the tests in unused function parameter static rule
SasinduDilshara Oct 10, 2024
cb595f5
Update tests in function parameter rules
SasinduDilshara Oct 10, 2024
e4bcc28
Rename unused function parameter analyzer rule description
SasinduDilshara Oct 11, 2024
cc3f86b
Update the checkpanic expression test class name
SasinduDilshara Oct 11, 2024
2ef4c57
Rename the static code analysis test files
SasinduDilshara Oct 11, 2024
301a9ec
Add issue template
anupama-pathirage Oct 21, 2024
8b67aa0
Merge pull request #26 from ballerina-platform/addtemplate
keizer619 Oct 23, 2024
9fab3e8
Change the test file names in rule-002
SasinduDilshara Oct 30, 2024
5d1abf5
Merge branch 'main' of https://github.com/ballerina-platform/static-c…
SasinduDilshara Oct 30, 2024
833c0b3
Update ballerina version into 2201.10.2
SasinduDilshara Oct 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading