public static ArgumentsResolutionResult ResolveArgumentContext( string code, int caretOffset, CodeLocation caretLocation, DMethod MethodScope, IEnumerable<IAbstractSyntaxTree> parseCache, IEnumerable<IAbstractSyntaxTree> ImportCache) { var ctxt = new ResolverContext { ScopedBlock = MethodScope, ParseCache = parseCache, ImportCache=ImportCache }; #region Parse the code between the last block opener and the caret var curMethodBody = MethodScope.GetSubBlockAt(caretLocation); if (curMethodBody == null && MethodScope.Parent is DMethod) { MethodScope = MethodScope.Parent as DMethod; curMethodBody = MethodScope.GetSubBlockAt(caretLocation); } if (curMethodBody == null) return null; var blockOpenerLocation = curMethodBody.StartLocation; var blockOpenerOffset = blockOpenerLocation.Line <= 0 ? blockOpenerLocation.Column : DocumentHelper.LocationToOffset(code, blockOpenerLocation); if (blockOpenerOffset >= 0 && caretOffset - blockOpenerOffset > 0) { var codeToParse = code.Substring(blockOpenerOffset, caretOffset - blockOpenerOffset); curMethodBody = DParser.ParseBlockStatement(codeToParse, blockOpenerLocation, MethodScope); if (curMethodBody != null) ctxt.ScopedStatement = curMethodBody.SearchStatementDeeply(caretLocation); } if (curMethodBody == null || ctxt.ScopedStatement == null) return null; #endregion // Scan statement for method calls or template instantiations var e = DResolver.SearchForMethodCallsOrTemplateInstances(ctxt.ScopedStatement, caretLocation); /* * 1) foo( -- normal arguments only * 2) foo!(...)( -- normal arguments + template args * 3) foo!( -- template args only * 4) new myclass( -- ctor call * 5) new myclass!( -- ditto * 6) new myclass!(...)( * 7) mystruct( -- opCall call */ var res = new ArgumentsResolutionResult() { ParsedExpression = e }; ITypeDeclaration methodIdentifier = null; // 1), 2) if (e is PostfixExpression_MethodCall) { res.IsMethodArguments = true; var call = e as PostfixExpression_MethodCall; if (call.Arguments != null) { int i = 0; foreach (var arg in call.Arguments) { if (caretLocation >= arg.Location && caretLocation <= arg.EndLocation) { res.CurrentlyTypedArgumentIndex = i; break; } i++; } } methodIdentifier = call.PostfixForeExpression.ExpressionTypeRepresentation; } // 3) else if (e is TemplateInstanceExpression) { var templ = e as TemplateInstanceExpression; res.IsTemplateInstanceArguments = true; if (templ.Arguments != null) { int i = 0; foreach (var arg in templ.Arguments) { if (caretLocation >= arg.Location && caretLocation <= arg.EndLocation) { res.CurrentlyTypedArgumentIndex = i; break; } i++; } } methodIdentifier = new IdentifierDeclaration(templ.TemplateIdentifier.Value) { InnerDeclaration=templ.InnerDeclaration }; } else if (e is NewExpression) { var ne = e as NewExpression; if (ne.Arguments != null) { int i = 0; foreach (var arg in ne.Arguments) { if (caretLocation >= arg.Location && caretLocation <= arg.EndLocation) { res.CurrentlyTypedArgumentIndex = i; break; } i++; } } methodIdentifier = ne.ExpressionTypeRepresentation; } if (methodIdentifier == null) return null; // Resolve all types, methods etc. which belong to the methodIdentifier res.ResolvedTypesOrMethods = ResolveType(methodIdentifier, ctxt); if (res.ResolvedTypesOrMethods == null) return res; // 4),5),6) if (e is NewExpression) { var substitutionList = new List<ResolveResult>(); foreach (var rr in res.ResolvedTypesOrMethods) if (rr is TypeResult) { var classDef = (rr as TypeResult).ResolvedTypeDefinition as DClassLike; if (classDef == null) continue; //TODO: Regard protection attributes for ctor members foreach (var i in classDef) if (i is DMethod && (i as DMethod).SpecialType == DMethod.MethodType.Constructor) substitutionList.Add(HandleNodeMatch(i, ctxt, resultBase: rr)); } if (substitutionList.Count > 0) res.ResolvedTypesOrMethods = substitutionList.ToArray(); } // 7) else if (e is PostfixExpression_MethodCall) { var substitutionList = new List<ResolveResult>(); var nonAliases=TryRemoveAliasesFromResult(res.ResolvedTypesOrMethods); foreach (var rr in nonAliases) if (rr is TypeResult) { var classDef = (rr as TypeResult).ResolvedTypeDefinition as DClassLike; if (classDef == null) continue; //TODO: Regard protection attributes for opCall members foreach (var i in classDef) if (i is DMethod && i.Name == "opCall") substitutionList.Add(HandleNodeMatch(i, ctxt, resultBase: rr)); } if (substitutionList.Count > 0) nonAliases = substitutionList.ToArray(); res.ResolvedTypesOrMethods = nonAliases; } return res; }
/// <summary> /// Parses the code between the start of the parent method's block and the given caret location. /// </summary> /// <returns>Returns the deepest Statement that exists in the statement hierarchy.</returns> public static IStatement ParseBlockStatementUntilCaret(string code, DMethod MethodParent, int caretOffset, CodeLocation caretLocation) { //HACK: Clear anonymous decl array to ensure that no duplicates occur when calling DParser.ParseBlockStatement() MethodParent.AdditionalChildren.Clear(); var oldBlock = MethodParent.GetSubBlockAt(caretLocation); if (oldBlock == null) return null; var blockOpenerLocation = oldBlock.StartLocation; var blockOpenerOffset = blockOpenerLocation.Line <= 0 ? blockOpenerLocation.Column : DocumentHelper.LocationToOffset(code, blockOpenerLocation); if (blockOpenerOffset >= 0 && caretOffset - blockOpenerOffset > 0) { var codeToParse = code.Substring(blockOpenerOffset, caretOffset - blockOpenerOffset); /* * So, if we're inside of a method, we parse all its 'contents' (statements, expressions, declarations etc.) * to achieve a fully updated insight. */ var newStmt = DParser.ParseBlockStatement(codeToParse, blockOpenerLocation, MethodParent); var ret = newStmt.SearchStatementDeeply(caretLocation); return ret == null ? newStmt : ret; } return null; }