As you can see, only the if statement gets the leading trivia and not the rest of it:
Input:
__Internal.DestroyContext(__arg0);
Current result:
if (IntPtr.Size == 4)
{
__Internal32.DestroyContext(__arg0);
}
else
{
__Internal64.DestroyContext(__arg0);
}
Expected:
if (IntPtr.Size == 4)
{
__Internal32.DestroyContext(__arg0);
}
else
{
__Internal64.DestroyContext(__arg0);
}
Code used:
var statement =
IfStatement(GetImportCondition(),
Block(ExpressionStatement(GetImportIdentifier32(invocation, name2))))
.WithElse(ElseClause(
Block(ExpressionStatement(GetImportIdentifier64(invocation, name2)))))
.NormalizeWhitespace()
.WithTriviaFrom(exp);
node = node.ReplaceNode(exp, statement);
If I remove NormalizeWhitespace, it works obviously but it isn't formatted anymore:
if(IntPtr.Size==4){__Internal32.DestroyContext(__arg0);}else{__Internal64.DestroyContext(__arg0);}
Question:
How can one apply WithTriviaFrom recursively when used for an IfStatement?
Please don't suggest to normalize whitespace at root as this formats the whole document.
Related
I'm working on a method that gives the next available node name if a node with the specified name exists. But the idea is that the method gives the next one from the max value, for example:
If I add a new node called "test", the method should return "test6" and not "test2". The same happens with the nodes that contain numbers as names:
If I add a new node with the name "20", the next available name should be "31".
So the idea is to get the "max value" from a sequence and add one to it. This tree node could contain easily more than 500 nodes, so is very important the optimization of this method. I've been trying to do this with this code, but does not work as expected:
internal static string GetNextAvailableName(TreeView treeView, string searchFor)
{
//Check if item exists
if (NodeExistsInSection(treeView, searchFor))
{
return searchFor;
}
else
{
//Initialize variables
string nextAvailableName = searchFor;
int counter = 0;
Match result = Regex.Match(searchFor, #"\d+$", RegexOptions.RightToLeft);
if (result.Success)
{
counter = int.Parse(result.Value);
if (searchFor.Length >= result.Value.Length)
{
searchFor = searchFor.Substring(0, (searchFor.Length - result.Value.Length));
}
}
while (SearchRecByText(treeView, nextAvailableName) != null)
{
counter++;
nextAvailableName = string.Join("", searchFor, counter);
}
return nextAvailableName;
}
}
internal static bool NodeExistsInSection(TreeView treeView, string searchFor)
{
bool nodeExists = false;
// Print each node recursively.
foreach (TreeNode n in treeView.Nodes)
{
//recursiveTotalNodes++;
if (LoopNodesRecursive(n, searchFor) != null)
{
nodeExists = true;
break;
}
}
return nodeExists;
}
internal static TreeNode SearchRecByText(TreeView treeView, string searchFor)
{
TreeNode matchedNode = null;
// Print each node recursively.
foreach (TreeNode n in treeView.Nodes)
{
//recursiveTotalNodes++;
matchedNode = LoopNodesRecursive(n, searchFor);
if (matchedNode != null)
{
break;
}
}
return matchedNode;
}
private static TreeNode LoopNodesRecursive(TreeNode treeNode, string searchFor)
{
// Visit each node recursively.
foreach (TreeNode tn in treeNode.Nodes)
{
if (tn.Text.Equals(searchFor, StringComparison.OrdinalIgnoreCase))
{
return tn;
}
}
return null;
}
If performance is your outright goal I think I'd have a dictionary track treenodes with a special case for if the user enters a number. From the code posted it seems that nodes must be uniquely named across the entire tree. As such I'd build a dictionary upon tree init and maintain it as I go
Here's the method that suggests new node names based on what the user types:
Dictionary<string, int> prefixes = new();
string GetNodeName(string prefix){
//strip trailing numbers entered by the user
prefix = Regex.Replace(prefix, "\\d+$", "");
//have we seen the prefix before?
var n = prefixes.GetValueOrDefault(prefix, 0);
prefixes[prefix] = n + 1;
if(n > 0) //nth time we saw it, return number suffix
return prefix+n;
if(prefix == "") //user entered just a number, for the first time
return "1";
return prefix; //user entered a new prefix
}
GetNodeName identifies the prefix text the user types by stripping off trailing numbers and checking what the next known number is for the resulting prefix. If the prefix is unknown it gets 0, 1 is then added as the next number and the 0 is special cased to "not having a numeric suffix"
If we need to restore the tree from somewhere we need to build up the max+1 values we see as we build:
void Build(string nodename){
//strip trailing numbers
var prefix = Regex.Replace(prefix, "\\d+$", "");
//get the number off the end. Uses c# 8 ranges; if your c# version is less, use Remove(length) instead
var number = int.Parse(nodename[prefix.Length..]);
//have we seen the prefix before?
var n = prefixes.GetValueOrDefault(prefix, 0);
//node number is higher than dictionary? Bump dict
if(number >= n)
prefixes[prefix] = number + 1;
}
Call build for every node text as you rebuild your tree from DB or whatever; it will bump up the number in the prefixes dictionary to be +1 of whatever it is seeing
I assume it's a logical error to allow a user to enter a prefix of "test2" repeatedly and you will make nodes of "test2","test21",test22" - I deem that the prefix is "test", the user supplied 2 is ignored and the node gets whatever is next in line for "test" ie "test7". This logic works if the user just enters a number, the prefix is then "" and is numbered accordingly
I am doing a problem from Top-Coder.The problem statement is-
One day, Jamie noticed that many English words only use the letters A
and B. Examples of such words include "AB" (short for abdominal),
"BAA" (the noise a sheep makes), "AA" (a type of lava), and "ABBA" (a
Swedish pop sensation).
Inspired by this observation, Jamie created a simple game. You are
given two Strings: initial and target. The goal of the game is to find
a sequence of valid moves that will change initial into target. There
are two types of valid moves:
Add the letter A to the end of the string. Reverse the string and then
add the letter B to the end of the string. Return "Possible" (quotes
for clarity) if there is a sequence of valid moves that will change
initial into target. Otherwise, return "Impossible".
Below is my solution of the problem which passed all the tests in the Panel but failed in system test.But,I did not get any specific information about which test case failed.Please check if my code will not work in some scenario.
class ABBA
{
public string canObtain(string initial,string target)
{
string s = "Impossible";
if (initial.Length > target.Length)
return "Impossible";
if (initial.Equals(target))
return "Possible";
if (CheckFirstWay(target,initial))
{
s=canObtain(initial+"A",target);
}
if (s.Equals("Impossible") && CheckSecondWay(target,initial))
{
s=canObtain(ReverseStringDirect(initial) + "B",target);
}
return s;
}
public static string ReverseStringDirect(string s)
{
char[] array = new char[s.Length];
int forward = 0;
for (int i = s.Length - 1; i >= 0; i--)
{
array[forward++] = s[i];
}
return new string(array);
}
private static bool CheckSecondWay(string final, string initial)
{
if (final.Contains(ReverseStringDirect(initial) + "B") || final.Contains("B"+initial))
{
return true;
}
else
{
return false;
}
}
private static bool CheckFirstWay(string final1, string initial)
{
if (final1.Contains(initial + "A") || final1.Contains(ReverseStringDirect(initial+"A")))
{
return true;
}
else
{
return false;
}
}
}
You can check on which test failed by following procedure,
Go to the specified room.
Open the problem.
Compile.
Submit it.
Then go to run system test.
you will see the error test there.
OR
Select the match from here.
Then in the page as shown you will see set of blue coders and red coders who topped the match.
Select any one player as per your division. [.] --> this logo beside name.
Then check their solution you will see those tests.
Here are the test cases..check it out.
You have to type system tests here. You can check the image below. Image credit : Google
I'm trying to use Roslyn to replace some old, slow code in a utility that searches our source code for string literals which are not wrapped in an X() function call (things wrapped in X() will be be translated).
I was able to use the Syntax Tree to get the string literals quite easily, and identified most of the places where they were wrapped in X(). What I was doing: given an LiteralExpressionSyntax object, I found that this gave me the function call and I could match it with a regular expression.
s.Parent.Parent.Parent.ToFullString()
I quickly ran into a problem when the string literal was split between two lines. At that point I realized my means of checking if it was in an X() call was poor, because I'd have to keep adding .Parent to the chain. While I could write something to crawl backwards up the tree, that didn't seem like it was the right way (and probably wouldn't perform very well).
I've been trying to find a way, given a string literal syntax node, to determine if that is an argument in a method call. I haven't been able to find a decent way of going from the Syntax Tree to the Semantic Model to find what I'm looking for. I'm not even sure if that's the right approach, or if I'm missing something obvious.
I was able to use SymbolFinder.FindSymbolAtPositionAsync to get to the symbol, but that suffers from the same issue - I can't just pass the position of the string literal argument, I have to pass the position of the (correct) parent and I'm back where I started.
I'm hoping to avoid having to loop through the syntax tree multiple times, because that slows things way down. I can parse 553 files in about 1 second, but as soon as I try to loop to account for these multi-line situations, I'm up to about 12-13 seconds.
Just in case I've lost you in this novella (sorry), here's what I'm hoping to figure out: for a string literal being passed as an argument to a method, is there an easy way to determine what that method is?
Here is some example code - I've replaced calls to my X() function with Convert.ToString just to simulate the code I'm searching (I had to add references to one of our DLLs, so I switched calls to Convert.ToString() so I could just reference mscorlib for this example.
static void TestAttempt()
{
string source = #"
Imports System
Namespace Exceptions
Public NotInheritable Class ExampleException
Inherits Validation
Public Sub New()
Convert.ToString(""Ignore me 1"")
Console.WriteLine(""Report me"")
Console.WriteLine(Convert.ToString(""Ignore me 2""))
MyBase.New(Convert.ToString(""Ignore me 3, "" & _
""Because I'm already translated.""))
End Sub
End Class
End Namespace";
var tree = VisualBasicSyntaxTree.ParseText(source);
var syntaxRoot = tree.GetRoot();
int i = 0;
foreach (var s in syntaxRoot.DescendantNodes().OfType<LiteralExpressionSyntax>())
{
// things to skip:
if (s == null) { continue; }
if (s.Kind() != SyntaxKind.StringLiteralExpression) { continue; }
var Mscorlib = PortableExecutableReference.CreateFromFile(#"C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll");
var compilation = VisualBasicCompilation.Create("MyCompilation", syntaxTrees: new[] { tree }, references: new[] { Mscorlib });
var model = compilation.GetSemanticModel(tree);
var symbol = SymbolFinder.FindSymbolAtPositionAsync(model, s.Parent.Parent.Parent.Span.Start, new AdhocWorkspace()).Result;
if (symbol.ToDisplayString().EndsWith("Convert")) { continue; }
Console.WriteLine(symbol);
Console.WriteLine($" Reported: {s.ToString()}");
i++;
}
Console.WriteLine();
Console.WriteLine($"Total: {i}");
}
With a warning that I have never used Roslyn before, and I normally code in VB.NET, I think I hacked together something that seems to do what you want (using LINQPad and lots of Dump() calls helped to find out what was going on).
void TestAttempt()
{
string source = #"
Imports System
Namespace Exceptions
Public NotInheritable Class ExampleException
Inherits Validation
Public Sub New()
X(""Ignore me 1"")
Console.WriteLine(""Report me"")
Console.WriteLine(X(""Ignore me 2""))
MyBase.New(X(""Ignore me 3, "" & _
""Because I'm already translated.""))
End Sub
End Class
End Namespace";
var tree = VisualBasicSyntaxTree.ParseText(source);
var syntaxRoot = tree.GetRoot();
int i = 0, notWrapped = 0;
foreach (var s in syntaxRoot.DescendantNodes().OfType<LiteralExpressionSyntax>())
{
// things to skip:
if (s == null) { continue; }
if (s.Kind() != SyntaxKind.StringLiteralExpression) { continue; }
if (!IsWrappedInCallToX(s))
{
Console.WriteLine($" Reported: {s.ToString()}");
notWrapped++;
}
i++;
}
Console.WriteLine();
Console.WriteLine($"Total: {i}, Not Wrapped In X: {notWrapped}");
}
bool IsWrappedInCallToX(SyntaxNode node)
{
var invocation = node as InvocationExpressionSyntax;
if (invocation != null)
{
var exp = invocation.Expression as IdentifierNameSyntax;
if (exp != null && exp.ToString() == "X")
{
return true;
}
}
if (node.Parent != null)
{
return IsWrappedInCallToX(node.Parent);
}
return false;
}
This results in:
Reported: "Report me"
Total: 5, Not Wrapped In X: 1
The IsWrappedInCallToX function just recurses up the tree looking for an InvocationExpressionSyntax for the X function. I know you said "While I could write something to crawl backwards up the tree, that didn't seem like it was the right way (and probably wouldn't perform very well)", but to me it seems like this is the right way - if the performance is horrible on your code base, maybe not!
Again, I know nothing about Roslyn (this just sounded interesting), so this is very likely a terrible solution! :-)
I want to do something like Google does in its search: if the user write some special char, like - or * the results are filtered.
What I have now: a filter that filters objects Name property with Contains method, and two special characters:
for leaving only the names that don't contain the typed text -
for searching a different property of my object (in my case it is Units) *
Ok, what I need is to combine above logic and be able to first filter with "-" or "*" and then be able to type and continue filtering the remaining results.
It's all about the logic I think, but it's getting complicated and I might need a little help.
item.View.Filter = delegate(object o)
{
//Lógica de filtrado
if ((item.FilterText.Length > 0) && ((item.FilterText[0] == '*') || (item.FilterText[0] == '-')))
{
//If the first char is *
if ((item.FilterText[0] == '*')
&& (((MyObject)o).Units[0].ToString().ToUpper(CultureInfo.InvariantCulture)
.Contains(item.FilterText.ToUpper(CultureInfo.InvariantCulture).Substring(1))
|| ((MyObject)o).Units[1].ToString().ToUpper(CultureInfo.InvariantCulture)
.Contains(item.FilterText.ToUpper(CultureInfo.InvariantCulture).Substring(1))))
{
return true;
}
//If the first char is -
if ((item.FilterText[0] == '-')
&& (!((MyObject)o).Name.ToUpper(CultureInfo.InvariantCulture)
.Contains(item.FilterText.ToUpper(CultureInfo.InvariantCulture).Substring(1))
|| !((MyObject)o).Name.ToUpper(CultureInfo.InvariantCulture)
.Contains(item.FilterText.ToUpper(CultureInfo.InvariantCulture).Substring(1))))
{
return true;
}
}
else
{
if (((MyObject)o).Name.ToUpper(CultureInfo.InvariantCulture)
.Contains(item.FilterText.ToUpper(CultureInfo.InvariantCulture)))
{
return true;
}
}
return false;
};
Is there a better way to do this.
FileInfo f = new FileInfo("C://notebook.txt");`
public bool Archived
{
get
{
return (((File.GetAttributes(f.FullName))
& FileAttributes.Archive) == FileAttributes.Archive);
}
set
{
if (value == true)
{
if (!this.Archived)
{
File.SetAttributes(f.FullName,
File.GetAttributes(f.FullName) | FileAttributes.Archive);
}
}
else if (value == false)
{
if (this.Archived)
{
File.SetAttributes(f.FullName,
File.GetAttributes(f.FullName)
& ~FileAttributes.Archive);
}
}
}
}
`
Yes, as you have a FileInfo object you can use it's Attributes property instead of using the File.GetAttributes and File.SetAttributes methods:
public bool Archived {
get {
return (f.Attributes & FileAttributes.Archive) != 0;
}
set {
if (value) {
if (!this.Archived) {
f.Attributes |= FileAttributes.Archive;
}
} else {
if (this.Archived) {
f.Attributes &= ~FileAttributes.Archive;
}
}
}
}
Well, you can always start by simplifying the way you handle the value in the setter. Then you could avoid a double-get by reading the attributes at the top of the setter.
public bool Archived
{
get
{
return (((File.GetAttributes(f.FullName)) & FileAttributes.Archive) != 0);
}
set
{
var attributes = File.GetAttributes(f.FullName);
bool archived = ((attributes & FileAttributes.Archive) != 0);
if (value)
{
if (!archived)
File.SetAttributes(f.FullName, attributes | FileAttributes.Archive);
}
else
{
if (archived)
File.SetAttributes(f.FullName, attributes & ~FileAttributes.Archive);
}
}
}
Now, Guffa has a point about the attributes being cached by FileInfo, though I see this more as an argument against using FileInfo in the first place. I'd prefer to store just the pathname as a string.
I also changed the bit test to compare to zero, which I should have done in the first place. Thanks, KeithS and Guffa.
And, to keep it all in one place, if we were using C# 4.0, we could say:
bool archived = attributes.HasFlag(FileAttributes.Archive);
No, that's pretty standard when dealing with flagged (bitwise rather) values.
You might wanna lose the else if bit, as booleans generally only have 2 states.
In the getter, if the bitwise AND evaluates to any nonzero, the bit's set, so your getter can be shortened somewhat:
get
{
return (((File.GetAttributes(f.FullName)) & FileAttributes.Archive) != 0);
}
Everything else is pretty much optimal; you can lose some parenthesis and one evaluation by getting rid of the braces around the if and else of the setter, and making the "else if" just an "else". Or, combine the inner and outer expressions; really, the inner expressions are not necessary as 1 | 1 == 1 and 1 & ~1 == 0, so setting it to the same value multiple times won't hurt anything.