77
88import com .google .common .annotations .VisibleForTesting ;
99import com .google .common .collect .Lists ;
10- import com .google .common .util .concurrent .Uninterruptibles ;
1110import com .google .dart .server .AnalysisServerListenerAdapter ;
1211import com .google .dart .server .ResponseListener ;
13- import com .google .gson .JsonArray ;
1412import com .google .gson .JsonElement ;
1513import com .google .gson .JsonObject ;
1614import com .google .gson .JsonPrimitive ;
1715import com .intellij .openapi .Disposable ;
16+ import com .intellij .openapi .application .Application ;
1817import com .intellij .openapi .application .ApplicationManager ;
1918import com .intellij .openapi .project .Project ;
2019import com .intellij .openapi .util .Disposer ;
21- import com .intellij .openapi .util .io .FileUtil ;
22- import com .intellij .openapi .vfs .VirtualFile ;
2320import com .intellij .util .Consumer ;
2421import com .jetbrains .lang .dart .analyzer .DartAnalysisServerService ;
2522import io .flutter .utils .JsonUtils ;
26- import org .dartlang .analysis .server .protocol .*;
23+ import org .dartlang .analysis .server .protocol .AnalysisError ;
24+ import org .dartlang .analysis .server .protocol .FlutterOutline ;
25+ import org .dartlang .analysis .server .protocol .FlutterService ;
2726import org .jetbrains .annotations .NotNull ;
2827import org .jetbrains .annotations .Nullable ;
2928
3029import java .util .*;
31- import java .util .concurrent .CompletableFuture ;
32- import java .util .concurrent .CountDownLatch ;
33- import java .util .concurrent .TimeUnit ;
34- import java .util .concurrent .atomic .AtomicReference ;
3530
3631public class FlutterDartAnalysisServer implements Disposable {
3732 private static final String FLUTTER_NOTIFICATION_OUTLINE = "flutter.outline" ;
38- private static final String FLUTTER_NOTIFICATION_OUTLINE_KEY = "\" flutter.outline\" " ;
3933
4034 @ NotNull final Project project ;
4135
@@ -70,7 +64,9 @@ public String getSdkVersion() {
7064 return getAnalysisService ().getSdkVersion ();
7165 }
7266
73- /** @noinspection BooleanMethodIsAlwaysInverted*/
67+ /**
68+ * @noinspection BooleanMethodIsAlwaysInverted
69+ */
7470 public boolean isServerConnected () {
7571 return !getSdkVersion ().isEmpty ();
7672 }
@@ -108,18 +104,19 @@ public void computedErrors(String file, List<AnalysisError> errors) {
108104 }
109105
110106 public void addOutlineListener (@ NotNull final String filePath , @ NotNull final FlutterOutlineListener listener ) {
111- if (!isServerConnected ()) {
107+ if (!isServerConnected ()) {
112108 return ;
113109 }
114110 synchronized (fileOutlineListeners ) {
115- final List <FlutterOutlineListener > listeners = fileOutlineListeners .computeIfAbsent (getAnalysisService ().getLocalFileUri (filePath ), k -> new ArrayList <>());
111+ final List <FlutterOutlineListener > listeners =
112+ fileOutlineListeners .computeIfAbsent (getAnalysisService ().getLocalFileUri (filePath ), k -> new ArrayList <>());
116113 listeners .add (listener );
117114 }
118115 addSubscription (FlutterService .OUTLINE , filePath );
119116 }
120117
121118 public void removeOutlineListener (@ NotNull final String filePath , @ NotNull final FlutterOutlineListener listener ) {
122- if (!isServerConnected ()) {
119+ if (!isServerConnected ()) {
123120 return ;
124121 }
125122 final boolean removeSubscription ;
@@ -138,7 +135,7 @@ public void removeOutlineListener(@NotNull final String filePath, @NotNull final
138135 * Note that <code>filePath</code> must be an absolute path.
139136 */
140137 private void addSubscription (@ NotNull final String service , @ NotNull final String filePath ) {
141- if (!isServerConnected ()) {
138+ if (!isServerConnected ()) {
142139 return ;
143140 }
144141 final List <String > files = subscriptions .computeIfAbsent (service , k -> new ArrayList <>());
@@ -155,7 +152,7 @@ private void addSubscription(@NotNull final String service, @NotNull final Strin
155152 * Note that <code>filePath</code> must be an absolute path.
156153 */
157154 private void removeSubscription (@ NotNull final String service , @ NotNull final String filePath ) {
158- if (!isServerConnected ()) {
155+ if (!isServerConnected ()) {
159156 return ;
160157 }
161158 final String filePathOrUri = getAnalysisService ().getLocalFileUri (filePath );
@@ -166,89 +163,39 @@ private void removeSubscription(@NotNull final String service, @NotNull final St
166163 }
167164
168165 private void sendSubscriptions () {
169- if (!isServerConnected ()) {
166+ if (!isServerConnected ()) {
170167 return ;
171168 }
172169 DartAnalysisServerService analysisService = getAnalysisService ();
173170 final String id = analysisService .generateUniqueId ();
174- analysisService .sendRequest (id , FlutterRequestUtilities .generateAnalysisSetSubscriptions (id , subscriptions ));
175- }
176-
177- @ NotNull
178- public List <SourceChange > edit_getAssists (@ NotNull VirtualFile file , int offset , int length ) {
179- DartAnalysisServerService analysisService = getAnalysisService ();
180- return analysisService .edit_getAssists (file , offset , length );
181- }
182-
183- @ Nullable
184- public CompletableFuture <List <FlutterWidgetProperty >> getWidgetDescription (@ NotNull VirtualFile file , int _offset ) {
185- final CompletableFuture <List <FlutterWidgetProperty >> result = new CompletableFuture <>();
186- final String filePath = FileUtil .toSystemDependentName (file .getPath ());
187- DartAnalysisServerService analysisService = getAnalysisService ();
188- final int offset = analysisService .getOriginalOffset (file , _offset );
189-
190- final String id = analysisService .generateUniqueId ();
191- synchronized (responseConsumers ) {
192- responseConsumers .put (id , (resultObject ) -> {
193- try {
194- final JsonArray propertiesObject = resultObject .getAsJsonArray ("properties" );
195- final ArrayList <FlutterWidgetProperty > properties = new ArrayList <>();
196- for (JsonElement propertyObject : propertiesObject ) {
197- properties .add (FlutterWidgetProperty .fromJson (propertyObject .getAsJsonObject ()));
198- }
199- result .complete (properties );
200- }
201- catch (Throwable ignored ) {
202- }
203- });
171+ if (id != null ) {
172+ analysisService .sendRequest (id , FlutterRequestUtilities .generateAnalysisSetSubscriptions (id , subscriptions ));
204173 }
205-
206- final JsonObject request = FlutterRequestUtilities .generateFlutterGetWidgetDescription (id , filePath , offset );
207- analysisService .sendRequest (id , request );
208-
209- return result ;
210174 }
211175
212-
213- @ Nullable
214- public SourceChange setWidgetPropertyValue (int propertyId , FlutterWidgetPropertyValue value ) {
215- final CountDownLatch latch = new CountDownLatch (1 );
216- final AtomicReference <SourceChange > result = new AtomicReference <>();
217- DartAnalysisServerService analysisService = getAnalysisService ();
218- final String id = analysisService .generateUniqueId ();
219- synchronized (responseConsumers ) {
220- responseConsumers .put (id , (resultObject ) -> {
221- try {
222- final JsonObject propertiesObject = resultObject .getAsJsonObject ("change" );
223- result .set (SourceChange .fromJson (propertiesObject ));
224- }
225- catch (Throwable ignored ) {
176+ private void processString (@ Nullable String jsonString ) {
177+ if (jsonString == null ) return ;
178+ if (isDisposed ) return ;
179+ Application application = ApplicationManager .getApplication ();
180+ if (application != null ) {
181+ application .executeOnPooledThread (() -> {
182+ // Short circuit just in case we have been disposed in the time it took
183+ // for us to get around to listening for the response.
184+ if (isDisposed ) return ;
185+ JsonElement jsonElement = JsonUtils .parseString (jsonString );
186+ if (jsonElement != null ) {
187+ processResponse (jsonElement .getAsJsonObject ());
226188 }
227- latch .countDown ();
228189 });
229190 }
230-
231- final JsonObject request = FlutterRequestUtilities .generateFlutterSetWidgetPropertyValue (id , propertyId , value );
232- analysisService .sendRequest (id , request );
233-
234- Uninterruptibles .awaitUninterruptibly (latch , 100 , TimeUnit .MILLISECONDS );
235- return result .get ();
236- }
237-
238- private void processString (String jsonString ) {
239- if (isDisposed ) return ;
240- ApplicationManager .getApplication ().executeOnPooledThread (() -> {
241- // Short circuit just in case we have been disposed in the time it took
242- // for us to get around to listening for the response.
243- if (isDisposed ) return ;
244- processResponse (JsonUtils .parseString (jsonString ).getAsJsonObject ());
245- });
246191 }
247192
248193 /**
249194 * Handle the given {@link JsonObject} response.
250195 */
251- private void processResponse (JsonObject response ) {
196+ private void processResponse (@ Nullable JsonObject response ) {
197+ if (response == null ) return ;
198+
252199 final JsonElement eventName = response .get ("event" );
253200 if (eventName != null && eventName .isJsonPrimitive ()) {
254201 processNotification (response , eventName );
@@ -284,6 +231,7 @@ private void processResponse(JsonObject response) {
284231 /**
285232 * Attempts to handle the given {@link JsonObject} as a notification.
286233 */
234+ @ SuppressWarnings ("DataFlowIssue" ) // Ignore for de-marshalling JSON objects.
287235 private void processNotification (JsonObject response , @ NotNull JsonElement eventName ) {
288236 // If we add code to handle more event types below, update the filter in processString().
289237 final String event = eventName .getAsString ();
@@ -304,7 +252,9 @@ private void processNotification(JsonObject response, @NotNull JsonElement event
304252 }
305253 if (listenersUpdated != null ) {
306254 for (FlutterOutlineListener listener : listenersUpdated ) {
307- listener .outlineUpdated (file , outline , instrumentedCode );
255+ if (listener != null && file != null ) {
256+ listener .outlineUpdated (file , outline , instrumentedCode );
257+ }
308258 }
309259 }
310260 }
0 commit comments