@@ -519,9 +519,66 @@ public static SourceFile fromCode(String fileName, String code) {
519
519
return builder ().withPath (fileName ).withContent (code ).build ();
520
520
}
521
521
522
+ /**
523
+ * Reconciles serialized state in a {@link SourceFileProto} with the existing state in this file.
524
+ *
525
+ * <p>This should be called whenever initializing a compilation based on TypedAST protos. For
526
+ * these compilations, the compiler initalization methods require creating SourceFiles before
527
+ * deserializing TypedAST protos, so we sometimes get two copies of the same SourceFile.)
528
+ */
529
+ public void restoreCachedStateFrom (SourceFileProto protoSourceFile ) {
530
+ checkState (
531
+ protoSourceFile .getFilename ().equals (this .getName ()),
532
+ "Cannot restore state for %s from %s" ,
533
+ this .getName (),
534
+ protoSourceFile .getFilename ());
535
+ // TypedAST proto information is expected to be more accurate for:
536
+ // 1) whether a SourceFile contains an @extern annotation or not. In non-TypedAST
537
+ // builds, we allow passing @extern files under the --js flag. For TypedAST builds, we
538
+ // could support this, but it's an uncommon pattern and trickier to support than ban.
539
+ // 2) tracking some extra state that is lazily computed in a SourceFile, like the number of
540
+ // lines and bytes in a file. SourceFile::restoreCachedStateFrom handles this case.
541
+ // Note: the state in the proto might be incorrect in other cases, since some state cannot be
542
+ // computed during library-level typechecking (e.g. what files are in the weak chunk)
543
+ if (protoSourceFile .getSourceKind () == SourceFileProto .SourceKind .EXTERN ) {
544
+ checkState (
545
+ this .getKind () == SourceKind .EXTERN ,
546
+ "TypedAST compilations must pass all extern files as externs, not js, but found %s" ,
547
+ this .getName ());
548
+ }
549
+
550
+ // Restore the number of lines/bytes from the proto, unless we already have cached
551
+ // numLines and numBytes. Offset by 1. the proto "unset" value is 0, where as in SourceFile we
552
+ // use "-1"
553
+ int protoNumLines = protoSourceFile .getNumLinesPlusOne () - 1 ;
554
+ int protoNumBytes = protoSourceFile .getNumBytesPlusOne () - 1 ;
555
+ checkState (
556
+ this .numLines == -1 || protoNumLines == -1 || this .numLines == protoNumLines ,
557
+ "Mismatch in numLines for %s. SourceFile: %s, SourceFileProto: %s" ,
558
+ this .getName (),
559
+ this .numLines ,
560
+ protoNumLines );
561
+ checkState (
562
+ this .numBytes == -1 || protoNumBytes == -1 || this .numBytes == protoNumBytes ,
563
+ "Mismatch in numBytes for %s. SourceFile: %s, SourceFileProto: %s" ,
564
+ this .getName (),
565
+ this .numBytes ,
566
+ protoNumBytes );
567
+ this .numLines = this .numLines != -1 ? this .numLines : protoNumLines ;
568
+ this .numBytes = this .numBytes != -1 ? this .numBytes : protoNumBytes ;
569
+ }
570
+
522
571
@ GwtIncompatible ("java.io.Reader" )
523
572
public static SourceFile fromProto (SourceFileProto protoSourceFile ) {
524
573
SourceKind sourceKind = getSourceKindFromProto (protoSourceFile );
574
+ SourceFile sourceFile = fromProto (protoSourceFile , sourceKind );
575
+ // Restore the number of lines/bytes, which are offset by 1 in the proto.
576
+ sourceFile .numLines = protoSourceFile .getNumLinesPlusOne () - 1 ;
577
+ sourceFile .numBytes = protoSourceFile .getNumBytesPlusOne () - 1 ;
578
+ return sourceFile ;
579
+ }
580
+
581
+ private static SourceFile fromProto (SourceFileProto protoSourceFile , SourceKind sourceKind ) {
525
582
switch (protoSourceFile .getLoaderCase ()) {
526
583
case PRELOADED_CONTENTS :
527
584
return SourceFile .fromCode (
@@ -939,6 +996,8 @@ public SourceFileProto getProto() {
939
996
.toProtoLocationBuilder (this .getName ())
940
997
.setFilename (this .getName ())
941
998
.setSourceKind (sourceKindToProto (this .getKind ()))
999
+ .setNumLinesPlusOne (this .numLines + 1 )
1000
+ .setNumBytesPlusOne (this .numBytes + 1 )
942
1001
.build ();
943
1002
}
944
1003
0 commit comments