public override SyntaxNode VisitSimpleLambdaExpression(SimpleLambdaExpressionSyntax node) { var newNode = base.VisitSimpleLambdaExpression(node); if (newNode is SimpleLambdaExpressionSyntax && _expandParameter) { var newSimpleLambda = (SimpleLambdaExpressionSyntax)newNode; var parameterSymbol = _semanticModel.GetDeclaredSymbol(node.Parameter); if (parameterSymbol != null && parameterSymbol.Kind == SymbolKind.Parameter) { if (parameterSymbol.Type != null) { var typeSyntax = parameterSymbol.Type.GenerateTypeSyntax().WithTrailingTrivia(s_oneWhitespaceSeparator); var newSimpleLambdaParameter = newSimpleLambda.Parameter.WithType(typeSyntax).WithoutTrailingTrivia(); var parenthesizedLambda = SyntaxFactory.ParenthesizedLambdaExpression( newSimpleLambda.AsyncKeyword, SyntaxFactory.ParameterList(SyntaxFactory.SingletonSeparatedList(newSimpleLambdaParameter)) .WithTrailingTrivia(newSimpleLambda.Parameter.GetTrailingTrivia()) .WithLeadingTrivia(newSimpleLambda.Parameter.GetLeadingTrivia()), newSimpleLambda.ArrowToken, newSimpleLambda.Body).WithAdditionalAnnotations(Simplifier.Annotation); return(SimplificationHelpers.CopyAnnotations(newNode, parenthesizedLambda)); } } } return(newNode); }
private static SyntaxNode SimplifyParenthesizedLambdaExpression( SyntaxNode node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) { if (node != null && node is ParenthesizedLambdaExpressionSyntax) { var parenthesizedLambda = (ParenthesizedLambdaExpressionSyntax)node; if (parenthesizedLambda.ParameterList != null && parenthesizedLambda.ParameterList.Parameters.Count == 1) { var parameter = parenthesizedLambda.ParameterList.Parameters.First(); if (CanRemoveTypeFromParameter(parameter, semanticModel, cancellationToken)) { var newParameterSyntax = parameter.WithType(null); var newSimpleLambda = SyntaxFactory.SimpleLambdaExpression( parenthesizedLambda.AsyncKeyword, newParameterSyntax.WithTrailingTrivia(parenthesizedLambda.ParameterList.GetTrailingTrivia()), parenthesizedLambda.ArrowToken, parenthesizedLambda.Body); return(SimplificationHelpers.CopyAnnotations(parenthesizedLambda, newSimpleLambda).WithoutAnnotations(Simplifier.Annotation)); } } } return(node); }
private static ExpressionSyntax SimplifyCast(CastExpressionSyntax node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) { if (!node.IsUnnecessaryCast(semanticModel, cancellationToken)) { return(node); } var leadingTrivia = node.OpenParenToken.LeadingTrivia .Concat(node.OpenParenToken.TrailingTrivia) .Concat(node.Type.GetLeadingTrivia()) .Concat(node.Type.GetTrailingTrivia()) .Concat(node.CloseParenToken.LeadingTrivia) .Concat(node.CloseParenToken.TrailingTrivia) .Concat(node.Expression.GetLeadingTrivia()) .Where(t => !t.IsElastic()); var trailingTrivia = node.GetTrailingTrivia().Where(t => !t.IsElastic()); var resultNode = node.Expression .WithLeadingTrivia(leadingTrivia) .WithTrailingTrivia(trailingTrivia); resultNode = SimplificationHelpers.CopyAnnotations(from: node, to: resultNode); return(resultNode); }
private static SyntaxNode SimplifyParameter( SyntaxNode node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) { if (CanRemoveTypeFromParameter(node, semanticModel, cancellationToken)) { var newParameterSyntax = ((ParameterSyntax)node).WithType(null); newParameterSyntax = SimplificationHelpers.CopyAnnotations(node, newParameterSyntax).WithoutAnnotations(Simplifier.Annotation); return(newParameterSyntax); } return(node); }
private static SyntaxNode SimplifyParentheses( ParenthesizedPatternSyntax node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) { if (node.CanRemoveParentheses(semanticModel)) { var resultNode = CSharpSyntaxFacts.Instance.Unparenthesize(node); return(SimplificationHelpers.CopyAnnotations(from: node, to: resultNode)); } // We don't know how to simplify this. return(node); }
public static bool TryReduceOrSimplifyExplicitName( this QualifiedCrefSyntax crefSyntax, SemanticModel semanticModel, out CrefSyntax replacementNode, out TextSpan issueSpan, OptionSet optionSet, CancellationToken cancellationToken) { replacementNode = null; issueSpan = default; var memberCref = crefSyntax.Member; // Currently we are dealing with only the NameMemberCrefs if (SimplificationHelpers.PreferPredefinedTypeKeywordInMemberAccess(optionSet, semanticModel.Language) && memberCref.IsKind(SyntaxKind.NameMemberCref, out NameMemberCrefSyntax nameMemberCref)) { var symbolInfo = semanticModel.GetSymbolInfo(nameMemberCref.Name, cancellationToken); var symbol = symbolInfo.Symbol; if (symbol == null) { return(false); } // 1. Check for Predefined Types if (symbol is INamedTypeSymbol namedSymbol) { var keywordKind = ExpressionSyntaxExtensions.GetPredefinedKeywordKind(namedSymbol.SpecialType); if (keywordKind != SyntaxKind.None) { replacementNode = CreateReplacement(crefSyntax, keywordKind); replacementNode = crefSyntax.CopyAnnotationsTo(replacementNode); // we want to show the whole name expression as unnecessary issueSpan = crefSyntax.Span; return(true); } } } return(TryReduceOrSimplifyQualifiedCref( crefSyntax, semanticModel, memberCref, out replacementNode, out issueSpan, cancellationToken)); }
public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax originalNode) { var rewrittenNode = (InvocationExpressionSyntax)base.VisitInvocationExpression(originalNode); if (originalNode.Expression.Kind() == SyntaxKind.SimpleMemberAccessExpression) { var memberAccess = (MemberAccessExpressionSyntax)originalNode.Expression; var targetSymbol = SimplificationHelpers.GetOriginalSymbolInfo(_semanticModel, memberAccess.Name); if (targetSymbol != null && targetSymbol.IsReducedExtension()) { rewrittenNode = RewriteExtensionMethodInvocation(originalNode, rewrittenNode, ((MemberAccessExpressionSyntax)rewrittenNode.Expression).Expression, (IMethodSymbol)targetSymbol); } } return(rewrittenNode); }
private static SyntaxNode SimplifyParentheses( ParenthesizedExpressionSyntax node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) { if (node.CanRemoveParentheses(semanticModel)) { // TODO(DustinCa): We should not be skipping elastic trivia below. // However, the formatter seems to mess up trailing trivia in some // cases if elastic trivia is there -- and it's not clear why. // Specifically remove the elastic trivia formatting rule doesn't // have any effect. var resultNode = CSharpSyntaxFactsService.Instance.Unparenthesize(node); return(SimplificationHelpers.CopyAnnotations(from: node, to: resultNode)); } // We don't know how to simplify this. return(node); }
public static ExpressionSyntax Uncast(this CastExpressionSyntax node) { var leadingTrivia = node.OpenParenToken.LeadingTrivia .Concat(node.OpenParenToken.TrailingTrivia) .Concat(node.Type.GetLeadingTrivia()) .Concat(node.Type.GetTrailingTrivia()) .Concat(node.CloseParenToken.LeadingTrivia) .Concat(node.CloseParenToken.TrailingTrivia) .Concat(node.Expression.GetLeadingTrivia()) .Where(t => !t.IsElastic()); var trailingTrivia = node.GetTrailingTrivia().Where(t => !t.IsElastic()); var resultNode = node.Expression .WithLeadingTrivia(leadingTrivia) .WithTrailingTrivia(trailingTrivia) .WithAdditionalAnnotations(Simplifier.Annotation); resultNode = SimplificationHelpers.CopyAnnotations(from: node, to: resultNode); return resultNode; }
private static bool IsThisOrTypeOrNamespace(MemberAccessExpressionSyntax memberAccess, SemanticModel semanticModel) { if (memberAccess.Expression.Kind() == SyntaxKind.ThisExpression) { var previousToken = memberAccess.Expression.GetFirstToken().GetPreviousToken(); var symbol = semanticModel.GetSymbolInfo(memberAccess.Name).Symbol; if (previousToken.Kind() == SyntaxKind.OpenParenToken && previousToken.Parent.IsKind(SyntaxKind.ParenthesizedExpression, out ParenthesizedExpressionSyntax parenExpr) && !parenExpr.IsParentKind(SyntaxKind.ParenthesizedExpression) && parenExpr.Expression.Kind() == SyntaxKind.SimpleMemberAccessExpression && symbol != null && symbol.Kind == SymbolKind.Method) { return(false); } return(true); } var expressionInfo = semanticModel.GetSymbolInfo(memberAccess.Expression); if (SimplificationHelpers.IsValidSymbolInfo(expressionInfo.Symbol)) { if (expressionInfo.Symbol is INamespaceOrTypeSymbol) { return(true); } if (expressionInfo.Symbol.IsThisParameter()) { return(true); } } return(false); }
private static SyntaxNode SimplifyParentheses( ParenthesizedExpressionSyntax node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) { if (node.CanRemoveParentheses(semanticModel)) { // TODO(DustinCa): We should not be skipping elastic trivia below. // However, the formatter seems to mess up trailing trivia in some // cases if elastic trivia is there -- and it's not clear why. // Specifically remove the elastic trivia formatting rule doesn't // have any effect. var leadingTrivia = node.OpenParenToken.LeadingTrivia .Concat(node.OpenParenToken.TrailingTrivia) .Where(t => !t.IsElastic()) .Concat(node.Expression.GetLeadingTrivia()); var trailingTrivia = node.Expression.GetTrailingTrivia() .Concat(node.CloseParenToken.LeadingTrivia) .Where(t => !t.IsElastic()) .Concat(node.CloseParenToken.TrailingTrivia); var resultNode = node.Expression .WithLeadingTrivia(leadingTrivia) .WithTrailingTrivia(trailingTrivia); resultNode = SimplificationHelpers.CopyAnnotations(from: node, to: resultNode); return(resultNode); } // We don't know how to simplify this. return(node); }
static bool GenerateMeshData(IvyGraph ivyGraph, IvyProfile ivyProfile, bool forceGeneration = false) { var p = ivyProfile; //branches foreach (var root in ivyGraph.roots) { var cache = IvyRoot.GetMeshCacheFor(root); if (root.useCachedBranchData && !forceGeneration) { combinedTriangleIndices.Clear(); cache.triangles.ForEach(localIndex => combinedTriangleIndices.Add(localIndex + verticesAll.Count)); trianglesAll.AddRange(combinedTriangleIndices); verticesAll.AddRange(cache.vertices); texCoordsAll.AddRange(cache.texCoords); continue; } root.useCachedBranchData = true; //process only roots with more than one node if (root.nodes.Count < 2) { continue; } cache.vertices.Clear(); cache.texCoords.Clear(); cache.triangles.Clear(); //branch diameter depends on number of parents AND branch taper float local_ivyBranchDiameter = 1.0f / Mathf.Lerp(1f, 1f + root.parents, ivyProfile.branchTaper); // smooth the line... which increases points a lot allPoints = root.nodes.Select(node => node.p).ToList(); var useThesePoints = allPoints; if (ivyProfile.branchSmooth > 1) { SmoothLineCatmullRomNonAlloc(allPoints, smoothPoints, ivyProfile.branchSmooth); useThesePoints = smoothPoints; } // generate simplified points for each root, to make it less wavy AND save tris if (!root.isAlive && ivyProfile.branchOptimize > 0f) { newPoints.Clear(); newPoints.AddRange(SimplificationHelpers.Simplify <Vector3>( useThesePoints, (vec1, vec2) => vec1 == vec2, (vec) => vec.x, (vec) => vec.y, (vec) => vec.z, ivyProfile.branchOptimize * ivyProfile.ivyStepDistance * 0.5f, false )); useThesePoints = newPoints; } // I'm not sure why there's this bug when we use Catmull Rom + line simplify, but let's do this hacky fix // if ( ivyProfile.branchSmooth > 1 && ivyProfile.branchOptimize > 0f ) { // useThesePoints.ForEach( delegate(Vector3 point) { // if ( float.IsInfinity(point.x) ) {point.x = 0f;} // if ( float.IsInfinity(point.y) ) {point.y = 0f;} // if ( float.IsInfinity(point.z) ) {point.z = 0f;} // } ); // } for (int n = 0; n < useThesePoints.Count; n++) { if (verticesAll.Count >= 65531) { Debug.LogWarning("Hedera: ending branch generation early, reached ~65536 vertex limit on mesh " + ivyGraph.seedPos + "... but this could technically be solved in Unity 2017.3+ or later with 32-bit index formats for meshes? The exercise is left to the reader."); break; } cache.meshSegments = n + 1; //weight depending on ratio of node length to total length float taper = 1f * n / useThesePoints.Count; taper = Mathf.Lerp(1f, (1f - taper) * taper, ivyProfile.branchTaper); //create trihedral vertices... TODO: let user specify how many sides? Vector3 up = Vector3.down; Vector3 basis = Vector3.Normalize(n < useThesePoints.Count - 1 ? useThesePoints[n + 1] - useThesePoints[n] : -(useThesePoints[n] - useThesePoints[n - 1])); // Debug.DrawLine( newPoints[node+1] + ivyGraph.seedPos, newPoints[node] + ivyGraph.seedPos, Color.cyan, 5f, false); int edges = 3; // TODO: finish this, make it configurable float texV = (n % 2 == 0 ? 1f : 0.0f); // vertical UV tiling for (int b = 0; b < edges; b++) { // generate vertices if (b == 0) { branchVertBasis[b] = Vector3.Cross(up, basis).normalized *Mathf.Max(0.001f, local_ivyBranchDiameter * p.ivyBranchSize * taper) + useThesePoints[n]; } else { branchVertBasis[b] = RotateAroundAxis(branchVertBasis[0], useThesePoints[n], basis, 6.283f * b / edges); } cache.vertices.Add(branchVertBasis[b]); // generate UVs cache.texCoords.Add(new Vector2(1f * b / (edges - 1), texV)); // add triangles // AddTriangle(root, 4, 1, 5); // AddTriangle(root, 5, 1, 2); // TODO: finish this } if (n == 0) // start cap { if (taper > 0f) { AddTriangle(cache, 1, 2, 3); } continue; } AddTriangle(cache, 4, 1, 5); AddTriangle(cache, 5, 1, 2); AddTriangle(cache, 5, 2, 6); AddTriangle(cache, 6, 2, 3); AddTriangle(cache, 6, 3, 1); AddTriangle(cache, 6, 1, 4); if (n == useThesePoints.Count - 1 && taper > 0f) // end cap { AddTriangle(cache, 3, 2, 1); } } combinedTriangleIndices.Clear(); cache.triangles.ForEach(localIndex => combinedTriangleIndices.Add(localIndex + verticesAll.Count)); trianglesAll.AddRange(combinedTriangleIndices); verticesAll.AddRange(cache.vertices); texCoordsAll.AddRange(cache.texCoords); } if (ivyProfile.ivyLeafSize <= 0.001f || ivyProfile.leafProbability <= 0.001f) { return(true); } //create leafs allLeafPoints.Clear(); foreach (var root in ivyGraph.roots) { // don't bother on small roots if (root.nodes.Count <= 2) { root.useCachedLeafData = false; continue; } var cache = IvyRoot.GetMeshCacheFor(root); // use cached mesh data for leaves only if (a) we're supposed to, and (b) if not using vertex colors OR vertex colors seem valid if (root.useCachedLeafData && !forceGeneration && (!ivyProfile.useVertexColors || cache.leafVertices.Count == cache.leafVertexColors.Count)) { combinedTriangleIndices.Clear(); cache.leafTriangles.ForEach(index => combinedTriangleIndices.Add(index + leafVerticesAll.Count)); leafTrianglesAll.AddRange(combinedTriangleIndices); allLeafPoints.AddRange(cache.leafPoints); leafVerticesAll.AddRange(cache.leafVertices); leafUVsAll.AddRange(cache.leafUVs); if (ivyProfile.useVertexColors) { leafColorsAll.AddRange(cache.leafVertexColors); } continue; } root.useCachedLeafData = true; cache.leafPoints.Clear(); cache.leafVertices.Clear(); cache.leafUVs.Clear(); cache.leafTriangles.Clear(); cache.leafVertexColors.Clear(); // simple multiplier, just to make it a more dense for (int i = 0; i < 1; ++i) { var leafPositions = GetAllSamplePosAlongRoot(root, p.ivyLeafSize); // for(int n=0; n<root.nodes.Count; n++) foreach (var kvp in leafPositions) { if (leafVerticesAll.Count >= 65530) { Debug.LogWarning("Hedera: ending leaf generation early, reached ~65536 vertex limit on mesh " + ivyGraph.seedPos + "... but this could technically be solved in Unity 2017.3+ or later with 32-bit index formats for meshes? The exercise is left to the reader."); break; } int n = kvp.Value; Vector3 newLeafPos = kvp.Key; var node = root.nodes[n]; // // do not generate a leaf on the first few nodes // if ( n <= 1 ) { // || n >= root.nodes.Count // continue; // } // probability of leaves on the ground is increased float groundedness = Vector3.Dot(Vector3.down, node.c.normalized); if (groundedness < -0.02f) { groundedness -= 0.1f; groundedness *= 3f; } else { groundedness = (groundedness - 0.25f) * 0.5f; } groundedness *= ivyProfile.leafSunlightBonus * p.leafProbability; // don't spawn a leaf on top of another leaf bool badLeafPos = false; float leafSqrSize = p.ivyLeafSize * p.ivyLeafSize * Mathf.Clamp(1f - p.leafProbability - groundedness, 0.01f, 2f); for (int f = 0; f < allLeafPoints.Count; f++) { if (Vector3.SqrMagnitude(allLeafPoints[f] - newLeafPos) < leafSqrSize) { badLeafPos = true; break; } } if (badLeafPos) { continue; } IvyNode previousNode = root.nodes[Mathf.Max(0, n - 1)]; float randomSpreadHack = 0.25f; if (n <= 1 || n == root.nodes.Count - 1) { randomSpreadHack = 0f; } // randomize leaf probability // guarantee a leaf on the first or last node if ((Random.value + groundedness > 1f - p.leafProbability) || randomSpreadHack == 0f) { cache.leafPoints.Add(node.p); allLeafPoints.Add(node.p); //center of leaf quad Vector3 up = (newLeafPos - previousNode.p).normalized; Vector3 right = Vector3.Cross(up, node.c); Vector3 center = newLeafPos - node.c.normalized * 0.05f + (up * Random.Range(-1f, 1f) + right * Random.Range(-1f, 1f)) * randomSpreadHack * p.ivyLeafSize; //size of leaf float sizeWeight = 1.5f - (Mathf.Abs(Mathf.Cos(2.0f * Mathf.PI)) * 0.5f + 0.5f); float leafSize = p.ivyLeafSize * sizeWeight + Random.Range(-p.ivyLeafSize, p.ivyLeafSize) * 0.1f + (p.ivyLeafSize * groundedness); leafSize = Mathf.Max(0.01f, leafSize); Quaternion facing = node.c.sqrMagnitude < 0.001f ? Quaternion.identity : Quaternion.LookRotation(Vector3.Lerp(-node.c, Vector3.up, Mathf.Clamp01(0.68f - Mathf.Abs(groundedness)) * ivyProfile.leafSunlightBonus), Random.onUnitSphere); AddLeafVertex(cache, center, new Vector3(-1f, 1f, 0f), leafSize, facing); AddLeafVertex(cache, center, new Vector3(1f, 1f, 0f), leafSize, facing); AddLeafVertex(cache, center, new Vector3(-1f, -1f, 0f), leafSize, facing); AddLeafVertex(cache, center, new Vector3(1f, -1f, 0f), leafSize, facing); cache.leafUVs.Add(new Vector2(1.0f, 1.0f)); cache.leafUVs.Add(new Vector2(0.0f, 1.0f)); cache.leafUVs.Add(new Vector2(1.0f, 0.0f)); cache.leafUVs.Add(new Vector2(0.0f, 0.0f)); if (ivyProfile.useVertexColors) { var randomColor = ivyProfile.leafVertexColors.Evaluate(Random.value); cache.leafVertexColors.Add(randomColor); cache.leafVertexColors.Add(randomColor); cache.leafVertexColors.Add(randomColor); cache.leafVertexColors.Add(randomColor); } // calculate normal of the leaf tri, and make it face outwards // var normal = GetNormal( // ivyGraph.leafVertices[ivyGraph.leafVertices.Count - 2], // ivyGraph.leafVertices[ivyGraph.leafVertices.Count - 4], // ivyGraph.leafVertices[ivyGraph.leafVertices.Count - 3] // ); // if ( Vector3.Dot( normal, node.adhesionVector) < 0f) { // AddLeafTriangle(ivyGraph, 2, 4, 3); // AddLeafTriangle(ivyGraph, 3, 1, 2); // } else { AddLeafTriangle(cache, 1, 3, 4); AddLeafTriangle(cache, 4, 2, 1); // } } } combinedTriangleIndices.Clear(); cache.leafTriangles.ForEach(index => combinedTriangleIndices.Add(index + leafVerticesAll.Count)); leafTrianglesAll.AddRange(combinedTriangleIndices); leafVerticesAll.AddRange(cache.leafVertices); leafUVsAll.AddRange(cache.leafUVs); if (ivyProfile.useVertexColors) { leafColorsAll.AddRange(cache.leafVertexColors); } } } return(true); }
public override bool TrySimplify( NameSyntax name, SemanticModel semanticModel, OptionSet optionSet, out TypeSyntax replacementNode, out TextSpan issueSpan, CancellationToken cancellationToken) { replacementNode = null; issueSpan = default; if (name.IsVar) { return(false); } // we should not simplify a name of a namespace declaration if (IsPartOfNamespaceDeclarationName(name)) { return(false); } // We can simplify Qualified names and AliasQualifiedNames. Generally, if we have // something like "A.B.C.D", we only consider the full thing something we can simplify. // However, in the case of "A.B.C<>.D", then we'll only consider simplifying up to the // first open name. This is because if we remove the open name, we'll often change // meaning as "D" will bind to C<T>.D which is different than C<>.D! if (name is QualifiedNameSyntax qualifiedName) { var left = qualifiedName.Left; if (ContainsOpenName(left)) { // Don't simplify A.B<>.C return(false); } } // 1. see whether binding the name binds to a symbol/type. if not, it is ambiguous and // nothing we can do here. var symbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, name); if (symbol == null) { return(false); } // treat constructor names as types var method = symbol as IMethodSymbol; if (method.IsConstructor()) { symbol = method.ContainingType; } if (symbol.Kind == SymbolKind.Method && name.Kind() == SyntaxKind.GenericName) { var genericName = (GenericNameSyntax)name; replacementNode = SyntaxFactory.IdentifierName(genericName.Identifier) .WithLeadingTrivia(genericName.GetLeadingTrivia()) .WithTrailingTrivia(genericName.GetTrailingTrivia()); issueSpan = genericName.TypeArgumentList.Span; return(CanReplaceWithReducedName( name, replacementNode, semanticModel, cancellationToken)); } if (!(symbol is INamespaceOrTypeSymbol)) { return(false); } if (name.HasAnnotations(SpecialTypeAnnotation.Kind)) { replacementNode = SyntaxFactory.PredefinedType( SyntaxFactory.Token( name.GetLeadingTrivia(), GetPredefinedKeywordKind(SpecialTypeAnnotation.GetSpecialType(name.GetAnnotations(SpecialTypeAnnotation.Kind).First())), name.GetTrailingTrivia())); issueSpan = name.Span; return(CanReplaceWithReducedNameInContext(name, replacementNode, semanticModel)); } else { if (!name.IsRightSideOfDotOrColonColon()) { if (TryReplaceExpressionWithAlias(name, semanticModel, symbol, cancellationToken, out var aliasReplacement)) { // get the token text as it appears in source code to preserve e.g. Unicode character escaping var text = aliasReplacement.Name; var syntaxRef = aliasReplacement.DeclaringSyntaxReferences.FirstOrDefault(); if (syntaxRef != null) { var declIdentifier = ((UsingDirectiveSyntax)syntaxRef.GetSyntax(cancellationToken)).Alias.Name.Identifier; text = declIdentifier.IsVerbatimIdentifier() ? declIdentifier.ToString().Substring(1) : declIdentifier.ToString(); } var identifierToken = SyntaxFactory.Identifier( name.GetLeadingTrivia(), SyntaxKind.IdentifierToken, text, aliasReplacement.Name, name.GetTrailingTrivia()); identifierToken = CSharpSimplificationService.TryEscapeIdentifierToken(identifierToken, name); replacementNode = SyntaxFactory.IdentifierName(identifierToken); // Merge annotation to new syntax node var annotatedNodesOrTokens = name.GetAnnotatedNodesAndTokens(RenameAnnotation.Kind); foreach (var annotatedNodeOrToken in annotatedNodesOrTokens) { if (annotatedNodeOrToken.IsToken) { identifierToken = annotatedNodeOrToken.AsToken().CopyAnnotationsTo(identifierToken); } else { replacementNode = annotatedNodeOrToken.AsNode().CopyAnnotationsTo(replacementNode); } } annotatedNodesOrTokens = name.GetAnnotatedNodesAndTokens(AliasAnnotation.Kind); foreach (var annotatedNodeOrToken in annotatedNodesOrTokens) { if (annotatedNodeOrToken.IsToken) { identifierToken = annotatedNodeOrToken.AsToken().CopyAnnotationsTo(identifierToken); } else { replacementNode = annotatedNodeOrToken.AsNode().CopyAnnotationsTo(replacementNode); } } replacementNode = ((SimpleNameSyntax)replacementNode).WithIdentifier(identifierToken); issueSpan = name.Span; // In case the alias name is the same as the last name of the alias target, we only include // the left part of the name in the unnecessary span to Not confuse uses. if (name.Kind() == SyntaxKind.QualifiedName) { var qualifiedName3 = (QualifiedNameSyntax)name; if (qualifiedName3.Right.Identifier.ValueText == identifierToken.ValueText) { issueSpan = qualifiedName3.Left.Span; } } // first check if this would be a valid reduction if (CanReplaceWithReducedNameInContext(name, replacementNode, semanticModel)) { // in case this alias name ends with "Attribute", we're going to see if we can also // remove that suffix. if (TryReduceAttributeSuffix( name, identifierToken, out var replacementNodeWithoutAttributeSuffix, out var issueSpanWithoutAttributeSuffix)) { if (CanReplaceWithReducedName(name, replacementNodeWithoutAttributeSuffix, semanticModel, cancellationToken)) { replacementNode = replacementNode.CopyAnnotationsTo(replacementNodeWithoutAttributeSuffix); issueSpan = issueSpanWithoutAttributeSuffix; } } return(true); } return(false); } var nameHasNoAlias = false; if (name is SimpleNameSyntax simpleName) { if (!simpleName.Identifier.HasAnnotations(AliasAnnotation.Kind)) { nameHasNoAlias = true; } } if (name is QualifiedNameSyntax qualifiedName2) { if (!qualifiedName2.Right.HasAnnotation(Simplifier.SpecialTypeAnnotation)) { nameHasNoAlias = true; } } if (name is AliasQualifiedNameSyntax aliasQualifiedName) { if (aliasQualifiedName.Name is SimpleNameSyntax && !aliasQualifiedName.Name.Identifier.HasAnnotations(AliasAnnotation.Kind) && !aliasQualifiedName.Name.HasAnnotation(Simplifier.SpecialTypeAnnotation)) { nameHasNoAlias = true; } } var aliasInfo = semanticModel.GetAliasInfo(name, cancellationToken); if (nameHasNoAlias && aliasInfo == null) { // Don't simplify to predefined type if name is part of a QualifiedName. // QualifiedNames can't contain PredefinedTypeNames (although MemberAccessExpressions can). // In other words, the left side of a QualifiedName can't be a PredefinedTypeName. var inDeclarationContext = PreferPredefinedTypeKeywordInDeclarations(name, optionSet, semanticModel); var inMemberAccessContext = PreferPredefinedTypeKeywordInMemberAccess(name, optionSet, semanticModel); if (!name.Parent.IsKind(SyntaxKind.QualifiedName) && (inDeclarationContext || inMemberAccessContext)) { // See if we can simplify this name (like System.Int32) to a built-in type (like 'int'). // If not, we'll still fall through and see if we can convert it to Int32. var codeStyleOptionName = inDeclarationContext ? nameof(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration) : nameof(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess); var type = semanticModel.GetTypeInfo(name, cancellationToken).Type; if (type != null) { var keywordKind = GetPredefinedKeywordKind(type.SpecialType); if (keywordKind != SyntaxKind.None && CanReplaceWithPredefinedTypeKeywordInContext(name, semanticModel, out replacementNode, ref issueSpan, keywordKind, codeStyleOptionName)) { return(true); } } else { var typeSymbol = semanticModel.GetSymbolInfo(name, cancellationToken).Symbol; if (typeSymbol.IsKind(SymbolKind.NamedType)) { var keywordKind = GetPredefinedKeywordKind(((INamedTypeSymbol)typeSymbol).SpecialType); if (keywordKind != SyntaxKind.None && CanReplaceWithPredefinedTypeKeywordInContext(name, semanticModel, out replacementNode, ref issueSpan, keywordKind, codeStyleOptionName)) { return(true); } } } } } // Nullable rewrite: Nullable<int> -> int? // Don't rewrite in the case where Nullable<int> is part of some qualified name like Nullable<int>.Something if (!name.IsVar && symbol.Kind == SymbolKind.NamedType && !name.IsLeftSideOfQualifiedName()) { var type = (INamedTypeSymbol)symbol; if (aliasInfo == null && CanSimplifyNullable(type, name, semanticModel)) { GenericNameSyntax genericName; if (name.Kind() == SyntaxKind.QualifiedName) { genericName = (GenericNameSyntax)((QualifiedNameSyntax)name).Right; } else { genericName = (GenericNameSyntax)name; } var oldType = genericName.TypeArgumentList.Arguments.First(); if (oldType.Kind() == SyntaxKind.OmittedTypeArgument) { return(false); } replacementNode = SyntaxFactory.NullableType(oldType) .WithLeadingTrivia(name.GetLeadingTrivia()) .WithTrailingTrivia(name.GetTrailingTrivia()); issueSpan = name.Span; // we need to simplify the whole qualified name at once, because replacing the identifier on the left in // System.Nullable<int> alone would be illegal. // If this fails we want to continue to try at least to remove the System if possible. if (CanReplaceWithReducedNameInContext(name, replacementNode, semanticModel)) { return(true); } } } } SyntaxToken identifier; switch (name.Kind()) { case SyntaxKind.AliasQualifiedName: var simpleName = ((AliasQualifiedNameSyntax)name).Name .WithLeadingTrivia(name.GetLeadingTrivia()); simpleName = simpleName.ReplaceToken(simpleName.Identifier, ((AliasQualifiedNameSyntax)name).Name.Identifier.CopyAnnotationsTo( simpleName.Identifier.WithLeadingTrivia( ((AliasQualifiedNameSyntax)name).Alias.Identifier.LeadingTrivia))); replacementNode = simpleName; issueSpan = ((AliasQualifiedNameSyntax)name).Alias.Span; break; case SyntaxKind.QualifiedName: replacementNode = ((QualifiedNameSyntax)name).Right.WithLeadingTrivia(name.GetLeadingTrivia()); issueSpan = ((QualifiedNameSyntax)name).Left.Span; break; case SyntaxKind.IdentifierName: identifier = ((IdentifierNameSyntax)name).Identifier; // we can try to remove the Attribute suffix if this is the attribute name TryReduceAttributeSuffix(name, identifier, out replacementNode, out issueSpan); break; } } if (replacementNode == null) { return(false); } // We may be looking at a name `X.Y` seeing if we can replace it with `Y`. However, in // order to know for sure, we actually have to look slightly higher at `X.Y.Z` to see if // it can simplify to `Y.Z`. This is because in the `Color Color` case we can only tell // if we can reduce by looking by also looking at what comes next to see if it will // cause the simplified name to bind to the instance or static side. if (TryReduceCrefColorColor(name, replacementNode, semanticModel, cancellationToken)) { return(true); } return(CanReplaceWithReducedName(name, replacementNode, semanticModel, cancellationToken)); }
private void pb_Draw_MouseUp(object sender, MouseEventArgs e) { isMouseDown = false; if (drawCheckbox.Checked) { try { IList <Point> simplifiedPointsLine = SimplificationHelpers.Simplify <Point>( pointCollection, (p1, p2) => p1 == p2, (p) => p.X, (p) => p.Y, Convert.ToDouble(tolerance_textbox.Text), hq_checkbox.Checked ); pointCollection = new List <Point>(); outputPointsLabel.Text = "Output points: " + simplifiedPointsLine.Count; if (tb_width.Text != "" && lv_charmap.SelectedItems.Count != 0) { if (autoInputOutputPoints.Checked && simplifiedPointsLine.Count > 0) //if checked - adding input point as input point { lv_points.Items.Add(simplifiedPointsLine[0].X / 2 + "," + simplifiedPointsLine[0].Y / 2 + ",-1,-1"); segs++; } for (int i = 0; i < simplifiedPointsLine.Count - 1; i++) //iterating through every point except the last one because line builds of two points - this and next { lv_points.Items.Add(simplifiedPointsLine[i].X / 2 + "," + simplifiedPointsLine[i].Y / 2 + "," + (simplifiedPointsLine[i + 1].X / 2 + "," + simplifiedPointsLine[i + 1].Y / 2)); segs++; } selected_seg = segs - 1; for (int i = 0; i < segs; i++) { lv_points.Items[i].Selected = false; lv_points.Items[i].Focused = false; } lv_points.Items[segs - 1].Selected = true; lv_points.Items[segs - 1].Focused = true; if (autoInputOutputPoints.Checked && simplifiedPointsLine.Count > 0) //if checked - adding last point as output point { lv_points.Items.Add("-1,-1," + simplifiedPointsLine[simplifiedPointsLine.Count - 1].X / 2 + "," + simplifiedPointsLine[simplifiedPointsLine.Count - 1].Y / 2); segs++; } if (autogapCheckbox.Checked) //autogapping on fly { remove_gaps(null, null); //it removes gapps and saves the array } else { setButton_Click(null, null); //it saves the array } } else { MaterialMessageBox.Show("Select the char and enter the width first!"); } } catch (FormatException exep) { MaterialMessageBox.Show("Tolerance value is incorrect!"); } //simplifying the pointcollection } }
public static bool TryReduceOrSimplifyExplicitName( this CrefSyntax crefSyntax, SemanticModel semanticModel, out CrefSyntax replacementNode, out TextSpan issueSpan, OptionSet optionSet, CancellationToken cancellationToken) { replacementNode = null; issueSpan = default; // Currently Qualified Cref is the only CrefSyntax We are handling separately if (crefSyntax.Kind() != SyntaxKind.QualifiedCref) { return(false); } var qualifiedCrefSyntax = (QualifiedCrefSyntax)crefSyntax; var memberCref = qualifiedCrefSyntax.Member; // Currently we are dealing with only the NameMemberCrefs if (SimplificationHelpers.PreferPredefinedTypeKeywordInMemberAccess(optionSet, semanticModel.Language) && (memberCref.Kind() == SyntaxKind.NameMemberCref)) { var nameMemberCref = ((NameMemberCrefSyntax)memberCref).Name; var symbolInfo = semanticModel.GetSymbolInfo(nameMemberCref, cancellationToken); var symbol = symbolInfo.Symbol; if (symbol == null) { return(false); } if (symbol is INamespaceOrTypeSymbol namespaceOrTypeSymbol) { // 1. Check for Predefined Types if (symbol is INamedTypeSymbol namedSymbol) { var keywordKind = ExpressionSyntaxExtensions.GetPredefinedKeywordKind(namedSymbol.SpecialType); if (keywordKind != SyntaxKind.None) { replacementNode = SyntaxFactory.TypeCref( SyntaxFactory.PredefinedType( SyntaxFactory.Token(crefSyntax.GetLeadingTrivia(), keywordKind, crefSyntax.GetTrailingTrivia()))); replacementNode = crefSyntax.CopyAnnotationsTo(replacementNode); // we want to show the whole name expression as unnecessary issueSpan = crefSyntax.Span; return(true); } } } } var oldSymbol = semanticModel.GetSymbolInfo(crefSyntax, cancellationToken).Symbol; if (oldSymbol != null) { var speculativeBindingOption = SpeculativeBindingOption.BindAsExpression; if (oldSymbol is INamespaceOrTypeSymbol) { speculativeBindingOption = SpeculativeBindingOption.BindAsTypeOrNamespace; } var newSymbol = semanticModel.GetSpeculativeSymbolInfo(crefSyntax.SpanStart, memberCref, speculativeBindingOption).Symbol; if (newSymbol == oldSymbol) { // Copy Trivia and Annotations memberCref = memberCref.WithLeadingTrivia(crefSyntax.GetLeadingTrivia()); memberCref = crefSyntax.CopyAnnotationsTo(memberCref); issueSpan = qualifiedCrefSyntax.Container.Span; replacementNode = memberCref; return(true); } } return(false); }
// Note: The caller needs to verify that replacement doesn't change semantics of the original expression. private static bool TrySimplifyMemberAccessOrQualifiedName( ExpressionSyntax left, ExpressionSyntax right, SemanticModel semanticModel, out ExpressionSyntax replacementNode, out TextSpan issueSpan) { replacementNode = null; issueSpan = default; if (left != null && right != null) { var leftSymbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, left); if (leftSymbol != null && leftSymbol.Kind == SymbolKind.NamedType) { var rightSymbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, right); if (rightSymbol != null && (rightSymbol.IsStatic || rightSymbol.Kind == SymbolKind.NamedType)) { // Static member access or nested type member access. var containingType = rightSymbol.ContainingType; var enclosingSymbol = semanticModel.GetEnclosingSymbol(left.SpanStart); var enclosingTypeParametersInsideOut = new List<ISymbol>(); while (enclosingSymbol != null) { if (enclosingSymbol is IMethodSymbol methodSymbol) { if (methodSymbol.TypeArguments.Length != 0) { enclosingTypeParametersInsideOut.AddRange(methodSymbol.TypeArguments); } } if (enclosingSymbol is INamedTypeSymbol namedTypeSymbol) { if (namedTypeSymbol.TypeArguments.Length != 0) { enclosingTypeParametersInsideOut.AddRange(namedTypeSymbol.TypeArguments); } } enclosingSymbol = enclosingSymbol.ContainingSymbol; } if (containingType != null && !containingType.Equals(leftSymbol)) { if (leftSymbol is INamedTypeSymbol namedType && containingType.TypeArguments.Length != 0) { return false; } // We have a static member access or a nested type member access using a more derived type. // Simplify syntax so as to use accessed member's most immediate containing type instead of the derived type. replacementNode = containingType.GenerateTypeSyntax() .WithLeadingTrivia(left.GetLeadingTrivia()) .WithTrailingTrivia(left.GetTrailingTrivia()); issueSpan = left.Span; return true; } } } } return false; }
private static bool TryReduceMemberAccessExpression( MemberAccessExpressionSyntax memberAccess, SemanticModel semanticModel, out TypeSyntax replacementNode, out TextSpan issueSpan, OptionSet optionSet, CancellationToken cancellationToken) { replacementNode = null; issueSpan = default; if (memberAccess.Name == null || memberAccess.Expression == null) return false; // if this node is annotated as being a SpecialType, let's use this information. if (memberAccess.HasAnnotations(SpecialTypeAnnotation.Kind)) { replacementNode = SyntaxFactory.PredefinedType( SyntaxFactory.Token( memberAccess.GetLeadingTrivia(), GetPredefinedKeywordKind(SpecialTypeAnnotation.GetSpecialType(memberAccess.GetAnnotations(SpecialTypeAnnotation.Kind).First())), memberAccess.GetTrailingTrivia())); issueSpan = memberAccess.Span; return true; } // See https://github.com/dotnet/roslyn/issues/40974 // // To be very safe, we only support simplifying code that bound to a symbol without any // sort of problems. We could potentially relax this in the future. However, we would // need to be very careful about the implications of us offering to fixup 'broken' code // in a manner that might end up making things worse or confusing the user. var symbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, memberAccess); if (symbol == null) return false; if (memberAccess.Expression.IsKind(SyntaxKind.ThisExpression) && !SimplificationHelpers.ShouldSimplifyThisOrMeMemberAccessExpression(semanticModel, optionSet, symbol)) { return false; } // if this node is on the left side, we could simplify to aliases if (!memberAccess.IsRightSideOfDot()) { // Check if we need to replace this syntax with an alias identifier if (TryReplaceExpressionWithAlias( memberAccess, semanticModel, symbol, cancellationToken, out var aliasReplacement)) { // get the token text as it appears in source code to preserve e.g. unicode character escaping var text = aliasReplacement.Name; var syntaxRef = aliasReplacement.DeclaringSyntaxReferences.FirstOrDefault(); if (syntaxRef != null) { var declIdentifier = ((UsingDirectiveSyntax)syntaxRef.GetSyntax(cancellationToken)).Alias.Name.Identifier; text = declIdentifier.IsVerbatimIdentifier() ? declIdentifier.ToString().Substring(1) : declIdentifier.ToString(); } replacementNode = SyntaxFactory.IdentifierName( memberAccess.Name.Identifier.CopyAnnotationsTo(SyntaxFactory.Identifier( memberAccess.GetLeadingTrivia(), SyntaxKind.IdentifierToken, text, aliasReplacement.Name, memberAccess.GetTrailingTrivia()))); replacementNode = memberAccess.CopyAnnotationsTo(replacementNode); replacementNode = memberAccess.Name.CopyAnnotationsTo(replacementNode); issueSpan = memberAccess.Span; // In case the alias name is the same as the last name of the alias target, we only include // the left part of the name in the unnecessary span to Not confuse uses. if (memberAccess.Name.Identifier.ValueText == ((IdentifierNameSyntax)replacementNode).Identifier.ValueText) { issueSpan = memberAccess.Expression.Span; } return true; } // Check if the Expression can be replaced by Predefined Type keyword if (PreferPredefinedTypeKeywordInMemberAccess(memberAccess, optionSet, semanticModel)) { if (symbol != null && symbol.IsKind(SymbolKind.NamedType)) { var keywordKind = GetPredefinedKeywordKind(((INamedTypeSymbol)symbol).SpecialType); if (keywordKind != SyntaxKind.None) { replacementNode = CreatePredefinedTypeSyntax(memberAccess, keywordKind); replacementNode = replacementNode .WithAdditionalAnnotations<TypeSyntax>(new SyntaxAnnotation( nameof(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess))); issueSpan = memberAccess.Span; // we want to show the whole expression as unnecessary return true; } } } } // Try to eliminate cases without actually calling CanReplaceWithReducedName. For expressions of the form // 'this.Name' or 'base.Name', no additional check here is required. if (!memberAccess.Expression.IsKind(SyntaxKind.ThisExpression, SyntaxKind.BaseExpression)) { GetReplacementCandidates( semanticModel, memberAccess, symbol, out var speculativeSymbols, out var speculativeNamespacesAndTypes); if (!IsReplacementCandidate(symbol, speculativeSymbols, speculativeNamespacesAndTypes)) { return false; } } replacementNode = memberAccess.GetNameWithTriviaMoved(); issueSpan = memberAccess.Expression.Span; return CanReplaceWithReducedName( memberAccess, replacementNode, semanticModel, symbol, cancellationToken); }