Why isn't Roslyn respecting Whitespace trivia, forcing tab indentation instead? - roslyn

I am developing a little hobby project trying to bring C# down to be compilable to the NES over at this repository. As of commit 9b532f739be some of the unit tests on my first Code Fix Provider are failing only because Roslyn is ignoring the Whitespace trivia that is coming from a node that I want replaced, in line 90 of the ForbidMuliplicationCodeFixProvider.cs file. I've also tried NormalizeWhiteSpace on the new node with the same WhiteSpaceTrivia indent size, and a couple other failed attemps, only to always end up with standard tab-size indents on the modified document. Will I have to live with this little bug?
var assignment = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, variableIdentifier, invocation);
assignment = assignment.WithTriviaFrom(node);
var syntaxRoot = await document.GetSyntaxRootAsync();
var modifiedRoot = syntaxRoot.ReplaceNode(node, assignment);
var modifiedDocument = document.WithSyntaxRoot(modifiedRoot);
modifiedDocument = await AddUsingStatementAsync(cancelToken, modifiedDocument);
return modifiedDocument;
The node variable comes from the original document with 6 spaces (3 tiers of indentation) of WhiteSpaceTrivia, which are supposed to be copied into the replacement node but the output of the modified document has 3 tabs of indentation instead.
My test fails with this message:
The checked string has different spaces than expected one. At line 7, col 12, expected '... test = NESMath....' was '... test = NE...'.
The checked string:
["using NINNES.Platform.Shims;
namespace NINNES.RoslynAnalyzers.Tests.Assets {
class MultiplicationAssignment {
public void Multiply() {
var test = 2;
test = NESMath.Multiply(test, 42);
}
}
}
"]
The expected string:
["using NINNES.Platform.Shims;
namespace NINNES.RoslynAnalyzers.Tests.Assets {
class MultiplicationAssignment {
public void Multiply() {
var test = 2;
test = NESMath.Multiply(test, 42);
}
}
}
"]
As an aside: Commentary on the Roslyn code would be greatly appreciated, just learning the ropes of the code modification stuff.

Related

Typescript regex exclude whole string if followed by specific string

I'm been running into weird issues with regex and Typescript in which I'm trying to have my expression replace the value of test minus the first instance if followed by test. In other words, replace the first two lines that have test but for the third line below, replace only the second value of test.
[test]
[test].[db]
[test].[test]
Where it should look like:
[newvalue]
[newvalue].[db]
[test].[newvalue]
I've come up with lots of variations but this is the one that I thought was simple enough to solve it and regex101 can confirm this works:
\[(\w+)\](?!\.\[test\])
But when using Typescript (custom task in VSTS build), it actually replaces the values like this:
[newvalue]
[newvalue].[db]
[newvalue].[test]
Update: It looks like a regex like (test)(?!.test) breaks when changing the use cases removing the square brackets, which makes me think this might be somewhere in the code. Could the problem be with the index that the value is replaced at?
Some of the code in Typescript that is calling this:
var filePattern = tl.getInput("filePattern", true);
var tokenRegex = tl.getInput("tokenRegex", true);
for (var i = 0; i < files.length; i++) {
var file = files[i];
console.info(`Starting regex replacement in [${file}]`);
var contents = fs.readFileSync(file).toString();
var reg = new RegExp(tokenRegex, "g");
// loop through each match
var match: RegExpExecArray;
// keep a separate var for the contents so that the regex index doesn't get messed up
// by replacing items underneath it
var newContents = contents;
while((match = reg.exec(contents)) !== null) {
var vName = match[1];
// find the variable value in the environment
var vValue = tl.getVariable(vName);
if (typeof vValue === 'undefined') {
tl.warning(`Token [${vName}] does not have an environment value`);
} else {
newContents = newContents.replace(match[0], vValue);
console.info(`Replaced token [${vName }]`);
}
}
}
Full code is for the task I'm using this with: https://github.com/colindembovsky/cols-agent-tasks/blob/master/Tasks/ReplaceTokens/replaceTokens.ts
For me this regex is working like you are expecting:
\[(test)\](?!\.\[test\])
with a Typescript code like that
myString.replace(/\[(test)\](?!\.\[test\])/g, "[newvalue]");
Instead, the regex you are using should replace also the [db] part.
I've tried with this code:
class Greeter {
myString1: string;
myString2: string;
myString3: string;
greeting: string;
constructor(str1: string, str2: string, str3: string) {
this.myString1 = str1.replace(/\[(test)\](?!\.\[test\])/g, "[newvalue]");
this.myString2 = str2.replace(/\[(test)\](?!\.\[test\])/g, "[newvalue]");
this.myString3 = str3.replace(/\[(test)\](?!\.\[test\])/g, "[newvalue]");
this.greeting = this.myString1 + "\n" + this.myString2 + "\n" + this.myString3;
}
greet() {
return "Hello, these are your replacements:\n" + this.greeting;
}
}
let greeter = new Greeter("[test]", "[test].[db]", "[test].[test]");
let button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function() {
alert(greeter.greet());
}
document.body.appendChild(button);
Online playground here.

Replace text in Go using regex

I am working in Go, I have a text file in which I want to replace a text based on a regex, but it's not working as expected even when I already tested the regex here and it says that there's a match.
I made the basic example in play ground and I am getting the same result. I have 3 text files with the same label (//==start== and //==end==), it works for the first one, but no for the second and third. What can be avoiding the regex to replace correctly the text?
https://play.golang.org/p/nZdHg5IfZ89
This is the code that I used, I pasted all the string because I want to be sure that it's not the one affecting me
package main
func main() {
var re = regexp.MustCompile(Myregex)
s := re.ReplaceAllLiteralString(originalString,"replaced")
fmt.Println(s)
}
var Myregex = `\/\/==start==\n(.+\n)*\/\/==end==`
var originalString = `// #Author: someone
// #Date: 2018-01-23T16:46:09-04:00
// #Email: dddddddd#gmail.com
// #Filename: _material.themes.scss
// #Last modified by: Someone
// #Last modified time: 2018-01-23T18:40:39-04:00
#include angular-material-theme($theme);
.app-dark {
#include angular-material-theme($dark-theme);
}
.app-pink {
#include angular-material-theme($pink-theme);
}
//==start==
//==end==`
Hope this will help you
func main() {
var re = regexp.MustCompile(Myregex)
s := re.ReplaceAllString(originalString, "replaced")
fmt.Println(s)
}
var Myregex = `//==start==\n.*\n//==end==`
See in action: https://play.golang.org/p/GITAdHOOQOg

Matching parameters of a function with Regex

What I have so far: \w+\(((".+")|(\d+))+\)I'm not sure how to go about matching more than one paramter separated by a comma. How can I capture the parameters (and function names) of the following test cases?
scroll("foo")
scroll("foo",55)
scroll("foo","bar")
scroll("foo","bar",55)
scroll(55)
scroll(55,"foo")
scroll(55, 13,"foo","bar")
For example, in the last one the groups must be scroll, 55, 13, "foo", and "bar".
Edit: Language is AS3
Try this lengthy regex:
(\"?\w+\"?)\((\"?\w+\"?)(?:[,\s]+(\"?\w+\"?))?(?:[,\s]+(\"?\w+\"?))?(?:[,\s]+(\"?\w+\"?))?\)?
The code above is set to capture up to five parameters. You can adjust that by adding/removing this code (?:[,\s]+(\"?\w+\"?))? based on your needs.
Demo: https://regex101.com/r/o1RRSG/1
i hope i'm in right way
you want to split for example
this: scroll ( 55, 13, "foo", "bar" )
to its function name and arguments like
this: scroll ( 55, 13, "foo", "bar" )
a better result of expression:
i just assume additional white spaces for more accuracy
the regex fot would be :
[^\t (,)]
Okay, you may not like it, but it's flawless as long as you have ExternalInterface backed with JS available. And it's funny. (While doing this with reg exps is the opposite of fun.)
The idea is to let JS do its eval. The manual says you have to pass a function name to ExternalInterface.call(), which is not true: pass just any code that evaluates to a function reference. This way you can inject any JS code into the page where your SWF resides (which is why AllowScriptAccess is such a terribly dangerous attribute).
public class Test extends Sprite
{
public function Test()
{
var test = "scroll(55, 13,\"foo\",\"bar\", \"now(), we are \\\"screwed\\\")\")";
trace(test);
var details = parseFunctionCall(test);
trace(details[0]);
for (var i = 1; i<details.length; i++) {
trace("\t"+i+": "+typeof(details[i])+" "+details[i]);
}
}
private function parseFunctionCall(input:String):Array
{
if (ExternalInterface.available) {
var split:RegExp = /^(\w+)\((.+)\)$/;
var info = split.exec(input);
var inject = "(function(){return ["+info[2]+"];})";
var params = ExternalInterface.call(inject);
params.unshift(info[1]);
return params;
}
return null;
}
}
/*
Output:
scroll
1: number 55
2: number 13
3: string foo
4: string bar
5: string now(), we are "screwed")
*/

Record with List of Records Unit Test Failing

I have the following records:
namespace FunctionalInnovate.Domain
module Voting=
open System
type Vote = {
VoteId : int
SuggestionId : int
VotePreference : int
}
type Suggestion = {
SuggetionId : int
SuggestionText : string
}
type User = {
UserId : int
Votes : Vote list
}
From these records, I have created the following Unit Test:
module ``Voting Tests``
open NUnit.Framework
open FsUnit
open FunctionalInnovate.Domain.Voting
[<Test>]
let``Get Vote from given SuggestionId``()=
let votePreference = 1
let vote1 = { VoteId = 1; SuggestionId = 34; VotePreference = votePreference }
let vote2 = { VoteId = 2; SuggestionId = 654; VotePreference = votePreference}
let votes = [ vote1; vote2; ]
let user = {UserId = 321; Votes = votes}
Assert.IsTrue(true) |> ignore
I've just changed the Assert statement to something simple at this point as it keeps failing at present. Using ReSharper, when I run the test I get an error. Upon investigation, it appears to be a problem with the List of Votes being assigned to the Votes type within my user declaration. What I find strange though is that if I load all of the types into FSI and then load each line of the test in turn, it works without any errors.
Anyone got any ideas as to why the unit test is failing?
The error ReSharper Test Runner is producing is:
System.MissingMethodException : Method not found: 'Void User..ctor(Int32, Microsoft.FSharp.Collections.FSharpList`1<Vote>)'.
at Voting Tests.Get Vote from given SuggestionId()
As per #Tomas Petricek and #John Palmer's advice, it was an issue with my ''FSharp.Core.dll'' version.
The version of this DLL in my UnitTest project was much older than what was in my Domain project.
All I did to fix it was going into NuGet Package Manager and update that specific package. Upon running my tests again, everything was green and healthy.

AS3/Regular Expressions - Replacing segments of a string

I have absolutely no knowledge in Regex whatsoever. Basically what I'm trying to do is have an error class that I can use to call errors (obviously) which looks like this:
package avian.framework.errors
{
public class AvError extends Object
{
// errors
public static const LAYER_WARNING:String = "Warning: {0} is not a valid layer - the default layer _fallback_ has been used as the container for {1}.";
/**
* Constructor
* Places a warning or error into the output console to assist with misuse of the framework
* #param err The error to display
* #param params A list of Objects to use throughout the error message
*/
public function AvError(err:String, ...params)
{
trace(err);
}
}
}
What I want to be able to do is use the LAYER_WARNING like this:
new AvError(AvError.LAYER_WARNING, targetLayer, this);
And have the output be something along the lines of:
Warning: randomLayer is not a valid layer - the default layer _fallback_ has been used as the container for [object AvChild].
The idea is to replace {0} with the first parameter parsed in ...params, {1} with the second, etc.
I've done a bit of research and I think I've worked out that I need to search using this pattern:
var pattern:RegExp = /{\d}/;
You can use StringUtil
var original:String = "Here is my {0} and my {1}!";
var myStr:String = StringUtil.substitute(original, ['first', 'second']);
Using the g flag in RegExp you can create an array containing all of your {x} matches, then loop through this array and replace each of the matches with the appropriate parameter.
Code:
var mystring:String = "{0} went to {1} on {2}";
function replace(str:String, ...params):String
{
var pattern:RegExp = /{\d}/g;
var ar:Array = str.match(pattern);
var i:uint = 0;
for(i; i<ar.length; i++)
{
str = str.split(ar[i]).join(params[i]);
}
return str;
}
trace(replace(mystring, "marty", "work", "friday")); // marty went to work on friday
i'm assuming you want to have several static constants with varying replacement instances ({0}, {1}, {2}, etc.) in each string constant.
something like this should work - sorry, it's untested:
public function AvError(err:String, ...params)
{
var replacementArray:Array = err.match(new RegExp("{\\d}", "g"));
for (var i:int = 0, i < replacementArray.length, i++)
err = err.replace(new RegExp(replacementArray[i], "g"), params[i]);
trace(err);
}
if you do have several static constants with varying replacement instances, you'll want to check for an appropriate matching amount of …params that are passed.