Skip to content

Commit c37090f

Browse files
authored
Merge pull request #1826 from TypeCobolTeam/1825_SupportExternalAnalyzers
WI #1825 Find and load analyzers from external assemblies
2 parents 269176a + 32a20e0 commit c37090f

File tree

12 files changed

+192
-25
lines changed

12 files changed

+192
-25
lines changed

CLI/src/CLI.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ private ReturnCode Compile()
112112
var analyzerProvider = new CompositeAnalyzerProvider();
113113
var reports = RegisterAnalyzers(analyzerProvider);
114114

115+
//Add external analyzers
116+
analyzerProvider.AddCustomProviders(_configuration.CustomAnalyzerFiles);
117+
115118
//Normalize TypeCobolOptions, the parser does not need to go beyond SemanticCheck for the first phase
116119
var typeCobolOptions = new TypeCobolOptions(_configuration);
117120
if (_configuration.ExecToStep > ExecutionStep.SemanticCheck)

CLI/test/CLITest.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,15 @@ public void TestRDZFormatInputEncodings()
330330
CLITestHelper.Test("rdzformat_inputencoding_wrong", ReturnCode.Success);
331331
CLITestHelper.Test("rdzformat_inputencoding_good", ReturnCode.Success);
332332
}
333+
334+
/// <summary>
335+
/// Test custom analyzers defined in TypeCobol.Analysis.Test.dll.
336+
/// </summary>
337+
[TestMethod]
338+
public void TestCustomAnalyzers()
339+
{
340+
CLITestHelper.Test("custom_analyzers", ReturnCode.Warning);
341+
}
333342
}
334343

335344
public class CLITestHelper {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-i input\CustomAnalyzers.rdz.tcbl -o output\CustomAnalyzers.cbl -d output\errors.txt -ca "..\..\TypeCobol.Analysis.Test.dll" --exectostep=QualityCheck
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
 IDENTIFICATION DIVISION.
2+
PROGRAM-ID. DVZZMFT0.
3+
DATA DIVISION.
4+
WORKING-STORAGE SECTION.
5+
01 var1 PIC X.
6+
PROCEDURE DIVISION.
7+
MOVE 'A' TO var1
8+
GOBACK
9+
.
10+
END PROGRAM DVZZMFT0.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ReturnCode=Warning_
2+
3 errors in "input\CustomAnalyzers.rdz.tcbl":
3+
Line 0[0,0] <45, Warning, General> - Info: Analyzer 'DummySyntaxDrivenAnalyzer': starting AST building...
4+
Line 0[0,0] <45, Warning, General> - Info: Analyzer 'DummySyntaxDrivenAnalyzer': finished AST building.
5+
Line 0[0,0] <45, Warning, General> - Info: Analyzer 'DummyASTAnalyzer': visiting source file.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using TypeCobol.Compiler.CodeElements;
2+
using TypeCobol.Compiler.CupParser.NodeBuilder;
3+
using TypeCobol.Compiler.Diagnostics;
4+
using TypeCobol.Compiler.Nodes;
5+
6+
namespace TypeCobol.Analysis.Test.CustomAnalyzers
7+
{
8+
/// <summary>
9+
/// Simple SyntaxDrivenAnalyzer to demonstrate dynamic load and use during AST building
10+
/// </summary>
11+
internal class DummySyntaxDrivenAnalyzer : SyntaxDrivenAnalyzerBase
12+
{
13+
public DummySyntaxDrivenAnalyzer(string identifier)
14+
: base(identifier)
15+
{
16+
17+
}
18+
19+
public override object GetResult()
20+
{
21+
return null;
22+
}
23+
24+
public override void StartCobolProgram(ProgramIdentification programIdentification, LibraryCopyCodeElement libraryCopy)
25+
{
26+
AddDiagnostic(new Diagnostic(MessageCode.Info, 0, 0, 0, $"Analyzer '{Identifier}': starting AST building..."));
27+
}
28+
29+
public override void EndCobolProgram(ProgramEnd end)
30+
{
31+
AddDiagnostic(new Diagnostic(MessageCode.Info, 0, 0, 0, $"Analyzer '{Identifier}': finished AST building."));
32+
}
33+
}
34+
35+
/// <summary>
36+
/// Simple ASTAnalyzer to demonstrate dynamic load and use in QualityCheck
37+
/// </summary>
38+
internal class DummyASTAnalyzer : ASTAnalyzerBase
39+
{
40+
public DummyASTAnalyzer(string identifier)
41+
: base(identifier)
42+
{
43+
44+
}
45+
46+
public override object GetResult()
47+
{
48+
return null;
49+
}
50+
51+
public override bool Visit(SourceFile sourceFile)
52+
{
53+
AddDiagnostic(new Diagnostic(MessageCode.Info, 0, 0, 0, $"Analyzer '{Identifier}': visiting source file."));
54+
return false;
55+
}
56+
}
57+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using TypeCobol.Compiler.Directives;
2+
using TypeCobol.Compiler.Text;
3+
4+
namespace TypeCobol.Analysis.Test.CustomAnalyzers
5+
{
6+
/// <summary>
7+
/// This provider is loaded and called in CLI.Test, see TestCustomAnalyzers unit test.
8+
/// </summary>
9+
public class TestAnalyzerProvider : IAnalyzerProvider
10+
{
11+
public ISyntaxDrivenAnalyzer[] CreateSyntaxDrivenAnalyzers(TypeCobolOptions options, TextSourceInfo textSourceInfo)
12+
{
13+
return new ISyntaxDrivenAnalyzer[] { new DummySyntaxDrivenAnalyzer(nameof(DummySyntaxDrivenAnalyzer)) };
14+
}
15+
16+
public IASTAnalyzer[] CreateASTAnalyzers(TypeCobolOptions options)
17+
{
18+
return new IASTAnalyzer[] { new DummyASTAnalyzer(nameof(DummyASTAnalyzer)) };
19+
}
20+
}
21+
}

TypeCobol.Analysis.Test/TypeCobol.Analysis.Test.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
<Compile Include="DfaBuildUseAndDefListTest.cs" />
3939
<Compile Include="DfaCallPgmReport.cs" />
4040
<Compile Include="BasicDfaSamplesTest.cs" />
41+
<Compile Include="CustomAnalyzers\TestAnalyzerProvider.cs" />
42+
<Compile Include="CustomAnalyzers\Analyzers.cs" />
4143
<Compile Include="Properties\AssemblyInfo.cs" />
4244
</ItemGroup>
4345
<ItemGroup>

TypeCobol.LanguageServer/Workspace.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,10 @@ public void DidChangeConfigurationParams(IEnumerable<string> arguments)
506506

507507
var typeCobolOptions = new TypeCobolOptions(Configuration);
508508

509-
//Configure CFG/DFA analyzer
509+
//Configure CFG/DFA analyzer + external analyzers if any
510510
var analyzerProvider = new CompositeAnalyzerProvider();
511511
analyzerProvider.AddActivator((o, t) => CfgDfaAnalyzerFactory.CreateCfgAnalyzer("cfg-dfa", Configuration.CfgBuildingMode));
512+
analyzerProvider.AddCustomProviders(Configuration.CustomAnalyzerFiles);
512513

513514
CompilationProject = new CompilationProject(_workspaceName, _rootDirectoryFullName, Helpers.DEFAULT_EXTENSIONS, Configuration.Format, typeCobolOptions, analyzerProvider);
514515

TypeCobol/Analysis/AnalyzerProvider.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ private TAnalyzer[] Concat<TAnalyzer>(TAnalyzer[] fromBase, Func<IAnalyzerProvid
7070
{
7171
if (_providers != null && _providers.Count > 0)
7272
{
73-
var result = _providers.SelectMany(selector);
73+
var result = _providers
74+
.Select(selector) //from provider to analyzers
75+
.Where(a => a != null) //providers may return null arrays so filter them out
76+
.SelectMany(a => a); //join all arrays into a single IEnumerable
7477
if (fromBase != null)
7578
{
7679
result = fromBase.Concat(result);

0 commit comments

Comments
 (0)