Beispiel #1
0
        /// <summary>
        /// Finds all of the matching type definitions for the return type of this method definition
        /// </summary>
        /// <returns>An enumerable of the matching type definitions for this method</returns>
        public override IEnumerable <TypeDefinition> ResolveType()
        {
            var matchingMethods = FindMatches().OfType <MethodDefinition>().ToList();

            if (matchingMethods.Any())
            {
                foreach (var methodDefinition in matchingMethods)
                {
                    var matchingTypes = Enumerable.Empty <TypeDefinition>();

                    if (methodDefinition.ReturnType != null)
                    {
                        matchingTypes = methodDefinition.ReturnType.ResolveType();
                    }
                    else if (methodDefinition.IsConstructor)
                    {
                        var methodName = methodDefinition.Name; //define local var because of Resharper warning about accessing foreach var in closure
                        matchingTypes = methodDefinition.GetAncestors <TypeDefinition>().Where(td => td.Name == methodName);
                    }
                    foreach (var result in matchingTypes)
                    {
                        yield return(result);
                    }
                }
            }
            else
            {
                //no matches
                //handle case of calls to default (implicit) constructors
                if (IsConstructor && Arguments.Count == 0)
                {
                    var tempType = new TypeUse()
                    {
                        Name                = this.Name,
                        Location            = this.Location,
                        ParentStatement     = this.ParentStatement,
                        ProgrammingLanguage = this.ProgrammingLanguage
                    };
                    foreach (var result in tempType.ResolveType())
                    {
                        yield return(result);
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Finds all of the matching type definitions for the return type of this method definition
        /// </summary>
        /// <returns>An enumerable of the matching type definitions for this method</returns>
        public override IEnumerable<TypeDefinition> ResolveType() {
            var matchingMethods = FindMatches().OfType<MethodDefinition>().ToList();
            if(matchingMethods.Any()) {
                foreach(var methodDefinition in matchingMethods) {
                    var matchingTypes = Enumerable.Empty<TypeDefinition>();

                    if(methodDefinition.ReturnType != null) {
                        matchingTypes = methodDefinition.ReturnType.ResolveType();
                    } else if(methodDefinition.IsConstructor) {
                        var methodName = methodDefinition.Name; //define local var because of Resharper warning about accessing foreach var in closure
                        matchingTypes = methodDefinition.GetAncestors<TypeDefinition>().Where(td => td.Name == methodName);
                    }
                    foreach(var result in matchingTypes) {
                        yield return result;
                    }
                }
            } else {
                //no matches
                //handle case of calls to default (implicit) constructors
                if(IsConstructor && Arguments.Count == 0) {
                    var tempType = new TypeUse() {
                        Name = this.Name, 
                        Location = this.Location,
                        ParentStatement = this.ParentStatement, 
                        ProgrammingLanguage = this.ProgrammingLanguage
                    };
                    foreach(var result in tempType.ResolveType()) {
                        yield return result;
                    }
                }
            }


        }
Beispiel #3
0
        /// <summary>
        /// Finds matching <see cref="MethodDefinition">method definitions</see> for this method call.
        /// This method searches for matches in the ancestor scopes of the call. Because method calls can also be
        /// to constructors and destructors, this will also search for matching types and then
        /// constructors within those types
        /// </summary>
        /// <returns>An enumerable of method definitions that match this method call</returns>
        public override IEnumerable<INamedEntity> FindMatches() {
            if(ParentStatement == null) {
                throw new InvalidOperationException("ParentStatement is null");
            }            

            if(IsConstructor || IsDestructor) {
                List<TypeDefinition> typeDefinitions;
                if(this.Name == "this" ||
                   (this.Name == "base" && this.ProgrammingLanguage == Language.CSharp) ||
                   (this.Name == "super" && this.ProgrammingLanguage == Language.Java)) {
                    typeDefinitions = TypeDefinition.GetTypeForKeyword(this).ToList();
                } else {
                    var tempTypeUse = new TypeUse() {
                        Name = this.Name,
                        ParentStatement = this.ParentStatement,
                        Location = this.Location
                    };
                    typeDefinitions = tempTypeUse.ResolveType().ToList();
                }
                
                //Handle case of C++ constructor initialization lists. 
                //These will be marked as constructor calls. They can be used to initialize fields, though, in which case the call name will be the field name,
                //rather than a type name.
                if(!typeDefinitions.Any() && IsConstructorInitializer && ProgrammingLanguage == Language.CPlusPlus) {
                    var containingType = ParentStatement.GetAncestorsAndSelf<TypeDefinition>().FirstOrDefault();
                    if(containingType != null) {
                        //search this type and its parents for a field matching the name of the call
                        var matchingField = containingType.GetParentTypesAndSelf(true).SelectMany(t => t.GetNamedChildren<VariableDeclaration>(this.Name)).FirstOrDefault();
                        if(matchingField != null) {
                            typeDefinitions = matchingField.VariableType.ResolveType().ToList();
                        }
                    }
                }

                var matchingMethods = from typeDefinition in typeDefinitions
                                      from method in typeDefinition.GetNamedChildren<MethodDefinition>(typeDefinition.Name)
                                      where SignatureMatches(typeDefinition.Name, method)
                                      select method;
                return matchingMethods;
            }

            //If there's a calling expression, resolve and search under the results
            var callingScopes = GetCallingScope();
            if(callingScopes != null) {
                IEnumerable<INamedEntity> matches = Enumerable.Empty<INamedEntity>();
                foreach(var scope in callingScopes) {
                    var localMatches = scope.GetNamedChildren<MethodDefinition>(this.Name).Where(SignatureMatches).ToList();
                    var callingType = scope as TypeDefinition;
                    if(!localMatches.Any() && callingType != null) {
                        //also search under the base types of the calling scope
                        matches = matches.Concat(callingType.SearchParentTypes<MethodDefinition>(this.Name, SignatureMatches));
                    } else {
                        matches = matches.Concat(localMatches);
                    }
                }
                return matches;
            }
            
            //search enclosing scopes and base types for the method
            foreach(var scope in ParentStatement.GetAncestors()) {
                var matches = scope.GetNamedChildren<MethodDefinition>(this).Where(SignatureMatches).ToList();
                if(matches.Any()) {
                    return matches;
                }
                var typeDef = scope as TypeDefinition;
                if(typeDef != null) {
                    //search the base types
                    var baseTypeMatches = typeDef.SearchParentTypes<MethodDefinition>(this.Name, SignatureMatches).ToList();
                    if(baseTypeMatches.Any()) {
                        return baseTypeMatches;
                    }
                }
            }

            //we didn't find it locally, search under imported namespaces
            return (from import in GetImports()
                    from match in import.ImportedNamespace.GetDescendantsAndSelf<NameUse>().Last().FindMatches().OfType<NamedScope>()
                    from child in match.GetNamedChildren<MethodDefinition>(this.Name)
                    where SignatureMatches(child)
                    select child);

        }
Beispiel #4
0
        /// <summary>
        /// Finds matching <see cref="MethodDefinition">method definitions</see> for this method call.
        /// This method searches for matches in the ancestor scopes of the call. Because method calls can also be
        /// to constructors and destructors, this will also search for matching types and then
        /// constructors within those types
        /// </summary>
        /// <returns>An enumerable of method definitions that match this method call</returns>
        public override IEnumerable <INamedEntity> FindMatches()
        {
            if (ParentStatement == null)
            {
                throw new InvalidOperationException("ParentStatement is null");
            }

            if (IsConstructor || IsDestructor)
            {
                List <TypeDefinition> typeDefinitions;
                if (this.Name == "this" ||
                    (this.Name == "base" && this.ProgrammingLanguage == Language.CSharp) ||
                    (this.Name == "super" && this.ProgrammingLanguage == Language.Java))
                {
                    typeDefinitions = TypeDefinition.GetTypeForKeyword(this).ToList();
                }
                else
                {
                    var tempTypeUse = new TypeUse()
                    {
                        Name            = this.Name,
                        ParentStatement = this.ParentStatement,
                        Location        = this.Location
                    };
                    typeDefinitions = tempTypeUse.ResolveType().ToList();
                }

                //Handle case of C++ constructor initialization lists.
                //These will be marked as constructor calls. They can be used to initialize fields, though, in which case the call name will be the field name,
                //rather than a type name.
                if (!typeDefinitions.Any() && IsConstructorInitializer && ProgrammingLanguage == Language.CPlusPlus)
                {
                    var containingType = ParentStatement.GetAncestorsAndSelf <TypeDefinition>().FirstOrDefault();
                    if (containingType != null)
                    {
                        //search this type and its parents for a field matching the name of the call
                        var matchingField = containingType.GetParentTypesAndSelf(true).SelectMany(t => t.GetNamedChildren <VariableDeclaration>(this.Name)).FirstOrDefault();
                        if (matchingField != null)
                        {
                            typeDefinitions = matchingField.VariableType.ResolveType().ToList();
                        }
                    }
                }

                var matchingMethods = from typeDefinition in typeDefinitions
                                      from method in typeDefinition.GetNamedChildren <MethodDefinition>(typeDefinition.Name)
                                      where SignatureMatches(typeDefinition.Name, method)
                                      select method;
                return(matchingMethods);
            }

            //If there's a calling expression, resolve and search under the results
            var callingScopes = GetCallingScope();

            if (callingScopes != null)
            {
                IEnumerable <INamedEntity> matches = Enumerable.Empty <INamedEntity>();
                foreach (var scope in callingScopes)
                {
                    var localMatches = scope.GetNamedChildren <MethodDefinition>(this.Name).Where(SignatureMatches).ToList();
                    var callingType  = scope as TypeDefinition;
                    if (!localMatches.Any() && callingType != null)
                    {
                        //also search under the base types of the calling scope
                        matches = matches.Concat(callingType.SearchParentTypes <MethodDefinition>(this.Name, SignatureMatches));
                    }
                    else
                    {
                        matches = matches.Concat(localMatches);
                    }
                }
                return(matches);
            }

            //search enclosing scopes and base types for the method
            foreach (var scope in ParentStatement.GetAncestors())
            {
                var matches = scope.GetNamedChildren <MethodDefinition>(this).Where(SignatureMatches).ToList();
                if (matches.Any())
                {
                    return(matches);
                }
                var typeDef = scope as TypeDefinition;
                if (typeDef != null)
                {
                    //search the base types
                    var baseTypeMatches = typeDef.SearchParentTypes <MethodDefinition>(this.Name, SignatureMatches).ToList();
                    if (baseTypeMatches.Any())
                    {
                        return(baseTypeMatches);
                    }
                }
            }

            //we didn't find it locally, search under imported namespaces
            return(from import in GetImports()
                   from match in import.ImportedNamespace.GetDescendantsAndSelf <NameUse>().Last().FindMatches().OfType <NamedScope>()
                   from child in match.GetNamedChildren <MethodDefinition>(this.Name)
                   where SignatureMatches(child)
                   select child);
        }
Beispiel #5
0
        /// <summary>
        /// If there is a calling expession preceding this NameUse, this method resolves it
        /// to determine the scope(s) in which to search for the use's name.
        /// </summary>
        /// <returns>An enumerable of the named entities that may contain the name being used in this NameUse.
        /// Returns null if there is no suitable calling expression.
        /// Returns an empty enumerable if there is a calling expression, but no matches are found.</returns>
        protected IEnumerable <NamedScope> GetCallingScope()
        {
            var siblings = GetSiblingsBeforeSelf().ToList();
            var priorOp  = siblings.LastOrDefault() as OperatorUse;

            if (priorOp == null || !NameInclusionOperators.Contains(priorOp.Text))
            {
                return(null);
            }

            if (siblings.Count == 1)
            {
                //This use is preceded by a name inclusion operator and nothing else
                //this is probably only possible in C++: ::MyGlobalClass
                //just return the global namespace
                return(ParentStatement.GetAncestorsAndSelf <NamespaceDefinition>().Where(n => n.IsGlobal));
            }

            var callingExp  = siblings[siblings.Count - 2]; //second-to-last sibling
            var callingName = callingExp as NameUse;

            if (callingName == null)
            {
                //Not a NameUse, probably an Expression
                return(callingExp.ResolveType());
            }

            var matches = callingName.FindMatches();
            var scopes  = new List <NamedScope>();

            foreach (var match in matches)
            {
                //TODO: update this to use polymorphism
                if (match is MethodDefinition)
                {
                    var method = match as MethodDefinition;
                    if (method.ReturnType != null)
                    {
                        scopes.AddRange(((MethodDefinition)match).ReturnType.ResolveType());
                    }
                    else if (method.IsConstructor)
                    {
                        //create the constructor return type
                        var tempTypeUse = new TypeUse()
                        {
                            Name            = method.Name,
                            ParentStatement = method.ParentStatement,
                            Location        = method.PrimaryLocation
                        };
                        scopes.AddRange(tempTypeUse.ResolveType());
                    }
                }
                else if (match is PropertyDefinition)
                {
                    scopes.AddRange(((PropertyDefinition)match).ReturnType.ResolveType());
                }
                else if (match is VariableDeclaration)
                {
                    scopes.AddRange(((VariableDeclaration)match).VariableType.ResolveType());
                }
                else
                {
                    //the only other possibilities are all NamedScopes
                    scopes.Add((NamedScope)match);
                }
            }
            if (scopes.Count == 0)
            {
                return(null);
            }
            else
            {
                return(scopes);
            }
        }
Beispiel #6
0
        /// <summary>
        /// If there is a calling expession preceding this NameUse, this method resolves it
        /// to determine the scope(s) in which to search for the use's name.
        /// </summary>
        /// <returns>An enumerable of the named entities that may contain the name being used in this NameUse.
        /// Returns null if there is no suitable calling expression.
        /// Returns an empty enumerable if there is a calling expression, but no matches are found.</returns>
        protected IEnumerable<NamedScope> GetCallingScope() {
            var siblings = GetSiblingsBeforeSelf().ToList();
            var priorOp = siblings.LastOrDefault() as OperatorUse;
            if(priorOp == null || !NameInclusionOperators.Contains(priorOp.Text)) {
                return null;
            }

            if(siblings.Count == 1) {
                //This use is preceded by a name inclusion operator and nothing else
                //this is probably only possible in C++: ::MyGlobalClass
                //just return the global namespace
                return ParentStatement.GetAncestorsAndSelf<NamespaceDefinition>().Where(n => n.IsGlobal);
            }

            var callingExp = siblings[siblings.Count - 2]; //second-to-last sibling
            var callingName = callingExp as NameUse;
            if(callingName == null) {
                //Not a NameUse, probably an Expression
                return callingExp.ResolveType();
            }

            var matches = callingName.FindMatches();
            var scopes = new List<NamedScope>();
            foreach(var match in matches) {
                //TODO: update this to use polymorphism
                if(match is MethodDefinition) {
                    var method = match as MethodDefinition;
                    if(method.ReturnType != null) {
                        scopes.AddRange(((MethodDefinition)match).ReturnType.ResolveType());
                    } else if(method.IsConstructor) {
                        //create the constructor return type
                        var tempTypeUse = new TypeUse() {
                            Name = method.Name,
                            ParentStatement = method.ParentStatement,
                            Location = method.PrimaryLocation
                        };
                        scopes.AddRange(tempTypeUse.ResolveType());
                    } 
                } else if(match is PropertyDefinition) {
                    scopes.AddRange(((PropertyDefinition)match).ReturnType.ResolveType());
                } else if(match is VariableDeclaration) {
                    scopes.AddRange(((VariableDeclaration)match).VariableType.ResolveType());
                } else {
                    //the only other possibilities are all NamedScopes
                    scopes.Add((NamedScope)match);
                }
            }
            return scopes;
        }