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); } }
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))); }