This repository has been archived by the owner on Mar 1, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implements first resolver: ==/!= with null comparer
- Loading branch information
1 parent
2fd8f06
commit 462fc68
Showing
2 changed files
with
107 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
module workspaced.dub.diagnostics; | ||
|
||
import workspaced.api; | ||
|
||
import std.algorithm; | ||
import std.string; | ||
|
||
import dparse.ast; | ||
import dparse.lexer; | ||
import dparse.parser; | ||
import dparse.rollback_allocator; | ||
|
||
int[2] resolveDubDiagnosticRange(scope const(char)[] code, | ||
scope const(Token)[] tokens, Module parsed, int position, | ||
scope const(char)[] diagnostic) | ||
{ | ||
if (diagnostic.startsWith("use `is` instead of `==`", | ||
"use `!is` instead of `!=`")) | ||
{ | ||
auto expr = new EqualComparisionFinder(position); | ||
expr.visit(parsed); | ||
if (expr.result !is null) | ||
{ | ||
const left = &expr.result.left.tokens[$ - 1]; | ||
const right = &expr.result.right.tokens[0]; | ||
auto between = left[1 .. right - left]; | ||
const tok = between[0]; | ||
if (tok.type == expr.result.operator) | ||
{ | ||
auto index = cast(int) tok.index; | ||
return [index, index + 2]; | ||
} | ||
} | ||
} | ||
return [position, position]; | ||
} | ||
|
||
/// Finds the equals comparision at the given index. | ||
/// Used to resolve issue locations for diagnostics of type | ||
/// - use `is` instead of `==` | ||
/// - use `!is` instead of `!=` | ||
class EqualComparisionFinder : ASTVisitor | ||
{ | ||
this(size_t index) | ||
{ | ||
this.index = index; | ||
} | ||
|
||
override void visit(const(CmpExpression) expr) | ||
{ | ||
if (expr.equalExpression !is null) | ||
{ | ||
const start = expr.tokens[0].index; | ||
const last = expr.tokens[$ - 1]; | ||
const end = last.index + last.text.length; | ||
if (index >= start && index < end) | ||
{ | ||
result = cast(EqualExpression) expr.equalExpression; | ||
} | ||
} | ||
super.visit(expr); | ||
} | ||
|
||
alias visit = ASTVisitor.visit; | ||
size_t index; | ||
EqualExpression result; | ||
} | ||
|
||
unittest | ||
{ | ||
string code = q{void main() { | ||
if (foo(a == 4) == null) | ||
{ | ||
} | ||
}}; | ||
|
||
LexerConfig config; | ||
RollbackAllocator rba; | ||
StringCache cache = StringCache(64); | ||
auto tokens = getTokensForParser(cast(ubyte[]) code, config, &cache); | ||
auto parsed = parseModule(tokens, "equal_finder.d", &rba); | ||
|
||
auto range = resolveDubDiagnosticRange(code, tokens, parsed, 19, | ||
"use `is` instead of `==` when comparing with `null`"); | ||
|
||
shouldEqual(range, [31, 33]); | ||
} |