| OLD | NEW | 
|    1 // Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file |    1 // Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file | 
|    2 // for details. All rights reserved. Use of this source code is governed by a |    2 // for details. All rights reserved. Use of this source code is governed by a | 
|    3 // BSD-style license that can be found in the LICENSE file. |    3 // BSD-style license that can be found in the LICENSE file. | 
|    4  |    4  | 
|    5 library services.src.refactoring.move_file; |    5 library services.src.refactoring.move_file; | 
|    6  |    6  | 
|    7 import 'dart:async'; |    7 import 'dart:async'; | 
|    8  |    8  | 
|    9 import 'package:analysis_server/src/protocol.dart' hide Element; |    9 import 'package:analysis_server/src/protocol.dart' hide Element; | 
|   10 import 'package:analysis_server/src/services/correction/status.dart'; |   10 import 'package:analysis_server/src/services/correction/status.dart'; | 
|   11 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; |   11 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; | 
|   12 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da
     rt'; |   12 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da
     rt'; | 
|   13 import 'package:analysis_server/src/services/search/search_engine.dart'; |   13 import 'package:analysis_server/src/services/search/search_engine.dart'; | 
|   14 import 'package:analyzer/src/generated/element.dart'; |   14 import 'package:analyzer/src/generated/element.dart'; | 
|   15 import 'package:analyzer/src/generated/engine.dart'; |   15 import 'package:analyzer/src/generated/engine.dart'; | 
|   16 import 'package:analyzer/src/generated/source.dart'; |   16 import 'package:analyzer/src/generated/source.dart'; | 
|   17 import 'package:path/path.dart' as pathos; |   17 import 'package:path/path.dart' as pathos; | 
|   18  |   18  | 
|   19  |   19  | 
|   20 /** |   20 /** | 
|   21  * [ExtractLocalRefactoring] implementation. |   21  * [ExtractLocalRefactoring] implementation. | 
|   22  */ |   22  */ | 
|   23 class MoveFileRefactoringImpl extends RefactoringImpl implements |   23 class MoveFileRefactoringImpl extends RefactoringImpl implements | 
|   24     MoveFileRefactoring { |   24     MoveFileRefactoring { | 
 |   25   final pathos.Context pathContext; | 
|   25   final SearchEngine searchEngine; |   26   final SearchEngine searchEngine; | 
|   26   final AnalysisContext context; |   27   final AnalysisContext context; | 
|   27   final Source source; |   28   final Source source; | 
|   28  |   29  | 
|   29   String oldFile; |   30   String oldFile; | 
|   30   String newFile; |   31   String newFile; | 
|   31  |   32  | 
|   32   SourceChange change; |   33   SourceChange change; | 
|   33   LibraryElement library; |   34   LibraryElement library; | 
|   34   String oldLibraryDir; |   35   String oldLibraryDir; | 
|   35   String newLibraryDir; |   36   String newLibraryDir; | 
|   36  |   37  | 
|   37   MoveFileRefactoringImpl(this.searchEngine, this.context, this.source) { |   38   MoveFileRefactoringImpl(this.pathContext, this.searchEngine, this.context, | 
 |   39       this.source) { | 
|   38     oldFile = source.fullName; |   40     oldFile = source.fullName; | 
|   39   } |   41   } | 
|   40  |   42  | 
|   41   @override |   43   @override | 
|   42   String get refactoringName => 'Move File'; |   44   String get refactoringName => 'Move File'; | 
|   43  |   45  | 
|   44   @override |   46   @override | 
|   45   Future<RefactoringStatus> checkFinalConditions() { |   47   Future<RefactoringStatus> checkFinalConditions() { | 
|   46     RefactoringStatus result = new RefactoringStatus(); |   48     RefactoringStatus result = new RefactoringStatus(); | 
|   47     return new Future.value(result); |   49     return new Future.value(result); | 
|   48   } |   50   } | 
|   49  |   51  | 
|   50   @override |   52   @override | 
|   51   Future<RefactoringStatus> checkInitialConditions() { |   53   Future<RefactoringStatus> checkInitialConditions() { | 
|   52     RefactoringStatus result = new RefactoringStatus(); |   54     RefactoringStatus result = new RefactoringStatus(); | 
|   53     return new Future.value(result); |   55     return new Future.value(result); | 
|   54   } |   56   } | 
|   55  |   57  | 
|   56   @override |   58   @override | 
|   57   Future<SourceChange> createChange() { |   59   Future<SourceChange> createChange() { | 
|   58     change = new SourceChange('Update File References'); |   60     change = new SourceChange('Update File References'); | 
|   59     List<Source> librarySources = context.getLibrariesContaining(source); |   61     List<Source> librarySources = context.getLibrariesContaining(source); | 
|   60     return Future.forEach(librarySources, (Source librarySource) { |   62     return Future.forEach(librarySources, (Source librarySource) { | 
|   61       CompilationUnitElement unitElement = |   63       CompilationUnitElement unitElement = | 
|   62           context.getCompilationUnitElement(source, librarySource); |   64           context.getCompilationUnitElement(source, librarySource); | 
|   63       if (unitElement != null) { |   65       if (unitElement != null) { | 
|   64         // if a defining unit, update outgoing references |   66         // if a defining unit, update outgoing references | 
|   65         library = unitElement.library; |   67         library = unitElement.library; | 
|   66         if (library.definingCompilationUnit == unitElement) { |   68         if (library.definingCompilationUnit == unitElement) { | 
|   67           oldLibraryDir = pathos.dirname(oldFile); |   69           oldLibraryDir = pathContext.dirname(oldFile); | 
|   68           newLibraryDir = pathos.dirname(newFile); |   70           newLibraryDir = pathContext.dirname(newFile); | 
|   69           _updateUriReferences(library.imports); |   71           _updateUriReferences(library.imports); | 
|   70           _updateUriReferences(library.exports); |   72           _updateUriReferences(library.exports); | 
|   71           _updateUriReferences(library.parts); |   73           _updateUriReferences(library.parts); | 
|   72         } |   74         } | 
|   73         // update reference to the unit |   75         // update reference to the unit | 
|   74         return searchEngine.searchReferences(unitElement).then((matches) { |   76         return searchEngine.searchReferences(unitElement).then((matches) { | 
|   75           List<SourceReference> references = getSourceReferences(matches); |   77           List<SourceReference> references = getSourceReferences(matches); | 
|   76           for (SourceReference reference in references) { |   78           for (SourceReference reference in references) { | 
|   77             String newUri = _computeNewUri(reference); |   79             String newUri = _computeNewUri(reference); | 
|   78             reference.addEdit(change, "'$newUri'"); |   80             reference.addEdit(change, "'$newUri'"); | 
|   79           } |   81           } | 
|   80         }); |   82         }); | 
|   81       } |   83       } | 
|   82     }).then((_) { |   84     }).then((_) { | 
|   83       return change; |   85       return change; | 
|   84     }); |   86     }); | 
|   85   } |   87   } | 
|   86  |   88  | 
|   87   @override |   89   @override | 
|   88   bool requiresPreview() => false; |   90   bool requiresPreview() => false; | 
|   89  |   91  | 
|   90   /** |   92   /** | 
|   91    * Computes the URI to use to reference [newFile] from [reference]. |   93    * Computes the URI to use to reference [newFile] from [reference]. | 
|   92    */ |   94    */ | 
|   93   String _computeNewUri(SourceReference reference) { |   95   String _computeNewUri(SourceReference reference) { | 
|   94     String refDir = pathos.dirname(reference.file); |   96     String refDir = pathContext.dirname(reference.file); | 
|   95     // try to keep package: URI |   97     // try to keep package: URI | 
|   96     if (_isPackageReference(reference)) { |   98     if (_isPackageReference(reference)) { | 
|   97       Source newSource = new NonExistingSource(newFile, UriKind.FILE_URI); |   99       Source newSource = new NonExistingSource(newFile, UriKind.FILE_URI); | 
|   98       Uri restoredUri = context.sourceFactory.restoreUri(newSource); |  100       Uri restoredUri = context.sourceFactory.restoreUri(newSource); | 
|   99       if (restoredUri != null) { |  101       if (restoredUri != null) { | 
|  100         return restoredUri.toString(); |  102         return restoredUri.toString(); | 
|  101       } |  103       } | 
|  102     } |  104     } | 
|  103     // if no package: URI, prepare relative |  105     // if no package: URI, prepare relative | 
|  104     return pathos.relative(newFile, from: refDir); |  106     return _getRelativeUri(newFile, refDir); | 
 |  107   } | 
 |  108  | 
 |  109   String _getRelativeUri(String path, String from) { | 
 |  110     String uri = pathContext.relative(path, from: from); | 
 |  111     List<String> parts = pathContext.split(uri); | 
 |  112     return pathos.posix.joinAll(parts); | 
|  105   } |  113   } | 
|  106  |  114  | 
|  107   bool _isPackageReference(SourceReference reference) { |  115   bool _isPackageReference(SourceReference reference) { | 
|  108     Source source = reference.element.source; |  116     Source source = reference.element.source; | 
|  109     int offset = reference.range.offset + "'".length; |  117     int offset = reference.range.offset + "'".length; | 
|  110     String content = context.getContents(source).data; |  118     String content = context.getContents(source).data; | 
|  111     return content.startsWith('package:', offset); |  119     return content.startsWith('package:', offset); | 
|  112   } |  120   } | 
|  113  |  121  | 
 |  122   /** | 
 |  123    * Checks if the given [path] represents a relative URI. | 
 |  124    * | 
 |  125    * The following URI's are not relative: | 
 |  126    *    `/absolute/path/file.dart` | 
 |  127    *    `dart:math` | 
 |  128    */ | 
 |  129   bool _isRelativeUri(String path) { | 
 |  130     // absolute URI | 
 |  131     if (Uri.parse(path).isAbsolute) { | 
 |  132       return false; | 
 |  133     } | 
 |  134     // absolute path | 
 |  135     if (pathContext.isAbsolute(path)) { | 
 |  136       return false; | 
 |  137     } | 
 |  138     // OK | 
 |  139     return true; | 
 |  140   } | 
 |  141  | 
|  114   void _updateUriReference(UriReferencedElement element) { |  142   void _updateUriReference(UriReferencedElement element) { | 
|  115     if (!element.isSynthetic) { |  143     if (!element.isSynthetic) { | 
|  116       String elementUri = element.uri; |  144       String elementUri = element.uri; | 
|  117       if (_isRelativeUri(elementUri)) { |  145       if (_isRelativeUri(elementUri)) { | 
|  118         String elementPath = pathos.join(oldLibraryDir, elementUri); |  146         String elementPath = pathContext.join(oldLibraryDir, elementUri); | 
|  119         String newUri = pathos.relative(elementPath, from: newLibraryDir); |  147         String newUri = _getRelativeUri(elementPath, newLibraryDir); | 
|  120         int uriOffset = element.uriOffset; |  148         int uriOffset = element.uriOffset; | 
|  121         int uriLength = element.uriEnd - uriOffset; |  149         int uriLength = element.uriEnd - uriOffset; | 
|  122         change.addElementEdit( |  150         change.addElementEdit( | 
|  123             library, |  151             library, | 
|  124             new SourceEdit(uriOffset, uriLength, "'$newUri'")); |  152             new SourceEdit(uriOffset, uriLength, "'$newUri'")); | 
|  125       } |  153       } | 
|  126     } |  154     } | 
|  127   } |  155   } | 
|  128  |  156  | 
|  129   void _updateUriReferences(List<UriReferencedElement> elements) { |  157   void _updateUriReferences(List<UriReferencedElement> elements) { | 
|  130     for (UriReferencedElement element in elements) { |  158     for (UriReferencedElement element in elements) { | 
|  131       _updateUriReference(element); |  159       _updateUriReference(element); | 
|  132     } |  160     } | 
|  133   } |  161   } | 
|  134  |  | 
|  135   /** |  | 
|  136    * Checks if the given [path] represents a relative URI. |  | 
|  137    * |  | 
|  138    * The following URI's are not relative: |  | 
|  139    *    `/absolute/path/file.dart` |  | 
|  140    *    `dart:math` |  | 
|  141    */ |  | 
|  142   static bool _isRelativeUri(String path) { |  | 
|  143     // absolute path |  | 
|  144     if (pathos.isAbsolute(path)) { |  | 
|  145       return false; |  | 
|  146     } |  | 
|  147     // absolute URI |  | 
|  148     if (Uri.parse(path).isAbsolute) { |  | 
|  149       return false; |  | 
|  150     } |  | 
|  151     // OK |  | 
|  152     return true; |  | 
|  153   } |  | 
|  154 } |  162 } | 
| OLD | NEW |