⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 booresolver.cs

📁 SharpDevelop2.0.0 c#开发免费工具
💻 CS
字号:
// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
//     <version>$Revision: 1417 $</version>
// </file>

using System;
using System.Collections;
using System.Collections.Generic;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Dom;
using Boo.Lang.Compiler;
using AST = Boo.Lang.Compiler.Ast;
using Boo.Lang.Compiler.IO;
using Boo.Lang.Compiler.Steps;
using NRResolver = ICSharpCode.SharpDevelop.Dom.NRefactoryResolver.NRefactoryResolver;

namespace Grunwald.BooBinding.CodeCompletion
{
	public class BooResolver : IResolver
	{
		#region Fields and properties
		ICompilationUnit cu;
		IProjectContent pc;
		int caretLine;
		int caretColumn;
		IClass callingClass;
		IMethodOrProperty callingMember;
		
		public IClass CallingClass {
			get {
				return callingClass;
			}
		}
		
		public IMethodOrProperty CallingMember {
			get {
				return callingMember;
			}
		}
		
		public int CaretLine {
			get {
				return caretLine;
			}
		}
		
		public int CaretColumn {
			get {
				return caretColumn;
			}
		}
		
		public IProjectContent ProjectContent {
			get {
				return pc;
			}
		}
		
		public ICompilationUnit CompilationUnit {
			get {
				return cu;
			}
		}
		
		/// <summary>
		/// Gets if duck typing is enabled for the Boo project.
		/// </summary>
		public bool IsDucky {
			get {
				BooProject p = pc.Project as BooProject;
				if (p != null)
					return p.Ducky;
				else
					return false;
			}
		}
		#endregion
		
		#region Initialization
		bool Initialize(string fileName, int caretLine, int caretColumn)
		{
			ParseInformation parseInfo = ParserService.GetParseInformation(fileName);
			if (parseInfo == null) {
				return false;
			}
			this.cu = parseInfo.MostRecentCompilationUnit;
			if (cu == null) {
				return false;
			}
			this.pc = cu.ProjectContent;
			this.caretLine = caretLine;
			this.caretColumn = caretColumn;
			this.callingClass = GetCallingClass(pc);
			callingMember = ResolveCurrentMember(callingClass);
			if (callingMember == null) {
				if (cu != parseInfo.BestCompilationUnit) {
					IClass olderClass = GetCallingClass(parseInfo.BestCompilationUnit.ProjectContent);
					if (olderClass != null && callingClass == null) {
						this.callingClass = olderClass;
					}
					callingMember = ResolveCurrentMember(olderClass);
				}
			}
			if (callingMember != null) {
				if (caretLine > callingMember.BodyRegion.EndLine) {
					this.caretLine = callingMember.BodyRegion.EndLine;
					this.caretColumn = callingMember.BodyRegion.EndColumn - 1;
				} else if (caretLine == callingMember.BodyRegion.EndLine && caretColumn >= callingMember.BodyRegion.EndColumn) {
					this.caretColumn = callingMember.BodyRegion.EndColumn - 1;
				}
			}
			return true;
		}
		
		IClass GetCallingClass(IProjectContent pc)
		{
			IClass callingClass = cu.GetInnermostClass(caretLine, caretColumn);
			if (callingClass == null) {
				if (cu.Classes.Count == 0) return null;
				callingClass = cu.Classes[cu.Classes.Count - 1];
				if (!callingClass.Region.IsEmpty) {
					if (callingClass.Region.BeginLine > caretLine)
						callingClass = null;
				}
			}
			return callingClass;
		}
		
		IMethodOrProperty ResolveCurrentMember(IClass callingClass)
		{
			//LoggingService.DebugFormatted("Getting current method... caretLine = {0}, caretColumn = {1}", caretLine, caretColumn);
			if (callingClass == null) return null;
			IMethodOrProperty best = null;
			int line = 0;
			foreach (IMethod m in callingClass.Methods) {
				if (m.Region.BeginLine <= caretLine && m.Region.BeginLine > line) {
					line = m.Region.BeginLine;
					best = m;
				}
			}
			foreach (IProperty m in callingClass.Properties) {
				if (m.Region.BeginLine <= caretLine && m.Region.BeginLine > line) {
					line = m.Region.BeginLine;
					best = m;
				}
			}
			if (callingClass.Region.IsEmpty) {
				// maybe we are in Main method?
				foreach (IMethod m in callingClass.Methods) {
					if (m.Region.IsEmpty && !m.IsSynthetic) {
						// the main method
						if (best == null || best.BodyRegion.EndLine < caretLine)
							return m;
					}
				}
			}
			return best;
		}
		#endregion
		
		#region GetTypeOfExpression
		public IReturnType GetTypeOfExpression(AST.Expression expr, IClass callingClass)
		{
			AST.Node node = expr;
			AST.LexicalInfo lexInfo;
			do {
				if (node == null) return null;
				lexInfo = node.LexicalInfo;
				node = node.ParentNode;
			} while (lexInfo == null || lexInfo.FileName == null);
			if (!Initialize(lexInfo.FileName, lexInfo.Line, lexInfo.Column))
				return null;
			if (callingClass != null)
				this.callingClass = callingClass;
			ResolveVisitor visitor = new ResolveVisitor(this);
			visitor.Visit(expr);
			if (visitor.ResolveResult == null)
				return null;
			else
				return visitor.ResolveResult.ResolvedType;
		}
		#endregion
		
		#region GetCurrentBooMethod
		AST.Node GetCurrentBooMethod()
		{
			if (callingMember == null)
				return null;
			// TODO: don't save boo's AST in userdata, but parse fileContent here
			return callingMember.UserData as AST.Node;
		}
		#endregion
		
		#region Resolve
		public ResolveResult Resolve(ExpressionResult expressionResult,
		                             int caretLineNumber, int caretColumn,
		                             string fileName, string fileContent)
		{
			if (!Initialize(fileName, caretLineNumber, caretColumn))
				return null;
			LoggingService.Debug("Resolve " + expressionResult.ToString());
			if (expressionResult.Expression == "__GlobalNamespace") { // used for "import" completion
				return new NamespaceResolveResult(callingClass, callingMember, "");
			}
			
			ResolveResult rr = NRResolver.GetResultFromDeclarationLine(callingClass, callingMember as IMethodOrProperty, this.caretLine, this.caretColumn, expressionResult.Expression);
			if (rr != null) return rr;
			
			AST.Expression expr;
			try {
				expr = Boo.Lang.Parser.BooParser.ParseExpression("expression", expressionResult.Expression);
			} catch (Exception ex) {
				LoggingService.Debug("Boo expression parser: " + ex.Message);
				return null;
			}
			if (expr == null)
				return null;
			if (expr is AST.IntegerLiteralExpression)
				return new IntegerLiteralResolveResult(callingClass, callingMember);
			
			if (expressionResult.Context == ExpressionFinder.BooAttributeContext.Instance) {
				AST.MethodInvocationExpression mie = expr as AST.MethodInvocationExpression;
				if (mie != null)
					expr = mie.Target;
				string name = expr.ToCodeString();
				IReturnType rt = pc.SearchType(name, 0, callingClass, cu, caretLine, caretColumn);
				if (rt != null && rt.GetUnderlyingClass() != null)
					return new TypeResolveResult(callingClass, callingMember, rt);
				rt = pc.SearchType(name + "Attribute", 0, callingClass, cu, caretLine, caretColumn);
				if (rt != null && rt.GetUnderlyingClass() != null)
					return new TypeResolveResult(callingClass, callingMember, rt);
				if (BooProject.BooCompilerPC != null) {
					IClass c = BooProject.BooCompilerPC.GetClass("Boo.Lang." + char.ToUpper(name[0]) + name.Substring(1) + "Attribute");
					if (c != null)
						return new TypeResolveResult(callingClass, callingMember, c);
				}
				string namespaceName = pc.SearchNamespace(name, callingClass, cu, caretLine, caretColumn);
				if (namespaceName != null) {
					return new NamespaceResolveResult(callingClass, callingMember, namespaceName);
				}
				return null;
			} else {
				if (expr.NodeType == AST.NodeType.ReferenceExpression) {
					// this could be a macro
					if (BooProject.BooCompilerPC != null) {
						string name = ((AST.ReferenceExpression)expr).Name;
						IClass c = BooProject.BooCompilerPC.GetClass("Boo.Lang." + char.ToUpper(name[0]) + name.Substring(1) + "Macro");
						if (c != null)
							return new TypeResolveResult(callingClass, callingMember, c);
					}
				}
			}
			
			ResolveVisitor visitor = new ResolveVisitor(this);
			visitor.Visit(expr);
			ResolveResult result = visitor.ResolveResult;
			if (expressionResult.Context == ExpressionContext.Type && result is MixedResolveResult)
				result = (result as MixedResolveResult).TypeResult;
			return result;
		}
		
		public IReturnType ConvertType(AST.TypeReference typeRef)
		{
			return ConvertVisitor.CreateReturnType(typeRef, callingClass, callingMember,
			                                       caretLine, caretColumn, pc);
		}
		
		public IField FindLocalVariable(string name, bool acceptImplicit)
		{
			VariableLookupVisitor vlv = new VariableLookupVisitor(this, name, acceptImplicit);
			vlv.Visit(GetCurrentBooMethod());
			return vlv.Result;
		}
		#endregion
		
		#region CtrlSpace
		static IClass GetPrimitiveClass(IProjectContent pc, string systemType, string newName)
		{
			IClass c = pc.GetClass(systemType);
			if (c == null) {
				LoggingService.Warn("Could not find " + systemType);
				return null;
			}
			DefaultClass c2 = new DefaultClass(c.CompilationUnit, newName);
			c2.ClassType = c.ClassType;
			c2.Modifiers = c.Modifiers;
			c2.Documentation = c.Documentation;
			c2.BaseTypes.AddRange(c.BaseTypes);
			c2.Methods.AddRange(c.Methods);
			c2.Fields.AddRange(c.Fields);
			c2.Properties.AddRange(c.Properties);
			c2.Events.AddRange(c.Events);
			return c2;
		}
		
		public ArrayList CtrlSpace(int caretLine, int caretColumn, string fileName, string fileContent, ExpressionContext context)
		{
			ArrayList result = new ArrayList();
			
			if (!Initialize(fileName, caretLine, caretColumn))
				return null;
			if (context == ExpressionContext.Importable) {
				pc.AddNamespaceContents(result, "", pc.Language, true);
				NRResolver.AddUsing(result, pc.DefaultImports, pc);
				return result;
			}
			
			NRResolver.AddContentsFromCalling(result, callingClass, callingMember);
			AddImportedNamespaceContents(result);
			
			if (BooProject.BooCompilerPC != null) {
				if (context == ExpressionFinder.BooAttributeContext.Instance) {
					foreach (object o in BooProject.BooCompilerPC.GetNamespaceContents("Boo.Lang")) {
						IClass c = o as IClass;
						if (c != null && c.Name.EndsWith("Attribute") && !c.IsAbstract) {
							result.Add(GetPrimitiveClass(BooProject.BooCompilerPC, c.FullyQualifiedName, c.Name.Substring(0, c.Name.Length - 9).ToLowerInvariant()));
						}
					}
				} else {
					foreach (object o in BooProject.BooCompilerPC.GetNamespaceContents("Boo.Lang")) {
						IClass c = o as IClass;
						if (c != null && c.Name.EndsWith("Macro") && !c.IsAbstract) {
							result.Add(GetPrimitiveClass(BooProject.BooCompilerPC, c.FullyQualifiedName, c.Name.Substring(0, c.Name.Length - 5).ToLowerInvariant()));
						}
					}
				}
			}
			
			List<string> knownVariableNames = new List<string>();
			foreach (object o in result) {
				IMember m = o as IMember;
				if (m != null) {
					knownVariableNames.Add(m.Name);
				}
			}
			VariableListLookupVisitor vllv = new VariableListLookupVisitor(knownVariableNames, this);
			vllv.Visit(GetCurrentBooMethod());
			foreach (KeyValuePair<string, IReturnType> entry in vllv.Results) {
				result.Add(new DefaultField.LocalVariableField(entry.Value, entry.Key, DomRegion.Empty, callingClass));
			}
			
			return result;
		}
		
		// used by ctrl+space and resolve visitor (resolve identifier)
		public ArrayList GetImportedNamespaceContents()
		{
			ArrayList result = new ArrayList();
			AddImportedNamespaceContents(result);
			return result;
		}
		
		void AddImportedNamespaceContents(ArrayList list)
		{
			IClass c;
			foreach (KeyValuePair<string, string> pair in BooAmbience.ReverseTypeConversionTable) {
				c = GetPrimitiveClass(pc, pair.Value, pair.Key);
				if (c != null) list.Add(c);
			}
			list.Add(new DuckClass(cu));
			NRResolver.AddImportedNamespaceContents(list, cu, callingClass);
		}
		
		internal class DuckClass : DefaultClass
		{
			public DuckClass(ICompilationUnit cu) : base(cu, "duck")
			{
				Documentation = "Use late-binding to access members of this type.<br/>\n'If it walks like a duck and quacks like a duck, it must be a duck.'";
				Modifiers = ModifierEnum.Public;
			}
			
			protected override IReturnType CreateDefaultReturnType()
			{
				return new DuckReturnType(this);
			}
		}
		
		internal class DuckReturnType : AbstractReturnType
		{
			IClass c;
			public DuckReturnType(IClass c) {
				this.c = c;
				FullyQualifiedName = c.FullyQualifiedName;
			}
			public override IClass GetUnderlyingClass() {
				return c;
			}
			public override List<IMethod> GetMethods() {
				return new List<IMethod>();
			}
			public override List<IProperty> GetProperties() {
				return new List<IProperty>();
			}
			public override List<IField> GetFields() {
				return new List<IField>();
			}
			public override List<IEvent> GetEvents() {
				return new List<IEvent>();
			}
		}
		#endregion
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -