// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team // // 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 System.Reflection; using System.Text; using System.Threading; using ICSharpCode.Core; using ICSharpCode.NRefactory; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom.ClassBrowser; using ICSharpCode.SharpDevelop.Editor.Search; using ICSharpCode.SharpDevelop.Parser; using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.ILSpyAddIn { /// /// This class "parses" a decompiled type to provide the information required /// by the ParserService. /// public class ILSpyParser : IParser { public bool CanParse(string fileName) { return fileName != null && fileName.StartsWith("ilspy://", StringComparison.OrdinalIgnoreCase); } readonly static ITextSource EmptyFileContent = new StringTextSource(""); public ITextSource GetFileContent(FileName fileName) { return EmptyFileContent; } public ParseInformation Parse(FileName fileName, ITextSource fileContent, bool fullParseInformationRequested, IProject parentProject, CancellationToken cancellationToken) { return ILSpyDecompilerService.DecompileType(DecompiledTypeReference.FromFileName(fileName), cancellationToken); } public ResolveResult Resolve(ParseInformation parseInfo, TextLocation location, ICompilation compilation, CancellationToken cancellationToken) { var decompiledParseInfo = parseInfo as ILSpyFullParseInformation; if (decompiledParseInfo == null) throw new ArgumentException("ParseInfo does not have SyntaxTree"); return ResolveAtLocation.Resolve(compilation, null, decompiledParseInfo.SyntaxTree, location, cancellationToken); } public ICodeContext ResolveContext(ParseInformation parseInfo, TextLocation location, ICompilation compilation, CancellationToken cancellationToken) { var decompiledParseInfo = parseInfo as ILSpyFullParseInformation; if (decompiledParseInfo == null) throw new ArgumentException("ParseInfo does not have SyntaxTree"); var syntaxTree = decompiledParseInfo.SyntaxTree; var node = syntaxTree.GetNodeAt(location); if (node == null) return null; // null result is allowed; the parser service will substitute a dummy context var resolver = new CSharpAstResolver(compilation, syntaxTree, null); return resolver.GetResolverStateBefore(node); } public ResolveResult ResolveSnippet(ParseInformation parseInfo, TextLocation location, string codeSnippet, ICompilation compilation, CancellationToken cancellationToken) { var decompiledParseInfo = parseInfo as ILSpyFullParseInformation; if (decompiledParseInfo == null) throw new ArgumentException("ParseInfo does not have SyntaxTree"); CSharpAstResolver contextResolver = new CSharpAstResolver(compilation, decompiledParseInfo.SyntaxTree, null); var node = decompiledParseInfo.SyntaxTree.GetNodeAt(location); CSharpResolver context; if (node != null) context = contextResolver.GetResolverStateAfter(node, cancellationToken); else context = new CSharpResolver(compilation); CSharpParser parser = new CSharpParser(); var expr = parser.ParseExpression(codeSnippet); if (parser.HasErrors) return new ErrorResolveResult(SpecialType.UnknownType, PrintErrorsAsString(parser.Errors), TextLocation.Empty); CSharpAstResolver snippetResolver = new CSharpAstResolver(context, expr); return snippetResolver.Resolve(expr, cancellationToken); } string PrintErrorsAsString(IEnumerable errors) { StringBuilder builder = new StringBuilder(); foreach (var error in errors) builder.AppendLine(error.Message); return builder.ToString(); } public void FindLocalReferences(ParseInformation parseInfo, ITextSource fileContent, IVariable variable, ICompilation compilation, Action callback, CancellationToken cancellationToken) { throw new NotImplementedException(); } public ICompilation CreateCompilationForSingleFile(FileName fileName, IUnresolvedFile unresolvedFile) { DecompiledTypeReference reference = DecompiledTypeReference.FromFileName(fileName); if (reference != null) { var model = SD.GetService().FindAssemblyModel(reference.AssemblyFile); if (model == null) model = SD.AssemblyParserService.GetAssemblyModelSafe(reference.AssemblyFile, true); if (model != null) return model.Context.GetCompilation(); } return new CSharpProjectContent() .AddOrUpdateFiles(unresolvedFile) .CreateCompilation(); } public IReadOnlyList TaskListTokens { get; set; } } }