[closes gh-25] Fixed incorrect parentheses in (e.g.) string comparisons.
This commit is contained in:
Родитель
4388c14afd
Коммит
2dfaa3f749
|
@ -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();
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче