Example #1
0
        private void AnalyzeTypeReference([CanBeNull] ITypeNode type)
        {
            if (type == null || type.IsPredefinedType())
            {
                return;
            }

            // Checking for named types like:
            // let n: CustomInterface = undefined;
            //        ~~~~~~~~~~~~~~~
            var typeReferenceNode = type.As <ITypeReferenceNode>();

            if (typeReferenceNode != null)
            {
                EntityName entityName = typeReferenceNode.TypeName;
                AnalyzeTypeReference(entityName);

                AnalyzeTypeArguments(typeReferenceNode.TypeArguments);
            }

            // Checking for typed literals like:
            // let n: {x: number, y: number} = {x: 1, y: 3};
            //        ~~~~~~~~~~~~~~~~~~~~~~
            var typeLiteralNode = type.As <ITypeLiteralNode>();

            if (typeLiteralNode != null)
            {
                // Don't need to register names, because it is not a real interface declaration.
                AnalyzeInterfaceMembers(typeLiteralNode.Members, registerPropertyNames: false);
            }

            // Check for array types like:
            // let n: number[] = [1,2];
            //        ~~~~~~~~
            var arrayTypeNode = type.As <IArrayTypeNode>();

            if (arrayTypeNode != null)
            {
                AnalyzeTypeReference(arrayTypeNode.ElementType);
            }

            // Check for function types like:
            // function foo(): () => number {}
            //                 ~~~~~~~~~~~~
            var functionType = type.As <IFunctionOrConstructorTypeNode>();

            if (functionType != null)
            {
                AnalyzeParameters(functionType.Parameters);
                AnalyzeTypeReference(functionType.Type);
                AnalyzeTypeParameters(functionType.TypeParameters);
            }

            // Check for parenthesized types like:
            // function foo(): (() => number)[] {return [];}
            //                 ~~~~~~~~~~~~~~~~
            var parenthesizedType = type.As <IParenthesizedTypeNode>();

            if (parenthesizedType != null)
            {
                AnalyzeTypeReference(parenthesizedType.Type);
            }

            // Checking for union types like:
            // type X = string | number;
            //          ~~~~~~~~~~~~~~~
            var unionType = type.As <IUnionTypeNode>();

            if (unionType != null)
            {
                foreach (var t in unionType.Types)
                {
                    AnalyzeTypeReference(t);
                }
            }

            // Checking for tuple types like:
            // type X = [1, 2];
            //          ~~~~~~~~~~~~~~~
            var tupleType = type.As <ITupleTypeNode>();

            if (tupleType != null)
            {
                foreach (var t in tupleType.ElementTypes)
                {
                    AnalyzeTypeReference(t);
                }
            }

            // Checking for type query like:
            // type X = typeof anIdentifier;
            //          ~~~~~~~~~~~~~~~
            var typeQueryType = type.As <ITypeQueryNode>();

            if (typeQueryType != null)
            {
                var entityName = typeQueryType.ExprName;
                AnalyzeTypeReference(entityName);
            }
        }
Example #2
0
        private bool IsTypeAccessible(ITypeNode type)
        {
            // type not declared --> treat it as accessible
            if (type == null)
            {
                return(true);
            }

            // predefined types are always accessible
            if (type.IsPredefinedType())
            {
                return(true);
            }

            // descend into ParenthesizedType
            if (type.Kind == TypeScript.Net.Types.SyntaxKind.ParenthesizedType)
            {
                return(IsTypeAccessible(type.Cast <IParenthesizedTypeNode>().Type));
            }

            // an array type is accessible iff its element type is accessible
            if (type.Kind == TypeScript.Net.Types.SyntaxKind.ArrayType)
            {
                return(IsTypeAccessible(type.Cast <IArrayTypeNode>().ElementType));
            }

            // a union type is accessible iff all its types are accessible
            if (type.Kind == TypeScript.Net.Types.SyntaxKind.UnionType)
            {
                return(type.Cast <IUnionOrIntersectionTypeNode>().Types.All(t => IsTypeAccessible(t)));
            }

            // a function type is accessible iff its return type and its type parameters are accessible
            if (type.Kind == TypeScript.Net.Types.SyntaxKind.FunctionType)
            {
                var fnType       = type.Cast <IFunctionOrConstructorTypeNode>();
                var fnParameters = fnType.Parameters ?? NodeArray.Empty <IParameterDeclaration>();
                return
                    (IsTypeAccessible(fnType.Type) &&
                     fnParameters.All(tp => IsTypeAccessible(tp.Type)));
            }

            // a type literal is accessible iff all its members are accessible
            if (type.Kind == TypeScript.Net.Types.SyntaxKind.TypeLiteral)
            {
                return(type.Cast <ITypeLiteralNode>().Members.All(m => IsMemberAccessible(m)));

                bool IsMemberAccessible(ITypeElement e)
                {
                    var memberTypes = e.Kind == TypeScript.Net.Types.SyntaxKind.PropertySignature
                        ? new[] { e.Cast <IPropertySignature>().Type }
                        : null; // handle other kinds if needed

                    return(memberTypes != null && memberTypes.All(t => IsTypeAccessible(t)));
                }
            }

            // if any type argument is inaccessible, this type is not accessible either
            var typeArguments = type.GetTypeArguments();

            if (!typeArguments.All(t => IsTypeAccessible(t)))
            {
                return(false);
            }

            // if this type couldn't be resolved, treat it as inaccessible
            var resolvedSymbol = type.ResolvedSymbol;

            if (resolvedSymbol == null)
            {
                return(false);
            }

            // otherwise, a type is accessible if any of its declarations is either explicitly exported or defined in the prelude
            return(resolvedSymbol
                   .GetDeclarations()
                   .Any(d =>
                        d.IsExported() ||
                        m_semanticModel.TypeChecker.IsPreludeDeclaration(d)));
        }