[closes gh-25] Fixed incorrect parentheses in (e.g.) string comparisons.

This commit is contained in:
Andrey Shchekin 2017-06-25 19:52:15 +12:00
Родитель 4388c14afd
Коммит 2dfaa3f749
8 изменённых файлов: 17 добавлений и 191 удалений

Просмотреть файл

@ -39,22 +39,10 @@ namespace SharpLab.Server.Decompilation {
var ast = new AstBuilder(context);
ast.AddAssembly(module.Assembly);
RunTransforms(ast, context);
// I cannot use GenerateCode as it re-runs all the transforms
WriteResult(codeWriter, ast.SyntaxTree, context);
WriteResult(codeWriter, ast);
}
protected abstract void WriteResult(TextWriter writer, AstNode ast, DecompilerContext context);
private void RunTransforms(AstBuilder ast, DecompilerContext context) {
var transforms = TransformationPipeline.CreatePipeline(context).ToList();
transforms[transforms.FindIndex(t => t is ConvertConstructorCallIntoInitializer)] = new RoslynFriendlyConvertConstructorCallIntoInitializer();
foreach (var transform in transforms) {
transform.Run(ast.SyntaxTree);
}
}
protected abstract void WriteResult(TextWriter writer, AstBuilder ast);
public abstract string LanguageName { get; }
}

Просмотреть файл

@ -8,13 +8,10 @@ using SharpLab.Server.Decompilation.Internal;
namespace SharpLab.Server.Decompilation {
public class CSharpDecompiler : AstBasedDecompiler {
protected override void WriteResult(TextWriter writer, AstNode ast, DecompilerContext context) {
var visitor = new DecompiledPseudoCSharpOutputVisitor(
new TextTokenWriter(new CustomizableIndentPlainTextOutput(writer) { IndentationString = " " }, context),
context.Settings.CSharpFormattingOptions
);
ast.AcceptVisitor(visitor);
protected override void WriteResult(TextWriter writer, AstBuilder ast) {
ast.GenerateCode(new CustomizableIndentPlainTextOutput(writer) {
IndentationString = " "
});
}
public override string LanguageName => LanguageNames.CSharp;

Просмотреть файл

@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using JetBrains.Annotations;
namespace SharpLab.Server.Decompilation.Internal {
public class DecompiledPseudoCSharpOutputVisitor : CSharpOutputVisitor {
private bool _currentStatementIsNotValidCSharp = false;
public DecompiledPseudoCSharpOutputVisitor(TextWriter textWriter, CSharpFormattingOptions formattingPolicy) : base(textWriter, formattingPolicy) {
}
public DecompiledPseudoCSharpOutputVisitor(TokenWriter tokenWriter, CSharpFormattingOptions formattingPolicy) : base(tokenWriter, formattingPolicy) {
}
public override void VisitExpressionStatement(ExpressionStatement expressionStatement) {
StartNode(expressionStatement);
expressionStatement.Expression.AcceptVisitor(this);
WriteToken(Roles.Semicolon);
if (_currentStatementIsNotValidCSharp) {
Space();
VisitComment(new Comment(" This is not valid C#, but it represents the IL correctly."));
_currentStatementIsNotValidCSharp = false;
}
NewLine();
EndNode(expressionStatement);
}
public override void VisitInvocationExpression(InvocationExpression invocationExpression) {
// writes base..ctor() as base() and this..ctor() as this()
var memberReference = invocationExpression.Target as MemberReferenceExpression;
if (IsBaseOrThisConstructor(memberReference)) {
var keyword = (memberReference.Target is ThisReferenceExpression)
? ConstructorInitializer.ThisKeywordRole
: ConstructorInitializer.BaseKeywordRole;
StartNode(invocationExpression);
WriteKeyword(keyword);
Space(policy.SpaceBeforeMethodCallParentheses);
WriteCommaSeparatedListInParenthesis(invocationExpression.Arguments, policy.SpaceWithinMethodCallParentheses);
EndNode(invocationExpression);
_currentStatementIsNotValidCSharp = true;
return;
}
base.VisitInvocationExpression(invocationExpression);
}
[ContractAnnotation("memberReference:null => false")]
private static bool IsBaseOrThisConstructor(MemberReferenceExpression memberReference) {
return memberReference != null
&& (memberReference.Target is BaseReferenceExpression || memberReference.Target is ThisReferenceExpression)
&& memberReference.MemberName == ".ctor";
}
}
}

Просмотреть файл

@ -1,92 +0,0 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
// Copyright (c) 2014 Andrey Shchekin (TryRsolyn changes only)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil;
namespace SharpLab.Server.Decompilation.Internal {
// This is mostly a copy of ConvertConstructorCallIntoInitializer from Decompiler library.
// However it is simplified so that it does not try to use field initializers, as that can not be
// correctly represented for primary constructor decompilation.
public class RoslynFriendlyConvertConstructorCallIntoInitializer : DepthFirstAstVisitor<object, object>, IAstTransform {
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) {
var stmt = constructorDeclaration.Body.Statements.FirstOrDefault() as ExpressionStatement;
if (stmt == null)
return null;
var invocation = stmt.Expression as InvocationExpression;
if (invocation == null)
return null;
var mre = invocation.Target as MemberReferenceExpression;
if (mre == null || mre.MemberName != ".ctor")
return null;
var initializer = new ConstructorInitializer();
if (mre.Target is ThisReferenceExpression)
initializer.ConstructorInitializerType = ConstructorInitializerType.This;
else if (mre.Target is BaseReferenceExpression)
initializer.ConstructorInitializerType = ConstructorInitializerType.Base;
else
return null;
// Move arguments from invocation to initializer:
invocation.Arguments.MoveTo(initializer.Arguments);
// Add the initializer: (unless it is the default 'base()')
if (initializer.ConstructorInitializerType != ConstructorInitializerType.Base || initializer.Arguments.Count > 0) {
initializer.AddAnnotation(invocation.Annotation<MethodReference>());
constructorDeclaration.Initializer = initializer;
}
// Remove the statement:
stmt.Remove();
return null;
}
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) {
// Now convert base constructor calls to initializers:
base.VisitTypeDeclaration(typeDeclaration, data);
// Remove single empty constructor:
RemoveSingleEmptyConstructor(typeDeclaration);
return null;
}
private void RemoveSingleEmptyConstructor(TypeDeclaration typeDeclaration) {
var instanceCtors = typeDeclaration.Members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
if (instanceCtors.Length != 1)
return;
var emptyCtor = new ConstructorDeclaration();
emptyCtor.Modifiers = ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public);
emptyCtor.Body = new BlockStatement();
if (emptyCtor.IsMatch(instanceCtors[0]))
instanceCtors[0].Remove();
}
public void Run(AstNode node) {
node.AcceptVisitor(this, null);
}
}
}

Просмотреть файл

@ -1,17 +1,16 @@
using System.Collections.Generic;
using System.IO;
using ICSharpCode.Decompiler;
using System.IO;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.ILSpy.VB;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.VB;
using ICSharpCode.NRefactory.VB.Visitors;
using Microsoft.CodeAnalysis;
using SharpLab.Server.Decompilation.Internal;
using AstNode = ICSharpCode.NRefactory.CSharp.AstNode;
namespace SharpLab.Server.Decompilation {
public class VisualBasicDecompiler : AstBasedDecompiler {
protected override void WriteResult(TextWriter writer, AstNode ast, DecompilerContext context) {
protected override void WriteResult(TextWriter writer, AstBuilder ast) {
ast.RunTransformations();
var converter = new CSharpToVBConverterVisitor(new ILSpyEnvironmentProvider());
var visitor = new OutputVisitor(
new VBTextOutputFormatter(new CustomizableIndentPlainTextOutput(writer) {
@ -19,8 +18,7 @@ namespace SharpLab.Server.Decompilation {
}),
new VBFormattingOptions()
);
ast.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
var converted = ast.AcceptVisitor(converter, null);
var converted = ast.SyntaxTree.AcceptVisitor(converter, null);
converted.AcceptVisitor(visitor, null);
}

Просмотреть файл

@ -25,7 +25,7 @@ public class C
{
public void M(string n)
{
if (n != "foo")
if (!(n == "foo"))
{
}
}

Просмотреть файл

@ -29,16 +29,10 @@ public class C
[Serializable]
private sealed class <>c
{
public static readonly C.<>c <>9;
public static readonly C.<>c <>9 = new C.<>c();
public static Func<int, int> <>9__0_0;
static <>c()
{
// Note: this type is marked as 'beforefieldinit'.
C.<>c.<>9 = new C.<>c();
}
internal int <M>b__0_0(int s)
{
return s;
@ -48,9 +42,9 @@ public class C
public void M()
{
Func<int, int> arg_1F_0;
if (arg_1F_0 = C.<>c.<>9__0_0 == null)
if ((arg_1F_0 = C.<>c.<>9__0_0) == null)
{
arg_1F_0 = C.<>c.<>9__0_0 = new Func<int, int>(C.<>c.<>9.<M>b__0_0);
arg_1F_0 = (C.<>c.<>9__0_0 = new Func<int, int>(C.<>c.<>9.<M>b__0_0));
}
Func<int, int> func = arg_1F_0;
int[] expr_26 = new int[4];

Просмотреть файл

@ -41,6 +41,6 @@ public class Point
public int M(Point p)
{
return (p != null ? new int?(p.X) : null).GetValueOrDefault();
return ((p != null) ? new int?(p.X) : null).GetValueOrDefault();
}
}