private string FinishFixingName(string name) { // Edge case: prefix "as", suffix "sa", name "asa" if (Suffix.Length + Prefix.Length >= name.Length) { return(name); } name = name.Substring(Prefix.Length, name.Length - Suffix.Length - Prefix.Length); IEnumerable <string> words = new[] { name }; if (!string.IsNullOrEmpty(WordSeparator)) { words = name.Split(new[] { WordSeparator }, StringSplitOptions.RemoveEmptyEntries); if (words.Count() == 1) // Only Split if words have not been split before { bool isWord = true; var parts = StringBreaker.GetParts(name, isWord); string[] newWords = new string[parts.Count]; for (int i = 0; i < parts.Count; i++) { newWords[i] = name.Substring(parts[i].Start, parts[i].End - parts[i].Start); } words = newWords; } } words = ApplyCapitalization(words); return(Prefix + string.Join(WordSeparator, words) + Suffix); }
public TextChunk(string text, bool allowFuzzingMatching) { this.Text = text; this.CharacterSpans = StringBreaker.BreakIntoCharacterParts(text); this.SimilarityChecker = allowFuzzingMatching ? WordSimilarityChecker.Allocate(text, substringsAreSimilar: false) : null; }
internal static ImmutableArray <Words> GetBaseNames(ITypeSymbol type, bool pluralize) { var baseName = TryRemoveInterfacePrefix(type); var parts = StringBreaker.GetWordParts(baseName); var result = GetInterleavedPatterns(parts, baseName, pluralize); parts.Free(); return(result); }
internal static ImmutableArray <IEnumerable <string> > GetBaseNames(ITypeSymbol type) { var baseName = TryRemoveInterfacePrefix(type); using (var breaks = StringBreaker.BreakIntoWordParts(baseName)) { return(GetInterleavedPatterns(breaks, baseName)); } }
public static IdentifierNameParts CreateIdentifierNameParts(ISymbol symbol, ImmutableArray <NamingRule> rules) { var baseName = RemovePrefixesAndSuffixes(symbol, rules, symbol.Name); var parts = StringBreaker.GetWordParts(baseName); var words = CreateWords(parts, baseName); return(new IdentifierNameParts(baseName, words)); }
internal static ImmutableArray <Words> GetBaseNames(ITypeSymbol type, bool pluralize) { var baseName = TryRemoveInterfacePrefix(type); using var parts = TemporaryArray <TextSpan> .Empty; StringBreaker.AddWordParts(baseName, ref parts.AsRef()); var result = GetInterleavedPatterns(parts, baseName, pluralize); return(result); }
public static IdentifierNameParts CreateIdentifierNameParts(ISymbol symbol, ImmutableArray <NamingRule> rules) { var baseName = RemovePrefixesAndSuffixes(symbol, rules, symbol.Name); using var parts = TemporaryArray <TextSpan> .Empty; StringBreaker.AddWordParts(baseName, ref parts.AsRef()); var words = CreateWords(parts, baseName); return(new IdentifierNameParts(baseName, words)); }
public TextChunk(string text, bool allowFuzzingMatching) { this.Text = text; this.PatternHumps = StringBreaker.GetCharacterParts(text); this.SimilarityChecker = allowFuzzingMatching ? WordSimilarityChecker.Allocate(text, substringsAreSimilar: false) : null; IsLowercase = !ContainsUpperCaseLetter(text); }
public TextChunk(string text, bool allowFuzzingMatching) { this.Text = text; PatternHumps = TemporaryArray <TextSpan> .Empty; StringBreaker.AddCharacterParts(text, ref PatternHumps); this.SimilarityChecker = allowFuzzingMatching ? WordSimilarityChecker.Allocate(text, substringsAreSimilar: false) : null; IsLowercase = !ContainsUpperCaseLetter(text); }
public void REMCommentsAreIdentified() { Assert.Equal( new IToken[] { new CommentToken(" Test", 0), new UnprocessedContentToken("WScript.Echo 1", 1) }, StringBreaker.SegmentString( "REM Test\nWScript.Echo 1" ), new TokenSetComparer() ); }
public void NonLineReturningWhiteSpaceBetweenCommentsIsIgnored() { Assert.Equal( new IToken[] { new CommentToken(" Comment 1", 0), new CommentToken(" Comment 2", 1) }, StringBreaker.SegmentString( "' Comment 1\n ' Comment 2" ), new TokenSetComparer() ); }
public void EmptyContentEscapedVariableNameIsSetToNumericValue() { Assert.Equal( new IToken[] { new EscapedNameToken("[]", 0), new UnprocessedContentToken(" = 1", 0) }, StringBreaker.SegmentString( "[] = 1" ), new TokenSetComparer() ); }
public void VariableSetToStringContentIncludedQuotedContent() { Assert.Equal( new IToken[] { new UnprocessedContentToken("strValue = ", 0), new StringToken("Test string with \"quoted\" content", 0), new UnprocessedContentToken("\n", 0) }, StringBreaker.SegmentString( "strValue = \"Test string with \"\"quoted\"\" content\"\n" ), new TokenSetComparer() ); }
public static string GetLocalName(this INamedTypeSymbol containingType) { var parts = StringBreaker.BreakIntoWordParts(containingType.Name); for (var i = parts.Count - 1; i >= 0; i--) { var p = parts[i]; if (char.IsLetter(containingType.Name[p.Start])) { return(containingType.Name.Substring(p.Start, p.Length).ToCamelCase()); } } return("v"); }
public void InlineREMCommentsAreIdentified() { Assert.Equal( new IToken[] { new UnprocessedContentToken("WScript.Echo 1", 0), new EndOfStatementSameLineToken(0), new InlineCommentToken(" Test", 0) }, StringBreaker.SegmentString( "WScript.Echo 1 REM Test" ), new TokenSetComparer() ); }
internal static ImmutableArray <Words> GetBaseNames(IAliasSymbol alias) { var name = alias.Name; if (alias.Target.IsType && (((INamedTypeSymbol)alias.Target).IsInterfaceType() && CanRemoveInterfacePrefix(name))) { name = name.Substring(1); } var breaks = StringBreaker.GetWordParts(name); var result = GetInterleavedPatterns(breaks, name, pluralize: false); breaks.Free(); return(result); }
public void WhitespaceBetweenStringTokenAndCommentDoesNotPreventEndOfStatementBeingInserted() { Assert.Equal( new IToken[] { new UnprocessedContentToken("a = ", 0), new StringToken("", 0), new EndOfStatementSameLineToken(0), new CommentToken(" Comment", 0) }, StringBreaker.SegmentString( "a = \"\" ' Comment" ), new TokenSetComparer() ); }
internal static ImmutableArray <Words> GetBaseNames(IAliasSymbol alias) { var name = alias.Name; if (alias.Target.IsType && ((INamedTypeSymbol)alias.Target).IsInterfaceType() && CanRemoveInterfacePrefix(name)) { name = name.Substring(1); } using var breaks = TemporaryArray <TextSpan> .Empty; StringBreaker.AddWordParts(name, ref breaks.AsRef()); var result = GetInterleavedPatterns(breaks, name, pluralize: false); return(result); }
public void InlineCommentsAreIdentifiedAsSuchWhenAfterMultipleLinesOfContent() { // The StringBreaker will insert an EndOfStatementSameLineToken between the UnprocessedContentToken and InlineCommentToken // since that the later processes rely on end-of-statement tokens, even before an inline comment Assert.Equal( new IToken[] { new UnprocessedContentToken("\nWScript.Echo 1", 0), new EndOfStatementSameLineToken(0), new InlineCommentToken(" Test", 1) }, StringBreaker.SegmentString( "\nWScript.Echo 1 ' Test" ), new TokenSetComparer() ); }
private static IEnumerable <IToken> GetTokens(string scriptContent) { // Break down content into String, Comment and UnprocessedContent tokens var tokens = StringBreaker.SegmentString(scriptContent); // Break down further into String, Comment, Atom and AbstractEndOfStatement tokens var atomTokens = new List <IToken>(); foreach (var token in tokens) { if (token is UnprocessedContentToken) { atomTokens.AddRange(TokenBreaker.BreakUnprocessedToken((UnprocessedContentToken)token)); } else { atomTokens.Add(token); } } return(NumberRebuilder.Rebuild(OperatorCombiner.Combine(atomTokens)).ToList()); }
private PatternMatch?NonFuzzyMatchPatternChunk( string candidate, TextChunk patternChunk, bool punctuationStripped) { var candidateLength = candidate.Length; var caseInsensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.IgnoreCase); if (caseInsensitiveIndex == 0) { // We found the pattern at the start of the candidate. This is either an exact or // prefix match. if (patternChunk.Text.Length == candidateLength) { // Lengths were the same, this is either a case insensitive or sensitive exact match. return(new PatternMatch( PatternMatchKind.Exact, punctuationStripped, isCaseSensitive: candidate == patternChunk.Text, matchedSpan: GetMatchedSpan(0, candidateLength))); } else { // Lengths were the same, this is either a case insensitive or sensitive prefix match. return(new PatternMatch( PatternMatchKind.Prefix, punctuationStripped, isCaseSensitive: _compareInfo.IsPrefix(candidate, patternChunk.Text), matchedSpan: GetMatchedSpan(0, patternChunk.Text.Length))); } } ArrayBuilder <TextSpan> candidateHumpsOpt = null; try { var patternIsLowercase = patternChunk.IsLowercase; if (caseInsensitiveIndex > 0) { // We found the pattern somewhere in the candidate. This could be a substring match. // However, we don't want to be overaggressive in returning just any substring results. // So do a few more checks to make sure this is a good result. if (!patternIsLowercase) { // Pattern contained uppercase letters. This is a strong indication from the // user that they expect the same letters to be uppercase in the result. As // such, only return this if we can find this pattern exactly in the candidate. var caseSensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.None); if (caseSensitiveIndex > 0) { return(new PatternMatch( PatternMatchKind.Substring, punctuationStripped, isCaseSensitive: true, matchedSpan: GetMatchedSpan(caseSensitiveIndex, patternChunk.Text.Length))); } } else { // Pattern was all lowercase. This can lead to lots of false positives. For // example, we don't want "bin" to match "CombineUnits". Instead, we want it // to match "BinaryOperator". As such, make sure our match looks like it's // starting an actual word in the candidate. // Do a quick check to avoid the expensive work of having to go get the candidate // humps. if (char.IsUpper(candidate[caseInsensitiveIndex])) { return(new PatternMatch(PatternMatchKind.Substring, punctuationStripped, isCaseSensitive: false, matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length))); } candidateHumpsOpt = StringBreaker.GetWordParts(candidate); for (int i = 0, n = candidateHumpsOpt.Count; i < n; i++) { var hump = TextSpan.FromBounds(candidateHumpsOpt[i].Start, candidateLength); if (PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.IgnoreCase)) { return(new PatternMatch(PatternMatchKind.Substring, punctuationStripped, isCaseSensitive: PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.None), matchedSpan: GetMatchedSpan(hump.Start, patternChunk.Text.Length))); } } } } // Didn't have an exact/prefix match, or a high enough quality substring match. // See if we can find a camel case match. if (candidateHumpsOpt == null) { candidateHumpsOpt = StringBreaker.GetWordParts(candidate); } // Didn't have an exact/prefix match, or a high enough quality substring match. // See if we can find a camel case match. return(TryCamelCaseMatch( candidate, patternChunk, punctuationStripped, patternIsLowercase, candidateHumpsOpt)); } finally { candidateHumpsOpt?.Free(); } }
/// <summary> /// Get the individual words in the parameter name. This way we can generate /// appropriate field/property names based on the user's preference. /// </summary> private List <string> GetParameterWordParts(IParameterSymbol parameter) => CreateWords(StringBreaker.BreakIntoWordParts(parameter.Name), parameter.Name);
private PatternMatch?NonFuzzyMatchPatternChunk( string candidate, TextChunk patternChunk, bool punctuationStripped) { var candidateLength = candidate.Length; var caseInsensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.IgnoreCase); if (caseInsensitiveIndex == 0) { // We found the pattern at the start of the candidate. This is either an exact or // prefix match. if (patternChunk.Text.Length == candidateLength) { // Lengths were the same, this is either a case insensitive or sensitive exact match. return(new PatternMatch( PatternMatchKind.Exact, punctuationStripped, isCaseSensitive: candidate == patternChunk.Text, matchedSpan: GetMatchedSpan(0, candidateLength))); } else { // Lengths were the same, this is either a case insensitive or sensitive prefix match. return(new PatternMatch( PatternMatchKind.Prefix, punctuationStripped, isCaseSensitive: _compareInfo.IsPrefix(candidate, patternChunk.Text), matchedSpan: GetMatchedSpan(0, patternChunk.Text.Length))); } } ArrayBuilder <TextSpan> candidateHumpsOpt = null; try { var patternIsLowercase = patternChunk.IsLowercase; if (caseInsensitiveIndex > 0) { // We found the pattern somewhere in the candidate. This could be a substring match. // However, we don't want to be overaggressive in returning just any substring results. // So do a few more checks to make sure this is a good result. if (!patternIsLowercase) { // Pattern contained uppercase letters. This is a strong indication from the // user that they expect the same letters to be uppercase in the result. As // such, only return this if we can find this pattern exactly in the candidate. var caseSensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.None); if (caseSensitiveIndex > 0) { if (char.IsUpper(candidate[caseInsensitiveIndex])) { return(new PatternMatch( PatternMatchKind.StartOfWordSubstring, punctuationStripped, isCaseSensitive: true, matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length))); } else { return(new PatternMatch( PatternMatchKind.NonLowercaseSubstring, punctuationStripped, isCaseSensitive: true, matchedSpan: GetMatchedSpan(caseSensitiveIndex, patternChunk.Text.Length))); } } } else { // Pattern was all lowercase. This can lead to lots of hits. For example, "bin" in // "CombineUnits". Instead, we want it to match "Operator[|Bin|]ary" first rather than // Com[|bin|]eUnits // If the lowercase search string matched what looks to be the start of a word then that's a // reasonable hit. This is equivalent to 'bin' matching 'Operator[|Bin|]ary' if (char.IsUpper(candidate[caseInsensitiveIndex])) { return(new PatternMatch(PatternMatchKind.StartOfWordSubstring, punctuationStripped, isCaseSensitive: false, matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length))); } // Now do the more expensive check to see if we're at the start of a word. This is to catch // word matches like CombineBinary. We want to find the hit against '[|Bin|]ary' not // 'Com[|bin|]e' candidateHumpsOpt = StringBreaker.GetWordParts(candidate); for (int i = 0, n = candidateHumpsOpt.Count; i < n; i++) { var hump = TextSpan.FromBounds(candidateHumpsOpt[i].Start, candidateLength); if (PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.IgnoreCase)) { return(new PatternMatch(PatternMatchKind.StartOfWordSubstring, punctuationStripped, isCaseSensitive: PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.None), matchedSpan: GetMatchedSpan(hump.Start, patternChunk.Text.Length))); } } } } // Didn't have an exact/prefix match, or a high enough quality substring match. // See if we can find a camel case match. if (candidateHumpsOpt == null) { candidateHumpsOpt = StringBreaker.GetWordParts(candidate); } // Didn't have an exact/prefix match, or a high enough quality substring match. // See if we can find a camel case match. var match = TryCamelCaseMatch(candidate, patternChunk, punctuationStripped, patternIsLowercase, candidateHumpsOpt); if (match != null) { return(match); } // If pattern was all lowercase, we allow it to match an all lowercase section of the candidate. But // only after we've tried all other forms first. This is the weakest of all matches. For example, if // user types 'bin' we want to match 'OperatorBinary' (start of word) or 'BinaryInformationNode' (camel // humps) before matching 'Combine'. // // We only do this for strings longer than three characters to avoid too many false positives when the // user has only barely started writing a word. if (patternIsLowercase && caseInsensitiveIndex > 0 && patternChunk.Text.Length >= 3) { var caseSensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.None); if (caseSensitiveIndex > 0) { return(new PatternMatch( PatternMatchKind.LowercaseSubstring, punctuationStripped, isCaseSensitive: true, matchedSpan: GetMatchedSpan(caseSensitiveIndex, patternChunk.Text.Length))); } } return(null); } finally { candidateHumpsOpt?.Free(); } }
private static IList <string> BreakIntoCharacterParts(string identifier) => PartListToSubstrings(identifier, StringBreaker.BreakIntoCharacterParts(identifier));
private static IList <string> BreakIntoWordParts(string identifier) { return(PartListToSubstrings(identifier, StringBreaker.BreakIntoWordParts(identifier))); }
private static IList <SyntaxNode> CreateEqualsMethodStatements( ISyntaxFactoryService factory, Compilation compilation, INamedTypeSymbol containingType, IEnumerable <ISymbol> members, CancellationToken cancellationToken) { var statements = new List <SyntaxNode>(); var parts = StringBreaker.BreakIntoWordParts(containingType.Name); string localName = "v"; for (int i = parts.Count - 1; i >= 0; i--) { var p = parts[i]; if (char.IsLetter(containingType.Name[p.Start])) { localName = containingType.Name.Substring(p.Start, p.Length).ToCamelCase(); break; } } var localNameExpression = factory.CreateIdentifierName(localName); var objNameExpression = factory.CreateIdentifierName(ObjName); var expressions = new List <SyntaxNode>(); if (containingType.IsValueType) { #if false if (!(obj is MyType)) { return(false); } #endif var ifStatement = factory.CreateIfStatement( factory.CreateLogicalNotExpression( factory.CreateIsExpression( objNameExpression, containingType)), new[] { factory.CreateReturnStatement(factory.CreateFalseExpression()) }); #if false var myType = (MyType)obj; #endif var localDeclaration = factory.CreateLocalDeclarationStatement( factory.CreateVariableDeclarator(localName, factory.CreateCastExpression(containingType, objNameExpression))); statements.Add(ifStatement); statements.Add(localDeclaration); } else { #if false var myType = obj as MyType; #endif var localDeclaration = factory.CreateLocalDeclarationStatement( factory.CreateVariableDeclarator(localName, factory.CreateAsExpression(objNameExpression, containingType))); statements.Add(localDeclaration); #if false myType != null #endif expressions.Add(factory.CreateReferenceNotEqualsExpression(localNameExpression, factory.CreateNullExpression())); if (HasExistingBaseEqualsMethod(containingType, cancellationToken)) { #if false base.Equals(obj) #endif expressions.Add(factory.CreateInvocationExpression( factory.CreateMemberAccessExpression( factory.CreateBaseExpression(), factory.CreateIdentifierName(EqualsName)), objNameExpression)); } } foreach (var member in members) { var symbolNameExpression = factory.CreateIdentifierName(member.Name); var thisSymbol = factory.CreateMemberAccessExpression(factory.CreateThisExpression(), symbolNameExpression).WithAdditionalAnnotations(Simplification.Simplifier.Annotation); var otherSymbol = factory.CreateMemberAccessExpression(localNameExpression, symbolNameExpression); #if false EqualityComparer <SType> .Default.Equals(this.S1, myType.S1) #endif var expression = factory.CreateInvocationExpression( factory.CreateMemberAccessExpression( GetDefaultEqualityComparer(factory, compilation, member), factory.CreateIdentifierName(EqualsName)), thisSymbol, otherSymbol); expressions.Add(expression); } #if false return(myType != null && base.Equals(obj) && EqualityComparer <int> .Default.Equals(this.S1, myType.S1) &&...); #endif statements.Add(factory.CreateReturnStatement( expressions.Aggregate(factory.CreateLogicalAndExpression))); return(statements); }
private static ImmutableArray <string> BreakIntoWordParts(string identifier) => PartListToSubstrings(identifier, StringBreaker.GetWordParts(identifier));
private static ImmutableArray <SyntaxNode> CreateEqualsMethodStatements( SyntaxGenerator factory, Compilation compilation, INamedTypeSymbol containingType, IEnumerable <ISymbol> members, CancellationToken cancellationToken) { var iequatableType = compilation.GetTypeByMetadataName("System.IEquatable`1"); var statements = ArrayBuilder <SyntaxNode> .GetInstance(); // Come up with a good name for the local variable we're going to compare against. // For example, if the class name is "CustomerOrder" then we'll generate: // // var order = obj as CustomerOrder; var parts = StringBreaker.BreakIntoWordParts(containingType.Name); var localName = "v"; for (var i = parts.Count - 1; i >= 0; i--) { var p = parts[i]; if (char.IsLetter(containingType.Name[p.Start])) { localName = containingType.Name.Substring(p.Start, p.Length).ToCamelCase(); break; } } var localNameExpression = factory.IdentifierName(localName); var objNameExpression = factory.IdentifierName(ObjName); // These will be all the expressions that we'll '&&' together inside the final // return statement of 'Equals'. var expressions = new List <SyntaxNode>(); if (containingType.IsValueType) { // If we're a value type, then we need an is-check first to make sure // the object is our type: // // if (!(obj is MyType)) // { // return false; // } var ifStatement = factory.IfStatement( factory.LogicalNotExpression( factory.IsTypeExpression( objNameExpression, containingType)), new[] { factory.ReturnStatement(factory.FalseLiteralExpression()) }); // Next, we cast the argument to our type: // // var myType = (MyType)obj; var localDeclaration = factory.LocalDeclarationStatement(localName, factory.CastExpression(containingType, objNameExpression)); statements.Add(ifStatement); statements.Add(localDeclaration); } else { // It's not a value type, we can just use "as" to test the parameter is the right type: // // var myType = obj as MyType; var localDeclaration = factory.LocalDeclarationStatement(localName, factory.TryCastExpression(objNameExpression, containingType)); statements.Add(localDeclaration); // Ensure that the parameter we got was not null (which also ensures the 'as' test // succeeded): // // myType != null expressions.Add(factory.ReferenceNotEqualsExpression(localNameExpression, factory.NullLiteralExpression())); if (HasExistingBaseEqualsMethod(containingType, cancellationToken)) { // If we're overriding something that also provided an overridden 'Equals', // then ensure the base type thinks it is equals as well. // // base.Equals(obj) expressions.Add(factory.InvocationExpression( factory.MemberAccessExpression( factory.BaseExpression(), factory.IdentifierName(EqualsName)), objNameExpression)); } } // Now, iterate over all the supplied members and ensure that our instance // and the parameter think they are equals. Specialize how we do this for // common types. Fall-back to EqualityComparer<SType>.Default.Equals for // everything else. foreach (var member in members) { var symbolNameExpression = factory.IdentifierName(member.Name); var thisSymbol = factory.MemberAccessExpression(factory.ThisExpression(), symbolNameExpression) .WithAdditionalAnnotations(Simplification.Simplifier.Annotation); var otherSymbol = factory.MemberAccessExpression(localNameExpression, symbolNameExpression); var memberType = member.GetSymbolType(); if (IsPrimitiveValueType(memberType)) { // If we have one of the well known primitive types, then just use '==' to compare // the values. // // this.a == other.a expressions.Add(factory.ValueEqualsExpression(thisSymbol, otherSymbol)); continue; } var valueIEquatable = memberType?.IsValueType == true && ImplementsIEquatable(memberType, iequatableType); if (valueIEquatable || memberType?.IsTupleType == true) { // If it's a value type and implements IEquatable<T>, Or if it's a tuple, then // just call directly into .Equals. This keeps the code simple and avoids an // unnecessary null check. // // this.a.Equals(other.a) expressions.Add(factory.InvocationExpression( factory.MemberAccessExpression(thisSymbol, nameof(object.Equals)), otherSymbol)); continue; } // Otherwise call EqualityComparer<SType>.Default.Equals(this.a, other.a). // This will do the appropriate null checks as well as calling directly // into IEquatable<T>.Equals implementations if available. expressions.Add(factory.InvocationExpression( factory.MemberAccessExpression( GetDefaultEqualityComparer(factory, compilation, member), factory.IdentifierName(EqualsName)), thisSymbol, otherSymbol)); } // Now combine all the comparison expressions together into one final statement like: // // return myType != null && // base.Equals(obj) && // this.S1 == myType.S1; statements.Add(factory.ReturnStatement( expressions.Aggregate(factory.LogicalAndExpression))); return(statements.ToImmutableAndFree()); }