@@ -85,7 +85,7 @@ function hasVarArgs(parameters: ts.ParameterDeclaration[]): boolean {
85
85
* }
86
86
* Path: m1.m2.foo
87
87
*/
88
- function fullJsPath ( node : base . NamedDeclaration ) : string {
88
+ function fullJsPath ( node : ts . NamedDeclaration ) : string {
89
89
const parts : Array < string > = [ base . ident ( node . name ) ] ;
90
90
let p : ts . Node = node . parent ;
91
91
while ( p != null ) {
@@ -131,7 +131,7 @@ export class NameRewriter {
131
131
132
132
constructor ( private fc : FacadeConverter ) { }
133
133
134
- private computeName ( node : base . NamedDeclaration ) : DartNameRecord {
134
+ private computeName ( node : ts . NamedDeclaration ) : DartNameRecord {
135
135
const fullPath = fullJsPath ( node ) ;
136
136
if ( this . dartTypes . has ( fullPath ) ) {
137
137
return this . dartTypes . get ( fullPath ) ;
@@ -178,7 +178,7 @@ export class NameRewriter {
178
178
}
179
179
}
180
180
181
- lookupName ( node : base . NamedDeclaration , context : ts . Node ) {
181
+ lookupName ( node : ts . NamedDeclaration , context : ts . Node ) {
182
182
let name = this . computeName ( node ) . name ;
183
183
return this . fc . resolveImportForSourceFile ( node . getSourceFile ( ) , context . getSourceFile ( ) , name ) ;
184
184
}
@@ -610,52 +610,83 @@ export class FacadeConverter extends base.TranspilerBase {
610
610
}
611
611
}
612
612
613
+ replaceNode ( original : ts . Node , replacement : ts . Node ) {
614
+ if ( ts . isVariableDeclaration ( original ) && ts . isClassDeclaration ( replacement ) ) {
615
+ // Handle the speical case in mergeVariablesIntoClasses where we upgrade variable declarations
616
+ // to classes.
617
+ const symbol = this . tc . getSymbolAtLocation ( original . name ) ;
618
+ symbol . declarations = symbol . getDeclarations ( ) . map ( ( declaration : ts . Declaration ) => {
619
+ // TODO(derekx): Changing the declarations of a symbol like this is a hack. It would be
620
+ // cleaner and safer to generate a new Program and TypeChecker after performing
621
+ // gatherClasses and mergeVariablesIntoClasses.
622
+ if ( declaration === original ) {
623
+ return replacement ;
624
+ }
625
+ return declaration ;
626
+ } ) ;
627
+ }
628
+
629
+ super . replaceNode ( original , replacement ) ;
630
+ }
631
+
613
632
getSymbolAtLocation ( identifier : ts . EntityName ) {
614
633
let symbol = this . tc . getSymbolAtLocation ( identifier ) ;
615
634
while ( symbol && symbol . flags & ts . SymbolFlags . Alias ) symbol = this . tc . getAliasedSymbol ( symbol ) ;
616
635
return symbol ;
617
636
}
618
637
619
- getSymbolDeclaration ( symbol : ts . Symbol , n ?: ts . Node ) : ts . Declaration {
620
- if ( ! symbol || this . tc . isUnknownSymbol ( symbol ) ) return null ;
621
- let decl = symbol . valueDeclaration ;
622
- if ( ! decl ) {
623
- // In the case of a pure declaration with no assignment, there is no value declared.
624
- // Just grab the first declaration, hoping it is declared once.
625
- if ( ! symbol . declarations || symbol . declarations . length === 0 ) {
626
- this . reportError ( n , 'no declarations for symbol ' + symbol . name ) ;
627
- return ;
628
- }
629
- decl = symbol . declarations [ 0 ] ;
638
+ getValueDeclarationOfSymbol ( symbol : ts . Symbol , n ?: ts . Node ) : ts . Declaration | undefined {
639
+ if ( ! symbol || this . tc . isUnknownSymbol ( symbol ) ) {
640
+ return undefined ;
641
+ }
642
+ if ( ! symbol . valueDeclaration ) {
643
+ this . reportError ( n , `no value declaration for symbol ${ symbol . name } ` ) ;
644
+ return undefined ;
630
645
}
631
- return decl ;
646
+ return symbol . valueDeclaration ;
647
+ }
648
+
649
+ getTypeDeclarationOfSymbol ( symbol : ts . Symbol , n ?: ts . Node ) : ts . Declaration | undefined {
650
+ if ( ! symbol || this . tc . isUnknownSymbol ( symbol ) ) {
651
+ return undefined ;
652
+ }
653
+ const typeDeclaration = symbol . declarations . find ( ( declaration : ts . Declaration ) => {
654
+ return ts . isInterfaceDeclaration ( declaration ) || ts . isClassDeclaration ( declaration ) ||
655
+ ts . isTypeAliasDeclaration ( declaration ) || ts . isTypeParameterDeclaration ( declaration ) ;
656
+ } ) ;
657
+ if ( ! typeDeclaration ) {
658
+ this . reportError ( n , `no type declarations for symbol ${ symbol . name } ` ) ;
659
+ return undefined ;
660
+ }
661
+ return typeDeclaration ;
632
662
}
633
663
634
664
generateDartName ( identifier : ts . EntityName , options : TypeDisplayOptions ) : string {
635
- let ret = this . lookupCustomDartTypeName ( identifier , options ) ;
636
- if ( ret ) return base . formatType ( ret . name , ret . comment , options ) ;
665
+ const ret = this . lookupCustomDartTypeName ( identifier , options ) ;
666
+ if ( ret ) {
667
+ return base . formatType ( ret . name , ret . comment , options ) ;
668
+ }
637
669
// TODO(jacobr): handle library import prefixes more robustly. This generally works but is
638
670
// fragile.
639
671
return this . maybeAddTypeArguments ( base . ident ( identifier ) , options ) ;
640
672
}
641
673
642
674
/**
643
- * Returns null if declaration cannot be found or is not valid in Dart.
675
+ * Resolves TypeReferences to find the declaration of the referenced type that matches the
676
+ * predicate.
677
+ *
678
+ * For example, if the type passed is a reference to X and the predicate passed is
679
+ * ts.isInterfaceDeclaration, then this function will will return the declaration of interface X,
680
+ * or undefined if there is no such declaration.
644
681
*/
645
- getDeclaration ( identifier : ts . EntityName ) : ts . Declaration {
646
- let symbol : ts . Symbol ;
647
-
648
- symbol = this . getSymbolAtLocation ( identifier ) ;
649
-
650
- let declaration = this . getSymbolDeclaration ( symbol , identifier ) ;
651
- if ( symbol && symbol . flags & ts . SymbolFlags . TypeParameter ) {
652
- let kind = declaration . parent . kind ;
653
- // Only kinds of TypeParameters supported by Dart.
654
- if ( kind !== ts . SyntaxKind . ClassDeclaration && kind !== ts . SyntaxKind . InterfaceDeclaration ) {
655
- return null ;
656
- }
682
+ getDeclarationOfReferencedType (
683
+ type : ts . TypeReferenceNode ,
684
+ predicate : ( declaration : ts . Declaration ) => boolean ) : ts . Declaration {
685
+ const referenceSymbol = this . tc . getTypeAtLocation ( type . typeName ) . getSymbol ( ) ;
686
+ if ( ! referenceSymbol ) {
687
+ return undefined ;
657
688
}
658
- return declaration ;
689
+ return referenceSymbol . getDeclarations ( ) . find ( predicate ) ;
659
690
}
660
691
661
692
maybeAddTypeArguments ( name : string , options : TypeDisplayOptions ) : string {
@@ -667,8 +698,7 @@ export class FacadeConverter extends base.TranspilerBase {
667
698
}
668
699
669
700
/**
670
- * Returns a custom Dart type name or null if the type isn't a custom Dart
671
- * type.
701
+ * Returns a custom Dart type name or null if the type isn't a custom Dart type.
672
702
*/
673
703
lookupCustomDartTypeName ( identifier : ts . EntityName , options ?: TypeDisplayOptions ) :
674
704
{ name ?: string , comment ?: string , keep ?: boolean } {
@@ -678,23 +708,22 @@ export class FacadeConverter extends base.TranspilerBase {
678
708
insideTypeArgument : this . insideTypeArgument
679
709
} ;
680
710
}
681
- let ident = base . ident ( identifier ) ;
711
+ const ident = base . ident ( identifier ) ;
682
712
if ( ident === 'Promise' && this . emitPromisesAsFutures ) {
683
713
return { name : this . maybeAddTypeArguments ( 'Future' , options ) } ;
684
714
}
685
- let symbol : ts . Symbol = this . getSymbolAtLocation ( identifier ) ;
686
- let declaration = this . getSymbolDeclaration ( symbol , identifier ) ;
715
+ const symbol : ts . Symbol = this . getSymbolAtLocation ( identifier ) ;
687
716
if ( symbol && symbol . flags & ts . SymbolFlags . TypeParameter ) {
688
- let kind = declaration . parent . kind ;
717
+ const parent = this . getTypeDeclarationOfSymbol ( symbol ) . parent ;
689
718
if ( options . resolvedTypeArguments && options . resolvedTypeArguments . has ( ident ) ) {
690
719
return {
691
720
name : this . generateDartTypeName (
692
721
options . resolvedTypeArguments . get ( ident ) , removeResolvedTypeArguments ( options ) )
693
722
} ;
694
723
}
695
724
// Only kinds of TypeParameters supported by Dart.
696
- if ( kind !== ts . SyntaxKind . ClassDeclaration && kind !== ts . SyntaxKind . InterfaceDeclaration &&
697
- kind !== ts . SyntaxKind . TypeAliasDeclaration ) {
725
+ if ( ! ts . isClassDeclaration ( parent ) && ! ts . isInterfaceDeclaration ( parent ) &&
726
+ ! ts . isTypeAliasDeclaration ( parent ) ) {
698
727
return { name : 'dynamic' , comment : ident } ;
699
728
}
700
729
}
@@ -704,7 +733,7 @@ export class FacadeConverter extends base.TranspilerBase {
704
733
return null ;
705
734
}
706
735
707
- let fileAndName = this . getFileAndName ( identifier , symbol ) ;
736
+ const fileAndName = this . getFileAndName ( identifier , symbol ) ;
708
737
709
738
if ( fileAndName ) {
710
739
let fileSubs = TS_TO_DART_TYPENAMES . get ( fileAndName . fileName ) ;
@@ -727,6 +756,8 @@ export class FacadeConverter extends base.TranspilerBase {
727
756
}
728
757
}
729
758
}
759
+
760
+ const declaration = this . getTypeDeclarationOfSymbol ( symbol , identifier ) ;
730
761
if ( declaration ) {
731
762
if ( symbol . flags & ts . SymbolFlags . Enum ) {
732
763
// We can't treat JavaScript enums as Dart enums in this case.
@@ -738,8 +769,7 @@ export class FacadeConverter extends base.TranspilerBase {
738
769
if ( supportedDeclaration ) {
739
770
return {
740
771
name : this . maybeAddTypeArguments (
741
- this . nameRewriter . lookupName ( < base . NamedDeclaration > declaration , identifier ) ,
742
- options ) ,
772
+ this . nameRewriter . lookupName ( declaration , identifier ) , options ) ,
743
773
keep : true
744
774
} ;
745
775
}
@@ -751,13 +781,10 @@ export class FacadeConverter extends base.TranspilerBase {
751
781
} ;
752
782
}
753
783
754
- let kind = declaration . kind ;
755
- if ( kind === ts . SyntaxKind . ClassDeclaration || kind === ts . SyntaxKind . InterfaceDeclaration ||
756
- kind === ts . SyntaxKind . VariableDeclaration ||
757
- kind === ts . SyntaxKind . PropertyDeclaration ||
758
- kind === ts . SyntaxKind . FunctionDeclaration ) {
759
- let name = this . nameRewriter . lookupName ( < base . NamedDeclaration > declaration , identifier ) ;
760
- if ( kind === ts . SyntaxKind . InterfaceDeclaration &&
784
+ if ( ts . isClassDeclaration ( declaration ) || ts . isInterfaceDeclaration ( declaration ) ||
785
+ ts . isTypeAliasDeclaration ( declaration ) ) {
786
+ const name = this . nameRewriter . lookupName ( declaration , identifier ) ;
787
+ if ( ts . isInterfaceDeclaration ( declaration ) &&
761
788
base . isFunctionTypedefLikeInterface ( < ts . InterfaceDeclaration > declaration ) &&
762
789
base . getAncestor ( identifier , ts . SyntaxKind . HeritageClause ) ) {
763
790
// TODO(jacobr): we need to specify a specific call method for this
@@ -770,6 +797,32 @@ export class FacadeConverter extends base.TranspilerBase {
770
797
return null ;
771
798
}
772
799
800
+ /**
801
+ * Looks up an identifier that is used as the name of a value (variable or function). Uses the
802
+ * name rewriter to fix naming conflicts.
803
+ *
804
+ * Returns the original name if it doesn't cause any conflicts, otherwise returns a renamed
805
+ * identifier.
806
+ */
807
+ lookupDartValueName ( identifier : ts . Identifier , options ?: TypeDisplayOptions ) :
808
+ { name ?: string , comment ?: string , keep ?: boolean } {
809
+ if ( ! options ) {
810
+ options = {
811
+ insideComment : this . insideCodeComment ,
812
+ insideTypeArgument : this . insideTypeArgument
813
+ } ;
814
+ }
815
+ const symbol : ts . Symbol = this . getSymbolAtLocation ( identifier ) ;
816
+ const declaration = this . getValueDeclarationOfSymbol ( symbol , identifier ) ;
817
+ if ( declaration ) {
818
+ if ( ts . isVariableDeclaration ( declaration ) || ts . isPropertyDeclaration ( declaration ) ||
819
+ ts . isFunctionDeclaration ( declaration ) ) {
820
+ const name = this . nameRewriter . lookupName ( declaration , identifier ) ;
821
+ return { name : this . maybeAddTypeArguments ( name , options ) , keep : true } ;
822
+ }
823
+ }
824
+ }
825
+
773
826
// TODO(jacobr): performance of this method could easily be optimized.
774
827
/**
775
828
* This method works around the lack of Dart support for union types
@@ -837,7 +890,7 @@ export class FacadeConverter extends base.TranspilerBase {
837
890
// TODO(jacobr): property need to prefix the name better.
838
891
referenceType . typeName = this . createEntityName ( symbol ) ;
839
892
referenceType . typeName . parent = referenceType ;
840
- let decl = this . getSymbolDeclaration ( symbol ) ;
893
+ const decl = this . getTypeDeclarationOfSymbol ( symbol ) ;
841
894
base . copyLocation ( decl , referenceType ) ;
842
895
return referenceType ;
843
896
}
@@ -855,7 +908,7 @@ export class FacadeConverter extends base.TranspilerBase {
855
908
// that is a typedef like interface causes the typescript compiler to stack
856
909
// overflow. Not sure if this is a bug in the typescript compiler or I am
857
910
// missing something obvious.
858
- let declaration = base . getDeclaration ( type ) as ts . InterfaceDeclaration ;
911
+ const declaration = this . getTypeDeclarationOfSymbol ( type . symbol ) as ts . InterfaceDeclaration ;
859
912
if ( base . isFunctionTypedefLikeInterface ( declaration ) ) {
860
913
return [ ] ;
861
914
}
@@ -923,7 +976,7 @@ export class FacadeConverter extends base.TranspilerBase {
923
976
private getFileAndName ( n : ts . Node , originalSymbol : ts . Symbol ) : { fileName : string , qname : string } {
924
977
let symbol = originalSymbol ;
925
978
while ( symbol . flags & ts . SymbolFlags . Alias ) symbol = this . tc . getAliasedSymbol ( symbol ) ;
926
- let decl = this . getSymbolDeclaration ( symbol , n ) ;
979
+ const decl = this . getTypeDeclarationOfSymbol ( symbol , n ) ;
927
980
928
981
const fileName = decl . getSourceFile ( ) . fileName ;
929
982
const canonicalFileName = this . getRelativeFileName ( fileName )
0 commit comments