Skip to content

Commit

Permalink
impl diagnostic manage
Browse files Browse the repository at this point in the history
  • Loading branch information
CppCXY committed Apr 15, 2024
1 parent 54a48a7 commit 3310a9d
Show file tree
Hide file tree
Showing 22 changed files with 496 additions and 30 deletions.
1 change: 1 addition & 0 deletions .idea/.idea.EmmyLuaAnalyzer/.idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ public void WalkIn(LuaSyntaxElement node)
Compilation.Diagnostics.AddMeta(DocumentId);
break;
}
case LuaDocTagDiagnosticSyntax diagnosticSyntax:
{
AnalyzeDiagnostic(diagnosticSyntax);
break;
}
}
}

Expand Down Expand Up @@ -1099,4 +1104,57 @@ private void IndexDocNameType(LuaDocNameTypeSyntax docNameType)
{
ProjectIndex.AddNameType(DocumentId, docNameType);
}

private void AnalyzeDiagnostic(LuaDocTagDiagnosticSyntax diagnosticSyntax)
{
if (diagnosticSyntax is
{
Action: { RepresentText: { } actionName },
Diagnostics: { DiagnosticNames: { } diagnosticNames }
})
{
switch (actionName)
{
case "disable-next-line":
{
if (diagnosticSyntax.Parent is LuaCommentSyntax { Owner.Range: { } range })
{
foreach (var diagnosticName in diagnosticNames)
{
if (diagnosticName is { RepresentText: { } name })
{
Compilation.Diagnostics.AddDiagnosticDisableNextLine(DocumentId, range, name);
}
}
}

break;
}
case "disable":
{
foreach (var diagnosticName in diagnosticNames)
{
if (diagnosticName is { RepresentText: { } name })
{
Compilation.Diagnostics.AddDiagnosticDisable(DocumentId, name);
}
}

break;
}
case "enable":
{
foreach (var diagnosticName in diagnosticNames)
{
if (diagnosticName is { RepresentText: { } name })
{
Compilation.Diagnostics.AddDiagnosticEnable(DocumentId, name);
}
}

break;
}
}
}
}
}
9 changes: 7 additions & 2 deletions EmmyLua/CodeAnalysis/Compilation/Infer/TypeInfer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,15 @@ public static LuaType InferFuncType(LuaDocFuncTypeSyntax funcType, SearchContext
var typedParameters = new List<ParameterLuaDeclaration>();
foreach (var typedParam in funcType.ParamList)
{
if (typedParam is { Name: { } name })
if (typedParam is { Name: { } name, Nullable: {} nullable })
{
var type = context.Infer(typedParam.Type);
if (nullable)
{
type = type.Union(Builtin.Nil);
}
var paramDeclaration = new ParameterLuaDeclaration(
name.RepresentText, new(typedParam), context.Infer(typedParam.Type));
name.RepresentText, new(typedParam), type);
typedParameters.Add(paramDeclaration);
}
else if (typedParam is { VarArgs: { } varArgs })
Expand Down
26 changes: 20 additions & 6 deletions EmmyLua/CodeAnalysis/Compile/Grammar/Doc/Tags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -559,12 +559,7 @@ private static CompleteMarker TagDiagnostic(LuaDocParser p)
if (p.Current is LuaTokenKind.TkColon)
{
p.Bump();
p.Expect(LuaTokenKind.TkName);
while (p.Current is LuaTokenKind.TkComma)
{
p.Bump();
p.Expect(LuaTokenKind.TkName);
}
DiagnosticList(p);
}

return m.Complete(p, LuaSyntaxKind.DocDiagnostic);
Expand All @@ -575,6 +570,25 @@ private static CompleteMarker TagDiagnostic(LuaDocParser p)
}
}

private static CompleteMarker DiagnosticList(LuaDocParser p)
{
var m = p.Marker();
try
{
p.Expect(LuaTokenKind.TkName);
while (p.Current is LuaTokenKind.TkComma)
{
p.Bump();
p.Expect(LuaTokenKind.TkName);
}
return m.Complete(p, LuaSyntaxKind.DiagnosticNameList);
}
catch (UnexpectedTokenException e)
{
return m.Fail(p, LuaSyntaxKind.DiagnosticNameList, e.Message);
}
}

private static CompleteMarker TagVersion(LuaDocParser p)
{
p.SetState(LuaDocLexerState.Normal);
Expand Down
4 changes: 2 additions & 2 deletions EmmyLua/CodeAnalysis/Compile/Parser/Marker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ public interface IMarkerEventContainer
public Marker Marker();
}

public struct Marker(int position)
public readonly struct Marker(int position)
{
public int Position { get; set; } = position;
public int Position { get; } = position;

public CompleteMarker Complete(IMarkerEventContainer p, LuaSyntaxKind kind)
{
Expand Down
11 changes: 10 additions & 1 deletion EmmyLua/CodeAnalysis/Diagnostics/DiagnosticConfig.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
namespace EmmyLua.CodeAnalysis.Diagnostics;
using EmmyLua.CodeAnalysis.Document;

namespace EmmyLua.CodeAnalysis.Diagnostics;

public class DiagnosticConfig
{
public HashSet<string> Globals { get; } = new();

public HashSet<DiagnosticCode> WorkspaceDisabledCodes { get; } = new();
}

public class DisableNextLine
{
public Dictionary<DiagnosticCode, List<SourceRange>> Ranges { get; } = new();
}
11 changes: 8 additions & 3 deletions EmmyLua/CodeAnalysis/Diagnostics/DiagnosticContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@

namespace EmmyLua.CodeAnalysis.Diagnostics;

public class DiagnosticContext(LuaDocument document, DiagnosticConfig config)
public class DiagnosticContext(LuaDocument document, LuaDiagnostics luaDiagnostics)
{
private LuaDiagnostics LuaDiagnostics { get; } = luaDiagnostics;

Check warning on line 7 in EmmyLua/CodeAnalysis/Diagnostics/DiagnosticContext.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux-x64, linux-x64)

Parameter 'LuaDiagnostics luaDiagnostics' is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.

Check warning on line 7 in EmmyLua/CodeAnalysis/Diagnostics/DiagnosticContext.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, osx-x64, darwin-x64)

Parameter 'LuaDiagnostics luaDiagnostics' is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.

Check warning on line 7 in EmmyLua/CodeAnalysis/Diagnostics/DiagnosticContext.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, osx-arm64, darwin-arm64)

Parameter 'LuaDiagnostics luaDiagnostics' is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.

Check warning on line 7 in EmmyLua/CodeAnalysis/Diagnostics/DiagnosticContext.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, win-x64, win32-x64)

Parameter 'LuaDiagnostics luaDiagnostics' is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.

Check warning on line 7 in EmmyLua/CodeAnalysis/Diagnostics/DiagnosticContext.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, linux-x64, linux-x64)

Parameter 'LuaDiagnostics luaDiagnostics' is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.

Check warning on line 7 in EmmyLua/CodeAnalysis/Diagnostics/DiagnosticContext.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, osx-x64, darwin-x64)

Parameter 'LuaDiagnostics luaDiagnostics' is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.

Check warning on line 7 in EmmyLua/CodeAnalysis/Diagnostics/DiagnosticContext.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest, osx-arm64, darwin-arm64)

Parameter 'LuaDiagnostics luaDiagnostics' is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.

Check warning on line 7 in EmmyLua/CodeAnalysis/Diagnostics/DiagnosticContext.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest, win-x64, win32-x64)

Parameter 'LuaDiagnostics luaDiagnostics' is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.

public LuaDocument Document { get; } = document;

public DiagnosticConfig Config { get; } = config;
public DiagnosticConfig Config => LuaDiagnostics.Config;

public void Report(Diagnostic diagnostic)
{
Document.SyntaxTree.PushDiagnostic(diagnostic);
if (luaDiagnostics.CanAddDiagnostic(Document.Id, diagnostic.Code, diagnostic.Range))
{
Document.SyntaxTree.PushDiagnostic(diagnostic);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

namespace EmmyLua.CodeAnalysis.Diagnostics.Handlers;

public abstract class DiagnosticHandlerBase(LuaCompilation compilation)
public abstract class DiagnosticHandlerBase(LuaCompilation compilation, List<DiagnosticCode> codes)
{
public LuaCompilation Compilation { get; } = compilation;

public List<DiagnosticCode> Codes { get; } = codes;

public virtual void Check(DiagnosticContext context)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace EmmyLua.CodeAnalysis.Diagnostics.Handlers;

public class TypeCheckHandler(LuaCompilation compilation) : DiagnosticHandlerBase(compilation)
public class TypeCheckHandler(LuaCompilation compilation) : DiagnosticHandlerBase(compilation, [])
{
public override void Check(DiagnosticContext context)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace EmmyLua.CodeAnalysis.Diagnostics.Handlers;

public class UndefinedGlobalHandler(LuaCompilation compilation) : DiagnosticHandlerBase(compilation)
public class UndefinedGlobalHandler(LuaCompilation compilation)
: DiagnosticHandlerBase(compilation,
[DiagnosticCode.UndefinedGlobal, DiagnosticCode.NeedImport])
{
public override void Check(DiagnosticContext context)
{
Expand Down Expand Up @@ -57,6 +59,7 @@ public override void Check(DiagnosticContext context)
));
continue;
}

if (documentIds.Count == 1)
{
var moduleIndex = Compilation.Workspace.ModuleGraph.GetModuleInfo(documentIds.First());
Expand Down
6 changes: 2 additions & 4 deletions EmmyLua/CodeAnalysis/Diagnostics/Handlers/UnusedHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@

namespace EmmyLua.CodeAnalysis.Diagnostics.Handlers;

public class UnusedHandler(LuaCompilation compilation) : DiagnosticHandlerBase(compilation)
public class UnusedHandler(LuaCompilation compilation) : DiagnosticHandlerBase(compilation, [DiagnosticCode.Unused])
{
private DiagnosticCode Code { get; } = DiagnosticCode.Unused;

public override void Check(DiagnosticContext context)
{
var semanticModel = Compilation.GetSemanticModel(context.Document.Id);
Expand Down Expand Up @@ -59,7 +57,7 @@ private void LocalOrParamUnusedCheck(
{
context.Report(new Diagnostic(
DiagnosticSeverity.Hint,
Code,
DiagnosticCode.Unused,
"unused variable",
luaDeclaration.Ptr.Range,
DiagnosticTag.Unnecessary
Expand Down
118 changes: 116 additions & 2 deletions EmmyLua/CodeAnalysis/Diagnostics/LuaDiagnostics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public class LuaDiagnostics(LuaCompilation compilation)

private HashSet<LuaDocumentId> IsMetaDocument { get; } = new();

private Dictionary<LuaDocumentId, HashSet<DiagnosticCode>> Disables { get; } = new();

private Dictionary<LuaDocumentId, HashSet<DiagnosticCode>> Enables { get; } = new();

private Dictionary<LuaDocumentId, DisableNextLine> DisableNextLines { get; } = new();

public DiagnosticConfig Config { get; set; } = new();

public void Check(LuaDocument document)
Expand All @@ -26,20 +32,128 @@ public void Check(LuaDocument document)
return;
}

var context = new DiagnosticContext(document, Config);
var context = new DiagnosticContext(document, this);
foreach (var handler in Handlers)
{
handler.Check(context);
if (CanCheck(document.Id, handler))
{
handler.Check(context);
}
}
}

public bool CanCheck(LuaDocumentId documentId, DiagnosticHandlerBase handlerBase)
{
var codes = handlerBase.Codes;
return codes.Count != 0 && codes.Any(code => CanCheckCode(documentId, code));
}

private bool CanCheckCode(LuaDocumentId documentId, DiagnosticCode code)
{
var shouldCheck = !Config.WorkspaceDisabledCodes.Contains(code);
if (Disables.TryGetValue(documentId, out var disables))
{
if (disables.Contains(code))
{
shouldCheck = false;
}
}

if (Enables.TryGetValue(documentId, out var enables))
{
if (enables.Contains(code))
{
shouldCheck = true;
}
}

return shouldCheck;
}

public bool CanAddDiagnostic(LuaDocumentId documentId, DiagnosticCode code, SourceRange range)
{
if (!CanCheckCode(documentId, code))
{
return false;
}

if (DisableNextLines.TryGetValue(documentId, out var disableNextLine))
{
if (disableNextLine.Ranges.TryGetValue(code, out var ranges))
{
return ranges.All(disableRange => !disableRange.Intersect(range));
}
}

return true;
}

public void AddMeta(LuaDocumentId documentId)
{
IsMetaDocument.Add(documentId);
}

public void AddDiagnosticDisable(LuaDocumentId documentId, string diagnosticName)
{
var code = DiagnosticCodeHelper.GetCode(diagnosticName);
if (code != DiagnosticCode.None)
{
if (!Disables.TryGetValue(documentId, out var disables))
{
disables = new HashSet<DiagnosticCode>();
Disables[documentId] = disables;
}

disables.Add(code);
}
}

public void AddDiagnosticEnable(LuaDocumentId documentId, string diagnosticName)
{
var code = DiagnosticCodeHelper.GetCode(diagnosticName);
if (code != DiagnosticCode.None)
{
if (!Enables.TryGetValue(documentId, out var enables))
{
enables = new HashSet<DiagnosticCode>();
Enables[documentId] = enables;
}

enables.Add(code);
}
}

public void AddDiagnosticDisableNextLine(LuaDocumentId documentId, SourceRange range, string diagnosticName)
{
var code = DiagnosticCodeHelper.GetCode(diagnosticName);
if (code != DiagnosticCode.None)
{
if (!DisableNextLines.TryGetValue(documentId, out var disableNextLine))
{
disableNextLine = new DisableNextLine();
DisableNextLines[documentId] = disableNextLine;
}

if (!disableNextLine.Ranges.TryGetValue(code, out var ranges))
{
ranges = new List<SourceRange>();
disableNextLine.Ranges[code] = ranges;
}

ranges.Add(range);
}
}

public void RemoveCache(LuaDocumentId documentId)
{
IsMetaDocument.Remove(documentId);
Disables.Remove(documentId);
Enables.Remove(documentId);
DisableNextLines.Remove(documentId);
}

public List<string> GetDiagnosticNames()
{
return Handlers.SelectMany(handler => handler.Codes.Select(DiagnosticCodeHelper.GetName)).ToList();
}
}
2 changes: 1 addition & 1 deletion EmmyLua/CodeAnalysis/Kind/LuaSyntaxKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public enum LuaSyntaxKind : ushort
TypedParameter,
GenericParameter,
GenericDeclareList,

DiagnosticNameList,
// start with '#' or '@'
Description
}
Loading

0 comments on commit 3310a9d

Please sign in to comment.