blob: 1428c341d9299ee551bfc3e489f591a1c7be97fc [file] [log] [blame]
/*
* Copyright (c) 2014, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.core.internal.analysis.model;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.dart.engine.error.ErrorCode;
import com.google.dart.server.AnalysisError;
import com.google.dart.server.AnalysisServer;
import com.google.dart.server.AnalysisService;
import com.google.dart.server.HighlightRegion;
import com.google.dart.server.NavigationRegion;
import com.google.dart.server.Occurrences;
import com.google.dart.server.Outline;
import com.google.dart.server.OverrideMember;
import com.google.dart.server.SearchResult;
import com.google.dart.tools.core.analysis.model.AnalysisServerData;
import com.google.dart.tools.core.analysis.model.AnalysisServerHighlightsListener;
import com.google.dart.tools.core.analysis.model.AnalysisServerOutlineListener;
import com.google.dart.tools.core.analysis.model.AnalysisServerOverridesListener;
import com.google.dart.tools.core.analysis.model.SearchResultsListener;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Instances of {@code AnalysisServerData} manage and provide access to analysis results reported by
* {@link AnalysisServer}.
*
* @coverage dart.tools.core.model
*/
public class AnalysisServerDataImpl implements AnalysisServerData {
private final Map<String, Set<AnalysisServerHighlightsListener>> highlightsSubscriptions = Maps.newHashMap();
private final Map<String, Set<AnalysisServerOutlineListener>> outlineSubscriptions = Maps.newHashMap();
private final Map<String, Set<AnalysisServerOverridesListener>> overridesSubscriptions = Maps.newHashMap();
private final Map<String, AnalysisError[]> errorData = Maps.newHashMap();
private final Map<String, NavigationRegion[]> navigationData = Maps.newHashMap();
private final Map<String, Occurrences[]> occurrencesData = Maps.newHashMap();
private final Map<AnalysisService, List<String>> analysisSubscriptions = Maps.newHashMap();
private final Map<String, SearchResultsListener> searchResultsListeners = Maps.newHashMap();
private final Map<String, List<SearchResultsSet>> searchResultsData = Maps.newHashMap();
// TODO(scheglov) restore or remove for the new API
// private final Map<String, Set<ErrorCode>> fixableErrorCodesData = Maps.newHashMap();
private AnalysisServer server;
@Override
public synchronized void addSearchResultsListener(String searchId, SearchResultsListener listener) {
List<SearchResultsSet> resultsSets = searchResultsData.remove(searchId);
boolean hasLast = false;
if (resultsSets != null) {
for (SearchResultsSet searchResultsSet : resultsSets) {
listener.computedSearchResults(searchResultsSet.results, searchResultsSet.last);
hasLast |= searchResultsSet.last;
}
}
if (!hasLast) {
searchResultsListeners.put(searchId, listener);
}
}
@Override
public AnalysisError[] getErrors(String file) {
AnalysisError[] errors = errorData.get(file);
if (errors == null) {
return AnalysisError.NO_ERRORS;
}
return errors;
}
@Override
public NavigationRegion[] getNavigation(String file) {
NavigationRegion[] sourceRegions = navigationData.get(file);
if (sourceRegions == null) {
return NavigationRegion.EMPTY_ARRAY;
}
return sourceRegions;
}
@Override
public Occurrences[] getOccurrences(String file) {
Occurrences[] occurrencesArray = occurrencesData.get(file);
if (occurrencesArray == null) {
return Occurrences.EMPTY_ARRAY;
}
return occurrencesArray;
}
@Override
public boolean isFixableErrorCode(String file, ErrorCode errorCode) {
// TODO(scheglov) restore or remove for the new API
return false;
// Set<ErrorCode> fixableErrorCodes = fixableErrorCodesData.get(contextId);
// if (fixableErrorCodes == null) {
// return false;
// }
// return fixableErrorCodes.contains(errorCode);
}
@Override
public synchronized void removeSearchResultsListener(String searchId,
SearchResultsListener listener) {
searchResultsData.remove(searchId);
searchResultsListeners.remove(searchId);
}
/**
* Sets the {@link AnalysisServer} to talk to.
*/
public void setServer(AnalysisServer server) {
this.server = server;
}
@Override
public void subscribeHighlights(String file, AnalysisServerHighlightsListener listener) {
Set<AnalysisServerHighlightsListener> subscriptions = highlightsSubscriptions.get(file);
if (subscriptions == null) {
subscriptions = Sets.newHashSet();
highlightsSubscriptions.put(file, subscriptions);
}
if (subscriptions.add(listener)) {
addAnalysisSubscription(AnalysisService.HIGHLIGHTS, file);
}
}
@Override
public void subscribeNavigation(String file) {
addAnalysisSubscription(AnalysisService.NAVIGATION, file);
}
@Override
public void subscribeOccurrences(String file) {
addAnalysisSubscription(AnalysisService.OCCURRENCES, file);
}
@Override
public void subscribeOutline(String file, AnalysisServerOutlineListener listener) {
Set<AnalysisServerOutlineListener> subscriptions = outlineSubscriptions.get(file);
if (subscriptions == null) {
subscriptions = Sets.newHashSet();
outlineSubscriptions.put(file, subscriptions);
}
if (subscriptions.add(listener)) {
addAnalysisSubscription(AnalysisService.OUTLINE, file);
}
}
@Override
public void subscribeOverrides(String file, AnalysisServerOverridesListener listener) {
Set<AnalysisServerOverridesListener> subscriptions = overridesSubscriptions.get(file);
if (subscriptions == null) {
subscriptions = Sets.newHashSet();
overridesSubscriptions.put(file, subscriptions);
}
if (subscriptions.add(listener)) {
addAnalysisSubscription(AnalysisService.OVERRIDES, file);
}
}
@Override
public void unsubscribeHighlights(String file, AnalysisServerHighlightsListener listener) {
Set<AnalysisServerHighlightsListener> subscriptions = highlightsSubscriptions.get(file);
if (subscriptions == null) {
return;
}
if (subscriptions.remove(listener)) {
if (subscriptions.isEmpty()) {
removeAnalysisSubscription(AnalysisService.HIGHLIGHTS, file);
}
}
}
@Override
public void unsubscribeNavigation(String file) {
removeAnalysisSubscription(AnalysisService.NAVIGATION, file);
}
@Override
public void unsubscribeOccurrences(String file) {
removeAnalysisSubscription(AnalysisService.OCCURRENCES, file);
}
@Override
public void unsubscribeOutline(String file, AnalysisServerOutlineListener listener) {
Set<AnalysisServerOutlineListener> subscriptions = outlineSubscriptions.get(file);
if (subscriptions == null) {
return;
}
if (subscriptions.remove(listener)) {
if (subscriptions.isEmpty()) {
removeAnalysisSubscription(AnalysisService.OUTLINE, file);
}
}
}
@Override
public void unsubscribeOverrides(String file, AnalysisServerOverridesListener listener) {
Set<AnalysisServerOverridesListener> subscriptions = overridesSubscriptions.get(file);
if (subscriptions == null) {
return;
}
if (subscriptions.remove(listener)) {
if (subscriptions.isEmpty()) {
removeAnalysisSubscription(AnalysisService.OVERRIDES, file);
}
}
}
void internalComputedErrors(String file, AnalysisError[] errors) {
errorData.put(file, errors);
}
void internalComputedHighlights(String file, HighlightRegion[] highlights) {
Set<AnalysisServerHighlightsListener> subscriptions = highlightsSubscriptions.get(file);
if (subscriptions == null) {
return;
}
subscriptions = ImmutableSet.copyOf(subscriptions);
for (AnalysisServerHighlightsListener listener : subscriptions) {
listener.computedHighlights(file, highlights);
}
}
void internalComputedNavigation(String file, NavigationRegion[] targets) {
navigationData.put(file, targets);
}
void internalComputedOccurrences(String file, Occurrences[] occurrencesArray) {
occurrencesData.put(file, occurrencesArray);
}
void internalComputedOutline(String file, Outline outline) {
Set<AnalysisServerOutlineListener> subscriptions = outlineSubscriptions.get(file);
if (subscriptions == null) {
return;
}
subscriptions = ImmutableSet.copyOf(subscriptions);
for (AnalysisServerOutlineListener listener : subscriptions) {
listener.computedOutline(file, outline);
}
}
void internalComputedOverrides(String file, OverrideMember[] overrides) {
Set<AnalysisServerOverridesListener> subscriptions = overridesSubscriptions.get(file);
if (subscriptions == null) {
return;
}
subscriptions = ImmutableSet.copyOf(subscriptions);
for (AnalysisServerOverridesListener listener : subscriptions) {
listener.computedHighlights(file, overrides);
}
}
synchronized void internalComputedSearchResults(String searchId, SearchResult[] results,
boolean last) {
SearchResultsListener listener = searchResultsListeners.get(searchId);
if (listener != null) {
if (last) {
searchResultsListeners.remove(searchId);
}
listener.computedSearchResults(results, last);
}
}
/**
* Remembers the {@link ErrorCode} that may be fixed in the given context.
*/
void internalSetFixableErrorCodes(String file, ErrorCode[] errorCodes) {
// TODO(scheglov) restore or remove for the new API
// fixableErrorCodesData.put(contextId, Sets.newHashSet(errorCodes));
}
/**
* Adds the given file to the subscription list for the given {@link AnalysisService}.
*/
private void addAnalysisSubscription(AnalysisService service, String file) {
List<String> files = analysisSubscriptions.get(service);
if (files == null) {
files = Lists.newArrayList();
analysisSubscriptions.put(service, files);
}
if (!files.contains(file)) {
files.add(file);
// TODO (jwren) re-enable after it is working in the java server again:
// server.analysis_setSubscriptions(analysisSubscriptions);
}
}
/**
* Removes the given file from the subscription list for the given {@link AnalysisService}.
*/
private void removeAnalysisSubscription(AnalysisService service, String file) {
List<String> files = analysisSubscriptions.get(service);
if (files == null) {
return;
}
if (files.remove(file)) {
if (files.isEmpty()) {
analysisSubscriptions.remove(service);
}
// TODO (jwren) re-implement after this is working
// server.analysis_setSubscriptions(analysisSubscriptions);
}
}
}